/*
Copyright (c) 2007, Yahoo! Inc. All rights reserved.
Code licensed under the BSD License:
http://developer.yahoo.net/yui/license.txt
version: 2.3.0
*/

if(typeof YAHOO=="undefined"){var YAHOO={};}
YAHOO.namespace=function(){var a=arguments,o=null,i,j,d;for(i=0;i<a.length;i=i+1){d=a[i].split(".");o=YAHOO;for(j=(d[0]=="YAHOO")?1:0;j<d.length;j=j+1){o[d[j]]=o[d[j]]||{};o=o[d[j]];}}
return o;};YAHOO.log=function(msg,cat,src){var l=YAHOO.widget.Logger;if(l&&l.log){return l.log(msg,cat,src);}else{return false;}};YAHOO.register=function(name,mainClass,data){var mods=YAHOO.env.modules;if(!mods[name]){mods[name]={versions:[],builds:[]};}
var m=mods[name],v=data.version,b=data.build,ls=YAHOO.env.listeners;m.name=name;m.version=v;m.build=b;m.versions.push(v);m.builds.push(b);m.mainClass=mainClass;for(var i=0;i<ls.length;i=i+1){ls[i](m);}
if(mainClass){mainClass.VERSION=v;mainClass.BUILD=b;}else{YAHOO.log("mainClass is undefined for module "+name,"warn");}};YAHOO.env=YAHOO.env||{modules:[],listeners:[]};YAHOO.env.getVersion=function(name){return YAHOO.env.modules[name]||null;};YAHOO.env.ua=function(){var o={ie:0,opera:0,gecko:0,webkit:0};var ua=navigator.userAgent,m;if((/KHTML/).test(ua)){o.webkit=1;}
m=ua.match(/AppleWebKit\/([^\s]*)/);if(m&&m[1]){o.webkit=parseFloat(m[1]);}
if(!o.webkit){m=ua.match(/Opera[\s\/]([^\s]*)/);if(m&&m[1]){o.opera=parseFloat(m[1]);}else{m=ua.match(/MSIE\s([^;]*)/);if(m&&m[1]){o.ie=parseFloat(m[1]);}else{m=ua.match(/Gecko\/([^\s]*)/);if(m){o.gecko=1;m=ua.match(/rv:([^\s\)]*)/);if(m&&m[1]){o.gecko=parseFloat(m[1]);}}}}}
return o;}();(function(){YAHOO.namespace("util","widget","example");if(typeof YAHOO_config!="undefined"){var l=YAHOO_config.listener,ls=YAHOO.env.listeners,unique=true,i;if(l){for(i=0;i<ls.length;i=i+1){if(ls[i]==l){unique=false;break;}}
if(unique){ls.push(l);}}}})();YAHOO.lang={isArray:function(o){if(o){var l=YAHOO.lang;return l.isNumber(o.length)&&l.isFunction(o.splice)&&!l.hasOwnProperty(o.length);}
return false;},isBoolean:function(o){return typeof o==='boolean';},isFunction:function(o){return typeof o==='function';},isNull:function(o){return o===null;},isNumber:function(o){return typeof o==='number'&&isFinite(o);},isObject:function(o){return(o&&(typeof o==='object'||YAHOO.lang.isFunction(o)))||false;},isString:function(o){return typeof o==='string';},isUndefined:function(o){return typeof o==='undefined';},hasOwnProperty:function(o,prop){if(Object.prototype.hasOwnProperty){return o.hasOwnProperty(prop);}
return!YAHOO.lang.isUndefined(o[prop])&&o.constructor.prototype[prop]!==o[prop];},_IEEnumFix:function(r,s){if(YAHOO.env.ua.ie){var add=["toString","valueOf"];for(i=0;i<add.length;i=i+1){var fname=add[i],f=s[fname];if(YAHOO.lang.isFunction(f)&&f!=Object.prototype[fname]){r[fname]=f;}}}},extend:function(subc,superc,overrides){if(!superc||!subc){throw new Error("YAHOO.lang.extend failed, please check that "+"all dependencies are included.");}
var F=function(){};F.prototype=superc.prototype;subc.prototype=new F();subc.prototype.constructor=subc;subc.superclass=superc.prototype;if(superc.prototype.constructor==Object.prototype.constructor){superc.prototype.constructor=superc;}
if(overrides){for(var i in overrides){subc.prototype[i]=overrides[i];}
YAHOO.lang._IEEnumFix(subc.prototype,overrides);}},augmentObject:function(r,s){if(!s||!r){throw new Error("Absorb failed, verify dependencies.");}
var a=arguments,i,p,override=a[2];if(override&&override!==true){for(i=2;i<a.length;i=i+1){r[a[i]]=s[a[i]];}}else{for(p in s){if(override||!r[p]){r[p]=s[p];}}
YAHOO.lang._IEEnumFix(r,s);}},augmentProto:function(r,s){if(!s||!r){throw new Error("Augment failed, verify dependencies.");}
var a=[r.prototype,s.prototype];for(var i=2;i<arguments.length;i=i+1){a.push(arguments[i]);}
YAHOO.lang.augmentObject.apply(this,a);},dump:function(o,d){var l=YAHOO.lang,i,len,s=[],OBJ="{...}",FUN="f(){...}",COMMA=', ',ARROW=' => ';if(!l.isObject(o)||o instanceof Date||("nodeType"in o&&"tagName"in o)){return o;}else if(l.isFunction(o)){return FUN;}
d=(l.isNumber(d))?d:3;if(l.isArray(o)){s.push("[");for(i=0,len=o.length;i<len;i=i+1){if(l.isObject(o[i])){s.push((d>0)?l.dump(o[i],d-1):OBJ);}else{s.push(o[i]);}
s.push(COMMA);}
if(s.length>1){s.pop();}
s.push("]");}else{s.push("{");for(i in o){if(l.hasOwnProperty(o,i)){s.push(i+ARROW);if(l.isObject(o[i])){s.push((d>0)?l.dump(o[i],d-1):OBJ);}else{s.push(o[i]);}
s.push(COMMA);}}
if(s.length>1){s.pop();}
s.push("}");}
return s.join("");},substitute:function(s,o,f){var i,j,k,key,v,meta,l=YAHOO.lang,saved=[],token,DUMP='dump',SPACE=' ',LBRACE='{',RBRACE='}';for(;;){i=s.lastIndexOf(LBRACE);if(i<0){break;}
j=s.indexOf(RBRACE,i);if(i+1>=j){break;}
token=s.substring(i+1,j);key=token;meta=null;k=key.indexOf(SPACE);if(k>-1){meta=key.substring(k+1);key=key.substring(0,k);}
v=o[key];if(f){v=f(key,v,meta);}
if(l.isObject(v)){if(l.isArray(v)){v=l.dump(v,parseInt(meta,10));}else{meta=meta||"";var dump=meta.indexOf(DUMP);if(dump>-1){meta=meta.substring(4);}
if(v.toString===Object.prototype.toString||dump>-1){v=l.dump(v,parseInt(meta,10));}else{v=v.toString();}}}else if(!l.isString(v)&&!l.isNumber(v)){v="~-"+saved.length+"-~";saved[saved.length]=token;}
s=s.substring(0,i)+v+s.substring(j+1);}
for(i=saved.length-1;i>=0;i=i-1){s=s.replace(new RegExp("~-"+i+"-~"),"{"+saved[i]+"}","g");}
return s;},trim:function(s){try{return s.replace(/^\s+|\s+$/g,"");}catch(e){return s;}},merge:function(){var o={},a=arguments,i;for(i=0;i<a.length;i=i+1){YAHOO.lang.augmentObject(o,a[i],true);}
return o;},isValue:function(o){var l=YAHOO.lang;return(l.isObject(o)||l.isString(o)||l.isNumber(o)||l.isBoolean(o));}};YAHOO.util.Lang=YAHOO.lang;YAHOO.lang.augment=YAHOO.lang.augmentProto;YAHOO.augment=YAHOO.lang.augmentProto;YAHOO.extend=YAHOO.lang.extend;YAHOO.register("yahoo",YAHOO,{version:"2.3.0",build:"442"});
(function(){var Y=YAHOO.util,getStyle,setStyle,id_counter=0,propertyCache={},reClassNameCache={};var isOpera=YAHOO.env.ua.opera,isSafari=YAHOO.env.ua.webkit,isGecko=YAHOO.env.ua.gecko,isIE=YAHOO.env.ua.ie;var patterns={HYPHEN:/(-[a-z])/i,ROOT_TAG:/^body|html$/i};var toCamel=function(property){if(!patterns.HYPHEN.test(property)){return property;}
if(propertyCache[property]){return propertyCache[property];}
var converted=property;while(patterns.HYPHEN.exec(converted)){converted=converted.replace(RegExp.$1,RegExp.$1.substr(1).toUpperCase());}
propertyCache[property]=converted;return converted;};var getClassRegEx=function(className){var re=reClassNameCache[className];if(!re){re=new RegExp('(?:^|\\s+)'+className+'(?:\\s+|$)');reClassNameCache[className]=re;}
return re;};if(document.defaultView&&document.defaultView.getComputedStyle){getStyle=function(el,property){var value=null;if(property=='float'){property='cssFloat';}
var computed=document.defaultView.getComputedStyle(el,'');if(computed){value=computed[toCamel(property)];}
return el.style[property]||value;};}else if(document.documentElement.currentStyle&&isIE){getStyle=function(el,property){switch(toCamel(property)){case'opacity':var val=100;try{val=el.filters['DXImageTransform.Microsoft.Alpha'].opacity;}catch(e){try{val=el.filters('alpha').opacity;}catch(e){}}
return val/100;case'float':property='styleFloat';default:var value=el.currentStyle?el.currentStyle[property]:null;return(el.style[property]||value);}};}else{getStyle=function(el,property){return el.style[property];};}
if(isIE){setStyle=function(el,property,val){switch(property){case'opacity':if(YAHOO.lang.isString(el.style.filter)){el.style.filter='alpha(opacity='+val*100+')';if(!el.currentStyle||!el.currentStyle.hasLayout){el.style.zoom=1;}}
break;case'float':property='styleFloat';default:el.style[property]=val;}};}else{setStyle=function(el,property,val){if(property=='float'){property='cssFloat';}
el.style[property]=val;};}
var testElement=function(node,method){return node&&node.nodeType==1&&(!method||method(node));};YAHOO.util.Dom={get:function(el){if(!el||el.tagName||el.item){return el;}
if(YAHOO.lang.isString(el)){return document.getElementById(el);}
if(el.splice){var c=[];for(var i=0,len=el.length;i<len;++i){c[c.length]=Y.Dom.get(el[i]);}
return c;}
return el;},getStyle:function(el,property){property=toCamel(property);var f=function(element){return getStyle(element,property);};return Y.Dom.batch(el,f,Y.Dom,true);},setStyle:function(el,property,val){property=toCamel(property);var f=function(element){setStyle(element,property,val);};Y.Dom.batch(el,f,Y.Dom,true);},getXY:function(el){var f=function(el){if((el.parentNode===null||el.offsetParent===null||this.getStyle(el,'display')=='none')&&el!=document.body){return false;}
var parentNode=null;var pos=[];var box;var doc=el.ownerDocument;if(el.getBoundingClientRect){box=el.getBoundingClientRect();return[box.left+Y.Dom.getDocumentScrollLeft(el.ownerDocument),box.top+Y.Dom.getDocumentScrollTop(el.ownerDocument)];}
else{pos=[el.offsetLeft,el.offsetTop];parentNode=el.offsetParent;var hasAbs=this.getStyle(el,'position')=='absolute';if(parentNode!=el){while(parentNode){pos[0]+=parentNode.offsetLeft;pos[1]+=parentNode.offsetTop;if(isSafari&&!hasAbs&&this.getStyle(parentNode,'position')=='absolute'){hasAbs=true;}
parentNode=parentNode.offsetParent;}}
if(isSafari&&hasAbs){pos[0]-=el.ownerDocument.body.offsetLeft;pos[1]-=el.ownerDocument.body.offsetTop;}}
parentNode=el.parentNode;while(parentNode.tagName&&!patterns.ROOT_TAG.test(parentNode.tagName))
{if(Y.Dom.getStyle(parentNode,'display').search(/^inline|table-row.*$/i)){pos[0]-=parentNode.scrollLeft;pos[1]-=parentNode.scrollTop;}
parentNode=parentNode.parentNode;}
return pos;};return Y.Dom.batch(el,f,Y.Dom,true);},getX:function(el){var f=function(el){return Y.Dom.getXY(el)[0];};return Y.Dom.batch(el,f,Y.Dom,true);},getY:function(el){var f=function(el){return Y.Dom.getXY(el)[1];};return Y.Dom.batch(el,f,Y.Dom,true);},setXY:function(el,pos,noRetry){var f=function(el){var style_pos=this.getStyle(el,'position');if(style_pos=='static'){this.setStyle(el,'position','relative');style_pos='relative';}
var pageXY=this.getXY(el);if(pageXY===false){return false;}
var delta=[parseInt(this.getStyle(el,'left'),10),parseInt(this.getStyle(el,'top'),10)];if(isNaN(delta[0])){delta[0]=(style_pos=='relative')?0:el.offsetLeft;}
if(isNaN(delta[1])){delta[1]=(style_pos=='relative')?0:el.offsetTop;}
if(pos[0]!==null){el.style.left=pos[0]-pageXY[0]+delta[0]+'px';}
if(pos[1]!==null){el.style.top=pos[1]-pageXY[1]+delta[1]+'px';}
if(!noRetry){var newXY=this.getXY(el);if((pos[0]!==null&&newXY[0]!=pos[0])||(pos[1]!==null&&newXY[1]!=pos[1])){this.setXY(el,pos,true);}}};Y.Dom.batch(el,f,Y.Dom,true);},setX:function(el,x){Y.Dom.setXY(el,[x,null]);},setY:function(el,y){Y.Dom.setXY(el,[null,y]);},getRegion:function(el){var f=function(el){if((el.parentNode===null||el.offsetParent===null||this.getStyle(el,'display')=='none')&&el!=document.body){return false;}
var region=Y.Region.getRegion(el);return region;};return Y.Dom.batch(el,f,Y.Dom,true);},getClientWidth:function(){return Y.Dom.getViewportWidth();},getClientHeight:function(){return Y.Dom.getViewportHeight();},getElementsByClassName:function(className,tag,root,apply){tag=tag||'*';root=(root)?Y.Dom.get(root):null||document;if(!root){return[];}
var nodes=[],elements=root.getElementsByTagName(tag),re=getClassRegEx(className);for(var i=0,len=elements.length;i<len;++i){if(re.test(elements[i].className)){nodes[nodes.length]=elements[i];if(apply){apply.call(elements[i],elements[i]);}}}
return nodes;},hasClass:function(el,className){var re=getClassRegEx(className);var f=function(el){return re.test(el.className);};return Y.Dom.batch(el,f,Y.Dom,true);},addClass:function(el,className){var f=function(el){if(this.hasClass(el,className)){return false;}
el.className=YAHOO.lang.trim([el.className,className].join(' '));return true;};return Y.Dom.batch(el,f,Y.Dom,true);},removeClass:function(el,className){var re=getClassRegEx(className);var f=function(el){if(!this.hasClass(el,className)){return false;}
var c=el.className;el.className=c.replace(re,' ');if(this.hasClass(el,className)){this.removeClass(el,className);}
el.className=YAHOO.lang.trim(el.className);return true;};return Y.Dom.batch(el,f,Y.Dom,true);},replaceClass:function(el,oldClassName,newClassName){if(!newClassName||oldClassName===newClassName){return false;}
var re=getClassRegEx(oldClassName);var f=function(el){if(!this.hasClass(el,oldClassName)){this.addClass(el,newClassName);return true;}
el.className=el.className.replace(re,' '+newClassName+' ');if(this.hasClass(el,oldClassName)){this.replaceClass(el,oldClassName,newClassName);}
el.className=YAHOO.lang.trim(el.className);return true;};return Y.Dom.batch(el,f,Y.Dom,true);},generateId:function(el,prefix){prefix=prefix||'yui-gen';var f=function(el){if(el&&el.id){return el.id;}
var id=prefix+id_counter++;if(el){el.id=id;}
return id;};return Y.Dom.batch(el,f,Y.Dom,true)||f.apply(Y.Dom,arguments);},isAncestor:function(haystack,needle){haystack=Y.Dom.get(haystack);if(!haystack||!needle){return false;}
var f=function(node){if(haystack.contains&&node.nodeType&&!isSafari){return haystack.contains(node);}
else if(haystack.compareDocumentPosition&&node.nodeType){return!!(haystack.compareDocumentPosition(node)&16);}else if(node.nodeType){return!!this.getAncestorBy(node,function(el){return el==haystack;});}
return false;};return Y.Dom.batch(needle,f,Y.Dom,true);},inDocument:function(el){var f=function(el){if(isSafari){while(el=el.parentNode){if(el==document.documentElement){return true;}}
return false;}
return this.isAncestor(document.documentElement,el);};return Y.Dom.batch(el,f,Y.Dom,true);},getElementsBy:function(method,tag,root,apply){tag=tag||'*';root=(root)?Y.Dom.get(root):null||document;if(!root){return[];}
var nodes=[],elements=root.getElementsByTagName(tag);for(var i=0,len=elements.length;i<len;++i){if(method(elements[i])){nodes[nodes.length]=elements[i];if(apply){apply(elements[i]);}}}
return nodes;},batch:function(el,method,o,override){el=(el&&el.tagName)?el:Y.Dom.get(el);if(!el||!method){return false;}
var scope=(override)?o:window;if(el.tagName||(!el.item&&!el.slice)){return method.call(scope,el,o);}
var collection=[];for(var i=0,len=el.length;i<len;++i){collection[collection.length]=method.call(scope,el[i],o);}
return collection;},getDocumentHeight:function(){var scrollHeight=(document.compatMode!='CSS1Compat')?document.body.scrollHeight:document.documentElement.scrollHeight;var h=Math.max(scrollHeight,Y.Dom.getViewportHeight());return h;},getDocumentWidth:function(){var scrollWidth=(document.compatMode!='CSS1Compat')?document.body.scrollWidth:document.documentElement.scrollWidth;var w=Math.max(scrollWidth,Y.Dom.getViewportWidth());return w;},getViewportHeight:function(){var height=self.innerHeight;var mode=document.compatMode;if((mode||isIE)&&!isOpera){height=(mode=='CSS1Compat')?document.documentElement.clientHeight:document.body.clientHeight;}
return height;},getViewportWidth:function(){var width=self.innerWidth;var mode=document.compatMode;if(mode||isIE){width=(mode=='CSS1Compat')?document.documentElement.clientWidth:document.body.clientWidth;}
return width;},getAncestorBy:function(node,method){while(node=node.parentNode){if(testElement(node,method)){return node;}}
return null;},getAncestorByClassName:function(node,className){node=Y.Dom.get(node);if(!node){return null;}
var method=function(el){return Y.Dom.hasClass(el,className);};return Y.Dom.getAncestorBy(node,method);},getAncestorByTagName:function(node,tagName){node=Y.Dom.get(node);if(!node){return null;}
var method=function(el){return el.tagName&&el.tagName.toUpperCase()==tagName.toUpperCase();};return Y.Dom.getAncestorBy(node,method);},getPreviousSiblingBy:function(node,method){while(node){node=node.previousSibling;if(testElement(node,method)){return node;}}
return null;},getPreviousSibling:function(node){node=Y.Dom.get(node);if(!node){return null;}
return Y.Dom.getPreviousSiblingBy(node);},getNextSiblingBy:function(node,method){while(node){node=node.nextSibling;if(testElement(node,method)){return node;}}
return null;},getNextSibling:function(node){node=Y.Dom.get(node);if(!node){return null;}
return Y.Dom.getNextSiblingBy(node);},getFirstChildBy:function(node,method){var child=(testElement(node.firstChild,method))?node.firstChild:null;return child||Y.Dom.getNextSiblingBy(node.firstChild,method);},getFirstChild:function(node,method){node=Y.Dom.get(node);if(!node){return null;}
return Y.Dom.getFirstChildBy(node);},getLastChildBy:function(node,method){if(!node){return null;}
var child=(testElement(node.lastChild,method))?node.lastChild:null;return child||Y.Dom.getPreviousSiblingBy(node.lastChild,method);},getLastChild:function(node){node=Y.Dom.get(node);return Y.Dom.getLastChildBy(node);},getChildrenBy:function(node,method){var child=Y.Dom.getFirstChildBy(node,method);var children=child?[child]:[];Y.Dom.getNextSiblingBy(child,function(node){if(!method||method(node)){children[children.length]=node;}
return false;});return children;},getChildren:function(node){node=Y.Dom.get(node);if(!node){}
return Y.Dom.getChildrenBy(node);},getDocumentScrollLeft:function(doc){doc=doc||document;return Math.max(doc.documentElement.scrollLeft,doc.body.scrollLeft);},getDocumentScrollTop:function(doc){doc=doc||document;return Math.max(doc.documentElement.scrollTop,doc.body.scrollTop);},insertBefore:function(newNode,referenceNode){newNode=Y.Dom.get(newNode);referenceNode=Y.Dom.get(referenceNode);if(!newNode||!referenceNode||!referenceNode.parentNode){return null;}
return referenceNode.parentNode.insertBefore(newNode,referenceNode);},insertAfter:function(newNode,referenceNode){newNode=Y.Dom.get(newNode);referenceNode=Y.Dom.get(referenceNode);if(!newNode||!referenceNode||!referenceNode.parentNode){return null;}
if(referenceNode.nextSibling){return referenceNode.parentNode.insertBefore(newNode,referenceNode.nextSibling);}else{return referenceNode.parentNode.appendChild(newNode);}}};})();YAHOO.util.Region=function(t,r,b,l){this.top=t;this[1]=t;this.right=r;this.bottom=b;this.left=l;this[0]=l;};YAHOO.util.Region.prototype.contains=function(region){return(region.left>=this.left&&region.right<=this.right&&region.top>=this.top&&region.bottom<=this.bottom);};YAHOO.util.Region.prototype.getArea=function(){return((this.bottom-this.top)*(this.right-this.left));};YAHOO.util.Region.prototype.intersect=function(region){var t=Math.max(this.top,region.top);var r=Math.min(this.right,region.right);var b=Math.min(this.bottom,region.bottom);var l=Math.max(this.left,region.left);if(b>=t&&r>=l){return new YAHOO.util.Region(t,r,b,l);}else{return null;}};YAHOO.util.Region.prototype.union=function(region){var t=Math.min(this.top,region.top);var r=Math.max(this.right,region.right);var b=Math.max(this.bottom,region.bottom);var l=Math.min(this.left,region.left);return new YAHOO.util.Region(t,r,b,l);};YAHOO.util.Region.prototype.toString=function(){return("Region {"+"top: "+this.top+", right: "+this.right+", bottom: "+this.bottom+", left: "+this.left+"}");};YAHOO.util.Region.getRegion=function(el){var p=YAHOO.util.Dom.getXY(el);var t=p[1];var r=p[0]+el.offsetWidth;var b=p[1]+el.offsetHeight;var l=p[0];return new YAHOO.util.Region(t,r,b,l);};YAHOO.util.Point=function(x,y){if(YAHOO.lang.isArray(x)){y=x[1];x=x[0];}
this.x=this.right=this.left=this[0]=x;this.y=this.top=this.bottom=this[1]=y;};YAHOO.util.Point.prototype=new YAHOO.util.Region();YAHOO.register("dom",YAHOO.util.Dom,{version:"2.3.0",build:"442"});
YAHOO.util.CustomEvent=function(type,oScope,silent,signature){this.type=type;this.scope=oScope||window;this.silent=silent;this.signature=signature||YAHOO.util.CustomEvent.LIST;this.subscribers=[];if(!this.silent){}
var onsubscribeType="_YUICEOnSubscribe";if(type!==onsubscribeType){this.subscribeEvent=new YAHOO.util.CustomEvent(onsubscribeType,this,true);}};YAHOO.util.CustomEvent.LIST=0;YAHOO.util.CustomEvent.FLAT=1;YAHOO.util.CustomEvent.prototype={subscribe:function(fn,obj,override){if(!fn){throw new Error("Invalid callback for subscriber to '"+this.type+"'");}
if(this.subscribeEvent){this.subscribeEvent.fire(fn,obj,override);}
this.subscribers.push(new YAHOO.util.Subscriber(fn,obj,override));},unsubscribe:function(fn,obj){if(!fn){return this.unsubscribeAll();}
var found=false;for(var i=0,len=this.subscribers.length;i<len;++i){var s=this.subscribers[i];if(s&&s.contains(fn,obj)){this._delete(i);found=true;}}
return found;},fire:function(){var len=this.subscribers.length;if(!len&&this.silent){return true;}
var args=[],ret=true,i,rebuild=false;for(i=0;i<arguments.length;++i){args.push(arguments[i]);}
var argslength=args.length;if(!this.silent){}
for(i=0;i<len;++i){var s=this.subscribers[i];if(!s){rebuild=true;}else{if(!this.silent){}
var scope=s.getScope(this.scope);if(this.signature==YAHOO.util.CustomEvent.FLAT){var param=null;if(args.length>0){param=args[0];}
ret=s.fn.call(scope,param,s.obj);}else{ret=s.fn.call(scope,this.type,args,s.obj);}
if(false===ret){if(!this.silent){}
return false;}}}
if(rebuild){var newlist=[],subs=this.subscribers;for(i=0,len=subs.length;i<len;++i){s=subs[i];newlist.push(subs[i]);}
this.subscribers=newlist;}
return true;},unsubscribeAll:function(){for(var i=0,len=this.subscribers.length;i<len;++i){this._delete(len-1-i);}
this.subscribers=[];return i;},_delete:function(index){var s=this.subscribers[index];if(s){delete s.fn;delete s.obj;}
this.subscribers[index]=null;},toString:function(){return"CustomEvent: "+"'"+this.type+"', "+"scope: "+this.scope;}};YAHOO.util.Subscriber=function(fn,obj,override){this.fn=fn;this.obj=YAHOO.lang.isUndefined(obj)?null:obj;this.override=override;};YAHOO.util.Subscriber.prototype.getScope=function(defaultScope){if(this.override){if(this.override===true){return this.obj;}else{return this.override;}}
return defaultScope;};YAHOO.util.Subscriber.prototype.contains=function(fn,obj){if(obj){return(this.fn==fn&&this.obj==obj);}else{return(this.fn==fn);}};YAHOO.util.Subscriber.prototype.toString=function(){return"Subscriber { obj: "+this.obj+", override: "+(this.override||"no")+" }";};if(!YAHOO.util.Event){YAHOO.util.Event=function(){var loadComplete=false;var DOMReady=false;var listeners=[];var unloadListeners=[];var legacyEvents=[];var legacyHandlers=[];var retryCount=0;var onAvailStack=[];var legacyMap=[];var counter=0;var webkitKeymap={63232:38,63233:40,63234:37,63235:39};return{POLL_RETRYS:4000,POLL_INTERVAL:10,EL:0,TYPE:1,FN:2,WFN:3,OBJ:3,ADJ_SCOPE:4,lastError:null,isSafari:YAHOO.env.ua.webkit,webkit:YAHOO.env.ua.webkit,isIE:YAHOO.env.ua.ie,_interval:null,startInterval:function(){if(!this._interval){var self=this;var callback=function(){self._tryPreloadAttach();};this._interval=setInterval(callback,this.POLL_INTERVAL);}},onAvailable:function(p_id,p_fn,p_obj,p_override){onAvailStack.push({id:p_id,fn:p_fn,obj:p_obj,override:p_override,checkReady:false});retryCount=this.POLL_RETRYS;this.startInterval();},onDOMReady:function(p_fn,p_obj,p_override){if(DOMReady){setTimeout(function(){var s=window;if(p_override){if(p_override===true){s=p_obj;}else{s=p_override;}}
p_fn.call(s,"DOMReady",[],p_obj);},0);}else{this.DOMReadyEvent.subscribe(p_fn,p_obj,p_override);}},onContentReady:function(p_id,p_fn,p_obj,p_override){onAvailStack.push({id:p_id,fn:p_fn,obj:p_obj,override:p_override,checkReady:true});retryCount=this.POLL_RETRYS;this.startInterval();},addListener:function(el,sType,fn,obj,override){if(!fn||!fn.call){return false;}
if(this._isValidCollection(el)){var ok=true;for(var i=0,len=el.length;i<len;++i){ok=this.on(el[i],sType,fn,obj,override)&&ok;}
return ok;}else if(YAHOO.lang.isString(el)){var oEl=this.getEl(el);if(oEl){el=oEl;}else{this.onAvailable(el,function(){YAHOO.util.Event.on(el,sType,fn,obj,override);});return true;}}
if(!el){return false;}
if("unload"==sType&&obj!==this){unloadListeners[unloadListeners.length]=[el,sType,fn,obj,override];return true;}
var scope=el;if(override){if(override===true){scope=obj;}else{scope=override;}}
var wrappedFn=function(e){return fn.call(scope,YAHOO.util.Event.getEvent(e),obj);};var li=[el,sType,fn,wrappedFn,scope];var index=listeners.length;listeners[index]=li;if(this.useLegacyEvent(el,sType)){var legacyIndex=this.getLegacyIndex(el,sType);if(legacyIndex==-1||el!=legacyEvents[legacyIndex][0]){legacyIndex=legacyEvents.length;legacyMap[el.id+sType]=legacyIndex;legacyEvents[legacyIndex]=[el,sType,el["on"+sType]];legacyHandlers[legacyIndex]=[];el["on"+sType]=function(e){YAHOO.util.Event.fireLegacyEvent(YAHOO.util.Event.getEvent(e),legacyIndex);};}
legacyHandlers[legacyIndex].push(li);}else{try{this._simpleAdd(el,sType,wrappedFn,false);}catch(ex){this.lastError=ex;this.removeListener(el,sType,fn);return false;}}
return true;},fireLegacyEvent:function(e,legacyIndex){var ok=true,le,lh,li,scope,ret;lh=legacyHandlers[legacyIndex];for(var i=0,len=lh.length;i<len;++i){li=lh[i];if(li&&li[this.WFN]){scope=li[this.ADJ_SCOPE];ret=li[this.WFN].call(scope,e);ok=(ok&&ret);}}
le=legacyEvents[legacyIndex];if(le&&le[2]){le[2](e);}
return ok;},getLegacyIndex:function(el,sType){var key=this.generateId(el)+sType;if(typeof legacyMap[key]=="undefined"){return-1;}else{return legacyMap[key];}},useLegacyEvent:function(el,sType){if(this.webkit&&("click"==sType||"dblclick"==sType)){var v=parseInt(this.webkit,10);if(!isNaN(v)&&v<418){return true;}}
return false;},removeListener:function(el,sType,fn){var i,len;if(typeof el=="string"){el=this.getEl(el);}else if(this._isValidCollection(el)){var ok=true;for(i=0,len=el.length;i<len;++i){ok=(this.removeListener(el[i],sType,fn)&&ok);}
return ok;}
if(!fn||!fn.call){return this.purgeElement(el,false,sType);}
if("unload"==sType){for(i=0,len=unloadListeners.length;i<len;i++){var li=unloadListeners[i];if(li&&li[0]==el&&li[1]==sType&&li[2]==fn){unloadListeners[i]=null;return true;}}
return false;}
var cacheItem=null;var index=arguments[3];if("undefined"==typeof index){index=this._getCacheIndex(el,sType,fn);}
if(index>=0){cacheItem=listeners[index];}
if(!el||!cacheItem){return false;}
if(this.useLegacyEvent(el,sType)){var legacyIndex=this.getLegacyIndex(el,sType);var llist=legacyHandlers[legacyIndex];if(llist){for(i=0,len=llist.length;i<len;++i){li=llist[i];if(li&&li[this.EL]==el&&li[this.TYPE]==sType&&li[this.FN]==fn){llist[i]=null;break;}}}}else{try{this._simpleRemove(el,sType,cacheItem[this.WFN],false);}catch(ex){this.lastError=ex;return false;}}
delete listeners[index][this.WFN];delete listeners[index][this.FN];listeners[index]=null;return true;},getTarget:function(ev,resolveTextNode){var t=ev.target||ev.srcElement;return this.resolveTextNode(t);},resolveTextNode:function(node){if(node&&3==node.nodeType){return node.parentNode;}else{return node;}},getPageX:function(ev){var x=ev.pageX;if(!x&&0!==x){x=ev.clientX||0;if(this.isIE){x+=this._getScrollLeft();}}
return x;},getPageY:function(ev){var y=ev.pageY;if(!y&&0!==y){y=ev.clientY||0;if(this.isIE){y+=this._getScrollTop();}}
return y;},getXY:function(ev){return[this.getPageX(ev),this.getPageY(ev)];},getRelatedTarget:function(ev){var t=ev.relatedTarget;if(!t){if(ev.type=="mouseout"){t=ev.toElement;}else if(ev.type=="mouseover"){t=ev.fromElement;}}
return this.resolveTextNode(t);},getTime:function(ev){if(!ev.time){var t=new Date().getTime();try{ev.time=t;}catch(ex){this.lastError=ex;return t;}}
return ev.time;},stopEvent:function(ev){this.stopPropagation(ev);this.preventDefault(ev);},stopPropagation:function(ev){if(ev.stopPropagation){ev.stopPropagation();}else{ev.cancelBubble=true;}},preventDefault:function(ev){if(ev.preventDefault){ev.preventDefault();}else{ev.returnValue=false;}},getEvent:function(e){var ev=e||window.event;if(!ev){var c=this.getEvent.caller;while(c){ev=c.arguments[0];if(ev&&Event==ev.constructor){break;}
c=c.caller;}}
return ev;},getCharCode:function(ev){var code=ev.keyCode||ev.charCode||0;if(YAHOO.env.ua.webkit&&(code in webkitKeymap)){code=webkitKeymap[code];}
return code;},_getCacheIndex:function(el,sType,fn){for(var i=0,len=listeners.length;i<len;++i){var li=listeners[i];if(li&&li[this.FN]==fn&&li[this.EL]==el&&li[this.TYPE]==sType){return i;}}
return-1;},generateId:function(el){var id=el.id;if(!id){id="yuievtautoid-"+counter;++counter;el.id=id;}
return id;},_isValidCollection:function(o){try{return(o&&o.length&&typeof o!="string"&&!o.tagName&&!o.alert&&typeof o[0]!="undefined");}catch(e){return false;}},elCache:{},getEl:function(id){return document.getElementById(id);},clearCache:function(){},DOMReadyEvent:new YAHOO.util.CustomEvent("DOMReady",this),_load:function(e){if(!loadComplete){loadComplete=true;var EU=YAHOO.util.Event;EU._ready();EU._tryPreloadAttach();}},_ready:function(e){if(!DOMReady){DOMReady=true;var EU=YAHOO.util.Event;EU.DOMReadyEvent.fire();EU._simpleRemove(document,"DOMContentLoaded",EU._ready);}},_tryPreloadAttach:function(){if(this.locked){return false;}
if(this.isIE){if(!DOMReady){this.startInterval();return false;}}
this.locked=true;var tryAgain=!loadComplete;if(!tryAgain){tryAgain=(retryCount>0);}
var notAvail=[];var executeItem=function(el,item){var scope=el;if(item.override){if(item.override===true){scope=item.obj;}else{scope=item.override;}}
item.fn.call(scope,item.obj);};var i,len,item,el;for(i=0,len=onAvailStack.length;i<len;++i){item=onAvailStack[i];if(item&&!item.checkReady){el=this.getEl(item.id);if(el){executeItem(el,item);onAvailStack[i]=null;}else{notAvail.push(item);}}}
for(i=0,len=onAvailStack.length;i<len;++i){item=onAvailStack[i];if(item&&item.checkReady){el=this.getEl(item.id);if(el){if(loadComplete||el.nextSibling){executeItem(el,item);onAvailStack[i]=null;}}else{notAvail.push(item);}}}
retryCount=(notAvail.length===0)?0:retryCount-1;if(tryAgain){this.startInterval();}else{clearInterval(this._interval);this._interval=null;}
this.locked=false;return true;},purgeElement:function(el,recurse,sType){var elListeners=this.getListeners(el,sType);if(elListeners){for(var i=0,len=elListeners.length;i<len;++i){var l=elListeners[i];this.removeListener(el,l.type,l.fn,l.index);}}
if(recurse&&el&&el.childNodes){for(i=0,len=el.childNodes.length;i<len;++i){this.purgeElement(el.childNodes[i],recurse,sType);}}},getListeners:function(el,sType){var results=[],searchLists;if(!sType){searchLists=[listeners,unloadListeners];}else if(sType=="unload"){searchLists=[unloadListeners];}else{searchLists=[listeners];}
for(var j=0;j<searchLists.length;++j){var searchList=searchLists[j];if(searchList&&searchList.length>0){for(var i=0,len=searchList.length;i<len;++i){var l=searchList[i];if(l&&l[this.EL]===el&&(!sType||sType===l[this.TYPE])){results.push({type:l[this.TYPE],fn:l[this.FN],obj:l[this.OBJ],adjust:l[this.ADJ_SCOPE],index:i});}}}}
return(results.length)?results:null;},_unload:function(e){var EU=YAHOO.util.Event,i,j,l,len,index;for(i=0,len=unloadListeners.length;i<len;++i){l=unloadListeners[i];if(l){var scope=window;if(l[EU.ADJ_SCOPE]){if(l[EU.ADJ_SCOPE]===true){scope=l[EU.OBJ];}else{scope=l[EU.ADJ_SCOPE];}}
l[EU.FN].call(scope,EU.getEvent(e),l[EU.OBJ]);unloadListeners[i]=null;l=null;scope=null;}}
unloadListeners=null;if(listeners&&listeners.length>0){j=listeners.length;while(j){index=j-1;l=listeners[index];if(l){EU.removeListener(l[EU.EL],l[EU.TYPE],l[EU.FN],index);}
j=j-1;}
l=null;EU.clearCache();}
for(i=0,len=legacyEvents.length;i<len;++i){legacyEvents[i][0]=null;legacyEvents[i]=null;}
legacyEvents=null;EU._simpleRemove(window,"unload",EU._unload);},_getScrollLeft:function(){return this._getScroll()[1];},_getScrollTop:function(){return this._getScroll()[0];},_getScroll:function(){var dd=document.documentElement,db=document.body;if(dd&&(dd.scrollTop||dd.scrollLeft)){return[dd.scrollTop,dd.scrollLeft];}else if(db){return[db.scrollTop,db.scrollLeft];}else{return[0,0];}},regCE:function(){},_simpleAdd:function(){if(window.addEventListener){return function(el,sType,fn,capture){el.addEventListener(sType,fn,(capture));};}else if(window.attachEvent){return function(el,sType,fn,capture){el.attachEvent("on"+sType,fn);};}else{return function(){};}}(),_simpleRemove:function(){if(window.removeEventListener){return function(el,sType,fn,capture){el.removeEventListener(sType,fn,(capture));};}else if(window.detachEvent){return function(el,sType,fn){el.detachEvent("on"+sType,fn);};}else{return function(){};}}()};}();(function(){var EU=YAHOO.util.Event;EU.on=EU.addListener;if(EU.isIE){YAHOO.util.Event.onDOMReady(YAHOO.util.Event._tryPreloadAttach,YAHOO.util.Event,true);var el,d=document,b=d.body;if(("undefined"!==typeof YAHOO_config)&&YAHOO_config.injecting){el=document.createElement("script");var p=d.getElementsByTagName("head")[0]||b;p.insertBefore(el,p.firstChild);}else{d.write('<scr'+'ipt id="_yui_eu_dr" defer="true" src="//:"><'+'/script>');el=document.getElementById("_yui_eu_dr");}
if(el){el.onreadystatechange=function(){if("complete"===this.readyState){this.parentNode.removeChild(this);YAHOO.util.Event._ready();}};}else{}
el=null;}else if(EU.webkit){EU._drwatch=setInterval(function(){var rs=document.readyState;if("loaded"==rs||"complete"==rs){clearInterval(EU._drwatch);EU._drwatch=null;EU._ready();}},EU.POLL_INTERVAL);}else{EU._simpleAdd(document,"DOMContentLoaded",EU._ready);}
EU._simpleAdd(window,"load",EU._load);EU._simpleAdd(window,"unload",EU._unload);EU._tryPreloadAttach();})();}
YAHOO.util.EventProvider=function(){};YAHOO.util.EventProvider.prototype={__yui_events:null,__yui_subscribers:null,subscribe:function(p_type,p_fn,p_obj,p_override){this.__yui_events=this.__yui_events||{};var ce=this.__yui_events[p_type];if(ce){ce.subscribe(p_fn,p_obj,p_override);}else{this.__yui_subscribers=this.__yui_subscribers||{};var subs=this.__yui_subscribers;if(!subs[p_type]){subs[p_type]=[];}
subs[p_type].push({fn:p_fn,obj:p_obj,override:p_override});}},unsubscribe:function(p_type,p_fn,p_obj){this.__yui_events=this.__yui_events||{};var evts=this.__yui_events;if(p_type){var ce=evts[p_type];if(ce){return ce.unsubscribe(p_fn,p_obj);}}else{for(var i in evts){var ret=true;if(YAHOO.lang.hasOwnProperty(evts,i)){ret=ret&&evts[i].unsubscribe(p_fn,p_obj);}}
return ret;}
return false;},unsubscribeAll:function(p_type){return this.unsubscribe(p_type);},createEvent:function(p_type,p_config){this.__yui_events=this.__yui_events||{};var opts=p_config||{};var events=this.__yui_events;if(events[p_type]){}else{var scope=opts.scope||this;var silent=(opts.silent);var ce=new YAHOO.util.CustomEvent(p_type,scope,silent,YAHOO.util.CustomEvent.FLAT);events[p_type]=ce;if(opts.onSubscribeCallback){ce.subscribeEvent.subscribe(opts.onSubscribeCallback);}
this.__yui_subscribers=this.__yui_subscribers||{};var qs=this.__yui_subscribers[p_type];if(qs){for(var i=0;i<qs.length;++i){ce.subscribe(qs[i].fn,qs[i].obj,qs[i].override);}}}
return events[p_type];},fireEvent:function(p_type,arg1,arg2,etc){this.__yui_events=this.__yui_events||{};var ce=this.__yui_events[p_type];if(!ce){return null;}
var args=[];for(var i=1;i<arguments.length;++i){args.push(arguments[i]);}
return ce.fire.apply(ce,args);},hasEvent:function(type){if(this.__yui_events){if(this.__yui_events[type]){return true;}}
return false;}};YAHOO.util.KeyListener=function(attachTo,keyData,handler,event){if(!attachTo){}else if(!keyData){}else if(!handler){}
if(!event){event=YAHOO.util.KeyListener.KEYDOWN;}
var keyEvent=new YAHOO.util.CustomEvent("keyPressed");this.enabledEvent=new YAHOO.util.CustomEvent("enabled");this.disabledEvent=new YAHOO.util.CustomEvent("disabled");if(typeof attachTo=='string'){attachTo=document.getElementById(attachTo);}
if(typeof handler=='function'){keyEvent.subscribe(handler);}else{keyEvent.subscribe(handler.fn,handler.scope,handler.correctScope);}
function handleKeyPress(e,obj){if(!keyData.shift){keyData.shift=false;}
if(!keyData.alt){keyData.alt=false;}
if(!keyData.ctrl){keyData.ctrl=false;}
if(e.shiftKey==keyData.shift&&e.altKey==keyData.alt&&e.ctrlKey==keyData.ctrl){var dataItem;var keyPressed;if(keyData.keys instanceof Array){for(var i=0;i<keyData.keys.length;i++){dataItem=keyData.keys[i];if(dataItem==e.charCode){keyEvent.fire(e.charCode,e);break;}else if(dataItem==e.keyCode){keyEvent.fire(e.keyCode,e);break;}}}else{dataItem=keyData.keys;if(dataItem==e.charCode){keyEvent.fire(e.charCode,e);}else if(dataItem==e.keyCode){keyEvent.fire(e.keyCode,e);}}}}
this.enable=function(){if(!this.enabled){YAHOO.util.Event.addListener(attachTo,event,handleKeyPress);this.enabledEvent.fire(keyData);}
this.enabled=true;};this.disable=function(){if(this.enabled){YAHOO.util.Event.removeListener(attachTo,event,handleKeyPress);this.disabledEvent.fire(keyData);}
this.enabled=false;};this.toString=function(){return"KeyListener ["+keyData.keys+"] "+attachTo.tagName+
(attachTo.id?"["+attachTo.id+"]":"");};};YAHOO.util.KeyListener.KEYDOWN="keydown";YAHOO.util.KeyListener.KEYUP="keyup";YAHOO.register("event",YAHOO.util.Event,{version:"2.3.0",build:"442"});YAHOO.register("yahoo-dom-event", YAHOO, {version: "2.3.0", build: "442"});
/*
Copyright (c) 2007, Yahoo! Inc. All rights reserved.
Code licensed under the BSD License:
http://developer.yahoo.net/yui/license.txt
version: 2.3.0
*/

if(!YAHOO.util.DragDropMgr){YAHOO.util.DragDropMgr=function(){var Event=YAHOO.util.Event;return{ids:{},handleIds:{},dragCurrent:null,dragOvers:{},deltaX:0,deltaY:0,preventDefault:true,stopPropagation:true,initialized:false,locked:false,interactionInfo:null,init:function(){this.initialized=true;},POINT:0,INTERSECT:1,STRICT_INTERSECT:2,mode:0,_execOnAll:function(sMethod,args){for(var i in this.ids){for(var j in this.ids[i]){var oDD=this.ids[i][j];if(!this.isTypeOfDD(oDD)){continue;}
oDD[sMethod].apply(oDD,args);}}},_onLoad:function(){this.init();Event.on(document,"mouseup",this.handleMouseUp,this,true);Event.on(document,"mousemove",this.handleMouseMove,this,true);Event.on(window,"unload",this._onUnload,this,true);Event.on(window,"resize",this._onResize,this,true);},_onResize:function(e){this._execOnAll("resetConstraints",[]);},lock:function(){this.locked=true;},unlock:function(){this.locked=false;},isLocked:function(){return this.locked;},locationCache:{},useCache:true,clickPixelThresh:3,clickTimeThresh:1000,dragThreshMet:false,clickTimeout:null,startX:0,startY:0,regDragDrop:function(oDD,sGroup){if(!this.initialized){this.init();}
if(!this.ids[sGroup]){this.ids[sGroup]={};}
this.ids[sGroup][oDD.id]=oDD;},removeDDFromGroup:function(oDD,sGroup){if(!this.ids[sGroup]){this.ids[sGroup]={};}
var obj=this.ids[sGroup];if(obj&&obj[oDD.id]){delete obj[oDD.id];}},_remove:function(oDD){for(var g in oDD.groups){if(g&&this.ids[g][oDD.id]){delete this.ids[g][oDD.id];}}
delete this.handleIds[oDD.id];},regHandle:function(sDDId,sHandleId){if(!this.handleIds[sDDId]){this.handleIds[sDDId]={};}
this.handleIds[sDDId][sHandleId]=sHandleId;},isDragDrop:function(id){return(this.getDDById(id))?true:false;},getRelated:function(p_oDD,bTargetsOnly){var oDDs=[];for(var i in p_oDD.groups){for(j in this.ids[i]){var dd=this.ids[i][j];if(!this.isTypeOfDD(dd)){continue;}
if(!bTargetsOnly||dd.isTarget){oDDs[oDDs.length]=dd;}}}
return oDDs;},isLegalTarget:function(oDD,oTargetDD){var targets=this.getRelated(oDD,true);for(var i=0,len=targets.length;i<len;++i){if(targets[i].id==oTargetDD.id){return true;}}
return false;},isTypeOfDD:function(oDD){return(oDD&&oDD.__ygDragDrop);},isHandle:function(sDDId,sHandleId){return(this.handleIds[sDDId]&&this.handleIds[sDDId][sHandleId]);},getDDById:function(id){for(var i in this.ids){if(this.ids[i][id]){return this.ids[i][id];}}
return null;},handleMouseDown:function(e,oDD){this.currentTarget=YAHOO.util.Event.getTarget(e);this.dragCurrent=oDD;var el=oDD.getEl();this.startX=YAHOO.util.Event.getPageX(e);this.startY=YAHOO.util.Event.getPageY(e);this.deltaX=this.startX-el.offsetLeft;this.deltaY=this.startY-el.offsetTop;this.dragThreshMet=false;this.clickTimeout=setTimeout(function(){var DDM=YAHOO.util.DDM;DDM.startDrag(DDM.startX,DDM.startY);},this.clickTimeThresh);},startDrag:function(x,y){clearTimeout(this.clickTimeout);var dc=this.dragCurrent;if(dc){dc.b4StartDrag(x,y);}
if(dc){dc.startDrag(x,y);}
this.dragThreshMet=true;},handleMouseUp:function(e){if(this.dragCurrent){clearTimeout(this.clickTimeout);if(this.dragThreshMet){this.fireEvents(e,true);}else{}
this.stopDrag(e);this.stopEvent(e);}},stopEvent:function(e){if(this.stopPropagation){YAHOO.util.Event.stopPropagation(e);}
if(this.preventDefault){YAHOO.util.Event.preventDefault(e);}},stopDrag:function(e,silent){if(this.dragCurrent&&!silent){if(this.dragThreshMet){this.dragCurrent.b4EndDrag(e);this.dragCurrent.endDrag(e);}
this.dragCurrent.onMouseUp(e);}
this.dragCurrent=null;this.dragOvers={};},handleMouseMove:function(e){var dc=this.dragCurrent;if(dc){if(YAHOO.util.Event.isIE&&!e.button){this.stopEvent(e);return this.handleMouseUp(e);}
if(!this.dragThreshMet){var diffX=Math.abs(this.startX-YAHOO.util.Event.getPageX(e));var diffY=Math.abs(this.startY-YAHOO.util.Event.getPageY(e));if(diffX>this.clickPixelThresh||diffY>this.clickPixelThresh){this.startDrag(this.startX,this.startY);}}
if(this.dragThreshMet){dc.b4Drag(e);if(dc){dc.onDrag(e);}
if(dc){this.fireEvents(e,false);}}
this.stopEvent(e);}},fireEvents:function(e,isDrop){var dc=this.dragCurrent;if(!dc||dc.isLocked()){return;}
var x=YAHOO.util.Event.getPageX(e);var y=YAHOO.util.Event.getPageY(e);var pt=new YAHOO.util.Point(x,y);var pos=dc.getTargetCoord(pt.x,pt.y);var el=dc.getDragEl();curRegion=new YAHOO.util.Region(pos.y,pos.x+el.offsetWidth,pos.y+el.offsetHeight,pos.x);var oldOvers=[];var outEvts=[];var overEvts=[];var dropEvts=[];var enterEvts=[];for(var i in this.dragOvers){var ddo=this.dragOvers[i];if(!this.isTypeOfDD(ddo)){continue;}
if(!this.isOverTarget(pt,ddo,this.mode,curRegion)){outEvts.push(ddo);}
oldOvers[i]=true;delete this.dragOvers[i];}
for(var sGroup in dc.groups){if("string"!=typeof sGroup){continue;}
for(i in this.ids[sGroup]){var oDD=this.ids[sGroup][i];if(!this.isTypeOfDD(oDD)){continue;}
if(oDD.isTarget&&!oDD.isLocked()&&oDD!=dc){if(this.isOverTarget(pt,oDD,this.mode,curRegion)){if(isDrop){dropEvts.push(oDD);}else{if(!oldOvers[oDD.id]){enterEvts.push(oDD);}else{overEvts.push(oDD);}
this.dragOvers[oDD.id]=oDD;}}}}}
this.interactionInfo={out:outEvts,enter:enterEvts,over:overEvts,drop:dropEvts,point:pt,draggedRegion:curRegion,sourceRegion:this.locationCache[dc.id],validDrop:isDrop};if(isDrop&&!dropEvts.length){this.interactionInfo.validDrop=false;dc.onInvalidDrop(e);}
if(this.mode){if(outEvts.length){dc.b4DragOut(e,outEvts);if(dc){dc.onDragOut(e,outEvts);}}
if(enterEvts.length){if(dc){dc.onDragEnter(e,enterEvts);}}
if(overEvts.length){if(dc){dc.b4DragOver(e,overEvts);}
if(dc){dc.onDragOver(e,overEvts);}}
if(dropEvts.length){if(dc){dc.b4DragDrop(e,dropEvts);}
if(dc){dc.onDragDrop(e,dropEvts);}}}else{var len=0;for(i=0,len=outEvts.length;i<len;++i){if(dc){dc.b4DragOut(e,outEvts[i].id);}
if(dc){dc.onDragOut(e,outEvts[i].id);}}
for(i=0,len=enterEvts.length;i<len;++i){if(dc){dc.onDragEnter(e,enterEvts[i].id);}}
for(i=0,len=overEvts.length;i<len;++i){if(dc){dc.b4DragOver(e,overEvts[i].id);}
if(dc){dc.onDragOver(e,overEvts[i].id);}}
for(i=0,len=dropEvts.length;i<len;++i){if(dc){dc.b4DragDrop(e,dropEvts[i].id);}
if(dc){dc.onDragDrop(e,dropEvts[i].id);}}}},getBestMatch:function(dds){var winner=null;var len=dds.length;if(len==1){winner=dds[0];}else{for(var i=0;i<len;++i){var dd=dds[i];if(this.mode==this.INTERSECT&&dd.cursorIsOver){winner=dd;break;}else{if(!winner||!winner.overlap||(dd.overlap&&winner.overlap.getArea()<dd.overlap.getArea())){winner=dd;}}}}
return winner;},refreshCache:function(groups){var g=groups||this.ids;for(var sGroup in g){if("string"!=typeof sGroup){continue;}
for(var i in this.ids[sGroup]){var oDD=this.ids[sGroup][i];if(this.isTypeOfDD(oDD)){var loc=this.getLocation(oDD);if(loc){this.locationCache[oDD.id]=loc;}else{delete this.locationCache[oDD.id];}}}}},verifyEl:function(el){try{if(el){var parent=el.offsetParent;if(parent){return true;}}}catch(e){}
return false;},getLocation:function(oDD){if(!this.isTypeOfDD(oDD)){return null;}
var el=oDD.getEl(),pos,x1,x2,y1,y2,t,r,b,l;try{pos=YAHOO.util.Dom.getXY(el);}catch(e){}
if(!pos){return null;}
x1=pos[0];x2=x1+el.offsetWidth;y1=pos[1];y2=y1+el.offsetHeight;t=y1-oDD.padding[0];r=x2+oDD.padding[1];b=y2+oDD.padding[2];l=x1-oDD.padding[3];return new YAHOO.util.Region(t,r,b,l);},isOverTarget:function(pt,oTarget,intersect,curRegion){var loc=this.locationCache[oTarget.id];if(!loc||!this.useCache){loc=this.getLocation(oTarget);this.locationCache[oTarget.id]=loc;}
if(!loc){return false;}
oTarget.cursorIsOver=loc.contains(pt);var dc=this.dragCurrent;if(!dc||(!intersect&&!dc.constrainX&&!dc.constrainY)){return oTarget.cursorIsOver;}
oTarget.overlap=null;if(!curRegion){var pos=dc.getTargetCoord(pt.x,pt.y);var el=dc.getDragEl();curRegion=new YAHOO.util.Region(pos.y,pos.x+el.offsetWidth,pos.y+el.offsetHeight,pos.x);}
var overlap=curRegion.intersect(loc);if(overlap){oTarget.overlap=overlap;return(intersect)?true:oTarget.cursorIsOver;}else{return false;}},_onUnload:function(e,me){this.unregAll();},unregAll:function(){if(this.dragCurrent){this.stopDrag();this.dragCurrent=null;}
this._execOnAll("unreg",[]);for(i in this.elementCache){delete this.elementCache[i];}
this.elementCache={};this.ids={};},elementCache:{},getElWrapper:function(id){var oWrapper=this.elementCache[id];if(!oWrapper||!oWrapper.el){oWrapper=this.elementCache[id]=new this.ElementWrapper(YAHOO.util.Dom.get(id));}
return oWrapper;},getElement:function(id){return YAHOO.util.Dom.get(id);},getCss:function(id){var el=YAHOO.util.Dom.get(id);return(el)?el.style:null;},ElementWrapper:function(el){this.el=el||null;this.id=this.el&&el.id;this.css=this.el&&el.style;},getPosX:function(el){return YAHOO.util.Dom.getX(el);},getPosY:function(el){return YAHOO.util.Dom.getY(el);},swapNode:function(n1,n2){if(n1.swapNode){n1.swapNode(n2);}else{var p=n2.parentNode;var s=n2.nextSibling;if(s==n1){p.insertBefore(n1,n2);}else if(n2==n1.nextSibling){p.insertBefore(n2,n1);}else{n1.parentNode.replaceChild(n2,n1);p.insertBefore(n1,s);}}},getScroll:function(){var t,l,dde=document.documentElement,db=document.body;if(dde&&(dde.scrollTop||dde.scrollLeft)){t=dde.scrollTop;l=dde.scrollLeft;}else if(db){t=db.scrollTop;l=db.scrollLeft;}else{}
return{top:t,left:l};},getStyle:function(el,styleProp){return YAHOO.util.Dom.getStyle(el,styleProp);},getScrollTop:function(){return this.getScroll().top;},getScrollLeft:function(){return this.getScroll().left;},moveToEl:function(moveEl,targetEl){var aCoord=YAHOO.util.Dom.getXY(targetEl);YAHOO.util.Dom.setXY(moveEl,aCoord);},getClientHeight:function(){return YAHOO.util.Dom.getViewportHeight();},getClientWidth:function(){return YAHOO.util.Dom.getViewportWidth();},numericSort:function(a,b){return(a-b);},_timeoutCount:0,_addListeners:function(){var DDM=YAHOO.util.DDM;if(YAHOO.util.Event&&document){DDM._onLoad();}else{if(DDM._timeoutCount>2000){}else{setTimeout(DDM._addListeners,10);if(document&&document.body){DDM._timeoutCount+=1;}}}},handleWasClicked:function(node,id){if(this.isHandle(id,node.id)){return true;}else{var p=node.parentNode;while(p){if(this.isHandle(id,p.id)){return true;}else{p=p.parentNode;}}}
return false;}};}();YAHOO.util.DDM=YAHOO.util.DragDropMgr;YAHOO.util.DDM._addListeners();}
(function(){var Event=YAHOO.util.Event;var Dom=YAHOO.util.Dom;YAHOO.util.DragDrop=function(id,sGroup,config){if(id){this.init(id,sGroup,config);}};YAHOO.util.DragDrop.prototype={id:null,config:null,dragElId:null,handleElId:null,invalidHandleTypes:null,invalidHandleIds:null,invalidHandleClasses:null,startPageX:0,startPageY:0,groups:null,locked:false,lock:function(){this.locked=true;},unlock:function(){this.locked=false;},isTarget:true,padding:null,_domRef:null,__ygDragDrop:true,constrainX:false,constrainY:false,minX:0,maxX:0,minY:0,maxY:0,deltaX:0,deltaY:0,maintainOffset:false,xTicks:null,yTicks:null,primaryButtonOnly:true,available:false,hasOuterHandles:false,cursorIsOver:false,overlap:null,b4StartDrag:function(x,y){},startDrag:function(x,y){},b4Drag:function(e){},onDrag:function(e){},onDragEnter:function(e,id){},b4DragOver:function(e){},onDragOver:function(e,id){},b4DragOut:function(e){},onDragOut:function(e,id){},b4DragDrop:function(e){},onDragDrop:function(e,id){},onInvalidDrop:function(e){},b4EndDrag:function(e){},endDrag:function(e){},b4MouseDown:function(e){},onMouseDown:function(e){},onMouseUp:function(e){},onAvailable:function(){},getEl:function(){if(!this._domRef){this._domRef=Dom.get(this.id);}
return this._domRef;},getDragEl:function(){return Dom.get(this.dragElId);},init:function(id,sGroup,config){this.initTarget(id,sGroup,config);Event.on(this._domRef||this.id,"mousedown",this.handleMouseDown,this,true);},initTarget:function(id,sGroup,config){this.config=config||{};this.DDM=YAHOO.util.DDM;this.groups={};if(typeof id!=="string"){this._domRef=id;id=Dom.generateId(id);}
this.id=id;this.addToGroup((sGroup)?sGroup:"default");this.handleElId=id;Event.onAvailable(id,this.handleOnAvailable,this,true);this.setDragElId(id);this.invalidHandleTypes={A:"A"};this.invalidHandleIds={};this.invalidHandleClasses=[];this.applyConfig();},applyConfig:function(){this.padding=this.config.padding||[0,0,0,0];this.isTarget=(this.config.isTarget!==false);this.maintainOffset=(this.config.maintainOffset);this.primaryButtonOnly=(this.config.primaryButtonOnly!==false);},handleOnAvailable:function(){this.available=true;this.resetConstraints();this.onAvailable();},setPadding:function(iTop,iRight,iBot,iLeft){if(!iRight&&0!==iRight){this.padding=[iTop,iTop,iTop,iTop];}else if(!iBot&&0!==iBot){this.padding=[iTop,iRight,iTop,iRight];}else{this.padding=[iTop,iRight,iBot,iLeft];}},setInitPosition:function(diffX,diffY){var el=this.getEl();if(!this.DDM.verifyEl(el)){return;}
var dx=diffX||0;var dy=diffY||0;var p=Dom.getXY(el);this.initPageX=p[0]-dx;this.initPageY=p[1]-dy;this.lastPageX=p[0];this.lastPageY=p[1];this.setStartPosition(p);},setStartPosition:function(pos){var p=pos||Dom.getXY(this.getEl());this.deltaSetXY=null;this.startPageX=p[0];this.startPageY=p[1];},addToGroup:function(sGroup){this.groups[sGroup]=true;this.DDM.regDragDrop(this,sGroup);},removeFromGroup:function(sGroup){if(this.groups[sGroup]){delete this.groups[sGroup];}
this.DDM.removeDDFromGroup(this,sGroup);},setDragElId:function(id){this.dragElId=id;},setHandleElId:function(id){if(typeof id!=="string"){id=Dom.generateId(id);}
this.handleElId=id;this.DDM.regHandle(this.id,id);},setOuterHandleElId:function(id){if(typeof id!=="string"){id=Dom.generateId(id);}
Event.on(id,"mousedown",this.handleMouseDown,this,true);this.setHandleElId(id);this.hasOuterHandles=true;},unreg:function(){Event.removeListener(this.id,"mousedown",this.handleMouseDown);this._domRef=null;this.DDM._remove(this);},isLocked:function(){return(this.DDM.isLocked()||this.locked);},handleMouseDown:function(e,oDD){var button=e.which||e.button;if(this.primaryButtonOnly&&button>1){return;}
if(this.isLocked()){return;}
this.b4MouseDown(e);this.onMouseDown(e);this.DDM.refreshCache(this.groups);var pt=new YAHOO.util.Point(Event.getPageX(e),Event.getPageY(e));if(!this.hasOuterHandles&&!this.DDM.isOverTarget(pt,this)){}else{if(this.clickValidator(e)){this.setStartPosition();this.DDM.handleMouseDown(e,this);this.DDM.stopEvent(e);}else{}}},clickValidator:function(e){var target=Event.getTarget(e);return(this.isValidHandleChild(target)&&(this.id==this.handleElId||this.DDM.handleWasClicked(target,this.id)));},getTargetCoord:function(iPageX,iPageY){var x=iPageX-this.deltaX;var y=iPageY-this.deltaY;if(this.constrainX){if(x<this.minX){x=this.minX;}
if(x>this.maxX){x=this.maxX;}}
if(this.constrainY){if(y<this.minY){y=this.minY;}
if(y>this.maxY){y=this.maxY;}}
x=this.getTick(x,this.xTicks);y=this.getTick(y,this.yTicks);return{x:x,y:y};},addInvalidHandleType:function(tagName){var type=tagName.toUpperCase();this.invalidHandleTypes[type]=type;},addInvalidHandleId:function(id){if(typeof id!=="string"){id=Dom.generateId(id);}
this.invalidHandleIds[id]=id;},addInvalidHandleClass:function(cssClass){this.invalidHandleClasses.push(cssClass);},removeInvalidHandleType:function(tagName){var type=tagName.toUpperCase();delete this.invalidHandleTypes[type];},removeInvalidHandleId:function(id){if(typeof id!=="string"){id=Dom.generateId(id);}
delete this.invalidHandleIds[id];},removeInvalidHandleClass:function(cssClass){for(var i=0,len=this.invalidHandleClasses.length;i<len;++i){if(this.invalidHandleClasses[i]==cssClass){delete this.invalidHandleClasses[i];}}},isValidHandleChild:function(node){var valid=true;var nodeName;try{nodeName=node.nodeName.toUpperCase();}catch(e){nodeName=node.nodeName;}
valid=valid&&!this.invalidHandleTypes[nodeName];valid=valid&&!this.invalidHandleIds[node.id];for(var i=0,len=this.invalidHandleClasses.length;valid&&i<len;++i){valid=!Dom.hasClass(node,this.invalidHandleClasses[i]);}
return valid;},setXTicks:function(iStartX,iTickSize){this.xTicks=[];this.xTickSize=iTickSize;var tickMap={};for(var i=this.initPageX;i>=this.minX;i=i-iTickSize){if(!tickMap[i]){this.xTicks[this.xTicks.length]=i;tickMap[i]=true;}}
for(i=this.initPageX;i<=this.maxX;i=i+iTickSize){if(!tickMap[i]){this.xTicks[this.xTicks.length]=i;tickMap[i]=true;}}
this.xTicks.sort(this.DDM.numericSort);},setYTicks:function(iStartY,iTickSize){this.yTicks=[];this.yTickSize=iTickSize;var tickMap={};for(var i=this.initPageY;i>=this.minY;i=i-iTickSize){if(!tickMap[i]){this.yTicks[this.yTicks.length]=i;tickMap[i]=true;}}
for(i=this.initPageY;i<=this.maxY;i=i+iTickSize){if(!tickMap[i]){this.yTicks[this.yTicks.length]=i;tickMap[i]=true;}}
this.yTicks.sort(this.DDM.numericSort);},setXConstraint:function(iLeft,iRight,iTickSize){this.leftConstraint=parseInt(iLeft,10);this.rightConstraint=parseInt(iRight,10);this.minX=this.initPageX-this.leftConstraint;this.maxX=this.initPageX+this.rightConstraint;if(iTickSize){this.setXTicks(this.initPageX,iTickSize);}
this.constrainX=true;},clearConstraints:function(){this.constrainX=false;this.constrainY=false;this.clearTicks();},clearTicks:function(){this.xTicks=null;this.yTicks=null;this.xTickSize=0;this.yTickSize=0;},setYConstraint:function(iUp,iDown,iTickSize){this.topConstraint=parseInt(iUp,10);this.bottomConstraint=parseInt(iDown,10);this.minY=this.initPageY-this.topConstraint;this.maxY=this.initPageY+this.bottomConstraint;if(iTickSize){this.setYTicks(this.initPageY,iTickSize);}
this.constrainY=true;},resetConstraints:function(){if(this.initPageX||this.initPageX===0){var dx=(this.maintainOffset)?this.lastPageX-this.initPageX:0;var dy=(this.maintainOffset)?this.lastPageY-this.initPageY:0;this.setInitPosition(dx,dy);}else{this.setInitPosition();}
if(this.constrainX){this.setXConstraint(this.leftConstraint,this.rightConstraint,this.xTickSize);}
if(this.constrainY){this.setYConstraint(this.topConstraint,this.bottomConstraint,this.yTickSize);}},getTick:function(val,tickArray){if(!tickArray){return val;}else if(tickArray[0]>=val){return tickArray[0];}else{for(var i=0,len=tickArray.length;i<len;++i){var next=i+1;if(tickArray[next]&&tickArray[next]>=val){var diff1=val-tickArray[i];var diff2=tickArray[next]-val;return(diff2>diff1)?tickArray[i]:tickArray[next];}}
return tickArray[tickArray.length-1];}},toString:function(){return("DragDrop "+this.id);}};})();YAHOO.util.DD=function(id,sGroup,config){if(id){this.init(id,sGroup,config);}};YAHOO.extend(YAHOO.util.DD,YAHOO.util.DragDrop,{scroll:true,autoOffset:function(iPageX,iPageY){var x=iPageX-this.startPageX;var y=iPageY-this.startPageY;this.setDelta(x,y);},setDelta:function(iDeltaX,iDeltaY){this.deltaX=iDeltaX;this.deltaY=iDeltaY;},setDragElPos:function(iPageX,iPageY){var el=this.getDragEl();this.alignElWithMouse(el,iPageX,iPageY);},alignElWithMouse:function(el,iPageX,iPageY){var oCoord=this.getTargetCoord(iPageX,iPageY);if(!this.deltaSetXY){var aCoord=[oCoord.x,oCoord.y];YAHOO.util.Dom.setXY(el,aCoord);var newLeft=parseInt(YAHOO.util.Dom.getStyle(el,"left"),10);var newTop=parseInt(YAHOO.util.Dom.getStyle(el,"top"),10);this.deltaSetXY=[newLeft-oCoord.x,newTop-oCoord.y];}else{YAHOO.util.Dom.setStyle(el,"left",(oCoord.x+this.deltaSetXY[0])+"px");YAHOO.util.Dom.setStyle(el,"top",(oCoord.y+this.deltaSetXY[1])+"px");}
this.cachePosition(oCoord.x,oCoord.y);this.autoScroll(oCoord.x,oCoord.y,el.offsetHeight,el.offsetWidth);},cachePosition:function(iPageX,iPageY){if(iPageX){this.lastPageX=iPageX;this.lastPageY=iPageY;}else{var aCoord=YAHOO.util.Dom.getXY(this.getEl());this.lastPageX=aCoord[0];this.lastPageY=aCoord[1];}},autoScroll:function(x,y,h,w){if(this.scroll){var clientH=this.DDM.getClientHeight();var clientW=this.DDM.getClientWidth();var st=this.DDM.getScrollTop();var sl=this.DDM.getScrollLeft();var bot=h+y;var right=w+x;var toBot=(clientH+st-y-this.deltaY);var toRight=(clientW+sl-x-this.deltaX);var thresh=40;var scrAmt=(document.all)?80:30;if(bot>clientH&&toBot<thresh){window.scrollTo(sl,st+scrAmt);}
if(y<st&&st>0&&y-st<thresh){window.scrollTo(sl,st-scrAmt);}
if(right>clientW&&toRight<thresh){window.scrollTo(sl+scrAmt,st);}
if(x<sl&&sl>0&&x-sl<thresh){window.scrollTo(sl-scrAmt,st);}}},applyConfig:function(){YAHOO.util.DD.superclass.applyConfig.call(this);this.scroll=(this.config.scroll!==false);},b4MouseDown:function(e){this.setStartPosition();this.autoOffset(YAHOO.util.Event.getPageX(e),YAHOO.util.Event.getPageY(e));},b4Drag:function(e){this.setDragElPos(YAHOO.util.Event.getPageX(e),YAHOO.util.Event.getPageY(e));},toString:function(){return("DD "+this.id);}});YAHOO.util.DDProxy=function(id,sGroup,config){if(id){this.init(id,sGroup,config);this.initFrame();}};YAHOO.util.DDProxy.dragElId="ygddfdiv";YAHOO.extend(YAHOO.util.DDProxy,YAHOO.util.DD,{resizeFrame:true,centerFrame:false,createFrame:function(){var self=this,body=document.body;if(!body||!body.firstChild){setTimeout(function(){self.createFrame();},50);return;}
var div=this.getDragEl(),Dom=YAHOO.util.Dom;if(!div){div=document.createElement("div");div.id=this.dragElId;var s=div.style;s.position="absolute";s.visibility="hidden";s.cursor="move";s.border="2px solid #aaa";s.zIndex=999;s.height="25px";s.width="25px";var _data=document.createElement('div');Dom.setStyle(_data,'height','100%');Dom.setStyle(_data,'width','100%');Dom.setStyle(_data,'background-color','#ccc');Dom.setStyle(_data,'opacity','0');div.appendChild(_data);body.insertBefore(div,body.firstChild);}},initFrame:function(){this.createFrame();},applyConfig:function(){YAHOO.util.DDProxy.superclass.applyConfig.call(this);this.resizeFrame=(this.config.resizeFrame!==false);this.centerFrame=(this.config.centerFrame);this.setDragElId(this.config.dragElId||YAHOO.util.DDProxy.dragElId);},showFrame:function(iPageX,iPageY){var el=this.getEl();var dragEl=this.getDragEl();var s=dragEl.style;this._resizeProxy();if(this.centerFrame){this.setDelta(Math.round(parseInt(s.width,10)/2),Math.round(parseInt(s.height,10)/2));}
this.setDragElPos(iPageX,iPageY);YAHOO.util.Dom.setStyle(dragEl,"visibility","visible");},_resizeProxy:function(){if(this.resizeFrame){var DOM=YAHOO.util.Dom;var el=this.getEl();var dragEl=this.getDragEl();var bt=parseInt(DOM.getStyle(dragEl,"borderTopWidth"),10);var br=parseInt(DOM.getStyle(dragEl,"borderRightWidth"),10);var bb=parseInt(DOM.getStyle(dragEl,"borderBottomWidth"),10);var bl=parseInt(DOM.getStyle(dragEl,"borderLeftWidth"),10);if(isNaN(bt)){bt=0;}
if(isNaN(br)){br=0;}
if(isNaN(bb)){bb=0;}
if(isNaN(bl)){bl=0;}
var newWidth=Math.max(0,el.offsetWidth-br-bl);var newHeight=Math.max(0,el.offsetHeight-bt-bb);DOM.setStyle(dragEl,"width",newWidth+"px");DOM.setStyle(dragEl,"height",newHeight+"px");}},b4MouseDown:function(e){this.setStartPosition();var x=YAHOO.util.Event.getPageX(e);var y=YAHOO.util.Event.getPageY(e);this.autoOffset(x,y);},b4StartDrag:function(x,y){this.showFrame(x,y);},b4EndDrag:function(e){YAHOO.util.Dom.setStyle(this.getDragEl(),"visibility","hidden");},endDrag:function(e){var DOM=YAHOO.util.Dom;var lel=this.getEl();var del=this.getDragEl();DOM.setStyle(del,"visibility","");DOM.setStyle(lel,"visibility","hidden");YAHOO.util.DDM.moveToEl(lel,del);DOM.setStyle(del,"visibility","hidden");DOM.setStyle(lel,"visibility","");},toString:function(){return("DDProxy "+this.id);}});YAHOO.util.DDTarget=function(id,sGroup,config){if(id){this.initTarget(id,sGroup,config);}};YAHOO.extend(YAHOO.util.DDTarget,YAHOO.util.DragDrop,{toString:function(){return("DDTarget "+this.id);}});YAHOO.register("dragdrop",YAHOO.util.DragDropMgr,{version:"2.3.0",build:"442"});/*
Copyright (c) 2007, Yahoo! Inc. All rights reserved.
Code licensed under the BSD License:
http://developer.yahoo.net/yui/license.txt
version: 2.3.0
*/

YAHOO.util.Attribute=function(hash,owner){if(owner){this.owner=owner;this.configure(hash,true);}};YAHOO.util.Attribute.prototype={name:undefined,value:null,owner:null,readOnly:false,writeOnce:false,_initialConfig:null,_written:false,method:null,validator:null,getValue:function(){return this.value;},setValue:function(value,silent){var beforeRetVal;var owner=this.owner;var name=this.name;var event={type:name,prevValue:this.getValue(),newValue:value};if(this.readOnly||(this.writeOnce&&this._written)){return false;}
if(this.validator&&!this.validator.call(owner,value)){return false;}
if(!silent){beforeRetVal=owner.fireBeforeChangeEvent(event);if(beforeRetVal===false){return false;}}
if(this.method){this.method.call(owner,value);}
this.value=value;this._written=true;event.type=name;if(!silent){this.owner.fireChangeEvent(event);}
return true;},configure:function(map,init){map=map||{};this._written=false;this._initialConfig=this._initialConfig||{};for(var key in map){if(key&&YAHOO.lang.hasOwnProperty(map,key)){this[key]=map[key];if(init){this._initialConfig[key]=map[key];}}}},resetValue:function(){return this.setValue(this._initialConfig.value);},resetConfig:function(){this.configure(this._initialConfig);},refresh:function(silent){this.setValue(this.value,silent);}};(function(){var Lang=YAHOO.util.Lang;YAHOO.util.AttributeProvider=function(){};YAHOO.util.AttributeProvider.prototype={_configs:null,get:function(key){var configs=this._configs||{};var config=configs[key];if(!config){return undefined;}
return config.value;},set:function(key,value,silent){var configs=this._configs||{};var config=configs[key];if(!config){return false;}
return config.setValue(value,silent);},getAttributeKeys:function(){var configs=this._configs;var keys=[];var config;for(var key in configs){config=configs[key];if(Lang.hasOwnProperty(configs,key)&&!Lang.isUndefined(config)){keys[keys.length]=key;}}
return keys;},setAttributes:function(map,silent){for(var key in map){if(Lang.hasOwnProperty(map,key)){this.set(key,map[key],silent);}}},resetValue:function(key,silent){var configs=this._configs||{};if(configs[key]){this.set(key,configs[key]._initialConfig.value,silent);return true;}
return false;},refresh:function(key,silent){var configs=this._configs;key=((Lang.isString(key))?[key]:key)||this.getAttributeKeys();for(var i=0,len=key.length;i<len;++i){if(configs[key[i]]&&!Lang.isUndefined(configs[key[i]].value)&&!Lang.isNull(configs[key[i]].value)){configs[key[i]].refresh(silent);}}},register:function(key,map){this.setAttributeConfig(key,map);},getAttributeConfig:function(key){var configs=this._configs||{};var config=configs[key]||{};var map={};for(key in config){if(Lang.hasOwnProperty(config,key)){map[key]=config[key];}}
return map;},setAttributeConfig:function(key,map,init){var configs=this._configs||{};map=map||{};if(!configs[key]){map.name=key;configs[key]=new YAHOO.util.Attribute(map,this);}else{configs[key].configure(map,init);}},configureAttribute:function(key,map,init){this.setAttributeConfig(key,map,init);},resetAttributeConfig:function(key){var configs=this._configs||{};configs[key].resetConfig();},fireBeforeChangeEvent:function(e){var type='before';type+=e.type.charAt(0).toUpperCase()+e.type.substr(1)+'Change';e.type=type;return this.fireEvent(e.type,e);},fireChangeEvent:function(e){e.type+='Change';return this.fireEvent(e.type,e);}};YAHOO.augment(YAHOO.util.AttributeProvider,YAHOO.util.EventProvider);})();(function(){var Dom=YAHOO.util.Dom,AttributeProvider=YAHOO.util.AttributeProvider;YAHOO.util.Element=function(el,map){if(arguments.length){this.init(el,map);}};YAHOO.util.Element.prototype={DOM_EVENTS:null,appendChild:function(child){child=child.get?child.get('element'):child;this.get('element').appendChild(child);},getElementsByTagName:function(tag){return this.get('element').getElementsByTagName(tag);},hasChildNodes:function(){return this.get('element').hasChildNodes();},insertBefore:function(element,before){element=element.get?element.get('element'):element;before=(before&&before.get)?before.get('element'):before;this.get('element').insertBefore(element,before);},removeChild:function(child){child=child.get?child.get('element'):child;this.get('element').removeChild(child);return true;},replaceChild:function(newNode,oldNode){newNode=newNode.get?newNode.get('element'):newNode;oldNode=oldNode.get?oldNode.get('element'):oldNode;return this.get('element').replaceChild(newNode,oldNode);},initAttributes:function(map){},addListener:function(type,fn,obj,scope){var el=this.get('element');scope=scope||this;el=this.get('id')||el;var self=this;if(!this._events[type]){if(this.DOM_EVENTS[type]){YAHOO.util.Event.addListener(el,type,function(e){if(e.srcElement&&!e.target){e.target=e.srcElement;}
self.fireEvent(type,e);},obj,scope);}
this.createEvent(type,this);}
YAHOO.util.EventProvider.prototype.subscribe.apply(this,arguments);},on:function(){this.addListener.apply(this,arguments);},subscribe:function(){this.addListener.apply(this,arguments);},removeListener:function(type,fn){this.unsubscribe.apply(this,arguments);},addClass:function(className){Dom.addClass(this.get('element'),className);},getElementsByClassName:function(className,tag){return Dom.getElementsByClassName(className,tag,this.get('element'));},hasClass:function(className){return Dom.hasClass(this.get('element'),className);},removeClass:function(className){return Dom.removeClass(this.get('element'),className);},replaceClass:function(oldClassName,newClassName){return Dom.replaceClass(this.get('element'),oldClassName,newClassName);},setStyle:function(property,value){var el=this.get('element');if(!el){return this._queue[this._queue.length]=['setStyle',arguments];}
return Dom.setStyle(el,property,value);},getStyle:function(property){return Dom.getStyle(this.get('element'),property);},fireQueue:function(){var queue=this._queue;for(var i=0,len=queue.length;i<len;++i){this[queue[i][0]].apply(this,queue[i][1]);}},appendTo:function(parent,before){parent=(parent.get)?parent.get('element'):Dom.get(parent);this.fireEvent('beforeAppendTo',{type:'beforeAppendTo',target:parent});before=(before&&before.get)?before.get('element'):Dom.get(before);var element=this.get('element');if(!element){return false;}
if(!parent){return false;}
if(element.parent!=parent){if(before){parent.insertBefore(element,before);}else{parent.appendChild(element);}}
this.fireEvent('appendTo',{type:'appendTo',target:parent});},get:function(key){var configs=this._configs||{};var el=configs.element;if(el&&!configs[key]&&!YAHOO.lang.isUndefined(el.value[key])){return el.value[key];}
return AttributeProvider.prototype.get.call(this,key);},setAttributes:function(map,silent){var el=this.get('element');for(var key in map){if(!this._configs[key]&&!YAHOO.lang.isUndefined(el[key])){this.setAttributeConfig(key);}}
for(var i=0,len=this._configOrder.length;i<len;++i){if(map[this._configOrder[i]]){this.set(this._configOrder[i],map[this._configOrder[i]],silent);}}},set:function(key,value,silent){var el=this.get('element');if(!el){this._queue[this._queue.length]=['set',arguments];if(this._configs[key]){this._configs[key].value=value;}
return;}
if(!this._configs[key]&&!YAHOO.lang.isUndefined(el[key])){_registerHTMLAttr.call(this,key);}
return AttributeProvider.prototype.set.apply(this,arguments);},setAttributeConfig:function(key,map,init){var el=this.get('element');if(el&&!this._configs[key]&&!YAHOO.lang.isUndefined(el[key])){_registerHTMLAttr.call(this,key,map);}else{AttributeProvider.prototype.setAttributeConfig.apply(this,arguments);}
this._configOrder.push(key);},getAttributeKeys:function(){var el=this.get('element');var keys=AttributeProvider.prototype.getAttributeKeys.call(this);for(var key in el){if(!this._configs[key]){keys[key]=keys[key]||el[key];}}
return keys;},createEvent:function(type,scope){this._events[type]=true;AttributeProvider.prototype.createEvent.apply(this,arguments);},init:function(el,attr){_initElement.apply(this,arguments);}};var _initElement=function(el,attr){this._queue=this._queue||[];this._events=this._events||{};this._configs=this._configs||{};this._configOrder=[];attr=attr||{};attr.element=attr.element||el||null;this.DOM_EVENTS={'click':true,'dblclick':true,'keydown':true,'keypress':true,'keyup':true,'mousedown':true,'mousemove':true,'mouseout':true,'mouseover':true,'mouseup':true,'focus':true,'blur':true,'submit':true};var isReady=false;if(YAHOO.lang.isString(el)){_registerHTMLAttr.call(this,'id',{value:attr.element});}
if(Dom.get(el)){isReady=true;_initHTMLElement.call(this,attr);_initContent.call(this,attr);}
YAHOO.util.Event.onAvailable(attr.element,function(){if(!isReady){_initHTMLElement.call(this,attr);}
this.fireEvent('available',{type:'available',target:attr.element});},this,true);YAHOO.util.Event.onContentReady(attr.element,function(){if(!isReady){_initContent.call(this,attr);}
this.fireEvent('contentReady',{type:'contentReady',target:attr.element});},this,true);};var _initHTMLElement=function(attr){this.setAttributeConfig('element',{value:Dom.get(attr.element),readOnly:true});};var _initContent=function(attr){this.initAttributes(attr);this.setAttributes(attr,true);this.fireQueue();};var _registerHTMLAttr=function(key,map){var el=this.get('element');map=map||{};map.name=key;map.method=map.method||function(value){el[key]=value;};map.value=map.value||el[key];this._configs[key]=new YAHOO.util.Attribute(map,this);};YAHOO.augment(YAHOO.util.Element,AttributeProvider);})();YAHOO.register("element",YAHOO.util.Element,{version:"2.3.0",build:"442"});/*
Copyright (c) 2007, Yahoo! Inc. All rights reserved.
Code licensed under the BSD License:
http://developer.yahoo.net/yui/license.txt
version: 2.3.0
*/

YAHOO.util.Anim=function(el,attributes,duration,method){if(!el){}
this.init(el,attributes,duration,method);};YAHOO.util.Anim.prototype={toString:function(){var el=this.getEl();var id=el.id||el.tagName||el;return("Anim "+id);},patterns:{noNegatives:/width|height|opacity|padding/i,offsetAttribute:/^((width|height)|(top|left))$/,defaultUnit:/width|height|top$|bottom$|left$|right$/i,offsetUnit:/\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i},doMethod:function(attr,start,end){return this.method(this.currentFrame,start,end-start,this.totalFrames);},setAttribute:function(attr,val,unit){if(this.patterns.noNegatives.test(attr)){val=(val>0)?val:0;}
YAHOO.util.Dom.setStyle(this.getEl(),attr,val+unit);},getAttribute:function(attr){var el=this.getEl();var val=YAHOO.util.Dom.getStyle(el,attr);if(val!=='auto'&&!this.patterns.offsetUnit.test(val)){return parseFloat(val);}
var a=this.patterns.offsetAttribute.exec(attr)||[];var pos=!!(a[3]);var box=!!(a[2]);if(box||(YAHOO.util.Dom.getStyle(el,'position')=='absolute'&&pos)){val=el['offset'+a[0].charAt(0).toUpperCase()+a[0].substr(1)];}else{val=0;}
return val;},getDefaultUnit:function(attr){if(this.patterns.defaultUnit.test(attr)){return'px';}
return'';},setRuntimeAttribute:function(attr){var start;var end;var attributes=this.attributes;this.runtimeAttributes[attr]={};var isset=function(prop){return(typeof prop!=='undefined');};if(!isset(attributes[attr]['to'])&&!isset(attributes[attr]['by'])){return false;}
start=(isset(attributes[attr]['from']))?attributes[attr]['from']:this.getAttribute(attr);if(isset(attributes[attr]['to'])){end=attributes[attr]['to'];}else if(isset(attributes[attr]['by'])){if(start.constructor==Array){end=[];for(var i=0,len=start.length;i<len;++i){end[i]=start[i]+attributes[attr]['by'][i]*1;}}else{end=start+attributes[attr]['by']*1;}}
this.runtimeAttributes[attr].start=start;this.runtimeAttributes[attr].end=end;this.runtimeAttributes[attr].unit=(isset(attributes[attr].unit))?attributes[attr]['unit']:this.getDefaultUnit(attr);return true;},init:function(el,attributes,duration,method){var isAnimated=false;var startTime=null;var actualFrames=0;el=YAHOO.util.Dom.get(el);this.attributes=attributes||{};this.duration=!YAHOO.lang.isUndefined(duration)?duration:1;this.method=method||YAHOO.util.Easing.easeNone;this.useSeconds=true;this.currentFrame=0;this.totalFrames=YAHOO.util.AnimMgr.fps;this.setEl=function(element){el=YAHOO.util.Dom.get(element);};this.getEl=function(){return el;};this.isAnimated=function(){return isAnimated;};this.getStartTime=function(){return startTime;};this.runtimeAttributes={};this.animate=function(){if(this.isAnimated()){return false;}
this.currentFrame=0;this.totalFrames=(this.useSeconds)?Math.ceil(YAHOO.util.AnimMgr.fps*this.duration):this.duration;if(this.duration===0&&this.useSeconds){this.totalFrames=1;}
YAHOO.util.AnimMgr.registerElement(this);return true;};this.stop=function(finish){if(finish){this.currentFrame=this.totalFrames;this._onTween.fire();}
YAHOO.util.AnimMgr.stop(this);};var onStart=function(){this.onStart.fire();this.runtimeAttributes={};for(var attr in this.attributes){this.setRuntimeAttribute(attr);}
isAnimated=true;actualFrames=0;startTime=new Date();};var onTween=function(){var data={duration:new Date()-this.getStartTime(),currentFrame:this.currentFrame};data.toString=function(){return('duration: '+data.duration+', currentFrame: '+data.currentFrame);};this.onTween.fire(data);var runtimeAttributes=this.runtimeAttributes;for(var attr in runtimeAttributes){this.setAttribute(attr,this.doMethod(attr,runtimeAttributes[attr].start,runtimeAttributes[attr].end),runtimeAttributes[attr].unit);}
actualFrames+=1;};var onComplete=function(){var actual_duration=(new Date()-startTime)/1000;var data={duration:actual_duration,frames:actualFrames,fps:actualFrames/actual_duration};data.toString=function(){return('duration: '+data.duration+', frames: '+data.frames+', fps: '+data.fps);};isAnimated=false;actualFrames=0;this.onComplete.fire(data);};this._onStart=new YAHOO.util.CustomEvent('_start',this,true);this.onStart=new YAHOO.util.CustomEvent('start',this);this.onTween=new YAHOO.util.CustomEvent('tween',this);this._onTween=new YAHOO.util.CustomEvent('_tween',this,true);this.onComplete=new YAHOO.util.CustomEvent('complete',this);this._onComplete=new YAHOO.util.CustomEvent('_complete',this,true);this._onStart.subscribe(onStart);this._onTween.subscribe(onTween);this._onComplete.subscribe(onComplete);}};YAHOO.util.AnimMgr=new function(){var thread=null;var queue=[];var tweenCount=0;this.fps=1000;this.delay=1;this.registerElement=function(tween){queue[queue.length]=tween;tweenCount+=1;tween._onStart.fire();this.start();};this.unRegister=function(tween,index){tween._onComplete.fire();index=index||getIndex(tween);if(index==-1){return false;}
queue.splice(index,1);tweenCount-=1;if(tweenCount<=0){this.stop();}
return true;};this.start=function(){if(thread===null){thread=setInterval(this.run,this.delay);}};this.stop=function(tween){if(!tween){clearInterval(thread);for(var i=0,len=queue.length;i<len;++i){if(queue[0].isAnimated()){this.unRegister(queue[0],0);}}
queue=[];thread=null;tweenCount=0;}
else{this.unRegister(tween);}};this.run=function(){for(var i=0,len=queue.length;i<len;++i){var tween=queue[i];if(!tween||!tween.isAnimated()){continue;}
if(tween.currentFrame<tween.totalFrames||tween.totalFrames===null)
{tween.currentFrame+=1;if(tween.useSeconds){correctFrame(tween);}
tween._onTween.fire();}
else{YAHOO.util.AnimMgr.stop(tween,i);}}};var getIndex=function(anim){for(var i=0,len=queue.length;i<len;++i){if(queue[i]==anim){return i;}}
return-1;};var correctFrame=function(tween){var frames=tween.totalFrames;var frame=tween.currentFrame;var expected=(tween.currentFrame*tween.duration*1000/tween.totalFrames);var elapsed=(new Date()-tween.getStartTime());var tweak=0;if(elapsed<tween.duration*1000){tweak=Math.round((elapsed/expected-1)*tween.currentFrame);}else{tweak=frames-(frame+1);}
if(tweak>0&&isFinite(tweak)){if(tween.currentFrame+tweak>=frames){tweak=frames-(frame+1);}
tween.currentFrame+=tweak;}};};YAHOO.util.Bezier=new function(){this.getPosition=function(points,t){var n=points.length;var tmp=[];for(var i=0;i<n;++i){tmp[i]=[points[i][0],points[i][1]];}
for(var j=1;j<n;++j){for(i=0;i<n-j;++i){tmp[i][0]=(1-t)*tmp[i][0]+t*tmp[parseInt(i+1,10)][0];tmp[i][1]=(1-t)*tmp[i][1]+t*tmp[parseInt(i+1,10)][1];}}
return[tmp[0][0],tmp[0][1]];};};(function(){YAHOO.util.ColorAnim=function(el,attributes,duration,method){YAHOO.util.ColorAnim.superclass.constructor.call(this,el,attributes,duration,method);};YAHOO.extend(YAHOO.util.ColorAnim,YAHOO.util.Anim);var Y=YAHOO.util;var superclass=Y.ColorAnim.superclass;var proto=Y.ColorAnim.prototype;proto.toString=function(){var el=this.getEl();var id=el.id||el.tagName;return("ColorAnim "+id);};proto.patterns.color=/color$/i;proto.patterns.rgb=/^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;proto.patterns.hex=/^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;proto.patterns.hex3=/^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;proto.patterns.transparent=/^transparent|rgba\(0, 0, 0, 0\)$/;proto.parseColor=function(s){if(s.length==3){return s;}
var c=this.patterns.hex.exec(s);if(c&&c.length==4){return[parseInt(c[1],16),parseInt(c[2],16),parseInt(c[3],16)];}
c=this.patterns.rgb.exec(s);if(c&&c.length==4){return[parseInt(c[1],10),parseInt(c[2],10),parseInt(c[3],10)];}
c=this.patterns.hex3.exec(s);if(c&&c.length==4){return[parseInt(c[1]+c[1],16),parseInt(c[2]+c[2],16),parseInt(c[3]+c[3],16)];}
return null;};proto.getAttribute=function(attr){var el=this.getEl();if(this.patterns.color.test(attr)){var val=YAHOO.util.Dom.getStyle(el,attr);if(this.patterns.transparent.test(val)){var parent=el.parentNode;val=Y.Dom.getStyle(parent,attr);while(parent&&this.patterns.transparent.test(val)){parent=parent.parentNode;val=Y.Dom.getStyle(parent,attr);if(parent.tagName.toUpperCase()=='HTML'){val='#fff';}}}}else{val=superclass.getAttribute.call(this,attr);}
return val;};proto.doMethod=function(attr,start,end){var val;if(this.patterns.color.test(attr)){val=[];for(var i=0,len=start.length;i<len;++i){val[i]=superclass.doMethod.call(this,attr,start[i],end[i]);}
val='rgb('+Math.floor(val[0])+','+Math.floor(val[1])+','+Math.floor(val[2])+')';}
else{val=superclass.doMethod.call(this,attr,start,end);}
return val;};proto.setRuntimeAttribute=function(attr){superclass.setRuntimeAttribute.call(this,attr);if(this.patterns.color.test(attr)){var attributes=this.attributes;var start=this.parseColor(this.runtimeAttributes[attr].start);var end=this.parseColor(this.runtimeAttributes[attr].end);if(typeof attributes[attr]['to']==='undefined'&&typeof attributes[attr]['by']!=='undefined'){end=this.parseColor(attributes[attr].by);for(var i=0,len=start.length;i<len;++i){end[i]=start[i]+end[i];}}
this.runtimeAttributes[attr].start=start;this.runtimeAttributes[attr].end=end;}};})();YAHOO.util.Easing={easeNone:function(t,b,c,d){return c*t/d+b;},easeIn:function(t,b,c,d){return c*(t/=d)*t+b;},easeOut:function(t,b,c,d){return-c*(t/=d)*(t-2)+b;},easeBoth:function(t,b,c,d){if((t/=d/2)<1){return c/2*t*t+b;}
return-c/2*((--t)*(t-2)-1)+b;},easeInStrong:function(t,b,c,d){return c*(t/=d)*t*t*t+b;},easeOutStrong:function(t,b,c,d){return-c*((t=t/d-1)*t*t*t-1)+b;},easeBothStrong:function(t,b,c,d){if((t/=d/2)<1){return c/2*t*t*t*t+b;}
return-c/2*((t-=2)*t*t*t-2)+b;},elasticIn:function(t,b,c,d,a,p){if(t==0){return b;}
if((t/=d)==1){return b+c;}
if(!p){p=d*.3;}
if(!a||a<Math.abs(c)){a=c;var s=p/4;}
else{var s=p/(2*Math.PI)*Math.asin(c/a);}
return-(a*Math.pow(2,10*(t-=1))*Math.sin((t*d-s)*(2*Math.PI)/p))+b;},elasticOut:function(t,b,c,d,a,p){if(t==0){return b;}
if((t/=d)==1){return b+c;}
if(!p){p=d*.3;}
if(!a||a<Math.abs(c)){a=c;var s=p/4;}
else{var s=p/(2*Math.PI)*Math.asin(c/a);}
return a*Math.pow(2,-10*t)*Math.sin((t*d-s)*(2*Math.PI)/p)+c+b;},elasticBoth:function(t,b,c,d,a,p){if(t==0){return b;}
if((t/=d/2)==2){return b+c;}
if(!p){p=d*(.3*1.5);}
if(!a||a<Math.abs(c)){a=c;var s=p/4;}
else{var s=p/(2*Math.PI)*Math.asin(c/a);}
if(t<1){return-.5*(a*Math.pow(2,10*(t-=1))*Math.sin((t*d-s)*(2*Math.PI)/p))+b;}
return a*Math.pow(2,-10*(t-=1))*Math.sin((t*d-s)*(2*Math.PI)/p)*.5+c+b;},backIn:function(t,b,c,d,s){if(typeof s=='undefined'){s=1.70158;}
return c*(t/=d)*t*((s+1)*t-s)+b;},backOut:function(t,b,c,d,s){if(typeof s=='undefined'){s=1.70158;}
return c*((t=t/d-1)*t*((s+1)*t+s)+1)+b;},backBoth:function(t,b,c,d,s){if(typeof s=='undefined'){s=1.70158;}
if((t/=d/2)<1){return c/2*(t*t*(((s*=(1.525))+1)*t-s))+b;}
return c/2*((t-=2)*t*(((s*=(1.525))+1)*t+s)+2)+b;},bounceIn:function(t,b,c,d){return c-YAHOO.util.Easing.bounceOut(d-t,0,c,d)+b;},bounceOut:function(t,b,c,d){if((t/=d)<(1/2.75)){return c*(7.5625*t*t)+b;}else if(t<(2/2.75)){return c*(7.5625*(t-=(1.5/2.75))*t+.75)+b;}else if(t<(2.5/2.75)){return c*(7.5625*(t-=(2.25/2.75))*t+.9375)+b;}
return c*(7.5625*(t-=(2.625/2.75))*t+.984375)+b;},bounceBoth:function(t,b,c,d){if(t<d/2){return YAHOO.util.Easing.bounceIn(t*2,0,c,d)*.5+b;}
return YAHOO.util.Easing.bounceOut(t*2-d,0,c,d)*.5+c*.5+b;}};(function(){YAHOO.util.Motion=function(el,attributes,duration,method){if(el){YAHOO.util.Motion.superclass.constructor.call(this,el,attributes,duration,method);}};YAHOO.extend(YAHOO.util.Motion,YAHOO.util.ColorAnim);var Y=YAHOO.util;var superclass=Y.Motion.superclass;var proto=Y.Motion.prototype;proto.toString=function(){var el=this.getEl();var id=el.id||el.tagName;return("Motion "+id);};proto.patterns.points=/^points$/i;proto.setAttribute=function(attr,val,unit){if(this.patterns.points.test(attr)){unit=unit||'px';superclass.setAttribute.call(this,'left',val[0],unit);superclass.setAttribute.call(this,'top',val[1],unit);}else{superclass.setAttribute.call(this,attr,val,unit);}};proto.getAttribute=function(attr){if(this.patterns.points.test(attr)){var val=[superclass.getAttribute.call(this,'left'),superclass.getAttribute.call(this,'top')];}else{val=superclass.getAttribute.call(this,attr);}
return val;};proto.doMethod=function(attr,start,end){var val=null;if(this.patterns.points.test(attr)){var t=this.method(this.currentFrame,0,100,this.totalFrames)/100;val=Y.Bezier.getPosition(this.runtimeAttributes[attr],t);}else{val=superclass.doMethod.call(this,attr,start,end);}
return val;};proto.setRuntimeAttribute=function(attr){if(this.patterns.points.test(attr)){var el=this.getEl();var attributes=this.attributes;var start;var control=attributes['points']['control']||[];var end;var i,len;if(control.length>0&&!(control[0]instanceof Array)){control=[control];}else{var tmp=[];for(i=0,len=control.length;i<len;++i){tmp[i]=control[i];}
control=tmp;}
if(Y.Dom.getStyle(el,'position')=='static'){Y.Dom.setStyle(el,'position','relative');}
if(isset(attributes['points']['from'])){Y.Dom.setXY(el,attributes['points']['from']);}
else{Y.Dom.setXY(el,Y.Dom.getXY(el));}
start=this.getAttribute('points');if(isset(attributes['points']['to'])){end=translateValues.call(this,attributes['points']['to'],start);var pageXY=Y.Dom.getXY(this.getEl());for(i=0,len=control.length;i<len;++i){control[i]=translateValues.call(this,control[i],start);}}else if(isset(attributes['points']['by'])){end=[start[0]+attributes['points']['by'][0],start[1]+attributes['points']['by'][1]];for(i=0,len=control.length;i<len;++i){control[i]=[start[0]+control[i][0],start[1]+control[i][1]];}}
this.runtimeAttributes[attr]=[start];if(control.length>0){this.runtimeAttributes[attr]=this.runtimeAttributes[attr].concat(control);}
this.runtimeAttributes[attr][this.runtimeAttributes[attr].length]=end;}
else{superclass.setRuntimeAttribute.call(this,attr);}};var translateValues=function(val,start){var pageXY=Y.Dom.getXY(this.getEl());val=[val[0]-pageXY[0]+start[0],val[1]-pageXY[1]+start[1]];return val;};var isset=function(prop){return(typeof prop!=='undefined');};})();(function(){YAHOO.util.Scroll=function(el,attributes,duration,method){if(el){YAHOO.util.Scroll.superclass.constructor.call(this,el,attributes,duration,method);}};YAHOO.extend(YAHOO.util.Scroll,YAHOO.util.ColorAnim);var Y=YAHOO.util;var superclass=Y.Scroll.superclass;var proto=Y.Scroll.prototype;proto.toString=function(){var el=this.getEl();var id=el.id||el.tagName;return("Scroll "+id);};proto.doMethod=function(attr,start,end){var val=null;if(attr=='scroll'){val=[this.method(this.currentFrame,start[0],end[0]-start[0],this.totalFrames),this.method(this.currentFrame,start[1],end[1]-start[1],this.totalFrames)];}else{val=superclass.doMethod.call(this,attr,start,end);}
return val;};proto.getAttribute=function(attr){var val=null;var el=this.getEl();if(attr=='scroll'){val=[el.scrollLeft,el.scrollTop];}else{val=superclass.getAttribute.call(this,attr);}
return val;};proto.setAttribute=function(attr,val,unit){var el=this.getEl();if(attr=='scroll'){el.scrollLeft=val[0];el.scrollTop=val[1];}else{superclass.setAttribute.call(this,attr,val,unit);}};})();YAHOO.register("animation",YAHOO.util.Anim,{version:"2.3.0",build:"442"});/*
Copyright (c) 2007, Yahoo! Inc. All rights reserved.
Code licensed under the BSD License:
http://developer.yahoo.net/yui/license.txt
version: 2.3.0
*/

YAHOO.util.Connect={_msxml_progid:['MSXML2.XMLHTTP.3.0','MSXML2.XMLHTTP','Microsoft.XMLHTTP'],_http_headers:{},_has_http_headers:false,_use_default_post_header:true,_default_post_header:'application/x-www-form-urlencoded; charset=UTF-8',_use_default_xhr_header:true,_default_xhr_header:'XMLHttpRequest',_has_default_headers:true,_default_headers:{},_isFormSubmit:false,_isFileUpload:false,_formNode:null,_sFormData:null,_poll:{},_timeOut:{},_polling_interval:50,_transaction_id:0,_submitElementValue:null,_hasSubmitListener:(function()
{if(YAHOO.util.Event){YAHOO.util.Event.addListener(document,'click',function(e){var obj=YAHOO.util.Event.getTarget(e);if(obj.type=='submit'){YAHOO.util.Connect._submitElementValue=encodeURIComponent(obj.name)+"="+encodeURIComponent(obj.value);}});return true;}
return false;})(),startEvent:new YAHOO.util.CustomEvent('start'),completeEvent:new YAHOO.util.CustomEvent('complete'),successEvent:new YAHOO.util.CustomEvent('success'),failureEvent:new YAHOO.util.CustomEvent('failure'),uploadEvent:new YAHOO.util.CustomEvent('upload'),abortEvent:new YAHOO.util.CustomEvent('abort'),_customEvents:{onStart:['startEvent','start'],onComplete:['completeEvent','complete'],onSuccess:['successEvent','success'],onFailure:['failureEvent','failure'],onUpload:['uploadEvent','upload'],onAbort:['abortEvent','abort']},setProgId:function(id)
{this._msxml_progid.unshift(id);},setDefaultPostHeader:function(b)
{this._use_default_post_header=b;},setDefaultXhrHeader:function(b)
{this._use_default_xhr_header=b;},setPollingInterval:function(i)
{if(typeof i=='number'&&isFinite(i)){this._polling_interval=i;}},createXhrObject:function(transactionId)
{var obj,http;try
{http=new XMLHttpRequest();obj={conn:http,tId:transactionId};}
catch(e)
{for(var i=0;i<this._msxml_progid.length;++i){try
{http=new ActiveXObject(this._msxml_progid[i]);obj={conn:http,tId:transactionId};break;}
catch(e){}}}
finally
{return obj;}},getConnectionObject:function(isFileUpload)
{var o;var tId=this._transaction_id;try
{if(!isFileUpload){o=this.createXhrObject(tId);}
else{o={};o.tId=tId;o.isUpload=true;}
if(o){this._transaction_id++;}}
catch(e){}
finally
{return o;}},asyncRequest:function(method,uri,callback,postData)
{var o=(this._isFileUpload)?this.getConnectionObject(true):this.getConnectionObject();if(!o){return null;}
else{if(callback&&callback.customevents){this.initCustomEvents(o,callback);}
if(this._isFormSubmit){if(this._isFileUpload){this.uploadFile(o,callback,uri,postData);return o;}
if(method.toUpperCase()=='GET'){if(this._sFormData.length!==0){uri+=((uri.indexOf('?')==-1)?'?':'&')+this._sFormData;}
else{uri+="?"+this._sFormData;}}
else if(method.toUpperCase()=='POST'){postData=postData?this._sFormData+"&"+postData:this._sFormData;}}
o.conn.open(method,uri,true);if(this._use_default_xhr_header){if(!this._default_headers['X-Requested-With']){this.initHeader('X-Requested-With',this._default_xhr_header,true);}}
if(this._isFormSubmit||(postData&&this._use_default_post_header)){this.initHeader('Content-Type',this._default_post_header);if(this._isFormSubmit){this.resetFormState();}}
if(this._has_default_headers||this._has_http_headers){this.setHeader(o);}
this.handleReadyState(o,callback);o.conn.send(postData||null);this.startEvent.fire(o);if(o.startEvent){o.startEvent.fire(o);}
return o;}},initCustomEvents:function(o,callback)
{for(var prop in callback.customevents){if(this._customEvents[prop][0]){o[this._customEvents[prop][0]]=new YAHOO.util.CustomEvent(this._customEvents[prop][1],(callback.scope)?callback.scope:null);o[this._customEvents[prop][0]].subscribe(callback.customevents[prop]);}}},handleReadyState:function(o,callback)
{var oConn=this;if(callback&&callback.timeout){this._timeOut[o.tId]=window.setTimeout(function(){oConn.abort(o,callback,true);},callback.timeout);}
this._poll[o.tId]=window.setInterval(function(){if(o.conn&&o.conn.readyState===4){window.clearInterval(oConn._poll[o.tId]);delete oConn._poll[o.tId];if(callback&&callback.timeout){window.clearTimeout(oConn._timeOut[o.tId]);delete oConn._timeOut[o.tId];}
oConn.completeEvent.fire(o);if(o.completeEvent){o.completeEvent.fire(o);}
oConn.handleTransactionResponse(o,callback);}},this._polling_interval);},handleTransactionResponse:function(o,callback,isAbort)
{if(!callback){this.releaseObject(o);return;}
var httpStatus,responseObject;try
{if(o.conn.status!==undefined&&o.conn.status!==0){httpStatus=o.conn.status;}
else{httpStatus=13030;}}
catch(e){httpStatus=13030;}
if(httpStatus>=200&&httpStatus<300||httpStatus===1223){responseObject=this.createResponseObject(o,callback.argument);if(callback.success){if(!callback.scope){callback.success(responseObject);}
else{callback.success.apply(callback.scope,[responseObject]);}}
this.successEvent.fire(responseObject);if(o.successEvent){o.successEvent.fire(responseObject);}}
else{switch(httpStatus){case 12002:case 12029:case 12030:case 12031:case 12152:case 13030:responseObject=this.createExceptionObject(o.tId,callback.argument,(isAbort?isAbort:false));if(callback.failure){if(!callback.scope){callback.failure(responseObject);}
else{callback.failure.apply(callback.scope,[responseObject]);}}
break;default:responseObject=this.createResponseObject(o,callback.argument);if(callback.failure){if(!callback.scope){callback.failure(responseObject);}
else{callback.failure.apply(callback.scope,[responseObject]);}}}
this.failureEvent.fire(responseObject);if(o.failureEvent){o.failureEvent.fire(responseObject);}}
this.releaseObject(o);responseObject=null;},createResponseObject:function(o,callbackArg)
{var obj={};var headerObj={};try
{var headerStr=o.conn.getAllResponseHeaders();var header=headerStr.split('\n');for(var i=0;i<header.length;i++){var delimitPos=header[i].indexOf(':');if(delimitPos!=-1){headerObj[header[i].substring(0,delimitPos)]=header[i].substring(delimitPos+2);}}}
catch(e){}
obj.tId=o.tId;obj.status=(o.conn.status==1223)?204:o.conn.status;obj.statusText=(o.conn.status==1223)?"No Content":o.conn.statusText;obj.getResponseHeader=headerObj;obj.getAllResponseHeaders=headerStr;obj.responseText=o.conn.responseText;obj.responseXML=o.conn.responseXML;if(typeof callbackArg!==undefined){obj.argument=callbackArg;}
return obj;},createExceptionObject:function(tId,callbackArg,isAbort)
{var COMM_CODE=0;var COMM_ERROR='communication failure';var ABORT_CODE=-1;var ABORT_ERROR='transaction aborted';var obj={};obj.tId=tId;if(isAbort){obj.status=ABORT_CODE;obj.statusText=ABORT_ERROR;}
else{obj.status=COMM_CODE;obj.statusText=COMM_ERROR;}
if(callbackArg){obj.argument=callbackArg;}
return obj;},initHeader:function(label,value,isDefault)
{var headerObj=(isDefault)?this._default_headers:this._http_headers;if(headerObj[label]===undefined){headerObj[label]=value;}
else{headerObj[label]=value+","+headerObj[label];}
if(isDefault){this._has_default_headers=true;}
else{this._has_http_headers=true;}},setHeader:function(o)
{if(this._has_default_headers){for(var prop in this._default_headers){if(YAHOO.lang.hasOwnProperty(this._default_headers,prop)){o.conn.setRequestHeader(prop,this._default_headers[prop]);}}}
if(this._has_http_headers){for(var prop in this._http_headers){if(YAHOO.lang.hasOwnProperty(this._http_headers,prop)){o.conn.setRequestHeader(prop,this._http_headers[prop]);}}
delete this._http_headers;this._http_headers={};this._has_http_headers=false;}},resetDefaultHeaders:function(){delete this._default_headers;this._default_headers={};this._has_default_headers=false;},setForm:function(formId,isUpload,secureUri)
{this.resetFormState();var oForm;if(typeof formId=='string'){oForm=(document.getElementById(formId)||document.forms[formId]);}
else if(typeof formId=='object'){oForm=formId;}
else{return;}
if(isUpload){var io=this.createFrame(secureUri?secureUri:null);this._isFormSubmit=true;this._isFileUpload=true;this._formNode=oForm;return;}
var oElement,oName,oValue,oDisabled;var hasSubmit=false;for(var i=0;i<oForm.elements.length;i++){oElement=oForm.elements[i];oDisabled=oForm.elements[i].disabled;oName=oForm.elements[i].name;oValue=oForm.elements[i].value;if(!oDisabled&&oName)
{switch(oElement.type)
{case'select-one':case'select-multiple':for(var j=0;j<oElement.options.length;j++){if(oElement.options[j].selected){if(window.ActiveXObject){this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oElement.options[j].attributes['value'].specified?oElement.options[j].value:oElement.options[j].text)+'&';}
else{this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oElement.options[j].hasAttribute('value')?oElement.options[j].value:oElement.options[j].text)+'&';}}}
break;case'radio':case'checkbox':if(oElement.checked){this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oValue)+'&';}
break;case'file':case undefined:case'reset':case'button':break;case'submit':if(hasSubmit===false){if(this._hasSubmitListener&&this._submitElementValue){this._sFormData+=this._submitElementValue+'&';}
else{this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oValue)+'&';}
hasSubmit=true;}
break;default:this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oValue)+'&';}}}
this._isFormSubmit=true;this._sFormData=this._sFormData.substr(0,this._sFormData.length-1);return this._sFormData;},resetFormState:function(){this._isFormSubmit=false;this._isFileUpload=false;this._formNode=null;this._sFormData="";},createFrame:function(secureUri){var frameId='yuiIO'+this._transaction_id;var io;if(window.ActiveXObject){io=document.createElement('<iframe id="'+frameId+'" name="'+frameId+'" />');if(typeof secureUri=='boolean'){io.src='javascript:false';}
else if(typeof secureURI=='string'){io.src=secureUri;}}
else{io=document.createElement('iframe');io.id=frameId;io.name=frameId;}
io.style.position='absolute';io.style.top='-1000px';io.style.left='-1000px';document.body.appendChild(io);},appendPostData:function(postData)
{var formElements=[];var postMessage=postData.split('&');for(var i=0;i<postMessage.length;i++){var delimitPos=postMessage[i].indexOf('=');if(delimitPos!=-1){formElements[i]=document.createElement('input');formElements[i].type='hidden';formElements[i].name=postMessage[i].substring(0,delimitPos);formElements[i].value=postMessage[i].substring(delimitPos+1);this._formNode.appendChild(formElements[i]);}}
return formElements;},uploadFile:function(o,callback,uri,postData){var frameId='yuiIO'+o.tId;var uploadEncoding='multipart/form-data';var io=document.getElementById(frameId);var oConn=this;var rawFormAttributes={action:this._formNode.getAttribute('action'),method:this._formNode.getAttribute('method'),target:this._formNode.getAttribute('target')};this._formNode.setAttribute('action',uri);this._formNode.setAttribute('method','POST');this._formNode.setAttribute('target',frameId);if(this._formNode.encoding){this._formNode.setAttribute('encoding',uploadEncoding);}
else{this._formNode.setAttribute('enctype',uploadEncoding);}
if(postData){var oElements=this.appendPostData(postData);}
this._formNode.submit();this.startEvent.fire(o);if(o.startEvent){o.startEvent.fire(o);}
if(callback&&callback.timeout){this._timeOut[o.tId]=window.setTimeout(function(){oConn.abort(o,callback,true);},callback.timeout);}
if(oElements&&oElements.length>0){for(var i=0;i<oElements.length;i++){this._formNode.removeChild(oElements[i]);}}
for(var prop in rawFormAttributes){if(YAHOO.lang.hasOwnProperty(rawFormAttributes,prop)){if(rawFormAttributes[prop]){this._formNode.setAttribute(prop,rawFormAttributes[prop]);}
else{this._formNode.removeAttribute(prop);}}}
this.resetFormState();var uploadCallback=function()
{if(callback&&callback.timeout){window.clearTimeout(oConn._timeOut[o.tId]);delete oConn._timeOut[o.tId];}
oConn.completeEvent.fire(o);if(o.completeEvent){o.completeEvent.fire(o);}
var obj={};obj.tId=o.tId;obj.argument=callback.argument;try
{obj.responseText=io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:io.contentWindow.document.documentElement.textContent;obj.responseXML=io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;}
catch(e){}
if(callback&&callback.upload){if(!callback.scope){callback.upload(obj);}
else{callback.upload.apply(callback.scope,[obj]);}}
oConn.uploadEvent.fire(obj);if(o.uploadEvent){o.uploadEvent.fire(obj);}
if(YAHOO.util.Event){YAHOO.util.Event.removeListener(io,"load",uploadCallback);}
else if(window.detachEvent){io.detachEvent('onload',uploadCallback);}
else{io.removeEventListener('load',uploadCallback,false);}
setTimeout(function(){document.body.removeChild(io);oConn.releaseObject(o);},100);};if(YAHOO.util.Event){YAHOO.util.Event.addListener(io,"load",uploadCallback);}
else if(window.attachEvent){io.attachEvent('onload',uploadCallback);}
else{io.addEventListener('load',uploadCallback,false);}},abort:function(o,callback,isTimeout)
{var abortStatus;if(o.conn){if(this.isCallInProgress(o)){o.conn.abort();window.clearInterval(this._poll[o.tId]);delete this._poll[o.tId];if(isTimeout){window.clearTimeout(this._timeOut[o.tId]);delete this._timeOut[o.tId];}
abortStatus=true;}}
else if(o.isUpload===true){var frameId='yuiIO'+o.tId;var io=document.getElementById(frameId);if(io){document.body.removeChild(io);if(isTimeout){window.clearTimeout(this._timeOut[o.tId]);delete this._timeOut[o.tId];}
abortStatus=true;}}
else{abortStatus=false;}
if(abortStatus===true){this.abortEvent.fire(o);if(o.abortEvent){o.abortEvent.fire(o);}
this.handleTransactionResponse(o,callback,true);}
else{}
return abortStatus;},isCallInProgress:function(o)
{if(o&&o.conn){return o.conn.readyState!==4&&o.conn.readyState!==0;}
else if(o&&o.isUpload===true){var frameId='yuiIO'+o.tId;return document.getElementById(frameId)?true:false;}
else{return false;}},releaseObject:function(o)
{if(o.conn){o.conn=null;}
o=null;}};YAHOO.register("connection",YAHOO.util.Connect,{version:"2.3.0",build:"442"});
/*
Copyright (c) 2007, Yahoo! Inc. All rights reserved.
Code licensed under the BSD License:
http://developer.yahoo.net/yui/license.txt
version: 2.3.0
*/

(function(){YAHOO.util.Config=function(owner){if(owner){this.init(owner);}
if(!owner){}};var Lang=YAHOO.lang,CustomEvent=YAHOO.util.CustomEvent,Config=YAHOO.util.Config;Config.CONFIG_CHANGED_EVENT="configChanged";Config.BOOLEAN_TYPE="boolean";Config.prototype={owner:null,queueInProgress:false,config:null,initialConfig:null,eventQueue:null,configChangedEvent:null,init:function(owner){this.owner=owner;this.configChangedEvent=this.createEvent(Config.CONFIG_CHANGED_EVENT);this.configChangedEvent.signature=CustomEvent.LIST;this.queueInProgress=false;this.config={};this.initialConfig={};this.eventQueue=[];},checkBoolean:function(val){return(typeof val==Config.BOOLEAN_TYPE);},checkNumber:function(val){return(!isNaN(val));},fireEvent:function(key,value){var property=this.config[key];if(property&&property.event){property.event.fire(value);}},addProperty:function(key,propertyObject){key=key.toLowerCase();this.config[key]=propertyObject;propertyObject.event=this.createEvent(key,{scope:this.owner});propertyObject.event.signature=CustomEvent.LIST;propertyObject.key=key;if(propertyObject.handler){propertyObject.event.subscribe(propertyObject.handler,this.owner);}
this.setProperty(key,propertyObject.value,true);if(!propertyObject.suppressEvent){this.queueProperty(key,propertyObject.value);}},getConfig:function(){var cfg={},prop,property;for(prop in this.config){property=this.config[prop];if(property&&property.event){cfg[prop]=property.value;}}
return cfg;},getProperty:function(key){var property=this.config[key.toLowerCase()];if(property&&property.event){return property.value;}else{return undefined;}},resetProperty:function(key){key=key.toLowerCase();var property=this.config[key];if(property&&property.event){if(this.initialConfig[key]&&!Lang.isUndefined(this.initialConfig[key])){this.setProperty(key,this.initialConfig[key]);return true;}}else{return false;}},setProperty:function(key,value,silent){var property;key=key.toLowerCase();if(this.queueInProgress&&!silent){this.queueProperty(key,value);return true;}else{property=this.config[key];if(property&&property.event){if(property.validator&&!property.validator(value)){return false;}else{property.value=value;if(!silent){this.fireEvent(key,value);this.configChangedEvent.fire([key,value]);}
return true;}}else{return false;}}},queueProperty:function(key,value){key=key.toLowerCase();var property=this.config[key],foundDuplicate=false,iLen,queueItem,queueItemKey,queueItemValue,sLen,supercedesCheck,qLen,queueItemCheck,queueItemCheckKey,queueItemCheckValue,i,s,q;if(property&&property.event){if(!Lang.isUndefined(value)&&property.validator&&!property.validator(value)){return false;}else{if(!Lang.isUndefined(value)){property.value=value;}else{value=property.value;}
foundDuplicate=false;iLen=this.eventQueue.length;for(i=0;i<iLen;i++){queueItem=this.eventQueue[i];if(queueItem){queueItemKey=queueItem[0];queueItemValue=queueItem[1];if(queueItemKey==key){this.eventQueue[i]=null;this.eventQueue.push([key,(!Lang.isUndefined(value)?value:queueItemValue)]);foundDuplicate=true;break;}}}
if(!foundDuplicate&&!Lang.isUndefined(value)){this.eventQueue.push([key,value]);}}
if(property.supercedes){sLen=property.supercedes.length;for(s=0;s<sLen;s++){supercedesCheck=property.supercedes[s];qLen=this.eventQueue.length;for(q=0;q<qLen;q++){queueItemCheck=this.eventQueue[q];if(queueItemCheck){queueItemCheckKey=queueItemCheck[0];queueItemCheckValue=queueItemCheck[1];if(queueItemCheckKey==supercedesCheck.toLowerCase()){this.eventQueue.push([queueItemCheckKey,queueItemCheckValue]);this.eventQueue[q]=null;break;}}}}}
return true;}else{return false;}},refireEvent:function(key){key=key.toLowerCase();var property=this.config[key];if(property&&property.event&&!Lang.isUndefined(property.value)){if(this.queueInProgress){this.queueProperty(key);}else{this.fireEvent(key,property.value);}}},applyConfig:function(userConfig,init){var sKey,oValue,oConfig;if(init){oConfig={};for(sKey in userConfig){if(Lang.hasOwnProperty(userConfig,sKey)){oConfig[sKey.toLowerCase()]=userConfig[sKey];}}
this.initialConfig=oConfig;}
for(sKey in userConfig){if(Lang.hasOwnProperty(userConfig,sKey)){this.queueProperty(sKey,userConfig[sKey]);}}},refresh:function(){var prop;for(prop in this.config){this.refireEvent(prop);}},fireQueue:function(){var i,queueItem,key,value,property;this.queueInProgress=true;for(i=0;i<this.eventQueue.length;i++){queueItem=this.eventQueue[i];if(queueItem){key=queueItem[0];value=queueItem[1];property=this.config[key];property.value=value;this.fireEvent(key,value);}}
this.queueInProgress=false;this.eventQueue=[];},subscribeToConfigEvent:function(key,handler,obj,override){var property=this.config[key.toLowerCase()];if(property&&property.event){if(!Config.alreadySubscribed(property.event,handler,obj)){property.event.subscribe(handler,obj,override);}
return true;}else{return false;}},unsubscribeFromConfigEvent:function(key,handler,obj){var property=this.config[key.toLowerCase()];if(property&&property.event){return property.event.unsubscribe(handler,obj);}else{return false;}},toString:function(){var output="Config";if(this.owner){output+=" ["+this.owner.toString()+"]";}
return output;},outputEventQueue:function(){var output="",queueItem,q,nQueue=this.eventQueue.length;for(q=0;q<nQueue;q++){queueItem=this.eventQueue[q];if(queueItem){output+=queueItem[0]+"="+queueItem[1]+", ";}}
return output;},destroy:function(){var oConfig=this.config,sProperty,oProperty;for(sProperty in oConfig){if(Lang.hasOwnProperty(oConfig,sProperty)){oProperty=oConfig[sProperty];oProperty.event.unsubscribeAll();oProperty.event=null;}}
this.configChangedEvent.unsubscribeAll();this.configChangedEvent=null;this.owner=null;this.config=null;this.initialConfig=null;this.eventQueue=null;}};Config.alreadySubscribed=function(evt,fn,obj){var nSubscribers=evt.subscribers.length,subsc,i;if(nSubscribers>0){i=nSubscribers-1;do{subsc=evt.subscribers[i];if(subsc&&subsc.obj==obj&&subsc.fn==fn){return true;}}
while(i--);}
return false;};YAHOO.lang.augmentProto(Config,YAHOO.util.EventProvider);}());(function(){YAHOO.widget.Module=function(el,userConfig){if(el){this.init(el,userConfig);}else{}};var Dom=YAHOO.util.Dom,Config=YAHOO.util.Config,Event=YAHOO.util.Event,CustomEvent=YAHOO.util.CustomEvent,Module=YAHOO.widget.Module,m_oModuleTemplate,m_oHeaderTemplate,m_oBodyTemplate,m_oFooterTemplate,EVENT_TYPES={"BEFORE_INIT":"beforeInit","INIT":"init","APPEND":"append","BEFORE_RENDER":"beforeRender","RENDER":"render","CHANGE_HEADER":"changeHeader","CHANGE_BODY":"changeBody","CHANGE_FOOTER":"changeFooter","CHANGE_CONTENT":"changeContent","DESTORY":"destroy","BEFORE_SHOW":"beforeShow","SHOW":"show","BEFORE_HIDE":"beforeHide","HIDE":"hide"},DEFAULT_CONFIG={"VISIBLE":{key:"visible",value:true,validator:YAHOO.lang.isBoolean},"EFFECT":{key:"effect",suppressEvent:true,supercedes:["visible"]},"MONITOR_RESIZE":{key:"monitorresize",value:true}};Module.IMG_ROOT=null;Module.IMG_ROOT_SSL=null;Module.CSS_MODULE="yui-module";Module.CSS_HEADER="hd";Module.CSS_BODY="bd";Module.CSS_FOOTER="ft";Module.RESIZE_MONITOR_SECURE_URL="javascript:false;";Module.textResizeEvent=new CustomEvent("textResize");function createModuleTemplate(){if(!m_oModuleTemplate){m_oModuleTemplate=document.createElement("div");m_oModuleTemplate.innerHTML=("<div class=\""+
Module.CSS_HEADER+"\"></div>"+"<div class=\""+
Module.CSS_BODY+"\"></div><div class=\""+
Module.CSS_FOOTER+"\"></div>");m_oHeaderTemplate=m_oModuleTemplate.firstChild;m_oBodyTemplate=m_oHeaderTemplate.nextSibling;m_oFooterTemplate=m_oBodyTemplate.nextSibling;}
return m_oModuleTemplate;}
function createHeader(){if(!m_oHeaderTemplate){createModuleTemplate();}
return(m_oHeaderTemplate.cloneNode(false));}
function createBody(){if(!m_oBodyTemplate){createModuleTemplate();}
return(m_oBodyTemplate.cloneNode(false));}
function createFooter(){if(!m_oFooterTemplate){createModuleTemplate();}
return(m_oFooterTemplate.cloneNode(false));}
Module.prototype={constructor:Module,element:null,header:null,body:null,footer:null,id:null,imageRoot:Module.IMG_ROOT,initEvents:function(){var SIGNATURE=CustomEvent.LIST;this.beforeInitEvent=this.createEvent(EVENT_TYPES.BEFORE_INIT);this.beforeInitEvent.signature=SIGNATURE;this.initEvent=this.createEvent(EVENT_TYPES.INIT);this.initEvent.signature=SIGNATURE;this.appendEvent=this.createEvent(EVENT_TYPES.APPEND);this.appendEvent.signature=SIGNATURE;this.beforeRenderEvent=this.createEvent(EVENT_TYPES.BEFORE_RENDER);this.beforeRenderEvent.signature=SIGNATURE;this.renderEvent=this.createEvent(EVENT_TYPES.RENDER);this.renderEvent.signature=SIGNATURE;this.changeHeaderEvent=this.createEvent(EVENT_TYPES.CHANGE_HEADER);this.changeHeaderEvent.signature=SIGNATURE;this.changeBodyEvent=this.createEvent(EVENT_TYPES.CHANGE_BODY);this.changeBodyEvent.signature=SIGNATURE;this.changeFooterEvent=this.createEvent(EVENT_TYPES.CHANGE_FOOTER);this.changeFooterEvent.signature=SIGNATURE;this.changeContentEvent=this.createEvent(EVENT_TYPES.CHANGE_CONTENT);this.changeContentEvent.signature=SIGNATURE;this.destroyEvent=this.createEvent(EVENT_TYPES.DESTORY);this.destroyEvent.signature=SIGNATURE;this.beforeShowEvent=this.createEvent(EVENT_TYPES.BEFORE_SHOW);this.beforeShowEvent.signature=SIGNATURE;this.showEvent=this.createEvent(EVENT_TYPES.SHOW);this.showEvent.signature=SIGNATURE;this.beforeHideEvent=this.createEvent(EVENT_TYPES.BEFORE_HIDE);this.beforeHideEvent.signature=SIGNATURE;this.hideEvent=this.createEvent(EVENT_TYPES.HIDE);this.hideEvent.signature=SIGNATURE;},platform:function(){var ua=navigator.userAgent.toLowerCase();if(ua.indexOf("windows")!=-1||ua.indexOf("win32")!=-1){return"windows";}else if(ua.indexOf("macintosh")!=-1){return"mac";}else{return false;}}(),browser:function(){var ua=navigator.userAgent.toLowerCase();if(ua.indexOf('opera')!=-1){return'opera';}else if(ua.indexOf('msie 7')!=-1){return'ie7';}else if(ua.indexOf('msie')!=-1){return'ie';}else if(ua.indexOf('safari')!=-1){return'safari';}else if(ua.indexOf('gecko')!=-1){return'gecko';}else{return false;}}(),isSecure:function(){if(window.location.href.toLowerCase().indexOf("https")===0){return true;}else{return false;}}(),initDefaultConfig:function(){this.cfg.addProperty(DEFAULT_CONFIG.VISIBLE.key,{handler:this.configVisible,value:DEFAULT_CONFIG.VISIBLE.value,validator:DEFAULT_CONFIG.VISIBLE.validator});this.cfg.addProperty(DEFAULT_CONFIG.EFFECT.key,{suppressEvent:DEFAULT_CONFIG.EFFECT.suppressEvent,supercedes:DEFAULT_CONFIG.EFFECT.supercedes});this.cfg.addProperty(DEFAULT_CONFIG.MONITOR_RESIZE.key,{handler:this.configMonitorResize,value:DEFAULT_CONFIG.MONITOR_RESIZE.value});},init:function(el,userConfig){var elId,i,child;this.initEvents();this.beforeInitEvent.fire(Module);this.cfg=new Config(this);if(this.isSecure){this.imageRoot=Module.IMG_ROOT_SSL;}
if(typeof el=="string"){elId=el;el=document.getElementById(el);if(!el){el=(createModuleTemplate()).cloneNode(false);el.id=elId;}}
this.element=el;if(el.id){this.id=el.id;}
child=this.element.firstChild;if(child){do{switch(child.className){case Module.CSS_HEADER:this.header=child;break;case Module.CSS_BODY:this.body=child;break;case Module.CSS_FOOTER:this.footer=child;break;}}while((child=child.nextSibling));}
this.initDefaultConfig();Dom.addClass(this.element,Module.CSS_MODULE);if(userConfig){this.cfg.applyConfig(userConfig,true);}
if(!Config.alreadySubscribed(this.renderEvent,this.cfg.fireQueue,this.cfg)){this.renderEvent.subscribe(this.cfg.fireQueue,this.cfg,true);}
this.initEvent.fire(Module);},initResizeMonitor:function(){var oDoc,oIFrame,sHTML;function fireTextResize(){Module.textResizeEvent.fire();}
if(!YAHOO.env.ua.opera){oIFrame=Dom.get("_yuiResizeMonitor");if(!oIFrame){oIFrame=document.createElement("iframe");if(this.isSecure&&Module.RESIZE_MONITOR_SECURE_URL&&YAHOO.env.ua.ie){oIFrame.src=Module.RESIZE_MONITOR_SECURE_URL;}
if(YAHOO.env.ua.gecko){sHTML="<html><head><script "+"type=\"text/javascript\">"+"window.onresize=function(){window.parent."+"YAHOO.widget.Module.textResizeEvent."+"fire();};window.parent.YAHOO.widget.Module."+"textResizeEvent.fire();</script></head>"+"<body></body></html>";oIFrame.src="data:text/html;charset=utf-8,"+
encodeURIComponent(sHTML);}
oIFrame.id="_yuiResizeMonitor";oIFrame.style.position="absolute";oIFrame.style.visibility="hidden";document.body.appendChild(oIFrame);oIFrame.style.width="10em";oIFrame.style.height="10em";oIFrame.style.top=(-1*oIFrame.offsetHeight)+"px";oIFrame.style.left=(-1*oIFrame.offsetWidth)+"px";oIFrame.style.borderWidth="0";oIFrame.style.visibility="visible";if(YAHOO.env.ua.webkit){oDoc=oIFrame.contentWindow.document;oDoc.open();oDoc.close();}}
if(oIFrame&&oIFrame.contentWindow){Module.textResizeEvent.subscribe(this.onDomResize,this,true);if(!Module.textResizeInitialized){if(!Event.on(oIFrame.contentWindow,"resize",fireTextResize)){Event.on(oIFrame,"resize",fireTextResize);}
Module.textResizeInitialized=true;}
this.resizeMonitor=oIFrame;}}},onDomResize:function(e,obj){var nLeft=-1*this.resizeMonitor.offsetWidth,nTop=-1*this.resizeMonitor.offsetHeight;this.resizeMonitor.style.top=nTop+"px";this.resizeMonitor.style.left=nLeft+"px";},setHeader:function(headerContent){var oHeader=this.header||(this.header=createHeader());if(typeof headerContent=="string"){oHeader.innerHTML=headerContent;}else{oHeader.innerHTML="";oHeader.appendChild(headerContent);}
this.changeHeaderEvent.fire(headerContent);this.changeContentEvent.fire();},appendToHeader:function(element){var oHeader=this.header||(this.header=createHeader());oHeader.appendChild(element);this.changeHeaderEvent.fire(element);this.changeContentEvent.fire();},setBody:function(bodyContent){var oBody=this.body||(this.body=createBody());if(typeof bodyContent=="string"){oBody.innerHTML=bodyContent;}else{oBody.innerHTML="";oBody.appendChild(bodyContent);}
this.changeBodyEvent.fire(bodyContent);this.changeContentEvent.fire();},appendToBody:function(element){var oBody=this.body||(this.body=createBody());oBody.appendChild(element);this.changeBodyEvent.fire(element);this.changeContentEvent.fire();},setFooter:function(footerContent){var oFooter=this.footer||(this.footer=createFooter());if(typeof footerContent=="string"){oFooter.innerHTML=footerContent;}else{oFooter.innerHTML="";oFooter.appendChild(footerContent);}
this.changeFooterEvent.fire(footerContent);this.changeContentEvent.fire();},appendToFooter:function(element){var oFooter=this.footer||(this.footer=createFooter());oFooter.appendChild(element);this.changeFooterEvent.fire(element);this.changeContentEvent.fire();},render:function(appendToNode,moduleElement){var me=this,firstChild;function appendTo(element){if(typeof element=="string"){element=document.getElementById(element);}
if(element){element.appendChild(me.element);me.appendEvent.fire();}}
this.beforeRenderEvent.fire();if(!moduleElement){moduleElement=this.element;}
if(appendToNode){appendTo(appendToNode);}else{if(!Dom.inDocument(this.element)){return false;}}
if(this.header&&!Dom.inDocument(this.header)){firstChild=moduleElement.firstChild;if(firstChild){moduleElement.insertBefore(this.header,firstChild);}else{moduleElement.appendChild(this.header);}}
if(this.body&&!Dom.inDocument(this.body)){if(this.footer&&Dom.isAncestor(this.moduleElement,this.footer)){moduleElement.insertBefore(this.body,this.footer);}else{moduleElement.appendChild(this.body);}}
if(this.footer&&!Dom.inDocument(this.footer)){moduleElement.appendChild(this.footer);}
this.renderEvent.fire();return true;},destroy:function(){var parent,e;if(this.element){Event.purgeElement(this.element,true);parent=this.element.parentNode;}
if(parent){parent.removeChild(this.element);}
this.element=null;this.header=null;this.body=null;this.footer=null;Module.textResizeEvent.unsubscribe(this.onDomResize,this);this.cfg.destroy();this.cfg=null;this.destroyEvent.fire();for(e in this){if(e instanceof CustomEvent){e.unsubscribeAll();}}},show:function(){this.cfg.setProperty("visible",true);},hide:function(){this.cfg.setProperty("visible",false);},configVisible:function(type,args,obj){var visible=args[0];if(visible){this.beforeShowEvent.fire();Dom.setStyle(this.element,"display","block");this.showEvent.fire();}else{this.beforeHideEvent.fire();Dom.setStyle(this.element,"display","none");this.hideEvent.fire();}},configMonitorResize:function(type,args,obj){var monitor=args[0];if(monitor){this.initResizeMonitor();}else{Module.textResizeEvent.unsubscribe(this.onDomResize,this,true);this.resizeMonitor=null;}},toString:function(){return"Module "+this.id;}};YAHOO.lang.augmentProto(Module,YAHOO.util.EventProvider);}());(function(){YAHOO.widget.Overlay=function(el,userConfig){YAHOO.widget.Overlay.superclass.constructor.call(this,el,userConfig);};var Lang=YAHOO.lang,CustomEvent=YAHOO.util.CustomEvent,Module=YAHOO.widget.Module,Event=YAHOO.util.Event,Dom=YAHOO.util.Dom,Config=YAHOO.util.Config,Overlay=YAHOO.widget.Overlay,m_oIFrameTemplate,EVENT_TYPES={"BEFORE_MOVE":"beforeMove","MOVE":"move"},DEFAULT_CONFIG={"X":{key:"x",validator:Lang.isNumber,suppressEvent:true,supercedes:["iframe"]},"Y":{key:"y",validator:Lang.isNumber,suppressEvent:true,supercedes:["iframe"]},"XY":{key:"xy",suppressEvent:true,supercedes:["iframe"]},"CONTEXT":{key:"context",suppressEvent:true,supercedes:["iframe"]},"FIXED_CENTER":{key:"fixedcenter",value:false,validator:Lang.isBoolean,supercedes:["iframe","visible"]},"WIDTH":{key:"width",suppressEvent:true,supercedes:["context","fixedcenter","iframe"]},"HEIGHT":{key:"height",suppressEvent:true,supercedes:["context","fixedcenter","iframe"]},"ZINDEX":{key:"zindex",value:null},"CONSTRAIN_TO_VIEWPORT":{key:"constraintoviewport",value:false,validator:Lang.isBoolean,supercedes:["iframe","x","y","xy"]},"IFRAME":{key:"iframe",value:(YAHOO.env.ua.ie==6?true:false),validator:Lang.isBoolean,supercedes:["zindex"]}};Overlay.IFRAME_SRC="javascript:false;";Overlay.IFRAME_OFFSET=3;Overlay.TOP_LEFT="tl";Overlay.TOP_RIGHT="tr";Overlay.BOTTOM_LEFT="bl";Overlay.BOTTOM_RIGHT="br";Overlay.CSS_OVERLAY="yui-overlay";Overlay.windowScrollEvent=new CustomEvent("windowScroll");Overlay.windowResizeEvent=new CustomEvent("windowResize");Overlay.windowScrollHandler=function(e){if(YAHOO.env.ua.ie){if(!window.scrollEnd){window.scrollEnd=-1;}
clearTimeout(window.scrollEnd);window.scrollEnd=setTimeout(function(){Overlay.windowScrollEvent.fire();},1);}else{Overlay.windowScrollEvent.fire();}};Overlay.windowResizeHandler=function(e){if(YAHOO.env.ua.ie){if(!window.resizeEnd){window.resizeEnd=-1;}
clearTimeout(window.resizeEnd);window.resizeEnd=setTimeout(function(){Overlay.windowResizeEvent.fire();},100);}else{Overlay.windowResizeEvent.fire();}};Overlay._initialized=null;if(Overlay._initialized===null){Event.on(window,"scroll",Overlay.windowScrollHandler);Event.on(window,"resize",Overlay.windowResizeHandler);Overlay._initialized=true;}
YAHOO.extend(Overlay,Module,{init:function(el,userConfig){Overlay.superclass.init.call(this,el);this.beforeInitEvent.fire(Overlay);Dom.addClass(this.element,Overlay.CSS_OVERLAY);if(userConfig){this.cfg.applyConfig(userConfig,true);}
if(this.platform=="mac"&&YAHOO.env.ua.gecko){if(!Config.alreadySubscribed(this.showEvent,this.showMacGeckoScrollbars,this)){this.showEvent.subscribe(this.showMacGeckoScrollbars,this,true);}
if(!Config.alreadySubscribed(this.hideEvent,this.hideMacGeckoScrollbars,this)){this.hideEvent.subscribe(this.hideMacGeckoScrollbars,this,true);}}
this.initEvent.fire(Overlay);},initEvents:function(){Overlay.superclass.initEvents.call(this);var SIGNATURE=CustomEvent.LIST;this.beforeMoveEvent=this.createEvent(EVENT_TYPES.BEFORE_MOVE);this.beforeMoveEvent.signature=SIGNATURE;this.moveEvent=this.createEvent(EVENT_TYPES.MOVE);this.moveEvent.signature=SIGNATURE;},initDefaultConfig:function(){Overlay.superclass.initDefaultConfig.call(this);this.cfg.addProperty(DEFAULT_CONFIG.X.key,{handler:this.configX,validator:DEFAULT_CONFIG.X.validator,suppressEvent:DEFAULT_CONFIG.X.suppressEvent,supercedes:DEFAULT_CONFIG.X.supercedes});this.cfg.addProperty(DEFAULT_CONFIG.Y.key,{handler:this.configY,validator:DEFAULT_CONFIG.Y.validator,suppressEvent:DEFAULT_CONFIG.Y.suppressEvent,supercedes:DEFAULT_CONFIG.Y.supercedes});this.cfg.addProperty(DEFAULT_CONFIG.XY.key,{handler:this.configXY,suppressEvent:DEFAULT_CONFIG.XY.suppressEvent,supercedes:DEFAULT_CONFIG.XY.supercedes});this.cfg.addProperty(DEFAULT_CONFIG.CONTEXT.key,{handler:this.configContext,suppressEvent:DEFAULT_CONFIG.CONTEXT.suppressEvent,supercedes:DEFAULT_CONFIG.CONTEXT.supercedes});this.cfg.addProperty(DEFAULT_CONFIG.FIXED_CENTER.key,{handler:this.configFixedCenter,value:DEFAULT_CONFIG.FIXED_CENTER.value,validator:DEFAULT_CONFIG.FIXED_CENTER.validator,supercedes:DEFAULT_CONFIG.FIXED_CENTER.supercedes});this.cfg.addProperty(DEFAULT_CONFIG.WIDTH.key,{handler:this.configWidth,suppressEvent:DEFAULT_CONFIG.WIDTH.suppressEvent,supercedes:DEFAULT_CONFIG.WIDTH.supercedes});this.cfg.addProperty(DEFAULT_CONFIG.HEIGHT.key,{handler:this.configHeight,suppressEvent:DEFAULT_CONFIG.HEIGHT.suppressEvent,supercedes:DEFAULT_CONFIG.HEIGHT.supercedes});this.cfg.addProperty(DEFAULT_CONFIG.ZINDEX.key,{handler:this.configzIndex,value:DEFAULT_CONFIG.ZINDEX.value});this.cfg.addProperty(DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.key,{handler:this.configConstrainToViewport,value:DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.value,validator:DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.validator,supercedes:DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.supercedes});this.cfg.addProperty(DEFAULT_CONFIG.IFRAME.key,{handler:this.configIframe,value:DEFAULT_CONFIG.IFRAME.value,validator:DEFAULT_CONFIG.IFRAME.validator,supercedes:DEFAULT_CONFIG.IFRAME.supercedes});},moveTo:function(x,y){this.cfg.setProperty("xy",[x,y]);},hideMacGeckoScrollbars:function(){Dom.removeClass(this.element,"show-scrollbars");Dom.addClass(this.element,"hide-scrollbars");},showMacGeckoScrollbars:function(){Dom.removeClass(this.element,"hide-scrollbars");Dom.addClass(this.element,"show-scrollbars");},configVisible:function(type,args,obj){var visible=args[0],currentVis=Dom.getStyle(this.element,"visibility"),effect=this.cfg.getProperty("effect"),effectInstances=[],isMacGecko=(this.platform=="mac"&&YAHOO.env.ua.gecko),alreadySubscribed=Config.alreadySubscribed,eff,ei,e,i,j,k,h,nEffects,nEffectInstances;if(currentVis=="inherit"){e=this.element.parentNode;while(e.nodeType!=9&&e.nodeType!=11){currentVis=Dom.getStyle(e,"visibility");if(currentVis!="inherit"){break;}
e=e.parentNode;}
if(currentVis=="inherit"){currentVis="visible";}}
if(effect){if(effect instanceof Array){nEffects=effect.length;for(i=0;i<nEffects;i++){eff=effect[i];effectInstances[effectInstances.length]=eff.effect(this,eff.duration);}}else{effectInstances[effectInstances.length]=effect.effect(this,effect.duration);}}
if(visible){if(isMacGecko){this.showMacGeckoScrollbars();}
if(effect){if(visible){if(currentVis!="visible"||currentVis===""){this.beforeShowEvent.fire();nEffectInstances=effectInstances.length;for(j=0;j<nEffectInstances;j++){ei=effectInstances[j];if(j===0&&!alreadySubscribed(ei.animateInCompleteEvent,this.showEvent.fire,this.showEvent)){ei.animateInCompleteEvent.subscribe(this.showEvent.fire,this.showEvent,true);}
ei.animateIn();}}}}else{if(currentVis!="visible"||currentVis===""){this.beforeShowEvent.fire();Dom.setStyle(this.element,"visibility","visible");this.cfg.refireEvent("iframe");this.showEvent.fire();}}}else{if(isMacGecko){this.hideMacGeckoScrollbars();}
if(effect){if(currentVis=="visible"){this.beforeHideEvent.fire();nEffectInstances=effectInstances.length;for(k=0;k<nEffectInstances;k++){h=effectInstances[k];if(k===0&&!alreadySubscribed(h.animateOutCompleteEvent,this.hideEvent.fire,this.hideEvent)){h.animateOutCompleteEvent.subscribe(this.hideEvent.fire,this.hideEvent,true);}
h.animateOut();}}else if(currentVis===""){Dom.setStyle(this.element,"visibility","hidden");}}else{if(currentVis=="visible"||currentVis===""){this.beforeHideEvent.fire();Dom.setStyle(this.element,"visibility","hidden");this.hideEvent.fire();}}}},doCenterOnDOMEvent:function(){if(this.cfg.getProperty("visible")){this.center();}},configFixedCenter:function(type,args,obj){var val=args[0],alreadySubscribed=Config.alreadySubscribed,windowResizeEvent=Overlay.windowResizeEvent,windowScrollEvent=Overlay.windowScrollEvent;if(val){this.center();if(!alreadySubscribed(this.beforeShowEvent,this.center,this)){this.beforeShowEvent.subscribe(this.center);}
if(!alreadySubscribed(windowResizeEvent,this.doCenterOnDOMEvent,this)){windowResizeEvent.subscribe(this.doCenterOnDOMEvent,this,true);}
if(!alreadySubscribed(windowScrollEvent,this.doCenterOnDOMEvent,this)){windowScrollEvent.subscribe(this.doCenterOnDOMEvent,this,true);}}else{this.beforeShowEvent.unsubscribe(this.center);windowResizeEvent.unsubscribe(this.doCenterOnDOMEvent,this);windowScrollEvent.unsubscribe(this.doCenterOnDOMEvent,this);}},configHeight:function(type,args,obj){var height=args[0],el=this.element;Dom.setStyle(el,"height",height);this.cfg.refireEvent("iframe");},configWidth:function(type,args,obj){var width=args[0],el=this.element;Dom.setStyle(el,"width",width);this.cfg.refireEvent("iframe");},configzIndex:function(type,args,obj){var zIndex=args[0],el=this.element;if(!zIndex){zIndex=Dom.getStyle(el,"zIndex");if(!zIndex||isNaN(zIndex)){zIndex=0;}}
if(this.iframe){if(zIndex<=0){zIndex=1;}
Dom.setStyle(this.iframe,"zIndex",(zIndex-1));}
Dom.setStyle(el,"zIndex",zIndex);this.cfg.setProperty("zIndex",zIndex,true);},configXY:function(type,args,obj){var pos=args[0],x=pos[0],y=pos[1];this.cfg.setProperty("x",x);this.cfg.setProperty("y",y);this.beforeMoveEvent.fire([x,y]);x=this.cfg.getProperty("x");y=this.cfg.getProperty("y");this.cfg.refireEvent("iframe");this.moveEvent.fire([x,y]);},configX:function(type,args,obj){var x=args[0],y=this.cfg.getProperty("y");this.cfg.setProperty("x",x,true);this.cfg.setProperty("y",y,true);this.beforeMoveEvent.fire([x,y]);x=this.cfg.getProperty("x");y=this.cfg.getProperty("y");Dom.setX(this.element,x,true);this.cfg.setProperty("xy",[x,y],true);this.cfg.refireEvent("iframe");this.moveEvent.fire([x,y]);},configY:function(type,args,obj){var x=this.cfg.getProperty("x"),y=args[0];this.cfg.setProperty("x",x,true);this.cfg.setProperty("y",y,true);this.beforeMoveEvent.fire([x,y]);x=this.cfg.getProperty("x");y=this.cfg.getProperty("y");Dom.setY(this.element,y,true);this.cfg.setProperty("xy",[x,y],true);this.cfg.refireEvent("iframe");this.moveEvent.fire([x,y]);},showIframe:function(){var oIFrame=this.iframe,oParentNode;if(oIFrame){oParentNode=this.element.parentNode;if(oParentNode!=oIFrame.parentNode){oParentNode.appendChild(oIFrame);}
oIFrame.style.display="block";}},hideIframe:function(){if(this.iframe){this.iframe.style.display="none";}},syncIframe:function(){var oIFrame=this.iframe,oElement=this.element,nOffset=Overlay.IFRAME_OFFSET,nDimensionOffset=(nOffset*2),aXY;if(oIFrame){oIFrame.style.width=(oElement.offsetWidth+nDimensionOffset+"px");oIFrame.style.height=(oElement.offsetHeight+nDimensionOffset+"px");aXY=this.cfg.getProperty("xy");if(!Lang.isArray(aXY)||(isNaN(aXY[0])||isNaN(aXY[1]))){this.syncPosition();aXY=this.cfg.getProperty("xy");}
Dom.setXY(oIFrame,[(aXY[0]-nOffset),(aXY[1]-nOffset)]);}},configIframe:function(type,args,obj){var bIFrame=args[0];function createIFrame(){var oIFrame=this.iframe,oElement=this.element,oParent,aXY;if(!oIFrame){if(!m_oIFrameTemplate){m_oIFrameTemplate=document.createElement("iframe");if(this.isSecure){m_oIFrameTemplate.src=Overlay.IFRAME_SRC;}
if(YAHOO.env.ua.ie){m_oIFrameTemplate.style.filter="alpha(opacity=0)";m_oIFrameTemplate.frameBorder=0;}
else{m_oIFrameTemplate.style.opacity="0";}
m_oIFrameTemplate.style.position="absolute";m_oIFrameTemplate.style.border="none";m_oIFrameTemplate.style.margin="0";m_oIFrameTemplate.style.padding="0";m_oIFrameTemplate.style.display="none";}
oIFrame=m_oIFrameTemplate.cloneNode(false);oParent=oElement.parentNode;if(oParent){oParent.appendChild(oIFrame);}else{document.body.appendChild(oIFrame);}
this.iframe=oIFrame;}
this.showIframe();this.syncIframe();if(!this._hasIframeEventListeners){this.showEvent.subscribe(this.showIframe);this.hideEvent.subscribe(this.hideIframe);this.changeContentEvent.subscribe(this.syncIframe);this._hasIframeEventListeners=true;}}
function onBeforeShow(){createIFrame.call(this);this.beforeShowEvent.unsubscribe(onBeforeShow);this._iframeDeferred=false;}
if(bIFrame){if(this.cfg.getProperty("visible")){createIFrame.call(this);}
else{if(!this._iframeDeferred){this.beforeShowEvent.subscribe(onBeforeShow);this._iframeDeferred=true;}}}else{this.hideIframe();if(this._hasIframeEventListeners){this.showEvent.unsubscribe(this.showIframe);this.hideEvent.unsubscribe(this.hideIframe);this.changeContentEvent.unsubscribe(this.syncIframe);this._hasIframeEventListeners=false;}}},configConstrainToViewport:function(type,args,obj){var val=args[0];if(val){if(!Config.alreadySubscribed(this.beforeMoveEvent,this.enforceConstraints,this)){this.beforeMoveEvent.subscribe(this.enforceConstraints,this,true);}}else{this.beforeMoveEvent.unsubscribe(this.enforceConstraints,this);}},configContext:function(type,args,obj){var contextArgs=args[0],contextEl,elementMagnetCorner,contextMagnetCorner;if(contextArgs){contextEl=contextArgs[0];elementMagnetCorner=contextArgs[1];contextMagnetCorner=contextArgs[2];if(contextEl){if(typeof contextEl=="string"){this.cfg.setProperty("context",[document.getElementById(contextEl),elementMagnetCorner,contextMagnetCorner],true);}
if(elementMagnetCorner&&contextMagnetCorner){this.align(elementMagnetCorner,contextMagnetCorner);}}}},align:function(elementAlign,contextAlign){var contextArgs=this.cfg.getProperty("context"),me=this,context,element,contextRegion;function doAlign(v,h){switch(elementAlign){case Overlay.TOP_LEFT:me.moveTo(h,v);break;case Overlay.TOP_RIGHT:me.moveTo((h-element.offsetWidth),v);break;case Overlay.BOTTOM_LEFT:me.moveTo(h,(v-element.offsetHeight));break;case Overlay.BOTTOM_RIGHT:me.moveTo((h-element.offsetWidth),(v-element.offsetHeight));break;}}
if(contextArgs){context=contextArgs[0];element=this.element;me=this;if(!elementAlign){elementAlign=contextArgs[1];}
if(!contextAlign){contextAlign=contextArgs[2];}
if(element&&context){contextRegion=Dom.getRegion(context);switch(contextAlign){case Overlay.TOP_LEFT:doAlign(contextRegion.top,contextRegion.left);break;case Overlay.TOP_RIGHT:doAlign(contextRegion.top,contextRegion.right);break;case Overlay.BOTTOM_LEFT:doAlign(contextRegion.bottom,contextRegion.left);break;case Overlay.BOTTOM_RIGHT:doAlign(contextRegion.bottom,contextRegion.right);break;}}}},enforceConstraints:function(type,args,obj){var pos=args[0],x=pos[0],y=pos[1],offsetHeight=this.element.offsetHeight,offsetWidth=this.element.offsetWidth,viewPortWidth=Dom.getViewportWidth(),viewPortHeight=Dom.getViewportHeight(),scrollX=Dom.getDocumentScrollLeft(),scrollY=Dom.getDocumentScrollTop(),topConstraint=scrollY+10,leftConstraint=scrollX+10,bottomConstraint=scrollY+viewPortHeight-offsetHeight-10,rightConstraint=scrollX+viewPortWidth-offsetWidth-10;if(x<leftConstraint){x=leftConstraint;}else if(x>rightConstraint){x=rightConstraint;}
if(y<topConstraint){y=topConstraint;}else if(y>bottomConstraint){y=bottomConstraint;}
this.cfg.setProperty("x",x,true);this.cfg.setProperty("y",y,true);this.cfg.setProperty("xy",[x,y],true);},center:function(){var scrollX=Dom.getDocumentScrollLeft(),scrollY=Dom.getDocumentScrollTop(),viewPortWidth=Dom.getClientWidth(),viewPortHeight=Dom.getClientHeight(),elementWidth=this.element.offsetWidth,elementHeight=this.element.offsetHeight,x=(viewPortWidth/2)-(elementWidth/2)+scrollX,y=(viewPortHeight/2)-(elementHeight/2)+scrollY;this.cfg.setProperty("xy",[parseInt(x,10),parseInt(y,10)]);this.cfg.refireEvent("iframe");},syncPosition:function(){var pos=Dom.getXY(this.element);this.cfg.setProperty("x",pos[0],true);this.cfg.setProperty("y",pos[1],true);this.cfg.setProperty("xy",pos,true);},onDomResize:function(e,obj){var me=this;Overlay.superclass.onDomResize.call(this,e,obj);setTimeout(function(){me.syncPosition();me.cfg.refireEvent("iframe");me.cfg.refireEvent("context");},0);},bringToTop:function(){var aOverlays=[],oElement=this.element;function compareZIndexDesc(p_oOverlay1,p_oOverlay2){var sZIndex1=Dom.getStyle(p_oOverlay1,"zIndex"),sZIndex2=Dom.getStyle(p_oOverlay2,"zIndex"),nZIndex1=(!sZIndex1||isNaN(sZIndex1))?0:parseInt(sZIndex1,10),nZIndex2=(!sZIndex2||isNaN(sZIndex2))?0:parseInt(sZIndex2,10);if(nZIndex1>nZIndex2){return-1;}else if(nZIndex1<nZIndex2){return 1;}else{return 0;}}
function isOverlayElement(p_oElement){var oOverlay=Dom.hasClass(p_oElement,Overlay.CSS_OVERLAY),Panel=YAHOO.widget.Panel;if(oOverlay&&!Dom.isAncestor(oElement,oOverlay)){if(Panel&&Dom.hasClass(p_oElement,Panel.CSS_PANEL)){aOverlays[aOverlays.length]=p_oElement.parentNode;}
else{aOverlays[aOverlays.length]=p_oElement;}}}
Dom.getElementsBy(isOverlayElement,"DIV",document.body);aOverlays.sort(compareZIndexDesc);var oTopOverlay=aOverlays[0],nTopZIndex;if(oTopOverlay){nTopZIndex=Dom.getStyle(oTopOverlay,"zIndex");if(!isNaN(nTopZIndex)&&oTopOverlay!=oElement){this.cfg.setProperty("zindex",(parseInt(nTopZIndex,10)+2));}}},destroy:function(){if(this.iframe){this.iframe.parentNode.removeChild(this.iframe);}
this.iframe=null;Overlay.windowResizeEvent.unsubscribe(this.doCenterOnDOMEvent,this);Overlay.windowScrollEvent.unsubscribe(this.doCenterOnDOMEvent,this);Overlay.superclass.destroy.call(this);},toString:function(){return"Overlay "+this.id;}});}());(function(){YAHOO.widget.OverlayManager=function(userConfig){this.init(userConfig);};var Overlay=YAHOO.widget.Overlay,Event=YAHOO.util.Event,Dom=YAHOO.util.Dom,Config=YAHOO.util.Config,CustomEvent=YAHOO.util.CustomEvent,OverlayManager=YAHOO.widget.OverlayManager;OverlayManager.CSS_FOCUSED="focused";OverlayManager.prototype={constructor:OverlayManager,overlays:null,initDefaultConfig:function(){this.cfg.addProperty("overlays",{suppressEvent:true});this.cfg.addProperty("focusevent",{value:"mousedown"});},init:function(userConfig){this.cfg=new Config(this);this.initDefaultConfig();if(userConfig){this.cfg.applyConfig(userConfig,true);}
this.cfg.fireQueue();var activeOverlay=null;this.getActive=function(){return activeOverlay;};this.focus=function(overlay){var o=this.find(overlay);if(o){if(activeOverlay!=o){if(activeOverlay){activeOverlay.blur();}
this.bringToTop(o);activeOverlay=o;Dom.addClass(activeOverlay.element,OverlayManager.CSS_FOCUSED);o.focusEvent.fire();}}};this.remove=function(overlay){var o=this.find(overlay),originalZ;if(o){if(activeOverlay==o){activeOverlay=null;}
originalZ=Dom.getStyle(o.element,"zIndex");o.cfg.setProperty("zIndex",-1000,true);this.overlays.sort(this.compareZIndexDesc);this.overlays=this.overlays.slice(0,(this.overlays.length-1));o.hideEvent.unsubscribe(o.blur);o.destroyEvent.unsubscribe(this._onOverlayDestroy,o);if(o.element){Event.removeListener(o.element,this.cfg.getProperty("focusevent"),this._onOverlayElementFocus);}
o.cfg.setProperty("zIndex",originalZ,true);o.cfg.setProperty("manager",null);o.focusEvent.unsubscribeAll();o.blurEvent.unsubscribeAll();o.focusEvent=null;o.blurEvent=null;o.focus=null;o.blur=null;}};this.blurAll=function(){var nOverlays=this.overlays.length,i;if(nOverlays>0){i=nOverlays-1;do{this.overlays[i].blur();}
while(i--);}};this._onOverlayBlur=function(p_sType,p_aArgs){activeOverlay=null;};var overlays=this.cfg.getProperty("overlays");if(!this.overlays){this.overlays=[];}
if(overlays){this.register(overlays);this.overlays.sort(this.compareZIndexDesc);}},_onOverlayElementFocus:function(p_oEvent){var oTarget=Event.getTarget(p_oEvent),oClose=this.close;if(oClose&&(oTarget==oClose||Dom.isAncestor(oClose,oTarget))){this.blur();}
else{this.focus();}},_onOverlayDestroy:function(p_sType,p_aArgs,p_oOverlay){this.remove(p_oOverlay);},register:function(overlay){var mgr=this,zIndex,regcount,i,nOverlays;if(overlay instanceof Overlay){overlay.cfg.addProperty("manager",{value:this});overlay.focusEvent=overlay.createEvent("focus");overlay.focusEvent.signature=CustomEvent.LIST;overlay.blurEvent=overlay.createEvent("blur");overlay.blurEvent.signature=CustomEvent.LIST;overlay.focus=function(){mgr.focus(this);};overlay.blur=function(){if(mgr.getActive()==this){Dom.removeClass(this.element,OverlayManager.CSS_FOCUSED);this.blurEvent.fire();}};overlay.blurEvent.subscribe(mgr._onOverlayBlur);overlay.hideEvent.subscribe(overlay.blur);overlay.destroyEvent.subscribe(this._onOverlayDestroy,overlay,this);Event.on(overlay.element,this.cfg.getProperty("focusevent"),this._onOverlayElementFocus,null,overlay);zIndex=Dom.getStyle(overlay.element,"zIndex");if(!isNaN(zIndex)){overlay.cfg.setProperty("zIndex",parseInt(zIndex,10));}else{overlay.cfg.setProperty("zIndex",0);}
this.overlays.push(overlay);this.bringToTop(overlay);return true;}else if(overlay instanceof Array){regcount=0;nOverlays=overlay.length;for(i=0;i<nOverlays;i++){if(this.register(overlay[i])){regcount++;}}
if(regcount>0){return true;}}else{return false;}},bringToTop:function(p_oOverlay){var oOverlay=this.find(p_oOverlay),nTopZIndex,oTopOverlay,aOverlays;if(oOverlay){aOverlays=this.overlays;aOverlays.sort(this.compareZIndexDesc);oTopOverlay=aOverlays[0];if(oTopOverlay){nTopZIndex=Dom.getStyle(oTopOverlay.element,"zIndex");if(!isNaN(nTopZIndex)&&oTopOverlay!=oOverlay){oOverlay.cfg.setProperty("zIndex",(parseInt(nTopZIndex,10)+2));}
aOverlays.sort(this.compareZIndexDesc);}}},find:function(overlay){var aOverlays=this.overlays,nOverlays=aOverlays.length,i;if(nOverlays>0){i=nOverlays-1;if(overlay instanceof Overlay){do{if(aOverlays[i]==overlay){return aOverlays[i];}}
while(i--);}else if(typeof overlay=="string"){do{if(aOverlays[i].id==overlay){return aOverlays[i];}}
while(i--);}
return null;}},compareZIndexDesc:function(o1,o2){var zIndex1=o1.cfg.getProperty("zIndex"),zIndex2=o2.cfg.getProperty("zIndex");if(zIndex1>zIndex2){return-1;}else if(zIndex1<zIndex2){return 1;}else{return 0;}},showAll:function(){var aOverlays=this.overlays,nOverlays=aOverlays.length,i;if(nOverlays>0){i=nOverlays-1;do{aOverlays[i].show();}
while(i--);}},hideAll:function(){var aOverlays=this.overlays,nOverlays=aOverlays.length,i;if(nOverlays>0){i=nOverlays-1;do{aOverlays[i].hide();}
while(i--);}},toString:function(){return"OverlayManager";}};}());(function(){YAHOO.widget.Tooltip=function(el,userConfig){YAHOO.widget.Tooltip.superclass.constructor.call(this,el,userConfig);};var Lang=YAHOO.lang,Event=YAHOO.util.Event,Dom=YAHOO.util.Dom,Tooltip=YAHOO.widget.Tooltip,m_oShadowTemplate,DEFAULT_CONFIG={"PREVENT_OVERLAP":{key:"preventoverlap",value:true,validator:Lang.isBoolean,supercedes:["x","y","xy"]},"SHOW_DELAY":{key:"showdelay",value:200,validator:Lang.isNumber},"AUTO_DISMISS_DELAY":{key:"autodismissdelay",value:5000,validator:Lang.isNumber},"HIDE_DELAY":{key:"hidedelay",value:250,validator:Lang.isNumber},"TEXT":{key:"text",suppressEvent:true},"CONTAINER":{key:"container"}};Tooltip.CSS_TOOLTIP="yui-tt";function restoreOriginalWidth(p_sType,p_aArgs,p_oObject){var sOriginalWidth=p_oObject[0],sNewWidth=p_oObject[1],oConfig=this.cfg,sCurrentWidth=oConfig.getProperty("width");if(sCurrentWidth==sNewWidth){oConfig.setProperty("width",sOriginalWidth);}
this.unsubscribe("hide",this._onHide,p_oObject);}
function setWidthToOffsetWidth(p_sType,p_aArgs){var oBody=document.body,oConfig=this.cfg,sOriginalWidth=oConfig.getProperty("width"),sNewWidth,oClone;if((!sOriginalWidth||sOriginalWidth=="auto")&&(oConfig.getProperty("container")!=oBody||oConfig.getProperty("x")>=Dom.getViewportWidth()||oConfig.getProperty("y")>=Dom.getViewportHeight())){oClone=this.element.cloneNode(true);oClone.style.visibility="hidden";oClone.style.top="0px";oClone.style.left="0px";oBody.appendChild(oClone);sNewWidth=(oClone.offsetWidth+"px");oBody.removeChild(oClone);oClone=null;oConfig.setProperty("width",sNewWidth);oConfig.refireEvent("xy");this.subscribe("hide",restoreOriginalWidth,[(sOriginalWidth||""),sNewWidth]);}}
function onDOMReady(p_sType,p_aArgs,p_oObject){this.render(p_oObject);}
function onInit(){Event.onDOMReady(onDOMReady,this.cfg.getProperty("container"),this);}
YAHOO.extend(Tooltip,YAHOO.widget.Overlay,{init:function(el,userConfig){Tooltip.superclass.init.call(this,el);this.beforeInitEvent.fire(Tooltip);Dom.addClass(this.element,Tooltip.CSS_TOOLTIP);if(userConfig){this.cfg.applyConfig(userConfig,true);}
this.cfg.queueProperty("visible",false);this.cfg.queueProperty("constraintoviewport",true);this.setBody("");this.subscribe("beforeShow",setWidthToOffsetWidth);this.subscribe("init",onInit);this.subscribe("render",this.onRender);this.initEvent.fire(Tooltip);},initDefaultConfig:function(){Tooltip.superclass.initDefaultConfig.call(this);this.cfg.addProperty(DEFAULT_CONFIG.PREVENT_OVERLAP.key,{value:DEFAULT_CONFIG.PREVENT_OVERLAP.value,validator:DEFAULT_CONFIG.PREVENT_OVERLAP.validator,supercedes:DEFAULT_CONFIG.PREVENT_OVERLAP.supercedes});this.cfg.addProperty(DEFAULT_CONFIG.SHOW_DELAY.key,{handler:this.configShowDelay,value:200,validator:DEFAULT_CONFIG.SHOW_DELAY.validator});this.cfg.addProperty(DEFAULT_CONFIG.AUTO_DISMISS_DELAY.key,{handler:this.configAutoDismissDelay,value:DEFAULT_CONFIG.AUTO_DISMISS_DELAY.value,validator:DEFAULT_CONFIG.AUTO_DISMISS_DELAY.validator});this.cfg.addProperty(DEFAULT_CONFIG.HIDE_DELAY.key,{handler:this.configHideDelay,value:DEFAULT_CONFIG.HIDE_DELAY.value,validator:DEFAULT_CONFIG.HIDE_DELAY.validator});this.cfg.addProperty(DEFAULT_CONFIG.TEXT.key,{handler:this.configText,suppressEvent:DEFAULT_CONFIG.TEXT.suppressEvent});this.cfg.addProperty(DEFAULT_CONFIG.CONTAINER.key,{handler:this.configContainer,value:document.body});},configText:function(type,args,obj){var text=args[0];if(text){this.setBody(text);}},configContainer:function(type,args,obj){var container=args[0];if(typeof container=='string'){this.cfg.setProperty("container",document.getElementById(container),true);}},_removeEventListeners:function(){var aElements=this._context,nElements,oElement,i;if(aElements){nElements=aElements.length;if(nElements>0){i=nElements-1;do{oElement=aElements[i];Event.removeListener(oElement,"mouseover",this.onContextMouseOver);Event.removeListener(oElement,"mousemove",this.onContextMouseMove);Event.removeListener(oElement,"mouseout",this.onContextMouseOut);}
while(i--);}}},configContext:function(type,args,obj){var context=args[0],aElements,nElements,oElement,i;if(context){if(!(context instanceof Array)){if(typeof context=="string"){this.cfg.setProperty("context",[document.getElementById(context)],true);}else{this.cfg.setProperty("context",[context],true);}
context=this.cfg.getProperty("context");}
this._removeEventListeners();this._context=context;aElements=this._context;if(aElements){nElements=aElements.length;if(nElements>0){i=nElements-1;do{oElement=aElements[i];Event.on(oElement,"mouseover",this.onContextMouseOver,this);Event.on(oElement,"mousemove",this.onContextMouseMove,this);Event.on(oElement,"mouseout",this.onContextMouseOut,this);}
while(i--);}}}},onContextMouseMove:function(e,obj){obj.pageX=Event.getPageX(e);obj.pageY=Event.getPageY(e);},onContextMouseOver:function(e,obj){var context=this;if(obj.hideProcId){clearTimeout(obj.hideProcId);obj.hideProcId=null;}
Event.on(context,"mousemove",obj.onContextMouseMove,obj);if(context.title){obj._tempTitle=context.title;context.title="";}
obj.showProcId=obj.doShow(e,context);},onContextMouseOut:function(e,obj){var el=this;if(obj._tempTitle){el.title=obj._tempTitle;obj._tempTitle=null;}
if(obj.showProcId){clearTimeout(obj.showProcId);obj.showProcId=null;}
if(obj.hideProcId){clearTimeout(obj.hideProcId);obj.hideProcId=null;}
obj.hideProcId=setTimeout(function(){obj.hide();},obj.cfg.getProperty("hidedelay"));},doShow:function(e,context){var yOffset=25,me=this;if(YAHOO.env.ua.opera&&context.tagName&&context.tagName.toUpperCase()=="A"){yOffset+=12;}
return setTimeout(function(){if(me._tempTitle){me.setBody(me._tempTitle);}else{me.cfg.refireEvent("text");}
me.moveTo(me.pageX,me.pageY+yOffset);if(me.cfg.getProperty("preventoverlap")){me.preventOverlap(me.pageX,me.pageY);}
Event.removeListener(context,"mousemove",me.onContextMouseMove);me.show();me.hideProcId=me.doHide();},this.cfg.getProperty("showdelay"));},doHide:function(){var me=this;return setTimeout(function(){me.hide();},this.cfg.getProperty("autodismissdelay"));},preventOverlap:function(pageX,pageY){var height=this.element.offsetHeight,mousePoint=new YAHOO.util.Point(pageX,pageY),elementRegion=Dom.getRegion(this.element);elementRegion.top-=5;elementRegion.left-=5;elementRegion.right+=5;elementRegion.bottom+=5;if(elementRegion.contains(mousePoint)){this.cfg.setProperty("y",(pageY-height-5));}},onRender:function(p_sType,p_aArgs){function sizeShadow(){var oElement=this.element,oShadow=this._shadow;if(oShadow){oShadow.style.width=(oElement.offsetWidth+6)+"px";oShadow.style.height=(oElement.offsetHeight+1)+"px";}}
function addShadowVisibleClass(){Dom.addClass(this._shadow,"yui-tt-shadow-visible");}
function removeShadowVisibleClass(){Dom.removeClass(this._shadow,"yui-tt-shadow-visible");}
function createShadow(){var oShadow=this._shadow,oElement,Module,nIE,me;if(!oShadow){oElement=this.element;Module=YAHOO.widget.Module;nIE=YAHOO.env.ua.ie;me=this;if(!m_oShadowTemplate){m_oShadowTemplate=document.createElement("div");m_oShadowTemplate.className="yui-tt-shadow";}
oShadow=m_oShadowTemplate.cloneNode(false);oElement.appendChild(oShadow);this._shadow=oShadow;addShadowVisibleClass.call(this);this.subscribe("beforeShow",addShadowVisibleClass);this.subscribe("beforeHide",removeShadowVisibleClass);if(nIE==6||(nIE==7&&document.compatMode=="BackCompat")){window.setTimeout(function(){sizeShadow.call(me);},0);this.cfg.subscribeToConfigEvent("width",sizeShadow);this.cfg.subscribeToConfigEvent("height",sizeShadow);this.subscribe("changeContent",sizeShadow);Module.textResizeEvent.subscribe(sizeShadow,this,true);this.subscribe("destroy",function(){Module.textResizeEvent.unsubscribe(sizeShadow,this);});}}}
function onBeforeShow(){createShadow.call(this);this.unsubscribe("beforeShow",onBeforeShow);}
if(this.cfg.getProperty("visible")){createShadow.call(this);}
else{this.subscribe("beforeShow",onBeforeShow);}},destroy:function(){this._removeEventListeners();Tooltip.superclass.destroy.call(this);},toString:function(){return"Tooltip "+this.id;}});}());(function(){YAHOO.widget.Panel=function(el,userConfig){YAHOO.widget.Panel.superclass.constructor.call(this,el,userConfig);};var Lang=YAHOO.lang,DD=YAHOO.util.DD,Dom=YAHOO.util.Dom,Event=YAHOO.util.Event,Overlay=YAHOO.widget.Overlay,CustomEvent=YAHOO.util.CustomEvent,Config=YAHOO.util.Config,Panel=YAHOO.widget.Panel,m_oMaskTemplate,m_oUnderlayTemplate,m_oCloseIconTemplate,EVENT_TYPES={"SHOW_MASK":"showMask","HIDE_MASK":"hideMask","DRAG":"drag"},DEFAULT_CONFIG={"CLOSE":{key:"close",value:true,validator:Lang.isBoolean,supercedes:["visible"]},"DRAGGABLE":{key:"draggable",value:(DD?true:false),validator:Lang.isBoolean,supercedes:["visible"]},"UNDERLAY":{key:"underlay",value:"shadow",supercedes:["visible"]},"MODAL":{key:"modal",value:false,validator:Lang.isBoolean,supercedes:["visible"]},"KEY_LISTENERS":{key:"keylisteners",suppressEvent:true,supercedes:["visible"]}};Panel.CSS_PANEL="yui-panel";Panel.CSS_PANEL_CONTAINER="yui-panel-container";function createHeader(p_sType,p_aArgs){if(!this.header){this.setHeader("&#160;");}}
function restoreOriginalWidth(p_sType,p_aArgs,p_oObject){var sOriginalWidth=p_oObject[0],sNewWidth=p_oObject[1],oConfig=this.cfg,sCurrentWidth=oConfig.getProperty("width");if(sCurrentWidth==sNewWidth){oConfig.setProperty("width",sOriginalWidth);}
this.unsubscribe("hide",restoreOriginalWidth,p_oObject);}
function setWidthToOffsetWidth(p_sType,p_aArgs){var nIE=YAHOO.env.ua.ie,oConfig,sOriginalWidth,sNewWidth;if(nIE==6||(nIE==7&&document.compatMode=="BackCompat")){oConfig=this.cfg;sOriginalWidth=oConfig.getProperty("width");if(!sOriginalWidth||sOriginalWidth=="auto"){sNewWidth=(this.element.offsetWidth+"px");oConfig.setProperty("width",sNewWidth);this.subscribe("hide",restoreOriginalWidth,[(sOriginalWidth||""),sNewWidth]);}}}
function onElementFocus(){this.blur();}
function addFocusEventHandlers(p_sType,p_aArgs){var me=this;function isFocusable(el){var sTagName=el.tagName.toUpperCase(),bFocusable=false;switch(sTagName){case"A":case"BUTTON":case"SELECT":case"TEXTAREA":if(!Dom.isAncestor(me.element,el)){Event.on(el,"focus",onElementFocus,el,true);bFocusable=true;}
break;case"INPUT":if(el.type!="hidden"&&!Dom.isAncestor(me.element,el)){Event.on(el,"focus",onElementFocus,el,true);bFocusable=true;}
break;}
return bFocusable;}
this.focusableElements=Dom.getElementsBy(isFocusable);}
function removeFocusEventHandlers(p_sType,p_aArgs){var aElements=this.focusableElements,nElements=aElements.length,el2,i;for(i=0;i<nElements;i++){el2=aElements[i];Event.removeListener(el2,"focus",onElementFocus);}}
YAHOO.extend(Panel,Overlay,{init:function(el,userConfig){Panel.superclass.init.call(this,el);this.beforeInitEvent.fire(Panel);Dom.addClass(this.element,Panel.CSS_PANEL);this.buildWrapper();if(userConfig){this.cfg.applyConfig(userConfig,true);}
this.subscribe("showMask",addFocusEventHandlers);this.subscribe("hideMask",removeFocusEventHandlers);this.initEvent.fire(Panel);},initEvents:function(){Panel.superclass.initEvents.call(this);var SIGNATURE=CustomEvent.LIST;this.showMaskEvent=this.createEvent(EVENT_TYPES.SHOW_MASK);this.showMaskEvent.signature=SIGNATURE;this.hideMaskEvent=this.createEvent(EVENT_TYPES.HIDE_MASK);this.hideMaskEvent.signature=SIGNATURE;this.dragEvent=this.createEvent(EVENT_TYPES.DRAG);this.dragEvent.signature=SIGNATURE;},initDefaultConfig:function(){Panel.superclass.initDefaultConfig.call(this);this.cfg.addProperty(DEFAULT_CONFIG.CLOSE.key,{handler:this.configClose,value:DEFAULT_CONFIG.CLOSE.value,validator:DEFAULT_CONFIG.CLOSE.validator,supercedes:DEFAULT_CONFIG.CLOSE.supercedes});this.cfg.addProperty(DEFAULT_CONFIG.DRAGGABLE.key,{handler:this.configDraggable,value:DEFAULT_CONFIG.DRAGGABLE.value,validator:DEFAULT_CONFIG.DRAGGABLE.validator,supercedes:DEFAULT_CONFIG.DRAGGABLE.supercedes});this.cfg.addProperty(DEFAULT_CONFIG.UNDERLAY.key,{handler:this.configUnderlay,value:DEFAULT_CONFIG.UNDERLAY.value,supercedes:DEFAULT_CONFIG.UNDERLAY.supercedes});this.cfg.addProperty(DEFAULT_CONFIG.MODAL.key,{handler:this.configModal,value:DEFAULT_CONFIG.MODAL.value,validator:DEFAULT_CONFIG.MODAL.validator,supercedes:DEFAULT_CONFIG.MODAL.supercedes});this.cfg.addProperty(DEFAULT_CONFIG.KEY_LISTENERS.key,{handler:this.configKeyListeners,suppressEvent:DEFAULT_CONFIG.KEY_LISTENERS.suppressEvent,supercedes:DEFAULT_CONFIG.KEY_LISTENERS.supercedes});},configClose:function(type,args,obj){var val=args[0],oClose=this.close;function doHide(e,obj){obj.hide();}
if(val){if(!oClose){if(!m_oCloseIconTemplate){m_oCloseIconTemplate=document.createElement("span");m_oCloseIconTemplate.innerHTML="&#160;";m_oCloseIconTemplate.className="container-close";}
oClose=m_oCloseIconTemplate.cloneNode(true);this.innerElement.appendChild(oClose);Event.on(oClose,"click",doHide,this);this.close=oClose;}else{oClose.style.display="block";}}else{if(oClose){oClose.style.display="none";}}},configDraggable:function(type,args,obj){var val=args[0];if(val){if(!DD){this.cfg.setProperty("draggable",false);return;}
if(this.header){Dom.setStyle(this.header,"cursor","move");this.registerDragDrop();}
this.subscribe("beforeRender",createHeader);this.subscribe("beforeShow",setWidthToOffsetWidth);}else{if(this.dd){this.dd.unreg();}
if(this.header){Dom.setStyle(this.header,"cursor","auto");}
this.unsubscribe("beforeRender",createHeader);this.unsubscribe("beforeShow",setWidthToOffsetWidth);}},configUnderlay:function(type,args,obj){var UA=YAHOO.env.ua,bMacGecko=(this.platform=="mac"&&UA.gecko),sUnderlay=args[0].toLowerCase(),oUnderlay=this.underlay,oElement=this.element;function createUnderlay(){var nIE;if(!oUnderlay){if(!m_oUnderlayTemplate){m_oUnderlayTemplate=document.createElement("div");m_oUnderlayTemplate.className="underlay";}
oUnderlay=m_oUnderlayTemplate.cloneNode(false);this.element.appendChild(oUnderlay);this.underlay=oUnderlay;nIE=UA.ie;if(nIE==6||(nIE==7&&document.compatMode=="BackCompat")){this.sizeUnderlay();this.cfg.subscribeToConfigEvent("width",this.sizeUnderlay);this.cfg.subscribeToConfigEvent("height",this.sizeUnderlay);this.changeContentEvent.subscribe(this.sizeUnderlay);YAHOO.widget.Module.textResizeEvent.subscribe(this.sizeUnderlay,this,true);}}}
function onBeforeShow(){createUnderlay.call(this);this._underlayDeferred=false;this.beforeShowEvent.unsubscribe(onBeforeShow);}
function destroyUnderlay(){if(this._underlayDeferred){this.beforeShowEvent.unsubscribe(onBeforeShow);this._underlayDeferred=false;}
if(oUnderlay){this.cfg.unsubscribeFromConfigEvent("width",this.sizeUnderlay);this.cfg.unsubscribeFromConfigEvent("height",this.sizeUnderlay);this.changeContentEvent.unsubscribe(this.sizeUnderlay);YAHOO.widget.Module.textResizeEvent.unsubscribe(this.sizeUnderlay,this,true);this.element.removeChild(oUnderlay);this.underlay=null;}}
switch(sUnderlay){case"shadow":Dom.removeClass(oElement,"matte");Dom.addClass(oElement,"shadow");break;case"matte":if(!bMacGecko){destroyUnderlay.call(this);}
Dom.removeClass(oElement,"shadow");Dom.addClass(oElement,"matte");break;default:if(!bMacGecko){destroyUnderlay.call(this);}
Dom.removeClass(oElement,"shadow");Dom.removeClass(oElement,"matte");break;}
if((sUnderlay=="shadow")||(bMacGecko&&!oUnderlay)){if(this.cfg.getProperty("visible")){createUnderlay.call(this);}
else{if(!this._underlayDeferred){this.beforeShowEvent.subscribe(onBeforeShow);this._underlayDeferred=true;}}}},configModal:function(type,args,obj){var modal=args[0];if(modal){if(!this._hasModalityEventListeners){this.subscribe("beforeShow",this.buildMask);this.subscribe("beforeShow",this.bringToTop);this.subscribe("beforeShow",this.showMask);this.subscribe("hide",this.hideMask);Overlay.windowResizeEvent.subscribe(this.sizeMask,this,true);this._hasModalityEventListeners=true;}}else{if(this._hasModalityEventListeners){if(this.cfg.getProperty("visible")){this.hideMask();this.removeMask();}
this.unsubscribe("beforeShow",this.buildMask);this.unsubscribe("beforeShow",this.bringToTop);this.unsubscribe("beforeShow",this.showMask);this.unsubscribe("hide",this.hideMask);Overlay.windowResizeEvent.unsubscribe(this.sizeMask,this);this._hasModalityEventListeners=false;}}},removeMask:function(){var oMask=this.mask,oParentNode;if(oMask){this.hideMask();oParentNode=oMask.parentNode;if(oParentNode){oParentNode.removeChild(oMask);}
this.mask=null;}},configKeyListeners:function(type,args,obj){var listeners=args[0],listener,nListeners,i;if(listeners){if(listeners instanceof Array){nListeners=listeners.length;for(i=0;i<nListeners;i++){listener=listeners[i];if(!Config.alreadySubscribed(this.showEvent,listener.enable,listener)){this.showEvent.subscribe(listener.enable,listener,true);}
if(!Config.alreadySubscribed(this.hideEvent,listener.disable,listener)){this.hideEvent.subscribe(listener.disable,listener,true);this.destroyEvent.subscribe(listener.disable,listener,true);}}}else{if(!Config.alreadySubscribed(this.showEvent,listeners.enable,listeners)){this.showEvent.subscribe(listeners.enable,listeners,true);}
if(!Config.alreadySubscribed(this.hideEvent,listeners.disable,listeners)){this.hideEvent.subscribe(listeners.disable,listeners,true);this.destroyEvent.subscribe(listeners.disable,listeners,true);}}}},configHeight:function(type,args,obj){var height=args[0],el=this.innerElement;Dom.setStyle(el,"height",height);this.cfg.refireEvent("iframe");},configWidth:function(type,args,obj){var width=args[0],el=this.innerElement;Dom.setStyle(el,"width",width);this.cfg.refireEvent("iframe");},configzIndex:function(type,args,obj){Panel.superclass.configzIndex.call(this,type,args,obj);var maskZ=0,currentZ=Dom.getStyle(this.element,"zIndex");if(this.mask){if(!currentZ||isNaN(currentZ)){currentZ=0;}
if(currentZ===0){this.cfg.setProperty("zIndex",1);}else{maskZ=currentZ-1;Dom.setStyle(this.mask,"zIndex",maskZ);}}},buildWrapper:function(){var elementParent=this.element.parentNode,originalElement=this.element,wrapper=document.createElement("div");wrapper.className=Panel.CSS_PANEL_CONTAINER;wrapper.id=originalElement.id+"_c";if(elementParent){elementParent.insertBefore(wrapper,originalElement);}
wrapper.appendChild(originalElement);this.element=wrapper;this.innerElement=originalElement;Dom.setStyle(this.innerElement,"visibility","inherit");},sizeUnderlay:function(){var oUnderlay=this.underlay,oElement;if(oUnderlay){oElement=this.element;oUnderlay.style.width=oElement.offsetWidth+"px";oUnderlay.style.height=oElement.offsetHeight+"px";}},registerDragDrop:function(){var me=this;if(this.header){if(!DD){return;}
this.dd=new DD(this.element.id,this.id);if(!this.header.id){this.header.id=this.id+"_h";}
this.dd.startDrag=function(){var offsetHeight,offsetWidth,viewPortWidth,viewPortHeight,scrollX,scrollY,topConstraint,leftConstraint,bottomConstraint,rightConstraint;if(YAHOO.env.ua.ie==6){Dom.addClass(me.element,"drag");}
if(me.cfg.getProperty("constraintoviewport")){offsetHeight=me.element.offsetHeight;offsetWidth=me.element.offsetWidth;viewPortWidth=Dom.getViewportWidth();viewPortHeight=Dom.getViewportHeight();scrollX=Dom.getDocumentScrollLeft();scrollY=Dom.getDocumentScrollTop();topConstraint=scrollY+10;leftConstraint=scrollX+10;bottomConstraint=scrollY+viewPortHeight-offsetHeight-10;rightConstraint=scrollX+viewPortWidth-offsetWidth-10;this.minX=leftConstraint;this.maxX=rightConstraint;this.constrainX=true;this.minY=topConstraint;this.maxY=bottomConstraint;this.constrainY=true;}else{this.constrainX=false;this.constrainY=false;}
me.dragEvent.fire("startDrag",arguments);};this.dd.onDrag=function(){me.syncPosition();me.cfg.refireEvent("iframe");if(this.platform=="mac"&&YAHOO.env.ua.gecko){this.showMacGeckoScrollbars();}
me.dragEvent.fire("onDrag",arguments);};this.dd.endDrag=function(){if(YAHOO.env.ua.ie==6){Dom.removeClass(me.element,"drag");}
me.dragEvent.fire("endDrag",arguments);me.moveEvent.fire(me.cfg.getProperty("xy"));};this.dd.setHandleElId(this.header.id);this.dd.addInvalidHandleType("INPUT");this.dd.addInvalidHandleType("SELECT");this.dd.addInvalidHandleType("TEXTAREA");}},buildMask:function(){var oMask=this.mask;if(!oMask){if(!m_oMaskTemplate){m_oMaskTemplate=document.createElement("div");m_oMaskTemplate.className="mask";m_oMaskTemplate.innerHTML="&#160;";}
oMask=m_oMaskTemplate.cloneNode(true);oMask.id=this.id+"_mask";document.body.insertBefore(oMask,document.body.firstChild);this.mask=oMask;}},hideMask:function(){if(this.cfg.getProperty("modal")&&this.mask){this.mask.style.display="none";this.hideMaskEvent.fire();Dom.removeClass(document.body,"masked");}},showMask:function(){if(this.cfg.getProperty("modal")&&this.mask){Dom.addClass(document.body,"masked");this.sizeMask();this.mask.style.display="block";this.showMaskEvent.fire();}},sizeMask:function(){if(this.mask){this.mask.style.height=Dom.getDocumentHeight()+"px";this.mask.style.width=Dom.getDocumentWidth()+"px";}},render:function(appendToNode){return Panel.superclass.render.call(this,appendToNode,this.innerElement);},destroy:function(){Overlay.windowResizeEvent.unsubscribe(this.sizeMask,this);this.removeMask();if(this.close){Event.purgeElement(this.close);}
Panel.superclass.destroy.call(this);},toString:function(){return"Panel "+this.id;}});}());(function(){YAHOO.widget.Dialog=function(el,userConfig){YAHOO.widget.Dialog.superclass.constructor.call(this,el,userConfig);};var Event=YAHOO.util.Event,CustomEvent=YAHOO.util.CustomEvent,Dom=YAHOO.util.Dom,KeyListener=YAHOO.util.KeyListener,Connect=YAHOO.util.Connect,Dialog=YAHOO.widget.Dialog,Lang=YAHOO.lang,EVENT_TYPES={"BEFORE_SUBMIT":"beforeSubmit","SUBMIT":"submit","MANUAL_SUBMIT":"manualSubmit","ASYNC_SUBMIT":"asyncSubmit","FORM_SUBMIT":"formSubmit","CANCEL":"cancel"},DEFAULT_CONFIG={"POST_METHOD":{key:"postmethod",value:"async"},"BUTTONS":{key:"buttons",value:"none"}};Dialog.CSS_DIALOG="yui-dialog";function removeButtonEventHandlers(){var aButtons=this._aButtons,nButtons,oButton,i;if(Lang.isArray(aButtons)){nButtons=aButtons.length;if(nButtons>0){i=nButtons-1;do{oButton=aButtons[i];if(oButton instanceof YAHOO.widget.Button){oButton.destroy();}
else if(oButton.tagName.toUpperCase()=="BUTTON"){Event.purgeElement(oButton);Event.purgeElement(oButton,false);}}
while(i--);}}}
YAHOO.extend(Dialog,YAHOO.widget.Panel,{form:null,initDefaultConfig:function(){Dialog.superclass.initDefaultConfig.call(this);this.callback={success:null,failure:null,argument:null};this.cfg.addProperty(DEFAULT_CONFIG.POST_METHOD.key,{handler:this.configPostMethod,value:DEFAULT_CONFIG.POST_METHOD.value,validator:function(val){if(val!="form"&&val!="async"&&val!="none"&&val!="manual"){return false;}else{return true;}}});this.cfg.addProperty(DEFAULT_CONFIG.BUTTONS.key,{handler:this.configButtons,value:DEFAULT_CONFIG.BUTTONS.value});},initEvents:function(){Dialog.superclass.initEvents.call(this);var SIGNATURE=CustomEvent.LIST;this.beforeSubmitEvent=this.createEvent(EVENT_TYPES.BEFORE_SUBMIT);this.beforeSubmitEvent.signature=SIGNATURE;this.submitEvent=this.createEvent(EVENT_TYPES.SUBMIT);this.submitEvent.signature=SIGNATURE;this.manualSubmitEvent=this.createEvent(EVENT_TYPES.MANUAL_SUBMIT);this.manualSubmitEvent.signature=SIGNATURE;this.asyncSubmitEvent=this.createEvent(EVENT_TYPES.ASYNC_SUBMIT);this.asyncSubmitEvent.signature=SIGNATURE;this.formSubmitEvent=this.createEvent(EVENT_TYPES.FORM_SUBMIT);this.formSubmitEvent.signature=SIGNATURE;this.cancelEvent=this.createEvent(EVENT_TYPES.CANCEL);this.cancelEvent.signature=SIGNATURE;},init:function(el,userConfig){Dialog.superclass.init.call(this,el);this.beforeInitEvent.fire(Dialog);Dom.addClass(this.element,Dialog.CSS_DIALOG);this.cfg.setProperty("visible",false);if(userConfig){this.cfg.applyConfig(userConfig,true);}
this.showEvent.subscribe(this.focusFirst,this,true);this.beforeHideEvent.subscribe(this.blurButtons,this,true);this.subscribe("changeBody",this.registerForm);this.initEvent.fire(Dialog);},doSubmit:function(){var oForm=this.form,bUseFileUpload=false,bUseSecureFileUpload=false,aElements,nElements,i,sMethod;switch(this.cfg.getProperty("postmethod")){case"async":aElements=oForm.elements;nElements=aElements.length;if(nElements>0){i=nElements-1;do{if(aElements[i].type=="file"){bUseFileUpload=true;break;}}
while(i--);}
if(bUseFileUpload&&YAHOO.env.ua.ie&&this.isSecure){bUseSecureFileUpload=true;}
sMethod=(oForm.getAttribute("method")||"POST").toUpperCase();Connect.setForm(oForm,bUseFileUpload,bUseSecureFileUpload);Connect.asyncRequest(sMethod,oForm.getAttribute("action"),this.callback);this.asyncSubmitEvent.fire();break;case"form":oForm.submit();this.formSubmitEvent.fire();break;case"none":case"manual":this.manualSubmitEvent.fire();break;}},registerForm:function(){var form=this.element.getElementsByTagName("form")[0],me=this,firstElement,lastElement;if(this.form){if(this.form==form&&Dom.isAncestor(this.element,this.form)){return;}
else{Event.purgeElement(this.form);this.form=null;}}
if(!form){form=document.createElement("form");form.name="frm_"+this.id;this.body.appendChild(form);}
if(form){this.form=form;Event.on(form,"submit",function(e){Event.stopEvent(e);this.submit();this.form.blur();});this.firstFormElement=function(){var f,el,nElements=form.elements.length;for(f=0;f<nElements;f++){el=form.elements[f];if(el.focus&&!el.disabled&&el.type!="hidden"){return el;}}
return null;}();this.lastFormElement=function(){var f,el,nElements=form.elements.length;for(f=nElements-1;f>=0;f--){el=form.elements[f];if(el.focus&&!el.disabled&&el.type!="hidden"){return el;}}
return null;}();if(this.cfg.getProperty("modal")){firstElement=this.firstFormElement||this.firstButton;if(firstElement){this.preventBackTab=new KeyListener(firstElement,{shift:true,keys:9},{fn:me.focusLast,scope:me,correctScope:true});this.showEvent.subscribe(this.preventBackTab.enable,this.preventBackTab,true);this.hideEvent.subscribe(this.preventBackTab.disable,this.preventBackTab,true);}
lastElement=this.lastButton||this.lastFormElement;if(lastElement){this.preventTabOut=new KeyListener(lastElement,{shift:false,keys:9},{fn:me.focusFirst,scope:me,correctScope:true});this.showEvent.subscribe(this.preventTabOut.enable,this.preventTabOut,true);this.hideEvent.subscribe(this.preventTabOut.disable,this.preventTabOut,true);}}}},configClose:function(type,args,obj){var val=args[0];function doCancel(e,obj){obj.cancel();}
if(val){if(!this.close){this.close=document.createElement("div");Dom.addClass(this.close,"container-close");this.close.innerHTML="&#160;";this.innerElement.appendChild(this.close);Event.on(this.close,"click",doCancel,this);}else{this.close.style.display="block";}}else{if(this.close){this.close.style.display="none";}}},configButtons:function(type,args,obj){var Button=YAHOO.widget.Button,aButtons=args[0],oInnerElement=this.innerElement,oButton,oButtonEl,oYUIButton,nButtons,oSpan,oFooter,i;removeButtonEventHandlers.call(this);this._aButtons=null;if(Lang.isArray(aButtons)){oSpan=document.createElement("span");oSpan.className="button-group";nButtons=aButtons.length;this._aButtons=[];for(i=0;i<nButtons;i++){oButton=aButtons[i];if(Button){oYUIButton=new Button({label:oButton.text,container:oSpan});oButtonEl=oYUIButton.get("element");if(oButton.isDefault){oYUIButton.addClass("default");this.defaultHtmlButton=oButtonEl;}
if(Lang.isFunction(oButton.handler)){oYUIButton.set("onclick",{fn:oButton.handler,obj:this,scope:this});}
else if(Lang.isObject(oButton.handler)&&Lang.isFunction(oButton.handler.fn)){oYUIButton.set("onclick",{fn:oButton.handler.fn,obj:((!Lang.isUndefined(oButton.handler.obj))?oButton.handler.obj:this),scope:(oButton.handler.scope||this)});}
this._aButtons[this._aButtons.length]=oYUIButton;}
else{oButtonEl=document.createElement("button");oButtonEl.setAttribute("type","button");if(oButton.isDefault){oButtonEl.className="default";this.defaultHtmlButton=oButtonEl;}
oButtonEl.innerHTML=oButton.text;if(Lang.isFunction(oButton.handler)){Event.on(oButtonEl,"click",oButton.handler,this,true);}
else if(Lang.isObject(oButton.handler)&&Lang.isFunction(oButton.handler.fn)){Event.on(oButtonEl,"click",oButton.handler.fn,((!Lang.isUndefined(oButton.handler.obj))?oButton.handler.obj:this),(oButton.handler.scope||this));}
oSpan.appendChild(oButtonEl);this._aButtons[this._aButtons.length]=oButtonEl;}
oButton.htmlButton=oButtonEl;if(i===0){this.firstButton=oButtonEl;}
if(i==(nButtons-1)){this.lastButton=oButtonEl;}}
this.setFooter(oSpan);oFooter=this.footer;if(Dom.inDocument(this.element)&&!Dom.isAncestor(oInnerElement,oFooter)){oInnerElement.appendChild(oFooter);}
this.buttonSpan=oSpan;}else{oSpan=this.buttonSpan;oFooter=this.footer;if(oSpan&&oFooter){oFooter.removeChild(oSpan);this.buttonSpan=null;this.firstButton=null;this.lastButton=null;this.defaultHtmlButton=null;}}
this.cfg.refireEvent("iframe");this.cfg.refireEvent("underlay");},getButtons:function(){var aButtons=this._aButtons;if(aButtons){return aButtons;}},focusFirst:function(type,args,obj){var oElement=this.firstFormElement,oEvent;if(args){oEvent=args[1];if(oEvent){Event.stopEvent(oEvent);}}
if(oElement){try{oElement.focus();}
catch(oException){}}else{this.focusDefaultButton();}},focusLast:function(type,args,obj){var aButtons=this.cfg.getProperty("buttons"),oElement=this.lastFormElement,oEvent;if(args){oEvent=args[1];if(oEvent){Event.stopEvent(oEvent);}}
if(aButtons&&Lang.isArray(aButtons)){this.focusLastButton();}else{if(oElement){try{oElement.focus();}
catch(oException){}}}},focusDefaultButton:function(){var oElement=this.defaultHtmlButton;if(oElement){try{oElement.focus();}
catch(oException){}}},blurButtons:function(){var aButtons=this.cfg.getProperty("buttons"),nButtons,oButton,oElement,i;if(aButtons&&Lang.isArray(aButtons)){nButtons=aButtons.length;if(nButtons>0){i=(nButtons-1);do{oButton=aButtons[i];if(oButton){oElement=oButton.htmlButton;if(oElement){try{oElement.blur();}
catch(oException){}}}}
while(i--);}}},focusFirstButton:function(){var aButtons=this.cfg.getProperty("buttons"),oButton,oElement;if(aButtons&&Lang.isArray(aButtons)){oButton=aButtons[0];if(oButton){oElement=oButton.htmlButton;if(oElement){try{oElement.focus();}
catch(oException){}}}}},focusLastButton:function(){var aButtons=this.cfg.getProperty("buttons"),nButtons,oButton,oElement;if(aButtons&&Lang.isArray(aButtons)){nButtons=aButtons.length;if(nButtons>0){oButton=aButtons[(nButtons-1)];if(oButton){oElement=oButton.htmlButton;if(oElement){try{oElement.focus();}
catch(oException){}}}}}},configPostMethod:function(type,args,obj){var postmethod=args[0];this.registerForm();},validate:function(){return true;},submit:function(){if(this.validate()){this.beforeSubmitEvent.fire();this.doSubmit();this.submitEvent.fire();this.hide();return true;}else{return false;}},cancel:function(){this.cancelEvent.fire();this.hide();},getData:function(){var oForm=this.form,aElements,nTotalElements,oData,sName,oElement,nElements,sType,sTagName,aOptions,nOptions,aValues,oOption,sValue,oRadio,oCheckbox,i,n;function isFormElement(p_oElement){var sTag=p_oElement.tagName.toUpperCase();return((sTag=="INPUT"||sTag=="TEXTAREA"||sTag=="SELECT")&&p_oElement.name==sName);}
if(oForm){aElements=oForm.elements;nTotalElements=aElements.length;oData={};for(i=0;i<nTotalElements;i++){sName=aElements[i].name;oElement=Dom.getElementsBy(isFormElement,"*",oForm);nElements=oElement.length;if(nElements>0){if(nElements==1){oElement=oElement[0];sType=oElement.type;sTagName=oElement.tagName.toUpperCase();switch(sTagName){case"INPUT":if(sType=="checkbox"){oData[sName]=oElement.checked;}
else if(sType!="radio"){oData[sName]=oElement.value;}
break;case"TEXTAREA":oData[sName]=oElement.value;break;case"SELECT":aOptions=oElement.options;nOptions=aOptions.length;aValues=[];for(n=0;n<nOptions;n++){oOption=aOptions[n];if(oOption.selected){sValue=oOption.value;if(!sValue||sValue===""){sValue=oOption.text;}
aValues[aValues.length]=sValue;}}
oData[sName]=aValues;break;}}
else{sType=oElement[0].type;switch(sType){case"radio":for(n=0;n<nElements;n++){oRadio=oElement[n];if(oRadio.checked){oData[sName]=oRadio.value;break;}}
break;case"checkbox":aValues=[];for(n=0;n<nElements;n++){oCheckbox=oElement[n];if(oCheckbox.checked){aValues[aValues.length]=oCheckbox.value;}}
oData[sName]=aValues;break;}}}}}
return oData;},destroy:function(){removeButtonEventHandlers.call(this);this._aButtons=null;var aForms=this.element.getElementsByTagName("form"),oForm;if(aForms.length>0){oForm=aForms[0];if(oForm){Event.purgeElement(oForm);this.body.removeChild(oForm);this.form=null;}}
Dialog.superclass.destroy.call(this);},toString:function(){return"Dialog "+this.id;}});}());(function(){YAHOO.widget.SimpleDialog=function(el,userConfig){YAHOO.widget.SimpleDialog.superclass.constructor.call(this,el,userConfig);};var Dom=YAHOO.util.Dom,SimpleDialog=YAHOO.widget.SimpleDialog,DEFAULT_CONFIG={"ICON":{key:"icon",value:"none",suppressEvent:true},"TEXT":{key:"text",value:"",suppressEvent:true,supercedes:["icon"]}};SimpleDialog.ICON_BLOCK="blckicon";SimpleDialog.ICON_ALARM="alrticon";SimpleDialog.ICON_HELP="hlpicon";SimpleDialog.ICON_INFO="infoicon";SimpleDialog.ICON_WARN="warnicon";SimpleDialog.ICON_TIP="tipicon";SimpleDialog.ICON_CSS_CLASSNAME="yui-icon";SimpleDialog.CSS_SIMPLEDIALOG="yui-simple-dialog";YAHOO.extend(SimpleDialog,YAHOO.widget.Dialog,{initDefaultConfig:function(){SimpleDialog.superclass.initDefaultConfig.call(this);this.cfg.addProperty(DEFAULT_CONFIG.ICON.key,{handler:this.configIcon,value:DEFAULT_CONFIG.ICON.value,suppressEvent:DEFAULT_CONFIG.ICON.suppressEvent});this.cfg.addProperty(DEFAULT_CONFIG.TEXT.key,{handler:this.configText,value:DEFAULT_CONFIG.TEXT.value,suppressEvent:DEFAULT_CONFIG.TEXT.suppressEvent,supercedes:DEFAULT_CONFIG.TEXT.supercedes});},init:function(el,userConfig){SimpleDialog.superclass.init.call(this,el);this.beforeInitEvent.fire(SimpleDialog);Dom.addClass(this.element,SimpleDialog.CSS_SIMPLEDIALOG);this.cfg.queueProperty("postmethod","manual");if(userConfig){this.cfg.applyConfig(userConfig,true);}
this.beforeRenderEvent.subscribe(function(){if(!this.body){this.setBody("");}},this,true);this.initEvent.fire(SimpleDialog);},registerForm:function(){SimpleDialog.superclass.registerForm.call(this);this.form.innerHTML+="<input type=\"hidden\" name=\""+
this.id+"\" value=\"\"/>";},configIcon:function(type,args,obj){var sIcon=args[0],oBody=this.body,sCSSClass=SimpleDialog.ICON_CSS_CLASSNAME,oIcon,oIconParent;if(sIcon&&sIcon!="none"){oIcon=Dom.getElementsByClassName(sCSSClass,"*",oBody);if(oIcon){oIconParent=oIcon.parentNode;if(oIconParent){oIconParent.removeChild(oIcon);oIcon=null;}}
if(sIcon.indexOf(".")==-1){oIcon=document.createElement("span");oIcon.className=(sCSSClass+" "+sIcon);oIcon.innerHTML="&#160;";}else{oIcon=document.createElement("img");oIcon.src=(this.imageRoot+sIcon);oIcon.className=sCSSClass;}
if(oIcon){oBody.insertBefore(oIcon,oBody.firstChild);}}},configText:function(type,args,obj){var text=args[0];if(text){this.setBody(text);this.cfg.refireEvent("icon");}},toString:function(){return"SimpleDialog "+this.id;}});}());(function(){YAHOO.widget.ContainerEffect=function(overlay,attrIn,attrOut,targetElement,animClass){if(!animClass){animClass=YAHOO.util.Anim;}
this.overlay=overlay;this.attrIn=attrIn;this.attrOut=attrOut;this.targetElement=targetElement||overlay.element;this.animClass=animClass;};var Dom=YAHOO.util.Dom,CustomEvent=YAHOO.util.CustomEvent,Easing=YAHOO.util.Easing,ContainerEffect=YAHOO.widget.ContainerEffect;ContainerEffect.FADE=function(overlay,dur){var fade=new ContainerEffect(overlay,{attributes:{opacity:{from:0,to:1}},duration:dur,method:Easing.easeIn},{attributes:{opacity:{to:0}},duration:dur,method:Easing.easeOut},overlay.element);fade.handleStartAnimateIn=function(type,args,obj){Dom.addClass(obj.overlay.element,"hide-select");if(!obj.overlay.underlay){obj.overlay.cfg.refireEvent("underlay");}
if(obj.overlay.underlay){obj.initialUnderlayOpacity=Dom.getStyle(obj.overlay.underlay,"opacity");obj.overlay.underlay.style.filter=null;}
Dom.setStyle(obj.overlay.element,"visibility","visible");Dom.setStyle(obj.overlay.element,"opacity",0);};fade.handleCompleteAnimateIn=function(type,args,obj){Dom.removeClass(obj.overlay.element,"hide-select");if(obj.overlay.element.style.filter){obj.overlay.element.style.filter=null;}
if(obj.overlay.underlay){Dom.setStyle(obj.overlay.underlay,"opacity",obj.initialUnderlayOpacity);}
obj.overlay.cfg.refireEvent("iframe");obj.animateInCompleteEvent.fire();};fade.handleStartAnimateOut=function(type,args,obj){Dom.addClass(obj.overlay.element,"hide-select");if(obj.overlay.underlay){obj.overlay.underlay.style.filter=null;}};fade.handleCompleteAnimateOut=function(type,args,obj){Dom.removeClass(obj.overlay.element,"hide-select");if(obj.overlay.element.style.filter){obj.overlay.element.style.filter=null;}
Dom.setStyle(obj.overlay.element,"visibility","hidden");Dom.setStyle(obj.overlay.element,"opacity",1);obj.overlay.cfg.refireEvent("iframe");obj.animateOutCompleteEvent.fire();};fade.init();return fade;};ContainerEffect.SLIDE=function(overlay,dur){var x=overlay.cfg.getProperty("x")||Dom.getX(overlay.element),y=overlay.cfg.getProperty("y")||Dom.getY(overlay.element),clientWidth=Dom.getClientWidth(),offsetWidth=overlay.element.offsetWidth,slide=new ContainerEffect(overlay,{attributes:{points:{to:[x,y]}},duration:dur,method:Easing.easeIn},{attributes:{points:{to:[(clientWidth+25),y]}},duration:dur,method:Easing.easeOut},overlay.element,YAHOO.util.Motion);slide.handleStartAnimateIn=function(type,args,obj){obj.overlay.element.style.left=((-25)-offsetWidth)+"px";obj.overlay.element.style.top=y+"px";};slide.handleTweenAnimateIn=function(type,args,obj){var pos=Dom.getXY(obj.overlay.element),currentX=pos[0],currentY=pos[1];if(Dom.getStyle(obj.overlay.element,"visibility")=="hidden"&&currentX<x){Dom.setStyle(obj.overlay.element,"visibility","visible");}
obj.overlay.cfg.setProperty("xy",[currentX,currentY],true);obj.overlay.cfg.refireEvent("iframe");};slide.handleCompleteAnimateIn=function(type,args,obj){obj.overlay.cfg.setProperty("xy",[x,y],true);obj.startX=x;obj.startY=y;obj.overlay.cfg.refireEvent("iframe");obj.animateInCompleteEvent.fire();};slide.handleStartAnimateOut=function(type,args,obj){var vw=Dom.getViewportWidth(),pos=Dom.getXY(obj.overlay.element),yso=pos[1],currentTo=obj.animOut.attributes.points.to;obj.animOut.attributes.points.to=[(vw+25),yso];};slide.handleTweenAnimateOut=function(type,args,obj){var pos=Dom.getXY(obj.overlay.element),xto=pos[0],yto=pos[1];obj.overlay.cfg.setProperty("xy",[xto,yto],true);obj.overlay.cfg.refireEvent("iframe");};slide.handleCompleteAnimateOut=function(type,args,obj){Dom.setStyle(obj.overlay.element,"visibility","hidden");obj.overlay.cfg.setProperty("xy",[x,y]);obj.animateOutCompleteEvent.fire();};slide.init();return slide;};ContainerEffect.prototype={init:function(){this.beforeAnimateInEvent=this.createEvent("beforeAnimateIn");this.beforeAnimateInEvent.signature=CustomEvent.LIST;this.beforeAnimateOutEvent=this.createEvent("beforeAnimateOut");this.beforeAnimateOutEvent.signature=CustomEvent.LIST;this.animateInCompleteEvent=this.createEvent("animateInComplete");this.animateInCompleteEvent.signature=CustomEvent.LIST;this.animateOutCompleteEvent=this.createEvent("animateOutComplete");this.animateOutCompleteEvent.signature=CustomEvent.LIST;this.animIn=new this.animClass(this.targetElement,this.attrIn.attributes,this.attrIn.duration,this.attrIn.method);this.animIn.onStart.subscribe(this.handleStartAnimateIn,this);this.animIn.onTween.subscribe(this.handleTweenAnimateIn,this);this.animIn.onComplete.subscribe(this.handleCompleteAnimateIn,this);this.animOut=new this.animClass(this.targetElement,this.attrOut.attributes,this.attrOut.duration,this.attrOut.method);this.animOut.onStart.subscribe(this.handleStartAnimateOut,this);this.animOut.onTween.subscribe(this.handleTweenAnimateOut,this);this.animOut.onComplete.subscribe(this.handleCompleteAnimateOut,this);},animateIn:function(){this.beforeAnimateInEvent.fire();this.animIn.animate();},animateOut:function(){this.beforeAnimateOutEvent.fire();this.animOut.animate();},handleStartAnimateIn:function(type,args,obj){},handleTweenAnimateIn:function(type,args,obj){},handleCompleteAnimateIn:function(type,args,obj){},handleStartAnimateOut:function(type,args,obj){},handleTweenAnimateOut:function(type,args,obj){},handleCompleteAnimateOut:function(type,args,obj){},toString:function(){var output="ContainerEffect";if(this.overlay){output+=" ["+this.overlay.toString()+"]";}
return output;}};YAHOO.lang.augmentProto(ContainerEffect,YAHOO.util.EventProvider);})();YAHOO.register("container",YAHOO.widget.Module,{version:"2.3.0",build:"442"});/*
Copyright (c) 2007, Yahoo! Inc. All rights reserved.
Code licensed under the BSD License:
http://developer.yahoo.net/yui/license.txt
version: 2.3.0
*/

YAHOO.widget.TreeView=function(id){if(id){this.init(id);}};YAHOO.widget.TreeView.prototype={id:null,_el:null,_nodes:null,locked:false,_expandAnim:null,_collapseAnim:null,_animCount:0,maxAnim:2,setExpandAnim:function(type){if(YAHOO.widget.TVAnim.isValid(type)){this._expandAnim=type;}},setCollapseAnim:function(type){if(YAHOO.widget.TVAnim.isValid(type)){this._collapseAnim=type;}},animateExpand:function(el,node){if(this._expandAnim&&this._animCount<this.maxAnim){var tree=this;var a=YAHOO.widget.TVAnim.getAnim(this._expandAnim,el,function(){tree.expandComplete(node);});if(a){++this._animCount;this.fireEvent("animStart",{"node":node,"type":"expand"});a.animate();}
return true;}
return false;},animateCollapse:function(el,node){if(this._collapseAnim&&this._animCount<this.maxAnim){var tree=this;var a=YAHOO.widget.TVAnim.getAnim(this._collapseAnim,el,function(){tree.collapseComplete(node);});if(a){++this._animCount;this.fireEvent("animStart",{"node":node,"type":"collapse"});a.animate();}
return true;}
return false;},expandComplete:function(node){--this._animCount;this.fireEvent("animComplete",{"node":node,"type":"expand"});},collapseComplete:function(node){--this._animCount;this.fireEvent("animComplete",{"node":node,"type":"collapse"});},init:function(id){this.id=id;if("string"!==typeof id){this._el=id;this.id=this.generateId(id);}
this.createEvent("animStart",this);this.createEvent("animComplete",this);this.createEvent("collapse",this);this.createEvent("collapseComplete",this);this.createEvent("expand",this);this.createEvent("expandComplete",this);this._nodes=[];YAHOO.widget.TreeView.trees[this.id]=this;this.root=new YAHOO.widget.RootNode(this);var LW=YAHOO.widget.LogWriter;},draw:function(){var html=this.root.getHtml();this.getEl().innerHTML=html;this.firstDraw=false;},getEl:function(){if(!this._el){this._el=document.getElementById(this.id);}
return this._el;},regNode:function(node){this._nodes[node.index]=node;},getRoot:function(){return this.root;},setDynamicLoad:function(fnDataLoader,iconMode){this.root.setDynamicLoad(fnDataLoader,iconMode);},expandAll:function(){if(!this.locked){this.root.expandAll();}},collapseAll:function(){if(!this.locked){this.root.collapseAll();}},getNodeByIndex:function(nodeIndex){var n=this._nodes[nodeIndex];return(n)?n:null;},getNodeByProperty:function(property,value){for(var i in this._nodes){var n=this._nodes[i];if(n.data&&value==n.data[property]){return n;}}
return null;},getNodesByProperty:function(property,value){var values=[];for(var i in this._nodes){var n=this._nodes[i];if(n.data&&value==n.data[property]){values.push(n);}}
return(values.length)?values:null;},removeNode:function(node,autoRefresh){if(node.isRoot()){return false;}
var p=node.parent;if(p.parent){p=p.parent;}
this._deleteNode(node);if(autoRefresh&&p&&p.childrenRendered){p.refresh();}
return true;},removeChildren:function(node){while(node.children.length){this._deleteNode(node.children[0]);}
node.childrenRendered=false;node.dynamicLoadComplete=false;if(node.expanded){node.collapse();}else{node.updateIcon();}},_deleteNode:function(node){this.removeChildren(node);this.popNode(node);},popNode:function(node){var p=node.parent;var a=[];for(var i=0,len=p.children.length;i<len;++i){if(p.children[i]!=node){a[a.length]=p.children[i];}}
p.children=a;p.childrenRendered=false;if(node.previousSibling){node.previousSibling.nextSibling=node.nextSibling;}
if(node.nextSibling){node.nextSibling.previousSibling=node.previousSibling;}
node.parent=null;node.previousSibling=null;node.nextSibling=null;node.tree=null;delete this._nodes[node.index];},toString:function(){return"TreeView "+this.id;},generateId:function(el){var id=el.id;if(!id){id="yui-tv-auto-id-"+YAHOO.widget.TreeView.counter;++YAHOO.widget.TreeView.counter;}
return id;},onExpand:function(node){},onCollapse:function(node){}};YAHOO.augment(YAHOO.widget.TreeView,YAHOO.util.EventProvider);YAHOO.widget.TreeView.nodeCount=0;YAHOO.widget.TreeView.trees=[];YAHOO.widget.TreeView.counter=0;YAHOO.widget.TreeView.getTree=function(treeId){var t=YAHOO.widget.TreeView.trees[treeId];return(t)?t:null;};YAHOO.widget.TreeView.getNode=function(treeId,nodeIndex){var t=YAHOO.widget.TreeView.getTree(treeId);return(t)?t.getNodeByIndex(nodeIndex):null;};YAHOO.widget.TreeView.addHandler=function(el,sType,fn){if(el.addEventListener){el.addEventListener(sType,fn,false);}else if(el.attachEvent){el.attachEvent("on"+sType,fn);}};YAHOO.widget.TreeView.removeHandler=function(el,sType,fn){if(el.removeEventListener){el.removeEventListener(sType,fn,false);}else if(el.detachEvent){el.detachEvent("on"+sType,fn);}};YAHOO.widget.TreeView.preload=function(e,prefix){prefix=prefix||"ygtv";var styles=["tn","tm","tmh","tp","tph","ln","lm","lmh","lp","lph","loading"];var sb=[];for(var i=1;i<styles.length;i=i+1){sb[sb.length]='<span class="'+prefix+styles[i]+'">&#160;</span>';}
var f=document.createElement("div");var s=f.style;s.className=prefix+styles[0];s.position="absolute";s.height="1px";s.width="1px";s.top="-1000px";s.left="-1000px";f.innerHTML=sb.join("");document.body.appendChild(f);YAHOO.widget.TreeView.removeHandler(window,"load",YAHOO.widget.TreeView.preload);};YAHOO.widget.TreeView.addHandler(window,"load",YAHOO.widget.TreeView.preload);YAHOO.widget.Node=function(oData,oParent,expanded){if(oData){this.init(oData,oParent,expanded);}};YAHOO.widget.Node.prototype={index:0,children:null,tree:null,data:null,parent:null,depth:-1,href:null,target:"_self",expanded:false,multiExpand:true,renderHidden:false,childrenRendered:false,dynamicLoadComplete:false,previousSibling:null,nextSibling:null,_dynLoad:false,dataLoader:null,isLoading:false,hasIcon:true,iconMode:0,nowrap:false,_type:"Node",init:function(oData,oParent,expanded){this.data=oData;this.children=[];this.index=YAHOO.widget.TreeView.nodeCount;++YAHOO.widget.TreeView.nodeCount;this.expanded=expanded;this.createEvent("parentChange",this);if(oParent){oParent.appendChild(this);}},applyParent:function(parentNode){if(!parentNode){return false;}
this.tree=parentNode.tree;this.parent=parentNode;this.depth=parentNode.depth+1;if(!this.href){this.href="javascript:"+this.getToggleLink();}
this.tree.regNode(this);parentNode.childrenRendered=false;for(var i=0,len=this.children.length;i<len;++i){this.children[i].applyParent(this);}
this.fireEvent("parentChange");return true;},appendChild:function(childNode){if(this.hasChildren()){var sib=this.children[this.children.length-1];sib.nextSibling=childNode;childNode.previousSibling=sib;}
this.children[this.children.length]=childNode;childNode.applyParent(this);if(this.childrenRendered&&this.expanded){this.getChildrenEl().style.display="";}
return childNode;},appendTo:function(parentNode){return parentNode.appendChild(this);},insertBefore:function(node){var p=node.parent;if(p){if(this.tree){this.tree.popNode(this);}
var refIndex=node.isChildOf(p);p.children.splice(refIndex,0,this);if(node.previousSibling){node.previousSibling.nextSibling=this;}
this.previousSibling=node.previousSibling;this.nextSibling=node;node.previousSibling=this;this.applyParent(p);}
return this;},insertAfter:function(node){var p=node.parent;if(p){if(this.tree){this.tree.popNode(this);}
var refIndex=node.isChildOf(p);if(!node.nextSibling){this.nextSibling=null;return this.appendTo(p);}
p.children.splice(refIndex+1,0,this);node.nextSibling.previousSibling=this;this.previousSibling=node;this.nextSibling=node.nextSibling;node.nextSibling=this;this.applyParent(p);}
return this;},isChildOf:function(parentNode){if(parentNode&&parentNode.children){for(var i=0,len=parentNode.children.length;i<len;++i){if(parentNode.children[i]===this){return i;}}}
return-1;},getSiblings:function(){return this.parent.children;},showChildren:function(){if(!this.tree.animateExpand(this.getChildrenEl(),this)){if(this.hasChildren()){this.getChildrenEl().style.display="";}}},hideChildren:function(){if(!this.tree.animateCollapse(this.getChildrenEl(),this)){this.getChildrenEl().style.display="none";}},getElId:function(){return"ygtv"+this.index;},getChildrenElId:function(){return"ygtvc"+this.index;},getToggleElId:function(){return"ygtvt"+this.index;},getEl:function(){return document.getElementById(this.getElId());},getChildrenEl:function(){return document.getElementById(this.getChildrenElId());},getToggleEl:function(){return document.getElementById(this.getToggleElId());},getToggleLink:function(){return"YAHOO.widget.TreeView.getNode(\'"+this.tree.id+"\',"+
this.index+").toggle()";},collapse:function(){if(!this.expanded){return;}
var ret=this.tree.onCollapse(this);if(false===ret){return;}
ret=this.tree.fireEvent("collapse",this);if(false===ret){return;}
if(!this.getEl()){this.expanded=false;}else{this.hideChildren();this.expanded=false;this.updateIcon();}
ret=this.tree.fireEvent("collapseComplete",this);},expand:function(){if(this.expanded){return;}
var ret=this.tree.onExpand(this);if(false===ret){return;}
ret=this.tree.fireEvent("expand",this);if(false===ret){return;}
if(!this.getEl()){this.expanded=true;return;}
if(!this.childrenRendered){this.getChildrenEl().innerHTML=this.renderChildren();}else{}
this.expanded=true;this.updateIcon();if(this.isLoading){this.expanded=false;return;}
if(!this.multiExpand){var sibs=this.getSiblings();for(var i=0;i<sibs.length;++i){if(sibs[i]!=this&&sibs[i].expanded){sibs[i].collapse();}}}
this.showChildren();ret=this.tree.fireEvent("expandComplete",this);},updateIcon:function(){if(this.hasIcon){var el=this.getToggleEl();if(el){el.className=this.getStyle();}}},getStyle:function(){if(this.isLoading){return"ygtvloading";}else{var loc=(this.nextSibling)?"t":"l";var type="n";if(this.hasChildren(true)||(this.isDynamic()&&!this.getIconMode())){type=(this.expanded)?"m":"p";}
return"ygtv"+loc+type;}},getHoverStyle:function(){var s=this.getStyle();if(this.hasChildren(true)&&!this.isLoading){s+="h";}
return s;},expandAll:function(){for(var i=0;i<this.children.length;++i){var c=this.children[i];if(c.isDynamic()){alert("Not supported (lazy load + expand all)");break;}else if(!c.multiExpand){alert("Not supported (no multi-expand + expand all)");break;}else{c.expand();c.expandAll();}}},collapseAll:function(){for(var i=0;i<this.children.length;++i){this.children[i].collapse();this.children[i].collapseAll();}},setDynamicLoad:function(fnDataLoader,iconMode){if(fnDataLoader){this.dataLoader=fnDataLoader;this._dynLoad=true;}else{this.dataLoader=null;this._dynLoad=false;}
if(iconMode){this.iconMode=iconMode;}},isRoot:function(){return(this==this.tree.root);},isDynamic:function(){var lazy=(!this.isRoot()&&(this._dynLoad||this.tree.root._dynLoad));return lazy;},getIconMode:function(){return(this.iconMode||this.tree.root.iconMode);},hasChildren:function(checkForLazyLoad){return(this.children.length>0||(checkForLazyLoad&&this.isDynamic()&&!this.dynamicLoadComplete));},toggle:function(){if(!this.tree.locked&&(this.hasChildren(true)||this.isDynamic())){if(this.expanded){this.collapse();}else{this.expand();}}},getHtml:function(){this.childrenRendered=false;var sb=[];sb[sb.length]='<div class="ygtvitem" id="'+this.getElId()+'">';sb[sb.length]=this.getNodeHtml();sb[sb.length]=this.getChildrenHtml();sb[sb.length]='</div>';return sb.join("");},getChildrenHtml:function(){var sb=[];sb[sb.length]='<div class="ygtvchildren"';sb[sb.length]=' id="'+this.getChildrenElId()+'"';if(!this.expanded||!this.hasChildren()){sb[sb.length]=' style="display:none;"';}
sb[sb.length]='>';if((this.hasChildren(true)&&this.expanded)||(this.renderHidden&&!this.isDynamic())){sb[sb.length]=this.renderChildren();}
sb[sb.length]='</div>';return sb.join("");},renderChildren:function(){var node=this;if(this.isDynamic()&&!this.dynamicLoadComplete){this.isLoading=true;this.tree.locked=true;if(this.dataLoader){setTimeout(function(){node.dataLoader(node,function(){node.loadComplete();});},10);}else if(this.tree.root.dataLoader){setTimeout(function(){node.tree.root.dataLoader(node,function(){node.loadComplete();});},10);}else{return"Error: data loader not found or not specified.";}
return"";}else{return this.completeRender();}},completeRender:function(){var sb=[];for(var i=0;i<this.children.length;++i){sb[sb.length]=this.children[i].getHtml();}
this.childrenRendered=true;return sb.join("");},loadComplete:function(){this.getChildrenEl().innerHTML=this.completeRender();this.dynamicLoadComplete=true;this.isLoading=false;this.expand();this.tree.locked=false;},getAncestor:function(depth){if(depth>=this.depth||depth<0){return null;}
var p=this.parent;while(p.depth>depth){p=p.parent;}
return p;},getDepthStyle:function(depth){return(this.getAncestor(depth).nextSibling)?"ygtvdepthcell":"ygtvblankdepthcell";},getNodeHtml:function(){return"";},refresh:function(){this.getChildrenEl().innerHTML=this.completeRender();if(this.hasIcon){var el=this.getToggleEl();if(el){el.className=this.getStyle();}}},toString:function(){return"Node ("+this.index+")";}};YAHOO.augment(YAHOO.widget.Node,YAHOO.util.EventProvider);YAHOO.widget.TextNode=function(oData,oParent,expanded){if(oData){this.init(oData,oParent,expanded);this.setUpLabel(oData);}};YAHOO.extend(YAHOO.widget.TextNode,YAHOO.widget.Node,{labelStyle:"ygtvlabel",labelElId:null,label:null,textNodeParentChange:function(){if(this.tree&&!this.tree.hasEvent("labelClick")){this.tree.createEvent("labelClick",this.tree);}},setUpLabel:function(oData){this.textNodeParentChange();this.subscribe("parentChange",this.textNodeParentChange);if(typeof oData=="string"){oData={label:oData};}
this.label=oData.label;this.data.label=oData.label;if(oData.href){this.href=oData.href;}
if(oData.target){this.target=oData.target;}
if(oData.style){this.labelStyle=oData.style;}
this.labelElId="ygtvlabelel"+this.index;},getLabelEl:function(){return document.getElementById(this.labelElId);},getNodeHtml:function(){var sb=[];sb[sb.length]='<table border="0" cellpadding="0" cellspacing="0">';sb[sb.length]='<tr>';for(var i=0;i<this.depth;++i){sb[sb.length]='<td class="'+this.getDepthStyle(i)+'"><div class="ygtvspacer"></div></td>';}
var getNode='YAHOO.widget.TreeView.getNode(\''+
this.tree.id+'\','+this.index+')';sb[sb.length]='<td';sb[sb.length]=' id="'+this.getToggleElId()+'"';sb[sb.length]=' class="'+this.getStyle()+'"';if(this.hasChildren(true)){sb[sb.length]=' onmouseover="this.className=';sb[sb.length]=getNode+'.getHoverStyle()"';sb[sb.length]=' onmouseout="this.className=';sb[sb.length]=getNode+'.getStyle()"';}
sb[sb.length]=' onclick="javascript:'+this.getToggleLink()+'">';sb[sb.length]='<div class="ygtvspacer">';sb[sb.length]='</div>';sb[sb.length]='</td>';sb[sb.length]='<td ';sb[sb.length]=(this.nowrap)?' nowrap="nowrap" ':'';sb[sb.length]=' >';sb[sb.length]='<a';sb[sb.length]=' id="'+this.labelElId+'"';sb[sb.length]=' class="'+this.labelStyle+'"';sb[sb.length]=' href="'+this.href+'"';sb[sb.length]=' target="'+this.target+'"';sb[sb.length]=' onclick="return '+getNode+'.onLabelClick('+getNode+')"';if(this.hasChildren(true)){sb[sb.length]=' onmouseover="document.getElementById(\'';sb[sb.length]=this.getToggleElId()+'\').className=';sb[sb.length]=getNode+'.getHoverStyle()"';sb[sb.length]=' onmouseout="document.getElementById(\'';sb[sb.length]=this.getToggleElId()+'\').className=';sb[sb.length]=getNode+'.getStyle()"';}
sb[sb.length]=' >';sb[sb.length]=this.label;sb[sb.length]='</a>';sb[sb.length]='</td>';sb[sb.length]='</tr>';sb[sb.length]='</table>';return sb.join("");},onLabelClick:function(me){return me.tree.fireEvent("labelClick",me);},toString:function(){return"TextNode ("+this.index+") "+this.label;}});YAHOO.widget.RootNode=function(oTree){this.init(null,null,true);this.tree=oTree;};YAHOO.extend(YAHOO.widget.RootNode,YAHOO.widget.Node,{getNodeHtml:function(){return"";},toString:function(){return"RootNode";},loadComplete:function(){this.tree.draw();},collapse:function(){},expand:function(){}});YAHOO.widget.HTMLNode=function(oData,oParent,expanded,hasIcon){if(oData){this.init(oData,oParent,expanded);this.initContent(oData,hasIcon);}};YAHOO.extend(YAHOO.widget.HTMLNode,YAHOO.widget.Node,{contentStyle:"ygtvhtml",contentElId:null,content:null,initContent:function(oData,hasIcon){if(typeof oData=="string"){oData={html:oData};}
this.html=oData.html;this.contentElId="ygtvcontentel"+this.index;this.hasIcon=hasIcon;},getContentEl:function(){return document.getElementById(this.contentElId);},getNodeHtml:function(){var sb=[];sb[sb.length]='<table border="0" cellpadding="0" cellspacing="0">';sb[sb.length]='<tr>';for(var i=0;i<this.depth;++i){sb[sb.length]='<td class="'+this.getDepthStyle(i)+'"><div class="ygtvspacer"></div></td>';}
if(this.hasIcon){sb[sb.length]='<td';sb[sb.length]=' id="'+this.getToggleElId()+'"';sb[sb.length]=' class="'+this.getStyle()+'"';sb[sb.length]=' onclick="javascript:'+this.getToggleLink()+'"';if(this.hasChildren(true)){sb[sb.length]=' onmouseover="this.className=';sb[sb.length]='YAHOO.widget.TreeView.getNode(\'';sb[sb.length]=this.tree.id+'\','+this.index+').getHoverStyle()"';sb[sb.length]=' onmouseout="this.className=';sb[sb.length]='YAHOO.widget.TreeView.getNode(\'';sb[sb.length]=this.tree.id+'\','+this.index+').getStyle()"';}
sb[sb.length]='><div class="ygtvspacer"></div></td>';}
sb[sb.length]='<td';sb[sb.length]=' id="'+this.contentElId+'"';sb[sb.length]=' class="'+this.contentStyle+'"';sb[sb.length]=(this.nowrap)?' nowrap="nowrap" ':'';sb[sb.length]=' >';sb[sb.length]=this.html;sb[sb.length]='</td>';sb[sb.length]='</tr>';sb[sb.length]='</table>';return sb.join("");},toString:function(){return"HTMLNode ("+this.index+")";}});YAHOO.widget.MenuNode=function(oData,oParent,expanded){if(oData){this.init(oData,oParent,expanded);this.setUpLabel(oData);}
this.multiExpand=false;};YAHOO.extend(YAHOO.widget.MenuNode,YAHOO.widget.TextNode,{toString:function(){return"MenuNode ("+this.index+") "+this.label;}});YAHOO.widget.TVAnim=function(){return{FADE_IN:"TVFadeIn",FADE_OUT:"TVFadeOut",getAnim:function(type,el,callback){if(YAHOO.widget[type]){return new YAHOO.widget[type](el,callback);}else{return null;}},isValid:function(type){return(YAHOO.widget[type]);}};}();YAHOO.widget.TVFadeIn=function(el,callback){this.el=el;this.callback=callback;};YAHOO.widget.TVFadeIn.prototype={animate:function(){var tvanim=this;var s=this.el.style;s.opacity=0.1;s.filter="alpha(opacity=10)";s.display="";var dur=0.4;var a=new YAHOO.util.Anim(this.el,{opacity:{from:0.1,to:1,unit:""}},dur);a.onComplete.subscribe(function(){tvanim.onComplete();});a.animate();},onComplete:function(){this.callback();},toString:function(){return"TVFadeIn";}};YAHOO.widget.TVFadeOut=function(el,callback){this.el=el;this.callback=callback;};YAHOO.widget.TVFadeOut.prototype={animate:function(){var tvanim=this;var dur=0.4;var a=new YAHOO.util.Anim(this.el,{opacity:{from:1,to:0.1,unit:""}},dur);a.onComplete.subscribe(function(){tvanim.onComplete();});a.animate();},onComplete:function(){var s=this.el.style;s.display="none";s.filter="alpha(opacity=100)";this.callback();},toString:function(){return"TVFadeOut";}};YAHOO.register("treeview",YAHOO.widget.TreeView,{version:"2.3.0",build:"442"});/*
Copyright (c) 2007, Yahoo! Inc. All rights reserved.
Code licensed under the BSD License:
http://developer.yahoo.net/yui/license.txt
version: 2.3.0
*/

YAHOO.widget.AutoComplete=function(elInput,elContainer,oDataSource,oConfigs){if(elInput&&elContainer&&oDataSource){if(oDataSource instanceof YAHOO.widget.DataSource){this.dataSource=oDataSource;}
else{return;}
if(YAHOO.util.Dom.inDocument(elInput)){if(YAHOO.lang.isString(elInput)){this._sName="instance"+YAHOO.widget.AutoComplete._nIndex+" "+elInput;this._oTextbox=document.getElementById(elInput);}
else{this._sName=(elInput.id)?"instance"+YAHOO.widget.AutoComplete._nIndex+" "+elInput.id:"instance"+YAHOO.widget.AutoComplete._nIndex;this._oTextbox=elInput;}
YAHOO.util.Dom.addClass(this._oTextbox,"yui-ac-input");}
else{return;}
if(YAHOO.util.Dom.inDocument(elContainer)){if(YAHOO.lang.isString(elContainer)){this._oContainer=document.getElementById(elContainer);}
else{this._oContainer=elContainer;}
if(this._oContainer.style.display=="none"){}
var elParent=this._oContainer.parentNode;var elTag=elParent.tagName.toLowerCase();while(elParent&&(elParent!="document")){if(elTag=="div"){YAHOO.util.Dom.addClass(elParent,"yui-ac");break;}
else{elParent=elParent.parentNode;elTag=elParent.tagName.toLowerCase();}}
if(elTag!="div"){}}
else{return;}
if(oConfigs&&(oConfigs.constructor==Object)){for(var sConfig in oConfigs){if(sConfig){this[sConfig]=oConfigs[sConfig];}}}
this._initContainer();this._initProps();this._initList();this._initContainerHelpers();var oSelf=this;var oTextbox=this._oTextbox;var oContent=this._oContainer._oContent;YAHOO.util.Event.addListener(oTextbox,"keyup",oSelf._onTextboxKeyUp,oSelf);YAHOO.util.Event.addListener(oTextbox,"keydown",oSelf._onTextboxKeyDown,oSelf);YAHOO.util.Event.addListener(oTextbox,"focus",oSelf._onTextboxFocus,oSelf);YAHOO.util.Event.addListener(oTextbox,"blur",oSelf._onTextboxBlur,oSelf);YAHOO.util.Event.addListener(oContent,"mouseover",oSelf._onContainerMouseover,oSelf);YAHOO.util.Event.addListener(oContent,"mouseout",oSelf._onContainerMouseout,oSelf);YAHOO.util.Event.addListener(oContent,"scroll",oSelf._onContainerScroll,oSelf);YAHOO.util.Event.addListener(oContent,"resize",oSelf._onContainerResize,oSelf);if(oTextbox.form){YAHOO.util.Event.addListener(oTextbox.form,"submit",oSelf._onFormSubmit,oSelf);}
YAHOO.util.Event.addListener(oTextbox,"keypress",oSelf._onTextboxKeyPress,oSelf);this.textboxFocusEvent=new YAHOO.util.CustomEvent("textboxFocus",this);this.textboxKeyEvent=new YAHOO.util.CustomEvent("textboxKey",this);this.dataRequestEvent=new YAHOO.util.CustomEvent("dataRequest",this);this.dataReturnEvent=new YAHOO.util.CustomEvent("dataReturn",this);this.dataErrorEvent=new YAHOO.util.CustomEvent("dataError",this);this.containerExpandEvent=new YAHOO.util.CustomEvent("containerExpand",this);this.typeAheadEvent=new YAHOO.util.CustomEvent("typeAhead",this);this.itemMouseOverEvent=new YAHOO.util.CustomEvent("itemMouseOver",this);this.itemMouseOutEvent=new YAHOO.util.CustomEvent("itemMouseOut",this);this.itemArrowToEvent=new YAHOO.util.CustomEvent("itemArrowTo",this);this.itemArrowFromEvent=new YAHOO.util.CustomEvent("itemArrowFrom",this);this.itemSelectEvent=new YAHOO.util.CustomEvent("itemSelect",this);this.unmatchedItemSelectEvent=new YAHOO.util.CustomEvent("unmatchedItemSelect",this);this.selectionEnforceEvent=new YAHOO.util.CustomEvent("selectionEnforce",this);this.containerCollapseEvent=new YAHOO.util.CustomEvent("containerCollapse",this);this.textboxBlurEvent=new YAHOO.util.CustomEvent("textboxBlur",this);oTextbox.setAttribute("autocomplete","off");YAHOO.widget.AutoComplete._nIndex++;}
else{}};YAHOO.widget.AutoComplete.prototype.dataSource=null;YAHOO.widget.AutoComplete.prototype.minQueryLength=1;YAHOO.widget.AutoComplete.prototype.maxResultsDisplayed=10;YAHOO.widget.AutoComplete.prototype.queryDelay=0.2;YAHOO.widget.AutoComplete.prototype.highlightClassName="yui-ac-highlight";YAHOO.widget.AutoComplete.prototype.prehighlightClassName=null;YAHOO.widget.AutoComplete.prototype.delimChar=null;YAHOO.widget.AutoComplete.prototype.autoHighlight=true;YAHOO.widget.AutoComplete.prototype.typeAhead=false;YAHOO.widget.AutoComplete.prototype.animHoriz=false;YAHOO.widget.AutoComplete.prototype.animVert=true;YAHOO.widget.AutoComplete.prototype.animSpeed=0.3;YAHOO.widget.AutoComplete.prototype.forceSelection=false;YAHOO.widget.AutoComplete.prototype.allowBrowserAutocomplete=true;YAHOO.widget.AutoComplete.prototype.alwaysShowContainer=false;YAHOO.widget.AutoComplete.prototype.useIFrame=false;YAHOO.widget.AutoComplete.prototype.useShadow=false;YAHOO.widget.AutoComplete.prototype.toString=function(){return"AutoComplete "+this._sName;};YAHOO.widget.AutoComplete.prototype.isContainerOpen=function(){return this._bContainerOpen;};YAHOO.widget.AutoComplete.prototype.getListItems=function(){return this._aListItems;};YAHOO.widget.AutoComplete.prototype.getListItemData=function(oListItem){if(oListItem._oResultData){return oListItem._oResultData;}
else{return false;}};YAHOO.widget.AutoComplete.prototype.setHeader=function(sHeader){if(sHeader){if(this._oContainer._oContent._oHeader){this._oContainer._oContent._oHeader.innerHTML=sHeader;this._oContainer._oContent._oHeader.style.display="block";}}
else{this._oContainer._oContent._oHeader.innerHTML="";this._oContainer._oContent._oHeader.style.display="none";}};YAHOO.widget.AutoComplete.prototype.setFooter=function(sFooter){if(sFooter){if(this._oContainer._oContent._oFooter){this._oContainer._oContent._oFooter.innerHTML=sFooter;this._oContainer._oContent._oFooter.style.display="block";}}
else{this._oContainer._oContent._oFooter.innerHTML="";this._oContainer._oContent._oFooter.style.display="none";}};YAHOO.widget.AutoComplete.prototype.setBody=function(sBody){if(sBody){if(this._oContainer._oContent._oBody){this._oContainer._oContent._oBody.innerHTML=sBody;this._oContainer._oContent._oBody.style.display="block";this._oContainer._oContent.style.display="block";}}
else{this._oContainer._oContent._oBody.innerHTML="";this._oContainer._oContent.style.display="none";}
this._maxResultsDisplayed=0;};YAHOO.widget.AutoComplete.prototype.formatResult=function(oResultItem,sQuery){var sResult=oResultItem[0];if(sResult){return sResult;}
else{return"";}};YAHOO.widget.AutoComplete.prototype.doBeforeExpandContainer=function(oTextbox,oContainer,sQuery,aResults){return true;};YAHOO.widget.AutoComplete.prototype.sendQuery=function(sQuery){this._sendQuery(sQuery);};YAHOO.widget.AutoComplete.prototype.doBeforeSendQuery=function(sQuery){return sQuery;};YAHOO.widget.AutoComplete.prototype.destroy=function(){var instanceName=this.toString();var elInput=this._oTextbox;var elContainer=this._oContainer;this.textboxFocusEvent.unsubscribe();this.textboxKeyEvent.unsubscribe();this.dataRequestEvent.unsubscribe();this.dataReturnEvent.unsubscribe();this.dataErrorEvent.unsubscribe();this.containerExpandEvent.unsubscribe();this.typeAheadEvent.unsubscribe();this.itemMouseOverEvent.unsubscribe();this.itemMouseOutEvent.unsubscribe();this.itemArrowToEvent.unsubscribe();this.itemArrowFromEvent.unsubscribe();this.itemSelectEvent.unsubscribe();this.unmatchedItemSelectEvent.unsubscribe();this.selectionEnforceEvent.unsubscribe();this.containerCollapseEvent.unsubscribe();this.textboxBlurEvent.unsubscribe();YAHOO.util.Event.purgeElement(elInput,true);YAHOO.util.Event.purgeElement(elContainer,true);elContainer.innerHTML="";for(var key in this){if(this.hasOwnProperty(key)){this[key]=null;}}};YAHOO.widget.AutoComplete.prototype.textboxFocusEvent=null;YAHOO.widget.AutoComplete.prototype.textboxKeyEvent=null;YAHOO.widget.AutoComplete.prototype.dataRequestEvent=null;YAHOO.widget.AutoComplete.prototype.dataReturnEvent=null;YAHOO.widget.AutoComplete.prototype.dataErrorEvent=null;YAHOO.widget.AutoComplete.prototype.containerExpandEvent=null;YAHOO.widget.AutoComplete.prototype.typeAheadEvent=null;YAHOO.widget.AutoComplete.prototype.itemMouseOverEvent=null;YAHOO.widget.AutoComplete.prototype.itemMouseOutEvent=null;YAHOO.widget.AutoComplete.prototype.itemArrowToEvent=null;YAHOO.widget.AutoComplete.prototype.itemArrowFromEvent=null;YAHOO.widget.AutoComplete.prototype.itemSelectEvent=null;YAHOO.widget.AutoComplete.prototype.unmatchedItemSelectEvent=null;YAHOO.widget.AutoComplete.prototype.selectionEnforceEvent=null;YAHOO.widget.AutoComplete.prototype.containerCollapseEvent=null;YAHOO.widget.AutoComplete.prototype.textboxBlurEvent=null;YAHOO.widget.AutoComplete._nIndex=0;YAHOO.widget.AutoComplete.prototype._sName=null;YAHOO.widget.AutoComplete.prototype._oTextbox=null;YAHOO.widget.AutoComplete.prototype._bFocused=true;YAHOO.widget.AutoComplete.prototype._oAnim=null;YAHOO.widget.AutoComplete.prototype._oContainer=null;YAHOO.widget.AutoComplete.prototype._bContainerOpen=false;YAHOO.widget.AutoComplete.prototype._bOverContainer=false;YAHOO.widget.AutoComplete.prototype._aListItems=null;YAHOO.widget.AutoComplete.prototype._nDisplayedItems=0;YAHOO.widget.AutoComplete.prototype._maxResultsDisplayed=0;YAHOO.widget.AutoComplete.prototype._sCurQuery=null;YAHOO.widget.AutoComplete.prototype._sSavedQuery=null;YAHOO.widget.AutoComplete.prototype._oCurItem=null;YAHOO.widget.AutoComplete.prototype._bItemSelected=false;YAHOO.widget.AutoComplete.prototype._nKeyCode=null;YAHOO.widget.AutoComplete.prototype._nDelayID=-1;YAHOO.widget.AutoComplete.prototype._iFrameSrc="javascript:false;";YAHOO.widget.AutoComplete.prototype._queryInterval=null;YAHOO.widget.AutoComplete.prototype._sLastTextboxValue=null;YAHOO.widget.AutoComplete.prototype._initProps=function(){var minQueryLength=this.minQueryLength;if(!YAHOO.lang.isNumber(minQueryLength)){this.minQueryLength=1;}
var maxResultsDisplayed=this.maxResultsDisplayed;if(!YAHOO.lang.isNumber(maxResultsDisplayed)||(maxResultsDisplayed<1)){this.maxResultsDisplayed=10;}
var queryDelay=this.queryDelay;if(!YAHOO.lang.isNumber(queryDelay)||(queryDelay<0)){this.queryDelay=0.2;}
var delimChar=this.delimChar;if(YAHOO.lang.isString(delimChar)){this.delimChar=[delimChar];}
else if(!YAHOO.lang.isArray(delimChar)){this.delimChar=null;}
var animSpeed=this.animSpeed;if((this.animHoriz||this.animVert)&&YAHOO.util.Anim){if(!YAHOO.lang.isNumber(animSpeed)||(animSpeed<0)){this.animSpeed=0.3;}
if(!this._oAnim){this._oAnim=new YAHOO.util.Anim(this._oContainer._oContent,{},this.animSpeed);}
else{this._oAnim.duration=this.animSpeed;}}
if(this.forceSelection&&delimChar){}};YAHOO.widget.AutoComplete.prototype._initContainerHelpers=function(){if(this.useShadow&&!this._oContainer._oShadow){var oShadow=document.createElement("div");oShadow.className="yui-ac-shadow";this._oContainer._oShadow=this._oContainer.appendChild(oShadow);}
if(this.useIFrame&&!this._oContainer._oIFrame){var oIFrame=document.createElement("iframe");oIFrame.src=this._iFrameSrc;oIFrame.frameBorder=0;oIFrame.scrolling="no";oIFrame.style.position="absolute";oIFrame.style.width="100%";oIFrame.style.height="100%";oIFrame.tabIndex=-1;this._oContainer._oIFrame=this._oContainer.appendChild(oIFrame);}};YAHOO.widget.AutoComplete.prototype._initContainer=function(){YAHOO.util.Dom.addClass(this._oContainer,"yui-ac-container");if(!this._oContainer._oContent){var oContent=document.createElement("div");oContent.className="yui-ac-content";oContent.style.display="none";this._oContainer._oContent=this._oContainer.appendChild(oContent);var oHeader=document.createElement("div");oHeader.className="yui-ac-hd";oHeader.style.display="none";this._oContainer._oContent._oHeader=this._oContainer._oContent.appendChild(oHeader);var oBody=document.createElement("div");oBody.className="yui-ac-bd";this._oContainer._oContent._oBody=this._oContainer._oContent.appendChild(oBody);var oFooter=document.createElement("div");oFooter.className="yui-ac-ft";oFooter.style.display="none";this._oContainer._oContent._oFooter=this._oContainer._oContent.appendChild(oFooter);}
else{}};YAHOO.widget.AutoComplete.prototype._initList=function(){this._aListItems=[];while(this._oContainer._oContent._oBody.hasChildNodes()){var oldListItems=this.getListItems();if(oldListItems){for(var oldi=oldListItems.length-1;oldi>=0;oldi--){oldListItems[oldi]=null;}}
this._oContainer._oContent._oBody.innerHTML="";}
var oList=document.createElement("ul");oList=this._oContainer._oContent._oBody.appendChild(oList);for(var i=0;i<this.maxResultsDisplayed;i++){var oItem=document.createElement("li");oItem=oList.appendChild(oItem);this._aListItems[i]=oItem;this._initListItem(oItem,i);}
this._maxResultsDisplayed=this.maxResultsDisplayed;};YAHOO.widget.AutoComplete.prototype._initListItem=function(oItem,nItemIndex){var oSelf=this;oItem.style.display="none";oItem._nItemIndex=nItemIndex;oItem.mouseover=oItem.mouseout=oItem.onclick=null;YAHOO.util.Event.addListener(oItem,"mouseover",oSelf._onItemMouseover,oSelf);YAHOO.util.Event.addListener(oItem,"mouseout",oSelf._onItemMouseout,oSelf);YAHOO.util.Event.addListener(oItem,"click",oSelf._onItemMouseclick,oSelf);};YAHOO.widget.AutoComplete.prototype._onIMEDetected=function(oSelf){oSelf._enableIntervalDetection();};YAHOO.widget.AutoComplete.prototype._enableIntervalDetection=function(){var currValue=this._oTextbox.value;var lastValue=this._sLastTextboxValue;if(currValue!=lastValue){this._sLastTextboxValue=currValue;this._sendQuery(currValue);}};YAHOO.widget.AutoComplete.prototype._cancelIntervalDetection=function(oSelf){if(oSelf._queryInterval){clearInterval(oSelf._queryInterval);}};YAHOO.widget.AutoComplete.prototype._isIgnoreKey=function(nKeyCode){if((nKeyCode==9)||(nKeyCode==13)||(nKeyCode==16)||(nKeyCode==17)||(nKeyCode>=18&&nKeyCode<=20)||(nKeyCode==27)||(nKeyCode>=33&&nKeyCode<=35)||(nKeyCode>=36&&nKeyCode<=40)||(nKeyCode>=44&&nKeyCode<=45)){return true;}
return false;};YAHOO.widget.AutoComplete.prototype._sendQuery=function(sQuery){if(this.minQueryLength==-1){this._toggleContainer(false);return;}
var aDelimChar=(this.delimChar)?this.delimChar:null;if(aDelimChar){var nDelimIndex=-1;for(var i=aDelimChar.length-1;i>=0;i--){var nNewIndex=sQuery.lastIndexOf(aDelimChar[i]);if(nNewIndex>nDelimIndex){nDelimIndex=nNewIndex;}}
if(aDelimChar[i]==" "){for(var j=aDelimChar.length-1;j>=0;j--){if(sQuery[nDelimIndex-1]==aDelimChar[j]){nDelimIndex--;break;}}}
if(nDelimIndex>-1){var nQueryStart=nDelimIndex+1;while(sQuery.charAt(nQueryStart)==" "){nQueryStart+=1;}
this._sSavedQuery=sQuery.substring(0,nQueryStart);sQuery=sQuery.substr(nQueryStart);}
else if(sQuery.indexOf(this._sSavedQuery)<0){this._sSavedQuery=null;}}
if((sQuery&&(sQuery.length<this.minQueryLength))||(!sQuery&&this.minQueryLength>0)){if(this._nDelayID!=-1){clearTimeout(this._nDelayID);}
this._toggleContainer(false);return;}
sQuery=encodeURIComponent(sQuery);this._nDelayID=-1;sQuery=this.doBeforeSendQuery(sQuery);this.dataRequestEvent.fire(this,sQuery);this.dataSource.getResults(this._populateList,sQuery,this);};YAHOO.widget.AutoComplete.prototype._populateList=function(sQuery,aResults,oSelf){if(aResults===null){oSelf.dataErrorEvent.fire(oSelf,sQuery);}
if(!oSelf._bFocused||!aResults){return;}
var isOpera=(navigator.userAgent.toLowerCase().indexOf("opera")!=-1);var contentStyle=oSelf._oContainer._oContent.style;contentStyle.width=(!isOpera)?null:"";contentStyle.height=(!isOpera)?null:"";var sCurQuery=decodeURIComponent(sQuery);oSelf._sCurQuery=sCurQuery;oSelf._bItemSelected=false;if(oSelf._maxResultsDisplayed!=oSelf.maxResultsDisplayed){oSelf._initList();}
var nItems=Math.min(aResults.length,oSelf.maxResultsDisplayed);oSelf._nDisplayedItems=nItems;if(nItems>0){oSelf._initContainerHelpers();var aItems=oSelf._aListItems;for(var i=nItems-1;i>=0;i--){var oItemi=aItems[i];var oResultItemi=aResults[i];oItemi.innerHTML=oSelf.formatResult(oResultItemi,sCurQuery);oItemi.style.display="list-item";oItemi._sResultKey=oResultItemi[0];oItemi._oResultData=oResultItemi;}
for(var j=aItems.length-1;j>=nItems;j--){var oItemj=aItems[j];oItemj.innerHTML=null;oItemj.style.display="none";oItemj._sResultKey=null;oItemj._oResultData=null;}
var ok=oSelf.doBeforeExpandContainer(oSelf._oTextbox,oSelf._oContainer,sQuery,aResults);oSelf._toggleContainer(ok);if(oSelf.autoHighlight){var oFirstItem=aItems[0];oSelf._toggleHighlight(oFirstItem,"to");oSelf.itemArrowToEvent.fire(oSelf,oFirstItem);oSelf._typeAhead(oFirstItem,sQuery);}
else{oSelf._oCurItem=null;}}
else{oSelf._toggleContainer(false);}
oSelf.dataReturnEvent.fire(oSelf,sQuery,aResults);};YAHOO.widget.AutoComplete.prototype._clearSelection=function(){var sValue=this._oTextbox.value;var sChar=(this.delimChar)?this.delimChar[0]:null;var nIndex=(sChar)?sValue.lastIndexOf(sChar,sValue.length-2):-1;if(nIndex>-1){this._oTextbox.value=sValue.substring(0,nIndex);}
else{this._oTextbox.value="";}
this._sSavedQuery=this._oTextbox.value;this.selectionEnforceEvent.fire(this);};YAHOO.widget.AutoComplete.prototype._textMatchesOption=function(){var foundMatch=null;for(var i=this._nDisplayedItems-1;i>=0;i--){var oItem=this._aListItems[i];var sMatch=oItem._sResultKey.toLowerCase();if(sMatch==this._sCurQuery.toLowerCase()){foundMatch=oItem;break;}}
return(foundMatch);};YAHOO.widget.AutoComplete.prototype._typeAhead=function(oItem,sQuery){if(!this.typeAhead||(this._nKeyCode==8)){return;}
var oTextbox=this._oTextbox;var sValue=this._oTextbox.value;if(!oTextbox.setSelectionRange&&!oTextbox.createTextRange){return;}
var nStart=sValue.length;this._updateValue(oItem);var nEnd=oTextbox.value.length;this._selectText(oTextbox,nStart,nEnd);var sPrefill=oTextbox.value.substr(nStart,nEnd);this.typeAheadEvent.fire(this,sQuery,sPrefill);};YAHOO.widget.AutoComplete.prototype._selectText=function(oTextbox,nStart,nEnd){if(oTextbox.setSelectionRange){oTextbox.setSelectionRange(nStart,nEnd);}
else if(oTextbox.createTextRange){var oTextRange=oTextbox.createTextRange();oTextRange.moveStart("character",nStart);oTextRange.moveEnd("character",nEnd-oTextbox.value.length);oTextRange.select();}
else{oTextbox.select();}};YAHOO.widget.AutoComplete.prototype._toggleContainerHelpers=function(bShow){var bFireEvent=false;var width=this._oContainer._oContent.offsetWidth+"px";var height=this._oContainer._oContent.offsetHeight+"px";if(this.useIFrame&&this._oContainer._oIFrame){bFireEvent=true;if(bShow){this._oContainer._oIFrame.style.width=width;this._oContainer._oIFrame.style.height=height;}
else{this._oContainer._oIFrame.style.width=0;this._oContainer._oIFrame.style.height=0;}}
if(this.useShadow&&this._oContainer._oShadow){bFireEvent=true;if(bShow){this._oContainer._oShadow.style.width=width;this._oContainer._oShadow.style.height=height;}
else{this._oContainer._oShadow.style.width=0;this._oContainer._oShadow.style.height=0;}}};YAHOO.widget.AutoComplete.prototype._toggleContainer=function(bShow){var oContainer=this._oContainer;if(this.alwaysShowContainer&&this._bContainerOpen){return;}
if(!bShow){this._oContainer._oContent.scrollTop=0;var aItems=this._aListItems;if(aItems&&(aItems.length>0)){for(var i=aItems.length-1;i>=0;i--){aItems[i].style.display="none";}}
if(this._oCurItem){this._toggleHighlight(this._oCurItem,"from");}
this._oCurItem=null;this._nDisplayedItems=0;this._sCurQuery=null;}
if(!bShow&&!this._bContainerOpen){oContainer._oContent.style.display="none";return;}
var oAnim=this._oAnim;if(oAnim&&oAnim.getEl()&&(this.animHoriz||this.animVert)){if(!bShow){this._toggleContainerHelpers(bShow);}
if(oAnim.isAnimated()){oAnim.stop();}
var oClone=oContainer._oContent.cloneNode(true);oContainer.appendChild(oClone);oClone.style.top="-9000px";oClone.style.display="block";var wExp=oClone.offsetWidth;var hExp=oClone.offsetHeight;var wColl=(this.animHoriz)?0:wExp;var hColl=(this.animVert)?0:hExp;oAnim.attributes=(bShow)?{width:{to:wExp},height:{to:hExp}}:{width:{to:wColl},height:{to:hColl}};if(bShow&&!this._bContainerOpen){oContainer._oContent.style.width=wColl+"px";oContainer._oContent.style.height=hColl+"px";}
else{oContainer._oContent.style.width=wExp+"px";oContainer._oContent.style.height=hExp+"px";}
oContainer.removeChild(oClone);oClone=null;var oSelf=this;var onAnimComplete=function(){oAnim.onComplete.unsubscribeAll();if(bShow){oSelf.containerExpandEvent.fire(oSelf);}
else{oContainer._oContent.style.display="none";oSelf.containerCollapseEvent.fire(oSelf);}
oSelf._toggleContainerHelpers(bShow);};oContainer._oContent.style.display="block";oAnim.onComplete.subscribe(onAnimComplete);oAnim.animate();this._bContainerOpen=bShow;}
else{if(bShow){oContainer._oContent.style.display="block";this.containerExpandEvent.fire(this);}
else{oContainer._oContent.style.display="none";this.containerCollapseEvent.fire(this);}
this._toggleContainerHelpers(bShow);this._bContainerOpen=bShow;}};YAHOO.widget.AutoComplete.prototype._toggleHighlight=function(oNewItem,sType){var sHighlight=this.highlightClassName;if(this._oCurItem){YAHOO.util.Dom.removeClass(this._oCurItem,sHighlight);}
if((sType=="to")&&sHighlight){YAHOO.util.Dom.addClass(oNewItem,sHighlight);this._oCurItem=oNewItem;}};YAHOO.widget.AutoComplete.prototype._togglePrehighlight=function(oNewItem,sType){if(oNewItem==this._oCurItem){return;}
var sPrehighlight=this.prehighlightClassName;if((sType=="mouseover")&&sPrehighlight){YAHOO.util.Dom.addClass(oNewItem,sPrehighlight);}
else{YAHOO.util.Dom.removeClass(oNewItem,sPrehighlight);}};YAHOO.widget.AutoComplete.prototype._updateValue=function(oItem){var oTextbox=this._oTextbox;var sDelimChar=(this.delimChar)?(this.delimChar[0]||this.delimChar):null;var sSavedQuery=this._sSavedQuery;var sResultKey=oItem._sResultKey;oTextbox.focus();oTextbox.value="";if(sDelimChar){if(sSavedQuery){oTextbox.value=sSavedQuery;}
oTextbox.value+=sResultKey+sDelimChar;if(sDelimChar!=" "){oTextbox.value+=" ";}}
else{oTextbox.value=sResultKey;}
if(oTextbox.type=="textarea"){oTextbox.scrollTop=oTextbox.scrollHeight;}
var end=oTextbox.value.length;this._selectText(oTextbox,end,end);this._oCurItem=oItem;};YAHOO.widget.AutoComplete.prototype._selectItem=function(oItem){this._bItemSelected=true;this._updateValue(oItem);this._cancelIntervalDetection(this);this.itemSelectEvent.fire(this,oItem,oItem._oResultData);this._toggleContainer(false);};YAHOO.widget.AutoComplete.prototype._jumpSelection=function(){if(this._oCurItem){this._selectItem(this._oCurItem);}
else{this._toggleContainer(false);}};YAHOO.widget.AutoComplete.prototype._moveSelection=function(nKeyCode){if(this._bContainerOpen){var oCurItem=this._oCurItem;var nCurItemIndex=-1;if(oCurItem){nCurItemIndex=oCurItem._nItemIndex;}
var nNewItemIndex=(nKeyCode==40)?(nCurItemIndex+1):(nCurItemIndex-1);if(nNewItemIndex<-2||nNewItemIndex>=this._nDisplayedItems){return;}
if(oCurItem){this._toggleHighlight(oCurItem,"from");this.itemArrowFromEvent.fire(this,oCurItem);}
if(nNewItemIndex==-1){if(this.delimChar&&this._sSavedQuery){if(!this._textMatchesOption()){this._oTextbox.value=this._sSavedQuery;}
else{this._oTextbox.value=this._sSavedQuery+this._sCurQuery;}}
else{this._oTextbox.value=this._sCurQuery;}
this._oCurItem=null;return;}
if(nNewItemIndex==-2){this._toggleContainer(false);return;}
var oNewItem=this._aListItems[nNewItemIndex];var oContent=this._oContainer._oContent;var scrollOn=((YAHOO.util.Dom.getStyle(oContent,"overflow")=="auto")||(YAHOO.util.Dom.getStyle(oContent,"overflowY")=="auto"));if(scrollOn&&(nNewItemIndex>-1)&&(nNewItemIndex<this._nDisplayedItems)){if(nKeyCode==40){if((oNewItem.offsetTop+oNewItem.offsetHeight)>(oContent.scrollTop+oContent.offsetHeight)){oContent.scrollTop=(oNewItem.offsetTop+oNewItem.offsetHeight)-oContent.offsetHeight;}
else if((oNewItem.offsetTop+oNewItem.offsetHeight)<oContent.scrollTop){oContent.scrollTop=oNewItem.offsetTop;}}
else{if(oNewItem.offsetTop<oContent.scrollTop){this._oContainer._oContent.scrollTop=oNewItem.offsetTop;}
else if(oNewItem.offsetTop>(oContent.scrollTop+oContent.offsetHeight)){this._oContainer._oContent.scrollTop=(oNewItem.offsetTop+oNewItem.offsetHeight)-oContent.offsetHeight;}}}
this._toggleHighlight(oNewItem,"to");this.itemArrowToEvent.fire(this,oNewItem);if(this.typeAhead){this._updateValue(oNewItem);}}};YAHOO.widget.AutoComplete.prototype._onItemMouseover=function(v,oSelf){if(oSelf.prehighlightClassName){oSelf._togglePrehighlight(this,"mouseover");}
else{oSelf._toggleHighlight(this,"to");}
oSelf.itemMouseOverEvent.fire(oSelf,this);};YAHOO.widget.AutoComplete.prototype._onItemMouseout=function(v,oSelf){if(oSelf.prehighlightClassName){oSelf._togglePrehighlight(this,"mouseout");}
else{oSelf._toggleHighlight(this,"from");}
oSelf.itemMouseOutEvent.fire(oSelf,this);};YAHOO.widget.AutoComplete.prototype._onItemMouseclick=function(v,oSelf){oSelf._toggleHighlight(this,"to");oSelf._selectItem(this);};YAHOO.widget.AutoComplete.prototype._onContainerMouseover=function(v,oSelf){oSelf._bOverContainer=true;};YAHOO.widget.AutoComplete.prototype._onContainerMouseout=function(v,oSelf){oSelf._bOverContainer=false;if(oSelf._oCurItem){oSelf._toggleHighlight(oSelf._oCurItem,"to");}};YAHOO.widget.AutoComplete.prototype._onContainerScroll=function(v,oSelf){oSelf._oTextbox.focus();};YAHOO.widget.AutoComplete.prototype._onContainerResize=function(v,oSelf){oSelf._toggleContainerHelpers(oSelf._bContainerOpen);};YAHOO.widget.AutoComplete.prototype._onTextboxKeyDown=function(v,oSelf){var nKeyCode=v.keyCode;switch(nKeyCode){case 9:if(oSelf._oCurItem){if(oSelf.delimChar&&(oSelf._nKeyCode!=nKeyCode)){if(oSelf._bContainerOpen){YAHOO.util.Event.stopEvent(v);}}
oSelf._selectItem(oSelf._oCurItem);}
else{oSelf._toggleContainer(false);}
break;case 13:if(oSelf._oCurItem){if(oSelf._nKeyCode!=nKeyCode){if(oSelf._bContainerOpen){YAHOO.util.Event.stopEvent(v);}}
oSelf._selectItem(oSelf._oCurItem);}
else{oSelf._toggleContainer(false);}
break;case 27:oSelf._toggleContainer(false);return;case 39:oSelf._jumpSelection();break;case 38:YAHOO.util.Event.stopEvent(v);oSelf._moveSelection(nKeyCode);break;case 40:YAHOO.util.Event.stopEvent(v);oSelf._moveSelection(nKeyCode);break;default:break;}};YAHOO.widget.AutoComplete.prototype._onTextboxKeyPress=function(v,oSelf){var nKeyCode=v.keyCode;var isMac=(navigator.userAgent.toLowerCase().indexOf("mac")!=-1);if(isMac){switch(nKeyCode){case 9:if(oSelf.delimChar&&(oSelf._nKeyCode!=nKeyCode)){YAHOO.util.Event.stopEvent(v);}
break;case 13:if(oSelf._nKeyCode!=nKeyCode){YAHOO.util.Event.stopEvent(v);}
break;case 38:case 40:YAHOO.util.Event.stopEvent(v);break;default:break;}}
else if(nKeyCode==229){oSelf._queryInterval=setInterval(function(){oSelf._onIMEDetected(oSelf);},500);}};YAHOO.widget.AutoComplete.prototype._onTextboxKeyUp=function(v,oSelf){oSelf._initProps();var nKeyCode=v.keyCode;oSelf._nKeyCode=nKeyCode;var sText=this.value;if(oSelf._isIgnoreKey(nKeyCode)||(sText.toLowerCase()==oSelf._sCurQuery)){return;}
else{oSelf._bItemSelected=false;YAHOO.util.Dom.removeClass(oSelf._oCurItem,oSelf.highlightClassName);oSelf._oCurItem=null;oSelf.textboxKeyEvent.fire(oSelf,nKeyCode);}
if(oSelf.queryDelay>0){var nDelayID=setTimeout(function(){oSelf._sendQuery(sText);},(oSelf.queryDelay*1000));if(oSelf._nDelayID!=-1){clearTimeout(oSelf._nDelayID);}
oSelf._nDelayID=nDelayID;}
else{oSelf._sendQuery(sText);}};YAHOO.widget.AutoComplete.prototype._onTextboxFocus=function(v,oSelf){oSelf._oTextbox.setAttribute("autocomplete","off");oSelf._bFocused=true;if(!oSelf._bItemSelected){oSelf.textboxFocusEvent.fire(oSelf);}};YAHOO.widget.AutoComplete.prototype._onTextboxBlur=function(v,oSelf){if(!oSelf._bOverContainer||(oSelf._nKeyCode==9)){if(!oSelf._bItemSelected){var oMatch=oSelf._textMatchesOption();if(!oSelf._bContainerOpen||(oSelf._bContainerOpen&&(oMatch===null))){if(oSelf.forceSelection){oSelf._clearSelection();}
else{oSelf.unmatchedItemSelectEvent.fire(oSelf,oSelf._sCurQuery);}}
else{oSelf._selectItem(oMatch);}}
if(oSelf._bContainerOpen){oSelf._toggleContainer(false);}
oSelf._cancelIntervalDetection(oSelf);oSelf._bFocused=false;oSelf.textboxBlurEvent.fire(oSelf);}};YAHOO.widget.AutoComplete.prototype._onFormSubmit=function(v,oSelf){if(oSelf.allowBrowserAutocomplete){oSelf._oTextbox.setAttribute("autocomplete","on");}
else{oSelf._oTextbox.setAttribute("autocomplete","off");}};YAHOO.widget.DataSource=function(){};YAHOO.widget.DataSource.ERROR_DATANULL="Response data was null";YAHOO.widget.DataSource.ERROR_DATAPARSE="Response data could not be parsed";YAHOO.widget.DataSource.prototype.maxCacheEntries=15;YAHOO.widget.DataSource.prototype.queryMatchContains=false;YAHOO.widget.DataSource.prototype.queryMatchSubset=false;YAHOO.widget.DataSource.prototype.queryMatchCase=false;YAHOO.widget.DataSource.prototype.toString=function(){return"DataSource "+this._sName;};YAHOO.widget.DataSource.prototype.getResults=function(oCallbackFn,sQuery,oParent){var aResults=this._doQueryCache(oCallbackFn,sQuery,oParent);if(aResults.length===0){this.queryEvent.fire(this,oParent,sQuery);this.doQuery(oCallbackFn,sQuery,oParent);}};YAHOO.widget.DataSource.prototype.doQuery=function(oCallbackFn,sQuery,oParent){};YAHOO.widget.DataSource.prototype.flushCache=function(){if(this._aCache){this._aCache=[];}
if(this._aCacheHelper){this._aCacheHelper=[];}
this.cacheFlushEvent.fire(this);};YAHOO.widget.DataSource.prototype.queryEvent=null;YAHOO.widget.DataSource.prototype.cacheQueryEvent=null;YAHOO.widget.DataSource.prototype.getResultsEvent=null;YAHOO.widget.DataSource.prototype.getCachedResultsEvent=null;YAHOO.widget.DataSource.prototype.dataErrorEvent=null;YAHOO.widget.DataSource.prototype.cacheFlushEvent=null;YAHOO.widget.DataSource._nIndex=0;YAHOO.widget.DataSource.prototype._sName=null;YAHOO.widget.DataSource.prototype._aCache=null;YAHOO.widget.DataSource.prototype._init=function(){var maxCacheEntries=this.maxCacheEntries;if(!YAHOO.lang.isNumber(maxCacheEntries)||(maxCacheEntries<0)){maxCacheEntries=0;}
if(maxCacheEntries>0&&!this._aCache){this._aCache=[];}
this._sName="instance"+YAHOO.widget.DataSource._nIndex;YAHOO.widget.DataSource._nIndex++;this.queryEvent=new YAHOO.util.CustomEvent("query",this);this.cacheQueryEvent=new YAHOO.util.CustomEvent("cacheQuery",this);this.getResultsEvent=new YAHOO.util.CustomEvent("getResults",this);this.getCachedResultsEvent=new YAHOO.util.CustomEvent("getCachedResults",this);this.dataErrorEvent=new YAHOO.util.CustomEvent("dataError",this);this.cacheFlushEvent=new YAHOO.util.CustomEvent("cacheFlush",this);};YAHOO.widget.DataSource.prototype._addCacheElem=function(oResult){var aCache=this._aCache;if(!aCache||!oResult||!oResult.query||!oResult.results){return;}
if(aCache.length>=this.maxCacheEntries){aCache.shift();}
aCache.push(oResult);};YAHOO.widget.DataSource.prototype._doQueryCache=function(oCallbackFn,sQuery,oParent){var aResults=[];var bMatchFound=false;var aCache=this._aCache;var nCacheLength=(aCache)?aCache.length:0;var bMatchContains=this.queryMatchContains;if((this.maxCacheEntries>0)&&aCache&&(nCacheLength>0)){this.cacheQueryEvent.fire(this,oParent,sQuery);if(!this.queryMatchCase){var sOrigQuery=sQuery;sQuery=sQuery.toLowerCase();}
for(var i=nCacheLength-1;i>=0;i--){var resultObj=aCache[i];var aAllResultItems=resultObj.results;var matchKey=(!this.queryMatchCase)?encodeURIComponent(resultObj.query).toLowerCase():encodeURIComponent(resultObj.query);if(matchKey==sQuery){bMatchFound=true;aResults=aAllResultItems;if(i!=nCacheLength-1){aCache.splice(i,1);this._addCacheElem(resultObj);}
break;}
else if(this.queryMatchSubset){for(var j=sQuery.length-1;j>=0;j--){var subQuery=sQuery.substr(0,j);if(matchKey==subQuery){bMatchFound=true;for(var k=aAllResultItems.length-1;k>=0;k--){var aRecord=aAllResultItems[k];var sKeyIndex=(this.queryMatchCase)?encodeURIComponent(aRecord[0]).indexOf(sQuery):encodeURIComponent(aRecord[0]).toLowerCase().indexOf(sQuery);if((!bMatchContains&&(sKeyIndex===0))||(bMatchContains&&(sKeyIndex>-1))){aResults.unshift(aRecord);}}
resultObj={};resultObj.query=sQuery;resultObj.results=aResults;this._addCacheElem(resultObj);break;}}
if(bMatchFound){break;}}}
if(bMatchFound){this.getCachedResultsEvent.fire(this,oParent,sOrigQuery,aResults);oCallbackFn(sOrigQuery,aResults,oParent);}}
return aResults;};YAHOO.widget.DS_XHR=function(sScriptURI,aSchema,oConfigs){if(oConfigs&&(oConfigs.constructor==Object)){for(var sConfig in oConfigs){this[sConfig]=oConfigs[sConfig];}}
if(!YAHOO.lang.isArray(aSchema)||!YAHOO.lang.isString(sScriptURI)){return;}
this.schema=aSchema;this.scriptURI=sScriptURI;this._init();};YAHOO.widget.DS_XHR.prototype=new YAHOO.widget.DataSource();YAHOO.widget.DS_XHR.TYPE_JSON=0;YAHOO.widget.DS_XHR.TYPE_XML=1;YAHOO.widget.DS_XHR.TYPE_FLAT=2;YAHOO.widget.DS_XHR.ERROR_DATAXHR="XHR response failed";YAHOO.widget.DS_XHR.prototype.connMgr=YAHOO.util.Connect;YAHOO.widget.DS_XHR.prototype.connTimeout=0;YAHOO.widget.DS_XHR.prototype.scriptURI=null;YAHOO.widget.DS_XHR.prototype.scriptQueryParam="query";YAHOO.widget.DS_XHR.prototype.scriptQueryAppend="";YAHOO.widget.DS_XHR.prototype.responseType=YAHOO.widget.DS_XHR.TYPE_JSON;YAHOO.widget.DS_XHR.prototype.responseStripAfter="\n<!-";YAHOO.widget.DS_XHR.prototype.doQuery=function(oCallbackFn,sQuery,oParent){var isXML=(this.responseType==YAHOO.widget.DS_XHR.TYPE_XML);var sUri=this.scriptURI+"?"+this.scriptQueryParam+"="+sQuery;if(this.scriptQueryAppend.length>0){sUri+="&"+this.scriptQueryAppend;}
var oResponse=null;var oSelf=this;var responseSuccess=function(oResp){if(!oSelf._oConn||(oResp.tId!=oSelf._oConn.tId)){oSelf.dataErrorEvent.fire(oSelf,oParent,sQuery,YAHOO.widget.DataSource.ERROR_DATANULL);return;}
for(var foo in oResp){}
if(!isXML){oResp=oResp.responseText;}
else{oResp=oResp.responseXML;}
if(oResp===null){oSelf.dataErrorEvent.fire(oSelf,oParent,sQuery,YAHOO.widget.DataSource.ERROR_DATANULL);return;}
var aResults=oSelf.parseResponse(sQuery,oResp,oParent);var resultObj={};resultObj.query=decodeURIComponent(sQuery);resultObj.results=aResults;if(aResults===null){oSelf.dataErrorEvent.fire(oSelf,oParent,sQuery,YAHOO.widget.DataSource.ERROR_DATAPARSE);aResults=[];}
else{oSelf.getResultsEvent.fire(oSelf,oParent,sQuery,aResults);oSelf._addCacheElem(resultObj);}
oCallbackFn(sQuery,aResults,oParent);};var responseFailure=function(oResp){oSelf.dataErrorEvent.fire(oSelf,oParent,sQuery,YAHOO.widget.DS_XHR.ERROR_DATAXHR);return;};var oCallback={success:responseSuccess,failure:responseFailure};if(YAHOO.lang.isNumber(this.connTimeout)&&(this.connTimeout>0)){oCallback.timeout=this.connTimeout;}
if(this._oConn){this.connMgr.abort(this._oConn);}
oSelf._oConn=this.connMgr.asyncRequest("GET",sUri,oCallback,null);};YAHOO.widget.DS_XHR.prototype.parseResponse=function(sQuery,oResponse,oParent){var aSchema=this.schema;var aResults=[];var bError=false;var nEnd=((this.responseStripAfter!=="")&&(oResponse.indexOf))?oResponse.indexOf(this.responseStripAfter):-1;if(nEnd!=-1){oResponse=oResponse.substring(0,nEnd);}
switch(this.responseType){case YAHOO.widget.DS_XHR.TYPE_JSON:var jsonList,jsonObjParsed;var isNotMac=(navigator.userAgent.toLowerCase().indexOf('khtml')==-1);if(oResponse.parseJSON&&isNotMac){jsonObjParsed=oResponse.parseJSON();if(!jsonObjParsed){bError=true;}
else{try{jsonList=eval("jsonObjParsed."+aSchema[0]);}
catch(e){bError=true;break;}}}
else if(window.JSON&&isNotMac){jsonObjParsed=JSON.parse(oResponse);if(!jsonObjParsed){bError=true;break;}
else{try{jsonList=eval("jsonObjParsed."+aSchema[0]);}
catch(e){bError=true;break;}}}
else{try{while(oResponse.substring(0,1)==" "){oResponse=oResponse.substring(1,oResponse.length);}
if(oResponse.indexOf("{")<0){bError=true;break;}
if(oResponse.indexOf("{}")===0){break;}
var jsonObjRaw=eval("("+oResponse+")");if(!jsonObjRaw){bError=true;break;}
jsonList=eval("(jsonObjRaw."+aSchema[0]+")");}
catch(e){bError=true;break;}}
if(!jsonList){bError=true;break;}
if(!YAHOO.lang.isArray(jsonList)){jsonList=[jsonList];}
for(var i=jsonList.length-1;i>=0;i--){var aResultItem=[];var jsonResult=jsonList[i];for(var j=aSchema.length-1;j>=1;j--){var dataFieldValue=jsonResult[aSchema[j]];if(!dataFieldValue){dataFieldValue="";}
aResultItem.unshift(dataFieldValue);}
if(aResultItem.length==1){aResultItem.push(jsonResult);}
aResults.unshift(aResultItem);}
break;case YAHOO.widget.DS_XHR.TYPE_XML:var xmlList=oResponse.getElementsByTagName(aSchema[0]);if(!xmlList){bError=true;break;}
for(var k=xmlList.length-1;k>=0;k--){var result=xmlList.item(k);var aFieldSet=[];for(var m=aSchema.length-1;m>=1;m--){var sValue=null;var xmlAttr=result.attributes.getNamedItem(aSchema[m]);if(xmlAttr){sValue=xmlAttr.value;}
else{var xmlNode=result.getElementsByTagName(aSchema[m]);if(xmlNode&&xmlNode.item(0)&&xmlNode.item(0).firstChild){sValue=xmlNode.item(0).firstChild.nodeValue;}
else{sValue="";}}
aFieldSet.unshift(sValue);}
aResults.unshift(aFieldSet);}
break;case YAHOO.widget.DS_XHR.TYPE_FLAT:if(oResponse.length>0){var newLength=oResponse.length-aSchema[0].length;if(oResponse.substr(newLength)==aSchema[0]){oResponse=oResponse.substr(0,newLength);}
var aRecords=oResponse.split(aSchema[0]);for(var n=aRecords.length-1;n>=0;n--){aResults[n]=aRecords[n].split(aSchema[1]);}}
break;default:break;}
sQuery=null;oResponse=null;oParent=null;if(bError){return null;}
else{return aResults;}};YAHOO.widget.DS_XHR.prototype._oConn=null;YAHOO.widget.DS_JSFunction=function(oFunction,oConfigs){if(oConfigs&&(oConfigs.constructor==Object)){for(var sConfig in oConfigs){this[sConfig]=oConfigs[sConfig];}}
if(!YAHOO.lang.isFunction(oFunction)){return;}
else{this.dataFunction=oFunction;this._init();}};YAHOO.widget.DS_JSFunction.prototype=new YAHOO.widget.DataSource();YAHOO.widget.DS_JSFunction.prototype.dataFunction=null;YAHOO.widget.DS_JSFunction.prototype.doQuery=function(oCallbackFn,sQuery,oParent){var oFunction=this.dataFunction;var aResults=[];aResults=oFunction(sQuery);if(aResults===null){this.dataErrorEvent.fire(this,oParent,sQuery,YAHOO.widget.DataSource.ERROR_DATANULL);return;}
var resultObj={};resultObj.query=decodeURIComponent(sQuery);resultObj.results=aResults;this._addCacheElem(resultObj);this.getResultsEvent.fire(this,oParent,sQuery,aResults);oCallbackFn(sQuery,aResults,oParent);return;};YAHOO.widget.DS_JSArray=function(aData,oConfigs){if(oConfigs&&(oConfigs.constructor==Object)){for(var sConfig in oConfigs){this[sConfig]=oConfigs[sConfig];}}
if(!YAHOO.lang.isArray(aData)){return;}
else{this.data=aData;this._init();}};YAHOO.widget.DS_JSArray.prototype=new YAHOO.widget.DataSource();YAHOO.widget.DS_JSArray.prototype.data=null;YAHOO.widget.DS_JSArray.prototype.doQuery=function(oCallbackFn,sQuery,oParent){var i;var aData=this.data;var aResults=[];var bMatchFound=false;var bMatchContains=this.queryMatchContains;if(sQuery){if(!this.queryMatchCase){sQuery=sQuery.toLowerCase();}
for(i=aData.length-1;i>=0;i--){var aDataset=[];if(YAHOO.lang.isString(aData[i])){aDataset[0]=aData[i];}
else if(YAHOO.lang.isArray(aData[i])){aDataset=aData[i];}
if(YAHOO.lang.isString(aDataset[0])){var sKeyIndex=(this.queryMatchCase)?encodeURIComponent(aDataset[0]).indexOf(sQuery):encodeURIComponent(aDataset[0]).toLowerCase().indexOf(sQuery);if((!bMatchContains&&(sKeyIndex===0))||(bMatchContains&&(sKeyIndex>-1))){aResults.unshift(aDataset);}}}}
else{for(i=aData.length-1;i>=0;i--){if(YAHOO.lang.isString(aData[i])){aResults.unshift([aData[i]]);}
else if(YAHOO.lang.isArray(aData[i])){aResults.unshift(aData[i]);}}}
this.getResultsEvent.fire(this,oParent,sQuery,aResults);oCallbackFn(sQuery,aResults,oParent);};YAHOO.register("autocomplete",YAHOO.widget.AutoComplete,{version:"2.3.0",build:"442"});/*
Copyright (c) 2007, Yahoo! Inc. All rights reserved.
Code licensed under the BSD License:
http://developer.yahoo.net/yui/license.txt
version: 2.3.0
*/

YAHOO.util.DataSource=function(oLiveData,oConfigs){if(oConfigs&&(oConfigs.constructor==Object)){for(var sConfig in oConfigs){if(sConfig){this[sConfig]=oConfigs[sConfig];}}}
if(!oLiveData){return;}
if(oLiveData.nodeType&&oLiveData.nodeType==9){this.dataType=YAHOO.util.DataSource.TYPE_XML;}
else if(YAHOO.lang.isArray(oLiveData)){this.dataType=YAHOO.util.DataSource.TYPE_JSARRAY;}
else if(YAHOO.lang.isString(oLiveData)){this.dataType=YAHOO.util.DataSource.TYPE_XHR;}
else if(YAHOO.lang.isFunction(oLiveData)){this.dataType=YAHOO.util.DataSource.TYPE_JSFUNCTION;}
else if(oLiveData.nodeName&&(oLiveData.nodeName.toLowerCase()=="table")){this.dataType=YAHOO.util.DataSource.TYPE_HTMLTABLE;}
else if(YAHOO.lang.isObject(oLiveData)){this.dataType=YAHOO.util.DataSource.TYPE_JSON;}
else{this.dataType=YAHOO.util.DataSource.TYPE_UNKNOWN;}
this.liveData=oLiveData;this._oQueue={interval:null,conn:null,requests:[]};var maxCacheEntries=this.maxCacheEntries;if(!YAHOO.lang.isNumber(maxCacheEntries)||(maxCacheEntries<0)){maxCacheEntries=0;}
if(maxCacheEntries>0&&!this._aCache){this._aCache=[];}
this._sName="DataSource instance"+YAHOO.util.DataSource._nIndex;YAHOO.util.DataSource._nIndex++;this.createEvent("cacheRequestEvent");this.createEvent("cacheResponseEvent");this.createEvent("requestEvent");this.createEvent("responseEvent");this.createEvent("responseParseEvent");this.createEvent("responseCacheEvent");this.createEvent("dataErrorEvent");this.createEvent("cacheFlushEvent");};YAHOO.augment(YAHOO.util.DataSource,YAHOO.util.EventProvider);YAHOO.util.DataSource.TYPE_UNKNOWN=-1;YAHOO.util.DataSource.TYPE_JSARRAY=0;YAHOO.util.DataSource.TYPE_JSFUNCTION=1;YAHOO.util.DataSource.TYPE_XHR=2;YAHOO.util.DataSource.TYPE_JSON=3;YAHOO.util.DataSource.TYPE_XML=4;YAHOO.util.DataSource.TYPE_TEXT=5;YAHOO.util.DataSource.TYPE_HTMLTABLE=6;YAHOO.util.DataSource.ERROR_DATAINVALID="Invalid data";YAHOO.util.DataSource.ERROR_DATANULL="Null data";YAHOO.util.DataSource._nIndex=0;YAHOO.util.DataSource._nTransactionId=0;YAHOO.util.DataSource.prototype._sName=null;YAHOO.util.DataSource.prototype._aCache=null;YAHOO.util.DataSource.prototype._oQueue=null;YAHOO.util.DataSource.prototype.maxCacheEntries=0;YAHOO.util.DataSource.prototype.liveData=null;YAHOO.util.DataSource.prototype.dataType=YAHOO.util.DataSource.TYPE_UNKNOWN;YAHOO.util.DataSource.prototype.responseType=YAHOO.util.DataSource.TYPE_UNKNOWN;YAHOO.util.DataSource.prototype.responseSchema=null;YAHOO.util.DataSource.prototype.connMgr=null;YAHOO.util.DataSource.prototype.connXhrMode="allowAll";YAHOO.util.DataSource.prototype.connMethodPost=false;YAHOO.util.DataSource.prototype.connTimeout=0;YAHOO.util.DataSource.parseString=function(oData){if(!YAHOO.lang.isValue(oData)){return null;}
var string=oData+"";if(YAHOO.lang.isString(string)){return string;}
else{return null;}};YAHOO.util.DataSource.parseNumber=function(oData){var number=oData*1;if(YAHOO.lang.isNumber(number)){return number;}
else{return null;}};YAHOO.util.DataSource.convertNumber=function(oData){return YAHOO.util.DataSource.parseNumber(oData);};YAHOO.util.DataSource.parseDate=function(oData){var date=null;if(!(oData instanceof Date)){date=new Date(oData);}
else{return oData;}
if(date instanceof Date){return date;}
else{return null;}};YAHOO.util.DataSource.convertDate=function(oData){return YAHOO.util.DataSource.parseDate(oData);};YAHOO.util.DataSource.prototype.toString=function(){return this._sName;};YAHOO.util.DataSource.prototype.getCachedResponse=function(oRequest,oCallback,oCaller){var aCache=this._aCache;var nCacheLength=(aCache)?aCache.length:0;var oResponse=null;if((this.maxCacheEntries>0)&&aCache&&(nCacheLength>0)){this.fireEvent("cacheRequestEvent",{request:oRequest,callback:oCallback,caller:oCaller});for(var i=nCacheLength-1;i>=0;i--){var oCacheElem=aCache[i];if(this.isCacheHit(oRequest,oCacheElem.request)){oResponse=oCacheElem.response;aCache.splice(i,1);this.addToCache(oRequest,oResponse);this.fireEvent("cacheResponseEvent",{request:oRequest,response:oResponse,callback:oCallback,caller:oCaller});break;}}}
return oResponse;};YAHOO.util.DataSource.prototype.isCacheHit=function(oRequest,oCachedRequest){return(oRequest===oCachedRequest);};YAHOO.util.DataSource.prototype.addToCache=function(oRequest,oResponse){var aCache=this._aCache;if(!aCache){return;}
while(aCache.length>=this.maxCacheEntries){aCache.shift();}
var oCacheElem={request:oRequest,response:oResponse};aCache.push(oCacheElem);this.fireEvent("responseCacheEvent",{request:oRequest,response:oResponse});};YAHOO.util.DataSource.prototype.flushCache=function(){if(this._aCache){this._aCache=[];this.fireEvent("cacheFlushEvent");}};YAHOO.util.DataSource.prototype.sendRequest=function(oRequest,oCallback,oCaller){var oCachedResponse=this.getCachedResponse(oRequest,oCallback,oCaller);if(oCachedResponse){oCallback.call(oCaller,oRequest,oCachedResponse);return null;}
return this.makeConnection(oRequest,oCallback,oCaller);};YAHOO.util.DataSource.prototype.makeConnection=function(oRequest,oCallback,oCaller){this.fireEvent("requestEvent",{request:oRequest,callback:oCallback,caller:oCaller});var oRawResponse=null;var tId=YAHOO.util.DataSource._nTransactionId++;switch(this.dataType){case YAHOO.util.DataSource.TYPE_JSFUNCTION:oRawResponse=this.liveData(oRequest);this.handleResponse(oRequest,oRawResponse,oCallback,oCaller,tId);break;case YAHOO.util.DataSource.TYPE_XHR:var oSelf=this;var oConnMgr=this.connMgr||YAHOO.util.Connect;var oQueue=this._oQueue;var _xhrSuccess=function(oResponse){if(oResponse&&(this.connXhrMode=="ignoreStaleResponses")&&(oResponse.tId!=oQueue.conn.tId)){return null;}
else if(!oResponse){this.fireEvent("dataErrorEvent",{request:oRequest,callback:oCallback,caller:oCaller,message:YAHOO.util.DataSource.ERROR_DATANULL});oCallback.call(oCaller,oRequest,oResponse,true);return null;}
else{this.handleResponse(oRequest,oResponse,oCallback,oCaller,tId);}};var _xhrFailure=function(oResponse){this.fireEvent("dataErrorEvent",{request:oRequest,callback:oCallback,caller:oCaller,message:YAHOO.util.DataSource.ERROR_DATAINVALID});if((this.liveData.lastIndexOf("?")!==this.liveData.length-1)&&(oRequest.indexOf("?")!==0)){}
oCallback.call(oCaller,oRequest,oResponse,true);return null;};var _xhrCallback={success:_xhrSuccess,failure:_xhrFailure,scope:this};if(YAHOO.lang.isNumber(this.connTimeout)){_xhrCallback.timeout=this.connTimeout;}
if(this.connXhrMode=="cancelStaleRequests"){if(oQueue.conn){if(oConnMgr.abort){oConnMgr.abort(oQueue.conn);oQueue.conn=null;}
else{}}}
if(oConnMgr&&oConnMgr.asyncRequest){var sLiveData=this.liveData;var isPost=this.connMethodPost;var sMethod=(isPost)?"POST":"GET";var sUri=(isPost)?sLiveData:sLiveData+oRequest;var sRequest=(isPost)?oRequest:null;if(this.connXhrMode!="queueRequests"){oQueue.conn=oConnMgr.asyncRequest(sMethod,sUri,_xhrCallback,sRequest);}
else{if(oQueue.conn){oQueue.requests.push({request:oRequest,callback:_xhrCallback});if(!oQueue.interval){oQueue.interval=setInterval(function(){if(oConnMgr.isCallInProgress(oQueue.conn)){return;}
else{if(oQueue.requests.length>0){sUri=(isPost)?sLiveData:sLiveData+oQueue.requests[0].request;sRequest=(isPost)?oQueue.requests[0].request:null;oQueue.conn=oConnMgr.asyncRequest(sMethod,sUri,oQueue.requests[0].callback,sRequest);oQueue.requests.shift();}
else{clearInterval(oQueue.interval);oQueue.interval=null;}}},50);}}
else{oQueue.conn=oConnMgr.asyncRequest(sMethod,sUri,_xhrCallback,sRequest);}}}
else{oCallback.call(oCaller,oRequest,null,true);}
break;default:oRawResponse=this.liveData;this.handleResponse(oRequest,oRawResponse,oCallback,oCaller,tId);break;}
return tId;};YAHOO.util.DataSource.prototype.handleResponse=function(oRequest,oRawResponse,oCallback,oCaller,tId){this.fireEvent("responseEvent",{request:oRequest,response:oRawResponse,callback:oCallback,caller:oCaller,tId:tId});var xhr=(this.dataType==YAHOO.util.DataSource.TYPE_XHR)?true:false;var oParsedResponse=null;var bError=false;oRawResponse=this.doBeforeParseData(oRequest,oRawResponse);switch(this.responseType){case YAHOO.util.DataSource.TYPE_JSARRAY:if(xhr&&oRawResponse.responseText){oRawResponse=oRawResponse.responseText;}
oParsedResponse=this.parseArrayData(oRequest,oRawResponse);break;case YAHOO.util.DataSource.TYPE_JSON:if(xhr&&oRawResponse.responseText){oRawResponse=oRawResponse.responseText;}
oParsedResponse=this.parseJSONData(oRequest,oRawResponse);break;case YAHOO.util.DataSource.TYPE_HTMLTABLE:if(xhr&&oRawResponse.responseText){oRawResponse=oRawResponse.responseText;}
oParsedResponse=this.parseHTMLTableData(oRequest,oRawResponse);break;case YAHOO.util.DataSource.TYPE_XML:if(xhr&&oRawResponse.responseXML){oRawResponse=oRawResponse.responseXML;}
oParsedResponse=this.parseXMLData(oRequest,oRawResponse);break;case YAHOO.util.DataSource.TYPE_TEXT:if(xhr&&oRawResponse.responseText){oRawResponse=oRawResponse.responseText;}
oParsedResponse=this.parseTextData(oRequest,oRawResponse);break;default:break;}
if(oParsedResponse){oParsedResponse.tId=tId;oParsedResponse=this.doBeforeCallback(oRequest,oRawResponse,oParsedResponse);this.fireEvent("responseParseEvent",{request:oRequest,response:oParsedResponse,callback:oCallback,caller:oCaller});this.addToCache(oRequest,oParsedResponse);}
else{this.fireEvent("dataErrorEvent",{request:oRequest,callback:oCallback,caller:oCaller,message:YAHOO.util.DataSource.ERROR_DATANULL});oParsedResponse={error:true};}
oCallback.call(oCaller,oRequest,oParsedResponse);};YAHOO.util.DataSource.prototype.doBeforeParseData=function(oRequest,oRawResponse){return oRawResponse;};YAHOO.util.DataSource.prototype.doBeforeCallback=function(oRequest,oRawResponse,oParsedResponse){return oParsedResponse;};YAHOO.util.DataSource.prototype.parseArrayData=function(oRequest,oRawResponse){if(YAHOO.lang.isArray(oRawResponse)&&YAHOO.lang.isArray(this.responseSchema.fields)){var oParsedResponse={results:[]};var fields=this.responseSchema.fields;for(var i=oRawResponse.length-1;i>-1;i--){var oResult={};for(var j=fields.length-1;j>-1;j--){var field=fields[j];var key=(YAHOO.lang.isValue(field.key))?field.key:field;var data=(YAHOO.lang.isValue(oRawResponse[i][j]))?oRawResponse[i][j]:oRawResponse[i][key];if(!field.parser&&field.converter){field.parser=field.converter;}
if(field.parser){data=field.parser.call(this,data);}
if(data===undefined){data=null;}
oResult[key]=data;}
oParsedResponse.results.unshift(oResult);}
return oParsedResponse;}
else{return null;}};YAHOO.util.DataSource.prototype.parseTextData=function(oRequest,oRawResponse){var oParsedResponse={};if(YAHOO.lang.isString(oRawResponse)&&YAHOO.lang.isArray(this.responseSchema.fields)&&YAHOO.lang.isString(this.responseSchema.recordDelim)&&YAHOO.lang.isString(this.responseSchema.fieldDelim)){oParsedResponse.results=[];var recDelim=this.responseSchema.recordDelim;var fieldDelim=this.responseSchema.fieldDelim;var fields=this.responseSchema.fields;if(oRawResponse.length>0){var newLength=oRawResponse.length-recDelim.length;if(oRawResponse.substr(newLength)==recDelim){oRawResponse=oRawResponse.substr(0,newLength);}
var recordsarray=oRawResponse.split(recDelim);for(var i=recordsarray.length-1;i>-1;i--){var oResult={};for(var j=fields.length-1;j>-1;j--){var fielddataarray=recordsarray[i].split(fieldDelim);var data=fielddataarray[j];if(data.charAt(0)=="\""){data=data.substr(1);}
if(data.charAt(data.length-1)=="\""){data=data.substr(0,data.length-1);}
var field=fields[j];var key=(YAHOO.lang.isValue(field.key))?field.key:field;if(!field.parser&&field.converter){field.parser=field.converter;}
if(field.parser){data=field.parser.call(this,data);}
if(data===undefined){data=null;}
oResult[key]=data;}
oParsedResponse.results.unshift(oResult);}}}
else{oParsedResponse.error=true;}
return oParsedResponse;};YAHOO.util.DataSource.prototype.parseXMLData=function(oRequest,oRawResponse){var bError=false;var oParsedResponse={};var xmlList=(this.responseSchema.resultNode)?oRawResponse.getElementsByTagName(this.responseSchema.resultNode):null;if(!xmlList||!YAHOO.lang.isArray(this.responseSchema.fields)){bError=true;}
else{oParsedResponse.results=[];for(var k=xmlList.length-1;k>=0;k--){var result=xmlList.item(k);var oResult={};for(var m=this.responseSchema.fields.length-1;m>=0;m--){var field=this.responseSchema.fields[m];var key=(YAHOO.lang.isValue(field.key))?field.key:field;var data=null;var xmlAttr=result.attributes.getNamedItem(key);if(xmlAttr){data=xmlAttr.value;}
else{var xmlNode=result.getElementsByTagName(key);if(xmlNode&&xmlNode.item(0)&&xmlNode.item(0).firstChild){data=xmlNode.item(0).firstChild.nodeValue;}
else{data="";}}
if(!field.parser&&field.converter){field.parser=field.converter;}
if(field.parser){data=field.parser.call(this,data);}
if(data===undefined){data=null;}
oResult[key]=data;}
oParsedResponse.results.unshift(oResult);}}
if(bError){oParsedResponse.error=true;}
else{}
return oParsedResponse;};YAHOO.util.DataSource.prototype.parseJSONData=function(oRequest,oRawResponse){var oParsedResponse={};if(oRawResponse&&YAHOO.lang.isArray(this.responseSchema.fields)){var fields=this.responseSchema.fields;var bError=false;oParsedResponse.results=[];var jsonObj,jsonList;if(YAHOO.lang.isString(oRawResponse)){var isNotMac=(navigator.userAgent.toLowerCase().indexOf('khtml')==-1);if(oRawResponse.parseJSON&&isNotMac){jsonObj=oRawResponse.parseJSON();if(!jsonObj){bError=true;}}
else if(window.JSON&&JSON.parse&&isNotMac){jsonObj=JSON.parse(oRawResponse);if(!jsonObj){bError=true;}}
else{try{while(oRawResponse.length>0&&(oRawResponse.charAt(0)!="{")&&(oRawResponse.charAt(0)!="[")){oRawResponse=oRawResponse.substring(1,oRawResponse.length);}
if(oRawResponse.length>0){var objEnd=Math.max(oRawResponse.lastIndexOf("]"),oRawResponse.lastIndexOf("}"));oRawResponse=oRawResponse.substring(0,objEnd+1);jsonObj=eval("("+oRawResponse+")");if(!jsonObj){bError=true;}}
else{jsonObj=null;bError=true;}}
catch(e){bError=true;}}}
else if(oRawResponse.constructor==Object){jsonObj=oRawResponse;}
else{bError=true;}
if(jsonObj&&jsonObj.constructor==Object){try{jsonList=eval("jsonObj."+this.responseSchema.resultsList);}
catch(e){bError=true;}}
if(bError||!jsonList){oParsedResponse.error=true;}
if(jsonList&&!YAHOO.lang.isArray(jsonList)){jsonList=[jsonList];}
else if(!jsonList){jsonList=[];}
for(var i=jsonList.length-1;i>=0;i--){var oResult={};var jsonResult=jsonList[i];for(var j=fields.length-1;j>=0;j--){var field=fields[j];var key=(YAHOO.lang.isValue(field.key))?field.key:field;var data=eval("jsonResult."+key);if(!field.parser&&field.converter){field.parser=field.converter;}
if(field.parser){data=field.parser.call(this,data);}
if(data===undefined){data=null;}
oResult[key]=data;}
oParsedResponse.results.unshift(oResult);}}
else{oParsedResponse.error=true;}
return oParsedResponse;};YAHOO.util.DataSource.prototype.parseHTMLTableData=function(oRequest,oRawResponse){var bError=false;var elTable=oRawResponse;var fields=this.responseSchema.fields;var oParsedResponse={};oParsedResponse.results=[];for(var i=0;i<elTable.tBodies.length;i++){var elTbody=elTable.tBodies[i];for(var j=elTbody.rows.length-1;j>-1;j--){var elRow=elTbody.rows[j];var oResult={};for(var k=fields.length-1;k>-1;k--){var field=fields[k];var key=(YAHOO.lang.isValue(field.key))?field.key:field;var data=elRow.cells[k].innerHTML;if(!field.parser&&field.converter){field.parser=field.converter;}
if(field.parser){data=field.parser.call(this,data);}
if(data===undefined){data=null;}
oResult[key]=data;}
oParsedResponse.results.unshift(oResult);}}
if(bError){oParsedResponse.error=true;}
else{}
return oParsedResponse;};YAHOO.register("datasource",YAHOO.util.DataSource,{version:"2.3.0",build:"442"});/*
Copyright (c) 2007, Yahoo! Inc. All rights reserved.
Code licensed under the BSD License:
http://developer.yahoo.net/yui/license.txt
version: 2.3.0
*/

(function(){YAHOO.widget.TabView=function(el,attr){attr=attr||{};if(arguments.length==1&&!YAHOO.lang.isString(el)&&!el.nodeName){attr=el;el=attr.element||null;}
if(!el&&!attr.element){el=_createTabViewElement.call(this,attr);}
YAHOO.widget.TabView.superclass.constructor.call(this,el,attr);};YAHOO.extend(YAHOO.widget.TabView,YAHOO.util.Element);var proto=YAHOO.widget.TabView.prototype;var Dom=YAHOO.util.Dom;var Event=YAHOO.util.Event;var Tab=YAHOO.widget.Tab;proto.CLASSNAME='yui-navset';proto.TAB_PARENT_CLASSNAME='yui-nav';proto.CONTENT_PARENT_CLASSNAME='yui-content';proto._tabParent=null;proto._contentParent=null;proto.addTab=function(tab,index){var tabs=this.get('tabs');if(!tabs){this._queue[this._queue.length]=['addTab',arguments];return false;}
index=(index===undefined)?tabs.length:index;var before=this.getTab(index);var self=this;var el=this.get('element');var tabParent=this._tabParent;var contentParent=this._contentParent;var tabElement=tab.get('element');var contentEl=tab.get('contentEl');if(before){tabParent.insertBefore(tabElement,before.get('element'));}else{tabParent.appendChild(tabElement);}
if(contentEl&&!Dom.isAncestor(contentParent,contentEl)){contentParent.appendChild(contentEl);}
if(!tab.get('active')){tab.set('contentVisible',false,true);}else{this.set('activeTab',tab,true);}
var activate=function(e){YAHOO.util.Event.preventDefault(e);var silent=false;if(this==self.get('activeTab')){silent=true;}
self.set('activeTab',this,silent);};tab.addListener(tab.get('activationEvent'),activate);tab.addListener('activationEventChange',function(e){if(e.prevValue!=e.newValue){tab.removeListener(e.prevValue,activate);tab.addListener(e.newValue,activate);}});tabs.splice(index,0,tab);};proto.DOMEventHandler=function(e){var el=this.get('element');var target=YAHOO.util.Event.getTarget(e);var tabParent=this._tabParent;if(Dom.isAncestor(tabParent,target)){var tabEl;var tab=null;var contentEl;var tabs=this.get('tabs');for(var i=0,len=tabs.length;i<len;i++){tabEl=tabs[i].get('element');contentEl=tabs[i].get('contentEl');if(target==tabEl||Dom.isAncestor(tabEl,target)){tab=tabs[i];break;}}
if(tab){tab.fireEvent(e.type,e);}}};proto.getTab=function(index){return this.get('tabs')[index];};proto.getTabIndex=function(tab){var index=null;var tabs=this.get('tabs');for(var i=0,len=tabs.length;i<len;++i){if(tab==tabs[i]){index=i;break;}}
return index;};proto.removeTab=function(tab){var tabCount=this.get('tabs').length;var index=this.getTabIndex(tab);var nextIndex=index+1;if(tab==this.get('activeTab')){if(tabCount>1){if(index+1==tabCount){this.set('activeIndex',index-1);}else{this.set('activeIndex',index+1);}}}
this._tabParent.removeChild(tab.get('element'));this._contentParent.removeChild(tab.get('contentEl'));this._configs.tabs.value.splice(index,1);};proto.toString=function(){var name=this.get('id')||this.get('tagName');return"TabView "+name;};proto.contentTransition=function(newTab,oldTab){newTab.set('contentVisible',true);oldTab.set('contentVisible',false);};proto.initAttributes=function(attr){YAHOO.widget.TabView.superclass.initAttributes.call(this,attr);if(!attr.orientation){attr.orientation='top';}
var el=this.get('element');if(!YAHOO.util.Dom.hasClass(el,this.CLASSNAME)){YAHOO.util.Dom.addClass(el,this.CLASSNAME);}
this.setAttributeConfig('tabs',{value:[],readOnly:true});this._tabParent=this.getElementsByClassName(this.TAB_PARENT_CLASSNAME,'ul')[0]||_createTabParent.call(this);this._contentParent=this.getElementsByClassName(this.CONTENT_PARENT_CLASSNAME,'div')[0]||_createContentParent.call(this);this.setAttributeConfig('orientation',{value:attr.orientation,method:function(value){var current=this.get('orientation');this.addClass('yui-navset-'+value);if(current!=value){this.removeClass('yui-navset-'+current);}
switch(value){case'bottom':this.appendChild(this._tabParent);break;}}});this.setAttributeConfig('activeIndex',{value:attr.activeIndex,method:function(value){this.set('activeTab',this.getTab(value));},validator:function(value){return!this.getTab(value).get('disabled');}});this.setAttributeConfig('activeTab',{value:attr.activeTab,method:function(tab){var activeTab=this.get('activeTab');if(tab){tab.set('active',true);this._configs['activeIndex'].value=this.getTabIndex(tab);}
if(activeTab&&activeTab!=tab){activeTab.set('active',false);}
if(activeTab&&tab!=activeTab){this.contentTransition(tab,activeTab);}else if(tab){tab.set('contentVisible',true);}},validator:function(value){return!value.get('disabled');}});if(this._tabParent){_initTabs.call(this);}
this.DOM_EVENTS.submit=false;this.DOM_EVENTS.focus=false;this.DOM_EVENTS.blur=false;for(var type in this.DOM_EVENTS){if(YAHOO.lang.hasOwnProperty(this.DOM_EVENTS,type)){this.addListener.call(this,type,this.DOMEventHandler);}}};var _initTabs=function(){var tab,attr,contentEl;var el=this.get('element');var tabs=_getChildNodes(this._tabParent);var contentElements=_getChildNodes(this._contentParent);for(var i=0,len=tabs.length;i<len;++i){attr={};if(contentElements[i]){attr.contentEl=contentElements[i];}
tab=new YAHOO.widget.Tab(tabs[i],attr);this.addTab(tab);if(tab.hasClass(tab.ACTIVE_CLASSNAME)){this._configs.activeTab.value=tab;this._configs.activeIndex.value=this.getTabIndex(tab);}}};var _createTabViewElement=function(attr){var el=document.createElement('div');if(this.CLASSNAME){el.className=this.CLASSNAME;}
return el;};var _createTabParent=function(attr){var el=document.createElement('ul');if(this.TAB_PARENT_CLASSNAME){el.className=this.TAB_PARENT_CLASSNAME;}
this.get('element').appendChild(el);return el;};var _createContentParent=function(attr){var el=document.createElement('div');if(this.CONTENT_PARENT_CLASSNAME){el.className=this.CONTENT_PARENT_CLASSNAME;}
this.get('element').appendChild(el);return el;};var _getChildNodes=function(el){var nodes=[];var childNodes=el.childNodes;for(var i=0,len=childNodes.length;i<len;++i){if(childNodes[i].nodeType==1){nodes[nodes.length]=childNodes[i];}}
return nodes;};})();(function(){var Dom=YAHOO.util.Dom,Event=YAHOO.util.Event;var Tab=function(el,attr){attr=attr||{};if(arguments.length==1&&!YAHOO.lang.isString(el)&&!el.nodeName){attr=el;el=attr.element;}
if(!el&&!attr.element){el=_createTabElement.call(this,attr);}
this.loadHandler={success:function(o){this.set('content',o.responseText);},failure:function(o){}};Tab.superclass.constructor.call(this,el,attr);this.DOM_EVENTS={};};YAHOO.extend(Tab,YAHOO.util.Element);var proto=Tab.prototype;proto.LABEL_TAGNAME='em';proto.ACTIVE_CLASSNAME='selected';proto.DISABLED_CLASSNAME='disabled';proto.LOADING_CLASSNAME='loading';proto.dataConnection=null;proto.loadHandler=null;proto._loading=false;proto.toString=function(){var el=this.get('element');var id=el.id||el.tagName;return"Tab "+id;};proto.initAttributes=function(attr){attr=attr||{};Tab.superclass.initAttributes.call(this,attr);var el=this.get('element');this.setAttributeConfig('activationEvent',{value:attr.activationEvent||'click'});this.setAttributeConfig('labelEl',{value:attr.labelEl||_getlabelEl.call(this),method:function(value){var current=this.get('labelEl');if(current){if(current==value){return false;}
this.replaceChild(value,current);}else if(el.firstChild){this.insertBefore(value,el.firstChild);}else{this.appendChild(value);}}});this.setAttributeConfig('label',{value:attr.label||_getLabel.call(this),method:function(value){var labelEl=this.get('labelEl');if(!labelEl){this.set('labelEl',_createlabelEl.call(this));}
_setLabel.call(this,value);}});this.setAttributeConfig('contentEl',{value:attr.contentEl||document.createElement('div'),method:function(value){var current=this.get('contentEl');if(current){if(current==value){return false;}
this.replaceChild(value,current);}}});this.setAttributeConfig('content',{value:attr.content,method:function(value){this.get('contentEl').innerHTML=value;}});var _dataLoaded=false;this.setAttributeConfig('dataSrc',{value:attr.dataSrc});this.setAttributeConfig('cacheData',{value:attr.cacheData||false,validator:YAHOO.lang.isBoolean});this.setAttributeConfig('loadMethod',{value:attr.loadMethod||'GET',validator:YAHOO.lang.isString});this.setAttributeConfig('dataLoaded',{value:false,validator:YAHOO.lang.isBoolean,writeOnce:true});this.setAttributeConfig('dataTimeout',{value:attr.dataTimeout||null,validator:YAHOO.lang.isNumber});this.setAttributeConfig('active',{value:attr.active||this.hasClass(this.ACTIVE_CLASSNAME),method:function(value){if(value===true){this.addClass(this.ACTIVE_CLASSNAME);this.set('title','active');}else{this.removeClass(this.ACTIVE_CLASSNAME);this.set('title','');}},validator:function(value){return YAHOO.lang.isBoolean(value)&&!this.get('disabled');}});this.setAttributeConfig('disabled',{value:attr.disabled||this.hasClass(this.DISABLED_CLASSNAME),method:function(value){if(value===true){Dom.addClass(this.get('element'),this.DISABLED_CLASSNAME);}else{Dom.removeClass(this.get('element'),this.DISABLED_CLASSNAME);}},validator:YAHOO.lang.isBoolean});this.setAttributeConfig('href',{value:attr.href||this.getElementsByTagName('a')[0].getAttribute('href',2)||'#',method:function(value){this.getElementsByTagName('a')[0].href=value;},validator:YAHOO.lang.isString});this.setAttributeConfig('contentVisible',{value:attr.contentVisible,method:function(value){if(value){this.get('contentEl').style.display='block';if(this.get('dataSrc')){if(!this._loading&&!(this.get('dataLoaded')&&this.get('cacheData'))){_dataConnect.call(this);}}}else{this.get('contentEl').style.display='none';}},validator:YAHOO.lang.isBoolean});};var _createTabElement=function(attr){var el=document.createElement('li');var a=document.createElement('a');a.href=attr.href||'#';el.appendChild(a);var label=attr.label||null;var labelEl=attr.labelEl||null;if(labelEl){if(!label){label=_getLabel.call(this,labelEl);}}else{labelEl=_createlabelEl.call(this);}
a.appendChild(labelEl);return el;};var _getlabelEl=function(){return this.getElementsByTagName(this.LABEL_TAGNAME)[0];};var _createlabelEl=function(){var el=document.createElement(this.LABEL_TAGNAME);return el;};var _setLabel=function(label){var el=this.get('labelEl');el.innerHTML=label;};var _getLabel=function(){var label,el=this.get('labelEl');if(!el){return undefined;}
return el.innerHTML;};var _dataConnect=function(){if(!YAHOO.util.Connect){return false;}
Dom.addClass(this.get('contentEl').parentNode,this.LOADING_CLASSNAME);this._loading=true;this.dataConnection=YAHOO.util.Connect.asyncRequest(this.get('loadMethod'),this.get('dataSrc'),{success:function(o){this.loadHandler.success.call(this,o);this.set('dataLoaded',true);this.dataConnection=null;Dom.removeClass(this.get('contentEl').parentNode,this.LOADING_CLASSNAME);this._loading=false;},failure:function(o){this.loadHandler.failure.call(this,o);this.dataConnection=null;Dom.removeClass(this.get('contentEl').parentNode,this.LOADING_CLASSNAME);this._loading=false;},scope:this,timeout:this.get('dataTimeout')});};YAHOO.widget.Tab=Tab;})();YAHOO.register("tabview",YAHOO.widget.TabView,{version:"2.3.0",build:"442"});/*
Copyright (c) 2007, Yahoo! Inc. All rights reserved.
Code licensed under the BSD License:
http://developer.yahoo.net/yui/license.txt
version: 2.3.0
*/
/**
 * The DataTable widget provides a progressively enhanced DHTML control for
 * displaying tabular data across A-grade browsers.
 *
 * @module datatable
 * @requires yahoo, dom, event, datasource
 * @optional dragdrop
 * @title DataTable Widget
 * @beta
 */

/****************************************************************************/
/****************************************************************************/
/****************************************************************************/

/**
 * DataTable class for the YUI DataTable widget.
 *
 * @namespace YAHOO.widget
 * @class DataTable
 * @uses YAHOO.util.EventProvider
 * @constructor
 * @param elContainer {HTMLElement} Container element for the TABLE.
 * @param aColumnDefs {Object[]} Array of object literal Column definitions.
 * @param oDataSource {YAHOO.util.DataSource} DataSource instance.
 * @param oConfigs {object} (optional) Object literal of configuration values.
 */
YAHOO.widget.DataTable = function(elContainer,aColumnDefs,oDataSource,oConfigs) {
    // Internal vars
    this._nIndex = YAHOO.widget.DataTable._nCount;
    this._sName = "instance" + this._nIndex;
    this.id = "yui-dt"+this._nIndex;

    // Initialize container element
    this._initContainerEl(elContainer);
    if(!this._elContainer) {
        return;
    }

    // Initialize configs
    this._initConfigs(oConfigs);

    // Initialize ColumnSet
    this._initColumnSet(aColumnDefs);
    if(!this._oColumnSet) {
        return;
    }
    
    // Initialize RecordSet
    this._initRecordSet();
    if(!this._oRecordSet) {
        return;
    }

    // Initialize DataSource
    this._initDataSource(oDataSource);
    if(!this._oDataSource) {
        return;
    }

    // Progressive enhancement special case
    if(this._oDataSource.dataType == YAHOO.util.DataSource.TYPE_HTMLTABLE) {
        this._oDataSource.sendRequest(this.get("initialRequest"), this._onDataReturnEnhanceTable, this);
    }
    else {
        // Initialize DOM elements
        this._initTableEl();
        if(!this._elTable || !this._elThead || !this._elTbody) {
            return;
        }

        // Call Element's constructor after DOM elements are created
        // but *before* table is populated with data
        YAHOO.widget.DataTable.superclass.constructor.call(this, this._elContainer, this._oConfigs);
        
        //HACK: Set the Paginator values here via updatePaginator
        if(this._oConfigs && this._oConfigs.paginator) {
            this.updatePaginator(this._oConfigs.paginator);
        }

        // Send out for data in an asynchronous request
        this._oDataSource.sendRequest(this.get("initialRequest"), this.onDataReturnInitializeTable, this);
    }

    // Initialize inline Cell editing
    this._initCellEditorEl();

    // Initialize Column sort
    this._initColumnSort();

    // Initialize DOM event listeners
    this._initDomEvents();

    YAHOO.widget.DataTable._nCount++;
};

if(YAHOO.util.Element) {
    YAHOO.lang.extend(YAHOO.widget.DataTable, YAHOO.util.Element);
}
else {
}

/////////////////////////////////////////////////////////////////////////////
//
// Superclass methods
//
/////////////////////////////////////////////////////////////////////////////

/**
 * Implementation of Element's abstract method. Sets up config values.
 *
 * @method initAttributes
 * @param oConfigs {Object} (Optional) Object literal definition of configuration values.
 * @private
 */

YAHOO.widget.DataTable.prototype.initAttributes = function(oConfigs) {
    oConfigs = oConfigs || {};
    YAHOO.widget.DataTable.superclass.initAttributes.call(this, oConfigs);

    /**
    * @config summary
    * @description Value for the SUMMARY attribute.
    * @type String
    */
    this.setAttributeConfig("summary", {
        value: null,
        validator: YAHOO.lang.isString,
        method: function(sSummary) {
            this._elTable.summary = sSummary;
        }
    });

    /**
    * @config selectionMode
    * @description Specifies row or cell selection mode. Accepts the following strings:
    *    <dl>
    *      <dt>"standard"</dt>
    *      <dd>Standard row selection with support for modifier keys to enable
    *      multiple selections.</dd>
    *
    *      <dt>"single"</dt>
    *      <dd>Row selection with modifier keys disabled to not allow
    *      multiple selections.</dd>
    *
    *      <dt>"singlecell"</dt>
    *      <dd>Cell selection with modifier keys disabled to not allow
    *      multiple selections.</dd>
    *
    *      <dt>"cellblock"</dt>
    *      <dd>Cell selection with support for modifier keys to enable multiple
    *      selections in a block-fashion, like a spreadsheet.</dd>
    *
    *      <dt>"cellrange"</dt>
    *      <dd>Cell selection with support for modifier keys to enable multiple
    *      selections in a range-fashion, like a calendar.</dd>
    *    </dl>
    *
    * @default "standard"
    * @type String
    */
    this.setAttributeConfig("selectionMode", {
        value: "standard",
        validator: YAHOO.lang.isString
    });

    /**
    * @config initialRequest
    * @description Defines the initial request that gets sent to the DataSource.
    * @type String
    */
    this.setAttributeConfig("initialRequest", {
        value: "",
        validator: YAHOO.lang.isString
    });

    /**
    * @config sortedBy
    * @description Object literal provides metadata for initial sort values if
    * data will arrive pre-sorted:
    * <dl>
    *     <dt>sortedBy.key</dt>
    *     <dd>Key of sorted Column</dd>
    *     <dt>sortedBy.dir</dt>
    *     <dd>Initial sort direction, either "asc" or "desc"</dd>
    * </dl>
    * @type Object
    */
    this.setAttributeConfig("sortedBy", {
        value: null,
        // TODO: accepted array for nested sorts
        validator: function(oNewSortedBy) {
            return (oNewSortedBy && (oNewSortedBy.constructor == Object) && oNewSortedBy.key);
        },
        method: function(oNewSortedBy) {
            // Remove ASC/DESC from TH
            var oOldSortedBy = this.get("sortedBy");
            if(oOldSortedBy && (oOldSortedBy.constructor == Object) && oOldSortedBy.key) {
                var oldColumn = this._oColumnSet.getColumn(oOldSortedBy.key);
                var oldThEl = this.getThEl(oldColumn);
                YAHOO.util.Dom.removeClass(oldThEl, YAHOO.widget.DataTable.CLASS_ASC);
                YAHOO.util.Dom.removeClass(oldThEl, YAHOO.widget.DataTable.CLASS_DESC);
            }
            
            // Set ASC/DESC on TH
            var column = (oNewSortedBy.column) ? oNewSortedBy.column : this._oColumnSet.getColumn(oNewSortedBy.key);
            if(column) {
                var newClass = (oNewSortedBy.dir && (oNewSortedBy.dir != "asc")) ?
                        YAHOO.widget.DataTable.CLASS_DESC :
                        YAHOO.widget.DataTable.CLASS_ASC;
                YAHOO.util.Dom.addClass(this.id + "-col" + column.getId(), newClass);
            }
        }
    });

    /**
    * @config paginator
    * @description Object literal of pagination values.
    * @default <br>
    *   { containers:[], // UI container elements <br>
    *   rowsPerPage:500, // 500 rows <br>
    *   currentPage:1,  // page one <br>
    *   pageLinks:0,    // show all links <br>
    *   pageLinksStart:1, // first link is page 1 <br>
    *   dropdownOptions:null, // no dropdown <br>
    *   links: [], // links elements <br>
    *   dropdowns: [] } //dropdown elements
    * 
    * @type Object
    */
    this.setAttributeConfig("paginator", {
        value: {
            rowsPerPage:500, // 500 rows per page
            currentPage:1,  // show page one
            startRecordIndex:0, // start with first Record
            totalRecords:0, // how many Records total
            totalPages:0, // how many pages total
            rowsThisPage:0, // how many rows this page
            pageLinks:0,    // show all links
            pageLinksStart:1, // first link is page 1
            dropdownOptions: null, //no dropdown
            containers:[], // Paginator container element references
            dropdowns: [], //dropdown element references,
            links: [] // links elements
        },
        validator: function(oNewPaginator) {
            if(oNewPaginator && (oNewPaginator.constructor == Object)) {
                // Check for incomplete set of values
                if((oNewPaginator.rowsPerPage !== undefined) &&
                        (oNewPaginator.currentPage !== undefined) &&
                        (oNewPaginator.startRecordIndex !== undefined) &&
                        (oNewPaginator.totalRecords !== undefined) &&
                        (oNewPaginator.totalPages !== undefined) &&
                        (oNewPaginator.rowsThisPage !== undefined) &&
                        (oNewPaginator.pageLinks !== undefined) &&
                        (oNewPaginator.pageLinksStart !== undefined) &&
                        (oNewPaginator.dropdownOptions !== undefined) &&
                        (oNewPaginator.containers !== undefined) &&
                        (oNewPaginator.dropdowns !== undefined) &&
                        (oNewPaginator.links !== undefined)) {

                    // Validate each value
                    if(YAHOO.lang.isNumber(oNewPaginator.rowsPerPage) &&
                            YAHOO.lang.isNumber(oNewPaginator.currentPage) &&
                            YAHOO.lang.isNumber(oNewPaginator.startRecordIndex) &&
                            YAHOO.lang.isNumber(oNewPaginator.totalRecords) &&
                            YAHOO.lang.isNumber(oNewPaginator.totalPages) &&
                            YAHOO.lang.isNumber(oNewPaginator.rowsThisPage) &&
                            YAHOO.lang.isNumber(oNewPaginator.pageLinks) &&
                            YAHOO.lang.isNumber(oNewPaginator.pageLinksStart) &&
                            YAHOO.lang.isArray(oNewPaginator.dropdownOptions) &&
                            YAHOO.lang.isArray(oNewPaginator.containers) &&
                            YAHOO.lang.isArray(oNewPaginator.dropdowns) &&
                            YAHOO.lang.isArray(oNewPaginator.links)) {
                        return true;
                    }
                }
            }
            return false;
        }
    });

    /**
    * @config paginated
    * @description True if built-in client-side pagination is enabled
    * @default false
    * @type Boolean
    */
    this.setAttributeConfig("paginated", {
        value: false,
        validator: YAHOO.lang.isBoolean,
        method: function(oParam) {
            var oPaginator = this.get("paginator");
            var aContainerEls = oPaginator.containers;
            
            // Paginator is enabled
            if(oParam) {
                // No containers found, create two from scratch
                if(aContainerEls.length === 0) {
                    // One before TABLE
                    var pag0 = document.createElement("span");
                    pag0.id = this.id + "-paginator0";
                    YAHOO.util.Dom.addClass(pag0, YAHOO.widget.DataTable.CLASS_PAGINATOR);
                    pag0 = this._elContainer.insertBefore(pag0, this._elTable);
                    aContainerEls.push(pag0);

                    // One after TABLE
                    var pag1 = document.createElement("span");
                    pag1.id = this.id + "-paginator1";
                    YAHOO.util.Dom.addClass(pag1, YAHOO.widget.DataTable.CLASS_PAGINATOR);
                    pag1 = this._elContainer.insertBefore(pag1, this._elTable.nextSibling);
                    aContainerEls.push(pag1);

                    // Add containers directly to tracker
                    this._configs.paginator.value.containers = [pag0, pag1];

                }
                else {
                    // Show each container
                    for(var i=0; i<aContainerEls.length; i++) {
                        aContainerEls[i].style.display = "";
                    }
                }

                // Links are enabled
                if(oPaginator.pageLinks > -1) {
                    var aLinkEls = oPaginator.links;
                    // No links containers found, create from scratch
                    if(aLinkEls.length === 0) {
                        for(i=0; i<aContainerEls.length; i++) {
                            // Create one links container per Paginator container
                            var linkEl = document.createElement("span");
                            linkEl.id = "yui-dt-pagselect"+i;
                            linkEl = aContainerEls[i].appendChild(linkEl);

                            // Add event listener
                            //TODO: anon fnc
                            YAHOO.util.Event.addListener(linkEl,"click",this._onPaginatorLinkClick,this);

                             // Add directly to tracker
                            this._configs.paginator.value.links.push(linkEl);
                       }
                   }
                }

                // Show these options in the dropdown
                var dropdownOptions = oPaginator.dropdownOptions || [];

                for(i=0; i<aContainerEls.length; i++) {
                    // Create one SELECT element per Paginator container
                    var selectEl = document.createElement("select");
                    YAHOO.util.Dom.addClass(selectEl, YAHOO.widget.DataTable.CLASS_DROPDOWN);
                    selectEl = aContainerEls[i].appendChild(selectEl);
                    selectEl.id = "yui-dt-pagselect"+i;

                    // Add event listener
                    //TODO: anon fnc
                    YAHOO.util.Event.addListener(selectEl,"change",this._onPaginatorDropdownChange,this);

                    // Add DOM reference directly to tracker
                   this._configs.paginator.value.dropdowns.push(selectEl);

                    // Hide dropdown
                    if(!oPaginator.dropdownOptions) {
                        selectEl.style.display = "none";
                    }
                }

                //TODO: fire paginatorDisabledEvent & add to api doc
            }
            // Pagination is disabled
            else {
                // Containers found
                if(aContainerEls.length > 0) {
                    // Destroy or just hide?
                    
                    // Hide each container
                    for(i=0; i<aContainerEls.length; i++) {
                        aContainerEls[i].style.display = "none";
                    }

                    /*TODO?
                    // Destroy each container
                    for(i=0; i<aContainerEls.length; i++) {
                        YAHOO.util.Event.purgeElement(aContainerEls[i], true);
                        aContainerEls.innerHTML = null;
                        //TODO: remove container?
                        // aContainerEls[i].parentNode.removeChild(aContainerEls[i]);
                    }
                    */
                }
                //TODO: fire paginatorDisabledEvent & add to api doc
            }
        }
    });

    /**
    * @config caption
    * @description Value for the CAPTION element.
    * @type String
    */
    this.setAttributeConfig("caption", {
        value: null,
        validator: YAHOO.lang.isString,
        method: function(sCaption) {
            // Create CAPTION element
            if(!this._elCaption) {
                if(!this._elTable.firstChild) {
                    this._elCaption = this._elTable.appendChild(document.createElement("caption"));
                }
                else {
                    this._elCaption = this._elTable.insertBefore(document.createElement("caption"), this._elTable.firstChild);
                }
            }
            // Set CAPTION value
            this._elCaption.innerHTML = sCaption;
        }
    });

    /**
    * @config scrollable
    * @description True if primary TBODY should scroll while THEAD remains fixed.
    * When enabling this feature, captions cannot be used, and the following
    * features are not recommended: inline editing, resizeable columns.
    * @default false
    * @type Boolean
    */
    this.setAttributeConfig("scrollable", {
        value: false,
        validator: function(oParam) {
            //TODO: validate agnst resizeable
            return (YAHOO.lang.isBoolean(oParam) &&
                    // Not compatible with caption
                    !YAHOO.lang.isString(this.get("caption")));
        },
        method: function(oParam) {
            if(oParam) {
                //TODO: conf height
                YAHOO.util.Dom.addClass(this._elContainer,YAHOO.widget.DataTable.CLASS_SCROLLABLE);
                YAHOO.util.Dom.addClass(this._elTbody,YAHOO.widget.DataTable.CLASS_SCROLLBODY);
            }
            else {
                YAHOO.util.Dom.removeClass(this._elContainer,YAHOO.widget.DataTable.CLASS_SCROLLABLE);
                YAHOO.util.Dom.removeClass(this._elTbody,YAHOO.widget.DataTable.CLASS_SCROLLBODY);

            }
        }
    });
};

/////////////////////////////////////////////////////////////////////////////
//
// Public constants
//
/////////////////////////////////////////////////////////////////////////////

/**
 * Class name assigned to TABLE element.
 *
 * @property DataTable.CLASS_TABLE
 * @type String
 * @static
 * @final
 * @default "yui-dt-table"
 */
YAHOO.widget.DataTable.CLASS_TABLE = "yui-dt-table";

/**
 * Class name assigned to header container elements within each TH element.
 *
 * @property DataTable.CLASS_HEADER
 * @type String
 * @static
 * @final
 * @default "yui-dt-header"
 */
YAHOO.widget.DataTable.CLASS_HEADER = "yui-dt-header";

/**
 * Class name assigned to the primary TBODY element.
 *
 * @property DataTable.CLASS_BODY
 * @type String
 * @static
 * @final
 * @default "yui-dt-body"
 */
YAHOO.widget.DataTable.CLASS_BODY = "yui-dt-body";

/**
 * Class name assigned to the scrolling TBODY element of a fixed scrolling DataTable.
 *
 * @property DataTable.CLASS_SCROLLBODY
 * @type String
 * @static
 * @final
 * @default "yui-dt-scrollbody"
 */
YAHOO.widget.DataTable.CLASS_SCROLLBODY = "yui-dt-scrollbody";

/**
 * Class name assigned to display label elements.
 *
 * @property DataTable.CLASS_LABEL
 * @type String
 * @static
 * @final
 * @default "yui-dt-label"
 */
YAHOO.widget.DataTable.CLASS_LABEL = "yui-dt-label";

/**
 * Class name assigned to resizer handle elements.
 *
 * @property DataTable.CLASS_RESIZER
 * @type String
 * @static
 * @final
 * @default "yui-dt-resizer"
 */
YAHOO.widget.DataTable.CLASS_RESIZER = "yui-dt-resizer";

/**
 * Class name assigned to Editor container elements.
 *
 * @property DataTable.CLASS_EDITOR
 * @type String
 * @static
 * @final
 * @default "yui-dt-editor"
 */
YAHOO.widget.DataTable.CLASS_EDITOR = "yui-dt-editor";

/**
 * Class name assigned to paginator container elements.
 *
 * @property DataTable.CLASS_PAGINATOR
 * @type String
 * @static
 * @final
 * @default "yui-dt-paginator"
 */
YAHOO.widget.DataTable.CLASS_PAGINATOR = "yui-dt-paginator";

/**
 * Class name assigned to page number indicators.
 *
 * @property DataTable.CLASS_PAGE
 * @type String
 * @static
 * @final
 * @default "yui-dt-page"
 */
YAHOO.widget.DataTable.CLASS_PAGE = "yui-dt-page";

/**
 * Class name assigned to default indicators.
 *
 * @property DataTable.CLASS_DEFAULT
 * @type String
 * @static
 * @final
 * @default "yui-dt-default"
 */
YAHOO.widget.DataTable.CLASS_DEFAULT = "yui-dt-default";

/**
 * Class name assigned to previous indicators.
 *
 * @property DataTable.CLASS_PREVIOUS
 * @type String
 * @static
 * @final
 * @default "yui-dt-previous"
 */
YAHOO.widget.DataTable.CLASS_PREVIOUS = "yui-dt-previous";

/**
 * Class name assigned next indicators.
 *
 * @property DataTable.CLASS_NEXT
 * @type String
 * @static
 * @final
 * @default "yui-dt-next"
 */
YAHOO.widget.DataTable.CLASS_NEXT = "yui-dt-next";

/**
 * Class name assigned to first elements.
 *
 * @property DataTable.CLASS_FIRST
 * @type String
 * @static
 * @final
 * @default "yui-dt-first"
 */
YAHOO.widget.DataTable.CLASS_FIRST = "yui-dt-first";

/**
 * Class name assigned to last elements.
 *
 * @property DataTable.CLASS_LAST
 * @type String
 * @static
 * @final
 * @default "yui-dt-last"
 */
YAHOO.widget.DataTable.CLASS_LAST = "yui-dt-last";

/**
 * Class name assigned to even elements.
 *
 * @property DataTable.CLASS_EVEN
 * @type String
 * @static
 * @final
 * @default "yui-dt-even"
 */
YAHOO.widget.DataTable.CLASS_EVEN = "yui-dt-even";

/**
 * Class name assigned to odd elements.
 *
 * @property DataTable.CLASS_ODD
 * @type String
 * @static
 * @final
 * @default "yui-dt-odd"
 */
YAHOO.widget.DataTable.CLASS_ODD = "yui-dt-odd";

/**
 * Class name assigned to selected elements.
 *
 * @property DataTable.CLASS_SELECTED
 * @type String
 * @static
 * @final
 * @default "yui-dt-selected"
 */
YAHOO.widget.DataTable.CLASS_SELECTED = "yui-dt-selected";

/**
 * Class name assigned to highlighted elements.
 *
 * @property DataTable.CLASS_HIGHLIGHTED
 * @type String
 * @static
 * @final
 * @default "yui-dt-highlighted"
 */
YAHOO.widget.DataTable.CLASS_HIGHLIGHTED = "yui-dt-highlighted";

/**
 * Class name assigned to disabled elements.
 *
 * @property DataTable.CLASS_DISABLED
 * @type String
 * @static
 * @final
 * @default "yui-dt-disabled"
 */
YAHOO.widget.DataTable.CLASS_DISABLED = "yui-dt-disabled";

/**
 * Class name assigned to empty indicators.
 *
 * @property DataTable.CLASS_EMPTY
 * @type String
 * @static
 * @final
 * @default "yui-dt-empty"
 */
YAHOO.widget.DataTable.CLASS_EMPTY = "yui-dt-empty";

/**
 * Class name assigned to loading indicatorx.
 *
 * @property DataTable.CLASS_LOADING
 * @type String
 * @static
 * @final
 * @default "yui-dt-loading"
 */
YAHOO.widget.DataTable.CLASS_LOADING = "yui-dt-loading";

/**
 * Class name assigned to error indicators.
 *
 * @property DataTable.CLASS_ERROR
 * @type String
 * @static
 * @final
 * @default "yui-dt-error"
 */
YAHOO.widget.DataTable.CLASS_ERROR = "yui-dt-error";

/**
 * Class name assigned to editable elements.
 *
 * @property DataTable.CLASS_EDITABLE
 * @type String
 * @static
 * @final
 * @default "yui-dt-editable"
 */
YAHOO.widget.DataTable.CLASS_EDITABLE = "yui-dt-editable";

/**
 * Class name assigned to scrollable elements.
 *
 * @property DataTable.CLASS_SCROLLABLE
 * @type String
 * @static
 * @final
 * @default "yui-dt-scrollable"
 */
YAHOO.widget.DataTable.CLASS_SCROLLABLE = "yui-dt-scrollable";

/**
 * Class name assigned to sortable elements.
 *
 * @property DataTable.CLASS_SORTABLE
 * @type String
 * @static
 * @final
 * @default "yui-dt-sortable"
 */
YAHOO.widget.DataTable.CLASS_SORTABLE = "yui-dt-sortable";

/**
 * Class name assigned to ascending elements.
 *
 * @property DataTable.CLASS_ASC
 * @type String
 * @static
 * @final
 * @default "yui-dt-asc"
 */
YAHOO.widget.DataTable.CLASS_ASC = "yui-dt-asc";

/**
 * Class name assigned to descending elements.
 *
 * @property DataTable.CLASS_DESC
 * @type String
 * @static
 * @final
 * @default "yui-dt-desc"
 */
YAHOO.widget.DataTable.CLASS_DESC = "yui-dt-desc";

/**
 * Class name assigned to BUTTON container elements.
 *
 * @property DataTable.CLASS_BUTTON
 * @type String
 * @static
 * @final
 * @default "yui-dt-button"
 */
YAHOO.widget.DataTable.CLASS_BUTTON = "yui-dt-button";

/**
 * Class name assigned to SELECT container elements.
 *
 * @property DataTable.CLASS_DROPDOWN
 * @type String
 * @static
 * @final
 * @default "yui-dt-dropdown"
 */
YAHOO.widget.DataTable.CLASS_DROPDOWN = "yui-dt-dropdown";

/**
 * Class name assigned to INPUT TYPE=CHECKBOX container elements.
 *
 * @property DataTable.CLASS_CHECKBOX
 * @type String
 * @static
 * @final
 * @default "yui-dt-checkbox"
 */
YAHOO.widget.DataTable.CLASS_CHECKBOX = "yui-dt-checkbox";

/**
 * Message to display if DataTable has no data.
 *
 * @property DataTable.MSG_EMPTY
 * @type String
 * @static
 * @final
 * @default "No records found."
 */
YAHOO.widget.DataTable.MSG_EMPTY = "No records found.";

/**
 * Message to display while DataTable is loading data.
 *
 * @property DataTable.MSG_LOADING
 * @type String
 * @static
 * @final
 * @default "Loading data..."
 */
YAHOO.widget.DataTable.MSG_LOADING = "Loading data...";

/**
 * Message to display while DataTable has data error.
 *
 * @property DataTable.MSG_ERROR
 * @type String
 * @static
 * @final
 * @default "Data error."
 */
YAHOO.widget.DataTable.MSG_ERROR = "Data error.";

/////////////////////////////////////////////////////////////////////////////
//
// Private member variables
//
/////////////////////////////////////////////////////////////////////////////

/**
 * Internal class variable for indexing multiple DataTable instances.
 *
 * @property DataTable._nCount
 * @type Number
 * @private
 * @static
 */
YAHOO.widget.DataTable._nCount = 0;

/**
 * Index assigned to instance.
 *
 * @property _nIndex
 * @type Number
 * @private
 */
YAHOO.widget.DataTable.prototype._nIndex = null;

/**
 * Counter for IDs assigned to TR elements.
 *
 * @property _nTrCount
 * @type Number
 * @private
 */
YAHOO.widget.DataTable.prototype._nTrCount = 0;

/**
 * Unique name assigned to instance.
 *
 * @property _sName
 * @type String
 * @private
 */
YAHOO.widget.DataTable.prototype._sName = null;

/**
 * DOM reference to the container element for the DataTable instance into which
 * the TABLE element gets created.
 *
 * @property _elContainer
 * @type HTMLElement
 * @private
 */
YAHOO.widget.DataTable.prototype._elContainer = null;

/**
 * DOM reference to the CAPTION element for the DataTable instance.
 *
 * @property _elCaption
 * @type HTMLElement
 * @private
 */
YAHOO.widget.DataTable.prototype._elCaption = null;

/**
 * DOM reference to the TABLE element for the DataTable instance.
 *
 * @property _elTable
 * @type HTMLElement
 * @private
 */
YAHOO.widget.DataTable.prototype._elTable = null;

/**
 * DOM reference to the THEAD element for the DataTable instance.
 *
 * @property _elThead
 * @type HTMLElement
 * @private
 */
YAHOO.widget.DataTable.prototype._elThead = null;

/**
 * DOM reference to the primary TBODY element for the DataTable instance.
 *
 * @property _elTbody
 * @type HTMLElement
 * @private
 */
YAHOO.widget.DataTable.prototype._elTbody = null;

/**
 * DOM reference to the secondary TBODY element used to display DataTable messages.
 *
 * @property _elMsgTbody
 * @type HTMLElement
 * @private
 */
YAHOO.widget.DataTable.prototype._elMsgTbody = null;

/**
 * DOM reference to the secondary TBODY element's single TR element used to display DataTable messages.
 *
 * @property _elMsgTbodyRow
 * @type HTMLElement
 * @private
 */
YAHOO.widget.DataTable.prototype._elMsgTbodyRow = null;

/**
 * DOM reference to the secondary TBODY element's single TD element used to display DataTable messages.
 *
 * @property _elMsgTbodyCell
 * @type HTMLElement
 * @private
 */
YAHOO.widget.DataTable.prototype._elMsgTbodyCell = null;

/**
 * DataSource instance for the DataTable instance.
 *
 * @property _oDataSource
 * @type YAHOO.util.DataSource
 * @private
 */
YAHOO.widget.DataTable.prototype._oDataSource = null;

/**
 * ColumnSet instance for the DataTable instance.
 *
 * @property _oColumnSet
 * @type YAHOO.widget.ColumnSet
 * @private
 */
YAHOO.widget.DataTable.prototype._oColumnSet = null;

/**
 * RecordSet instance for the DataTable instance.
 *
 * @property _oRecordSet
 * @type YAHOO.widget.RecordSet
 * @private
 */
YAHOO.widget.DataTable.prototype._oRecordSet = null;

/**
 * ID string of first label link element of the current DataTable page, if any.
 * Used for focusing sortable Columns with TAB.
 *
 * @property _sFirstLabelLinkId
 * @type String
 * @private
 */
YAHOO.widget.DataTable.prototype._sFirstLabelLinkId = null;

/**
 * ID string of first TR element of the current DataTable page.
 *
 * @property _sFirstTrId
 * @type String
 * @private
 */
YAHOO.widget.DataTable.prototype._sFirstTrId = null;

/**
 * ID string of the last TR element of the current DataTable page.
 *
 * @property _sLastTrId
 * @type String
 * @private
 */
YAHOO.widget.DataTable.prototype._sLastTrId = null;
































/////////////////////////////////////////////////////////////////////////////
//
// Private methods
//
/////////////////////////////////////////////////////////////////////////////

/**
 * Sets focus on the given element.
 *
 * @method _focusEl
 * @param el {HTMLElement} Element.
 * @private
 */
YAHOO.widget.DataTable.prototype._focusEl = function(el) {
    el = el || this._elTable;
    // http://developer.mozilla.org/en/docs/index.php?title=Key-navigable_custom_DHTML_widgets
    // The timeout is necessary in both IE and Firefox 1.5, to prevent scripts from doing
    // strange unexpected things as the user clicks on buttons and other controls.
    setTimeout(function() { el.focus(); },0);
};





// INIT FUNCTIONS

/**
 * Initializes container element.
 *
 * @method _initContainerEl
 * @param elContainer {HTMLElement | String} HTML DIV element by reference or ID.
 * @private
 */
YAHOO.widget.DataTable.prototype._initContainerEl = function(elContainer) {
    this._elContainer = null;
    elContainer = YAHOO.util.Dom.get(elContainer);
    if(elContainer && elContainer.tagName && (elContainer.tagName.toLowerCase() == "div")) {
        this._elContainer = elContainer;
    }
};

/**
 * Initializes object literal of config values.
 *
 * @method _initConfigs
 * @param oConfig {Object} Object literal of config values.
 * @private
 */
YAHOO.widget.DataTable.prototype._initConfigs = function(oConfigs) {
    if(oConfigs) {
        if(oConfigs.constructor != Object) {
            oConfigs = null;
        }
        // Backward compatibility
        else if(YAHOO.lang.isBoolean(oConfigs.paginator)) {
        }
        this._oConfigs = oConfigs;
    }
};

/**
 * Initializes ColumnSet.
 *
 * @method _initColumnSet
 * @param aColumnDefs {Object[]} Array of object literal Column definitions.
 * @private
 */
YAHOO.widget.DataTable.prototype._initColumnSet = function(aColumnDefs) {
    this._oColumnSet = null;
    if(YAHOO.lang.isArray(aColumnDefs)) {
        this._oColumnSet =  new YAHOO.widget.ColumnSet(aColumnDefs);
    }
    // Backward compatibility
    else if(aColumnDefs instanceof YAHOO.widget.ColumnSet) {
        this._oColumnSet =  aColumnDefs;
    }
};

/**
 * Initializes DataSource.
 *
 * @method _initDataSource
 * @param oDataSource {YAHOO.util.DataSource} DataSource instance.
 * @private
 */
YAHOO.widget.DataTable.prototype._initDataSource = function(oDataSource) {
    this._oDataSource = null;
    if(oDataSource && (oDataSource instanceof YAHOO.util.DataSource)) {
        this._oDataSource = oDataSource;
    }
    // Backward compatibility
    else {
        var tmpTable = null;
        var tmpContainer = this._elContainer;
        // Peek in container child nodes to see if TABLE already exists
        if(tmpContainer.hasChildNodes()) {
            var tmpChildren = tmpContainer.childNodes;
            for(i=0; i<tmpChildren.length; i++) {
                if(tmpChildren[i].tagName && tmpChildren[i].tagName.toLowerCase() == "table") {
                    tmpTable = tmpChildren[i];
                    break;
                }
            }
            if(tmpTable) {
                var tmpFieldsArray = [];
                for(i=0; i<this._oColumnSet.keys.length; i++) {
                    tmpFieldsArray.push({key:this._oColumnSet.keys[i].key});
                }

                this._oDataSource = new YAHOO.util.DataSource(tmpTable);
                this._oDataSource.responseType = YAHOO.util.DataSource.TYPE_HTMLTABLE;
                this._oDataSource.responseSchema = {fields: tmpFieldsArray};
            }
        }
    }
};

/**
 * Initializes RecordSet.
 *
 * @method _initRecordSet
 * @private
 */
YAHOO.widget.DataTable.prototype._initRecordSet = function() {
    if(this._oRecordSet) {
        this._oRecordSet.reset();
    }
    else {
        this._oRecordSet = new YAHOO.widget.RecordSet();
    }
};

/**
 * Creates HTML markup for TABLE, THEAD and TBODY elements.
 *
 * @method _initTableEl
 * @private
 */
YAHOO.widget.DataTable.prototype._initTableEl = function() {
    // Clear the container
    YAHOO.util.Event.purgeElement(this._elContainer, true);
    this._elContainer.innerHTML = "";

    // Create TABLE
    this._elTable = this._elContainer.appendChild(document.createElement("table"));
    var elTable = this._elTable;
    elTable.tabIndex = 0;
    elTable.id = this.id + "-table";
    YAHOO.util.Dom.addClass(elTable, YAHOO.widget.DataTable.CLASS_TABLE);

    // Create THEAD
    this._initTheadEl(elTable, this._oColumnSet);


    // Create TBODY for messages
    var elMsgTbody = document.createElement("tbody");
    var elMsgRow = elMsgTbody.appendChild(document.createElement("tr"));
    YAHOO.util.Dom.addClass(elMsgRow,YAHOO.widget.DataTable.CLASS_FIRST);
    YAHOO.util.Dom.addClass(elMsgRow,YAHOO.widget.DataTable.CLASS_LAST);
    this._elMsgRow = elMsgRow;
    var elMsgCell = elMsgRow.appendChild(document.createElement("td"));
    elMsgCell.colSpan = this._oColumnSet.keys.length;
    YAHOO.util.Dom.addClass(elMsgCell,YAHOO.widget.DataTable.CLASS_FIRST);
    YAHOO.util.Dom.addClass(elMsgCell,YAHOO.widget.DataTable.CLASS_LAST);
    this._elMsgTd = elMsgCell;
    this._elMsgTbody = elTable.appendChild(elMsgTbody);
    this.showTableMessage(YAHOO.widget.DataTable.MSG_LOADING, YAHOO.widget.DataTable.CLASS_LOADING);

    // Create TBODY for data
    this._elTbody = elTable.appendChild(document.createElement("tbody"));
    YAHOO.util.Dom.addClass(this._elTbody,YAHOO.widget.DataTable.CLASS_BODY);
};

/**
 * Populates THEAD element with TH cells as defined by ColumnSet.
 *
 * @method _initTheadEl
 * @private
 */
YAHOO.widget.DataTable.prototype._initTheadEl = function() {
    var i,oColumn, colId;
    var oColumnSet = this._oColumnSet;
    this._sFirstLabelLinkId = null;
    
    // Create THEAD
    var elThead = document.createElement("thead");

    // Iterate through each row of Column headers...
    var colTree = oColumnSet.tree;
    for(i=0; i<colTree.length; i++) {
        var elTheadRow = elThead.appendChild(document.createElement("tr"));
        elTheadRow.id = this.id+"-hdrow"+i;

        var elTheadCell;
        // ...and create THEAD cells
        for(var j=0; j<colTree[i].length; j++) {
            oColumn = colTree[i][j];
            colId = oColumn.getId();
            elTheadCell = elTheadRow.appendChild(document.createElement("th"));
            elTheadCell.id = this.id + "-col" + colId;
            this._initThEl(elTheadCell,oColumn,i,j);
        }

        // Set FIRST/LAST on THEAD rows
        if(i === 0) {
            YAHOO.util.Dom.addClass(elTheadRow, YAHOO.widget.DataTable.CLASS_FIRST);
        }
        if(i === (colTree.length-1)) {
            YAHOO.util.Dom.addClass(elTheadRow, YAHOO.widget.DataTable.CLASS_LAST);
        }
    }

    this._elThead = this._elTable.appendChild(elThead);

    // Set FIRST/LAST on THEAD cells using the values in ColumnSet headers array
    var aFirstHeaders = oColumnSet.headers[0].split(" ");
    var aLastHeaders = oColumnSet.headers[oColumnSet.headers.length-1].split(" ");
    for(i=0; i<aFirstHeaders.length; i++) {
        YAHOO.util.Dom.addClass(YAHOO.util.Dom.get(this.id+"-col"+aFirstHeaders[i]), YAHOO.widget.DataTable.CLASS_FIRST);
    }
    for(i=0; i<aLastHeaders.length; i++) {
        YAHOO.util.Dom.addClass(YAHOO.util.Dom.get(this.id+"-col"+aLastHeaders[i]), YAHOO.widget.DataTable.CLASS_LAST);
    }
    
    // Add Resizer only after DOM has been updated
    var foundDD = (YAHOO.util.DD) ? true : false;
    var needDD = false;
    for(i=0; i<this._oColumnSet.keys.length; i++) {
        oColumn = this._oColumnSet.keys[i];
        colId = oColumn.getId();
        var elTheadCellId = YAHOO.util.Dom.get(this.id + "-col" + colId);
        if(oColumn.resizeable) {
            if(foundDD) {
                //TODO: fix fixed width tables
                // Skip the last column for fixed-width tables
                if(!this.fixedWidth || (this.fixedWidth &&
                        (oColumn.getKeyIndex() != this._oColumnSet.keys.length-1))) {
                    // TODO: better way to get elTheadContainer
                    var elThContainer = YAHOO.util.Dom.getElementsByClassName(YAHOO.widget.DataTable.CLASS_HEADER,"div",elTheadCellId)[0];
                    var elThResizer = elThContainer.appendChild(document.createElement("span"));
                    elThResizer.id = this.id + "-resizer" + colId;
                    YAHOO.util.Dom.addClass(elThResizer,YAHOO.widget.DataTable.CLASS_RESIZER);
                    oColumn.ddResizer = new YAHOO.util.ColumnResizer(
                            this, oColumn, elTheadCellId, elThResizer.id, elThResizer.id);
                    var cancelClick = function(e) {
                        YAHOO.util.Event.stopPropagation(e);
                    };
                    YAHOO.util.Event.addListener(elThResizer,"click",cancelClick);
                }
                if(this.fixedWidth) {
                    //TODO: fix fixedWidth
                    //elThContainer.style.overflow = "hidden";
                    //TODO: better way to get elTheadText
                    var elThLabel = (YAHOO.util.Dom.getElementsByClassName(YAHOO.widget.DataTable.CLASS_LABEL,"span",elTheadCellId))[0];
                    elThLabel.style.overflow = "hidden";
                }
            }
            else {
                needDD = true;
            }
        }
    }
    if(needDD) {
    }

};

/**
 * Populates TH cell as defined by Column.
 *
 * @method _initThEl
 * @param elTheadCell {HTMLElement} TH cell element reference.
 * @param oColumn {YAHOO.widget.Column} Column object.
 * @param row {number} Row index.
 * @param col {number} Column index.
 * @private
 */
YAHOO.widget.DataTable.prototype._initThEl = function(elTheadCell,oColumn,row,col) {
    // Clear out the cell of prior content
    // TODO: purgeListeners and other validation-related things
    var index = this._nIndex;
    var colId = oColumn.getId();
    elTheadCell.yuiColumnId = colId;
    if(oColumn.abbr) {
        elTheadCell.abbr = oColumn.abbr;
    }
    if(oColumn.width) {
        elTheadCell.style.width = oColumn.width;
    }

    var aCustomClasses;
    if(YAHOO.lang.isString(oColumn.className)) {
        aCustomClasses = [oColumn.className];
    }
    else if(YAHOO.lang.isArray(oColumn.className)) {
        aCustomClasses = oColumn.className;
    }
    if(aCustomClasses) {
        for(var i=0; i<aCustomClasses.length; i++) {
            YAHOO.util.Dom.addClass(elTheadCell,aCustomClasses[i]);
        }
    }
    
    YAHOO.util.Dom.addClass(elTheadCell, "yui-dt-col-"+oColumn.key);
    
    elTheadCell.innerHTML = "";
    elTheadCell.rowSpan = oColumn.getRowspan();
    elTheadCell.colSpan = oColumn.getColspan();

    var elTheadContainer = elTheadCell.appendChild(document.createElement("div"));
    elTheadContainer.id = this.id + "-container" + colId;
    YAHOO.util.Dom.addClass(elTheadContainer,YAHOO.widget.DataTable.CLASS_HEADER);
    var elTheadLabel = elTheadContainer.appendChild(document.createElement("span"));
    elTheadLabel.id = this.id + "-label" + colId;
    YAHOO.util.Dom.addClass(elTheadLabel,YAHOO.widget.DataTable.CLASS_LABEL);

    var sLabel = YAHOO.lang.isValue(oColumn.label) ? oColumn.label : oColumn.key;
    if(oColumn.sortable) {
        YAHOO.util.Dom.addClass(elTheadCell,YAHOO.widget.DataTable.CLASS_SORTABLE);
        //TODO: Make sortLink customizeable
        //TODO: Make title configurable
        //TODO: Separate label from an accessibility link that says
        // "Click to sort ascending" and push it offscreen
        var sLabelLinkId = this.id + "-labellink" + colId;
        var sortLink = "?key=" + oColumn.key;
        elTheadLabel.innerHTML = "<a id=\"" + sLabelLinkId + "\" href=\"" + sortLink + "\" title=\"Click to sort\" class=\"" + YAHOO.widget.DataTable.CLASS_SORTABLE + "\">" + sLabel + "</a>";
        if(!this._sFirstLabelLinkId) {
            this._sFirstLabelLinkId = sLabelLinkId;
        }
    }
    else {
        elTheadLabel.innerHTML = sLabel;
    }
};

/**
 * Creates HTML markup for Cell Editor.
 *
 * @method _initCellEditorEl
 * @private
 */
YAHOO.widget.DataTable.prototype._initCellEditorEl = function() {
    // Attach Cell Editor container element to body
    var elCellEditor = document.createElement("div");
    elCellEditor.id = this.id + "-celleditor";
    elCellEditor.style.display = "none";
    YAHOO.util.Dom.addClass(elCellEditor, YAHOO.widget.DataTable.CLASS_EDITOR);
    elCellEditor = document.body.appendChild(elCellEditor);

    // Internal tracker of Cell Editor values
    var oCellEditor = {};
    oCellEditor.container = elCellEditor;
    oCellEditor.value = null;
    oCellEditor.isActive = false;
    this._oCellEditor = oCellEditor;

    // Handle ESC key
    this.subscribe("editorKeydownEvent", function(oArgs) {
        var e = oArgs.event;
        var elTarget = YAHOO.util.Event.getTarget(e);

        // ESC hides Cell Editor
        if((e.keyCode == 27)) {
            this.cancelCellEditor();
        }
    });
};

/**
 * Initializes Column sorting.
 *
 * @method _initColumnSort
 * @private
 */
YAHOO.widget.DataTable.prototype._initColumnSort = function() {
    this.subscribe("headerCellClickEvent", this.onEventSortColumn);
};

/**
 * Initializes DOM event listeners.
 *
 * @method _initDomEvents
 * @private
 */
YAHOO.widget.DataTable.prototype._initDomEvents = function() {
    var elTable = this._elTable;
    var elThead = this._elThead;
    var elTbody = this._elTbody;
    var elContainer = this._elContainer;

    YAHOO.util.Event.addListener(document, "click", this._onDocumentClick, this);
    YAHOO.util.Event.addListener(document, "keydown", this._onDocumentKeydown, this);

    YAHOO.util.Event.addListener(elTable, "focus", this._onTableFocus, this);
    YAHOO.util.Event.addListener(elTable, "mouseover", this._onTableMouseover, this);
    YAHOO.util.Event.addListener(elTable, "mouseout", this._onTableMouseout, this);
    YAHOO.util.Event.addListener(elTable, "mousedown", this._onTableMousedown, this);
    YAHOO.util.Event.addListener(elTable, "keydown", this._onTableKeydown, this);
    YAHOO.util.Event.addListener(elTable, "keypress", this._onTableKeypress, this);

    // Since we can't listen for click and dblclick on the same element...
    YAHOO.util.Event.addListener(elTable, "dblclick", this._onTableDblclick, this);
    YAHOO.util.Event.addListener(elThead, "click", this._onTheadClick, this);
    YAHOO.util.Event.addListener(elTbody, "click", this._onTbodyClick, this);

    YAHOO.util.Event.addListener(elContainer, "scroll", this._onScroll, this); // for IE
    YAHOO.util.Event.addListener(elTbody, "scroll", this._onScroll, this); // for everyone else
};





































// DOM MUTATION FUNCTIONS




/**
 * Adds a TR element to the primary TBODY at the page row index if given, otherwise
 * at the end of the page. Formats TD elements within the TR element using data
 * from the given Record.
 *
 * @method _addTrEl
 * @param oRecord {YAHOO.widget.Record} Record instance.
 * @param index {Number} (optional) The page row index at which to add the TR
 * element.
 * @return {String} ID of the added TR element, or null.
 * @private
 */
YAHOO.widget.DataTable.prototype._addTrEl = function(oRecord, index) {
    this.hideTableMessage();

    // It's an append if no index provided, or index is negative or too big
    var append = (!YAHOO.lang.isNumber(index) || (index < 0) ||
            (index >= (this._elTbody.rows.length))) ? true : false;
            
    var oColumnSet = this._oColumnSet;
    var oRecordSet = this._oRecordSet;
    var isSortedBy = this.get("sortedBy");
    var sortedColKeyIndex  = null;
    var sortedDir, newClass;
    if(isSortedBy) {
        sortedColKeyIndex = (isSortedBy.column) ?
                isSortedBy.column.getKeyIndex() :
                this._oColumnSet.getColumn(isSortedBy.key).getKeyIndex();
        sortedDir = isSortedBy.dir;
        newClass = (sortedDir === "desc") ? YAHOO.widget.DataTable.CLASS_DESC :
                YAHOO.widget.DataTable.CLASS_ASC;

    }


    var elRow = (append) ? this._elTbody.appendChild(document.createElement("tr")) :
        this._elTbody.insertBefore(document.createElement("tr"),this._elTbody.rows[index]);

    elRow.id = this.id+"-bdrow"+this._nTrCount;
    this._nTrCount++;
    elRow.yuiRecordId = oRecord.getId();

    // Create TD cells
    for(var j=0; j<oColumnSet.keys.length; j++) {
        var oColumn = oColumnSet.keys[j];
        var elCell = elRow.appendChild(document.createElement("td"));
        elCell.id = elRow.id+"-cell"+j;
        elCell.yuiColumnId = oColumn.getId();
        elCell.headers = oColumnSet.headers[j];
        // For SF2 cellIndex bug: http://www.webreference.com/programming/javascript/ppk2/3.html
        elCell.yuiCellIndex = j;

        // Update UI
        this.formatCell(elCell, oRecord, oColumn);

        // Set FIRST/LAST on TD
        if (j === 0) {
            YAHOO.util.Dom.addClass(elCell, YAHOO.widget.DataTable.CLASS_FIRST);
        }
        else if (j === this._oColumnSet.keys.length-1) {
            YAHOO.util.Dom.addClass(elCell, YAHOO.widget.DataTable.CLASS_LAST);
        }
        
        // Remove ASC/DESC
        YAHOO.util.Dom.removeClass(elCell, YAHOO.widget.DataTable.CLASS_ASC);
        YAHOO.util.Dom.removeClass(elCell, YAHOO.widget.DataTable.CLASS_DESC);
        
        // Set ASC/DESC on TD
        if(j === sortedColKeyIndex) {
            newClass = (sortedDir === "desc") ?
                    YAHOO.widget.DataTable.CLASS_DESC :
                    YAHOO.widget.DataTable.CLASS_ASC;
            YAHOO.util.Dom.addClass(elCell, newClass);
        }


        /*p.abx {word-wrap:break-word;}
ought to solve the problem for Safari (the long words will wrap in your
tds, instead of overflowing to the next td.
(this is supported by IE win as well, so hide it if needed).

One thing, though: it doesn't work in combination with
'white-space:nowrap'.*/

// need a div wrapper for safari?
        //TODO: fix fixedWidth
        if(this.fixedWidth) {
            elCell.style.overflow = "hidden";
            //elCell.style.width = "20px";
        }
    }

    return elRow.id;
};

/**
 * Formats all TD elements of given TR element with data from the given Record.
 *
 * @method _updateTrEl
 * @param elRow {HTMLElement} The TR element to update.
 * @param oRecord {YAHOO.widget.Record} The associated Record instance.
 * @return {String} ID of the updated TR element, or null.
 * @private
 */
YAHOO.widget.DataTable.prototype._updateTrEl = function(elRow, oRecord) {
    this.hideTableMessage();

    var isSortedBy = this.get("sortedBy");
    var sortedColKeyIndex  = null;
    var sortedDir, newClass;
    if(isSortedBy) {
        sortedColKeyIndex = (isSortedBy.column) ?
                isSortedBy.column.getKeyIndex() :
                this._oColumnSet.getColumn(isSortedBy.key).getKeyIndex();
        sortedDir = isSortedBy.dir;
        newClass = (sortedDir === "desc") ? YAHOO.widget.DataTable.CLASS_DESC :
                YAHOO.widget.DataTable.CLASS_ASC;
    }

    // Update TD elements with new data
    for(var j=0; j<elRow.cells.length; j++) {
        var oColumn = this._oColumnSet.keys[j];
        var elCell = elRow.cells[j];
        this.formatCell(elCell, oRecord, oColumn);

        // Remove ASC/DESC
        YAHOO.util.Dom.removeClass(elCell, YAHOO.widget.DataTable.CLASS_ASC);
        YAHOO.util.Dom.removeClass(elCell, YAHOO.widget.DataTable.CLASS_DESC);

        // Set ASC/DESC on TD
        if(j === sortedColKeyIndex) {
            YAHOO.util.Dom.addClass(elCell, newClass);
        }
    }

    // Update Record ID
    elRow.yuiRecordId = oRecord.getId();
    
    return elRow.id;
};


/**
 * Deletes TR element by DOM reference or by DataTable page row index.
 *
 * @method _deleteTrEl
 * @param row {HTMLElement | Number} TR element reference or Datatable page row index.
 * @return {Boolean} Returns true if successful, else returns false.
 * @private
 */
YAHOO.widget.DataTable.prototype._deleteTrEl = function(row) {
    var rowIndex;
    
    // Get page row index for the element
    if(!YAHOO.lang.isNumber(row)) {
        rowIndex = YAHOO.util.Dom.get(row).sectionRowIndex;
    }
    else {
        rowIndex = row;
    }
    if(YAHOO.lang.isNumber(rowIndex) && (rowIndex > -2) && (rowIndex < this._elTbody.rows.length)) {
        this._elTbody.deleteRow(rowIndex);
        return true;
    }
    else {
        return false;
    }
};



























// CSS/STATE FUNCTIONS




/**
 * Assigns the class YAHOO.widget.DataTable.CLASS_FIRST to the first TR element
 * of the DataTable page and updates internal tracker.
 *
 * @method _setFirstRow
 * @private
 */
YAHOO.widget.DataTable.prototype._setFirstRow = function() {
    var rowEl = this.getFirstTrEl();
    if(rowEl) {
        // Remove FIRST
        if(this._sFirstTrId) {
            YAHOO.util.Dom.removeClass(this._sFirstTrId, YAHOO.widget.DataTable.CLASS_FIRST);
        }
        // Set FIRST
        YAHOO.util.Dom.addClass(rowEl, YAHOO.widget.DataTable.CLASS_FIRST);
        this._sFirstTrId = rowEl.id;
    }
    else {
        this._sFirstTrId = null;
    }
};

/**
 * Assigns the class YAHOO.widget.DataTable.CLASS_LAST to the last TR element
 * of the DataTable page and updates internal tracker.
 *
 * @method _setLastRow
 * @private
 */
YAHOO.widget.DataTable.prototype._setLastRow = function() {
    var rowEl = this.getLastTrEl();
    if(rowEl) {
        // Unassign previous class
        if(this._sLastTrId) {
            YAHOO.util.Dom.removeClass(this._sLastTrId, YAHOO.widget.DataTable.CLASS_LAST);
        }
        // Assign class
        YAHOO.util.Dom.addClass(rowEl, YAHOO.widget.DataTable.CLASS_LAST);
        this._sLastTrId = rowEl.id;
    }
    else {
        this._sLastTrId = null;
    }
};

/**
 * Assigns the classes YAHOO.widget.DataTable.CLASS_EVEN and
 * YAHOO.widget.DataTable.CLASS_ODD to alternating TR elements of the DataTable
 * page. For performance, a subset of rows may be specified.
 *
 * @method _setRowStripes
 * @param row {HTMLElement | String | Number} (optional) HTML TR element reference
 * or string ID, or page row index of where to start striping.
 * @param range {Number} (optional) If given, how many rows to stripe, otherwise
 * stripe all the rows until the end.
 * @private
 */
YAHOO.widget.DataTable.prototype._setRowStripes = function(row, range) {
    // Default values stripe all rows
    var allRows = this._elTbody.rows;
    var nStartIndex = 0;
    var nEndIndex = allRows.length;
    
    // Stripe a subset
    if((row !== null) && (row !== undefined)) {
        // Validate given start row
        var elStartRow = this.getTrEl(row);
        if(elStartRow) {
            nStartIndex = elStartRow.sectionRowIndex;
            
            // Validate given range
            if(YAHOO.lang.isNumber(range) && (range > 1)) {
                nEndIndex = nStartIndex + range;
            }
        }
    }

    for(var i=nStartIndex; i<nEndIndex; i++) {
        if(i%2) {
            YAHOO.util.Dom.removeClass(allRows[i], YAHOO.widget.DataTable.CLASS_EVEN);
            YAHOO.util.Dom.addClass(allRows[i], YAHOO.widget.DataTable.CLASS_ODD);
        }
        else {
            YAHOO.util.Dom.removeClass(allRows[i], YAHOO.widget.DataTable.CLASS_ODD);
            YAHOO.util.Dom.addClass(allRows[i], YAHOO.widget.DataTable.CLASS_EVEN);
        }
    }
};













































/////////////////////////////////////////////////////////////////////////////
//
// Private DOM Event Handlers
//
/////////////////////////////////////////////////////////////////////////////

/**
 * Handles scroll events on the CONTAINER (for IE) and TBODY elements (for everyone else).
 *
 * @method _onScroll
 * @param e {HTMLEvent} The scroll event.
 * @param oSelf {YAHOO.widget.DataTable} DataTable instance.
 * @private
 */
YAHOO.widget.DataTable.prototype._onScroll = function(e, oSelf) {
    var elTarget = YAHOO.util.Event.getTarget(e);
    var elTag = elTarget.tagName.toLowerCase();
    
    if(oSelf._oCellEditor.isActive) {
        oSelf.fireEvent("editorBlurEvent", {editor:oSelf._oCellEditor});
        oSelf.cancelCellEditor();
    }

    oSelf.fireEvent("tableScrollEvent", {event:e, target:elTarget});
};

/**
 * Handles click events on the DOCUMENT.
 *
 * @method _onDocumentClick
 * @param e {HTMLEvent} The click event.
 * @param oSelf {YAHOO.widget.DataTable} DataTable instance.
 * @private
 */
YAHOO.widget.DataTable.prototype._onDocumentClick = function(e, oSelf) {
    var elTarget = YAHOO.util.Event.getTarget(e);
    var elTag = elTarget.tagName.toLowerCase();

    if(!YAHOO.util.Dom.isAncestor(oSelf._elTable, elTarget)) {
        oSelf.fireEvent("tableBlurEvent");

        // Fires editorBlurEvent when click is not within the TABLE.
        // For cases when click is within the TABLE, due to timing issues,
        // the editorBlurEvent needs to get fired by the lower-level DOM click
        // handlers below rather than by the TABLE click handler directly.
        if(oSelf._oCellEditor && oSelf._oCellEditor.isActive) {
            // Only if the click was not within the Cell Editor container
            if(!YAHOO.util.Dom.isAncestor(oSelf._oCellEditor.container, elTarget) &&
                    (oSelf._oCellEditor.container.id !== elTarget.id)) {
                oSelf.fireEvent("editorBlurEvent", {editor:oSelf._oCellEditor});
            }
        }
    }
};

/**
 * Handles keydown events on the DOCUMENT.
 *
 * @method _onDocumentKeydown
 * @param e {HTMLEvent} The keydown event.
 * @param oSelf {YAHOO.widget.DataTable} DataTable instance.
 * @private
 */
YAHOO.widget.DataTable.prototype._onDocumentKeydown = function(e, oSelf) {
    var elTarget = YAHOO.util.Event.getTarget(e);
    var elTag = elTarget.tagName.toLowerCase();

    if(oSelf._oCellEditor && oSelf._oCellEditor.isActive &&
            YAHOO.util.Dom.isAncestor(oSelf._oCellEditor.container, elTarget)) {
        oSelf.fireEvent("editorKeydownEvent", {editor:oSelf._oCellEditor, event:e});
    }
};

/**
 * Handles focus events on the TABLE element.
 *
 * @method _onTableFocus
 * @param e {HTMLEvent} The focus event.
 * @param oSelf {YAHOO.widget.DataTable} DataTable instance.
 * @private
 */
YAHOO.widget.DataTable.prototype._onTableMouseover = function(e, oSelf) {
    oSelf.fireEvent("tableFocusEvent");
};

/**
 * Handles mouseover events on the TABLE element.
 *
 * @method _onTableMouseover
 * @param e {HTMLEvent} The mouseover event.
 * @param oSelf {YAHOO.widget.DataTable} DataTable instance.
 * @private
 */
YAHOO.widget.DataTable.prototype._onTableMouseover = function(e, oSelf) {
    var elTarget = YAHOO.util.Event.getTarget(e);
    var elTag = elTarget.tagName.toLowerCase();

    while(elTarget && (elTag != "table")) {
        switch(elTag) {
            case "body":
                 break;
            case "a":
                break;
            case "td":
                oSelf.fireEvent("cellMouseoverEvent",{target:elTarget,event:e});
                break;
            case "span":
                if(YAHOO.util.Dom.hasClass(elTarget, YAHOO.widget.DataTable.CLASS_LABEL)) {
                    oSelf.fireEvent("headerLabelMouseoverEvent",{target:elTarget,event:e});
                }
                break;
            case "th":
                oSelf.fireEvent("headerCellMouseoverEvent",{target:elTarget,event:e});
                break;
            case "tr":
                if(elTarget.parentNode.tagName.toLowerCase() == "thead") {
                    oSelf.fireEvent("headerRowMouseoverEvent",{target:elTarget,event:e});
                }
                else {
                    oSelf.fireEvent("rowMouseoverEvent",{target:elTarget,event:e});
                }
                break;
            default:
                break;
        }
        elTarget = elTarget.parentNode;
        if(elTarget) {
            elTag = elTarget.tagName.toLowerCase();
        }
    }
    oSelf.fireEvent("tableMouseoverEvent",{target:(elTarget || oSelf._elTable),event:e});
};

/**
 * Handles mouseout events on the TABLE element.
 *
 * @method _onTableMouseout
 * @param e {HTMLEvent} The mouseout event.
 * @param oSelf {YAHOO.widget.DataTable} DataTable instance.
 * @private
 */
YAHOO.widget.DataTable.prototype._onTableMouseout = function(e, oSelf) {
    var elTarget = YAHOO.util.Event.getTarget(e);
    var elTag = elTarget.tagName.toLowerCase();

    while(elTarget && (elTag != "table")) {
        switch(elTag) {
            case "body":
                break;
            case "a":
                break;
            case "td":
                oSelf.fireEvent("cellMouseoutEvent",{target:elTarget,event:e});
                break;
            case "span":
                if(YAHOO.util.Dom.hasClass(elTarget, YAHOO.widget.DataTable.CLASS_LABEL)) {
                    oSelf.fireEvent("headerLabelMouseoutEvent",{target:elTarget,event:e});
                }
                break;
            case "th":
                oSelf.fireEvent("headerCellMouseoutEvent",{target:elTarget,event:e});
                break;
            case "tr":
                if(elTarget.parentNode.tagName.toLowerCase() == "thead") {
                    oSelf.fireEvent("headerRowMouseoutEvent",{target:elTarget,event:e});
                }
                else {
                    oSelf.fireEvent("rowMouseoutEvent",{target:elTarget,event:e});
                }
                break;
            default:
                break;
        }
        elTarget = elTarget.parentNode;
        if(elTarget) {
            elTag = elTarget.tagName.toLowerCase();
        }
    }
    oSelf.fireEvent("tableMouseoutEvent",{target:(elTarget || oSelf._elTable),event:e});
};

/**
 * Handles mousedown events on the TABLE element.
 *
 * @method _onTableMousedown
 * @param e {HTMLEvent} The mousedown event.
 * @param oSelf {YAHOO.widget.DataTable} DataTable instance.
 * @private
 */
YAHOO.widget.DataTable.prototype._onTableMousedown = function(e, oSelf) {
    var elTarget = YAHOO.util.Event.getTarget(e);
    var elTag = elTarget.tagName.toLowerCase();

    while(elTarget && (elTag != "table")) {
        switch(elTag) {
            case "body":
                break;
            case "a":
                break;
            case "td":
                oSelf.fireEvent("cellMousedownEvent",{target:elTarget,event:e});
                break;
            case "span":
                if(YAHOO.util.Dom.hasClass(elTarget, YAHOO.widget.DataTable.CLASS_LABEL)) {
                    oSelf.fireEvent("headerLabelMousedownEvent",{target:elTarget,event:e});
                }
                break;
            case "th":
                oSelf.fireEvent("headerCellMousedownEvent",{target:elTarget,event:e});
                break;
            case "tr":
                if(elTarget.parentNode.tagName.toLowerCase() == "thead") {
                    oSelf.fireEvent("headerRowMousedownEvent",{target:elTarget,event:e});
                }
                else {
                    oSelf.fireEvent("rowMousedownEvent",{target:elTarget,event:e});
                }
                break;
            default:
                break;
        }
        elTarget = elTarget.parentNode;
        if(elTarget) {
            elTag = elTarget.tagName.toLowerCase();
        }
    }
    oSelf.fireEvent("tableMousedownEvent",{target:(elTarget || oSelf._elTable),event:e});
};

/**
 * Handles dblclick events on the TABLE element.
 *
 * @method _onTableDblclick
 * @param e {HTMLEvent} The dblclick event.
 * @param oSelf {YAHOO.widget.DataTable} DataTable instance.
 * @private
 */
YAHOO.widget.DataTable.prototype._onTableDblclick = function(e, oSelf) {
    var elTarget = YAHOO.util.Event.getTarget(e);
    var elTag = elTarget.tagName.toLowerCase();

    while(elTarget && (elTag != "table")) {
        switch(elTag) {
            case "body":
                break;
            case "td":
                oSelf.fireEvent("cellDblclickEvent",{target:elTarget,event:e});
                break;
            case "span":
                if(YAHOO.util.Dom.hasClass(elTarget, YAHOO.widget.DataTable.CLASS_LABEL)) {
                    oSelf.fireEvent("headerLabelDblclickEvent",{target:elTarget,event:e});
                }
                break;
            case "th":
                oSelf.fireEvent("headerCellDblclickEvent",{target:elTarget,event:e});
                break;
            case "tr":
                if(elTarget.parentNode.tagName.toLowerCase() == "thead") {
                    oSelf.fireEvent("headerRowDblclickEvent",{target:elTarget,event:e});
                }
                else {
                    oSelf.fireEvent("rowDblclickEvent",{target:elTarget,event:e});
                }
                break;
            default:
                break;
        }
        elTarget = elTarget.parentNode;
        if(elTarget) {
            elTag = elTarget.tagName.toLowerCase();
        }
    }
    oSelf.fireEvent("tableDblclickEvent",{target:(elTarget || oSelf._elTable),event:e});
};

/**
 * Handles keydown events on the TABLE element. Handles arrow selection.
 *
 * @method _onTableKeydown
 * @param e {HTMLEvent} The key event.
 * @param oSelf {YAHOO.widget.DataTable} DataTable instance.
 * @private
 */
YAHOO.widget.DataTable.prototype._onTableKeydown = function(e, oSelf) {
    var bSHIFT = e.shiftKey;
    var elTarget = YAHOO.util.Event.getTarget(e);
    
    // Ignore actions in the THEAD
    if(YAHOO.util.Dom.isAncestor(oSelf._elThead, elTarget)) {
        return;
    }
    
    var nKey = YAHOO.util.Event.getCharCode(e);
    
    // TAB to first label link if any
    if(nKey === 9 && !bSHIFT && (elTarget.id === oSelf._elTable.id)) {
        if(oSelf._sFirstLabelLinkId) {
            YAHOO.util.Event.stopEvent(e);
            oSelf._focusEl(YAHOO.util.Dom.get(oSelf._sFirstLabelLinkId));
        }
        return;
    }

    // Something is currently selected
    var lastSelectedId = oSelf._sLastSelectedId;
    var lastSelectedEl = YAHOO.util.Dom.get(lastSelectedId);
    if(lastSelectedEl && oSelf.isSelected(lastSelectedEl)) {
        //TODO: handle tab, backspace, delete
        
        // Handle arrow selection
        if((nKey > 36) && (nKey < 41)) {
            YAHOO.util.Event.stopEvent(e);
        }
        else {
            return;
        }

        var sMode = oSelf.get("selectionMode");
        var allRows = oSelf._elTbody.rows;
        var anchorId = oSelf._sSelectionAnchorId;
        var anchorEl = YAHOO.util.Dom.get(anchorId);
        var newSelectedEl, trIndex, tdIndex, startIndex, endIndex, i, anchorPos;

        ////////////////////////////////////////////////////////////////////////
        //
        // SHIFT cell block selection
        //
        ////////////////////////////////////////////////////////////////////////
        if(bSHIFT && (sMode == "cellblock")) {
            trIndex = lastSelectedEl.parentNode.sectionRowIndex;
            tdIndex = lastSelectedEl.yuiCellIndex;

            // Arrow DOWN
            if(nKey == 40) {
                // Is the anchor cell above, below, or same row
                if(anchorEl.parentNode.sectionRowIndex > trIndex) {
                    anchorPos = 1;
                }
                else if(anchorEl.parentNode.sectionRowIndex < trIndex) {
                    anchorPos = -1;
                }
                else {
                    anchorPos = 0;
                }

                // Is the anchor cell left or right
                startIndex = Math.min(anchorEl.yuiCellIndex, tdIndex);
                endIndex = Math.max(anchorEl.yuiCellIndex, tdIndex);

                // Selecting away from anchor cell
                if(anchorPos <= 0) {
                    // Select the horiz block on the next row
                    if(trIndex < allRows.length-1) {
                        for(i=startIndex; i<=endIndex; i++) {
                            newSelectedEl = allRows[trIndex+1].cells[i];
                            oSelf.selectCell(newSelectedEl);
                        }
                        oSelf._sLastSelectedId = allRows[trIndex+1].cells[tdIndex].id;
                    }
                }
                // Unselecting towards anchor cell
                else {
                    // Unselect the horiz block on this row towards the next row
                    for(i=startIndex; i<=endIndex; i++) {
                        oSelf.unselectCell(allRows[trIndex].cells[i]);
                    }
                    oSelf._sLastSelectedId = allRows[trIndex+1].cells[tdIndex].id;
                }
            }
            // Arrow up
            else if(nKey == 38) {
                // Is the anchor cell above, below, or same row
                if(anchorEl.parentNode.sectionRowIndex > trIndex) {
                    anchorPos = 1;
                }
                else if(anchorEl.parentNode.sectionRowIndex < trIndex) {
                    anchorPos = -1;
                }
                else {
                    anchorPos = 0;
                }

                // Is the anchor cell left or right?
                startIndex = Math.min(anchorEl.yuiCellIndex, tdIndex);
                endIndex = Math.max(anchorEl.yuiCellIndex, tdIndex);

                // Selecting away from anchor cell
                if(anchorPos >= 0) {
                    // Select the horiz block on the previous row
                    if(trIndex > 0) {
                        for(i=startIndex; i<=endIndex; i++) {
                            newSelectedEl = allRows[trIndex-1].cells[i];
                            oSelf.selectCell(newSelectedEl);
                        }
                        oSelf._sLastSelectedId = allRows[trIndex-1].cells[tdIndex].id;
                    }
                }
                // Unselecting towards anchor cell
                else {
                    // Unselect the horiz block on this row towards the previous row
                    for(i=startIndex; i<=endIndex; i++) {
                        oSelf.unselectCell(allRows[trIndex].cells[i]);
                    }
                    oSelf._sLastSelectedId = allRows[trIndex-1].cells[tdIndex].id;
                }
            }
            // Arrow right
            else if(nKey == 39) {
                // Is the anchor cell left, right, or same column
                if(anchorEl.yuiCellIndex > tdIndex) {
                    anchorPos = 1;
                }
                else if(anchorEl.yuiCellIndex < tdIndex) {
                    anchorPos = -1;
                }
                else {
                    anchorPos = 0;
                }

                // Selecting away from anchor cell
                if(anchorPos <= 0) {
                    //Select the next vert block to the right
                    if(tdIndex < allRows[trIndex].cells.length-1) {
                        startIndex = Math.min(anchorEl.parentNode.sectionRowIndex, trIndex);
                        endIndex = Math.max(anchorEl.parentNode.sectionRowIndex, trIndex);
                        for(i=startIndex; i<=endIndex; i++) {
                            newSelectedEl = allRows[i].cells[tdIndex+1];
                            oSelf.selectCell(newSelectedEl);
                        }
                        oSelf._sLastSelectedId = allRows[trIndex].cells[tdIndex+1].id;
                    }
                }
                // Unselecting towards anchor cell
                else {
                    // Unselect the vert block on this column towards the right
                    startIndex = Math.min(anchorEl.parentNode.sectionRowIndex, trIndex);
                    endIndex = Math.max(anchorEl.parentNode.sectionRowIndex, trIndex);
                    for(i=startIndex; i<=endIndex; i++) {
                        oSelf.unselectCell(allRows[i].cells[tdIndex]);
                    }
                    oSelf._sLastSelectedId = allRows[trIndex].cells[tdIndex+1].id;
                }
            }
            // Arrow left
            else if(nKey == 37) {
                // Is the anchor cell left, right, or same column
                if(anchorEl.yuiCellIndex > tdIndex) {
                    anchorPos = 1;
                }
                else if(anchorEl.yuiCellIndex < tdIndex) {
                    anchorPos = -1;
                }
                else {
                    anchorPos = 0;
                }

                // Selecting away from anchor cell
                if(anchorPos >= 0) {
                    //Select the previous vert block to the left
                    if(tdIndex > 0) {
                        startIndex = Math.min(anchorEl.parentNode.sectionRowIndex, trIndex);
                        endIndex = Math.max(anchorEl.parentNode.sectionRowIndex, trIndex);
                        for(i=startIndex; i<=endIndex; i++) {
                            newSelectedEl = allRows[i].cells[tdIndex-1];
                            oSelf.selectCell(newSelectedEl);
                        }
                        oSelf._sLastSelectedId = allRows[trIndex].cells[tdIndex-1].id;
                    }
                }
                // Unselecting towards anchor cell
                else {
                    // Unselect the vert block on this column towards the left
                    startIndex = Math.min(anchorEl.parentNode.sectionRowIndex, trIndex);
                    endIndex = Math.max(anchorEl.parentNode.sectionRowIndex, trIndex);
                    for(i=startIndex; i<=endIndex; i++) {
                        oSelf.unselectCell(allRows[i].cells[tdIndex]);
                    }
                    oSelf._sLastSelectedId = allRows[trIndex].cells[tdIndex-1].id;
                }
            }
        }
        ////////////////////////////////////////////////////////////////////////
        //
        // SHIFT cell range selection
        //
        ////////////////////////////////////////////////////////////////////////
        else if(bSHIFT && (sMode == "cellrange")) {
            trIndex = lastSelectedEl.parentNode.sectionRowIndex;
            tdIndex = lastSelectedEl.yuiCellIndex;

            // Is the anchor cell above, below, or same row
            if(anchorEl.parentNode.sectionRowIndex > trIndex) {
                anchorPos = 1;
            }
            else if(anchorEl.parentNode.sectionRowIndex < trIndex) {
                anchorPos = -1;
            }
            else {
                anchorPos = 0;
            }

            // Arrow down
            if(nKey == 40) {
                // Selecting away from anchor cell
                if(anchorPos <= 0) {
                    // Select all cells to the end of this row
                    for(i=tdIndex+1; i<allRows[trIndex].cells.length; i++){
                        newSelectedEl = allRows[trIndex].cells[i];
                        oSelf.selectCell(newSelectedEl);
                    }

                    // Select some of the cells on the next row down
                    if(trIndex < allRows.length-1) {
                        for(i=0; i<=tdIndex; i++){
                            newSelectedEl = allRows[trIndex+1].cells[i];
                            oSelf.selectCell(newSelectedEl);
                        }
                    }
                }
                // Unselecting towards anchor cell
                else {
                    // Unselect all cells to the end of this row
                    for(i=tdIndex; i<allRows[trIndex].cells.length; i++){
                        oSelf.unselectCell(allRows[trIndex].cells[i]);
                    }

                    // Unselect some of the cells on the next row down
                    for(i=0; i<tdIndex; i++){
                        oSelf.unselectCell(allRows[trIndex+1].cells[i]);
                    }
                    oSelf._sLastSelectedId = allRows[trIndex+1].cells[tdIndex].id;
                }
            }
            // Arrow up
            else if(nKey == 38) {
                // Selecting away from anchor cell
                if(anchorPos >= 0) {
                    // Select all the cells to the beginning of this row
                    for(i=tdIndex-1; i>-1; i--){
                        newSelectedEl = allRows[trIndex].cells[i];
                        oSelf.selectCell(newSelectedEl);
                    }

                    // Select some of the cells from the end of the previous row
                    if(trIndex > 0) {
                        for(i=allRows[trIndex].cells.length-1; i>=tdIndex; i--){
                            newSelectedEl = allRows[trIndex-1].cells[i];
                            oSelf.selectCell(newSelectedEl);
                        }
                    }
                }
                // Unselecting towards anchor cell
                else {
                    // Unselect all the cells to the beginning of this row
                    for(i=tdIndex; i>-1; i--){
                        oSelf.unselectCell(allRows[trIndex].cells[i]);
                    }

                    // Unselect some of the cells from the end of the previous row
                    for(i=allRows[trIndex].cells.length-1; i>tdIndex; i--){
                        oSelf.unselectCell(allRows[trIndex-1].cells[i]);
                    }
                    oSelf._sLastSelectedId = allRows[trIndex-1].cells[tdIndex].id;
                }
            }
            // Arrow right
            else if(nKey == 39) {
                // Selecting away from anchor cell
                if(anchorPos < 0) {
                    // Select the next cell to the right
                    if(tdIndex < allRows[trIndex].cells.length-1) {
                        newSelectedEl = allRows[trIndex].cells[tdIndex+1];
                        oSelf.selectCell(newSelectedEl);
                    }
                    // Select the first cell of the next row
                    else if(trIndex < allRows.length-1) {
                        newSelectedEl = allRows[trIndex+1].cells[0];
                        oSelf.selectCell(newSelectedEl);
                    }
                }
                // Unselecting towards anchor cell
                else if(anchorPos > 0) {
                    oSelf.unselectCell(allRows[trIndex].cells[tdIndex]);

                    // Unselect this cell towards the right
                    if(tdIndex < allRows[trIndex].cells.length-1) {
                        oSelf._sLastSelectedId = allRows[trIndex].cells[tdIndex+1].id;
                    }
                    // Unselect this cells towards the first cell of the next row
                    else {
                        oSelf._sLastSelectedId = allRows[trIndex+1].cells[0].id;
                    }
                }
                // Anchor is on this row
                else {
                    // Selecting away from anchor
                    if(anchorEl.yuiCellIndex <= tdIndex) {
                        // Select the next cell to the right
                        if(tdIndex < allRows[trIndex].cells.length-1) {
                            newSelectedEl = allRows[trIndex].cells[tdIndex+1];
                            oSelf.selectCell(newSelectedEl);
                        }
                        // Select the first cell on the next row
                        else if(trIndex < allRows.length-1){
                            newSelectedEl = allRows[trIndex+1].cells[0];
                            oSelf.selectCell(newSelectedEl);
                        }
                    }
                    // Unselecting towards anchor
                    else {
                        // Unselect this cell towards the right
                        oSelf.unselectCell(allRows[trIndex].cells[tdIndex]);
                        oSelf._sLastSelectedId = allRows[trIndex].cells[tdIndex+1].id;
                    }
                }
            }
            // Arrow left
            else if(nKey == 37) {
                // Unselecting towards the anchor
                if(anchorPos < 0) {
                    oSelf.unselectCell(allRows[trIndex].cells[tdIndex]);

                    // Unselect this cell towards the left
                    if(tdIndex > 0) {
                        oSelf._sLastSelectedId = allRows[trIndex].cells[tdIndex-1].id;
                    }
                    // Unselect this cell towards the last cell of the previous row
                    else {
                        oSelf._sLastSelectedId = allRows[trIndex-1].cells[allRows[trIndex-1].cells.length-1].id;
                    }
                }
                // Selecting towards the anchor
                else if(anchorPos > 0) {
                    // Select the next cell to the left
                    if(tdIndex > 0) {
                        newSelectedEl = allRows[trIndex].cells[tdIndex-1];
                        oSelf.selectCell(newSelectedEl);
                    }
                    // Select the last cell of the previous row
                    else if(trIndex > 0){
                        newSelectedEl = allRows[trIndex-1].cells[allRows[trIndex-1].cells.length-1];
                        oSelf.selectCell(newSelectedEl);
                    }
                }
                // Anchor is on this row
                else {
                    // Selecting away from anchor cell
                    if(anchorEl.yuiCellIndex >= tdIndex) {
                        // Select the next cell to the left
                        if(tdIndex > 0) {
                            newSelectedEl = allRows[trIndex].cells[tdIndex-1];
                            oSelf.selectCell(newSelectedEl);
                        }
                        // Select the last cell of the previous row
                        else if(trIndex > 0){
                            newSelectedEl = allRows[trIndex-1].cells[allRows[trIndex-1].cells.length-1];
                            oSelf.selectCell(newSelectedEl);
                        }
                    }
                    // Unselecting towards anchor cell
                    else {
                        oSelf.unselectCell(allRows[trIndex].cells[tdIndex]);

                        // Unselect this cell towards the left
                        if(tdIndex > 0) {
                            oSelf._sLastSelectedId = allRows[trIndex].cells[tdIndex-1].id;
                        }
                        // Unselect this cell towards the last cell of the previous row
                        else {
                            oSelf._sLastSelectedId = allRows[trIndex-1].cells[allRows[trIndex-1].cells.length-1].id;
                        }
                    }
                }
            }
        }
        ////////////////////////////////////////////////////////////////////////
        //
        // Simple single cell selection
        //
        ////////////////////////////////////////////////////////////////////////
        else if((sMode == "cellblock") || (sMode == "cellrange") || (sMode == "singlecell")) {
            trIndex = lastSelectedEl.parentNode.sectionRowIndex;
            tdIndex = lastSelectedEl.yuiCellIndex;

            // Arrow down
            if(nKey == 40) {
                oSelf.unselectAllCells();

                // Select the next cell down
                if(trIndex < allRows.length-1) {
                    newSelectedEl = allRows[trIndex+1].cells[tdIndex];
                    oSelf.selectCell(newSelectedEl);
                }
                // Select only the bottom cell
                else {
                    newSelectedEl = lastSelectedEl;
                    oSelf.selectCell(newSelectedEl);
                }

                oSelf._sSelectionAnchorId = newSelectedEl.id;
            }
            // Arrow up
            else if(nKey == 38) {
                oSelf.unselectAllCells();

                // Select the next cell up
                if(trIndex > 0) {
                    newSelectedEl = allRows[trIndex-1].cells[tdIndex];
                    oSelf.selectCell(newSelectedEl);
                }
                // Select only the top cell
                else {
                    newSelectedEl = lastSelectedEl;
                    oSelf.selectCell(newSelectedEl);
                }

                oSelf._sSelectionAnchorId = newSelectedEl.id;
            }
            // Arrow right
            else if(nKey == 39) {
                oSelf.unselectAllCells();

                // Select the next cell to the right
                if(tdIndex < lastSelectedEl.parentNode.cells.length-1) {
                    newSelectedEl = lastSelectedEl.parentNode.cells[tdIndex+1];
                    oSelf.selectCell(newSelectedEl);
                }
                // Select only the right cell
                else {
                    newSelectedEl = lastSelectedEl;
                    oSelf.selectCell(newSelectedEl);
                }

                oSelf._sSelectionAnchorId = newSelectedEl.id;
            }
            // Arrow left
            else if(nKey == 37) {
                oSelf.unselectAllCells();

                // Select the next cell to the left
                if(tdIndex > 0) {
                    newSelectedEl = lastSelectedEl.parentNode.cells[tdIndex-1];
                    oSelf.selectCell(newSelectedEl);
                }
                // Select only the left cell
                else {
                    newSelectedEl = lastSelectedEl;
                    oSelf.selectCell(newSelectedEl);
                }

                oSelf._sSelectionAnchorId = newSelectedEl.id;
            }
        }
        ////////////////////////////////////////////////////////////////////////
        //
        // SHIFT row selection
        //
        ////////////////////////////////////////////////////////////////////////
        else if(bSHIFT && (sMode != "single")) {
            trIndex = lastSelectedEl.sectionRowIndex;

            if(anchorEl.sectionRowIndex > trIndex) {
                anchorPos = 1;
            }
            else if(anchorEl.sectionRowIndex < trIndex) {
                anchorPos = -1;
            }
            else {
                anchorPos = 0;
            }

            // Arrow down
            if(nKey == 40) {
                // Selecting away from anchor row
                if(anchorPos <= 0) {
                    // Select the next row down
                    if(trIndex < allRows.length-1) {
                        oSelf.selectRow(trIndex+1);
                    }
                }
                // Unselecting toward anchor row
                else {
                    // Unselect this row towards the anchor row down
                    oSelf.unselectRow(lastSelectedEl);
                    oSelf._sLastSelectedId = allRows[trIndex+1].id;
                }

            }
            // Arrow up
            else if(nKey == 38) {
                // Selecting away from anchor row
                if(anchorPos >= 0) {
                    // Select the next row up
                    if(trIndex > 0) {
                        oSelf.selectRow(trIndex-1);
                    }
                }
                // Unselect this row towards the anchor row up
                else {
                    oSelf.unselectRow(lastSelectedEl);
                    oSelf._sLastSelectedId = allRows[trIndex-1].id;
                }
            }
            // Arrow right
            else if(nKey == 39) {
                // Do nothing
            }
            // Arrow left
            else if(nKey == 37) {
                // Do nothing
            }
        }
        ////////////////////////////////////////////////////////////////////////
        //
        // Simple single row selection
        //
        ////////////////////////////////////////////////////////////////////////
        else {
            trIndex = lastSelectedEl.sectionRowIndex;

            // Arrow down
            if(nKey == 40) {
                oSelf.unselectAllRows();

                // Select the next row
                if(trIndex < allRows.length-1) {
                    newSelectedEl = allRows[trIndex+1];
                    oSelf.selectRow(newSelectedEl);
                }
                // Select only the last row
                else {
                    newSelectedEl = lastSelectedEl;
                    oSelf.selectRow(lastSelectedEl);
                }

                oSelf._sSelectionAnchorId = newSelectedEl.id;
            }
            // Arrow up
            else if(nKey == 38) {
                oSelf.unselectAllRows();

                // Select the previous row
                if(trIndex > 0) {
                    newSelectedEl = allRows[trIndex-1];
                    oSelf.selectRow(newSelectedEl);
                }
                // Select only the first row
                else {
                    newSelectedEl = lastSelectedEl;
                    oSelf.selectRow(newSelectedEl);
                }

                oSelf._sSelectionAnchorId = newSelectedEl.id;
            }
            // Arrow right
            else if(nKey == 39) {
                // Do nothing
            }
            // Arrow left
            else if(nKey == 37) {
                // Do nothing
            }
        }
    }
};

/**
 * Handles keypress events on the TABLE. Mainly to support stopEvent on Mac.
 *
 * @method _onTableKeypress
 * @param e {HTMLEvent} The key event.
 * @param oSelf {YAHOO.widget.DataTable} DataTable instance.
 * @private
 */
YAHOO.widget.DataTable.prototype._onTableKeypress = function(e, oSelf) {
    var isMac = (navigator.userAgent.toLowerCase().indexOf("mac") != -1);
    if(isMac) {
        var nKey = YAHOO.util.Event.getCharCode(e);
        // arrow down
        if(nKey == 40) {
            YAHOO.util.Event.stopEvent(e);
        }
        // arrow up
        else if(nKey == 38) {
            YAHOO.util.Event.stopEvent(e);
        }
    }
};

/**
 * Handles click events on the THEAD element.
 *
 * @method _onTheadClick
 * @param e {HTMLEvent} The click event.
 * @param oSelf {YAHOO.widget.DataTable} DataTable instance.
 * @private
 */
YAHOO.widget.DataTable.prototype._onTheadClick = function(e, oSelf) {
    var elTarget = YAHOO.util.Event.getTarget(e);
    var elTag = elTarget.tagName.toLowerCase();

    if(oSelf._oCellEditor && oSelf._oCellEditor.isActive) {
        oSelf.fireEvent("editorBlurEvent", {editor:oSelf._oCellEditor});
    }

    while(elTarget && (elTag != "thead")) {
            switch(elTag) {
                case "body":
                    break;
                case "span":
                    if(YAHOO.util.Dom.hasClass(elTarget, YAHOO.widget.DataTable.CLASS_LABEL)) {
                        oSelf.fireEvent("headerLabelClickEvent",{target:elTarget,event:e});
                    }
                    break;
                case "th":
                    oSelf.fireEvent("headerCellClickEvent",{target:elTarget,event:e});
                    break;
                case "tr":
                    oSelf.fireEvent("headerRowClickEvent",{target:elTarget,event:e});
                    break;
                default:
                    break;
            }
            elTarget = elTarget.parentNode;
            if(elTarget) {
                elTag = elTarget.tagName.toLowerCase();
            }
    }
    oSelf.fireEvent("tableClickEvent",{target:(elTarget || oSelf._elTable),event:e});
};

/**
 * Handles click events on the primary TBODY element.
 *
 * @method _onTbodyClick
 * @param e {HTMLEvent} The click event.
 * @param oSelf {YAHOO.widget.DataTable} DataTable instance.
 * @private
 */
YAHOO.widget.DataTable.prototype._onTbodyClick = function(e, oSelf) {
    var elTarget = YAHOO.util.Event.getTarget(e);
    var elTag = elTarget.tagName.toLowerCase();

    if(oSelf._oCellEditor && oSelf._oCellEditor.isActive) {
        oSelf.fireEvent("editorBlurEvent", {editor:oSelf._oCellEditor});
    }

    while(elTarget && (elTag != "table")) {
        switch(elTag) {
            case "body":
                break;
            case "input":
                if(elTarget.type.toLowerCase() == "checkbox") {
                    oSelf.fireEvent("checkboxClickEvent",{target:elTarget,event:e});
                }
                else if(elTarget.type.toLowerCase() == "radio") {
                    oSelf.fireEvent("radioClickEvent",{target:elTarget,event:e});
                }
                break;
            case "a":
                oSelf.fireEvent("linkClickEvent",{target:elTarget,event:e});
                break;
            case "button":
                oSelf.fireEvent("buttonClickEvent",{target:elTarget,event:e});
                break;
            case "td":
                oSelf.fireEvent("cellClickEvent",{target:elTarget,event:e});
                break;
            case "tr":
                oSelf.fireEvent("rowClickEvent",{target:elTarget,event:e});
                break;
            default:
                break;
        }
        elTarget = elTarget.parentNode;
        if(elTarget) {
            elTag = elTarget.tagName.toLowerCase();
        }
    }
    oSelf.fireEvent("tableClickEvent",{target:(elTarget || oSelf._elTable),event:e});
};

/*TODO: delete
 * Handles keyup events on the TBODY. Executes deletion.
 *
 * @method _onTbodyKeyup
 * @param e {HTMLEvent} The key event.
 * @param oSelf {YAHOO.widget.DataTable} DataTable instance.
 * @private
 */
/*YAHOO.widget.DataTable.prototype._onTbodyKeyup = function(e, oSelf) {
   var nKey = YAHOO.util.Event.getCharCode(e);
    // delete
    if(nKey == 46) {//TODO: if something is selected
        //TODO: delete row
    }
};*/

/**
 * Handles click events on paginator links.
 *
 * @method _onPaginatorLinkClick
 * @param e {HTMLEvent} The click event.
 * @param oSelf {YAHOO.widget.DataTable} DataTable instance.
 * @private
 */
YAHOO.widget.DataTable.prototype._onPaginatorLinkClick = function(e, oSelf) {
    var elTarget = YAHOO.util.Event.getTarget(e);
    var elTag = elTarget.tagName.toLowerCase();

    if(oSelf._oCellEditor && oSelf._oCellEditor.isActive) {
        oSelf.fireEvent("editorBlurEvent", {editor:oSelf._oCellEditor});
    }

    while(elTarget && (elTag != "table")) {
        switch(elTag) {
            case "body":
                return;
            case "a":
                YAHOO.util.Event.stopEvent(e);
                //TODO: after the showPage call, figure out which link
                //TODO: was clicked and reset focus to the new version of it
                switch(elTarget.className) {
                    case YAHOO.widget.DataTable.CLASS_PAGE:
                        oSelf.showPage(parseInt(elTarget.innerHTML,10));
                        return;
                    case YAHOO.widget.DataTable.CLASS_FIRST:
                        oSelf.showPage(1);
                        return;
                    case YAHOO.widget.DataTable.CLASS_LAST:
                        oSelf.showPage(oSelf.get("paginator").totalPages);
                        return;
                    case YAHOO.widget.DataTable.CLASS_PREVIOUS:
                        oSelf.showPage(oSelf.get("paginator").currentPage - 1);
                        return;
                    case YAHOO.widget.DataTable.CLASS_NEXT:
                        oSelf.showPage(oSelf.get("paginator").currentPage + 1);
                        return;
                }
                break;
            default:
                return;
        }
        elTarget = elTarget.parentNode;
        if(elTarget) {
            elTag = elTarget.tagName.toLowerCase();
        }
        else {
            return;
        }
    }
};

/**
 * Handles change events on paginator SELECT element.
 *
 * @method _onPaginatorDropdownChange
 * @param e {HTMLEvent} The change event.
 * @param oSelf {YAHOO.widget.DataTable} DataTable instance.
 * @private
 */
YAHOO.widget.DataTable.prototype._onPaginatorDropdownChange = function(e, oSelf) {
    var elTarget = YAHOO.util.Event.getTarget(e);
    var newValue = elTarget[elTarget.selectedIndex].value;

    var newRowsPerPage = YAHOO.lang.isValue(parseInt(newValue,10)) ? parseInt(newValue,10) : null;
    if(newRowsPerPage !== null) {
        var newStartRecordIndex = (oSelf.get("paginator").currentPage-1) * newRowsPerPage;
        oSelf.updatePaginator({rowsPerPage:newRowsPerPage, startRecordIndex:newStartRecordIndex});
        oSelf.refreshView();
    }
    else {
    }
};

/**
 * Handles change events on SELECT elements within DataTable.
 *
 * @method _onDropdownChange
 * @param e {HTMLEvent} The change event.
 * @param oSelf {YAHOO.widget.DataTable} DataTable instance.
 * @private
 */
YAHOO.widget.DataTable.prototype._onDropdownChange = function(e, oSelf) {
    var elTarget = YAHOO.util.Event.getTarget(e);
    //TODO: pass what args?
    //var value = elTarget[elTarget.selectedIndex].value;
    oSelf.fireEvent("dropdownChangeEvent", {event:e, target:elTarget});
};







































/////////////////////////////////////////////////////////////////////////////
//
// Public member variables
//
/////////////////////////////////////////////////////////////////////////////


/////////////////////////////////////////////////////////////////////////////
//
// Public methods
//
/////////////////////////////////////////////////////////////////////////////

// OBJECT ACCESSORS

/**
 * Public accessor to the unique name of the DataSource instance.
 *
 * @method toString
 * @return {String} Unique name of the DataSource instance.
 */

YAHOO.widget.DataTable.prototype.toString = function() {
    return "DataTable " + this._sName;
};

/**
 * Returns the DataTable instance's DataSource instance.
 *
 * @method getDataSource
 * @return {YAHOO.util.DataSource} DataSource instance.
 */
YAHOO.widget.DataTable.prototype.getDataSource = function() {
    return this._oDataSource;
};

/**
 * Returns the DataTable instance's ColumnSet instance.
 *
 * @method getColumnSet
 * @return {YAHOO.widget.ColumnSet} ColumnSet instance.
 */
YAHOO.widget.DataTable.prototype.getColumnSet = function() {
    return this._oColumnSet;
};

/**
 * Returns the DataTable instance's RecordSet instance.
 *
 * @method getRecordSet
 * @return {YAHOO.widget.RecordSet} RecordSet instance.
 */
YAHOO.widget.DataTable.prototype.getRecordSet = function() {
    return this._oRecordSet;
};

/**
 * Returns the DataTable instance's Cell Editor as an object literal with the
 * following properties:
 * <dl>
 * <dt>cell</dt>
 * <dd>Cell element being edited</dd>
 *
 * <dt>column</dt>
 * <dd>Associated Column instance</dd>
 *
 * <dt>container</dt>
 * <dd>Reference to editor's container DIV element</dd>
 *
 * <dt>isActive</dt>
 * <dd>True if cell is currently being edited</dd>
 *
 * <dt>record</dt>
 * <dd>Associated Record instance</dd>
 *
 * <dt>validator</dt>
 * <dd>Associated validator function</dd>
 *
 * <dt>value</dt>
 * <dd>Current input value</dd>
 * </dl>
 *
 *
 *
 *
 *
 *
 * @method getCellEditor
 * @return {Object} Cell Editor object literal values.
 */
YAHOO.widget.DataTable.prototype.getCellEditor = function() {
    return this._oCellEditor;
};











































// DOM ACCESSORS

/**
 * Returns DOM reference to the DataTable's TABLE element.
 *
 * @method getTableEl
 * @return {HTMLElement} Reference to TABLE element.
 */
YAHOO.widget.DataTable.prototype.getTableEl = function() {
    return this._elTable;
};

/**
 * Returns DOM reference to the DataTable's THEAD element.
 *
 * @method getTheadEl
 * @return {HTMLElement} Reference to THEAD element.
 */
YAHOO.widget.DataTable.prototype.getTheadEl = function() {
    return this._elThead;
};

/**
 * Returns DOM reference to the DataTable's primary TBODY element.
 *
 * @method getTbodyEl
 * @return {HTMLElement} Reference to TBODY element.
 */
YAHOO.widget.DataTable.prototype.getTbodyEl = function() {
    return this._elTbody;
};
// Backward compatibility
YAHOO.widget.DataTable.prototype.getBody = function() {
    return this.getTbodyEl();
};

/**
 * Returns DOM reference to the DataTable's secondary TBODY element that is
 * used to display messages.
 *
 * @method getMsgTbodyEl
 * @return {HTMLElement} Reference to TBODY element.
 */
YAHOO.widget.DataTable.prototype.getMsgTbodyEl = function() {
    return this._elMsgTbody;
};

/**
 * Returns DOM reference to the TD element within the secondary TBODY that is
 * used to display messages.
 *
 * @method getMsgTdEl
 * @return {HTMLElement} Reference to TD element.
 */
YAHOO.widget.DataTable.prototype.getMsgTdEl = function() {
    return this._elMsgTd;
};

/**
 * Returns the corresponding TR reference for a given DOM element, ID string or
 * directly page row index. If the given identifier is a child of a TR element,
 * then DOM tree is traversed until a parent TR element is returned, otherwise
 * null.
 *
 * @method getTrEl
 * @param row {HTMLElement | String | Number | YAHOO.widget.Record} Which row to
 * get: by element reference, ID string, page row index, or Record.
 * @return {HTMLElement} Reference to TR element, or null.
 */
YAHOO.widget.DataTable.prototype.getTrEl = function(row) {
    var allRows = this._elTbody.rows;
    
    // By Record
    if(row instanceof YAHOO.widget.Record) {
        var nTrIndex = this.getTrIndex(row);
        return allRows[nTrIndex];
    }
    // By page row index
    else if(YAHOO.lang.isNumber(row) && (row > -1) && (row < allRows.length)) {
        return allRows[row];
    }
    // By ID string or element reference
    else {
        var elRow;
        var el = YAHOO.util.Dom.get(row);
        
        // Validate HTML element
        if(el && (el.ownerDocument == document)) {
            // Validate TR element
            if(el.tagName.toLowerCase() != "tr") {
                // Traverse up the DOM to find the corresponding TR element
                elRow = YAHOO.util.Dom.getAncestorByTagName(el,"tr");
            }
            else {
                elRow = el;
            }

            // Make sure the TR is in this TBODY
            if(elRow && (elRow.parentNode == this._elTbody)) {
                // Now we can return the TR element
                return elRow;
            }
        }
    }
    
    return null;
};
// Backward compatibility
YAHOO.widget.DataTable.prototype.getRow = function(index) {
    return this.getTrEl(index);
};

/**
 * Returns DOM reference to the first TR element in the DataTable page, or null.
 *
 * @method getFirstTrEl
 * @return {HTMLElement} Reference to TR element.
 */
YAHOO.widget.DataTable.prototype.getFirstTrEl = function() {
    return this._elTbody.rows[0] || null;
};

/**
 * Returns DOM reference to the last TR element in the DataTable page, or null.
 *
 * @method getLastTrEl
 * @return {HTMLElement} Reference to last TR element.
 */
YAHOO.widget.DataTable.prototype.getLastTrEl = function() {
    var allRows = this._elTbody.rows;
        if(allRows.length > 0) {
            return allRows[allRows.length-1] || null;
        }
};

/**
 * Returns DOM reference to the given TD element.
 *
 * @method getTdEl
 * @param cell {HTMLElement | String} DOM element reference or string ID.
 * @return {HTMLElement} Reference to TD element.
 */
YAHOO.widget.DataTable.prototype.getTdEl = function(cell) {
    var elCell;
    var el = YAHOO.util.Dom.get(cell);

    // Validate HTML element
    if(el && (el.ownerDocument == document)) {
        // Validate TD element
        if(el.tagName.toLowerCase() != "td") {
            // Traverse up the DOM to find the corresponding TR element
            elCell = YAHOO.util.Dom.getAncestorByTagName(el, "td");
        }
        else {
            elCell = el;
        }

        // Make sure the TD is in this TBODY
        if(elCell && (elCell.parentNode.parentNode == this._elTbody)) {
            // Now we can return the TD element
            return elCell;
        }
    }
    
    return null;
};

/**
 * Returns DOM reference to the TH element at given DataTable page coordinates, or null.
 *
 * @method getThEl
 * @param header {HTMLElement | String | YAHOO.widget.Column} DOM element
 * reference or string ID, or Column instance.
 * @return {HTMLElement} Reference to TH element.
 */
YAHOO.widget.DataTable.prototype.getThEl = function(header) {
    var elHeader;
        
    // Validate Column instance
    if(header instanceof YAHOO.widget.Column) {
        var oColumn = header;
        elHeader = YAHOO.util.Dom.get(this.id + "-col" + oColumn.getId());
        if(elHeader) {
            return elHeader;
        }
    }
    // Validate HTML element
    else {
        var el = YAHOO.util.Dom.get(header);

        if(el && (el.ownerDocument == document)) {
            // Validate TH element
            if(el.tagName.toLowerCase() != "th") {
                // Traverse up the DOM to find the corresponding TR element
                elHeader = YAHOO.util.Dom.getAncestorByTagName(el,"th");
            }
            else {
                elHeader = el;
            }

            // Make sure the TH is in this THEAD
            if(elHeader && (elHeader.parentNode.parentNode == this._elThead)) {
                // Now we can return the TD element
                return elHeader;
            }
        }
    }

    return null;
};

/**
 * Returns the page row index of given row. Returns null if the row is not in
 * view on the current DataTable page.
 *
 * @method getTrIndex
 * @param row {HTMLElement | String | YAHOO.widget.Record | Number} DOM or ID
 * string reference to an element within the DataTable page, a Record instance,
 * or a Record's RecordSet index.
 * @return {Number} Page row index, or null if row does not exist or is not in view.
 */
YAHOO.widget.DataTable.prototype.getTrIndex = function(row) {
    var nRecordIndex;
    
    // By Record
    if(row instanceof YAHOO.widget.Record) {
        nRecordIndex = this._oRecordSet.getRecordIndex(row);
    }
    // Calculate page row index from Record index
    else if(YAHOO.lang.isNumber(row)) {
        nRecordIndex = row;
    }
    if(YAHOO.lang.isNumber(nRecordIndex)) {
        // DataTable is paginated
        if(this.get("paginated")) {
            // Get the first and last Record on this page
            var startRecordIndex = this.get("paginator").startRecordIndex;
            var endRecordIndex = startRecordIndex + this.get("paginator").rowsPerPage - 1;
            // This Record is in view
            if((nRecordIndex >= startRecordIndex) && (nRecordIndex <= endRecordIndex)) {
                return nRecordIndex - startRecordIndex;
            }
            // This Record is not in view
            else {
                return null;
            }
        }
        // Not paginated, just return the Record index
        else {
            return nRecordIndex;
        }

    }
    // By element reference or ID string
    else {
        // Validate TR element
        elRow = this.getTrEl(row);
        if(elRow && (elRow.ownerDocument == document) &&
                (elRow.parentNode == this._elTbody)) {
            return elRow.sectionRowIndex;
        }
    }
    
    return null;
};














































// TABLE FUNCTIONS

/**
 * Resets a RecordSet with the given data and populates the page view
 * with the new data. Any previous data and selection states are cleared.
 * However, sort states are not cleared, so if the given data is in a particular
 * sort order, implementers should take care to reset the sortedBy property. If
 * pagination is enabled, the currentPage is shown and Paginator UI updated,
 * otherwise all rows are displayed as a single page. For performance, existing
 * DOM elements are reused when possible.
 *
 * @method initializeTable
 * @param oData {Object | Object[]} An object literal of data or an array of
 * object literals containing data.
 */
YAHOO.widget.DataTable.prototype.initializeTable = function(oData) {
    // Clear the RecordSet
    this._oRecordSet.reset();

    // Add data to RecordSet
    var records = this._oRecordSet.addRecords(oData);

    // Clear selections
    this._unselectAllTrEls();
    this._unselectAllTdEls();
    this._aSelections = null;
    this._sLastSelectedId = null;
    this._sSelectionAnchorId = null;

    // Refresh the view
    this.refreshView();
    this.fireEvent("initEvent");
};

/**
 * Refreshes the view with existing Records from the RecordSet while
 * maintaining sort, pagination, and selection states. For performance, reuses
 * existing DOM elements when possible while deleting extraneous elements.
 *
 * @method refreshView
 */
YAHOO.widget.DataTable.prototype.refreshView = function() {
    var i, j, k, l, aRecords;
    var oPaginator = this.updatePaginator();

    // Paginator is enabled, show a subset of Records and update Paginator UI
    if(this.get("paginated")) {
        var rowsPerPage = oPaginator.rowsPerPage;
        var startRecordIndex = (oPaginator.currentPage - 1) * rowsPerPage;
        aRecords = this._oRecordSet.getRecords(startRecordIndex, rowsPerPage);
        this.formatPaginators();
    }
    // Show all records
    else {
        aRecords = this._oRecordSet.getRecords();
    }

    var elTbody = this._elTbody;
    var elRows = elTbody.rows;

    // Has rows
    if(YAHOO.lang.isArray(aRecords) && (aRecords.length > 0)) {
        this.hideTableMessage();

        // Keep track of selected rows
        var aSelectedRows = this.getSelectedRows();
        // Keep track of selected cells
        var aSelectedCells = this.getSelectedCells();
        // Anything to reinstate?
        var bReselect = (aSelectedRows.length>0) || (aSelectedCells.length > 0);

        // Remove extra rows from the bottom so as to preserve ID order
        while(elTbody.hasChildNodes() && (elRows.length > aRecords.length)) {
            elTbody.deleteRow(-1);
        }

        // Unselect all TR and TD elements in the UI
        if(bReselect) {
            this._unselectAllTrEls();
            this._unselectAllTdEls();
        }

        // From the top, update in-place existing rows
        for(i=0; i<elRows.length; i++) {
            this._updateTrEl(elRows[i], aRecords[i]);
        }

        // Add TR elements as necessary
        for(i=elRows.length; i<aRecords.length; i++) {
            this._addTrEl(aRecords[i]);
        }

        // Reinstate selected and sorted classes
        var allRows = elTbody.rows;
        if(bReselect) {
            // Loop over each row
            for(j=0; j<allRows.length; j++) {
                var thisRow = allRows[j];
                var sMode = this.get("selectionMode");
                if ((sMode == "standard") || (sMode == "single")) {
                    // Set SELECTED
                    for(k=0; k<aSelectedRows.length; k++) {
                        if(aSelectedRows[k] === thisRow.yuiRecordId) {
                            YAHOO.util.Dom.addClass(thisRow, YAHOO.widget.DataTable.CLASS_SELECTED);
                            if(j === allRows.length-1) {
                                this._sLastSelectedId = thisRow.id;
                                this._sSelectionAnchorId = thisRow.id;
                            }
                        }
                    }
                }
                else {
                    // Loop over each cell
                    for(k=0; k<thisRow.cells.length; k++) {
                        var thisCell = thisRow.cells[k];
                        // Set SELECTED
                        for(l=0; l<aSelectedCells.length; l++) {
                            if((aSelectedCells[l].recordId === thisRow.yuiRecordId) &&
                                    (aSelectedCells[l].columnId === thisCell.yuiColumnId)) {
                                YAHOO.util.Dom.addClass(thisCell, YAHOO.widget.DataTable.CLASS_SELECTED);
                                if(k === thisRow.cells.length-1) {
                                    this._sLastSelectedId = thisCell.id;
                                    this._sSelectionAnchorId = thisCell.id;
                                }
                            }
                        }
                    }
                }
            }
        }
        
        // Set FIRST/LAST, EVEN/ODD
        this._setFirstRow();
        this._setLastRow();
        this._setRowStripes();

        this.fireEvent("refreshEvent");
    }
    // Empty
    else {
        // Remove all rows
        while(elTbody.hasChildNodes()) {
            elTbody.deleteRow(-1);
        }

        this.showTableMessage(YAHOO.widget.DataTable.MSG_EMPTY, YAHOO.widget.DataTable.CLASS_EMPTY);
    }
};

/**
 * Nulls out the entire DataTable instance and related objects, removes attached
 * event listeners, and clears out DOM elements inside the container. After
 * calling this method, the instance reference should be expliclitly nulled by
 * implementer, as in myDataTable = null. Use with caution!
 *
 * @method destroy
 */
YAHOO.widget.DataTable.prototype.destroy = function() {
    // Destroy Cell Editor
    YAHOO.util.Event.purgeElement(this._oCellEditor.container, true);
    document.body.removeChild(this._oCellEditor.container);
    
    var instanceName = this.toString();
    var elContainer = this._elContainer;

    // Unhook custom events
    this._oRecordSet.unsubscribeAll();
    this.unsubscribeAll();

    // Unhook DOM events
    YAHOO.util.Event.purgeElement(elContainer, true);

    // Remove DOM elements
    elContainer.innerHTML = "";

    // Null out objects
    for(var param in this) {
        if(this.hasOwnProperty(param)) {
            this[param] = null;
        }
    }

};

/**
 * Displays message within secondary TBODY.
 *
 * @method showTableMessage
 * @param sHTML {String} (optional) Value for innerHTML.
 * @param sClassName {String} (optional) Classname.
 */
YAHOO.widget.DataTable.prototype.showTableMessage = function(sHTML, sClassName) {
    var elCell = this._elMsgTd;
    if(YAHOO.lang.isString(sHTML)) {
        elCell.innerHTML = sHTML;
    }
    if(YAHOO.lang.isString(sClassName)) {
        YAHOO.util.Dom.addClass(elCell, sClassName);
    }
    this._elMsgTbody.style.display = "";
    this.fireEvent("tableMsgShowEvent", {html:sHTML, className:sClassName});
};

/**
 * Hides secondary TBODY.
 *
 * @method hideTableMessage
 */
YAHOO.widget.DataTable.prototype.hideTableMessage = function() {
    if(this._elMsgTbody.style.display != "none") {
        this._elMsgTbody.style.display = "none";
        this.fireEvent("tableMsgHideEvent");
    }
};

/**
 * Brings focus to DataTable instance.
 *
 * @method focus
 */
YAHOO.widget.DataTable.prototype.focus = function() {
    this._focusEl(this._elTable);
};


































































// RECORDSET FUNCTIONS

/**
 * Returns Record index for given TR element or page row index.
 *
 * @method getRecordIndex
 * @param row {YAHOO.widget.Record | HTMLElement | Number} Record instance, TR
 * element reference or page row index.
 * @return {Number} Record's RecordSet index, or null.
 */
YAHOO.widget.DataTable.prototype.getRecordIndex = function(row) {
    var nTrIndex;

    if(!YAHOO.lang.isNumber(row)) {
        // By Record
        if(row instanceof YAHOO.widget.Record) {
            return this._oRecordSet.getRecordIndex(row);
        }
        // By element reference
        else {
            // Find the TR element
            var el = this.getTrEl(row);
            if(el) {
                nTrIndex = el.sectionRowIndex;
            }
        }
    }
    // By page row index
    else {
        nTrIndex = row;
    }

    if(YAHOO.lang.isNumber(nTrIndex)) {
        if(this.get("paginated")) {
            return this.get("paginator").startRecordIndex + nTrIndex;
        }
        else {
            return nTrIndex;
        }
    }

    return null;
};

/**
 * For the given identifier, returns the associated Record instance.
 *
 * @method getRecord
 * @param row {HTMLElement | String | Number} RecordSet position index, DOM
 * reference or ID string to an element within the DataTable page.
 * @return {YAHOO.widget.Record} Record instance.
 */
YAHOO.widget.DataTable.prototype.getRecord = function(row) {
    var nRecordIndex = row;
    
    // By element reference or ID string
    if(!YAHOO.lang.isNumber(nRecordIndex)) {
        // Validate TR element
        var elRow = this.getTrEl(row);
        if(elRow) {
            nRecordIndex = this.getRecordIndex(row);
        }
    }
    // By Record index
    if(YAHOO.lang.isNumber(nRecordIndex)) {
        return this._oRecordSet.getRecord(nRecordIndex);
    }
    
    return null;
};














































// COLUMN FUNCTIONS

/**
 * For the given identifier, returns the associated Column instance.
 *
 * @method getColumn
 * @param column {HTMLElement | String | Number} ColumnSet.keys position index, DOM
 * reference or ID string to an element within the DataTable page.
 * @return {YAHOO.widget.Column} Column instance.
 */
 YAHOO.widget.DataTable.prototype.getColumn = function(column) {
    var nColumnIndex = column;

    // By element reference or ID string
    if(!YAHOO.lang.isNumber(nColumnIndex)) {
        // Validate TD element
        var elCell = this.getTdEl(column);
        if(elCell) {
            nColumnIndex = elCell.yuiColumnId;
        }
        // Validate TH element
        else {
            elCell = this.getThEl(column);
            if(elCell) {
                nColumnIndex = elCell.yuiColumnId;
            }
        }
    }
    
    // By Column index
    if(YAHOO.lang.isNumber(nColumnIndex)) {
        return this._oColumnSet.getColumn(nColumnIndex);
    }

    return null;
 };

/**
 * Sorts given Column.
 *
 * @method sortColumn
 * @param oColumn {YAHOO.widget.Column} Column instance.
 */
YAHOO.widget.DataTable.prototype.sortColumn = function(oColumn) {
    if(!oColumn) {
        return;
    }
    if(!oColumn instanceof YAHOO.widget.Column) {
        //TODO: accept the TH or TH.key
        //TODO: Get the column based on TH.yuiColumnId
        return;
    }
    if(oColumn.sortable) {
        // What is the default sort direction?
        var sortDir = (oColumn.sortOptions && oColumn.sortOptions.defaultOrder) ? oColumn.sortOptions.defaultOrder : "asc";

        // Already sorted?
        var oSortedBy = this.get("sortedBy");
        if(oSortedBy && (oSortedBy.key === oColumn.key)) {
            if(oSortedBy.dir) {
                sortDir = (oSortedBy.dir == "asc") ? "desc" : "asc";
            }
            else {
                sortDir = (sortDir == "asc") ? "desc" : "asc";
            }
        }

        // Is there a custom sort handler function defined?
        var sortFnc = (oColumn.sortOptions && YAHOO.lang.isFunction(oColumn.sortOptions.sortFunction)) ?
                oColumn.sortOptions.sortFunction : function(a, b, desc) {
                    var sorted = YAHOO.util.Sort.compare(a.getData(oColumn.key),b.getData(oColumn.key), desc);
                    if(sorted === 0) {
                        return YAHOO.util.Sort.compare(a.getId(),b.getId(), desc);
                    }
                    else {
                        return sorted;
                    }
        };

        // Do the actual sort
        var desc = (sortDir == "desc") ? true : false;
        this._oRecordSet.sortRecords(sortFnc, desc);

        // Update sortedBy tracker
        this.set("sortedBy", {key:oColumn.key, dir:sortDir, column:oColumn});
        
        // Reset to first page
        //TODO: Keep selection in view
        this.updatePaginator({currentPage:1});

        // Update the UI
        this.refreshView();

        this.fireEvent("columnSortEvent",{column:oColumn,dir:sortDir});
    }
    else {
        //TODO
    }
};













































// ROW FUNCTIONS


/**
 * Adds one new Record of data into the RecordSet at the index if given,
 * otherwise at the end. If the new Record is in page view, the
 * corresponding DOM elements are also updated.
 *
 * @method addRow
 * @param oData {Object} Object literal of data for the row.
 * @param index {Number} (optional) RecordSet position index at which to add data.
 */
YAHOO.widget.DataTable.prototype.addRow = function(oData, index) {
    if(oData && (oData.constructor == Object)) {
        var oRecord = this._oRecordSet.addRecord(oData, index);
        if(oRecord) {
            var nTrIndex = this.getTrIndex(oRecord);

            // Row is in view
            if(YAHOO.lang.isNumber(nTrIndex)) {
                // Paginated so just refresh the view to keep pagination state
                if(this.get("paginated")) {
                    this.refreshView();
                }
                // Add the TR element
                else {
                    var newTrId = this._addTrEl(oRecord, nTrIndex);
                    if(newTrId) {
                        // Is this an insert or an append?
                        var append = (YAHOO.lang.isNumber(nTrIndex) &&
                                (nTrIndex == this._elTbody.rows.length-1)) ? true : false;

                        // Stripe the one new row
                        if(append) {
                            if((this._elTbody.rows.length-1)%2) {
                                YAHOO.util.Dom.addClass(newTrId, YAHOO.widget.DataTable.CLASS_ODD);
                            }
                            else {
                                YAHOO.util.Dom.addClass(newTrId, YAHOO.widget.DataTable.CLASS_EVEN);
                            }
                        }
                        // Restripe all the rows after the new one
                        else {
                            this._setRowStripes(nTrIndex);
                        }

                        // If new row is at the bottom
                        if(append) {
                            this._setLastRow();
                        }
                        // If new row is at the top
                        else if(YAHOO.lang.isNumber(index) && (nTrIndex === 0)) {
                            this._setFirstRow();
                        }
                    }
                }
            }
            // Record is not in view so just update pagination UI
            else {
                this.updatePaginator();
            }

            // TODO: what args to pass?
            this.fireEvent("rowAddEvent", {record:oRecord});

            // For log message
            nTrIndex = (YAHOO.lang.isValue(nTrIndex))? nTrIndex : "n/a";

            return;
        }
    }
};

/**
 * Convenience method to add multiple rows.
 *
 * @method addRows
 * @param aData {Object[]} Array of object literal data for the rows.
 * @param index {Number} (optional) RecordSet position index at which to add data.
 */
YAHOO.widget.DataTable.prototype.addRows = function(aData, index) {
    if(YAHOO.lang.isArray(aData)) {
        var i;
        if(YAHOO.lang.isNumber(index)) {
            for(i=aData.length-1; i>-1; i--) {
                this.addRow(aData[i], index);
            }
        }
        else {
            for(i=0; i<aData.length; i++) {
                this.addRow(aData[i]);
            }
        }
    }
    else {
    }
};

/**
 * For the given row, updates the associated Record with the given data. If the
 * row is in view, the corresponding DOM elements are also updated.
 *
 * @method updateRow
 * @param row {YAHOO.widget.Record | Number | HTMLElement | String}
 * Which row to update: By Record instance, by Record's RecordSet
 * position index, by HTMLElement reference to the TR element, or by ID string
 * of the TR element.
 * @param oData {Object} Object literal of data for the row.
 */
YAHOO.widget.DataTable.prototype.updateRow = function(row, oData) {
    var oldRecord, updatedRecord, elRow;

    // Get the Record directly
    if((row instanceof YAHOO.widget.Record) || (YAHOO.lang.isNumber(row))) {
            // Get the Record directly
            oldRecord = this._oRecordSet.getRecord(row);
            
            // Is this row in view?
            elRow = this.getTrEl(oldRecord);
    }
    // Get the Record by TR element
    else {
        elRow = this.getTrEl(row);
        if(elRow) {
            oldRecord = this._oRecordSet.getRecord(this.getRecordIndex(elRow));
        }
    }

    // Update the Record
    if(oldRecord) {
        // Copy data from the Record for the event that gets fired later
        var oRecordData = oldRecord.getData();
        var oldData = {};
        for(var param in oRecordData) {
            oldData[param] = oRecordData[param];
        }

        updatedRecord = this._oRecordSet.updateRecord(oldRecord, oData);
    }
    else {
        return;

    }
    
    // Update the TR only if row is in view
    if(elRow) {
        this._updateTrEl(elRow, updatedRecord);
    }

    this.fireEvent("rowUpdateEvent", {record:updatedRecord, oldData:oldData});
};

/**
 * Deletes the given row's Record from the RecordSet. If the row is in view, the
 * corresponding DOM elements are also deleted.
 *
 * @method deleteRow
 * @param row {HTMLElement | String | Number} DOM element reference or ID string
 * to DataTable page element or RecordSet index.
 */
YAHOO.widget.DataTable.prototype.deleteRow = function(row) {
    // Get the Record index...
    var nRecordIndex = null;
    // ...by Record index
    if(YAHOO.lang.isNumber(row)) {
        nRecordIndex = row;
    }
    // ...by element reference
    else {
        var elRow = YAHOO.util.Dom.get(row);
        elRow = this.getTrEl(elRow);
        if(elRow) {
            nRecordIndex = this.getRecordIndex(elRow);
        }
    }
    if(nRecordIndex !== null) {
        var oRecord = this._oRecordSet.getRecord(nRecordIndex);
        if(oRecord) {
            var nRecordId = oRecord.getId();
            
            // Remove from selection tracker if there
            var tracker = this._aSelections || [];
            for(var j=0; j<tracker.length; j++) {
                if((YAHOO.lang.isNumber(tracker[j]) && (tracker[j] === nRecordId)) ||
                        ((tracker[j].constructor == Object) && (tracker[j].recordId === nRecordId))) {
                    tracker.splice(j,1);
                }
            }

            // Copy data from the Record for the event that gets fired later
            var oRecordData = oRecord.getData();
            var oData = {};
            for(var param in oRecordData) {
                oData[param] = oRecordData[param];
            }

            // Delete Record from RecordSet
            this._oRecordSet.deleteRecord(nRecordIndex);

            // If row is in view, delete the TR element
            var nTrIndex = this.getTrIndex(nRecordIndex);
            if(YAHOO.lang.isNumber(nTrIndex)) {
                var isLast = (nTrIndex == this.getLastTrEl().sectionRowIndex) ?
                        true : false;
                this._deleteTrEl(nTrIndex);

                // Empty body
                if(this._elTbody.rows.length === 0) {
                    this.showTableMessage(YAHOO.widget.DataTable.MSG_EMPTY, YAHOO.widget.DataTable.CLASS_EMPTY);
                }
                // Update UI
                else {
                    // Set FIRST/LAST
                    if(nTrIndex === 0) {
                        this._setFirstRow();
                    }
                    if(isLast) {
                        this._setLastRow();
                    }
                    // Set EVEN/ODD
                    if(nTrIndex != this._elTbody.rows.length) {
                        this._setRowStripes(nTrIndex);
                    }
                }
            }

            this.fireEvent("rowDeleteEvent", {recordIndex:nRecordIndex,
                    oldData:oData, trElIndex:nTrIndex});
        }
    }
    else {
    }
};

/**
 * Convenience method to delete multiple rows.
 *
 * @method deleteRows
 * @param row {HTMLElement | String | Number} DOM element reference or ID string
 * to DataTable page element or RecordSet index.
 * @param count {Number} (optional) How many rows to delete. A negative value
 * will delete towards the beginning.
 */
YAHOO.widget.DataTable.prototype.deleteRows = function(row, count) {
    // Get the Record index...
    var nRecordIndex = null;
    // ...by Record index
    if(YAHOO.lang.isNumber(row)) {
        nRecordIndex = row;
    }
    // ...by element reference
    else {
        var elRow = YAHOO.util.Dom.get(row);
        elRow = this.getTrEl(elRow);
        if(elRow) {
            nRecordIndex = this.getRecordIndex(elRow);
        }
    }
    if(nRecordIndex !== null) {
        if(count && YAHOO.lang.isNumber(count)) {
            // Start with highest index and work down
            var startIndex = (count > 0) ? nRecordIndex + count -1 : nRecordIndex;
            var endIndex = (count > 0) ? nRecordIndex : nRecordIndex + count + 1;
            for(var i=startIndex; i>endIndex-1; i--) {
                this.deleteRow(i);
            }
        }
        else {
            this.deleteRow(nRecordIndex);
        }
    }
    else {
    }
};














































// CELL FUNCTIONS

/**
 * Outputs markup into the given TD based on given Record.
 *
 * @method formatCell
 * @param elCell {HTMLElement} TD Element.
 * @param oRecord {YAHOO.widget.Record} (Optional) Record instance.
 * @param oColumn {YAHOO.widget.Column} (Optional) Column instance.
 * @return {HTML} Markup.
 */
YAHOO.widget.DataTable.prototype.formatCell = function(elCell, oRecord, oColumn) {
    if(!(oRecord instanceof YAHOO.widget.Record)) {
        oRecord = this.getRecord(elCell);
    }
    if(!(oColumn instanceof YAHOO.widget.Column)) {
        oColumn = this._oColumnSet.getColumn(elCell.yuiColumnId);
    }
    
    if(oRecord && oColumn) {
        var oData = oRecord.getData(oColumn.key);

        var fnFormatter;
        if(YAHOO.lang.isString(oColumn.formatter)) {
            switch(oColumn.formatter) {
                case "button":
                    fnFormatter = YAHOO.widget.DataTable.formatButton;
                    break;
                case "checkbox":
                    fnFormatter = YAHOO.widget.DataTable.formatCheckbox;
                    break;
                case "currency":
                    fnFormatter = YAHOO.widget.DataTable.formatCurrency;
                    break;
                case "date":
                    fnFormatter = YAHOO.widget.DataTable.formatDate;
                    break;
                case "dropdown":
                    fnFormatter = YAHOO.widget.DataTable.formatDropdown;
                    break;
                case "email":
                    fnFormatter = YAHOO.widget.DataTable.formatEmail;
                    break;
                case "link":
                    fnFormatter = YAHOO.widget.DataTable.formatLink;
                    break;
                case "number":
                    fnFormatter = YAHOO.widget.DataTable.formatNumber;
                    break;
                case "radio":
                    fnFormatter = YAHOO.widget.DataTable.formatRadio;
                    break;
                case "text":
                    fnFormatter = YAHOO.widget.DataTable.formatText;
                    break;
                case "textarea":
                    fnFormatter = YAHOO.widget.DataTable.formatTextarea;
                    break;
                case "textbox":
                    fnFormatter = YAHOO.widget.DataTable.formatTextbox;
                    break;
                case "html":
                    // This is the default
                    break;
                default:
                    fnFormatter = null;
            }
        }
        else if(YAHOO.lang.isFunction(oColumn.formatter)) {
            fnFormatter = oColumn.formatter;
        }

        // Apply special formatter
        if(fnFormatter) {
            fnFormatter.call(this, elCell, oRecord, oColumn, oData);
        }
        else {
            elCell.innerHTML = (YAHOO.lang.isValue(oData)) ? oData.toString() : "";
        }

        // Add custom classNames
        var aCustomClasses = null;
        if(YAHOO.lang.isString(oColumn.className)) {
            aCustomClasses = [oColumn.className];
        }
        else if(YAHOO.lang.isArray(oColumn.className)) {
            aCustomClasses = oColumn.className;
        }
        if(aCustomClasses) {
            for(var i=0; i<aCustomClasses.length; i++) {
                YAHOO.util.Dom.addClass(elCell, aCustomClasses[i]);
            }
        }
        
        YAHOO.util.Dom.addClass(elCell, "yui-dt-col-"+oColumn.key);

        // Is editable?
        if(oColumn.editor) {
            YAHOO.util.Dom.addClass(elCell,YAHOO.widget.DataTable.CLASS_EDITABLE);
        }
        
        this.fireEvent("cellFormatEvent", {record:oRecord, key:oColumn.key, el:elCell});
    }
    else {
    }
};


/**
 * Formats a BUTTON element.
 *
 * @method DataTable.formatButton
 * @param el {HTMLElement} The element to format with markup.
 * @param oRecord {YAHOO.widget.Record} Record instance.
 * @param oColumn {YAHOO.widget.Column} Column instance.
 * @param oData {Object | Boolean} Data value for the cell. By default, the value
 * is what gets written to the BUTTON.
 * @static
 */
YAHOO.widget.DataTable.formatButton= function(el, oRecord, oColumn, oData) {
    var sValue = YAHOO.lang.isValue(oData) ? oData : "Click";
    //TODO: support YAHOO.widget.Button
    //if(YAHOO.widget.Button) {
    
    //}
    //else {
        el.innerHTML = "<button type=\"button\" class=\""+
                YAHOO.widget.DataTable.CLASS_BUTTON + "\">" + sValue + "</button>";
    //}
};

/**
 * Formats a CHECKBOX element.
 *
 * @method DataTable.formatCheckbox
 * @param el {HTMLElement} The element to format with markup.
 * @param oRecord {YAHOO.widget.Record} Record instance.
 * @param oColumn {YAHOO.widget.Column} Column instance.
 * @param oData {Object | Boolean} Data value for the cell. Can be a simple
 * Boolean to indicate whether checkbox is checked or not. Can be object literal
 * {checked:bBoolean, label:sLabel}. Other forms of oData require a custom
 * formatter.
 * @static
 */
YAHOO.widget.DataTable.formatCheckbox = function(el, oRecord, oColumn, oData) {
    var bChecked = oData;
    bChecked = (bChecked) ? " checked" : "";
    el.innerHTML = "<input type=\"checkbox\"" + bChecked +
            " class=\"" + YAHOO.widget.DataTable.CLASS_CHECKBOX + "\">";
};

/**
 * Formats currency. Default unit is USD.
 *
 * @method DataTable.formatCurrency
 * @param el {HTMLElement} The element to format with markup.
 * @param oRecord {YAHOO.widget.Record} Record instance.
 * @param oColumn {YAHOO.widget.Column} Column instance.
 * @param oData {Number} Data value for the cell.
 * @static
 */
YAHOO.widget.DataTable.formatCurrency = function(el, oRecord, oColumn, oData) {
    if(YAHOO.lang.isNumber(oData)) {
        var nAmount = oData;
        var markup;

        // Round to the penny
        nAmount = Math.round(nAmount*100)/100;

        // Default currency is USD
        markup = "$"+nAmount;

        // Normalize digits
        var dotIndex = markup.indexOf(".");
        if(dotIndex < 0) {
            markup += ".00";
        }
        else {
            while(dotIndex > markup.length-3) {
                markup += "0";
            }
        }
        el.innerHTML = markup;
    }
    else {
        el.innerHTML = YAHOO.lang.isValue(oData) ? oData : "";
    }
};

/**
 * Formats JavaScript Dates.
 *
 * @method DataTable.formatDate
 * @param el {HTMLElement} The element to format with markup.
 * @param oRecord {YAHOO.widget.Record} Record instance.
 * @param oColumn {YAHOO.widget.Column} Column instance.
 * @param oData {Object} Data value for the cell, or null.
 * @static
 */
YAHOO.widget.DataTable.formatDate = function(el, oRecord, oColumn, oData) {
    var oDate = oData;
    if(oDate instanceof Date) {
        el.innerHTML = (oDate.getMonth()+1) + "/" + oDate.getDate()  + "/" + oDate.getFullYear();
    }
    else {
        el.innerHTML = YAHOO.lang.isValue(oData) ? oData : "";
    }
};

/**
 * Formats SELECT elements.
 *
 * @method DataTable.formatDropdown
 * @param el {HTMLElement} The element to format with markup.
 * @param oRecord {YAHOO.widget.Record} Record instance.
 * @param oColumn {YAHOO.widget.Column} Column instance.
 * @param oData {Object} Data value for the cell, or null.
 * @static
 */
YAHOO.widget.DataTable.formatDropdown = function(el, oRecord, oColumn, oData) {
    var selectedValue = (YAHOO.lang.isValue(oData)) ? oData : oRecord.getData(oColumn.key);
    var options = (YAHOO.lang.isArray(oColumn.dropdownOptions)) ?
            oColumn.dropdownOptions : null;

    var selectEl;
    var collection = el.getElementsByTagName("select");
    
    // Create the form element only once, so we can attach the onChange listener
    if(collection.length === 0) {
        // Create SELECT element
        selectEl = document.createElement("select");
        YAHOO.util.Dom.addClass(selectEl, YAHOO.widget.DataTable.CLASS_DROPDOWN);
        selectEl = el.appendChild(selectEl);

        // Add event listener
        //TODO: static method doesn't have access to the datatable instance...
        YAHOO.util.Event.addListener(selectEl,"change",oDataTable._onDropdownChange,oDataTable);
    }

    selectEl = collection[0];

    // Update the form element
    if(selectEl) {
        // Clear out previous options
        selectEl.innerHTML = "";
        
        // We have options to populate
        if(options) {
            // Create OPTION elements
            for(var i=0; i<options.length; i++) {
                var option = options[i];
                var optionEl = document.createElement("option");
                optionEl.value = (YAHOO.lang.isValue(option.value)) ?
                        option.value : option;
                optionEl.innerHTML = (YAHOO.lang.isValue(option.text)) ?
                        option.text : option;
                optionEl = selectEl.appendChild(optionEl);
            }
        }
        // Selected value is our only option
        else {
            selectEl.innerHTML = "<option value=\"" + selectedValue + "\">" + selectedValue + "</option>";
        }
    }
    else {
        el.innerHTML = YAHOO.lang.isValue(oData) ? oData : "";
    }
};

/**
 * Formats emails.
 *
 * @method DataTable.formatEmail
 * @param el {HTMLElement} The element to format with markup.
 * @param oRecord {YAHOO.widget.Record} Record instance.
 * @param oColumn {YAHOO.widget.Column} Column instance.
 * @param oData {Object} Data value for the cell, or null.
 * @static
 */
YAHOO.widget.DataTable.formatEmail = function(el, oRecord, oColumn, oData) {
    if(YAHOO.lang.isString(oData)) {
        el.innerHTML = "<a href=\"mailto:" + oData + "\">" + oData + "</a>";
    }
    else {
        el.innerHTML = YAHOO.lang.isValue(oData) ? oData : "";
    }
};

/**
 * Formats links.
 *
 * @method DataTable.formatLink
 * @param el {HTMLElement} The element to format with markup.
 * @param oRecord {YAHOO.widget.Record} Record instance.
 * @param oColumn {YAHOO.widget.Column} Column instance.
 * @param oData {Object} Data value for the cell, or null.
 * @static
 */
YAHOO.widget.DataTable.formatLink = function(el, oRecord, oColumn, oData) {
    if(YAHOO.lang.isString(oData)) {
        el.innerHTML = "<a href=\"" + oData + "\">" + oData + "</a>";
    }
    else {
        el.innerHTML = YAHOO.lang.isValue(oData) ? oData : "";
    }
};

/**
 * Formats numbers.
 *
 * @method DataTable.formatNumber
 * @param el {HTMLElement} The element to format with markup.
 * @param oRecord {YAHOO.widget.Record} Record instance.
 * @param oColumn {YAHOO.widget.Column} Column instance.
 * @param oData {Object} Data value for the cell, or null.
 * @static
 */
YAHOO.widget.DataTable.formatNumber = function(el, oRecord, oColumn, oData) {
    if(YAHOO.lang.isNumber(oData)) {
        el.innerHTML = oData;
    }
    else {
        el.innerHTML = YAHOO.lang.isValue(oData) ? oData : "";
    }
};

/**
 * Formats INPUT TYPE=RADIO elements.
 *
 * @method DataTable.formatRadio
 * @param el {HTMLElement} The element to format with markup.
 * @param oRecord {YAHOO.widget.Record} Record instance.
 * @param oColumn {YAHOO.widget.Column} Column instance.
 * @param oData {Object} (Optional) Data value for the cell.
 * @static
 */
YAHOO.widget.DataTable.formatRadio = function(el, oRecord, oColumn, oData) {
    var bChecked = oData;
    bChecked = (bChecked) ? " checked" : "";
    el.innerHTML = "<input type=\"radio\"" + bChecked +
            " name=\"" + oColumn.getId() + "-radio\"" +
            " class=\"" + YAHOO.widget.DataTable.CLASS_CHECKBOX + "\">";
};

/**
 * Formats text strings.
 *
 * @method DataTable.formatText
 * @param el {HTMLElement} The element to format with markup.
 * @param oRecord {YAHOO.widget.Record} Record instance.
 * @param oColumn {YAHOO.widget.Column} Column instance.
 * @param oData {Object} (Optional) Data value for the cell.
 * @static
 */
YAHOO.widget.DataTable.formatText = function(el, oRecord, oColumn, oData) {
    var value = (YAHOO.lang.isValue(oRecord.getData(oColumn.key))) ?
            oRecord.getData(oColumn.key) : "";
    //TODO: move to util function
    el.innerHTML = value.toString().replace(/&/g, "&#38;").replace(/</g, "&#60;").replace(/>/g, "&#62;");
};

/**
 * Formats TEXTAREA elements.
 *
 * @method DataTable.formatTextarea
 * @param el {HTMLElement} The element to format with markup.
 * @param oRecord {YAHOO.widget.Record} Record instance.
 * @param oColumn {YAHOO.widget.Column} Column instance.
 * @param oData {Object} (Optional) Data value for the cell.
 * @static
 */
YAHOO.widget.DataTable.formatTextarea = function(el, oRecord, oColumn, oData) {
    var value = (YAHOO.lang.isValue(oRecord.getData(oColumn.key))) ?
            oRecord.getData(oColumn.key) : "";
    var markup = "<textarea>" + value + "</textarea>";
    el.innerHTML = markup;
};

/**
 * Formats INPUT TYPE=TEXT elements.
 *
 * @method DataTable.formatTextbox
 * @param el {HTMLElement} The element to format with markup.
 * @param oRecord {YAHOO.widget.Record} Record instance.
 * @param oColumn {YAHOO.widget.Column} Column instance.
 * @param oData {Object} (Optional) Data value for the cell.
 * @static
 */
YAHOO.widget.DataTable.formatTextbox = function(el, oRecord, oColumn, oData) {
    var value = (YAHOO.lang.isValue(oRecord.getData(oColumn.key))) ?
            oRecord.getData(oColumn.key) : "";
    var markup = "<input type=\"text\" value=\"" + value + "\">";
    el.innerHTML = markup;
};
















































// PAGINATION

/**
 * Updates Paginator values in response to RecordSet changes and/or DOM events.
 * Pass in all, a subset, or no values.
 *
 * @method updatePaginator
 * @param oNewValues {Object} (Optional) Object literal of Paginator values, or
 * a subset of Paginator values.
 * @param {Object} Object literal of all Paginator values.
 */

YAHOO.widget.DataTable.prototype.updatePaginator = function(oNewValues) {
    // Complete the set
    var oValidPaginator = this.get("paginator");
    for(var param in oNewValues) {
        if(oValidPaginator.hasOwnProperty(param)) {
            oValidPaginator[param] = oNewValues[param];
        }
    }
    
    oValidPaginator.totalRecords = this._oRecordSet.getLength();
    oValidPaginator.rowsThisPage = Math.min(oValidPaginator.rowsPerPage, oValidPaginator.totalRecords);
    oValidPaginator.totalPages = Math.ceil(oValidPaginator.totalRecords / oValidPaginator.rowsThisPage);
    if(isNaN(oValidPaginator.totalPages)) {
        oValidPaginator.totalPages = 0;
    }

    this.set("paginator", oValidPaginator);
    return this.get("paginator");
};

/**
 * Displays given page of a paginated DataTable.
 *
 * @method showPage
 * @param nPage {Number} Which page.
 */
YAHOO.widget.DataTable.prototype.showPage = function(nPage) {
    // Validate input
    if(!YAHOO.lang.isNumber(nPage) || (nPage < 1) || (nPage > this.get("paginator").totalPages)) {
        nPage = 1;
    }
    this.updatePaginator({currentPage:nPage});
    this.refreshView();
};

/**
 * Updates Paginator containers with markup. Override this method to customize pagination UI.
 *
 * @method formatPaginators
 */
 YAHOO.widget.DataTable.prototype.formatPaginators = function() {
    var pag = this.get("paginator");

    // For Opera workaround
    var dropdownEnabled = false;

    // Links are enabled
    if(pag.pageLinks > -1) {
        for(var i=0; i<pag.links.length; i++) {
            this.formatPaginatorLinks(pag.links[i], pag.currentPage, pag.pageLinksStart, pag.pageLinks, pag.totalPages);
        }
    }

    // Dropdown is enabled
    for(i=0; i<pag.dropdowns.length; i++) {
         if(pag.dropdownOptions) {
            dropdownEnabled = true;
            this.formatPaginatorDropdown(pag.dropdowns[i], pag.dropdownOptions);
        }
        else {
            pag.dropdowns[i].style.display = "none";
        }
    }

    // For Opera artifacting in dropdowns
    if(dropdownEnabled && navigator.userAgent.toLowerCase().indexOf("opera") != -1) {
        document.body.style += '';
    }
};

/**
 * Updates Paginator dropdown. If dropdown doesn't exist, the markup is created.
 * Sets dropdown elements's "selected" value.
 *
 * @method formatPaginatorDropdown
 * @param elDropdown {HTMLElement} The SELECT element.
 * @param dropdownOptions {Object[]} OPTION values for display in the SELECT element.
 */
YAHOO.widget.DataTable.prototype.formatPaginatorDropdown = function(elDropdown, dropdownOptions) {
    if(elDropdown && (elDropdown.ownerDocument == document)) {
        // Clear OPTION elements
        while (elDropdown.firstChild) {
            elDropdown.removeChild(elDropdown.firstChild);
        }

        // Create OPTION elements
        for(var j=0; j<dropdownOptions.length; j++) {
            var dropdownOption = dropdownOptions[j];
            var optionEl = document.createElement("option");
            optionEl.value = (YAHOO.lang.isValue(dropdownOption.value)) ?
                    dropdownOption.value : dropdownOption;
            optionEl.innerHTML = (YAHOO.lang.isValue(dropdownOption.text)) ?
                    dropdownOption.text : dropdownOption;
            optionEl = elDropdown.appendChild(optionEl);
        }

        var options = elDropdown.options;
        // Update dropdown's "selected" value
        if(options.length) {
            for(var i=options.length-1; i>-1; i--) {
                if((this.get("paginator").rowsPerPage + "") === options[i].value) {
                    options[i].selected = true;
                }
            }
        }

        // Show the dropdown
        elDropdown.style.display = "";
        return;
    }
};

/**
 * Updates Paginator links container with markup.
 *
 * @method formatPaginatorLinks
 * @param elContainer {HTMLElement} The link container element.
 * @param nCurrentPage {Number} Current page.
 * @param nPageLinksStart {Number} First page link to display.
 * @param nPageLinksLength {Number} How many page links to display.
 * @param nTotalPages {Number} Total number of pages.
 */
YAHOO.widget.DataTable.prototype.formatPaginatorLinks = function(elContainer, nCurrentPage, nPageLinksStart, nPageLinksLength, nTotalPages) {
    if(elContainer && (elContainer.ownerDocument == document) &&
            YAHOO.lang.isNumber(nCurrentPage) && YAHOO.lang.isNumber(nPageLinksStart) &&
            YAHOO.lang.isNumber(nTotalPages)) {
        // Set up markup for first/last/previous/next
        var bIsFirstPage = (nCurrentPage == 1) ? true : false;
        var bIsLastPage = (nCurrentPage == nTotalPages) ? true : false;
        var sFirstLinkMarkup = (bIsFirstPage) ?
                " <span class=\"" + YAHOO.widget.DataTable.CLASS_DISABLED +
                " " + YAHOO.widget.DataTable.CLASS_FIRST + "\">&lt;&lt;</span> " :
                " <a href=\"#\" class=\"" + YAHOO.widget.DataTable.CLASS_FIRST + "\">&lt;&lt;</a> ";
        var sPrevLinkMarkup = (bIsFirstPage) ?
                " <span class=\"" + YAHOO.widget.DataTable.CLASS_DISABLED +
                " " + YAHOO.widget.DataTable.CLASS_PREVIOUS + "\">&lt;</span> " :
                " <a href=\"#\" class=\"" + YAHOO.widget.DataTable.CLASS_PREVIOUS + "\">&lt;</a> " ;
        var sNextLinkMarkup = (bIsLastPage) ?
                " <span class=\"" + YAHOO.widget.DataTable.CLASS_DISABLED +
                " " + YAHOO.widget.DataTable.CLASS_NEXT + "\">&gt;</span> " :
                " <a href=\"#\" class=\"" + YAHOO.widget.DataTable.CLASS_NEXT + "\">&gt;</a> " ;
        var sLastLinkMarkup = (bIsLastPage) ?
                " <span class=\"" + YAHOO.widget.DataTable.CLASS_DISABLED +
                " " + YAHOO.widget.DataTable.CLASS_LAST +  "\">&gt;&gt;</span> " :
                " <a href=\"#\" class=\"" + YAHOO.widget.DataTable.CLASS_LAST + "\">&gt;&gt;</a> ";

        // Start with first and previous
        var sMarkup = sFirstLinkMarkup + sPrevLinkMarkup;
        
        // Ok to show all links
        var nMaxLinks = nTotalPages;
        var nFirstLink = 1;
        var nLastLink = nTotalPages;

        if(nPageLinksLength > 0) {
        // Calculate how many links to show
            nMaxLinks = (nPageLinksStart+nPageLinksLength < nTotalPages) ?
                    nPageLinksStart+nPageLinksLength-1 : nTotalPages;

            // Try to keep the current page in the middle
            nFirstLink = (nCurrentPage - Math.floor(nMaxLinks/2) > 0) ? nCurrentPage - Math.floor(nMaxLinks/2) : 1;
            nLastLink = (nCurrentPage + Math.floor(nMaxLinks/2) <= nTotalPages) ? nCurrentPage + Math.floor(nMaxLinks/2) : nTotalPages;

            // Keep the last link in range
            if(nFirstLink === 1) {
                nLastLink = nMaxLinks;
            }
            // Keep the first link in range
            else if(nLastLink === nTotalPages) {
                nFirstLink = nTotalPages - nMaxLinks + 1;
            }

            // An even number of links can get funky
            if(nLastLink - nFirstLink === nMaxLinks) {
                nLastLink--;
            }
      }
        
        // Generate markup for each page
        for(var i=nFirstLink; i<=nLastLink; i++) {
            if(i != nCurrentPage) {
                sMarkup += " <a href=\"#\" class=\"" + YAHOO.widget.DataTable.CLASS_PAGE + "\">" + i + "</a> ";
            }
            else {
                sMarkup += " <span class=\"" + YAHOO.widget.DataTable.CLASS_SELECTED + "\">" + i + "</span>";
            }
        }
        sMarkup += sNextLinkMarkup + sLastLinkMarkup;
        elContainer.innerHTML = sMarkup;
        return;
    }
};

















































// SELECTION/HIGHLIGHTING

/**
 * ID string of last highlighted cell element
 *
 * @property _sLastHighlightedCellId
 * @type String
 * @private
 */
YAHOO.widget.DataTable.prototype._sLastHighlightedCellId = null;

/**
 * ID string of last highlighted row element
 *
 * @property _sLastHighlightedRowId
 * @type String
 * @private
 */
YAHOO.widget.DataTable.prototype._sLastHighlightedRowId = null;

/**
 * Array of selections: {recordId:nRecordId, cellIndex:nCellIndex}
 *
 * @property _aSelections
 * @type Object[]
 * @private
 */
YAHOO.widget.DataTable.prototype._aSelections = null;

/**
 * ID string of last selected element
 *
 * @property _sLastSelectedId
 * @type String
 * @private
 */
YAHOO.widget.DataTable.prototype._sLastSelectedId = null;

/**
 * ID string of the selection anchor element.
 *
 * @property _sSelectionAnchorId
 * @type String
 * @private
 */
YAHOO.widget.DataTable.prototype._sSelectionAnchorId = null;

/**
 * Convenience method to remove the class YAHOO.widget.DataTable.CLASS_SELECTED
 * from all TR elements on the page.
 *
 * @method _unselectAllTrEls
 * @private
 */
YAHOO.widget.DataTable.prototype._unselectAllTrEls = function() {
    var selectedRows = YAHOO.util.Dom.getElementsByClassName(YAHOO.widget.DataTable.CLASS_SELECTED,"tr",this._elTbody);
    YAHOO.util.Dom.removeClass(selectedRows, YAHOO.widget.DataTable.CLASS_SELECTED);
};

/**
 * Returns array of selected TR elements on the page.
 *
 * @method getSelectedTrEls
 * @return {HTMLElement[]} Array of selected TR elements.
 */
YAHOO.widget.DataTable.prototype.getSelectedTrEls = function() {
    return YAHOO.util.Dom.getElementsByClassName(YAHOO.widget.DataTable.CLASS_SELECTED,"tr",this._elTbody);
};

/**
 * Sets given row to the selected state.
 *
 * @method selectRow
 * @param row {HTMLElement | String} HTML element reference or ID.
 */
YAHOO.widget.DataTable.prototype.selectRow = function(row) {
    // Validate the row
    var elRow = this.getTrEl(row);
    if(elRow) {
        var oRecord = this.getRecord(elRow);
        if(oRecord) {
            // Get Record ID
            var tracker = this._aSelections || [];
            var nRecordId = oRecord.getId();
            // Remove if already there

            // Use Array.indexOf if available...
            if(tracker.indexOf && (tracker.indexOf(nRecordId) >  -1)) {
                tracker.splice(tracker.indexOf(nRecordId),1);
            }
            // ...or do it the old-fashioned way
            else {
                for(var j=0; j<tracker.length; j++) {
                   if(tracker[j] === nRecordId){
                        tracker.splice(j,1);
                    }
                }
            }
            // Add to the end
            tracker.push(nRecordId);

            // Update trackers
            this._sLastSelectedId = elRow.id;
            if(!this._sSelectionAnchorId) {
                this._sSelectionAnchorId = elRow.id;
            }
            this._aSelections = tracker;
        
            // Update UI
            YAHOO.util.Dom.addClass(elRow, YAHOO.widget.DataTable.CLASS_SELECTED);

            this.fireEvent("rowSelectEvent", {record:oRecord, el:elRow});

            return;
        }
    }
};
// Backward compatibility
YAHOO.widget.DataTable.prototype.select = function(els) {
    if(!YAHOO.lang.isArray(els)) {
        els = [els];
    }
    for(var i=0; i<els.length; i++) {
        this.selectRow(els[i]);
    }
};

/**
 * Sets given row to the unselected state.
 *
 * @method unselectRow
 * @param row {HTMLElement | String} HTML TR element reference or ID.
 */
YAHOO.widget.DataTable.prototype.unselectRow = function(row) {
    // Validate the row
    var elRow = this.getTrEl(row);
    if(elRow) {
        var oRecord = this.getRecord(elRow);
        if(oRecord) {
            // Get Record ID
            var tracker = this._aSelections || [];
            var nRecordId = oRecord.getId();

            // Remove if there
            var bFound = false;
            
            // Use Array.indexOf if available...
            if(tracker.indexOf && (tracker.indexOf(nRecordId) >  -1)) {
                tracker.splice(tracker.indexOf(nRecordId),1);
                bFound = true;
            }
            // ...or do it the old-fashioned way
            else {
                for(var j=0; j<tracker.length; j++) {
                   if(tracker[j] === nRecordId){
                        tracker.splice(j,1);
                        bFound = true;
                    }
                }
            }

            if(bFound) {
                // Update tracker
                this._aSelections = tracker;

                // Update the UI
                YAHOO.util.Dom.removeClass(elRow, YAHOO.widget.DataTable.CLASS_SELECTED);

                this.fireEvent("rowUnselectEvent", {record:oRecord, el:elRow});

                return;
            }
        }
    }
};

/**
 * Clears out all row selections.
 *
 * @method unselectAllRows
 */
YAHOO.widget.DataTable.prototype.unselectAllRows = function() {
    // Remove from tracker
    var tracker = this._aSelections || [];
    for(var j=0; j<tracker.length; j++) {
       if(YAHOO.lang.isNumber(tracker[j])){
            tracker.splice(j,1);
        }
    }

    // Update tracker
    this._aSelections = tracker;

    // Update UI
    this._unselectAllTrEls();

    //TODO: send an array of [{el:el,record:record}]
    //TODO: or convert this to an unselectRows method
    //TODO: that takes an array of rows or unselects all if none given
    this.fireEvent("unselectAllRowsEvent");
};

/**
 * Convenience method to remove the class YAHOO.widget.DataTable.CLASS_SELECTED
 * from all TD elements in the internal tracker.
 *
 * @method _unselectAllTdEls
 * @private
 */
YAHOO.widget.DataTable.prototype._unselectAllTdEls = function() {
    var selectedCells = YAHOO.util.Dom.getElementsByClassName(YAHOO.widget.DataTable.CLASS_SELECTED,"td",this._elTbody);
    YAHOO.util.Dom.removeClass(selectedCells, YAHOO.widget.DataTable.CLASS_SELECTED);
};

/**
 * Returns array of selected TD elements on the page.
 *
 * @method getSelectedTdEls
 * @return {HTMLElement[]} Array of selected TD elements.
 */
YAHOO.widget.DataTable.prototype.getSelectedTdEls = function() {
    return YAHOO.util.Dom.getElementsByClassName(YAHOO.widget.DataTable.CLASS_SELECTED,"td",this._elTbody);
};

/**
 * Sets given cell to the selected state.
 *
 * @method selectCell
 * @param cell {HTMLElement | String} DOM element reference or ID string
 * to DataTable page element or RecordSet index.
 */
YAHOO.widget.DataTable.prototype.selectCell = function(cell) {
    var elCell = this.getTdEl(cell);
    
    if(elCell) {
        var oRecord = this.getRecord(elCell);
        var nColumnId = elCell.yuiColumnId;

        if(oRecord && YAHOO.lang.isNumber(nColumnId)) {
            // Get Record ID
            var tracker = this._aSelections || [];
            var nRecordId = oRecord.getId();

            // Remove if there
            for(var j=0; j<tracker.length; j++) {
               if((tracker[j].recordId === nRecordId) && (tracker[j].columnId === nColumnId)){
                    tracker.splice(j,1);
                }
            }

            // Add to the end
            tracker.push({recordId:nRecordId, columnId:nColumnId});

            // Update trackers
            this._aSelections = tracker;
            this._sLastSelectedId = elCell.id;
            if(!this._sSelectionAnchorId) {
                this._sSelectionAnchorId = elCell.id;
            }

            // Update the UI
            YAHOO.util.Dom.addClass(elCell, YAHOO.widget.DataTable.CLASS_SELECTED);

            this.fireEvent("cellSelectEvent", {record:oRecord,
                    key: this._oColumnSet.getColumn(nColumnId).key, el:elCell});
            return;
        }
    }
};

/**
 * Sets given cell to the unselected state.
 *
 * @method unselectCell
 * @param cell {HTMLElement | String} DOM element reference or ID string
 * to DataTable page element or RecordSet index.
 */
YAHOO.widget.DataTable.prototype.unselectCell = function(cell) {
    var elCell = this.getTdEl(cell);

    if(elCell) {
        var oRecord = this.getRecord(elCell);
        var nColumnId = elCell.yuiColumnId;

        if(oRecord && YAHOO.lang.isNumber(nColumnId)) {
            // Get Record ID
            var tracker = this._aSelections || [];
            var id = oRecord.getId();

            // Is it selected?
            for(var j=0; j<tracker.length; j++) {
                if((tracker[j].recordId === id) && (tracker[j].columnId === nColumnId)){
                    // Remove from tracker
                    tracker.splice(j,1);
                    
                    // Update tracker
                    this._aSelections = tracker;

                    // Update the UI
                    YAHOO.util.Dom.removeClass(elCell, YAHOO.widget.DataTable.CLASS_SELECTED);

                    this.fireEvent("cellUnselectEvent", {record:oRecord,
                            key:this._oColumnSet.getColumn(nColumnId).key, el:elCell});

                    return;
                }
            }
        }
    }
};

/**
 * Clears out all cell selections.
 *
 * @method unselectAllCells
 */
YAHOO.widget.DataTable.prototype.unselectAllCells= function() {
    // Remove from tracker
    var tracker = this._aSelections || [];
    for(var j=0; j<tracker.length; j++) {
       if(tracker[j].constructor == Object){
            tracker.splice(j,1);
        }
    }

    // Update tracker
    this._aSelections = tracker;

    // Update UI
    this._unselectAllTdEls();
    
    //TODO: send data
    //TODO: or fire individual cellUnselectEvent
    this.fireEvent("unselectAllCellsEvent");
};

/**
 * Returns true if given TR or TD element is select, false otherwise.
 *
 * @method isSelected
 * @param el {HTMLElement} HTML element reference or ID of a TR or TD.
 * @return {Boolean} True if element is selected.
 */
YAHOO.widget.DataTable.prototype.isSelected = function(el) {
    return YAHOO.util.Dom.hasClass(el,YAHOO.widget.DataTable.CLASS_SELECTED);
};

/**
 * Returns selected rows as an array of Record IDs.
 *
 * @method getSelectedRows
 * @return {HTMLElement[]} Array of selected rows by Record ID.
 */
YAHOO.widget.DataTable.prototype.getSelectedRows = function() {
    var aSelectedRows = [];
    var tracker = this._aSelections || [];
    for(var j=0; j<tracker.length; j++) {
       if(YAHOO.lang.isNumber(tracker[j])){
            aSelectedRows.push(tracker[j]);
        }
    }
    return aSelectedRows;
};

/**
 * Returns selected cells as an array of object literals:
 *     {recordId:nRecordID, columnId:nColumnId}.
 *
 * @method getSelectedCells
 * @return {HTMLElement[]} Array of selected cells by Record and Column IDs.
 */
YAHOO.widget.DataTable.prototype.getSelectedCells = function() {
    var aSelectedCells = [];
    var tracker = this._aSelections || [];
    for(var j=0; j<tracker.length; j++) {
       if(tracker[j] && (tracker[j].constructor == Object)){
            aSelectedCells.push({recordId:tracker[j].recordId, columnId:tracker[j].columnId});
        }
    }
    return aSelectedCells;
};

/**
 * Assigns the class YAHOO.widget.DataTable.CLASS_HIGHLIGHTED to the given row.
 *
 * @method highlightRow
 * @param row {HTMLElement | String} DOM element reference or ID string.
 */
YAHOO.widget.DataTable.prototype.highlightRow = function(row) {
    var elRow = this.getTrEl(row);

    if(elRow) {
        // Make sure previous row is unhighlighted
        if(this._sLastHighlightedRowId) {
            YAHOO.util.Dom.removeClass(this._sLastHighlightedRowId,YAHOO.widget.DataTable.CLASS_HIGHLIGHTED);
        }
        var oRecord = this.getRecord(elRow);
        YAHOO.util.Dom.addClass(elRow,YAHOO.widget.DataTable.CLASS_HIGHLIGHTED);
        this._sLastHighlightedRowId = elRow.id;
        this.fireEvent("rowHighlightEvent", {record:oRecord, el:elRow});
        return;
    }
};

/**
 * Removes the class YAHOO.widget.DataTable.CLASS_HIGHLIGHTED from the given row.
 *
 * @method unhighlightRow
 * @param row {HTMLElement | String} DOM element reference or ID string.
 */
YAHOO.widget.DataTable.prototype.unhighlightRow = function(row) {
    var elRow = this.getTrEl(row);

    if(elRow) {
        var oRecord = this.getRecord(elRow);
        YAHOO.util.Dom.removeClass(elRow,YAHOO.widget.DataTable.CLASS_HIGHLIGHTED);
        this.fireEvent("rowUnhighlightEvent", {record:oRecord, el:elRow});
        return;
    }
};

/**
 * Assigns the class YAHOO.widget.DataTable.CLASS_HIGHLIGHTED to the given cell.
 *
 * @method highlightCell
 * @param cell {HTMLElement | String} DOM element reference or ID string.
 */
YAHOO.widget.DataTable.prototype.highlightCell = function(cell) {
    var elCell = this.getTdEl(cell);

    if(elCell) {
        // Make sure previous cell is unhighlighted
        if(this._sLastHighlightedCellId) {
            YAHOO.util.Dom.removeClass(this._sLastHighlightedCellId,YAHOO.widget.DataTable.CLASS_HIGHLIGHTED);
        }
        
        var oRecord = this.getRecord(elCell);
        YAHOO.util.Dom.addClass(elCell,YAHOO.widget.DataTable.CLASS_HIGHLIGHTED);
        this._sLastHighlightedCellId = elCell.id;
        this.fireEvent("cellHighlightEvent", {record:oRecord,
                    key:this._oColumnSet.getColumn(elCell.yuiColumnId).key, el:elCell});
        return;
    }
};

/**
 * Removes the class YAHOO.widget.DataTable.CLASS_HIGHLIGHTED from the given cell.
 *
 * @method unhighlightCell
 * @param cell {HTMLElement | String} DOM element reference or ID string.
 */
YAHOO.widget.DataTable.prototype.unhighlightCell = function(cell) {
    var elCell = this.getTdEl(cell);

    if(elCell) {
        var oRecord = this.getRecord(elCell);
        YAHOO.util.Dom.removeClass(elCell,YAHOO.widget.DataTable.CLASS_HIGHLIGHTED);
        this.fireEvent("cellUnhighlightEvent", {record:oRecord,
                    key:this._oColumnSet.getColumn(elCell.yuiColumnId).key, el:elCell});
        return;
    }
};













































// INLINE EDITING

/*TODO: for TAB handling
 * Shows Cell Editor for next cell.
 *
 * @method editNextCell
 * @param elCell {HTMLElement} Cell element from which to edit next cell.
 */
//YAHOO.widget.DataTable.prototype.editNextCell = function(elCell) {
//};

/**
 * Shows Cell Editor for given cell.
 *
 * @method showCellEditor
 * @param elCell {HTMLElement | String} Cell element to edit.
 * @param oRecord {YAHOO.widget.Record} (Optional) Record instance.
 * @param oColumn {YAHOO.widget.Column} (Optional) Column instance.
 */
YAHOO.widget.DataTable.prototype.showCellEditor = function(elCell, oRecord, oColumn) {
    elCell = YAHOO.util.Dom.get(elCell);
    
    if(elCell && (elCell.ownerDocument === document)) {
        if(!oRecord || !(oRecord instanceof YAHOO.widget.Record)) {
            oRecord = this.getRecord(elCell);
        }
        if(!oColumn || !(oColumn instanceof YAHOO.widget.Column)) {
            oColumn = this.getColumn(elCell);
        }
        if(oRecord && oColumn) {
            var oCellEditor = this._oCellEditor;
            
            // Clear previous Editor
            if(oCellEditor.isActive) {
                this.cancelCellEditor();
            }

            // Editor not defined
            if(!oColumn.editor) {
                return;
            }
            
            // Update Editor values
            oCellEditor.cell = elCell;
            oCellEditor.record = oRecord;
            oCellEditor.column = oColumn;
            oCellEditor.validator = (oColumn.editorOptions &&
                    YAHOO.lang.isFunction(oColumn.editorOptions.validator)) ?
                    oColumn.editorOptions.validator : null;
            oCellEditor.value = oRecord.getData(oColumn.key);

            // Move Editor
            var elContainer = oCellEditor.container;
            var x = YAHOO.util.Dom.getX(elCell);
            var y = YAHOO.util.Dom.getY(elCell);

            // SF doesn't get xy for cells in scrolling table
            // when tbody display is set to block
            if(isNaN(x) || isNaN(y)) {
                x = elCell.offsetLeft + // cell pos relative to table
                        YAHOO.util.Dom.getX(this._elTable) - // plus table pos relative to document
                        this._elTbody.scrollLeft; // minus tbody scroll
                y = elCell.offsetTop + // cell pos relative to table
                        YAHOO.util.Dom.getY(this._elTable) - // plus table pos relative to document
                        this._elTbody.scrollTop + // minus tbody scroll
                        this._elThead.offsetHeight; // account for fixed headers
            }
            
            elContainer.style.left = x + "px";
            elContainer.style.top = y + "px";

            // Show Editor
            elContainer.style.display = "";
            
            // Render Editor markup
            var fnEditor;
            if(YAHOO.lang.isString(oColumn.editor)) {
                switch(oColumn.editor) {
                    case "checkbox":
                        fnEditor = YAHOO.widget.DataTable.editCheckbox;
                        break;
                    case "date":
                        fnEditor = YAHOO.widget.DataTable.editDate;
                        break;
                    case "dropdown":
                        fnEditor = YAHOO.widget.DataTable.editDropdown;
                        break;
                    case "radio":
                        fnEditor = YAHOO.widget.DataTable.editRadio;
                        break;
                    case "textarea":
                        fnEditor = YAHOO.widget.DataTable.editTextarea;
                        break;
                    case "textbox":
                        fnEditor = YAHOO.widget.DataTable.editTextbox;
                        break;
                    default:
                        fnEditor = null;
                }
            }
            else if(YAHOO.lang.isFunction(oColumn.editor)) {
                fnEditor = oColumn.editor;
            }

            if(fnEditor) {
                // Create DOM input elements
                fnEditor(this._oCellEditor, this);
                
                // Show Save/Cancel buttons
                if(!oColumn.editorOptions || !oColumn.editorOptions.disableBtns) {
                    this.showCellEditorBtns(elContainer);
                }

                // Hook to customize the UI
                this.doBeforeShowCellEditor(this._oCellEditor);

                oCellEditor.isActive = true;
                
                //TODO: verify which args to pass
                this.fireEvent("editorShowEvent", {editor:oCellEditor});
                return;
            }
        }
    }
};

/**
 * Overridable abstract method to customize Cell Editor UI.
 *
 * @method doBeforeShowCellEditor
 * @param oCellEditor {Object} Cell Editor object literal.
 */
YAHOO.widget.DataTable.prototype.doBeforeShowCellEditor = function(oCellEditor) {
};

/**
 * Adds Save/Cancel buttons to Cell Editor.
 *
 * @method showCellEditorBtns
 * @param elContainer {HTMLElement} Cell Editor container.
 */
YAHOO.widget.DataTable.prototype.showCellEditorBtns = function(elContainer) {
    // Buttons
    var elBtnsDiv = elContainer.appendChild(document.createElement("div"));
    YAHOO.util.Dom.addClass(elBtnsDiv, YAHOO.widget.DataTable.CLASS_BUTTON);

    // Save button
    var elSaveBtn = elBtnsDiv.appendChild(document.createElement("button"));
    YAHOO.util.Dom.addClass(elSaveBtn, YAHOO.widget.DataTable.CLASS_DEFAULT);
    elSaveBtn.innerHTML = "OK";
    YAHOO.util.Event.addListener(elSaveBtn, "click", this.saveCellEditor, this, true);

    // Cancel button
    var elCancelBtn = elBtnsDiv.appendChild(document.createElement("button"));
    elCancelBtn.innerHTML = "Cancel";
    YAHOO.util.Event.addListener(elCancelBtn, "click", this.cancelCellEditor, this, true);
};

/**
 * Clears Cell Editor of all state and UI.
 *
 * @method resetCellEditor
 */

YAHOO.widget.DataTable.prototype.resetCellEditor = function() {
    var elContainer = this._oCellEditor.container;
    elContainer.style.display = "none";
    YAHOO.util.Event.purgeElement(elContainer, true);
    elContainer.innerHTML = "";
    this._oCellEditor.value = null;
    this._oCellEditor.isActive = false;
};

/**
 * Saves Cell Editor input to Record.
 *
 * @method saveCellEditor
 */
YAHOO.widget.DataTable.prototype.saveCellEditor = function() {
    //TODO: Copy the editor's values to pass to the event
    if(this._oCellEditor.isActive) {
        var newData = this._oCellEditor.value;
        var oldData = this._oCellEditor.record.getData(this._oCellEditor.column.key);

        // Validate input data
        if(this._oCellEditor.validator) {
            this._oCellEditor.value = this._oCellEditor.validator.call(this, newData, oldData);
            if(this._oCellEditor.value === null ) {
                this.resetCellEditor();
                this.fireEvent("editorRevertEvent",
                        {editor:this._oCellEditor, oldData:oldData, newData:newData});
                return;
            }
        }

        // Update the Record
        this._oRecordSet.updateKey(this._oCellEditor.record, this._oCellEditor.column.key, this._oCellEditor.value);

        // Update the UI
        this.formatCell(this._oCellEditor.cell);

        // Clear out the Cell Editor
        this.resetCellEditor();

        this.fireEvent("editorSaveEvent",
                {editor:this._oCellEditor, oldData:oldData, newData:newData});
    }
    else {
    }
};

/**
 * Cancels Cell Editor.
 *
 * @method cancelCellEditor
 */
YAHOO.widget.DataTable.prototype.cancelCellEditor = function() {
    if(this._oCellEditor.isActive) {
        this.resetCellEditor();
        //TODO: preserve values for the event?
        this.fireEvent("editorCancelEvent", {editor:this._oCellEditor});
    }
    else {
    }
};

/**
 * Enables CHECKBOX Editor.
 *
 * @method editCheckbox
 */
//YAHOO.widget.DataTable.editCheckbox = function(elContainer, oRecord, oColumn, oEditor, oSelf) {
YAHOO.widget.DataTable.editCheckbox = function(oEditor, oSelf) {
    var elCell = oEditor.cell;
    var oRecord = oEditor.record;
    var oColumn = oEditor.column;
    var elContainer = oEditor.container;
    var aCheckedValues = oRecord.getData(oColumn.key);
    if(!YAHOO.lang.isArray(aCheckedValues)) {
        aCheckedValues = [aCheckedValues];
    }

    // Checkboxes
    if(oColumn.editorOptions && YAHOO.lang.isArray(oColumn.editorOptions.checkboxOptions)) {
        var checkboxOptions = oColumn.editorOptions.checkboxOptions;
        var checkboxValue, checkboxId, elLabel, j, k;
        // First create the checkbox buttons in an IE-friendly way
        for(j=0; j<checkboxOptions.length; j++) {
            checkboxValue = YAHOO.lang.isValue(checkboxOptions[j].label) ?
                    checkboxOptions[j].label : checkboxOptions[j];
            checkboxId =  oSelf.id + "-editor-checkbox" + j;
            elContainer.innerHTML += "<input type=\"checkbox\"" +
                    " name=\"" + oSelf.id + "-editor-checkbox\"" +
                    " value=\"" + checkboxValue + "\"" +
                    " id=\"" +  checkboxId + "\">";
            // Then create the labels in an IE-friendly way
            elLabel = elContainer.appendChild(document.createElement("label"));
            elLabel.htmlFor = checkboxId;
            elLabel.innerHTML = checkboxValue;
        }
        var aCheckboxEls = [];
        var checkboxEl;
        // Loop through checkboxes to check them
        for(j=0; j<checkboxOptions.length; j++) {
            checkboxEl = YAHOO.util.Dom.get(oSelf.id + "-editor-checkbox" + j);
            aCheckboxEls.push(checkboxEl);
            for(k=0; k<aCheckedValues.length; k++) {
                if(checkboxEl.value === aCheckedValues[k]) {
                    checkboxEl.checked = true;
                }
            }
            // Focus the first checkbox
            if(j===0) {
                oSelf._focusEl(checkboxEl);
            }
        }
        // Loop through checkboxes to assign click handlers
        for(j=0; j<checkboxOptions.length; j++) {
            checkboxEl = YAHOO.util.Dom.get(oSelf.id + "-editor-checkbox" + j);
            YAHOO.util.Event.addListener(checkboxEl, "click", function(){
                var aNewValues = [];
                for(var m=0; m<aCheckboxEls.length; m++) {
                    if(aCheckboxEls[m].checked) {
                        aNewValues.push(aCheckboxEls[m].value);
                    }
                }
                oSelf._oCellEditor.value = aNewValues;
                oSelf.fireEvent("editorUpdateEvent",{editor:oSelf._oCellEditor});
            });
        }
    }
};

/**
 * Enables Date Editor.
 *
 * @method editDate
 */
YAHOO.widget.DataTable.editDate = function(oEditor, oSelf) {
    var elCell = oEditor.cell;
    var oRecord = oEditor.record;
    var oColumn = oEditor.column;
    var elContainer = oEditor.container;
    var value = oRecord.getData(oColumn.key);

    // Calendar widget
    if(YAHOO.widget.Calendar) {
        var selectedValue = (value.getMonth()+1)+"/"+value.getDate()+"/"+value.getFullYear();
        var calContainer = elContainer.appendChild(document.createElement("div"));
        calContainer.id = "yui-dt-" + oSelf._nIndex + "-col" + oColumn.getKeyIndex() + "-dateContainer";
        var calendar =
                new YAHOO.widget.Calendar("yui-dt-" + oSelf._nIndex + "-col" + oColumn.getKeyIndex() + "-date",
                calContainer.id,
                {selected:selectedValue, pagedate:value});
        calendar.render();
        calContainer.style.cssFloat = "none";

        //var calFloatClearer = elContainer.appendChild(document.createElement("br"));
        //calFloatClearer.style.clear = "both";
        
        calendar.selectEvent.subscribe(function(type, args, obj) {
            oSelf._oCellEditor.value = new Date(args[0][0][0], args[0][0][1]-1, args[0][0][2]);
        });
        oSelf.fireEvent("editorUpdateEvent",{editor:oSelf._oCellEditor});
    }
    else {
        //TODO;
    }
};

/**
 * Enables SELECT Editor.
 *
 * @method editDropdown
 */
YAHOO.widget.DataTable.editDropdown = function(oEditor, oSelf) {
    var elCell = oEditor.cell;
    var oRecord = oEditor.record;
    var oColumn = oEditor.column;
    var elContainer = oEditor.container;
    var value = oRecord.getData(oColumn.key);

    // Textbox
    var elDropdown = elContainer.appendChild(document.createElement("select"));
    var dropdownOptions = (oColumn.editorOptions && YAHOO.lang.isArray(oColumn.editorOptions.dropdownOptions)) ?
            oColumn.editorOptions.dropdownOptions : [];
    for(var j=0; j<dropdownOptions.length; j++) {
        var dropdownOption = dropdownOptions[j];
        var elOption = document.createElement("option");
        elOption.value = (YAHOO.lang.isValue(dropdownOption.value)) ?
                dropdownOption.value : dropdownOption;
        elOption.innerHTML = (YAHOO.lang.isValue(dropdownOption.text)) ?
                dropdownOption.text : dropdownOption;
        elOption = elDropdown.appendChild(elOption);
        if(value === elDropdown.options[j].value) {
            elDropdown.options[j].selected = true;
        }
    }
    
    // Set up a listener on each check box to track the input value
    YAHOO.util.Event.addListener(elDropdown, "change",
        function(){
            oSelf._oCellEditor.value = elDropdown[elDropdown.selectedIndex].value;
            oSelf.fireEvent("editorUpdateEvent",{editor:oSelf._oCellEditor});
    });
            
    // Focus the dropdown
    oSelf._focusEl(elDropdown);
};

/**
 * Enables INPUT TYPE=RADIO Editor.
 *
 * @method editRadio
 */
YAHOO.widget.DataTable.editRadio = function(oEditor, oSelf) {
    var elCell = oEditor.cell;
    var oRecord = oEditor.record;
    var oColumn = oEditor.column;
    var elContainer = oEditor.container;
    var value = oRecord.getData(oColumn.key);

    // Radios
    if(oColumn.editorOptions && YAHOO.lang.isArray(oColumn.editorOptions.radioOptions)) {
        var radioOptions = oColumn.editorOptions.radioOptions;
        var radioValue, radioId, elLabel, j;
        // First create the radio buttons in an IE-friendly way
        for(j=0; j<radioOptions.length; j++) {
            radioValue = YAHOO.lang.isValue(radioOptions[j].label) ?
                    radioOptions[j].label : radioOptions[j];
            radioId =  oSelf.id + "-editor-radio" + j;
            elContainer.innerHTML += "<input type=\"radio\"" +
                    " name=\"" + oSelf.id + "-editor-radio\"" +
                    " value=\"" + radioValue + "\"" +
                    " id=\"" +  radioId + "\">";
            // Then create the labels in an IE-friendly way
            elLabel = elContainer.appendChild(document.createElement("label"));
            elLabel.htmlFor = radioId;
            elLabel.innerHTML = radioValue;
        }
        // Then check one, and assign click handlers
        for(j=0; j<radioOptions.length; j++) {
            var radioEl = YAHOO.util.Dom.get(oSelf.id + "-editor-radio" + j);
            if(value === radioEl.value) {
                radioEl.checked = true;
                oSelf._focusEl(radioEl);
            }
            YAHOO.util.Event.addListener(radioEl, "click",
                function(){
                    oSelf._oCellEditor.value = this.value;
                    oSelf.fireEvent("editorUpdateEvent",{editor:oSelf._oCellEditor});
            });
        }
    }
};

/**
 * Enables TEXTAREA Editor.
 *
 * @method editTextarea
 */
YAHOO.widget.DataTable.editTextarea = function(oEditor, oSelf) {
   var elCell = oEditor.cell;
   var oRecord = oEditor.record;
   var oColumn = oEditor.column;
   var elContainer = oEditor.container;
   var value = oRecord.getData(oColumn.key);

    // Textarea
    var elTextarea = elContainer.appendChild(document.createElement("textarea"));
    elTextarea.style.width = elCell.offsetWidth + "px"; //(parseInt(elCell.offsetWidth,10)) + "px";
    elTextarea.style.height = "3em"; //(parseInt(elCell.offsetHeight,10)) + "px";
    elTextarea.value = YAHOO.lang.isValue(value) ? value : "";
    
    // Set up a listener on each check box to track the input value
    YAHOO.util.Event.addListener(elTextarea, "keyup", function(){
        //TODO: set on a timeout
        oSelf._oCellEditor.value = elTextarea.value;
        oSelf.fireEvent("editorUpdateEvent",{editor:oSelf._oCellEditor});
    });
    
    // Select the text
    elTextarea.focus();
    elTextarea.select();
};

/**
 * Enables INPUT TYPE=TEXT Editor.
 *
 * @method editTextbox
 */
YAHOO.widget.DataTable.editTextbox = function(oEditor, oSelf) {
   var elCell = oEditor.cell;
   var oRecord = oEditor.record;
   var oColumn = oEditor.column;
   var elContainer = oEditor.container;
   var value = YAHOO.lang.isValue(oRecord.getData(oColumn.key)) ? oRecord.getData(oColumn.key) : "";

    // Textbox
    var elTextbox = elContainer.appendChild(document.createElement("input"));
    elTextbox.type = "text";
    elTextbox.style.width = elCell.offsetWidth + "px"; //(parseInt(elCell.offsetWidth,10)) + "px";
    //elTextbox.style.height = "1em"; //(parseInt(elCell.offsetHeight,10)) + "px";
    elTextbox.value = value;

    // Set up a listener on each textbox to track the input value
    YAHOO.util.Event.addListener(elTextbox, "keyup", function(){
        //TODO: set on a timeout
        oSelf._oCellEditor.value = elTextbox.value;
        oSelf.fireEvent("editorUpdateEvent",{editor:oSelf._oCellEditor});
    });

    // Select the text
    elTextbox.focus();
    elTextbox.select();
};

/*
 * Validates Editor input value to type Number, doing type conversion as
 * necessary. A valid Number value is return, else the previous value is returned
 * if input value does not validate.
 * 
 *
 * @method validateNumber
 * @static
*/
YAHOO.widget.DataTable.validateNumber = function(oData) {
    //Convert to number
    var number = oData * 1;

    // Validate
    if(YAHOO.lang.isNumber(number)) {
        return number;
    }
    else {
        return null;
    }
};






































// ABSTRACT METHODS

/**
 * Overridable method gives implementers a hook to access data before
 * it gets added to RecordSet and rendered to the TBODY.
 *
 * @method doBeforeLoadData
 * @param sRequest {String} Original request.
 * @param oResponse {Object} Response object.
 * @return {Boolean} Return true to continue loading data into RecordSet and
 * updating DataTable with new Records, false to cancel.
 */
YAHOO.widget.DataTable.prototype.doBeforeLoadData = function(sRequest, oResponse) {
    return true;
};































































/////////////////////////////////////////////////////////////////////////////
//
// Public Custom Event Handlers
//
/////////////////////////////////////////////////////////////////////////////

/**
 * Overridable custom event handler to sort Column.
 *
 * @method onEventSortColumn
 * @param oArgs.event {HTMLEvent} Event object.
 * @param oArgs.target {HTMLElement} Target element.
 */
YAHOO.widget.DataTable.prototype.onEventSortColumn = function(oArgs) {
//TODO: support nested header column sorting
    var evt = oArgs.event;
    var target = oArgs.target;
    YAHOO.util.Event.stopEvent(evt);
    
    var el = this.getThEl(target) || this.getTdEl(target);
    if(el && YAHOO.lang.isNumber(el.yuiColumnId)) {
        this.sortColumn(this._oColumnSet.getColumn(el.yuiColumnId));
    }
    else {
    }
};

/**
 * Overridable custom event handler to manage selection according to desktop paradigm.
 *
 * @method onEventSelectRow
 * @param oArgs.event {HTMLEvent} Event object.
 * @param oArgs.target {HTMLElement} Target element.
 */
YAHOO.widget.DataTable.prototype.onEventSelectRow = function(oArgs) {
    var sMode = this.get("selectionMode");
    if ((sMode == "singlecell") || (sMode == "cellblock") || (sMode == "cellrange")) {
        return;
    }

    var evt = oArgs.event;
    var elTarget = oArgs.target;

    var bSHIFT = evt.shiftKey;
    var bCTRL = evt.ctrlKey;
    var i, nAnchorTrIndex;

    // Validate target row
    var elTargetRow = this.getTrEl(elTarget);
    if(elTargetRow) {
        var allRows = this._elTbody.rows;
        var nTargetTrIndex = elTargetRow.sectionRowIndex;
        var elAnchorRow = YAHOO.util.Dom.get(this._sSelectionAnchorId);
        
        // Both SHIFT and CTRL
        if((sMode != "single") && bSHIFT && bCTRL) {
            // Validate anchor row
            if(elAnchorRow && YAHOO.lang.isNumber(elAnchorRow.sectionRowIndex)) {
                nAnchorTrIndex = elAnchorRow.sectionRowIndex;
                if(this.isSelected(elAnchorRow)) {
                    // Select all rows between anchor row and target row, including target row
                    if(nAnchorTrIndex < nTargetTrIndex) {
                        for(i=nAnchorTrIndex+1; i<=nTargetTrIndex; i++) {
                            if(!this.isSelected(allRows[i])) {
                                this.selectRow(allRows[i]);
                            }
                        }
                    }
                    // Select all rows between target row and anchor row, including target row
                    else {
                        for(i=nAnchorTrIndex-1; i>=nTargetTrIndex; i--) {
                            if(!this.isSelected(allRows[i])) {
                                this.selectRow(allRows[i]);
                            }
                        }
                    }
                }
                else {
                    // Unselect all rows between anchor row and target row
                    if(nAnchorTrIndex < nTargetTrIndex) {
                        for(i=nAnchorTrIndex+1; i<=nTargetTrIndex-1; i++) {
                            if(this.isSelected(allRows[i])) {
                                this.unselectRow(allRows[i]);
                            }
                        }
                    }
                    // Unselect all rows between target row and anchor row
                    else {
                        for(i=nTargetTrIndex+1; i<=nAnchorTrIndex-1; i++) {
                            if(this.isSelected(allRows[i])) {
                                this.unselectRow(allRows[i]);
                            }
                        }
                    }
                    // Select the target row
                    this.selectRow(elTargetRow);
                }
            }
            // Invalid anchor
            else {
                // Set anchor
                this._sSelectionAnchorId = elTargetRow.id;

                // Toggle selection of target
                if(this.isSelected(elTargetRow)) {
                    this.unselectRow(elTargetRow);
                }
                else {
                    this.selectRow(elTargetRow);
                }
            }
        }
        // Only SHIFT
        else if((sMode != "single") && bSHIFT) {
            this.unselectAllRows();

            // Validate anchor
            if(elAnchorRow && YAHOO.lang.isNumber(elAnchorRow.sectionRowIndex)) {
                nAnchorTrIndex = elAnchorRow.sectionRowIndex;

                // Select all rows between anchor row and target row,
                // including the anchor row and target row
                if(nAnchorTrIndex < nTargetTrIndex) {
                    for(i=nAnchorTrIndex; i<=nTargetTrIndex; i++) {
                        this.selectRow(allRows[i]);
                    }
                }
                // Select all rows between target row and anchor row,
                // including the target row and anchor row
                else {
                    for(i=nAnchorTrIndex; i>=nTargetTrIndex; i--) {
                        this.selectRow(allRows[i]);
                    }
                }
            }
            // Invalid anchor
            else {
                // Set anchor
                this._sSelectionAnchorId = elTargetRow.id;

                // Select target row only
                this.selectRow(elTargetRow);
            }
        }
        // Only CTRL
        else if((sMode != "single") && bCTRL) {
            // Set anchor
            this._sSelectionAnchorId = elTargetRow.id;

            // Toggle selection of target
            if(this.isSelected(elTargetRow)) {
                this.unselectRow(elTargetRow);
            }
            else {
                this.selectRow(elTargetRow);
            }
        }
        // Neither SHIFT nor CTRL
        else if(sMode == "single") {
            this.unselectAllRows();
            this.selectRow(elTargetRow);
        }
        // Neither SHIFT nor CTRL
        else {
            // Set anchor
            this._sSelectionAnchorId = elTargetRow.id;

            // Select only target
            this.unselectAllRows();
            this.selectRow(elTargetRow);
        }
        YAHOO.util.Event.stopEvent(evt);

        // Clear any selections that are a byproduct of the click or dblclick
        var sel;
        if(window.getSelection) {
        	sel = window.getSelection();
        }
        else if(document.getSelection) {
        	sel = document.getSelection();
        }
        else if(document.selection) {
        	sel = document.selection;
        }
        if(sel) {
            if(sel.empty) {
                sel.empty();
            }
            else if (sel.removeAllRanges) {
                sel.removeAllRanges();
            }
            else if(sel.collapse) {
                sel.collapse();
            }
        }
    }
    else {
    }
};

/**
 * Overridable custom event handler to select cell.
 *
 * @method onEventSelectCell
 * @param oArgs.event {HTMLEvent} Event object.
 * @param oArgs.target {HTMLElement} Target element.
 */
YAHOO.widget.DataTable.prototype.onEventSelectCell = function(oArgs) {
    var sMode = this.get("selectionMode");
    if ((sMode == "standard") || (sMode == "single")) {
        return;
    }

    var evt = oArgs.event;
    var elTarget = oArgs.target;

    var bSHIFT = evt.shiftKey;
    var bCTRL = evt.ctrlKey;
    var i, j, nAnchorTrIndex, nAnchorTdIndex, currentRow, startIndex, endIndex;
    
    var elTargetCell = this.getTdEl(elTarget);
    if(elTargetCell) {
        var elTargetRow = this.getTrEl(elTargetCell);
        var allRows = this._elTbody.rows;
        var nTargetTrIndex = elTargetRow.sectionRowIndex;
        var nTargetTdIndex = elTarget.yuiCellIndex;
        var elAnchorCell = YAHOO.util.Dom.get(this._sSelectionAnchorId);

        // Both SHIFT and CTRL
        if((sMode != "singlecell") && bSHIFT && bCTRL) {
            // Validate anchor
            if(elAnchorCell && YAHOO.lang.isNumber(elAnchorCell.yuiCellIndex)) {
                nAnchorTrIndex = elAnchorCell.parentNode.sectionRowIndex;
                nAnchorTdIndex = elAnchorCell.yuiCellIndex;
                
                // Anchor is selected
                if(this.isSelected(elAnchorCell)) {
                    // All cells are on the same row
                    if(nAnchorTrIndex == nTargetTrIndex) {
                        // Select all cells between anchor cell and target cell, including target cell
                        if(nAnchorTdIndex < nTargetTdIndex) {
                            for(i=nAnchorTdIndex+1; i<=nTargetTdIndex; i++) {
                                this.selectCell(allRows[nTargetTrIndex].cells[i]);
                            }
                        }
                        // Select all cells between target cell and anchor cell, including target cell
                        else if(nTargetTdIndex < nAnchorTdIndex) {
                            for(i=nTargetTdIndex; i<nAnchorTdIndex; i++) {
                                this.selectCell(allRows[nTargetTrIndex].cells[i]);
                            }
                        }
                    }
                    // Anchor row is above target row
                    else if(nAnchorTrIndex < nTargetTrIndex) {
                        if(sMode == "cellrange") {
                            // Select all cells on anchor row from anchor cell to the end of the row
                            for(i=nAnchorTdIndex+1; i<allRows[nAnchorTrIndex].cells.length; i++) {
                                this.selectCell(allRows[nAnchorTrIndex].cells[i]);
                            }
                            
                            // Select all cells on all rows between anchor row and target row
                            for(i=nAnchorTrIndex+1; i<nTargetTrIndex; i++) {
                                for(j=0; j<allRows[i].cells.length; j++){
                                    this.selectCell(allRows[i].cells[j]);
                                }
                            }

                            // Select all cells on target row from first cell to the target cell
                            for(i=0; i<=nTargetTdIndex; i++) {
                                this.selectCell(allRows[nTargetTrIndex].cells[i]);
                            }
                        }
                        else if(sMode == "cellblock") {
                            startIndex = Math.min(nAnchorTdIndex, nTargetTdIndex);
                            endIndex = Math.max(nAnchorTdIndex, nTargetTdIndex);
                            
                            // Select all cells from startIndex to endIndex on rows between anchor row and target row
                            for(i=nAnchorTrIndex; i<=nTargetTrIndex; i++) {
                                for(j=startIndex; j<=endIndex; j++) {
                                    this.selectCell(allRows[i].cells[j]);
                                }
                            }
                        }
                    }
                    // Anchor row is below target row
                    else {
                        if(sMode == "cellrange") {
                            // Select all cells on target row from target cell to the end of the row
                            for(i=nTargetTdIndex; i<allRows[nTargetTrIndex].cells.length; i++) {
                                this.selectCell(allRows[nTargetTrIndex].cells[i]);
                            }

                            // Select all cells on all rows between target row and anchor row
                            for(i=nTargetTrIndex+1; i<nAnchorTrIndex; i++) {
                                for(j=0; j<allRows[i].cells.length; j++){
                                    this.selectCell(allRows[i].cells[j]);
                                }
                            }

                            // Select all cells on anchor row from first cell to the anchor cell
                            for(i=0; i<nAnchorTdIndex; i++) {
                                this.selectCell(allRows[nAnchorTrIndex].cells[i]);
                            }
                        }
                        else if(sMode == "cellblock") {
                            startIndex = Math.min(nAnchorTdIndex, nTargetTdIndex);
                            endIndex = Math.max(nAnchorTdIndex, nTargetTdIndex);

                            // Select all cells from startIndex to endIndex on rows between target row and anchor row
                            for(i=nAnchorTrIndex; i>=nTargetTrIndex; i--) {
                                for(j=endIndex; j>=startIndex; j--) {
                                    this.selectCell(allRows[i].cells[j]);
                                }
                            }
                        }
                    }
                }
                // Anchor cell is unselected
                else {
                    // All cells are on the same row
                    if(nAnchorTrIndex == nTargetTrIndex) {
                        // Unselect all cells between anchor cell and target cell
                        if(nAnchorTdIndex < nTargetTdIndex) {
                            for(i=nAnchorTdIndex+1; i<nTargetTdIndex; i++) {
                                this.unselectCell(allRows[nTargetTrIndex].cells[i]);
                            }
                        }
                        // Select all cells between target cell and anchor cell
                        else if(nTargetTdIndex < nAnchorTdIndex) {
                            for(i=nTargetTdIndex+1; i<nAnchorTdIndex; i++) {
                                this.unselectCell(allRows[nTargetTrIndex].cells[i]);
                            }
                        }
                    }
                    // Anchor row is above target row
                    if(nAnchorTrIndex < nTargetTrIndex) {
                        // Unselect all cells from anchor cell to target cell
                        for(i=nAnchorTrIndex; i<=nTargetTrIndex; i++) {
                            currentRow = allRows[i];
                            for(j=0; j<currentRow.cells.length; j++) {
                                // This is the anchor row, only unselect cells after the anchor cell
                                if(currentRow.sectionRowIndex == nAnchorTrIndex) {
                                    if(j>nAnchorTdIndex) {
                                        this.unselectCell(currentRow.cells[j]);
                                    }
                                }
                                // This is the target row, only unelect cells before the target cell
                                else if(currentRow.sectionRowIndex == nTargetTrIndex) {
                                    if(j<nTargetTdIndex) {
                                        this.unselectCell(currentRow.cells[j]);
                                    }
                                }
                                // Unselect all cells on this row
                                else {
                                    this.unselectCell(currentRow.cells[j]);
                                }
                            }
                        }
                    }
                    // Anchor row is below target row
                    else {
                        // Unselect all cells from target cell to anchor cell
                        for(i=nTargetTrIndex; i<=nAnchorTrIndex; i++) {
                            currentRow = allRows[i];
                            for(j=0; j<currentRow.cells.length; j++) {
                                // This is the target row, only unselect cells after the target cell
                                if(currentRow.sectionRowIndex == nTargetTrIndex) {
                                    if(j>nTargetTdIndex) {
                                        this.unselectCell(currentRow.cells[j]);
                                    }
                                }
                                // This is the anchor row, only unselect cells before the anchor cell
                                else if(currentRow.sectionRowIndex == nAnchorTrIndex) {
                                    if(j<nAnchorTdIndex) {
                                        this.unselectCell(currentRow.cells[j]);
                                    }
                                }
                                // Unselect all cells on this row
                                else {
                                    this.unselectCell(currentRow.cells[j]);
                                }
                            }
                        }
                    }

                    // Select the target cell
                    this.selectCell(elTargetCell);
                }
            }
            // Invalid anchor
            else {
                // Set anchor
                this._sSelectionAnchorId = elTargetCell.id;

                // Toggle selection of target
                if(this.isSelected(elTargetCell)) {
                    this.unselectCell(elTargetCell);
                }
                else {
                    this.selectCell(elTargetCell);
                }
            }
        }
        // Only SHIFT
        else if((sMode != "singlecell") && bSHIFT) {
            this.unselectAllCells();

            // Validate anchor
            if(elAnchorCell && YAHOO.lang.isNumber(elAnchorCell.yuiCellIndex)) {
                nAnchorTrIndex = elAnchorCell.parentNode.sectionRowIndex;
                nAnchorTdIndex = elAnchorCell.yuiCellIndex;
                
                // All cells are on the same row
                if(nAnchorTrIndex == nTargetTrIndex) {
                    // Select all cells between anchor cell and target cell,
                    // including the anchor cell and target cell
                    if(nAnchorTdIndex < nTargetTdIndex) {
                        for(i=nAnchorTdIndex; i<=nTargetTdIndex; i++) {
                            this.selectCell(allRows[nTargetTrIndex].cells[i]);
                        }
                    }
                    // Select all cells between target cell and anchor cell
                    // including the target cell and anchor cell
                    else if(nTargetTdIndex < nAnchorTdIndex) {
                        for(i=nTargetTdIndex; i<=nAnchorTdIndex; i++) {
                            this.selectCell(allRows[nTargetTrIndex].cells[i]);
                        }
                    }
                }
                // Anchor row is above target row
                else if(nAnchorTrIndex < nTargetTrIndex) {
                    if(sMode == "cellrange") {
                        // Select all cells from anchor cell to target cell
                        // including the anchor cell and target cell
                        for(i=nAnchorTrIndex; i<=nTargetTrIndex; i++) {
                            currentRow = allRows[i];
                            for(j=0; j<currentRow.cells.length; j++) {
                                // This is the anchor row, only select the anchor cell and after
                                if(currentRow.sectionRowIndex == nAnchorTrIndex) {
                                    if(j>=nAnchorTdIndex) {
                                        this.selectCell(currentRow.cells[j]);
                                    }
                                }
                                // This is the target row, only select the target cell and before
                                else if(currentRow.sectionRowIndex == nTargetTrIndex) {
                                    if(j<=nTargetTdIndex) {
                                        this.selectCell(currentRow.cells[j]);
                                    }
                                }
                                // Select all cells on this row
                                else {
                                    this.selectCell(currentRow.cells[j]);
                                }
                            }
                        }
                    }
                    else if(sMode == "cellblock") {
                        // Select the cellblock from anchor cell to target cell
                        // including the anchor cell and the target cell
                        startIndex = Math.min(nAnchorTdIndex, nTargetTdIndex);
                        endIndex = Math.max(nAnchorTdIndex, nTargetTdIndex);

                        for(i=nAnchorTrIndex; i<=nTargetTrIndex; i++) {
                            for(j=startIndex; j<=endIndex; j++) {
                                this.selectCell(allRows[i].cells[j]);
                            }
                        }
                        
                        this._sLastSelectedId = allRows[nTargetTrIndex].cells[nTargetTdIndex].id;
                    }
                }
                // Anchor row is below target row
                else {
                    if(sMode == "cellrange") {
                        // Select all cells from target cell to anchor cell,
                        // including the target cell and anchor cell
                        for(i=nTargetTrIndex; i<=nAnchorTrIndex; i++) {
                            currentRow = allRows[i];
                            for(j=0; j<currentRow.cells.length; j++) {
                                // This is the target row, only select the target cell and after
                                if(currentRow.sectionRowIndex == nTargetTrIndex) {
                                    if(j>=nTargetTdIndex) {
                                        this.selectCell(currentRow.cells[j]);
                                    }
                                }
                                // This is the anchor row, only select the anchor cell and before
                                else if(currentRow.sectionRowIndex == nAnchorTrIndex) {
                                    if(j<=nAnchorTdIndex) {
                                        this.selectCell(currentRow.cells[j]);
                                    }
                                }
                                // Select all cells on this row
                                else {
                                    this.selectCell(currentRow.cells[j]);
                                }
                            }
                        }
                    }
                    else if(sMode == "cellblock") {
                        // Select the cellblock from target cell to anchor cell
                        // including the target cell and the anchor cell
                        startIndex = Math.min(nAnchorTdIndex, nTargetTdIndex);
                        endIndex = Math.max(nAnchorTdIndex, nTargetTdIndex);

                        for(i=nTargetTrIndex; i<=nAnchorTrIndex; i++) {
                            for(j=startIndex; j<=endIndex; j++) {
                                this.selectCell(allRows[i].cells[j]);
                            }
                        }
                        
                        this._sLastSelectedId = allRows[nTargetTrIndex].cells[nTargetTdIndex].id;
                    }
                }
            }
            // Invalid anchor
            else {
                // Set anchor
                this._sSelectionAnchorId = elTargetCell.id;

                // Select target only
                this.selectCell(elTargetCell);
            }
        }
        // Only CTRL
        else if((sMode != "singlecell") && bCTRL) {
            // Set anchor
            this._sSelectionAnchorId = elTargetCell.id;

            // Toggle selection of target
            if(this.isSelected(elTargetCell)) {
                this.unselectCell(elTargetCell);
            }
            else {
                this.selectCell(elTargetCell);
            }
        }
        // Neither SHIFT nor CTRL, or multi-selection has been disabled
        else {
            // Set anchor
            this._sSelectionAnchorId = elTargetCell.id;

            // Select only target
            this.unselectAllCells();
            this.selectCell(elTargetCell);
        }

        YAHOO.util.Event.stopEvent(evt);

        // Clear any selections that are a byproduct of the click or dblclick
        var sel;
        if(window.getSelection) {
        	sel = window.getSelection();
        }
        else if(document.getSelection) {
        	sel = document.getSelection();
        }
        else if(document.selection) {
        	sel = document.selection;
        }
        if(sel) {
            if(sel.empty) {
                sel.empty();
            }
            else if (sel.removeAllRanges) {
                sel.removeAllRanges();
            }
            else if(sel.collapse) {
                sel.collapse();
            }
        }
    }
    else {
    }
};











/**
 * Overridable custom event handler to highlight row.
 *
 * @method onEventHighlightRow
 * @param oArgs.event {HTMLEvent} Event object.
 * @param oArgs.target {HTMLElement} Target element.
 */
YAHOO.widget.DataTable.prototype.onEventHighlightRow = function(oArgs) {
    var evt = oArgs.event;
    var elTarget = oArgs.target;
    this.highlightRow(elTarget);
};

/**
 * Overridable custom event handler to unhighlight row.
 *
 * @method onEventUnhighlightRow
 * @param oArgs.event {HTMLEvent} Event object.
 * @param oArgs.target {HTMLElement} Target element.
 */
YAHOO.widget.DataTable.prototype.onEventUnhighlightRow = function(oArgs) {
    var evt = oArgs.event;
    var elTarget = oArgs.target;
    this.unhighlightRow(elTarget);
};

/**
 * Overridable custom event handler to highlight cell.
 *
 * @method onEventHighlightCell
 * @param oArgs.event {HTMLEvent} Event object.
 * @param oArgs.target {HTMLElement} Target element.
 */
YAHOO.widget.DataTable.prototype.onEventHighlightCell = function(oArgs) {
    var evt = oArgs.event;
    var elTarget = oArgs.target;
    this.highlightCell(elTarget);
};

/**
 * Overridable custom event handler to unhighlight cell.
 *
 * @method onEventUnhighlightCell
 * @param oArgs.event {HTMLEvent} Event object.
 * @param oArgs.target {HTMLElement} Target element.
 */
YAHOO.widget.DataTable.prototype.onEventUnhighlightCell = function(oArgs) {
    var evt = oArgs.event;
    var elTarget = oArgs.target;
    this.unhighlightCell(elTarget);
};

/**
 * Overridable custom event handler to format cell.
 *
 * @method onEventFormatCell
 * @param oArgs.event {HTMLEvent} Event object.
 * @param oArgs.target {HTMLElement} Target element.
 */
YAHOO.widget.DataTable.prototype.onEventFormatCell = function(oArgs) {
    var evt = oArgs.event;
    var target = oArgs.target;
    var elTag = target.tagName.toLowerCase();

    var elCell = this.getTdEl(target);
    if(elCell && YAHOO.lang.isNumber(elCell.yuiColumnId)) {
        var oColumn = this._oColumnSet.getColumn(elCell.yuiColumnId);
        this.formatCell(elCell, this.getRecord(elCell), oColumn);
    }
    else {
    }
};

/**
 * Overridable custom event handler to edit cell.
 *
 * @method onEventShowCellEditor
 * @param oArgs.event {HTMLEvent} Event object.
 * @param oArgs.target {HTMLElement} Target element.
 */
YAHOO.widget.DataTable.prototype.onEventShowCellEditor = function(oArgs) {
    var evt = oArgs.event;
    var target = oArgs.target;
    var elTag = target.tagName.toLowerCase();

    var elCell = this.getTdEl(target);
    if(elCell) {
        this.showCellEditor(elCell);
    }
    else {
    }
};
// Backward compatibility
YAHOO.widget.DataTable.prototype.onEventEditCell = function(oArgs) {
    this.onEventShowCellEditor(oArgs);
};

/**
 * Overridable custom event handler to save Cell Editor input.
 *
 * @method onEventSaveCellEditor
 * @param oArgs.editor {Object} Cell Editor object literal.
 */
YAHOO.widget.DataTable.prototype.onEventSaveCellEditor = function(oArgs) {
    this.saveCellEditor();
};

/**
 * Callback function for creating a progressively enhanced DataTable first
 * receives data from DataSource and populates the RecordSet, then initializes
 * DOM elements.
 *
 * @method _onDataReturnEnhanceTable
 * @param sRequest {String} Original request.
 * @param oResponse {Object} Response object.
 * @param bError {Boolean} (optional) True if there was a data error.
 * @private
 */
YAHOO.widget.DataTable.prototype._onDataReturnEnhanceTable = function(sRequest, oResponse) {
    // Pass data through abstract method for any transformations
    var ok = this.doBeforeLoadData(sRequest, oResponse);

    // Data ok to populate
    if(ok && oResponse && !oResponse.error && YAHOO.lang.isArray(oResponse.results)) {
        // Update RecordSet
        this._oRecordSet.addRecords(oResponse.results);

        // Initialize DOM elements
        this._initTableEl();
        if(!this._elTable || !this._elThead || !this._elTbody) {
            return;
        }

        // Call Element's constructor after DOM elements are created
        // but *before* UI is updated with data
        YAHOO.widget.DataTable.superclass.constructor.call(this, this._elContainer, this._oConfigs);

        //HACK: Set the Paginator values
        if(this._oConfigs.paginator) {
            this.updatePaginator(this._oConfigs.paginator);
        }

        // Update the UI
        this.refreshView();
    }
    // Error
    else if(ok && oResponse.error) {
        this.showTableMessage(YAHOO.widget.DataTable.MSG_ERROR, YAHOO.widget.DataTable.CLASS_ERROR);
    }
    // Empty
    else if(ok){
        this.showTableMessage(YAHOO.widget.DataTable.MSG_EMPTY, YAHOO.widget.DataTable.CLASS_EMPTY);
    }
};
    
/**
 * Callback function receives data from DataSource and populates an entire
 * DataTable with Records and TR elements, clearing previous Records, if any.
 *
 * @method onDataReturnInitializeTable
 * @param sRequest {String} Original request.
 * @param oResponse {Object} Response object.
 * @param bError {Boolean} (optional) True if there was a data error.
 */
YAHOO.widget.DataTable.prototype.onDataReturnInitializeTable = function(sRequest, oResponse) {
    this.fireEvent("dataReturnEvent", {request:sRequest,response:oResponse});

    // Pass data through abstract method for any transformations
    var ok = this.doBeforeLoadData(sRequest, oResponse);

    // Data ok to populate
    if(ok && oResponse && !oResponse.error && YAHOO.lang.isArray(oResponse.results)) {
        this.initializeTable(oResponse.results);
    }
    // Error
    else if(ok && oResponse.error) {
        this.showTableMessage(YAHOO.widget.DataTable.MSG_ERROR, YAHOO.widget.DataTable.CLASS_ERROR);
    }
    // Empty
    else if(ok){
        this.showTableMessage(YAHOO.widget.DataTable.MSG_EMPTY, YAHOO.widget.DataTable.CLASS_EMPTY);
    }
};
// Backward compatibility
YAHOO.widget.DataTable.prototype.onDataReturnReplaceRows = function(sRequest, oResponse) {
    this.onDataReturnInitializeTable(sRequest, oResponse);
};

/**
 * Callback function receives data from DataSource and appends to an existing
 * DataTable new Records and, if applicable, creates or updates
 * corresponding TR elements.
 *
 * @method onDataReturnAppendRows
 * @param sRequest {String} Original request.
 * @param oResponse {Object} Response object.
 * @param bError {Boolean} (optional) True if there was a data error.
 */
YAHOO.widget.DataTable.prototype.onDataReturnAppendRows = function(sRequest, oResponse) {
    this.fireEvent("dataReturnEvent", {request:sRequest,response:oResponse});
    
    // Pass data through abstract method for any transformations
    var ok = this.doBeforeLoadData(sRequest, oResponse);
    
    // Data ok to append
    if(ok && oResponse && !oResponse.error && YAHOO.lang.isArray(oResponse.results)) {
        this.addRows(oResponse.results);
    }
    // Error
    else if(ok && oResponse.error) {
        this.showTableMessage(YAHOO.widget.DataTable.MSG_ERROR, YAHOO.widget.DataTable.CLASS_ERROR);
    }
};

/**
 * Callback function receives data from DataSource and inserts into top of an
 * existing DataTable new Records and, if applicable, creates or updates
 * corresponding TR elements.
 *
 * @method onDataReturnInsertRows
 * @param sRequest {String} Original request.
 * @param oResponse {Object} Response object.
 * @param bError {Boolean} (optional) True if there was a data error.
 */
YAHOO.widget.DataTable.prototype.onDataReturnInsertRows = function(sRequest, oResponse) {
    this.fireEvent("dataReturnEvent", {request:sRequest,response:oResponse});
    
    // Pass data through abstract method for any transformations
    var ok = this.doBeforeLoadData(sRequest, oResponse);
    
    // Data ok to append
    if(ok && oResponse && !oResponse.error && YAHOO.lang.isArray(oResponse.results)) {
        this.addRows(oResponse.results, 0);
    }
    // Error
    else if(ok && oResponse.error) {
        this.showTableMessage(YAHOO.widget.DataTable.MSG_ERROR, YAHOO.widget.DataTable.CLASS_ERROR);
    }
};



































    /////////////////////////////////////////////////////////////////////////////
    //
    // Custom Events
    //
    /////////////////////////////////////////////////////////////////////////////

    /**
     * Fired when the DataTable instance's initialization is complete.
     *
     * @event initEvent
     */

    /**
     * Fired when the DataTable's view is refreshed.
     *
     * @event refreshEvent
     */

    /**
     * Fired when data is returned from DataSource.
     *
     * @event dataReturnEvent
     * @param oArgs.request {String} Original request.
     * @param oArgs.response {Object} Response object.
     */

    /**
     * Fired when the DataTable has a focus.
     *
     * @event tableFocusEvent
     */

    /**
     * Fired when the DataTable has a blur.
     *
     * @event tableBlurEvent
     */

    /**
     * Fired when the DataTable has a mouseover.
     *
     * @event tableMouseoverEvent
     * @param oArgs.event {HTMLEvent} The event object.
     * @param oArgs.target {HTMLElement} The DataTable's TABLE element.
     *
     */

    /**
     * Fired when the DataTable has a mouseout.
     *
     * @event tableMouseoutEvent
     * @param oArgs.event {HTMLEvent} The event object.
     * @param oArgs.target {HTMLElement} The DataTable's TABLE element.
     *
     */

    /**
     * Fired when the DataTable has a mousedown.
     *
     * @event tableMousedownEvent
     * @param oArgs.event {HTMLEvent} The event object.
     * @param oArgs.target {HTMLElement} The DataTable's TABLE element.
     *
     */

    /**
     * Fired when the DataTable has a click.
     *
     * @event tableClickEvent
     * @param oArgs.event {HTMLEvent} The event object.
     * @param oArgs.target {HTMLElement} The DataTable's TABLE element.
     *
     */

    /**
     * Fired when the DataTable has a dblclick.
     *
     * @event tableDblclickEvent
     * @param oArgs.event {HTMLEvent} The event object.
     * @param oArgs.target {HTMLElement} The DataTable's TABLE element.
     *
     */

    /**
     * Fired when a fixed scrolling DataTable has a scroll.
     *
     * @event tableScrollEvent
     * @param oArgs.event {HTMLEvent} The event object.
     * @param oArgs.target {HTMLElement} The DataTable's CONTAINER element (in IE)
     * or the DataTable's TBODY element (everyone else).
     *
     */

    /**
     * Fired when a message is shown in the DataTable's message element.
     *
     * @event tableMsgShowEvent
     * @param oArgs.html {String} The HTML displayed.
     * @param oArgs.className {String} The className assigned.
     *
     */

    /**
     * Fired when the DataTable's message element is hidden.
     *
     * @event tableMsgHideEvent
     */

    /**
     * Fired when a header row has a mouseover.
     *
     * @event headerRowMouseoverEvent
     * @param oArgs.event {HTMLEvent} The event object.
     * @param oArgs.target {HTMLElement} The TR element.
     */

    /**
     * Fired when a header row has a mouseout.
     *
     * @event headerRowMouseoutEvent
     * @param oArgs.event {HTMLEvent} The event object.
     * @param oArgs.target {HTMLElement} The TR element.
     */

    /**
     * Fired when a header row has a mousedown.
     *
     * @event headerRowMousedownEvent
     * @param oArgs.event {HTMLEvent} The event object.
     * @param oArgs.target {HTMLElement} The TR element.
     */

    /**
     * Fired when a header row has a click.
     *
     * @event headerRowClickEvent
     * @param oArgs.event {HTMLEvent} The event object.
     * @param oArgs.target {HTMLElement} The TR element.
     */

    /**
     * Fired when a header row has a dblclick.
     *
     * @event headerRowDblclickEvent
     * @param oArgs.event {HTMLEvent} The event object.
     * @param oArgs.target {HTMLElement} The TR element.
     */

    /**
     * Fired when a header cell has a mouseover.
     *
     * @event headerCellMouseoverEvent
     * @param oArgs.event {HTMLEvent} The event object.
     * @param oArgs.target {HTMLElement} The TH element.
     *
     */

    /**
     * Fired when a header cell has a mouseout.
     *
     * @event headerCellMouseoutEvent
     * @param oArgs.event {HTMLEvent} The event object.
     * @param oArgs.target {HTMLElement} The TH element.
     *
     */

    /**
     * Fired when a header cell has a mousedown.
     *
     * @event headerCellMousedownEvent
     * @param oArgs.event {HTMLEvent} The event object.
     * @param oArgs.target {HTMLElement} The TH element.
     */

    /**
     * Fired when a header cell has a click.
     *
     * @event headerCellClickEvent
     * @param oArgs.event {HTMLEvent} The event object.
     * @param oArgs.target {HTMLElement} The TH element.
     */

    /**
     * Fired when a header cell has a dblclick.
     *
     * @event headerCellDblclickEvent
     * @param oArgs.event {HTMLEvent} The event object.
     * @param oArgs.target {HTMLElement} The TH element.
     */

    /**
     * Fired when a header label has a mouseover.
     *
     * @event headerLabelMouseoverEvent
     * @param oArgs.event {HTMLEvent} The event object.
     * @param oArgs.target {HTMLElement} The SPAN element.
     *
     */

    /**
     * Fired when a header label has a mouseout.
     *
     * @event headerLabelMouseoutEvent
     * @param oArgs.event {HTMLEvent} The event object.
     * @param oArgs.target {HTMLElement} The SPAN element.
     *
     */

    /**
     * Fired when a header label has a mousedown.
     *
     * @event headerLabelMousedownEvent
     * @param oArgs.event {HTMLEvent} The event object.
     * @param oArgs.target {HTMLElement} The SPAN element.
     */

    /**
     * Fired when a header label has a click.
     *
     * @event headerLabelClickEvent
     * @param oArgs.event {HTMLEvent} The event object.
     * @param oArgs.target {HTMLElement} The SPAN element.
     */

    /**
     * Fired when a header label has a dblclick.
     *
     * @event headerLabelDblclickEvent
     * @param oArgs.event {HTMLEvent} The event object.
     * @param oArgs.target {HTMLElement} The SPAN element.
     */

    /**
     * Fired when a column is sorted.
     *
     * @event columnSortEvent
     * @param oArgs.column {YAHOO.widget.Column} The Column instance.
     * @param oArgs.dir {String} Sort direction "asc" or "desc".
     */

    /**
     * Fired when a column is resized.
     *
     * @event columnResizeEvent
     * @param oArgs.column {YAHOO.widget.Column} The Column instance.
     * @param oArgs.target {HTMLElement} The TH element.
     */

    /**
     * Fired when a row has a mouseover.
     *
     * @event rowMouseoverEvent
     * @param oArgs.event {HTMLEvent} The event object.
     * @param oArgs.target {HTMLElement} The TR element.
     */

    /**
     * Fired when a row has a mouseout.
     *
     * @event rowMouseoutEvent
     * @param oArgs.event {HTMLEvent} The event object.
     * @param oArgs.target {HTMLElement} The TR element.
     */

    /**
     * Fired when a row has a mousedown.
     *
     * @event rowMousedownEvent
     * @param oArgs.event {HTMLEvent} The event object.
     * @param oArgs.target {HTMLElement} The TR element.
     */

    /**
     * Fired when a row has a click.
     *
     * @event rowClickEvent
     * @param oArgs.event {HTMLEvent} The event object.
     * @param oArgs.target {HTMLElement} The TR element.
     */

    /**
     * Fired when a row has a dblclick.
     *
     * @event rowDblclickEvent
     * @param oArgs.event {HTMLEvent} The event object.
     * @param oArgs.target {HTMLElement} The TR element.
     */

    /**
     * Fired when a row is added.
     *
     * @event rowAddEvent
     * @param oArgs.record {YAHOO.widget.Record} The added Record.
     */

    /**
     * Fired when a row is updated.
     *
     * @event rowUpdateEvent
     * @param oArgs.record {YAHOO.widget.Record} The updated Record.
     * @param oArgs.oldData {Object} Object literal of the old data.
     */

    /**
     * Fired when a row is deleted.
     *
     * @event rowDeleteEvent
     * @param oArgs.oldData {Object} Object literal of the deleted data.
     * @param oArgs.recordIndex {Number} Index of the deleted Record.
     * @param oArgs.trElIndex {Number} Index of the deleted TR element, if in view.
     */

    /**
     * Fired when a row is selected.
     *
     * @event rowSelectEvent
     * @param oArgs.el {HTMLElement} The selected TR element, if applicable.
     * @param oArgs.record {YAHOO.widget.Record} The selected Record.
     */

    /**
     * Fired when a row is unselected.
     *
     * @event rowUnselectEvent
     * @param oArgs.el {HTMLElement} The unselected TR element, if applicable.
     * @param oArgs.record {YAHOO.widget.Record} The unselected Record.
     */

    /*TODO: delete and use rowUnselectEvent?
     * Fired when all row selections are cleared.
     *
     * @event unselectAllRowsEvent
     */

    /*
     * Fired when a row is highlighted.
     *
     * @event rowHighlightEvent
     * @param oArgs.el {HTMLElement} The highlighted TR element.
     * @param oArgs.record {YAHOO.widget.Record} The highlighted Record.
     */

    /*
     * Fired when a row is unhighlighted.
     *
     * @event rowUnhighlightEvent
     * @param oArgs.el {HTMLElement} The highlighted TR element.
     * @param oArgs.record {YAHOO.widget.Record} The highlighted Record.
     */

    /**
     * Fired when a cell has a mouseover.
     *
     * @event cellMouseoverEvent
     * @param oArgs.event {HTMLEvent} The event object.
     * @param oArgs.target {HTMLElement} The TD element.
     */

    /**
     * Fired when a cell has a mouseout.
     *
     * @event cellMouseoutEvent
     * @param oArgs.event {HTMLEvent} The event object.
     * @param oArgs.target {HTMLElement} The TD element.
     */

    /**
     * Fired when a cell has a mousedown.
     *
     * @event cellMousedownEvent
     * @param oArgs.event {HTMLEvent} The event object.
     * @param oArgs.target {HTMLElement} The TD element.
     */

    /**
     * Fired when a cell has a click.
     *
     * @event cellClickEvent
     * @param oArgs.event {HTMLEvent} The event object.
     * @param oArgs.target {HTMLElement} The TD element.
     */

    /**
     * Fired when a cell has a dblclick.
     *
     * @event cellDblclickEvent
     * @param oArgs.event {HTMLEvent} The event object.
     * @param oArgs.target {HTMLElement} The TD element.
     */

    /**
     * Fired when a cell is formatted.
     *
     * @event cellFormatEvent
     * @param oArgs.el {HTMLElement} The formatted TD element.
     * @param oArgs.record {YAHOO.widget.Record} The formatted Record.
     * @param oArgs.key {String} The key of the formatted cell.
     */

    /**
     * Fired when a cell is selected.
     *
     * @event cellSelectEvent
     * @param oArgs.el {HTMLElement} The selected TD element.
     * @param oArgs.record {YAHOO.widget.Record} The selected Record.
     * @param oArgs.key {String} The key of the selected cell.
     */

    /**
     * Fired when a cell is unselected.
     *
     * @event cellUnselectEvent
     * @param oArgs.el {HTMLElement} The unselected TD element.
     * @param oArgs.record {YAHOO.widget.Record} The unselected Record.
     * @param oArgs.key {String} The key of the unselected cell.
     */

    /**
     * Fired when a cell is highlighted.
     *
     * @event cellHighlightEvent
     * @param oArgs.el {HTMLElement} The highlighted TD element.
     * @param oArgs.record {YAHOO.widget.Record} The highlighted Record.
     * @param oArgs.key {String} The key of the highlighted cell.
     */

    /**
     * Fired when a cell is unhighlighted.
     *
     * @event cellUnhighlightEvent
     * @param oArgs.el {HTMLElement} The unhighlighted TD element.
     * @param oArgs.record {YAHOO.widget.Record} The unhighlighted Record.
     * @param oArgs.key {String} The key of the unhighlighted cell.
     */

    /*TODO: hide from doc and use cellUnselectEvent
     * Fired when all cell selections are cleared.
     *
     * @event unselectAllCellsEvent
     */

    /*TODO: implement
     * Fired when DataTable paginator is updated.
     *
     * @event paginatorUpdateEvent
     * @param paginator {Object} Object literal of Paginator values.
     */

    /**
     * Fired when an Editor is activated.
     *
     * @event editorShowEvent
     * @param oArgs.editor {Object} The Editor object literal.
     */

    /**
     * Fired when an active Editor has a keydown.
     *
     * @event editorKeydownEvent
     * @param oArgs.editor {Object} The Editor object literal.
     * @param oArgs.event {HTMLEvent} The event object.
     */

    /**
     * Fired when Editor input is reverted.
     *
     * @event editorRevertEvent
     * @param oArgs.editor {Object} The Editor object literal.
     * @param oArgs.newData {Object} New data value.
     * @param oArgs.oldData {Object} Old data value.
     */

    /**
     * Fired when Editor input is saved.
     *
     * @event editorSaveEvent
     * @param oArgs.editor {Object} The Editor object literal.
     * @param oArgs.newData {Object} New data value.
     * @param oArgs.oldData {Object} Old data value.
     */

    /**
     * Fired when Editor input is canceled.
     *
     * @event editorCancelEvent
     * @param oArgs.editor {Object} The Editor object literal.
     */

    /**
     * Fired when an active Editor has a blur.
     *
     * @event editorBlurEvent
     * @param oArgs.editor {Object} The Editor object literal.
     */







    /**
     * Fired when a link is clicked.
     *
     * @event linkClickEvent
     * @param oArgs.event {HTMLEvent} The event object.
     * @param oArgs.target {HTMLElement} The A element.
     */

    /**
     * Fired when a BUTTON element is clicked.
     *
     * @event buttonClickEvent
     * @param oArgs.event {HTMLEvent} The event object.
     * @param oArgs.target {HTMLElement} The BUTTON element.
     */

    /**
     * Fired when a CHECKBOX element is clicked.
     *
     * @event checkboxClickEvent
     * @param oArgs.event {HTMLEvent} The event object.
     * @param oArgs.target {HTMLElement} The CHECKBOX element.
     */

    /*TODO
     * Fired when a SELECT element is changed.
     *
     * @event dropdownChangeEvent
     * @param oArgs.event {HTMLEvent} The event object.
     * @param oArgs.target {HTMLElement} The SELECT element.
     */

    /**
     * Fired when a RADIO element is clicked.
     *
     * @event radioClickEvent
     * @param oArgs.event {HTMLEvent} The event object.
     * @param oArgs.target {HTMLElement} The RADIO element.
     */


/****************************************************************************/
/****************************************************************************/
/****************************************************************************/

/**
 * The ColumnSet class defines and manages a DataTable's Columns,
 * including nested hierarchies and access to individual Column instances.
 *
 * @namespace YAHOO.widget
 * @class ColumnSet
 * @uses YAHOO.util.EventProvider
 * @constructor
 * @param aHeaders {Object[]} Array of object literals that define header cells.
 */
YAHOO.widget.ColumnSet = function(aHeaders) {
    this._sName = "instance" + YAHOO.widget.ColumnSet._nCount;

    // DOM tree representation of all Columns
    var tree = [];
    // Flat representation of all Columns
    var flat = [];
    // Flat representation of only Columns that are meant to display data
    var keys = [];
    // Array of HEADERS attribute values for all keys in the "keys" array
    var headers = [];

    // Tracks current node list depth being tracked
    var nodeDepth = -1;

    // Internal recursive function to defined Column instances
    var parseColumns = function(nodeList, parent) {
        // One level down
        nodeDepth++;

        // Create corresponding tree node if not already there for this depth
        if(!tree[nodeDepth]) {
            tree[nodeDepth] = [];
        }


        // Parse each node at this depth for attributes and any children
        for(var j=0; j<nodeList.length; j++) {
            var currentNode = nodeList[j];

            // Instantiate a new Column for each node
            var oColumn = new YAHOO.widget.Column(currentNode);

            // Add the new Column to the flat list
            flat.push(oColumn);

            // Assign its parent as an attribute, if applicable
            if(parent) {
                oColumn.parent = parent;
            }

            // The Column has descendants
            if(YAHOO.lang.isArray(currentNode.children)) {
                oColumn.children = currentNode.children;

                // Determine COLSPAN value for this Column
                var terminalChildNodes = 0;
                var countTerminalChildNodes = function(ancestor) {
                    var descendants = ancestor.children;
                    // Drill down each branch and count terminal nodes
                    for(var k=0; k<descendants.length; k++) {
                        // Keep drilling down
                        if(YAHOO.lang.isArray(descendants[k].children)) {
                            countTerminalChildNodes(descendants[k]);
                        }
                        // Reached branch terminus
                        else {
                            terminalChildNodes++;
                        }
                    }
                };
                countTerminalChildNodes(currentNode);
                oColumn._colspan = terminalChildNodes;

                // Cascade certain properties to children if not defined on their own
                var currentChildren = currentNode.children;
                for(var k=0; k<currentChildren.length; k++) {
                    var child = currentChildren[k];
                    if(oColumn.className && (child.className === undefined)) {
                        child.className = oColumn.className;
                    }
                    if(oColumn.editor && (child.editor === undefined)) {
                        child.editor = oColumn.editor;
                    }
                    if(oColumn.editorOptions && (child.editorOptions === undefined)) {
                        child.editorOptions = oColumn.editorOptions;
                    }
                    if(oColumn.formatter && (child.formatter === undefined)) {
                        child.formatter = oColumn.formatter;
                    }
                    if(oColumn.resizeable && (child.resizeable === undefined)) {
                        child.resizeable = oColumn.resizeable;
                    }
                    if(oColumn.sortable && (child.sortable === undefined)) {
                        child.sortable = oColumn.sortable;
                    }
                    if(oColumn.width && (child.width === undefined)) {
                        child.width = oColumn.width;
                    }
                    // Backward compatibility
                    if(oColumn.type && (child.type === undefined)) {
                        child.type = oColumn.type;
                    }
                    if(oColumn.type && !oColumn.formatter) {
                        oColumn.formatter = oColumn.type;
                    }
                    if(oColumn.text && !YAHOO.lang.isValue(oColumn.label)) {
                        oColumn.label = oColumn.text;
                    }
                    if(oColumn.parser) {
                    }
                    if(oColumn.sortOptions && ((oColumn.sortOptions.ascFunction) ||
                            (oColumn.sortOptions.descFunction))) {
                    }
                }

                // The children themselves must also be parsed for Column instances
                if(!tree[nodeDepth+1]) {
                    tree[nodeDepth+1] = [];
                }
                parseColumns(currentChildren, oColumn);
            }
            // This Column does not have any children
            else {
                oColumn._nKeyIndex = keys.length;
                oColumn._colspan = 1;
                keys.push(oColumn);
            }

            // Add the Column to the top-down tree
            tree[nodeDepth].push(oColumn);
        }
        nodeDepth--;
    };

    // Parse out Column instances from the array of object literals
    if(YAHOO.lang.isArray(aHeaders)) {
        parseColumns(aHeaders);
    }

    // Determine ROWSPAN value for each Column in the tree
    var parseTreeForRowspan = function(tree) {
        var maxRowDepth = 1;
        var currentRow;
        var currentColumn;

        // Calculate the max depth of descendants for this row
        var countMaxRowDepth = function(row, tmpRowDepth) {
            tmpRowDepth = tmpRowDepth || 1;

            for(var n=0; n<row.length; n++) {
                var col = row[n];
                // Column has children, so keep counting
                if(YAHOO.lang.isArray(col.children)) {
                    tmpRowDepth++;
                    countMaxRowDepth(col.children, tmpRowDepth);
                    tmpRowDepth--;
                }
                // No children, is it the max depth?
                else {
                    if(tmpRowDepth > maxRowDepth) {
                        maxRowDepth = tmpRowDepth;
                    }
                }

            }
        };

        // Count max row depth for each row
        for(var m=0; m<tree.length; m++) {
            currentRow = tree[m];
            countMaxRowDepth(currentRow);

            // Assign the right ROWSPAN values to each Column in the row
            for(var p=0; p<currentRow.length; p++) {
                currentColumn = currentRow[p];
                if(!YAHOO.lang.isArray(currentColumn.children)) {
                    currentColumn._rowspan = maxRowDepth;
                }
                else {
                    currentColumn._rowspan = 1;
                }
            }

            // Reset counter for next row
            maxRowDepth = 1;
        }
    };
    parseTreeForRowspan(tree);





    // Store header relationships in an array for HEADERS attribute
    var recurseAncestorsForHeaders = function(i, oColumn) {
        headers[i].push(oColumn._nId);
        if(oColumn.parent) {
            recurseAncestorsForHeaders(i, oColumn.parent);
        }
    };
    for(var i=0; i<keys.length; i++) {
        headers[i] = [];
        recurseAncestorsForHeaders(i, keys[i]);
        headers[i] = headers[i].reverse();
        headers[i] = headers[i].join(" ");
    }

    // Save to the ColumnSet instance
    this.tree = tree;
    this.flat = flat;
    this.keys = keys;
    this.headers = headers;

    YAHOO.widget.ColumnSet._nCount++;
};

/////////////////////////////////////////////////////////////////////////////
//
// Public member variables
//
/////////////////////////////////////////////////////////////////////////////

/**
 * Internal class variable to index multiple data table instances.
 *
 * @property ColumnSet._nCount
 * @type number
 * @private
 * @static
 */
YAHOO.widget.ColumnSet._nCount = 0;

/**
 * Unique instance name.
 *
 * @property _sName
 * @type String
 * @private
 */
YAHOO.widget.ColumnSet.prototype._sName = null;

/////////////////////////////////////////////////////////////////////////////
//
// Public member variables
//
/////////////////////////////////////////////////////////////////////////////

/**
 * Top-down tree representation of Column hierarchy.
 *
 * @property tree
 * @type YAHOO.widget.Column[]
 */
YAHOO.widget.ColumnSet.prototype.tree = null;

/**
 * Flattened representation of all Columns.
 *
 * @property flat
 * @type YAHOO.widget.Column[]
 * @default []
 */
YAHOO.widget.ColumnSet.prototype.flat = null;

/**
 * Array of Columns that map one-to-one to a table column.
 *
 * @property keys
 * @type YAHOO.widget.Column[]
 * @default []
 */
YAHOO.widget.ColumnSet.prototype.keys = null;

/**
 * ID index of nested parent hierarchies for HEADERS accessibility attribute.
 *
 * @property headers
 * @type String[]
 * @default []
 */
YAHOO.widget.ColumnSet.prototype.headers = null;

/////////////////////////////////////////////////////////////////////////////
//
// Public methods
//
/////////////////////////////////////////////////////////////////////////////

/**
 * Public accessor to the unique name of the ColumnSet instance.
 *
 * @method toString
 * @return {String} Unique name of the ColumnSet instance.
 */

YAHOO.widget.ColumnSet.prototype.toString = function() {
    return "ColumnSet " + this._sName;
};

/**
 * Returns Column instance with given ID number or key.
 *
 * @method getColumn
 * @param column {Number | String} ID number or unique key.
 * @return {YAHOO.widget.Column} Column instance.
 */

YAHOO.widget.ColumnSet.prototype.getColumn = function(column) {
    var allColumns = this.flat;
    if(YAHOO.lang.isNumber(column)) {
        for(var i=0; i<allColumns.length; i++) {
            if(allColumns[i]._nId === column) {
                return allColumns[i];
            }
        }
    }
    else if(YAHOO.lang.isString(column)) {
        for(i=0; i<allColumns.length; i++) {
            if(allColumns[i].key === column) {
                return allColumns[i];
            }
        }
    }
    return null;
};

/****************************************************************************/
/****************************************************************************/
/****************************************************************************/

/**
 * The Column class defines and manages attributes of DataTable Columns
 *
 * @namespace YAHOO.widget
 * @class Column
 * @constructor
 * @param oConfigs {Object} Object literal of configuration values.
 */
YAHOO.widget.Column = function(oConfigs) {
    // Internal variables
    this._nId = YAHOO.widget.Column._nCount;
    this._sName = "Column instance" + this._nId;

    // Object literal defines Column attributes
    if(oConfigs && (oConfigs.constructor == Object)) {
        for(var sConfig in oConfigs) {
            if(sConfig) {
                this[sConfig] = oConfigs[sConfig];
            }
        }
    }

    if(!YAHOO.lang.isValue(this.key)) {
        this.key = "yui-dt-column"+this._nId;
    }
    YAHOO.widget.Column._nCount++;
};

/////////////////////////////////////////////////////////////////////////////
//
// Private member variables
//
/////////////////////////////////////////////////////////////////////////////

/**
 * Internal instance counter.
 *
 * @property Column._nCount
 * @type Number
 * @private
 * @static
 * @default 0
 */
YAHOO.widget.Column._nCount = 0;

/**
 * Unique instance name.
 *
 * @property _sName
 * @type String
 * @private
 */
YAHOO.widget.Column.prototype._sName = null;


/**
 * Unique number assigned at instantiation, indicates original order within
 * ColumnSet.
 *
 * @property _nId
 * @type Number
 * @private
 */
YAHOO.widget.Column.prototype._nId = null;

/**
 * Reference to Column's index within its ColumnSet's keys array, or null if not applicable.
 *
 * @property _nKeyIndex
 * @type Number
 * @private
 */
YAHOO.widget.Column.prototype._nKeyIndex = null;

/**
 * Number of table cells the Column spans.
 *
 * @property _colspan
 * @type Number
 * @private
 */
YAHOO.widget.Column.prototype._colspan = 1;

/**
 * Number of table rows the Column spans.
 *
 * @property _rowspan
 * @type Number
 * @private
 */
YAHOO.widget.Column.prototype._rowspan = 1;

/**
 * Column's parent Column instance, or null.
 *
 * @property _parent
 * @type YAHOO.widget.Column
 * @private
 */
YAHOO.widget.Column.prototype._parent = null;

/**
 * Current offsetWidth of the Column (in pixels).
 *
 * @property _width
 * @type Number
 * @private
 */
YAHOO.widget.Column.prototype._width = null;

/**
 * Minimum width the Column can support (in pixels). Value is populated only if table
 * is fixedWidth, null otherwise.
 *
 * @property _minWidth
 * @type Number
 * @private
 */
YAHOO.widget.Column.prototype._minWidth = null;

/////////////////////////////////////////////////////////////////////////////
//
// Public member variables
//
/////////////////////////////////////////////////////////////////////////////

/**
 * Associated database field, or null.
 *
 * @property key
 * @type String
 */
YAHOO.widget.Column.prototype.key = null;

/**
 * Text or HTML for display as Column's label in the TH element.
 *
 * @property label
 * @type String
 */
YAHOO.widget.Column.prototype.label = null;

/**
 * Column head cell ABBR for accessibility.
 *
 * @property abbr
 * @type String
 */
YAHOO.widget.Column.prototype.abbr = null;

/**
 * Array of object literals that define children (nested headers) of a Column.
 *
 * @property children
 * @type Object[]
 */
YAHOO.widget.Column.prototype.children = null;

/**
 * Column width.
 *
 * @property width
 * @type String
 */
YAHOO.widget.Column.prototype.width = null;

/**
 * Custom CSS class or array of classes to be applied to every cell in the Column.
 *
 * @property className
 * @type String || String[]
 */
YAHOO.widget.Column.prototype.className = null;

/**
 * Defines a format function.
 *
 * @property formatter
 * @type String || HTMLFunction
 */
YAHOO.widget.Column.prototype.formatter = null;

/**
 * Defines an editor function, otherwise Column is not editable.
 *
 * @property editor
 * @type String || HTMLFunction
 */
YAHOO.widget.Column.prototype.editor = null;

/**
 * Defines editor options for Column in an object literal of param:value pairs.
 *
 * @property editorOptions
 * @type Object
 */
YAHOO.widget.Column.prototype.editorOptions = null;

/**
 * True if Column is resizeable, false otherwise.
 *
 * @property resizeable
 * @type Boolean
 * @default false
 */
YAHOO.widget.Column.prototype.resizeable = false;

/**
 * True if Column is sortable, false otherwise.
 *
 * @property sortable
 * @type Boolean
 * @default false
 */
YAHOO.widget.Column.prototype.sortable = false;

/**
 * Default sort order for Column: "asc" or "desc".
 *
 * @property sortOptions.defaultOrder
 * @type String
 * @default null
 */
/**
 * Custom sort handler.
 *
 * @property sortOptions.sortFunction
 * @type Function
 * @default null
 */
YAHOO.widget.Column.prototype.sortOptions = null;















/////////////////////////////////////////////////////////////////////////////
//
// Public methods
//
/////////////////////////////////////////////////////////////////////////////

/**
 * Public accessor to the unique name of the Column instance.
 *
 * @method toString
 * @return {String} Column's unique name.
 */
YAHOO.widget.Column.prototype.toString = function() {
    return this._sName;
};

/**
 * Returns unique number assigned at instantiation, indicates original order
 * within ColumnSet.
 *
 * @method getId
 * @return {Number} Column's unique ID number.
 */
YAHOO.widget.Column.prototype.getId = function() {
    return this._nId;
};

/**
 * Public accessor returns Column's key index within its ColumnSet's keys array, or
 * null if not applicable.
 *
 * @method getKeyIndex
 * @return {Number} Column's key index within its ColumnSet keys array, if applicable.
 */
YAHOO.widget.Column.prototype.getKeyIndex = function() {
    return this._nKeyIndex;
};

/**
 * Public accessor returns Column's parent instance if any, or null otherwise.
 *
 * @method getParent
 * @return {YAHOO.widget.Column} Column's parent instance.
 */
YAHOO.widget.Column.prototype.getParent = function() {
    return this._parent;
};

/**
 * Public accessor returns Column's calculated COLSPAN value.
 *
 * @method getColspan
 * @return {Number} Column's COLSPAN value.
 */
YAHOO.widget.Column.prototype.getColspan = function() {
    return this._colspan;
};
// Backward compatibility
YAHOO.widget.Column.prototype.getColSpan = function() {
    return this.getColspan();
};

/**
 * Public accessor returns Column's calculated ROWSPAN value.
 *
 * @method getRowspan
 * @return {Number} Column's ROWSPAN value.
 */
YAHOO.widget.Column.prototype.getRowspan = function() {
    return this._rowspan;
};

// Backward compatibility
YAHOO.widget.Column.prototype.getIndex = function() {
    return this.getKeyIndex();
};
YAHOO.widget.Column.prototype.format = function() {
};
YAHOO.widget.Column.formatCheckbox = function(elCell, oRecord, oColumn, oData) {
    YAHOO.widget.DataTable.formatCheckbox(elCell, oRecord, oColumn, oData);
};
YAHOO.widget.Column.formatCurrency = function(elCell, oRecord, oColumn, oData) {
    YAHOO.widget.DataTable.formatCurrency(elCell, oRecord, oColumn, oData);
};
YAHOO.widget.Column.formatDate = function(elCell, oRecord, oColumn, oData) {
    YAHOO.widget.DataTable.formatDate(elCell, oRecord, oColumn, oData);
};
YAHOO.widget.Column.formatEmail = function(elCell, oRecord, oColumn, oData) {
    YAHOO.widget.DataTable.formatEmail(elCell, oRecord, oColumn, oData);
};
YAHOO.widget.Column.formatLink = function(elCell, oRecord, oColumn, oData) {
    YAHOO.widget.DataTable.formatLink(elCell, oRecord, oColumn, oData);
};
YAHOO.widget.Column.formatNumber = function(elCell, oRecord, oColumn, oData) {
    YAHOO.widget.DataTable.formatNumber(elCell, oRecord, oColumn, oData);
};
YAHOO.widget.Column.formatSelect = function(elCell, oRecord, oColumn, oData) {
    YAHOO.widget.DataTable.formatDropdown(elCell, oRecord, oColumn, oData);
};

/****************************************************************************/
/****************************************************************************/
/****************************************************************************/

/**
 * Sort static utility to support Column sorting.
 *
 * @namespace YAHOO.util
 * @class Sort
 * @static
 */
YAHOO.util.Sort = {
    /////////////////////////////////////////////////////////////////////////////
    //
    // Public methods
    //
    /////////////////////////////////////////////////////////////////////////////

    /**
     * Comparator function for simple case-insensitive string sorting.
     *
     * @method compare
     * @param a {Object} First sort argument.
     * @param b {Object} Second sort argument.
     * @param desc {Boolean} True if sort direction is descending, false if
     * sort direction is ascending.
     */
    compare: function(a, b, desc) {
        if((a === null) || (typeof a == "undefined")) {
            if((b === null) || (typeof b == "undefined")) {
                return 0;
            }
            else {
                return 1;
            }
        }
        else if((b === null) || (typeof b == "undefined")) {
            return -1;
        }

        if(a.constructor == String) {
            a = a.toLowerCase();
        }
        if(b.constructor == String) {
            b = b.toLowerCase();
        }
        if(a < b) {
            return (desc) ? 1 : -1;
        }
        else if (a > b) {
            return (desc) ? -1 : 1;
        }
        else {
            return 0;
        }
    }
};

/****************************************************************************/
/****************************************************************************/
/****************************************************************************/

/**
 * ColumnResizer subclasses DragDrop to support resizeable Columns.
 *
 * @namespace YAHOO.util
 * @class ColumnResizer
 * @extends YAHOO.util.DragDrop
 * @constructor
 * @param oDataTable {YAHOO.widget.DataTable} DataTable instance.
 * @param oColumn {YAHOO.widget.Column} Column instance.
 * @param elThead {HTMLElement} TH element reference.
 * @param sHandleElId {String} DOM ID of the handle element that causes the resize.
 * @param sGroup {String} Group name of related DragDrop items.
 * @param oConfig {Object} (Optional) Object literal of config values.
 */
YAHOO.util.ColumnResizer = function(oDataTable, oColumn, elThead, sHandleId, sGroup, oConfig) {
    if(oDataTable && oColumn && elThead && sHandleId) {
        this.datatable = oDataTable;
        this.column = oColumn;
        this.cell = elThead;
        this.init(sHandleId, sGroup, oConfig);
        //this.initFrame();
        this.setYConstraint(0,0);
    }
    else {
    }
};

if(YAHOO.util.DD) {
    YAHOO.extend(YAHOO.util.ColumnResizer, YAHOO.util.DD);
}

/////////////////////////////////////////////////////////////////////////////
//
// Public DOM event handlers
//
/////////////////////////////////////////////////////////////////////////////

/**
 * Handles mousedown events on the Column resizer.
 *
 * @method onMouseDown
 * @param e {string} The mousedown event
 */
YAHOO.util.ColumnResizer.prototype.onMouseDown = function(e) {
    this.startWidth = this.cell.offsetWidth;
    this.startPos = YAHOO.util.Dom.getX(this.getDragEl());

    if(this.datatable.fixedWidth) {
        var cellLabel = YAHOO.util.Dom.getElementsByClassName(YAHOO.widget.DataTable.CLASS_LABEL,"span",this.cell)[0];
        this.minWidth = cellLabel.offsetWidth + 6;
        var sib = this.cell.nextSibling;
        var sibCellLabel = YAHOO.util.Dom.getElementsByClassName(YAHOO.widget.DataTable.CLASS_LABEL,"span",sib)[0];
        this.sibMinWidth = sibCellLabel.offsetWidth + 6;
//!!
        var left = ((this.startWidth - this.minWidth) < 0) ? 0 : (this.startWidth - this.minWidth);
        var right = ((sib.offsetWidth - this.sibMinWidth) < 0) ? 0 : (sib.offsetWidth - this.sibMinWidth);
        this.setXConstraint(left, right);
    }

};

/**
 * Handles mouseup events on the Column resizer.
 *
 * @method onMouseUp
 * @param e {string} The mouseup event
 */
YAHOO.util.ColumnResizer.prototype.onMouseUp = function(e) {
    //TODO: replace the resizer where it belongs:
    var resizeStyle = YAHOO.util.Dom.get(this.handleElId).style;
    resizeStyle.left = "auto";
    resizeStyle.right = 0;
    resizeStyle.marginRight = "-6px";
    resizeStyle.width = "6px";
    //.yui-dt-headresizer {position:absolute;margin-right:-6px;right:0;bottom:0;width:6px;height:100%;cursor:w-resize;cursor:col-resize;}


    //var cells = this.datatable._elTable.tHead.rows[this.datatable._elTable.tHead.rows.length-1].cells;
    //for(var i=0; i<cells.length; i++) {
        //cells[i].style.width = "5px";
    //}

    //TODO: set new ColumnSet width values
    this.datatable.fireEvent("columnResizeEvent", {column:this.column,target:this.cell});
};

/**
 * Handles drag events on the Column resizer.
 *
 * @method onDrag
 * @param e {string} The drag event
 */
YAHOO.util.ColumnResizer.prototype.onDrag = function(e) {
    var newPos = YAHOO.util.Dom.getX(this.getDragEl());
    var offsetX = newPos - this.startPos;
    var newWidth = this.startWidth + offsetX;

    if(newWidth < this.minWidth) {
        newWidth = this.minWidth;
    }

    // Resize the Column
    var oDataTable = this.datatable;
    var elCell = this.cell;


    // Resize the other Columns
    if(oDataTable.fixedWidth) {
        // Moving right or left?
        var sib = elCell.nextSibling;
        //var sibIndex = elCell.index + 1;
        var sibnewwidth = sib.offsetWidth - offsetX;
        if(sibnewwidth < this.sibMinWidth) {
            sibnewwidth = this.sibMinWidth;
        }

        //TODO: how else to cycle through all the Columns without having to use an index property?
        for(var i=0; i<oDataTable._oColumnSet.length; i++) {
            //if((i != elCell.index) &&  (i!=sibIndex)) {
            //    YAHOO.util.Dom.get(oDataTable._oColumnSet.keys[i].id).style.width = oDataTable._oColumnSet.keys[i].width + "px";
            //}
        }
        sib.style.width = sibnewwidth;
        elCell.style.width = newWidth + "px";
        //oDataTable._oColumnSet.flat[sibIndex].width = sibnewwidth;
        //oDataTable._oColumnSet.flat[elCell.index].width = newWidth;

    }
    else {
        elCell.style.width = newWidth + "px";
    }
};




/****************************************************************************/
/****************************************************************************/
/****************************************************************************/

/**
 * A RecordSet defines and manages a set of Records.
 *
 * @namespace YAHOO.widget
 * @class RecordSet
 * @param data {Object || Object[]} An object literal or an array of data.
 * @constructor
 */
YAHOO.widget.RecordSet = function(data) {
    // Internal variables
    this._sName = "RecordSet instance" + YAHOO.widget.RecordSet._nCount;
    YAHOO.widget.RecordSet._nCount++;
    this._records = [];
    this._length = 0;
    
    if(data) {
        if(YAHOO.lang.isArray(data)) {
            this.addRecords(data);
        }
        else if(data.constructor == Object) {
            this.addRecord(data);
        }
    }

    /**
     * Fired when a new Record is added to the RecordSet.
     *
     * @event recordAddEvent
     * @param oArgs.record {YAHOO.widget.Record} The Record instance.
     * @param oArgs.data {Object} Data added.
     */
    this.createEvent("recordAddEvent");

    /**
     * Fired when multiple Records are added to the RecordSet at once.
     *
     * @event recordsAddEvent
     * @param oArgs.records {YAHOO.widget.Record[]} An array of Record instances.
     * @param oArgs.data {Object[]} Data added.
     */
    this.createEvent("recordsAddEvent");

    /**
     * Fired when a Record is updated with new data.
     *
     * @event recordUpdateEvent
     * @param oArgs.record {YAHOO.widget.Record} The Record instance.
     * @param oArgs.newData {Object} New data.
     * @param oArgs.oldData {Object} Old data.
     */
    this.createEvent("recordUpdateEvent");
    
    /**
     * Fired when a Record is deleted from the RecordSet.
     *
     * @event recordDeleteEvent
     * @param oArgs.data {Object} A copy of the data held by the Record,
     * or an array of data object literals if multiple Records were deleted at once.
     * @param oArgs.index {Object} Index of the deleted Record.
     */
    this.createEvent("recordDeleteEvent");

    /**
     * Fired when multiple Records are deleted from the RecordSet at once.
     *
     * @event recordsDeleteEvent
     * @param oArgs.data {Object[]} An array of data object literals copied
     * from the Records.
     * @param oArgs.index {Object} Index of the first deleted Record.
     */
    this.createEvent("recordsDeleteEvent");
    
    /**
     * Fired when all Records are deleted from the RecordSet at once.
     *
     * @event resetEvent
     */
    this.createEvent("resetEvent");

    /**
     * Fired when a Record Key is updated with new data.
     *
     * @event keyUpdateEvent
     * @param oArgs.record {YAHOO.widget.Record} The Record instance.
     * @param oArgs.key {String} The updated key.
     * @param oArgs.newData {Object} New data.
     * @param oArgs.oldData {Object} Old data.
     *
     */
    this.createEvent("keyUpdateEvent");

};

if(YAHOO.util.EventProvider) {
    YAHOO.augment(YAHOO.widget.RecordSet, YAHOO.util.EventProvider);
}
else {
}

/////////////////////////////////////////////////////////////////////////////
//
// Private member variables
//
/////////////////////////////////////////////////////////////////////////////
/**
 * Internal class variable to name multiple Recordset instances.
 *
 * @property RecordSet._nCount
 * @type Number
 * @private
 * @static
 */
YAHOO.widget.RecordSet._nCount = 0;

/**
 * Unique instance name.
 *
 * @property _sName
 * @type String
 * @private
 */
YAHOO.widget.RecordSet.prototype._sName = null;

/**
 * Internal variable to give unique indexes to Record instances.
 *
 * @property _nCount
 * @type Number
 * @private
 */
YAHOO.widget.RecordSet.prototype._nRecordCount = 0;

/**
 * Internal counter of how many Records are in the RecordSet.
 *
 * @property _length
 * @type Number
 * @private
 */
YAHOO.widget.RecordSet.prototype._length = null;

/////////////////////////////////////////////////////////////////////////////
//
// Private methods
//
/////////////////////////////////////////////////////////////////////////////

/**
 * Adds one Record to the RecordSet at the given index. If index is null,
 * then adds the Record to the end of the RecordSet.
 *
 * @method _addRecord
 * @param oData {Object} An object literal of data.
 * @param index {Number} (optional) Position index.
 * @return {YAHOO.widget.Record} A Record instance.
 * @private
 */
YAHOO.widget.RecordSet.prototype._addRecord = function(oData, index) {
    var oRecord = new YAHOO.widget.Record(oData);
    oRecord._nId = this._nRecordCount;
    this._nRecordCount++;
    
    if(YAHOO.lang.isNumber(index) && (index > -1)) {
        this._records.splice(index,0,oRecord);
    }
    else {
        index = this.getLength();
        this._records.push(oRecord);
    }
    this._length++;
    return oRecord;
};

/**
 * Deletes Records from the RecordSet at the given index. If range is null,
 * then only one Record is deleted.
 *
 * @method _deleteRecord
 * @param index {Number} Position index.
 * @param range {Number} (optional) How many Records to delete
 * @private
 */
YAHOO.widget.RecordSet.prototype._deleteRecord = function(index, range) {
    if(!YAHOO.lang.isNumber(range) || (range < 0)) {
        range = 1;
    }
    this._records.splice(index, range);
    this._length = this._length - range;
};

/////////////////////////////////////////////////////////////////////////////
//
// Public methods
//
/////////////////////////////////////////////////////////////////////////////

/**
 * Public accessor to the unique name of the RecordSet instance.
 *
 * @method toString
 * @return {String} Unique name of the RecordSet instance.
 */
YAHOO.widget.RecordSet.prototype.toString = function() {
    return this._sName;
};

/**
 * Returns the number of Records held in the RecordSet.
 *
 * @method getLength
 * @return {Number} Number of records in the RecordSet.
 */
YAHOO.widget.RecordSet.prototype.getLength = function() {
        return this._length;
};

/**
 * Returns Record at given position index.
 *
 * @method getRecord
 * @param index {Number} Record's Recordset position index.
 * @return {YAHOO.widget.Record} Record object.
 */
YAHOO.widget.RecordSet.prototype.getRecord = function(index) {
    if(YAHOO.lang.isNumber(index)) {
        return this._records[index];
    }
    /*else if(YAHOO.lang.isString(identifier)) {
        for(var i=0; i<this._records.length; i++) {
            if(this._records[i].yuiRecordId == identifier) {
                return this._records[i];
            }
        }
    }*/
    return null;

};

/*
 * Returns an array of Records from the RecordSet.
 *
 * @method getRecords
 * @param index {Number} (optional) Recordset position index of which Record to
 * start at.
 * @param range {Number} (optional) Number of Records to get.
 * @return {YAHOO.widget.Record[]} Array of Records starting at given index and
 * length equal to given range. If index is not given, all Records are returned.
 */
YAHOO.widget.RecordSet.prototype.getRecords = function(index, range) {
    if(!YAHOO.lang.isNumber(index)) {
        return this._records;
    }
    if(!YAHOO.lang.isNumber(range)) {
        return this._records.slice(index);
    }
    return this._records.slice(index, index+range);
};

/**
 * Returns position index for the given Record.
 *
 * @method getRecordIndex
 * @param oRecord {YAHOO.widget.Record} Record instance.
 * @return {Number} Record's RecordSet position index.
 */

YAHOO.widget.RecordSet.prototype.getRecordIndex = function(oRecord) {
    for(var i=this._records.length-1; i>-1; i--) {
        if(oRecord.getId() === this._records[i].getId()) {
            return i;
        }
    }
    return null;

};

/**
 * Adds one Record to the RecordSet at the given index. If index is null,
 * then adds the Record to the end of the RecordSet.
 *
 * @method addRecord
 * @param oData {Object} An object literal of data.
 * @param index {Number} (optional) Position index.
 * @return {YAHOO.widget.Record} A Record instance.
 */
YAHOO.widget.RecordSet.prototype.addRecord = function(oData, index) {
    if(oData && (oData.constructor == Object)) {
        var oRecord = this._addRecord(oData, index);
        this.fireEvent("recordAddEvent",{record:oRecord,data:oData});
        return oRecord;
    }
    else {
        return null;
    }
};

/**
 * Adds multiple Records at once to the RecordSet at the given index with the
 * given data. If index is null, then the new Records are added to the end of
 * the RecordSet.
 *
 * @method addRecords
 * @param aData {Object[]} An array of object literal data.
 * @param index {Number} (optional) Position index.
 * @return {YAHOO.widget.Record[]} An array of Record instances.
 */
YAHOO.widget.RecordSet.prototype.addRecords = function(aData, index) {
    if(YAHOO.lang.isArray(aData)) {
        var newRecords = [];
        // Can't go backwards bc we need to preserve order
        for(var i=0; i<aData.length; i++) {
            if(aData[i] && (aData[i].constructor == Object)) {
                var record = this._addRecord(aData[i], index);
                newRecords.push(record);
            }
       }
        this.fireEvent("recordsAddEvent",{records:newRecords,data:aData});
       return newRecords;
    }
    else if(aData && (aData.constructor == Object)) {
        var oRecord = this._addRecord(aData);
        this.fireEvent("recordsAddEvent",{records:[oRecord],data:aData});
        return oRecord;
    }
    else {
    }
};

/**
 * Updates given Record with given data.
 *
 * @method updateRecord
 * @param record {YAHOO.widget.Record | Number} A Record instance, or Record's
 * RecordSet position index.
 * @param oData {Object) Object literal of new data.
 * @return {YAHOO.widget.Record} Updated Record, or null.
 */
YAHOO.widget.RecordSet.prototype.updateRecord = function(record, oData) {
    var oRecord = null;
    if(YAHOO.lang.isNumber(record)) {
        oRecord = this._records[record];
    }
    else if(record instanceof YAHOO.widget.Record) {
        oRecord = record;
    }
    if(oRecord && oData && (oData.constructor == Object)) {
        // Copy data from the Record for the event that gets fired later
        var oldData = {};
        for(var key in oRecord._oData) {
            oldData[key] = oRecord._oData[key];
        }
        oRecord._oData = oData;
        this.fireEvent("recordUpdateEvent",{record:oRecord,newData:oData,oldData:oldData});
        return oRecord;
    }
    else {
        return null;
    }
};

/**
 * Updates given Record at given key with given data.
 *
 * @method updateKey
 * @param record {YAHOO.widget.Record | Number} A Record instance, or Record's
 * RecordSet position index.
 * @param sKey {String} Key name.
 * @param oData {Object) New data.
 */
YAHOO.widget.RecordSet.prototype.updateKey = function(record, sKey, oData) {
    var oRecord;
    
    if(YAHOO.lang.isNumber(record)) {
        oRecord = this._records[record];
    }
    if(record instanceof YAHOO.widget.Record) {
        oRecord = record;

        var oldData = null;
        var keyValue = oRecord._oData[sKey];
        // Copy data from the Record for the event that gets fired later
        if(keyValue && keyValue.constructor == Object) {
            oldData = {};
            for(var key in keyValue) {
                oldData[key] = keyValue[key];
            }
        }
        // Copy by value
        else {
            oldData = keyValue;
        }

        oRecord._oData[sKey] = oData;
        this.fireEvent("keyUpdateEvent",{record:oRecord,key:sKey,newData:oData,oldData:oldData});
    }
    else {
    }
};

/**
 * Replaces all Records in RecordSet with new data.
 *
 * @method replaceRecords
 * @param data {Object || Object[]} An object literal of data or an array of
 * object literal data.
 * @return {YAHOO.widget.Record || YAHOO.widget.Record[]} A Record instance or
 * an array of Records.
 */
YAHOO.widget.RecordSet.prototype.replaceRecords = function(data) {
    this.reset();
    return this.addRecords(data);
};

/**
 * Sorts all Records by given function.
 *
 * @method sortRecords
 * @param fnSort {Function} Reference to a sort function.
 * @param desc {Boolean} True if sort direction is descending, false if sort
 * direction is ascending.
 * @return {YAHOO.widget.Record[]} Sorted array of Records.
 */
YAHOO.widget.RecordSet.prototype.sortRecords = function(fnSort, desc) {
    return this._records.sort(function(a, b) {return fnSort(a, b, desc);});
};


/**
 * Removes the Record at the given position index from the RecordSet. If a range
 * is also provided, removes that many Records, starting from the index. Length
 * of RecordSet is correspondingly shortened.
 *
 * @method deleteRecord
 * @param index {Number} Record's RecordSet position index.
 * @param range {Number} (optional) How many Records to delete.
 * @return {Object} A copy of the data held by the deleted Record.
 */
YAHOO.widget.RecordSet.prototype.deleteRecord = function(index) {
    if(YAHOO.lang.isNumber(index) && (index > -1) && (index < this.getLength())) {
        // Copy data from the Record for the event that gets fired later
        var oRecordData = this.getRecord(index).getData();
        var oData = {};
        for(var key in oRecordData) {
            oData[key] = oRecordData[key];
        }
        
        this._deleteRecord(index);
        this.fireEvent("recordDeleteEvent",{data:oData,index:index});
        return oData;
    }
    else {
        return null;
    }
};

/**
 * Removes the Record at the given position index from the RecordSet. If a range
 * is also provided, removes that many Records, starting from the index. Length
 * of RecordSet is correspondingly shortened.
 *
 * @method deleteRecords
 * @param index {Number} Record's RecordSet position index.
 * @param range {Number} (optional) How many Records to delete.
 */
YAHOO.widget.RecordSet.prototype.deleteRecords = function(index, range) {
    if(!YAHOO.lang.isNumber(range)) {
        range = 1;
    }
    if(YAHOO.lang.isNumber(index) && (index > -1) && (index < this.getLength())) {
        var recordsToDelete = this.getRecords(index, range);
        // Copy data from each Record for the event that gets fired later
        var deletedData = [];
        for(var i=0; i<recordsToDelete.length; i++) {
            var oData = {};
            for(var key in recordsToDelete[i]) {
                oData[key] = recordsToDelete[i][key];
            }
            deletedData.push(oData);
        }
        this._deleteRecord(index, range);

        this.fireEvent("recordsDeleteEvent",{data:deletedData,index:index});

    }
    else {
    }
};

/**
 * Deletes all Records from the RecordSet.
 *
 * @method reset
 */
YAHOO.widget.RecordSet.prototype.reset = function() {
    this._records = [];
    this._length = 0;
    this.fireEvent("resetEvent");
};


/****************************************************************************/
/****************************************************************************/
/****************************************************************************/

/**
 * The Record class defines a DataTable record.
 *
 * @namespace YAHOO.widget
 * @class Record
 * @constructor
 * @param oConfigs {Object} (optional) Object literal of key/value pairs.
 */
YAHOO.widget.Record = function(oLiteral) {
    this._oData = {};
    if(oLiteral && (oLiteral.constructor == Object)) {
        for(var sKey in oLiteral) {
            this._oData[sKey] = oLiteral[sKey];
        }
    }
};

/////////////////////////////////////////////////////////////////////////////
//
// Private member variables
//
/////////////////////////////////////////////////////////////////////////////
/**
 * Unique number assigned at instantiation, indicates original order within
 * RecordSet.
 *
 * @property _nId
 * @type Number
 * @private
 */
YAHOO.widget.Record.prototype._nId = null;

/**
 * Holds data for the Record in an object literal.
 *
 * @property _oData
 * @type Object
 * @private
 */
YAHOO.widget.Record.prototype._oData = null;

/////////////////////////////////////////////////////////////////////////////
//
// Public member variables
//
/////////////////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////////////////////////
//
// Public methods
//
/////////////////////////////////////////////////////////////////////////////

/**
 * Returns unique number assigned at instantiation, indicates original order
 * within RecordSet.
 *
 * @method getId
 * @return Number
 */
YAHOO.widget.Record.prototype.getId = function() {
    return this._nId;
};

/**
 * Returns data for the Record for a key if given, or the entire object
 * literal otherwise.
 *
 * @method getData
 * @param sKey {String} (Optional) The key to retrieve a single data value.
 * @return Object
 */
YAHOO.widget.Record.prototype.getData = function(sKey) {
    if(YAHOO.lang.isString(sKey)) {
        return this._oData[sKey];
    }
    else {
        return this._oData;
    }
};


YAHOO.register("datatable", YAHOO.widget.DataTable, {version: "2.3.0", build: "442"});
/**
 * ====================================================================
 * About
 * ====================================================================
 * Sarissa is an ECMAScript library acting as a cross-browser wrapper for native XML APIs.
 * The library supports Gecko based browsers like Mozilla and Firefox,
 * Internet Explorer (5.5+ with MSXML3.0+), Konqueror, Safari and a little of Opera
 * @version ${project.version}
 * @author: Manos Batsis, mailto: mbatsis at users full stop sourceforge full stop net
 * ====================================================================
 * Licence
 * ====================================================================
 * Sarissa is free software distributed under the GNU GPL version 2 (see <a href="gpl.txt">gpl.txt</a>) or higher, 
 * GNU LGPL version 2.1 (see <a href="lgpl.txt">lgpl.txt</a>) or higher and Apache Software License 2.0 or higher 
 * (see <a href="asl.txt">asl.txt</a>). This means you can choose one of the three and use that if you like. If 
 * you make modifications under the ASL, i would appreciate it if you submitted those.
 * In case your copy of Sarissa does not include the license texts, you may find
 * them online in various formats at <a href="http://www.gnu.org">http://www.gnu.org</a> and 
 * <a href="http://www.apache.org">http://www.apache.org</a>.
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY 
 * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 
 * WARRANTIES OF MERCHANTABILITY,FITNESS FOR A PARTICULAR PURPOSE 
 * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 
 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
/**
 * <p>Sarissa is a utility class. Provides "static" methods for DOMDocument, 
 * DOM Node serialization to XML strings and other utility goodies.</p>
 * @constructor
 */
function Sarissa(){};
Sarissa.VERSION = "${project.version}";
Sarissa.PARSED_OK = "Document contains no parsing errors";
Sarissa.PARSED_EMPTY = "Document is empty";
Sarissa.PARSED_UNKNOWN_ERROR = "Not well-formed or other error";
Sarissa.IS_ENABLED_TRANSFORM_NODE = false;
var _sarissa_iNsCounter = 0;
var _SARISSA_IEPREFIX4XSLPARAM = "";
var _SARISSA_HAS_DOM_IMPLEMENTATION = document.implementation && true;
var _SARISSA_HAS_DOM_CREATE_DOCUMENT = _SARISSA_HAS_DOM_IMPLEMENTATION && document.implementation.createDocument;
var _SARISSA_HAS_DOM_FEATURE = _SARISSA_HAS_DOM_IMPLEMENTATION && document.implementation.hasFeature;
var _SARISSA_IS_MOZ = _SARISSA_HAS_DOM_CREATE_DOCUMENT && _SARISSA_HAS_DOM_FEATURE;
var _SARISSA_IS_SAFARI = navigator.userAgent.toLowerCase().indexOf("safari") != -1 || navigator.userAgent.toLowerCase().indexOf("konqueror") != -1;
var _SARISSA_IS_SAFARI_OLD = _SARISSA_IS_SAFARI && parseInt((navigator.userAgent.match(/AppleWebKit\/(\d+)/)||{})[1]) < 420;
var _SARISSA_IS_IE = document.all && window.ActiveXObject && navigator.userAgent.toLowerCase().indexOf("msie") > -1  && navigator.userAgent.toLowerCase().indexOf("opera") == -1;
var _SARISSA_IS_OPERA = navigator.userAgent.toLowerCase().indexOf("opera") != -1;
if(!window.Node || !Node.ELEMENT_NODE){
    Node = {ELEMENT_NODE: 1, ATTRIBUTE_NODE: 2, TEXT_NODE: 3, CDATA_SECTION_NODE: 4, ENTITY_REFERENCE_NODE: 5,  ENTITY_NODE: 6, PROCESSING_INSTRUCTION_NODE: 7, COMMENT_NODE: 8, DOCUMENT_NODE: 9, DOCUMENT_TYPE_NODE: 10, DOCUMENT_FRAGMENT_NODE: 11, NOTATION_NODE: 12};
};

//This breaks for(x in o) loops in the old Safari
if(_SARISSA_IS_SAFARI_OLD){
    HTMLHtmlElement = document.createElement("html").constructor;
    Node = HTMLElement = {};
    HTMLElement.prototype = HTMLHtmlElement.__proto__.__proto__;
    HTMLDocument = Document = document.constructor;
    var x = new DOMParser();
    XMLDocument = x.constructor;
    Element = x.parseFromString("<Single />", "text/xml").documentElement.constructor;
    x = null;
}
if(typeof XMLDocument == "undefined" && typeof Document !="undefined"){ XMLDocument = Document; } 

// IE initialization
if(_SARISSA_IS_IE){
    // for XSLT parameter names, prefix needed by IE
    _SARISSA_IEPREFIX4XSLPARAM = "xsl:";
    // used to store the most recent ProgID available out of the above
    var _SARISSA_DOM_PROGID = "";
    var _SARISSA_XMLHTTP_PROGID = "";
    var _SARISSA_DOM_XMLWRITER = "";
    /**
     * Called when the Sarissa_xx.js file is parsed, to pick most recent
     * ProgIDs for IE, then gets destroyed.
     * @private
     * @param idList an array of MSXML PROGIDs from which the most recent will be picked for a given object
     * @param enabledList an array of arrays where each array has two items; the index of the PROGID for which a certain feature is enabled
     */
    Sarissa.pickRecentProgID = function (idList){
        // found progID flag
        var bFound = false;
        for(var i=0; i < idList.length && !bFound; i++){
            try{
                var oDoc = new ActiveXObject(idList[i]);
                o2Store = idList[i];
                bFound = true;
            }catch (objException){
                // trap; try next progID
            };
        };
        if (!bFound) {
            throw "Could not retreive a valid progID of Class: " + idList[idList.length-1]+". (original exception: "+e+")";
        };
        idList = null;
        return o2Store;
    };
    // pick best available MSXML progIDs
    _SARISSA_DOM_PROGID = null;
    _SARISSA_THREADEDDOM_PROGID = null;
    _SARISSA_XSLTEMPLATE_PROGID = null;
    _SARISSA_XMLHTTP_PROGID = null;
    if(!window.XMLHttpRequest){
        /**
         * Emulate XMLHttpRequest
         * @constructor
         */
        XMLHttpRequest = function() {
            if(!_SARISSA_XMLHTTP_PROGID){
                _SARISSA_XMLHTTP_PROGID = Sarissa.pickRecentProgID(["Msxml2.XMLHTTP.6.0", "MSXML2.XMLHTTP.3.0", "MSXML2.XMLHTTP", "Microsoft.XMLHTTP"]);
            };
            return new ActiveXObject(_SARISSA_XMLHTTP_PROGID);
        };
    };
    // we dont need this anymore
    //============================================
    // Factory methods (IE)
    //============================================
    // see non-IE version
    Sarissa.getDomDocument = function(sUri, sName){
        if(!_SARISSA_DOM_PROGID){
            _SARISSA_DOM_PROGID = Sarissa.pickRecentProgID(["Msxml2.DOMDocument.6.0", "Msxml2.DOMDocument.3.0", "MSXML2.DOMDocument", "MSXML.DOMDocument", "Microsoft.XMLDOM"]);
        };
        var oDoc = new ActiveXObject(_SARISSA_DOM_PROGID);
        // if a root tag name was provided, we need to load it in the DOM object
        if (sName){
            // create an artifical namespace prefix 
            // or reuse existing prefix if applicable
            var prefix = "";
            if(sUri){
                if(sName.indexOf(":") > 1){
                    prefix = sName.substring(0, sName.indexOf(":"));
                    sName = sName.substring(sName.indexOf(":")+1); 
                }else{
                    prefix = "a" + (_sarissa_iNsCounter++);
                };
            };
            // use namespaces if a namespace URI exists
            if(sUri){
                oDoc.loadXML('<' + prefix+':'+sName + " xmlns:" + prefix + "=\"" + sUri + "\"" + " />");
            } else {
                oDoc.loadXML('<' + sName + " />");
            };
        };
        return oDoc;
    };
    // see non-IE version   
    Sarissa.getParseErrorText = function (oDoc) {
        var parseErrorText = Sarissa.PARSED_OK;
        if(oDoc && oDoc.parseError && oDoc.parseError.errorCode && oDoc.parseError.errorCode != 0){
            parseErrorText = "XML Parsing Error: " + oDoc.parseError.reason + 
                "\nLocation: " + oDoc.parseError.url + 
                "\nLine Number " + oDoc.parseError.line + ", Column " + 
                oDoc.parseError.linepos + 
                ":\n" + oDoc.parseError.srcText +
                "\n";
            for(var i = 0;  i < oDoc.parseError.linepos;i++){
                parseErrorText += "-";
            };
            parseErrorText +=  "^\n";
        }
        else if(oDoc.documentElement == null){
            parseErrorText = Sarissa.PARSED_EMPTY;
        };
        return parseErrorText;
    };
    // see non-IE version
    Sarissa.setXpathNamespaces = function(oDoc, sNsSet) {
        oDoc.setProperty("SelectionLanguage", "XPath");
        oDoc.setProperty("SelectionNamespaces", sNsSet);
    };   
    /**
     * Basic implementation of Mozilla's XSLTProcessor for IE. 
     * Reuses the same XSLT stylesheet for multiple transforms
     * @constructor
     */
    XSLTProcessor = function(){
        if(!_SARISSA_XSLTEMPLATE_PROGID){
            _SARISSA_XSLTEMPLATE_PROGID = Sarissa.pickRecentProgID(["Msxml2.XSLTemplate.6.0", "MSXML2.XSLTemplate.3.0"]);
        };
        this.template = new ActiveXObject(_SARISSA_XSLTEMPLATE_PROGID);
        this.processor = null;
    };
    /**
     * Imports the given XSLT DOM and compiles it to a reusable transform
     * <b>Note:</b> If the stylesheet was loaded from a URL and contains xsl:import or xsl:include elements,it will be reloaded to resolve those
     * @argument xslDoc The XSLT DOMDocument to import
     */
    XSLTProcessor.prototype.importStylesheet = function(xslDoc){
        if(!_SARISSA_THREADEDDOM_PROGID){
            _SARISSA_THREADEDDOM_PROGID = Sarissa.pickRecentProgID(["MSXML2.FreeThreadedDOMDocument.6.0", "MSXML2.FreeThreadedDOMDocument.3.0"]);
        };
        xslDoc.setProperty("SelectionLanguage", "XPath");
        xslDoc.setProperty("SelectionNamespaces", "xmlns:xsl='http://www.w3.org/1999/XSL/Transform'");
        // convert stylesheet to free threaded
        var converted = new ActiveXObject(_SARISSA_THREADEDDOM_PROGID);
        // make included/imported stylesheets work if exist and xsl was originally loaded from url
        if (_SARISSA_THREADEDDOM_PROGID == "MSXML2.FreeThreadedDOMDocument.6.0") { 
            converted.setProperty("AllowDocumentFunction", true); 
            converted.resolveExternals = true; 
        };
        if(xslDoc.url && xslDoc.selectSingleNode("//xsl:*[local-name() = 'import' or local-name() = 'include']") != null){
            converted.async = false;
            converted.load(xslDoc.url);
        } else {
            converted.loadXML(xslDoc.xml);
        };
        converted.setProperty("SelectionNamespaces", "xmlns:xsl='http://www.w3.org/1999/XSL/Transform'");
        var output = converted.selectSingleNode("//xsl:output");
        this.outputMethod = output ? output.getAttribute("method") : "html";
        this.template.stylesheet = converted;
        this.processor = this.template.createProcessor();
        // for getParameter and clearParameters
        this.paramsSet = new Array();
    };

    /**
     * Transform the given XML DOM and return the transformation result as a new DOM document
     * @argument sourceDoc The XML DOMDocument to transform
     * @return The transformation result as a DOM Document
     */
    XSLTProcessor.prototype.transformToDocument = function(sourceDoc){
        // fix for bug 1549749
        if(_SARISSA_THREADEDDOM_PROGID){
            this.processor.input=sourceDoc;
            var outDoc=new ActiveXObject(_SARISSA_DOM_PROGID);
            this.processor.output=outDoc;
            this.processor.transform();
            return outDoc;
        }
        else{
            if(!_SARISSA_DOM_XMLWRITER){
                _SARISSA_DOM_XMLWRITER = Sarissa.pickRecentProgID(["Msxml2.MXXMLWriter.6.0", "Msxml2.MXXMLWriter.3.0", "MSXML2.MXXMLWriter", "MSXML.MXXMLWriter", "Microsoft.XMLDOM"]);
            };
            this.processor.input = sourceDoc;
            var outDoc = new ActiveXObject(_SARISSA_DOM_XMLWRITER);
            this.processor.output = outDoc; 
            this.processor.transform();
            var oDoc = new ActiveXObject(_SARISSA_DOM_PROGID);
            oDoc.loadXML(outDoc.output+"");
            return oDoc;
        };
    };
    
    /**
     * Transform the given XML DOM and return the transformation result as a new DOM fragment.
     * <b>Note</b>: The xsl:output method must match the nature of the owner document (XML/HTML).
     * @argument sourceDoc The XML DOMDocument to transform
     * @argument ownerDoc The owner of the result fragment
     * @return The transformation result as a DOM Document
     */
    XSLTProcessor.prototype.transformToFragment = function (sourceDoc, ownerDoc) {
        this.processor.input = sourceDoc;
        this.processor.transform();
        var s = this.processor.output;
        var f = ownerDoc.createDocumentFragment();
        if (this.outputMethod == 'text') {
            f.appendChild(ownerDoc.createTextNode(s));
        } else if (ownerDoc.body && ownerDoc.body.innerHTML) {
            var container = ownerDoc.createElement('div');
            container.innerHTML = s;
            while (container.hasChildNodes()) {
                f.appendChild(container.firstChild);
            }
        }
        else {
            var oDoc = new ActiveXObject(_SARISSA_DOM_PROGID);
            if (s.substring(0, 5) == '<?xml') {
                s = s.substring(s.indexOf('?>') + 2);
            }
            var xml = ''.concat('<my>', s, '</my>');
            oDoc.loadXML(xml);
            var container = oDoc.documentElement;
            while (container.hasChildNodes()) {
                f.appendChild(container.firstChild);
            }
        }
        return f;
    };
    
    /**
     * Set global XSLT parameter of the imported stylesheet
     * @argument nsURI The parameter namespace URI
     * @argument name The parameter base name
     * @argument value The new parameter value
     */
     XSLTProcessor.prototype.setParameter = function(nsURI, name, value){
         // make value a zero length string if null to allow clearing
         value = value ? value : "";
         // nsURI is optional but cannot be null
         if(nsURI){
             this.processor.addParameter(name, value, nsURI);
         }else{
             this.processor.addParameter(name, value);
         };
         // update updated params for getParameter
         nsURI = "" + (nsURI || "");
         if(!this.paramsSet[nsURI]){
             this.paramsSet[nsURI] = new Array();
         };
         this.paramsSet[nsURI][name] = value;
     };
    /**
     * Gets a parameter if previously set by setParameter. Returns null
     * otherwise
     * @argument name The parameter base name
     * @argument value The new parameter value
     * @return The parameter value if reviously set by setParameter, null otherwise
     */
    XSLTProcessor.prototype.getParameter = function(nsURI, name){
        nsURI = "" + (nsURI || "");
        if(this.paramsSet[nsURI] && this.paramsSet[nsURI][name]){
            return this.paramsSet[nsURI][name];
        }else{
            return null;
        };
    };
    /**
     * Clear parameters (set them to default values as defined in the stylesheet itself)
     */
    XSLTProcessor.prototype.clearParameters = function(){
        for(var nsURI in this.paramsSet){
            for(var name in this.paramsSet[nsURI]){
                if(nsURI!=""){
                    this.processor.addParameter(name, "", nsURI);
                }else{
                    this.processor.addParameter(name, "");
                };
            };
        };
        this.paramsSet = new Array();
    };
}else{ /* end IE initialization, try to deal with real browsers now ;-) */
    if(_SARISSA_HAS_DOM_CREATE_DOCUMENT){
        /**
         * <p>Ensures the document was loaded correctly, otherwise sets the
         * parseError to -1 to indicate something went wrong. Internal use</p>
         * @private
         */
        Sarissa.__handleLoad__ = function(oDoc){
            Sarissa.__setReadyState__(oDoc, 4);
        };
        /**
        * <p>Attached by an event handler to the load event. Internal use.</p>
        * @private
        */
        _sarissa_XMLDocument_onload = function(){
            Sarissa.__handleLoad__(this);
        };
        /**
         * <p>Sets the readyState property of the given DOM Document object.
         * Internal use.</p>
         * @private
         * @argument oDoc the DOM Document object to fire the
         *          readystatechange event
         * @argument iReadyState the number to change the readystate property to
         */
        Sarissa.__setReadyState__ = function(oDoc, iReadyState){
            oDoc.readyState = iReadyState;
            oDoc.readystate = iReadyState;
            if (oDoc.onreadystatechange != null && typeof oDoc.onreadystatechange == "function")
                oDoc.onreadystatechange();
        };
        Sarissa.getDomDocument = function(sUri, sName){
            var oDoc = document.implementation.createDocument(sUri?sUri:null, sName?sName:null, null);
            if(!oDoc.onreadystatechange){
            
                /**
                * <p>Emulate IE's onreadystatechange attribute</p>
                */
                oDoc.onreadystatechange = null;
            };
            if(!oDoc.readyState){
                /**
                * <p>Emulates IE's readyState property, which always gives an integer from 0 to 4:</p>
                * <ul><li>1 == LOADING,</li>
                * <li>2 == LOADED,</li>
                * <li>3 == INTERACTIVE,</li>
                * <li>4 == COMPLETED</li></ul>
                */
                oDoc.readyState = 0;
            };
            oDoc.addEventListener("load", _sarissa_XMLDocument_onload, false);
            return oDoc;
        };
        if(window.XMLDocument){
            // do nothing
        }// TODO: check if the new document has content before trying to copynodes, check  for error handling in DOM 3 LS
        else if(_SARISSA_HAS_DOM_FEATURE && window.Document && !Document.prototype.load && document.implementation.hasFeature('LS', '3.0')){
            //Opera 9 may get the XPath branch which gives creates XMLDocument, therefore it doesn't reach here which is good
            /**
            * <p>Factory method to obtain a new DOM Document object</p>
            * @argument sUri the namespace of the root node (if any)
            * @argument sUri the local name of the root node (if any)
            * @returns a new DOM Document
            */
            Sarissa.getDomDocument = function(sUri, sName){
                var oDoc = document.implementation.createDocument(sUri?sUri:null, sName?sName:null, null);
                return oDoc;
            };
        }
        else {
            Sarissa.getDomDocument = function(sUri, sName){
                var oDoc = document.implementation.createDocument(sUri?sUri:null, sName?sName:null, null);
                // looks like safari does not create the root element for some unknown reason
                if(oDoc && (sUri || sName) && !oDoc.documentElement){
                    oDoc.appendChild(oDoc.createElementNS(sUri, sName));
                };
                return oDoc;
            };
        };
    };//if(_SARISSA_HAS_DOM_CREATE_DOCUMENT)
};
//==========================================
// Common stuff
//==========================================
if(!window.DOMParser){
    if(_SARISSA_IS_SAFARI){
        /*
         * DOMParser is a utility class, used to construct DOMDocuments from XML strings
         * @constructor
         */
        DOMParser = function() { };
        /** 
        * Construct a new DOM Document from the given XMLstring
        * @param sXml the given XML string
        * @param contentType the content type of the document the given string represents (one of text/xml, application/xml, application/xhtml+xml). 
        * @return a new DOM Document from the given XML string
        */
        DOMParser.prototype.parseFromString = function(sXml, contentType){
            var xmlhttp = new XMLHttpRequest();
            xmlhttp.open("GET", "data:text/xml;charset=utf-8," + encodeURIComponent(sXml), false);
            xmlhttp.send(null);
            return xmlhttp.responseXML;
        };
    }else if(Sarissa.getDomDocument && Sarissa.getDomDocument() && Sarissa.getDomDocument(null, "bar").xml){
        DOMParser = function() { };
        DOMParser.prototype.parseFromString = function(sXml, contentType){
            var doc = Sarissa.getDomDocument();
            doc.loadXML(sXml);
            return doc;
        };
    };
};

if((typeof(document.importNode) == "undefined") && _SARISSA_IS_IE){
    try{
        /**
        * Implementation of importNode for the context window document in IE.
        * If <code>oNode</code> is a TextNode, <code>bChildren</code> is ignored.
        * @param oNode the Node to import
        * @param bChildren whether to include the children of oNode
        * @returns the imported node for further use
        */
        document.importNode = function(oNode, bChildren){
            var tmp;
            if (oNode.nodeName=='#text') {
                return document.createTextElement(oNode.data);
            }
            else {
                if(oNode.nodeName == "tbody" || oNode.nodeName == "tr"){
                    tmp = document.createElement("table");
                }
                else if(oNode.nodeName == "td"){
                    tmp = document.createElement("tr");
                }
                else if(oNode.nodeName == "option"){
                    tmp = document.createElement("select");
                }
                else{
                    tmp = document.createElement("div");
                };
                if(bChildren){
                    tmp.innerHTML = oNode.xml ? oNode.xml : oNode.outerHTML;
                }else{
                    tmp.innerHTML = oNode.xml ? oNode.cloneNode(false).xml : oNode.cloneNode(false).outerHTML;
                };
                return tmp.getElementsByTagName("*")[0];
            };
            
        };
    }catch(e){ };
};
if(!Sarissa.getParseErrorText){
    /**
     * <p>Returns a human readable description of the parsing error. Usefull
     * for debugging. Tip: append the returned error string in a &lt;pre&gt;
     * element if you want to render it.</p>
     * <p>Many thanks to Christian Stocker for the initial patch.</p>
     * @argument oDoc The target DOM document
     * @returns The parsing error description of the target Document in
     *          human readable form (preformated text)
     */
    Sarissa.getParseErrorText = function (oDoc){
        var parseErrorText = Sarissa.PARSED_OK;
        if(!oDoc.documentElement){
            parseErrorText = Sarissa.PARSED_EMPTY;
        } else if(oDoc.documentElement.tagName == "parsererror"){
            parseErrorText = oDoc.documentElement.firstChild.data;
            parseErrorText += "\n" +  oDoc.documentElement.firstChild.nextSibling.firstChild.data;
        } else if(oDoc.getElementsByTagName("parsererror").length > 0){
            var parsererror = oDoc.getElementsByTagName("parsererror")[0];
            parseErrorText = Sarissa.getText(parsererror, true)+"\n";
        } else if(oDoc.parseError && oDoc.parseError.errorCode != 0){
            parseErrorText = Sarissa.PARSED_UNKNOWN_ERROR;
        };
        return parseErrorText;
    };
};
Sarissa.getText = function(oNode, deep){
    var s = "";
    var nodes = oNode.childNodes;
    for(var i=0; i < nodes.length; i++){
        var node = nodes[i];
        var nodeType = node.nodeType;
        if(nodeType == Node.TEXT_NODE || nodeType == Node.CDATA_SECTION_NODE){
            s += node.data;
        } else if(deep == true
                    && (nodeType == Node.ELEMENT_NODE
                        || nodeType == Node.DOCUMENT_NODE
                        || nodeType == Node.DOCUMENT_FRAGMENT_NODE)){
            s += Sarissa.getText(node, true);
        };
    };
    return s;
};
if(!window.XMLSerializer 
    && Sarissa.getDomDocument 
    && Sarissa.getDomDocument("","foo", null).xml){
    /**
     * Utility class to serialize DOM Node objects to XML strings
     * @constructor
     */
    XMLSerializer = function(){};
    /**
     * Serialize the given DOM Node to an XML string
     * @param oNode the DOM Node to serialize
     */
    XMLSerializer.prototype.serializeToString = function(oNode) {
        return oNode.xml;
    };
};

/**
 * strips tags from a markup string
 */
Sarissa.stripTags = function (s) {
    return s.replace(/<[^>]+>/g,"");
};
/**
 * <p>Deletes all child nodes of the given node</p>
 * @argument oNode the Node to empty
 */
Sarissa.clearChildNodes = function(oNode) {
    // need to check for firstChild due to opera 8 bug with hasChildNodes
    while(oNode.firstChild) {
        oNode.removeChild(oNode.firstChild);
    };
};
/**
 * <p> Copies the childNodes of nodeFrom to nodeTo</p>
 * <p> <b>Note:</b> The second object's original content is deleted before 
 * the copy operation, unless you supply a true third parameter</p>
 * @argument nodeFrom the Node to copy the childNodes from
 * @argument nodeTo the Node to copy the childNodes to
 * @argument bPreserveExisting whether to preserve the original content of nodeTo, default is false
 */
Sarissa.copyChildNodes = function(nodeFrom, nodeTo, bPreserveExisting) {
    if(_SARISSA_IS_SAFARI && nodeTo.nodeType == Node.DOCUMENT_NODE){ // SAFARI_OLD ??
        nodeTo = nodeTo.documentElement; //Appearantly there's a bug in safari where you can't appendChild to a document node
    }
    
    if((!nodeFrom) || (!nodeTo)){
        throw "Both source and destination nodes must be provided";
    };
    if(!bPreserveExisting){
        Sarissa.clearChildNodes(nodeTo);
    };
    var ownerDoc = nodeTo.nodeType == Node.DOCUMENT_NODE ? nodeTo : nodeTo.ownerDocument;
    var nodes = nodeFrom.childNodes;
    if(typeof(ownerDoc.importNode) != "undefined")  {
        for(var i=0;i < nodes.length;i++) {
            nodeTo.appendChild(ownerDoc.importNode(nodes[i], true));
        };
    } else {
        for(var i=0;i < nodes.length;i++) {
            nodeTo.appendChild(nodes[i].cloneNode(true));
        };
    };
};

/**
 * <p> Moves the childNodes of nodeFrom to nodeTo</p>
 * <p> <b>Note:</b> The second object's original content is deleted before 
 * the move operation, unless you supply a true third parameter</p>
 * @argument nodeFrom the Node to copy the childNodes from
 * @argument nodeTo the Node to copy the childNodes to
 * @argument bPreserveExisting whether to preserve the original content of nodeTo, default is
 */ 
Sarissa.moveChildNodes = function(nodeFrom, nodeTo, bPreserveExisting) {
    if((!nodeFrom) || (!nodeTo)){
        throw "Both source and destination nodes must be provided";
    };
    if(!bPreserveExisting){
        Sarissa.clearChildNodes(nodeTo);
    };
    var nodes = nodeFrom.childNodes;
    // if within the same doc, just move, else copy and delete
    if(nodeFrom.ownerDocument == nodeTo.ownerDocument){
        while(nodeFrom.firstChild){
            nodeTo.appendChild(nodeFrom.firstChild);
        };
    } else {
        var ownerDoc = nodeTo.nodeType == Node.DOCUMENT_NODE ? nodeTo : nodeTo.ownerDocument;
        if(typeof(ownerDoc.importNode) != "undefined") {
           for(var i=0;i < nodes.length;i++) {
               nodeTo.appendChild(ownerDoc.importNode(nodes[i], true));
           };
        }else{
           for(var i=0;i < nodes.length;i++) {
               nodeTo.appendChild(nodes[i].cloneNode(true));
           };
        };
        Sarissa.clearChildNodes(nodeFrom);
    };
};

/** 
 * <p>Serialize any object to an XML string. All properties are serialized using the property name
 * as the XML element name. Array elements are rendered as <code>array-item</code> elements, 
 * using their index/key as the value of the <code>key</code> attribute.</p>
 * @argument anyObject the object to serialize
 * @argument objectName a name for that object
 * @return the XML serializationj of the given object as a string
 */
Sarissa.xmlize = function(anyObject, objectName, indentSpace){
    indentSpace = indentSpace?indentSpace:'';
    var s = indentSpace  + '<' + objectName + '>';
    var isLeaf = false;
    if(!(anyObject instanceof Object) || anyObject instanceof Number || anyObject instanceof String 
        || anyObject instanceof Boolean || anyObject instanceof Date){
        s += Sarissa.escape(""+anyObject);
        isLeaf = true;
    }else{
        s += "\n";
        var itemKey = '';
        var isArrayItem = anyObject instanceof Array;
        for(var name in anyObject){
            s += Sarissa.xmlize(anyObject[name], (isArrayItem?"array-item key=\""+name+"\"":name), indentSpace + "   ");
        };
        s += indentSpace;
    };
    return s += (objectName.indexOf(' ')!=-1?"</array-item>\n":"</" + objectName + ">\n");
};

/** 
 * Escape the given string chacters that correspond to the five predefined XML entities
 * @param sXml the string to escape
 */
Sarissa.escape = function(sXml){
    return sXml.replace(/&/g, "&amp;")
        .replace(/</g, "&lt;")
        .replace(/>/g, "&gt;")
        .replace(/"/g, "&quot;")
        .replace(/'/g, "&apos;");
};

/** 
 * Unescape the given string. This turns the occurences of the predefined XML 
 * entities to become the characters they represent correspond to the five predefined XML entities
 * @param sXml the string to unescape
 */
Sarissa.unescape = function(sXml){
    return sXml.replace(/&apos;/g,"'")
        .replace(/&quot;/g,"\"")
        .replace(/&gt;/g,">")
        .replace(/&lt;/g,"<")
        .replace(/&amp;/g,"&");
};
//   EOF
/**
 * ====================================================================
 * About
 * ====================================================================
 * Sarissa cross browser XML library - IE .load eulation (deprecated)
 * @version ${project.version}
 * @author: Manos Batsis, mailto: mbatsis at users full stop sourceforge full stop net
 *
 * This script emulates Internet Explorer's .load method of DOM Document objects. 
 *
 * All functionality in this file is DEPRECATED, XMLHttpRequest objects 
 * should be used to load XML documents instead 
 *
 * @version @sarissa.version@
 * @author: Manos Batsis, mailto: mbatsis at users full stop sourceforge full stop net
 * ====================================================================
 * Licence
 * ====================================================================
 * Sarissa is free software distributed under the GNU GPL version 2 (see <a href="gpl.txt">gpl.txt</a>) or higher, 
 * GNU LGPL version 2.1 (see <a href="lgpl.txt">lgpl.txt</a>) or higher and Apache Software License 2.0 or higher 
 * (see <a href="asl.txt">asl.txt</a>). This means you can choose one of the three and use that if you like. If 
 * you make modifications under the ASL, i would appreciate it if you submitted those.
 * In case your copy of Sarissa does not include the license texts, you may find
 * them online in various formats at <a href="http://www.gnu.org">http://www.gnu.org</a> and 
 * <a href="http://www.apache.org">http://www.apache.org</a>.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY 
 * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 
 * WARRANTIES OF MERCHANTABILITY,FITNESS FOR A PARTICULAR PURPOSE 
 * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 
 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
if(!_SARISSA_IS_IE){
    if(_SARISSA_HAS_DOM_CREATE_DOCUMENT){
        /**
         * <p>Ensures the document was loaded correctly, otherwise sets the
         * parseError to -1 to indicate something went wrong. Internal use</p>
         * @private
         */
        Sarissa.__handleLoad__ = function(oDoc){
            Sarissa.__setReadyState__(oDoc, 4);
        };
        function SarissaParseError() {
            this.errorCode = 0;
        };
        /**
        * <p>Attached by an event handler to the load event. Internal use.</p>
        * @private
        */
        _sarissa_XMLDocument_onload = function(){
            Sarissa.__handleLoad__(this);
        };
        /**
         * <p>Sets the readyState property of the given DOM Document object.
         * Internal use.</p>
         * @private
         * @argument oDoc the DOM Document object to fire the
         *          readystatechange event
         * @argument iReadyState the number to change the readystate property to
         */
        Sarissa.__setReadyState__ = function(oDoc, iReadyState){
            oDoc.readyState = iReadyState;
            oDoc.readystate = iReadyState;
            if (oDoc.onreadystatechange != null && typeof oDoc.onreadystatechange == "function")
                oDoc.onreadystatechange();
        };
        Sarissa.getDomDocument = function(sUri, sName){
            
            var oDoc = document.implementation.createDocument(sUri?sUri:null, sName?sName:null, null);
            if(!oDoc.onreadystatechange){
            
                /**
                * <p>Emulate IE's onreadystatechange attribute</p>
                */
                oDoc.onreadystatechange = null;
            };
            if(!oDoc.readyState){
                /**
                * <p>Emulates IE's readyState property, which always gives an integer from 0 to 4:</p>
                * <ul><li>1 == LOADING,</li>
                * <li>2 == LOADED,</li>
                * <li>3 == INTERACTIVE,</li>
                * <li>4 == COMPLETED</li></ul>
                */
                oDoc.readyState = 0;
            };
            if(!oDoc.parseError){
                oDoc.parseError = new SarissaParseError();
            };
            oDoc.addEventListener("load", _sarissa_XMLDocument_onload, false);
            return oDoc;
        };
        if(window.XMLDocument){
            /**
            * <p>Keeps a handle to the original load() method. Internal use and only
            * if Mozilla version is lower than 1.4</p>
            * @private
            */
            XMLDocument.prototype._sarissa_load = XMLDocument.prototype.load;
            // NOTE: setting async to false will only work with documents
            // called over HTTP (meaning a server), not the local file system,
            // unless you are using Moz 1.4+.
        
            /**
            * <p>This is deprecated, use XMLHttpRequest to load remote documents instead. 
            * Overrides the original load method to provide synchronous loading for
            * Mozilla versions prior to 1.4 and fix ready state stuff.</p>
            * @deprecated 
            * @returns the DOM Object as it was before the load() call (may be  empty)
            */
            XMLDocument.prototype.load = function(sURI) {
                var oDoc = Sarissa.getDomDocument();
                Sarissa.copyChildNodes(this, oDoc);
                this.parseError.errorCode = 0;
                Sarissa.__setReadyState__(this, 1);
                try {
                    if(this.async == false && _SARISSA_SYNC_NON_IMPLEMENTED) {
                        var tmp = new XMLHttpRequest();
                        tmp.open("GET", sURI, false);
                        tmp.send(null);
                        Sarissa.__setReadyState__(this, 2);
                        Sarissa.copyChildNodes(tmp.responseXML, this);
                        Sarissa.__setReadyState__(this, 3);
                    }else{
                        this._sarissa_load(sURI);
                    };
                }
                catch (objException) {
                        oDoc.parseError.errorCode = -1;
                }
                finally {
                    if (!oDoc.documentElement || oDoc.documentElement.tagName == "parsererror"){
                        oDoc.parseError.errorCode = -1;
                    };
                    if(this.async == false){
                        Sarissa.__handleLoad__(this);
                    };
                };
                return oDoc;
            };
        //if(window.XMLDocument) , now mainly for opera  
        }// TODO: check if the new document has content before trying to copynodes, check  for error handling in DOM 3 LS
        else if(document.implementation && document.implementation.hasFeature && document.implementation.hasFeature('LS', '3.0')){
            Document.prototype.async = true;
            Document.prototype.onreadystatechange = null;
            Document.prototype.load = function(sURI) {
                var oldDoc = Sarissa.getDomDocument();
                Sarissa.copyChildNodes(this, oldDoc, false);
                var parser = document.implementation.createLSParser(this.async ? document.implementation.MODE_ASYNCHRONOUS : document.implementation.MODE_SYNCHRONOUS, null);
                if(this.async){
                    var self = this;
                    parser.addEventListener("load", 
                        function(e) { 
                              self.readyState = 4;
                              Sarissa.copyChildNodes(e.newDocument, self, false);
                              self.onreadystatechange.call(); 
                        }, 
                        false); 
                };
                try {
                    var oDoc = parser.parseURI(sURI);
                    if(!this.async) {
                        Sarissa.copyChildNodes(oDoc, this, false);
                    };
                }
                catch(e){
                    this.parseError.errorCode = -1;
                };
                return oldDoc;
            };
            /**
            * <p>Factory method to obtain a new DOM Document object</p>
            * @argument sUri the namespace of the root node (if any)
            * @argument sUri the local name of the root node (if any)
            * @returns a new DOM Document
            */
            Sarissa.getDomDocument = function(sUri, sName){
                var oDoc = document.implementation.createDocument(sUri?sUri:null, sName?sName:null, null);
                if(!oDoc.parseError){
                    oDoc.parseError = {errorCode:0};
                };
                return oDoc;
            };
        }
        else {
            Sarissa.getDomDocument = function(sUri, sName){
                var oDoc = document.implementation.createDocument(sUri?sUri:null, sName?sName:null, null);
                // looks like safari does not create the root element for some unknown reason
                if(oDoc && (sUri || sName) && !oDoc.documentElement){
                    oDoc.appendChild(oDoc.createElementNS(sUri, sName));
                };
                // attachb to the new object as we have no prototype to use, this is for safari
                if(!oDoc.load) {
                        oDoc.load = function(sUrl) {
                            var oldDoc = document.implementation.createDocument();
                            Sarissa.copyChildNodes(this, oldDoc);
                            this.parseError = {errorCode : 0};
                            Sarissa.__setReadyState__(this, 1);
                            if(this.async == false) {
                                var tmp = new XMLHttpRequest();
                                tmp.open("GET", sUrl, false);
                                tmp.send(null);
                                Sarissa.__setReadyState__(this, 2);
                                Sarissa.copyChildNodes(tmp.responseXML, oDoc);
                                if(!oDoc.documentElement || oDoc.getElementsByTagName("parsererror").length >0){
                                    oDoc.parseError.errorCode = -1;
                                };
                                Sarissa.__setReadyState__(this, 3);
                                Sarissa.__setReadyState__(this, 4);
                            }
                            else {
                                var xmlhttp = new XMLHttpRequest();
                                xmlhttp.open('GET', sUrl, true);
                                xmlhttp.onreadystatechange = function(){
                                    if (xmlhttp.readyState == 4) {
                                        Sarissa.copyChildNodes(xmlhttp.responseXML, oDoc);
                                        if(!oDoc.documentElement || oDoc.getElementsByTagName("parsererror").length > 0){
                                            oDoc.parseError.errorCode = -1;
                                        };      
                                    };
                                Sarissa.__setReadyState__(oDoc, xmlhttp.readyState);
                                };
                                xmlhttp.send(null);
                            };
                            return oldDoc;
                        };
                };
                return oDoc;
            };
        };
    };//if(_SARISSA_HAS_DOM_CREATE_DOCUMENT)
};
//   EOF
/**
 * ====================================================================
 * About
 * ====================================================================
 * Sarissa cross browser XML library - IE XPath Emulation 
 * @version ${project.version}
 * @author: Manos Batsis, mailto: mbatsis at users full stop sourceforge full stop net
 *
 * This script emulates Internet Explorer's selectNodes and selectSingleNode
 * for Mozilla. Associating namespace prefixes with URIs for your XPath queries
 * is easy with IE's setProperty. 
 * USers may also map a namespace prefix to a default (unprefixed) namespace in the
 * source document with Sarissa.setXpathNamespaces
 *
 *
 * ====================================================================
 * Licence
 * ====================================================================
 * Sarissa is free software distributed under the GNU GPL version 2 (see <a href="gpl.txt">gpl.txt</a>) or higher, 
 * GNU LGPL version 2.1 (see <a href="lgpl.txt">lgpl.txt</a>) or higher and Apache Software License 2.0 or higher 
 * (see <a href="asl.txt">asl.txt</a>). This means you can choose one of the three and use that if you like. If 
 * you make modifications under the ASL, i would appreciate it if you submitted those.
 * In case your copy of Sarissa does not include the license texts, you may find
 * them online in various formats at <a href="http://www.gnu.org">http://www.gnu.org</a> and 
 * <a href="http://www.apache.org">http://www.apache.org</a>.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY 
 * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 
 * WARRANTIES OF MERCHANTABILITY,FITNESS FOR A PARTICULAR PURPOSE 
 * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 
 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
if(_SARISSA_HAS_DOM_FEATURE && document.implementation.hasFeature("XPath", "3.0")){
    /**
    * <p>SarissaNodeList behaves as a NodeList but is only used as a result to <code>selectNodes</code>,
    * so it also has some properties IEs proprietery object features.</p>
    * @private
    * @constructor
    * @argument i the (initial) list size
    */
    function SarissaNodeList(i){
        this.length = i;
    };
    /** <p>Set an Array as the prototype object</p> */
    SarissaNodeList.prototype = new Array(0);
    /** <p>Inherit the Array constructor </p> */
    SarissaNodeList.prototype.constructor = Array;
    /**
    * <p>Returns the node at the specified index or null if the given index
    * is greater than the list size or less than zero </p>
    * <p><b>Note</b> that in ECMAScript you can also use the square-bracket
    * array notation instead of calling <code>item</code>
    * @argument i the index of the member to return
    * @returns the member corresponding to the given index
    */
    SarissaNodeList.prototype.item = function(i) {
        return (i < 0 || i >= this.length)?null:this[i];
    };
    /**
    * <p>Emulate IE's expr property
    * (Here the SarissaNodeList object is given as the result of selectNodes).</p>
    * @returns the XPath expression passed to selectNodes that resulted in
    *          this SarissaNodeList
    */
    SarissaNodeList.prototype.expr = "";
    /** dummy, used to accept IE's stuff without throwing errors */
    if(window.XMLDocument && (!XMLDocument.prototype.setProperty)){
        XMLDocument.prototype.setProperty  = function(x,y){};
    };
    /**
    * <p>Programmatically control namespace URI/prefix mappings for XPath
    * queries.</p>
    * <p>This method comes especially handy when used to apply XPath queries
    * on XML documents with a default namespace, as there is no other way
    * of mapping that to a prefix.</p>
    * <p>Using no namespace prefix in DOM Level 3 XPath queries, implies you
    * are looking for elements in the null namespace. If you need to look
    * for nodes in the default namespace, you need to map a prefix to it
    * first like:</p>
    * <pre>Sarissa.setXpathNamespaces(oDoc, &quot;xmlns:myprefix=&amp;aposhttp://mynsURI&amp;apos&quot;);</pre>
    * <p><b>Note 1 </b>: Use this method only if the source document features
    * a default namespace (without a prefix), otherwise just use IE's setProperty
    * (moz will rezolve non-default namespaces by itself). You will need to map that
    * namespace to a prefix for queries to work.</p>
    * <p><b>Note 2 </b>: This method calls IE's setProperty method to set the
    * appropriate namespace-prefix mappings, so you dont have to do that.</p>
    * @param oDoc The target XMLDocument to set the namespace mappings for.
    * @param sNsSet A whilespace-seperated list of namespace declarations as
    *            those would appear in an XML document. E.g.:
    *            <code>&quot;xmlns:xhtml=&apos;http://www.w3.org/1999/xhtml&apos;
    * xmlns:&apos;http://www.w3.org/1999/XSL/Transform&apos;&quot;</code>
    * @throws An error if the format of the given namespace declarations is bad.
    */
    Sarissa.setXpathNamespaces = function(oDoc, sNsSet) {
        //oDoc._sarissa_setXpathNamespaces(sNsSet);
        oDoc._sarissa_useCustomResolver = true;
        var namespaces = sNsSet.indexOf(" ")>-1?sNsSet.split(" "):new Array(sNsSet);
        oDoc._sarissa_xpathNamespaces = new Array(namespaces.length);
        for(var i=0;i < namespaces.length;i++){
            var ns = namespaces[i];
            var colonPos = ns.indexOf(":");
            var assignPos = ns.indexOf("=");
            if(colonPos > 0 && assignPos > colonPos+1){
                var prefix = ns.substring(colonPos+1, assignPos);
                var uri = ns.substring(assignPos+2, ns.length-1);
                oDoc._sarissa_xpathNamespaces[prefix] = uri;
            }else{
                throw "Bad format on namespace declaration(s) given";
            };
        };
    };
    /**
    * @private Flag to control whether a custom namespace resolver should
    *          be used, set to true by Sarissa.setXpathNamespaces
    */
    XMLDocument.prototype._sarissa_useCustomResolver = false;
    /** @private */
    XMLDocument.prototype._sarissa_xpathNamespaces = new Array();
    /**
    * <p>Extends the XMLDocument to emulate IE's selectNodes.</p>
    * @argument sExpr the XPath expression to use
    * @argument contextNode this is for internal use only by the same
    *           method when called on Elements
    * @returns the result of the XPath search as a SarissaNodeList
    * @throws An error if no namespace URI is found for the given prefix.
    */
    XMLDocument.prototype.selectNodes = function(sExpr, contextNode, returnSingle){
        var nsDoc = this;
        var nsresolver = this._sarissa_useCustomResolver
        ? function(prefix){
            var s = nsDoc._sarissa_xpathNamespaces[prefix];
            if(s)return s;
            else throw "No namespace URI found for prefix: '" + prefix+"'";
            }
        : this.createNSResolver(this.documentElement);
        var result = null;
        if(!returnSingle){
            var oResult = this.evaluate(sExpr,
                (contextNode?contextNode:this),
                nsresolver,
                XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
            var nodeList = new SarissaNodeList(oResult.snapshotLength);
            nodeList.expr = sExpr;
            for(var i=0;i<nodeList.length;i++)
                nodeList[i] = oResult.snapshotItem(i);
            result = nodeList;
        }
        else {
            result = oResult = this.evaluate(sExpr,
                (contextNode?contextNode:this),
                nsresolver,
                XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
        };
        return result;      
    };
    /**
    * <p>Extends the Element to emulate IE's selectNodes</p>
    * @argument sExpr the XPath expression to use
    * @returns the result of the XPath search as an (Sarissa)NodeList
    * @throws An
    *             error if invoked on an HTML Element as this is only be
    *             available to XML Elements.
    */
    Element.prototype.selectNodes = function(sExpr){
        var doc = this.ownerDocument;
        if(doc.selectNodes)
            return doc.selectNodes(sExpr, this);
        else
            throw "Method selectNodes is only supported by XML Elements";
    };
    /**
    * <p>Extends the XMLDocument to emulate IE's selectSingleNode.</p>
    * @argument sExpr the XPath expression to use
    * @argument contextNode this is for internal use only by the same
    *           method when called on Elements
    * @returns the result of the XPath search as an (Sarissa)NodeList
    */
    XMLDocument.prototype.selectSingleNode = function(sExpr, contextNode){
        var ctx = contextNode?contextNode:null;
        return this.selectNodes(sExpr, ctx, true);
    };
    /**
    * <p>Extends the Element to emulate IE's selectSingleNode.</p>
    * @argument sExpr the XPath expression to use
    * @returns the result of the XPath search as an (Sarissa)NodeList
    * @throws An error if invoked on an HTML Element as this is only be
    *             available to XML Elements.
    */
    Element.prototype.selectSingleNode = function(sExpr){
        var doc = this.ownerDocument;
        if(doc.selectSingleNode)
            return doc.selectSingleNode(sExpr, this);
        else
            throw "Method selectNodes is only supported by XML Elements";
    };
    Sarissa.IS_ENABLED_SELECT_NODES = true;
};
/////////////////////////////////////////////////
//
// Configuration manager 
//
// Configuration manager provides an easy to use
// configuration repository.
//
// See config folder for the configuration files.
//
// Author: Tasos Vogiatzoglou
//
/////////////////////////////////////////////////

YAHOO.namespace("mapConfig");

YAHOO.mapConfig = {};
YAHOO.mapConfig.onConfigLoad = function(){};
YAHOO.mapConfig.onConfigFailure = function(){};
YAHOO.mapConfig.img_service ='xee_map_am';
YAHOO.mapConfig.feature_service ='xee_map_ft';


var _generalCallback = {
};

YAHOO.mapConfig.load = function() {
      setTimeout(function() {
      YAHOO.mapConfig.onConfigLoad();
	},1000);
};


function openPopup(url){
	window.open(url,"product","width=390,height=550,toolbar=no, resizable=yes,scrollbars=yes");
}

var cfg = YAHOO.mapConfig;

var detailsFormatter = function(elCell, oRecord, oColumn, oData) {
            var numm = oData;
            var rec = oRecord.getData();
            var s = "minx="+rec.minx+"&miny="+rec.miny+"&maxx="+rec.maxx+"&maxy="+rec.maxy;
            elCell.innerHTML = "<a href='javascript:openPopup(\"http://webgis.hnhs.gr/servlet/xee.jsp?code="+numm+"&lang="+lang+"&"+s+"\")'>"+resMan.get('lblDetailsOrders')+"</a>";
        };


		var detailsFormatterEnc = function(elCell, oRecord, oColumn, oData) {
		            var numm = oData;
		            elCell.innerHTML = "<a href='javascript:openPopup(\"http://webgis.hnhs.gr/servlet/enc.jsp?code="+numm+"&lang="+lang+"\")'>"+resMan.get('lblDetailsOrders')+"</a>";
		        };


var highlightChart = function (id,envelope) {
	var lr = '<LAYER type="featureclass" name="highlight" visible="true" id="highlight">';
      lr += '<DATASET fromlayer="'+YAHOO.mapComponent.service.getLayerId('charts')+'"/>';
	
      var qry = '<SPATIALQUERY where="MAP_NO = \''+id+'\'" subfields="#ALL#">';
      qry += '</SPATIALQUERY>';

      lr += qry;
//      lr += '<GROUPRENDERER>';
      lr += '<SIMPLERENDERER>';
      lr += '	  <SIMPLEPOLYGONSYMBOL boundarytransparency="1,0" filltransparency="0.7" filltype="solid" boundarycolor="255,234,190" boundarycaptype="round" />';
      lr += '</SIMPLERENDERER>';
//      lr += '<SIMPLELABELRENDERER field="MAP_NO">';
//      lr += ' <TEXTSYMBOL antialiasing="true" font="Arial" fontstyle="regular" fontcolor="255,255,255" fontsize="10" glowing="255,0,0" />';
//      lr += '</SIMPLELABELRENDERER>';
//      lr += '</GROUPRENDERER>';
      lr += '</LAYER>';

        YAHOO.mapComponent.service.dynamicLayers["highlight_chart"] = lr;
        YAHOO.mapComponent.service.dynamicLayers['highlight_XEE'] = "";
   YAHOO.mapComponent.service.getLayerByName('charts').setVisible(true);
   YAHOO.mapComponent.service.getLayerByName('XEE').setVisible(false);
	YAHOO.mapComponent.changeExtent(envelope.zoomByFactor(-1.2));
};

var highlightChart = function (id,envelope) {
	var lr = '<LAYER type="featureclass" name="highlight" visible="true" id="highlight">';
      lr += '<DATASET fromlayer="'+YAHOO.mapComponent.service.getLayerId('XEE')+'"/>';
	
      var qry = '<SPATIALQUERY where="CHART_NO = \''+id+'\'" subfields="#ALL#">';
      qry += '</SPATIALQUERY>';

      lr += qry;
//      lr += '<GROUPRENDERER>';
      lr += '<SIMPLERENDERER>';
      lr += '	  <SIMPLEPOLYGONSYMBOL boundarytransparency="1,0" filltransparency="0.7" filltype="solid" boundarycolor="255,234,190" boundarycaptype="round" />';
      lr += '</SIMPLERENDERER>';
//      lr += '<SIMPLELABELRENDERER field="CHART_NO">';
//      lr += ' <TEXTSYMBOL antialiasing="true" font="Arial" fontstyle="regular" fontcolor="255,255,255" fontsize="10" glowing="255,0,0" />';
//      lr += '</SIMPLELABELRENDERER>';
//      lr += '</GROUPRENDERER>';
      lr += '</LAYER>';

        YAHOO.mapComponent.service.dynamicLayers["highlight_XEE"] = lr;
   YAHOO.mapComponent.service.getLayerByName('XEE').setVisible(true);
	YAHOO.mapComponent.changeExtent(envelope.zoomByFactor(-1.2));
};


var highlightXEE = function (id,envelope) {
	var lr = '<LAYER type="featureclass" name="highlight" visible="true" id="highlight">';
      lr += '<DATASET fromlayer="'+YAHOO.mapComponent.service.getLayerId('XEE')+'"/>';
	
      var qry = '<SPATIALQUERY where="MAP_NO = \''+id+'\'" subfields="#ALL#">';
      qry += '</SPATIALQUERY>';

      lr += qry;
//      lr += '<GROUPRENDERER>';
      lr += '<SIMPLERENDERER>';
      lr += '	  <SIMPLEPOLYGONSYMBOL boundarytransparency="1,0" filltransparency="0.7" filltype="solid" boundarycolor="255,234,190" boundarycaptype="round" />';
      lr += '</SIMPLERENDERER>';
//      lr += '<SIMPLELABELRENDERER field="MAP_NO">';
//      lr += ' <TEXTSYMBOL antialiasing="true" font="Arial" fontstyle="regular" fontcolor="255,255,255" fontsize="10" glowing="255,0,0" />';
//      lr += '</SIMPLELABELRENDERER>';
//      lr += '</GROUPRENDERER>';
      lr += '</LAYER>';

        YAHOO.mapComponent.service.dynamicLayers["highlight_XEE"] = lr;
   YAHOO.mapComponent.service.getLayerByName('XEE').setVisible(true);
	YAHOO.mapComponent.changeExtent(envelope.zoomByFactor(-1.2));
};

var zoomToPoint = function(elCell,oRecord,oColumn,oData){
            var numm = oData;
            var code = 'highlightXEE("'+numm+'",new Envelope(new Point('+oRecord.getData().minx.toString().replace(',','.')+','+oRecord.getData().miny.toString().replace(',','.')+'),new Point('+oRecord.getData().maxx.toString().replace(',','.')+','+oRecord.getData().maxy.toString().replace(',','.')+')))';
            elCell.innerHTML = "<a href='javascript:"+code+"'>"+numm+"</a>";
   };
   

var XEE_FIELDS = [{key:"XEE_AOI.MAP_NO",label:resMan.get("xeenum"),width:80,formatter:zoomToPoint},
		  {key:"XEE_AOI."+(lang=='el'?"TITLE_GR":"TITLE_EN"),label:resMan.get("title_gr"),width:200},
		  {key:"XEE_CATALOG.YRLAST",label:resMan.get("yrlast"),width:100},
		  {key:"XEE_AOI.MAP_NO",formatter:detailsFormatter,label:resMan.get("detLinks"),width:60}];



var XEE_FIELDS2 = [{key:"SDE.XEE_AOI.MAP_NO",label:resMan.get("xeenum"),width:80,formatter:zoomToPoint},
		  {key:"SDE.XEE_AOI."+(lang=='el'?"TITLE_GR":"TITLE_EN"),label:resMan.get("title_gr"),width:200},
		  {key:"SDE.XEE_CATALOG.YRLAST",label:resMan.get("yrlast"),width:100},
		  {key:"SDE.XEE_AOI.MAP_NO",formatter:detailsFormatter,label:resMan.get("detLinks"),width:60}];

var ENC_FIELDS = [{key:"CNAME",label:resMan.get("enc_name"),width:80,formatter:zoomToPoint},
		  {key:"S57_ED",label:resMan.get("s57_edition"),width:200},
		  {key:"CNAME",formatter:detailsFormatterEnc
				,label:resMan.get("detLinks"),width:60}];

cfg.layers = {
   XEE : { select : XEE_FIELDS2 },
   XEE_45_2 : { select : XEE_FIELDS },
   XEE_95_50 : { select : XEE_FIELDS },              
   XEE_150_100 : { select : XEE_FIELDS },
   XEE_300_250 : { select : XEE_FIELDS },   
   XEE_500 : { select : XEE_FIELDS },      
   XEE_GENERAL : { select : XEE_FIELDS } ,
   enc_coastal : { select : ENC_FIELDS },
   enc_coastal_intersect : { select : ENC_FIELDS },
   enc_general_intersect : { select : ENC_FIELDS },
   enc_general : { select : ENC_FIELDS },
	enc_approach: { select : ENC_FIELDS},
	enc_berthing : {select:ENC_FIELDS},
	enc_harbour : {select:ENC_FIELDS}
	
};


   
function fts(flt) {
	return flt.toString().replace('.',DC);
}

var DC=","
/*
   Point class.
*/
var Point = function(x,y,unit) {

   var xp = parseFloat(x.toString().replace(',','.'));
   var y = parseFloat(y.toString().replace(',','.'));
   var id = "point";
   var unit = unit?unit:"meters";


   return {
      getX : function() {
         return xp;
      },
      getY : function() {
         return y;
      },
      setX : function (xpar) {
         xp = xpar;
      },
      setY : function (ypar) {
         y = ypar;
      },
      getId : function() {
         return id;
      },
      setId : function(idp) {
         id = idp;
      },
      getDistance : function(pnt) {
      },
      toString: function() {
         return "["+(Math.round(xp*100)/100)+ "," + (Math.round(y*100)/100)+"]";
      },
      toAXL: function() {
         return fts(xp) + " " + fts(y);
      },
      convertToMapCoords: function(envl) {

         var rx = envl.getXDistance()/YAHOO.mapComponent.getWidth();
         var ry = envl.getYDistance()/YAHOO.mapComponent.getHeight();

         var mx = xp*rx + envl.getMinPoint().getX();

         var my = (YAHOO.mapComponent.getHeight()-y)*ry + envl.getMinPoint().getY();


         var p = new Point(Math.round(mx*100000)/100000,Math.round(my*100000)/100000);
         p.setId(id);

         return p;
      },
      convertToImageCoords: function(envl) {
         var r = envl.getXDistance()/YAHOO.mapComponent.getWidth();        
         var l = envl.getCenter().getX() - (envl.getXDistance()/2);
         var t = envl.getCenter().getY() + (r*YAHOO.mapComponent.getHeight())/2;

         var ix = (xp -l)/r;
         var iy = (t -y)/r;
         
         var p = new Point(parseInt(ix),parseInt(iy));
         p.setId(id);

         return p;        
      },
      convertToProjectedCoords: function() {
	      return gr87_philambda_to_xy(carto.utils.degToRad(xp),carto.utils.degToRad(y));	
      },
      convertToGeographicCoords : function() {
	      var fl = gr87_xy_to_philambda(xp,y);
         return new Point(YAHOO.gis.radToDeg(fl[1]),YAHOO.gis.radToDeg(fl[0]));
      },
      isOutside : function(env) {
         return (
            xp<env.getMinPoint().getX() || xp>env.getMaxPoint().getX() || 
            y>env.getMaxPoint().getY() || y<env.getMinPoint().getY());
      }
   };
};

var Envelope = function(minPoint,maxPoint) {
   var maxPoint = maxPoint;
   var minPonit = minPoint;
   return {
      getMaxPoint : function() {
         return maxPoint;
      },
      getMinPoint : function() {
         return minPoint;
      },
      toAXL : function() {
         return '<ENVELOPE minx="'+fts(minPoint.getX())+
                '" miny="'+fts(minPoint.getY())+
                '" maxx="'+fts(maxPoint.getX())+
                '" maxy="'+fts(maxPoint.getY())+'" reaspect="true"/>';
      },
      toString : function() {
         return this.toAXL();
      },
      fromAXL : function (node) {

         var minx = node.attributes.getNamedItem("minx").value;

         //support chaning decimal separators
         if (minx.indexOf(',')==-1) {
             DC="."
         } else {
             DC=","
         }

         var miny = node.attributes.getNamedItem("miny").value;
         var maxx = node.attributes.getNamedItem("maxx").value;
         var maxy = node.attributes.getNamedItem("maxy").value;

         minPoint = new Point(minx,miny);

         maxPoint = new Point(maxx,maxy);

      },
      getXDistance : function() {
         return Math.abs(minPoint.getX()-maxPoint.getX());
      },
      getYDistance : function() {
         return Math.abs(minPoint.getY()-maxPoint.getY());
      },
      getCenter : function() {

         var x = minPoint.getX() + this.getXDistance()/2;
         var y = minPoint.getY() + this.getYDistance()/2;
         
         return new Point(x,y);
      }
      ,
      centerToPoint : function(point) {
         
         var minx = minPoint.getX();
         var miny = minPoint.getY();
         var maxx = maxPoint.getX();
         var maxy = maxPoint.getY();

         var dx = ((maxx-minx)/2) + minx;
         var dy = ((maxy-miny)/2) + miny;
         
         var nmin = new Point(
            minx + (point.getX() - dx),
            miny + (point.getY() - dy)
            );

         var nmax = new Point(
            maxx + (point.getX() - dx),
            maxy + (point.getY() - dy)
            );

         return new Envelope(nmin,nmax);
      },
      to_geographic_coords : function () {
	return new Envelope(this.getMinPoint().convertToGeographicCoords(),this.getMaxPoint().convertToGeographicCoords());
      },
      to_projected_coords : function () {
	return new Envelope(this.getMinPoint().convertToProjectedCoords(),this.getMaxPoint().convertToProjectedCoords());
      },
      zoomByFactor : function(factor) {
         if (factor > 0 ) {
            var xf = (
                        (this.getMaxPoint().getX()-this.getMinPoint().getX())*
                        (1-factor)
                     )/(-2*factor);

            var yf = (
                        (this.getMaxPoint().getY()-this.getMinPoint().getY())*
                        (1-factor)
                     )/(-2*factor);

            var nenv = new Envelope(
               new Point(minPoint.getX()+xf,minPoint.getY()+yf),
               new Point(maxPoint.getX()-xf,maxPoint.getY()-yf)
               );

            return nenv;
         } else {
            factor = factor*(-1);
            var xf = ((factor-1)*(maxPoint.getX()-minPoint.getX()))/2;

            var yf = ((factor-1)*(maxPoint.getY()-minPoint.getY()))/2;

            var nenv = new Envelope(
               new Point(minPoint.getX()-xf,minPoint.getY()-yf),
               new Point(maxPoint.getX()+xf,maxPoint.getY()+yf)
               );

            return nenv;
         }

      }
   };
};
   
/*
   LayerDefinition class. Represents a ArcIMS Service Layer
*/
var LayerDefinition = function(id,layerName,type,visible,minscale,maxscale) {
   var name = layerName;
   var type = type;
   var id = id;
   var visible = visible;
   var minscale = minscale;
   var maxscale = maxscale;

   var envelope = [];
   var fclass = new FeatureClass();
   return {
      getName : function() {
         return name;
      },
      getId : function() {
         return id;
      },
      isVisible : function() {
         return visible;
      },
      setVisible : function(visibility) {
         visible = visibility;
      },
      getType : function() {
         return type;
      },
      setEnvelope: function(minPoint,maxPoint) {
      },

      getEnvelope: function() {
      },
      getMinScale: function() {
         return minscale;
      },
      getMaxScale: function() {
         return maxscale;
      },
      setFClass: function(fclass) {
         this.fclass = fclass;
      },

      getFclass: function() {
         return fclass;
      }
   };
};

var FeatureClass = function(type,minPoint,maxPoint) {
   var type = type;
   var envelope = new Envelope(minPoint,maxPoint);
   var fields = [];

   return {
      addField: function (name,type,size,prec) {
      },
      getFields: function() {
      }
   };
};



/*************************************
 *
 *
 *
 *************************************/

var carto = {};

carto.EARTH_RADIUS = 6378.135;
carto.EARTH_RADIUS_M = 6378135.0;
carto.PI = 3.141592653589793;
carto.PI_2 = carto.PI/2;
//Ellipsoid model constants (actual values here are for WGS84)
carto.sm_a = 6378137.0;
carto.sm_b = 6356752.314;
carto.sm_EccSquared = 6.69437999013e-03;
carto.UTMScaleFactor = 0.9996;

var theUnitLabel;
var theConversion;

carto.BigSemiaxis = 6378137;
carto.e2 = 0.006694380015894481;//0.006694380;
carto.f = 1/298.257222101;//1/298.2572236;
carto.x0 = 500000.000;
carto.lambda0 = 0.418879020478639098;
carto.kappa0 = 0.9996;
carto.et2 = 1/((1-carto.f)*(1-carto.f))*carto.e2;
	
carto.utils = {};
carto.utils.parseAngular  = function (degs,arcmin,arcsec) {
   if (degs >= 0 && arcmin >= 0 && arcsec >=0) {
      return degs*1 + (arcmin/60)*1 + (arcsec/3600)*1;
   } else {
      return -1;
   }
};

carto.utils.degToRad = function (deg)  {
   return (deg / 180.0 * carto.PI)
};

carto.utils.radToDeg = function (rad) {
   return (rad / carto.PI * 180.0)
};

carto.utils.ellipsoid_arc = function( phi )
{
	var M0, M2,M4, M6,M8,e4,e6,e8;

	var returnvalue;
	e4 = Math.pow(carto.e2,2);
	e6 = Math.pow(carto.e2,3);
	e8 = Math.pow(carto.e2,4);
	
	M0 = 1 + 0.75*carto.e2 + 0.703125*e4 + 0.68359375*e6 + 0.67291259765625*e8; 
	M2 = 0.375*carto.e2 + 0.46875*e4 + 0.5126953125*e6 + 0.538330078125*e8;

	M4= 0.05859375*e4 + 0.1025390625*e6 + 0.25*e8;
	M6= 0.01139322916666667*e6 + 0.025634765625*e8;
	M8= 0.002408551504771226*e8;
	
	returnvalue = (carto.BigSemiaxis*(1-carto.e2)*(M0*phi-M2*Math.sin(2*phi)+M4*Math.sin(4*phi)-  M6*Math.sin(6*phi)+M8*Math.sin(8*phi)))
	
	return returnvalue;
}


carto.utils.fit = function(aphi)
{
	var l, phi0, phi0_old;
	
	var acount;
	
	l = aphi/carto.kappa0;             
	phi0=l/carto.BigSemiaxis;            
	acount = 0;
	do  {
		acount++;
		phi0_old = phi0;
		phi0 = phi0 + (l - carto.utils.ellipsoid_arc(phi0))/carto.utils.ellipsoid_main_normal_section_radius(phi0);
	} while(Math.abs(phi0-phi0_old)>1e-17 && acount<100 )

	return phi0;
}


carto.utils.displace_geodetic_system = function (phi, lambda,  dx, dy, dz) {

   
   var phi_rad =  carto.utils.ellipsoid_main_normal_section_radius(phi)*Math.cos(phi);
   var x = phi_rad*Math.cos(lambda);
   var y = phi_rad*Math.sin(lambda);
   var z = carto.utils.ellipsoid_main_normal_section_radius(phi)*(1-carto.e2)*Math.sin(phi);

   x = x + dx;
   y = y + dy;
   z = z + dz;
	
   var radius = carto.BigSemiaxis;
   var radius_old;

   var phi_lambda = new Array(2);

   if(Math.abs(z)<radius)
      phi_lambda[0] = Math.asin(z/radius);
   else
      phi_lambda[0] = carto.PI_2*( (z>0)?(1):(-1) ); //+- ð/2

   if (Math.abs(x) > (1/1000)) {
      phi_lambda[1]  = Math.atan(y/x);
   }
   else {
      phi_lambda[1] = carto.PI_2*( (y>0)?(1):(-1) ); //+- ð/2 
   }


   if(x<0)
      phi_lambda[1] = carto.PI - phi_lambda[1];
		
   phi_lambda[0] = Math.atan( z*(1+carto.et2) / Math.sqrt(x*x+y*y) );
	
   var acount = 0;
   do {
      acount++;
      radius_old = radius;
      radius = carto.utils.ellipsoid_main_normal_section_radius(phi_lambda[0]);
      phi_lambda[0] = Math.atan( (z+carto.e2*radius*Math.sin(phi_lambda[0])) / Math.sqrt(x*x+y*y) );
   } while (Math.abs(radius-radius_old)>0.00005 && acount<100) 

   return phi_lambda;
};

carto.utils.ellipsoid_main_normal_section_radius = function ( phi ) {
   return carto.BigSemiaxis/Math.sqrt(1-carto.e2*Math.sin(phi)*Math.sin(phi));
};


carto.utils.wgs_to_egsa = function (phi, lambda)
{

   var phi_lambda = carto.utils.displace_geodetic_system(carto.utils.degToRad(phi),carto.utils.degToRad(lambda), 
                           199.72, -74.03, -246.02);


   var phi = phi_lambda[0];
   var lambda = phi_lambda[1];

	var t, n2,L, dl, Ni, Mi;
 	var myxy= new Array(2);

	var x = 0;
	var y = 0;
	
	dl = lambda - carto.lambda0;
    	t = Math.tan(phi);
	
	n2 = carto.e2*Math.cos(phi)*Math.cos(phi)/(1-carto.e2);
	
	L = dl*Math.cos(phi);
	
	Ni = carto.utils.ellipsoid_main_normal_section_radius(phi);
	
	Mi = carto.utils.ellipsoid_arc(phi);
	
	x= (((5-18*t*t+t*t*t*t+14*n2-58*t*t*n2)*L*L/120.00 + (1-t*t+n2)/6.00)*L*L+1)*L*carto.kappa0*Ni +carto.x0;
	y= Mi + (Ni*t/2)*L*L + (Ni*t/24)*(5-t*t+9*n2+4*n2*n2)*L*L*L*L + (Ni*t/720)*(61-58*t*t)*L*L*L*L*L*L;
	y = y * carto.kappa0;
	gamma = t*L+t*L*L*L*(1+3*n2+4*n2*n2)/3+t*(2-t*t)*L*L*L*L*L/15;

   var rpnt = new Point(x,y);	
	return rpnt;
}


carto.utils.egsa_to_wgs = function(pnt)
{

	return gr87_xy_to_philambda(pnt.getX(),pnt.getY());

	var t, n2, f0, N0, P, P2;
 
	var phi_lambda= new Array(2);

	var phi = 0;
	var lambda = 0;
	var x = pnt.getX() - carto.x0;
	
	f0 = carto.utils.fit(pnt.getY());
	
	N0 = carto.utils.ellipsoid_main_normal_section_radius(f0);
    	t = Math.tan(f0);
	n2 = carto.et2 * Math.cos(f0)*Math.cos(f0);
	P = (x/(carto.kappa0*N0));
	P2 = P*P;
		
	phi = (((-(61+90*t*t+45*t*t*t*t)*P2/720 +  (5+3*t*t+6*n2-3*n2*n2-6*t*t*n2-9*t*t*n2*n2)/24)*P2- (1+n2)/2)*P2)*t + f0;
	lambda = ((((5+6*n2+28*t*t+8*t*t*n2+24*t*t*t*t)*P2/120 -(1+2*t*t+n2)/6)*P2+1)*P)/Math.cos(f0) + carto.lambda0;

	gamma=x*t/(carto.kappa0*N0)-t*(1+t*t-n2-2*n2*n2)*x*x*x/(3*carto.kappa0*carto.kappa0*carto.kappa0*N0*N0*N0)+t*(2+5*t*t+3*t*t*t*t)*Math.pow(x/(carto.kappa0*N0),5)/15;

	phi_lambda[0] = phi;
	phi_lambda[1] = lambda;
	return phi_lambda;
}

/*************************************************************/


YAHOO.gis = {};
YAHOO.gis.EARTH_RADIUS = 6378.135;
YAHOO.gis.EARTH_RADIUS_M = 6378135.0;
YAHOO.gis.PI = 3.14159265359;


//Ellipsoid model constants (actual values here are for WGS84)
var sm_a = 6378137.0;
var sm_b = 6356752.314;
var sm_EccSquared = 6.69437999013e-03;
var UTMScaleFactor = 0.9996;

var theUnitLabel;
var theConversion;

var BigSemiaxis = 6378137;
var e2 = 0.006694380015894481;//0.006694380;
var f = 1/298.257222101;//1/298.2572236;
var x0 = 500000.000;
var lambda0 = 0.418879020478639098;
var kappa0 = 0.9996;
var et2 = 1/((1-f)*(1-f))*e2;
	

YAHOO.gis.parseAngular  = function (degs,arcmin,arcsec) {
   if (degs >= 0 && arcmin >= 0 && arcsec >=0) {
      return degs*1 + (arcmin/60)*1 + (arcsec/3600)*1;
   } else {
      return -1;
   }
};

YAHOO.gis.degToRad = function (deg)  {
   return (deg / 180.0 * Math.PI)
};

YAHOO.gis.radToDeg = function (rad) {
   return (rad / Math.PI * 180.0)
};

YAHOO.gis.point_by_azimuth = function (phi_lambda, azimuth, distance)  {

   var azimuth = 180 - azimuth;

   var fo = 1.0 - f;
   var lat1 = phi_lambda[0];
   var long1 = phi_lambda[1];

   /*
         * Modified Rainsford's method with Helmert's elliptical terms.
         * Effective in any azimuth and at any distance short of antipodal.
         *
         * Latitudes and longitudes in radians positive North and East.
         * Forward azimuths at both points returned in radians from North.
         *
         * Source: ftp://ftp.ngs.noaa.gov/pub/pcsoft/for_inv.3d/source/forward.for
         *         subroutine DIRECT1
         */
   var TU  = fo*Math.sin(lat1) / Math.cos(lat1);
   var SF  = Math.sin(azimuth);
   var CF  = Math.cos(azimuth);
        var BAZ = (CF!=0) ? Math.atan2(TU,CF)*2.0 : 0;
        var CU  = 1/Math.sqrt(TU*TU + 1.0);
        var SU  = TU*CU;
        var SA  = CU*SF;
        var C2A = 1.0 - SA*SA;
        var X   = Math.sqrt((1.0/fo/fo-1)*C2A+1.0) + 1.0;
        X   = (X-2.0)/X;
        var C   = 1.0-X;
        C   = (X*X/4.0+1.0)/C;
        var D   = (0.375*X*X-1.0)*X;
        TU   = distance / fo / BigSemiaxis / C;
        var Y   = TU;
        var SY, CY, CZ, E;
        do {
            SY = Math.sin(Y);
            CY = Math.cos(Y);
            CZ = Math.cos(BAZ+Y);
            E  = CZ*CZ*2.0-1.0;
            C  = Y;
            X  = E*CY;
            Y  = E+E-1.0;
            Y  = (((SY*SY*4.0-3.0)*Y*CZ*D/6.0+X)*D/4.0-CZ)*SY*D+TU;
        } while (Math.abs(Y-C) > 0.000001);
 
       BAZ  = CU*CY*CF - SU*SY;
        C    = fo*Math.sqrt(SA*SA+BAZ*BAZ);
        D    = SU*CY + CU*SY*CF;
        var lat2 = Math.atan2(D,C);
        C    = CU*CY-SU*SY*CF;
        X    = Math.atan2(SY*SF,C);
        C    = ((-3.0*C2A+4.0)*f+4.0)*C2A*f/16.0;
        D    = ((E*CY*C+CZ)*SY*C+Y)*SA;
        var long2 = long1+X - (1.0-C)*D*f;
        var long2 = long2 - (2*YAHOO.gis.PI) * Math.floor(long2/(2*YAHOO.gis.PI) + 0.5); 

	return gr87_philambda_to_xy(lat2,long2);
};

function ellipsoid_arc( phi )
{
	var M0, M2,M4, M6,M8,e4,e6,e8;

	var returnvalue;
	e4 = e2 * e2;
	e6 = e4 * e2;
	e8 = e6 * e2;
	
	M0 = 1 + 0.75*e2 + 0.703125*e4 + 0.68359375*e6 + 0.67291259765625*e8; 
	M2 = 0.375*e2 + 0.46875*e4 + 0.5126953125*e6 + 0.538330078125*e8;
	M4= 0.05859375*e4 + 0.1025390625*e6 + 0.25*e8;
	M6= 0.01139322916666667*e6 + 0.025634765625*e8;
	M8= 0.002408551504771226*e8;
	
	returnvalue = (BigSemiaxis*(1-e2)*(M0*phi-M2*Math.sin(2*phi)+M4*Math.sin(4*phi)-  M6*Math.sin(6*phi)+M8*Math.sin(8*phi)))
	
	return returnvalue;
}


function fit(aphi)
{
	var l, phi0, phi0_old;
	
	var acount;
	
	l = aphi/kappa0;             
	phi0=l/BigSemiaxis;            
	acount = 0;
	do  {
		acount++;
		phi0_old = phi0;
		phi0 = phi0 + (l - ellipsoid_arc(phi0))/ellipsoid_main_normal_section_radius(phi0);
	} while(Math.abs(phi0-phi0_old)>1e-17 && acount<100 )
	return phi0;
}


YAHOO.gis.displace_geodetic_system = function (phi, lambda,  dx, dy, dz) {

   
   var phi_rad =  ellipsoid_main_normal_section_radius(phi)*Math.cos(phi);
   var x = phi_rad*Math.cos(lambda);
   var y = phi_rad*Math.sin(lambda);
   var z = ellipsoid_main_normal_section_radius(phi)*(1-e2)*Math.sin(phi);

   x = x + dx;
   y = y + dy;
   z = z + dz;
	
   var radius = BigSemiaxis;
   var radius_old;

   var phi_lambda = new Array(2);

   if(Math.abs(z)<radius)
      phi_lambda[0] = Math.asin(z/radius);
   else
      phi_lambda[0] = 1.5707963267948966*( (z>0)?(1):(-1) ); //+- ð/2

   if (Math.abs(x) > (1/1000)) {
      phi_lambda[1]  = Math.atan(y/x);
   }
   else {
      phi_lambda[1] = 1.5707963267948966*( (y>0)?(1):(-1) ); //+- ð/2 
   }


   if(x<0)
      phi_lambda[1] = 3.141592653589793 - phi_lambda[1];
		
   phi_lambda[0] = Math.atan( z*(1+et2) / Math.sqrt(x*x+y*y) );
	
   var acount = 0;
   do {
      acount++;
      radius_old = radius;
      radius = ellipsoid_main_normal_section_radius(phi_lambda[0]);
      phi_lambda[0] = Math.atan( (z+e2*radius*Math.sin(phi_lambda[0])) / Math.sqrt(x*x+y*y) );
   } while (Math.abs(radius-radius_old)>0.00005 && acount<100) 

   return phi_lambda;
};



function ellipsoid_main_normal_section_radius( phi ) {
   return BigSemiaxis/Math.sqrt(1-e2*Math.sin(phi)*Math.sin(phi));
};

function gr87_philambda_to_xy(phi, lambda)
{

   phi_lambda = carto.utils.displace_geodetic_system(phi,lambda, 199.72, -74.03, -246.02);

   phi = phi_lambda[1];
   lambda = phi_lambda[0];

	var t, n2,L, dl, Ni, Mi;
 	var myxy= new Array(2);

	var x = 0;
	var y = 0;
	
	dl = lambda - lambda0;
    	t = Math.tan(phi);
	
	n2 = e2*Math.cos(phi)*Math.cos(phi)/(1-e2);
	
	L = dl*Math.cos(phi);
	
	Ni = ellipsoid_main_normal_section_radius(phi);
	
	Mi = ellipsoid_arc(phi);
	
	x= (((5-18*t*t+t*t*t*t+14*n2-58*t*t*n2)*L*L/120.00 + (1-t*t+n2)/6.00)*L*L+1)*L*kappa0*Ni +x0;
	y= Mi + (Ni*t/2)*L*L + (Ni*t/24)*(5-t*t+9*n2+4*n2*n2)*L*L*L*L + (Ni*t/720)*(61-58*t*t)*L*L*L*L*L*L;
	y = y * kappa0;
	gamma = t*L+t*L*L*L*(1+3*n2+4*n2*n2)/3+t*(2-t*t)*L*L*L*L*L/15;

        var rpnt = new Point(x,y);	

	return rpnt;
}

function ellipsoid_arc( phi )
{
	var M0, M2,M4, M6,M8,e4,e6,e8;

	var returnvalue;
	e4 = e2 * e2;
	e6 = e4 * e2;
	e8 = e6 * e2;
	
	M0 = 1 + 0.75*e2 + 0.703125*e4 + 0.68359375*e6 + 0.67291259765625*e8; 
	M2 = 0.375*e2 + 0.46875*e4 + 0.5126953125*e6 + 0.538330078125*e8;
	M4= 0.05859375*e4 + 0.1025390625*e6 + 0.25*e8;
	M6= 0.01139322916666667*e6 + 0.025634765625*e8;
	M8= 0.002408551504771226*e8;
	
	returnvalue = (BigSemiaxis*(1-e2)*(M0*phi-M2*Math.sin(2*phi)+M4*Math.sin(4*phi)-  M6*Math.sin(6*phi)+M8*Math.sin(8*phi)))
	
	return returnvalue;
}


function gr87_xy_to_philambda(x, y)
{
	var t, n2, f0, N0, P, P2;
 
	var phi_lambda= new Array(2);

	phi = 0;
	lambda = 0;
	x = x - x0;
	f0 = fit(y);
	
	N0 = ellipsoid_main_normal_section_radius(f0);
    t = Math.tan(f0);
	n2 = et2 * Math.cos(f0)*Math.cos(f0);
	P = (x/(kappa0*N0));
	P2 = P*P;
		
	phi = (((-(61+90*t*t+45*t*t*t*t)*P2/720 +  (5+3*t*t+6*n2-3*n2*n2-6*t*t*n2-9*t*t*n2*n2)/24)*P2- (1+n2)/2)*P2)*t + f0;

	lambda = ((((5+6*n2+28*t*t+8*t*t*n2+24*t*t*t*t)*P2/120 -(1+2*t*t+n2)/6)*P2+1)*P)/Math.cos(f0) + lambda0;

	gamma=x*t/(kappa0*N0)-t*(1+t*t-n2-2*n2*n2)*x*x*x/(3*kappa0*kappa0*kappa0*N0*N0*N0)+	t*(2+5*t*t+3*t*t*t*t)*Math.pow(x/(kappa0*N0),5)/15;

	phi_lambda[0] = Math.round(parseFloat(phi)*1000)/1000;
	phi_lambda[1] = Math.round(parseFloat(lambda)*1000)/1000;
	return phi_lambda;
}

/**
 * @extends YAHOO.widget.TextNode
 * @constructor
 * @param oData    {object}  A string or object containing the data that will
 *                           be used to render this node.
 * @param oParent  {Node}    This node's parent node
 * @param expanded {boolean} The initial expanded/collapsed state
 * @param checked  {boolean} The initial checked/unchecked state
 */
YAHOO.widget.TOCNode = function(id,oData, oParent, expanded, checked,searchLayer) {

   this.id = id;
   this.searchLayer = searchLayer;

    if (YAHOO.widget.LogWriter) {
        this.logger = new YAHOO.widget.LogWriter(this.toString());
    } else {
        this.logger = YAHOO;
    }

    if (oData) { 
        this.init(oData, oParent, expanded);
        this.setUpLabel(oData);
        this.setUpCheck(checked);
    }

};

YAHOO.extend(YAHOO.widget.TOCNode, YAHOO.widget.TextNode, {

   getId: function() {
      return this.id;
   },
    /**
     * True if checkstate is 1 (some children checked) or 2 (all children checked),
     * false if 0.
     * @type boolean
     */
    checked: false,

    /**
     * checkState
     * 0=unchecked, 1=some children checked, 2=all children checked
     * @type int
     */
    checkState: 0,

    taskNodeParentChange: function() {
        //this.updateParent();
    },

    setUpCheck: function(checked) {
        // if this node is checked by default, run the check code to update
        // the parent's display state
        if (checked && checked === true) {
            this.check();
        // otherwise the parent needs to be updated only if its checkstate 
        // needs to change from fully selected to partially selected
        } else if (this.parent && 2 == this.parent.checkState) {
             this.updateParent();
        }

        // set up the custom event on the tree for checkClick
        /**
         * Custom event that is fired when the check box is clicked.  The
         * custom event is defined on the tree instance, so there is a single
         * event that handles all nodes in the tree.  The node clicked is 
         * provided as an argument.  Note, your custom node implentation can
         * implement its own node specific events this way.
         *
         * @event checkClick
         * @for YAHOO.widget.TreeView
         * @param {YAHOO.widget.Node} node the node clicked
         */
        if (this.tree && !this.tree.hasEvent("checkClick")) {
            this.tree.createEvent("checkClick", this.tree);
        }

        this.subscribe("parentChange", this.taskNodeParentChange);

    },

    /**
     * The id of the check element
     * @for YAHOO.widget.TOCNode
     * @type string
     */
    getCheckElId: function() { 
        return "ygtvcheck" + this.index; 
    },

    /**
     * Returns the check box element
     * @return the check html element (img)
     */
    getCheckEl: function() { 
        return document.getElementById(this.getCheckElId()); 
    },

    /**
     * The style of the check element, derived from its current state
     * @return {string} the css style for the current check state
     */
    getCheckStyle: function() { 
        return "ygtvcheck" + this.checkState;
    },

    /**
     * Returns the link that will invoke this node's check toggle
     * @return {string} returns the link required to adjust the checkbox state
     */
    getCheckLink: function() { 
        return "YAHOO.widget.TreeView.getNode(\'" + this.tree.id + "\'," + 
            this.index + ").checkClick()";
    },

    /**
     * Invoked when the user clicks the check box
     */
    checkClick: function() { 
        this.logger.log("previous checkstate: " + this.checkState);
        if (this.checkState === 0) {
            this.check();
        } else {
            this.uncheck();
        }

        this.onCheckClick(this);
        this.tree.fireEvent("checkClick", this);
    },

    /**
     * Override to get the check click event
     */
    onCheckClick: function() {

      var l = YAHOO.mapTOC.component.service.layers;

      for (var i=0;i<l.length;i++) {
         var nm = YAHOO.mapTOC.service.layers[i].getName();
            if (this.data.lyr == nm) {
               l[i].setVisible(this.checked);
               YAHOO.mapTOC.scheduleRefresh();               
               return;
            }
      }




        this.logger.log("onCheckClick: " + this);
    },

    /**
     * Refresh the state of this node's parent, and cascade up.
     */
    updateParent: function() { 
        var p = this.parent;

        if (!p || !p.updateParent) {
            this.logger.log("Abort udpate parent: " + this.index);
            return;
        }

        var somethingChecked = false;
        var somethingNotChecked = false;

        for (var i=0;i< p.children.length;++i) {
            if (p.children[i].checked) {
                somethingChecked = true;
                // checkState will be 1 if the child node has unchecked children
                if (p.children[i].checkState == 1) {
                    somethingNotChecked = true;
                }
            } else {
                somethingNotChecked = true;
            }
        }

        if (somethingChecked) {
            p.setCheckState( (somethingNotChecked) ? 1 : 2 );
        } else {
            p.setCheckState(0);
        }

        p.updateCheckHtml();
        p.updateParent();
    },

    /**
     * If the node has been rendered, update the html to reflect the current
     * state of the node.
     */
    updateCheckHtml: function() { 
        if (this.parent && this.parent.childrenRendered) {
            this.getCheckEl().className = this.getCheckStyle();
        }
    },

    /**
     * Updates the state.  The checked property is true if the state is 1 or 2
     * 
     * @param the new check state
     */
    setCheckState: function(state) { 
        this.checkState = state;
        this.checked = (state > 0);
    },

    /**
     * Check this node
     */
    check: function() { 
        this.logger.log("check");
        this.setCheckState(2);
        for (var i=0; i<this.children.length; ++i) {
            this.children[i].check();
        }
        this.updateCheckHtml();
        this.updateParent();
    },

    /**
     * Uncheck this node
     */
    uncheck: function() { 
        this.setCheckState(0);
        for (var i=0; i<this.children.length; ++i) {
            this.children[i].uncheck();
        }
        this.updateCheckHtml();
        this.updateParent();
    },

    // Overrides YAHOO.widget.TextNode
    getNodeHtml: function() { 
        this.logger.log("Generating html");
        var sb = [];

        var getNode = 'YAHOO.widget.TreeView.getNode(\'' +
                        this.tree.id + '\',' + this.index + ')';


        sb[sb.length] = '<table border="0" cellpadding="0" cellspacing="0">';
        sb[sb.length] = '<tr>';
        
        for (var i=0;i<this.depth;++i) {
            //sb[sb.length] = '<td class="' + this.getDepthStyle(i) + '"> </td>';
            sb[sb.length] = '<td class="' + this.getDepthStyle(i) + '"><div class="ygtvspacer"></div></td>';
        }

        sb[sb.length] = '<td';
        sb[sb.length] = ' id="' + this.getToggleElId() + '"';
        sb[sb.length] = ' class="' + this.getStyle() + '"';
        if (this.hasChildren(true)) {
            sb[sb.length] = ' onmouseover="this.className=';
            sb[sb.length] = 'YAHOO.widget.TreeView.getNode(\'';
            sb[sb.length] = this.tree.id + '\',' + this.index +  ').getHoverStyle()"';
            sb[sb.length] = ' onmouseout="this.className=';
            sb[sb.length] = 'YAHOO.widget.TreeView.getNode(\'';
            sb[sb.length] = this.tree.id + '\',' + this.index +  ').getStyle()"';
        } 
        sb[sb.length] = ' onclick="javascript:' + this.getToggleLink() + '"> ';
        //sb[sb.length] = '</td>';
        sb[sb.length] = '<div class="ygtvspacer"></div></td>';

        // check box
        sb[sb.length] = '<td';
        sb[sb.length] = ' id="' + this.getCheckElId() + '"';
        sb[sb.length] = ' class="' + this.getCheckStyle() + '"';
        sb[sb.length] = ' onclick="javascript:' + this.getCheckLink() + '">';
        //sb[sb.length] = ' </td>';
        sb[sb.length] = '<div class="ygtvspacer"></div></td>';

	if (this.searchLayer) {
	sb[sb.length] = '<td onclick="javascript:searchLayer(\''+this.searchLayer+'\')"><img src="./img/select.png"/></td>';
	}


        sb[sb.length] = '<td>';
        
         sb[sb.length] = '<a';
        sb[sb.length] = ' id="' + this.labelElId + '"';
        sb[sb.length] = ' class="' + this.labelStyle + '"';
        sb[sb.length] = ' href="' + this.href + '"';
        sb[sb.length] = ' target="' + this.target + '"';
        sb[sb.length] = ' onclick="return ' + getNode + '.onLabelClick(' + getNode +')"';
        if (this.hasChildren(true)) {
            sb[sb.length] = ' onmouseover="document.getElementById(\'';
            sb[sb.length] = this.getToggleElId() + '\').className=';
            sb[sb.length] = 'YAHOO.widget.TreeView.getNode(\'';
            sb[sb.length] = this.tree.id + '\',' + this.index +  ').getHoverStyle()"';
            sb[sb.length] = ' onmouseout="document.getElementById(\'';
            sb[sb.length] = this.getToggleElId() + '\').className=';
            sb[sb.length] = 'YAHOO.widget.TreeView.getNode(\'';
            sb[sb.length] = this.tree.id + '\',' + this.index +  ').getStyle()"';
        }
        sb[sb.length] = ' nowrap="nowrap" ';//(this.nowrap) ? ' nowrap="nowrap" ' : '';
        sb[sb.length] = ' >';
        sb[sb.length] = this.label;
        sb[sb.length] = '</a>';
        sb[sb.length] = '</td>';
        sb[sb.length] = '</tr>';
        sb[sb.length] = '</table>';

        return sb.join("");

    },

    toString: function() {
        return "TOCNode (" + this.index + ") " + this.label;
    }

});

YAHOO.namespace("mapTOC");
YAHOO.namespace("mapResources");

YAHOO.mapTOC.tree = new YAHOO.widget.TreeView("toc_tree");

YAHOO.mapTOC.generateListener = function (layers) {
   var l = layers;

   return function() {
       for (var i=0;i<YAHOO.mapTOC.service.layers.length;i++) {
         if (l.length) {
            if (l.indexOf(YAHOO.mapTOC.service.layers[i].getId()) > -1) {
               YAHOO.mapTOC.service.layers[i].setVisible(this.checked);
            }
         } else {
            if (YAHOO.mapTOC.service.layers[i].getId()==l) {
               YAHOO.mapTOC.service.layers[i].setVisible(this.checked);
            }
         }
      }
      YAHOO.mapTOC.scheduleRefresh();
   };
}; 

YAHOO.mapTOC.refreshInterval = null;

YAHOO.mapTOC.scheduleRefresh = function() {
   if (YAHOO.mapTOC.refreshInterval) {
      clearTimeout(YAHOO.mapTOC.refreshInterval);
   };

   YAHOO.mapTOC.refreshInterval = setTimeout(function() { YAHOO.mapComponent.refreshImage() ; }, 1000);
};
YAHOO.mapTOC.service = null;

function createNode(parentNode,layer,expanded,searchLayer) {
   return new YAHOO.widget.TOCNode('nd'+layer,{label:resMan.get("layer_"+layer),lyr:layer}, parentNode, false,expanded,searchLayer);
};


YAHOO.mapTOC.refresh = function() {

   var root = YAHOO.mapTOC.tree.getRoot();

   var nautCharts = createNode(root,"nauticalCharts",true,'xee');
   var nca = createNode(nautCharts,"XEE_GENERAL",false);
   var ncb = createNode(nautCharts,"XEE_500",false);
   var ncc = createNode(nautCharts,"XEE_300_250",false);
   var ncd = createNode(nautCharts,"XEE_150_100",false);
   var nce = createNode(nautCharts,"XEE_95_50",false);
   var ncf = createNode(nautCharts,"XEE_45_2",false);

   var encs = createNode(root,"encs",true);

   var covg = new YAHOO.widget.TOCNode('enc_cv','Coverage area',encs,false,false);

   var encf = new YAHOO.widget.TOCNode('enc_overview','Overview',encs,false,false);
   var ence = new YAHOO.widget.TOCNode('enc_general','General', encs,false,false);
   var encd = new YAHOO.widget.TOCNode('enc_coastal','Coastal', encs,false,false);
   var encc = new YAHOO.widget.TOCNode('enc_approach','Approach', encs, false,false);
   var enca = new YAHOO.widget.TOCNode('enc_berthing','Berthing', encs, false,false);
   var encb = new YAHOO.widget.TOCNode('enc_harbour','Harbour', encs, false,false);

var isCV = false;
YAHOO.mapTOC.tree.subscribe("checkClick",function (node) {
	//console.debug('click');
	//console.debug(node.id);
	var id = node.id;
	var parts = id.split('_');
	if (parts[0]=="enc")  {
		if (parts[1]=="cv") {
			isCV = node.checked;
			for (var i=0;i<YAHOO.mapTOC.service.layers.length;i++) {
				var lr = YAHOO.mapTOC.service.layers[i];
				if (lr.getName() == "enc_general" || lr.getName() == "enc_coastal" ||  lr.getName() == "enc_approach" )
					{
						if (lr.isVisible()){
							lr.setVisible(false);
							YAHOO.mapTOC.service.getLayerByName(lr.getName()+"_intersect").setVisible(node.checked);
						} else if (YAHOO.mapTOC.service.getLayerByName(lr.getName()+"_intersect").isVisible()) {
							YAHOO.mapTOC.service.getLayerByName(lr.getName()+"_intersect").setVisible(false);
							lr.setVisible(true);
						}
					}

				//console.debug(lr.getName());
			}
			YAHOO.mapTOC.scheduleRefresh();
		} else {

      		var l = YAHOO.mapTOC.component.service.layers;

 		     for (var i=0;i<l.length;i++) {
       		  var nm = YAHOO.mapTOC.service.layers[i].getName();
			 	    if (node.id == nm) {
					if (isCV){
						YAHOO.mapTOC.service.getLayerByName(l[i].getName()+"_intersect").setVisible(node.checked);
					} else {
						l[i].setVisible(node.checked);
					}
			        YAHOO.mapTOC.scheduleRefresh();               
     		          return;
     		       }
      		}

		}
	}
//}

});


/*   var topoGrams = new YAHOO.widget.TOCNode('grpTopo','ÂáèõìåôñéêÜ êáé ÔïðïãñáöéêÜ ÄéáãñÜììáôá', root, false,false);

   var topoGramsa = new YAHOO.widget.TOCNode('1','ÁðëÞò ÄÝóìçò', topoGrams, false,false);
   var topoGramsb = new YAHOO.widget.TOCNode('1','ÐïëëáðëÞò ÄÝóìçò', topoGrams, false,false);
   var topoGramsc = new YAHOO.widget.TOCNode('1','ÔïðïãñáöéêÜ ÄéáãñÜììáôá', topoGrams, false,false);

   var ocData = new YAHOO.widget.TOCNode('ocData','ÙêåáíïãñáöéêÜ ÄåäïìÝíá', root, false,false);

   var ocDataa = new YAHOO.widget.TOCNode('1','ÌåôñÞóåéò ÁíÝìïõ', ocData, false,false);
   var ocDatab = new YAHOO.widget.TOCNode('1','ÓôÜèìç ÈÜëáóóáò', ocData, false,false);
   var ocDatac = new YAHOO.widget.TOCNode('1','Óôïé÷åßá Êõìáôéóìïý', ocData, false,false);
   var ocDatad = new YAHOO.widget.TOCNode('1','ÈáëÜóóéá Ñåýìáôá', ocData, false,false);
   var ocDatae = new YAHOO.widget.TOCNode('1','ÃåùëïãéêÜ Óôïé÷åßá Âõèïý', ocData, false,false);
   var ocDataf = new YAHOO.widget.TOCNode('1','×çìéêÝò Áíáëýóåéò íåñïý', ocData, false,false);
*/
   YAHOO.mapTOC.tree.draw();
};


/////////////////////////////////////////////////
//
// IMS Service Facade
//
// Implements and provides methods to easily handle
// IMS requests and responses.
//
// Author: Tasos Vogiatzoglou
//
/////////////////////////////////////////////////

YAHOO.namespace("mapService");

var NOOP = function(){};

YAHOO.mapService.ImsService = function(serviceName,featureService) {

   /////////////////////////////////////////////////
   //
   //    Constants
   //
   /////////////////////////////////////////////////

   var _requestHeader = '<?xml version="1.0" encoding="UTF-8"?>\n';
   _requestHeader += '<ARCXML version="1.1">\n<REQUEST>\n';

   var _requestFooter = '\n</REQUEST>\n</ARCXML>'; 
   var _urlPrefix = "/servlet/com.esri.esrimap.Esrimap?ClientVersion=4.0&Form=False&Encode=True";

   /////////////////////////////////////////////////
   //
   //    Private Variables
   //
   /////////////////////////////////////////////////
   
   this.layers = [];
   this.initialExtent = null;
   var currentEnvelope = null;
   this.dynamicLayers = [];
   this.mapUnits = "meters";
   var serviceName = serviceName;
   var featureService = featureService;
   
   var host = window.location.hostname;
   
   var port = 80;
   var _url = "http://"+ host + _urlPrefix + "&ServiceName=";


   /////////////////////////////////////////////////
   //
   //    Communication Infrastructure
   //
   /////////////////////////////////////////////////

   /**
    * Sends a request to the IMS service
    *
    * @param xml The xml request to send to the IMS Service 
    * @param cb  The callbacks that will be invoked by the ASYNCHRONOUS method call
    *
    */
    this.sendRequest = function (xml,cb,service) {

         (cb.onStart?cb.onStart:NOOP)();
         var callback = {
            success: function(res){
               var oDomDoc = Sarissa.getDomDocument();
               var xmlString = res.responseText;
               //ims returns some strang non-valid xml. We strip the # with __
               xmlString = xmlString.replace(/#/g,'__');
               oDomDoc = (new DOMParser()).parseFromString(xmlString, "text/xml");

               var erNode = oDomDoc.selectSingleNode("//ERROR");

               if (erNode) {
                  alert(erNode.firstChild.nodeValue);
                  (cb.onFailure?cb.onFailure:NOOP)();
                  return;
               };

               (cb.onSuccess?cb.onSuccess:NOOP).call(this,oDomDoc);
               (cb.onEnd?cb.onEnd:NOOP)();

            }, 
            failure: function(res) {
               (cb.onFailure?cb.onFailure:NOOP)(res);
               (cb.onEnd?cb.onEnd:NOOP)();
            },
            scope: this
         };

         var req = _requestHeader + xml + _requestFooter;
         var cObj = YAHOO.util.Connect.asyncRequest('POST', _url+(service?service:serviceName), callback,req); 
   };



   /////////////////////////////////////////////////
   //
   // Service public methods
   //
   /////////////////////////////////////////////////

   this.getLayerId = function(name) {
      var ln = this.layers.length;
      for (var i=0;i<ln;i++) {
         if (this.layers[i].getName() == name){
            return this.layers[i].getId();
         }
      }   
     
      return null;
   };

   /**
      Begins an asynchronous call to get an image of the specified dimensions
      and envelope.

      @param width The image width
      @param height The image height
      @param envelope The envelope of the visible map
      @param reaspect Whether we want to reaspect the image (e.g. in case of resize)
   **/
   this.getImageWithEnvelope = function(width,height,envelope,reaspect,cback) {
      var getImgXml = '<GET_IMAGE><PROPERTIES>';
      getImgXml += ' <FEATURECOORDSYS id="4326" /><FILTERCOORDSYS id="4326"  />';
      getImgXml += '<LAYERLIST>';

      for (var i=0;i<this.layers.length;i++) {
         getImgXml += '<LAYERDEF id="'+this.layers[i].getId()+'" visible="'+this.layers[i].isVisible()+'"/>';
      }
      getImgXml += '</LAYERLIST>';
      getImgXml += '<IMAGESIZE width="'+width+'" height="'+height+'" />';
      
      //if (project) {
      // var env2 = envelope.to_geographic_coords();
      // getImgXml += env2.toAXL();
      //} else { 
      // getImgXml += envelope.to_geographic_coords().toAXL();
      getImgXml += envelope.toAXL();
      //}

      getImgXml += '</PROPERTIES>';

      for ( a in this.dynamicLayers ) {
         getImgXml += this.dynamicLayers[a];
      }

      getImgXml += '</GET_IMAGE>';

      var cb = { onSuccess: function(o) {
                              var layerNfo = o.selectSingleNode("/ARCXML/RESPONSE/IMAGE");
   
                              if (layerNfo!=null) {
                                 var img= layerNfo.selectSingleNode('./OUTPUT').attributes[0].value;
 
                                 var env = new Envelope(-1,-1,-1,-1);
                                 env.fromAXL(layerNfo.selectSingleNode('./ENVELOPE'),this.mapUnits);

                                 this.refreshTree();

   
                                 (cback?cback:NOOP)(img,env); 
                              }
                           },
                scope: this
               };


      this.sendRequest(getImgXml,cb);
   };

   /**
      Begins an asynchronous call to execute a query against the specified layer. The
      query is expressed as an AXL fragment.

      @param layerId The layer the query will be run against
      @param expression The AXL fragment describing the query
      @param featureLimit The maximum returned features 
      @param beginRecord The record to begin with
   **/
   this.queryFeatures = function(query,featureLimit,beginRecord,cback,target) {

      var target = target;

      var beginRecord = (beginRecord)?beginRecord:0;

      var getFtXml = '<GET_FEATURES geometry="false" outputmode="xml" envelope="true" compact="false" checkesc="true" ';
      getFtXml += ' ' + (featureLimit?' featurelimit="'+featureLimit+'" ':'') ;
      getFtXml += ' ' + (beginRecord?' beginrecord="'+beginRecord+'" ':'') ;
      getFtXml += '>';
      getFtXml += query;
      getFtXml += '</GET_FEATURES>';

      var cb = { onSuccess: function(o) {
                              var featuresNodeList = o.selectNodes("//FEATURE");
                              var queryInfoNode = o.selectSingleNode("//FEATURECOUNT");
  
                              var cnt = -1;
                              var hasmore = false;

                              if (queryInfoNode!=null) { 
                                 cnt = parseInt(queryInfoNode.attributes.getNamedItem('count').value);
                                 hasmore = (queryInfoNode.attributes.getNamedItem('hasmore').value == "true");
                              } else {
                                 cnt = featuresNode.childNodes.length;
                                 hasmore = false;
                              }

                              if (hasmore && cnt > 25) {
                                 //alert('Has more');
                              }
   
                              var recs = [];
                              
                              for (var i=0;i<cnt;i++) {
                                 var elem = featuresNodeList.item(i);
                                 var env = elem.selectSingleNode("./ENVELOPE");
                                 var fields = elem.selectSingleNode("./FIELDS");
                                 var rec = {};
                                 for (var ai=0;ai<fields.attributes.length;ai++) {
                                    rec[fields.attributes.item(ai).nodeName] = fields.attributes[ai].value;
                                 }
                                 rec["minx"] = env.attributes[0].value;
                                 rec["miny"] = env.attributes[1].value;
                                 rec["maxx"] = env.attributes[2].value;
                                 rec["maxy"] = env.attributes[3].value;
                                 recs.push(rec);
                              }
                                 window.status = ("Finished parsing");
                              
                              var res = {};
                              res.layer = target;
                              res.results = recs;
                              res.hasMore = hasmore;
                              
                              cback(recs,res);
                           }
               };

      this.sendRequest(getFtXml,cb,featureService);
   };

   /**
      Initializes this service with the ArcIms service specified.

      @param serviceName The arcIms service to initialize
   **/
   this.initService = function(callback) {
	
      var cb = { onSuccess: function(o){ 
                              if (o.selectSingleNode("//ERROR")) {
                              }

                              if (o.selectSingleNode("//MAPUNITS")) {
                                this.mapUnits = o.selectSingleNode('//MAPUNITS').attributes.getNamedItem("units").value;
                              } else {
                                this.mapUnits = "meters";
                              }
                              

                              var sinfo = o.selectSingleNode('//PROPERTIES');

				//alert(sinfo);
   
                              var env = sinfo.selectSingleNode('./ENVELOPE');
                              var envel = new Envelope();
                              envel.fromAXL(env,this.mapUnits);

                              this.initialExtent = envel;

                              var layerNdl = o.selectNodes("//LAYERINFO");
                              for (var l=0;l<layerNdl.length;l++) {
                                 var layer = layerNdl.item(l);

                                 var minScaleAttr = layer.attributes.getNamedItem("minscale");
                                 var maxScaleAttr = layer.attributes.getNamedItem("maxscale");

                                 var ldef = new LayerDefinition(
                                    layer.attributes.getNamedItem("id").value,
                                    layer.attributes.getNamedItem("name").value,
                                    layer.attributes.getNamedItem("type").value,
                                    layer.attributes.getNamedItem("visible").value=="true",
                                    (minScaleAttr?minScaleAttr.value:null),
                                    (maxScaleAttr?maxScaleAttr.value:null)
                                 );
      
                                 this.layers.push(ldef);
                              }

                              (callback?callback:NOOP)(envel);
                        }
               };

      var xml = '<GET_SERVICE_INFO envelope="false" fields="true" renderer="false" extensions="false"/>';
      this.sendRequest(xml,cb);
   };

   this.getLayerByName = function(name) {
      for (var i=0;i<this.layers.length;i++) {
        if (name==this.layers[i].getName()) {
            return this.layers[i];
         } 
      }
      return null;      
   };

   this.refreshTree = function(tree) {

      if (!tree) {
         tree = YAHOO.mapTOC.tree;
      }

      if (tree) {
         for (var i=0;i<this.layers.length;i++){
            var nd = tree.getNodeByProperty('lyr',this.layers[i].getName());
            if (nd) {
               var scl = YAHOO.mapComponent.getScale();
               var lr =this.layers[i]; 
               if (lr.isVisible() && 

                     (
                        ( ( lr.getMinScale() < scl) && (lr.getMaxScale() > scl) ) ||
                        (lr.getMinScale()==null && lr.getMaxScale()==null)
                     ) 
                  ) {
                  if (!nd.hasChildren(true)) {
                     nd.check();
                  }
               }
            }
         }
      }
   }


};


/////////////////////////////////////////////////
//
// Map component implementing presentation and event
// handling of map images.
//
// Author: Tasos Vogiatzoglou
//
/////////////////////////////////////////////////

YAHOO.namespace("mapComponent");
 
///////////////////////////////////////////////////
//
// Constants and internal variables
//
/////////////////////////////////////////////////

YAHOO.mapComponent.image = new YAHOO.util.Element('map_image');
YAHOO.mapComponent.currentTool = "none";
YAHOO.mapComponent.service = null;
YAHOO.mapComponent._downPoint = null;
YAHOO.mapComponent._layoutTimeout = null;
YAHOO.mapComponent._downTime = null;
YAHOO.mapComponent._cancelClick = false;
YAHOO.mapComponent.wayPoints = [];
YAHOO.mapComponent.movingWaypoint = null;

/////////////////////////////////////////////////
//
// Helper functions
//
/////////////////////////////////////////////////

/**
   Returns the point of an event relative to the map image 

   @param evt A browser event object
*/
YAHOO.mapComponent.getEventPoint = function (evt){
   var pnt = null;

   var xy = YAHOO.util.Event.getXY(evt);
   var ofxy = YAHOO.util.Dom.getRegion('map_image_container');
   
   pnt = new Point(xy[0]-ofxy['left'],xy[1]-ofxy['top']);
  
   return pnt;
};

/**
   Layouts the mapComponent elements
**/
YAHOO.mapComponent.doLayout = function () {

   var a = Math.round(YAHOO.util.Dom.getViewportHeight()*0.7);
   var b = Math.round(YAHOO.util.Dom.getViewportHeight()*0.28);
   var c = Math.round(YAHOO.util.Dom.getViewportHeight()*0.5);
   var d = Math.round(YAHOO.util.Dom.getViewportHeight()*0.5);

   $('map_container').style.height = (a-50) + 'px';

   $('dataTable').style.height = b + "px";
   $('featuresGrid').style.height = b + "px";

   YAHOO.util.Dom.setXY('wptBox',YAHOO.util.Dom.getXY('map_image_container'));

   $('wptBox').style.width = YAHOO.mapComponent.getWidth();
   $('wptBox').style.height = YAHOO.mapComponent.getHeight();

   $('toc_container').style.height = (c-16 + 50) + 'px';
   $('toc_tree_container').style.height = (c - 43 + 50) + 'px';
   YAHOO.mapComponent._layoutTimeout=null;

   YAHOO.mapComponent.redrawWaypoints(true);
   
   if (YAHOO.mapComponent.getWidth()<500) {
      $('navigateTo').style.display = "none";
   } else {
      $('navigateTo').style.display = "block";
   }
};



/////////////////////////////////////////////////
//
//   Event handlers for the event box.
//
/////////////////////////////////////////////////

/**
   Handler for the mouseup event
**/
YAHOO.mapComponent.onMapMouseUp = function (evt) {
      if (YAHOO.mapTools.tools[YAHOO.mapComponent.currentTool]) {
	      YAHOO.mapTools.tools[YAHOO.mapComponent.currentTool].mouseUp(YAHOO.mapComponent,YAHOO.mapComponent.getEventPoint(evt));
	      YAHOO.mapTools.downPoint=null;
	      if (YAHOO.mapTools.tools[YAHOO.mapComponent.currentTool].stopEvent) {
		      YAHOO.util.Event.stopEvent(evt);
	      }
      }
};

/**
   Handler for the mousedown event
**/
YAHOO.mapComponent.onMapMouseDown = function (evt) {
      if (YAHOO.mapTools.tools[YAHOO.mapComponent.currentTool]) {
	      YAHOO.mapTools.tools[YAHOO.mapComponent.currentTool].mouseDown(YAHOO.mapComponent,YAHOO.mapComponent.getEventPoint(evt));
	      if (YAHOO.mapTools.tools[YAHOO.mapComponent.currentTool].stopEvent) {
		      YAHOO.util.Event.stopEvent(evt);
	      }
      }

   return true; 
};

/**
   Handler for the mouse move event
**/
YAHOO.mapComponent.onMapMouseMove = function (evt) {

      window.status = YAHOO.mapComponent.toMapCoords(evt).toString();

      if (YAHOO.mapTools.tools[YAHOO.mapComponent.currentTool]) {
	      YAHOO.mapTools.tools[YAHOO.mapComponent.currentTool].mouseMove(YAHOO.mapComponent,YAHOO.mapComponent.getEventPoint(evt));
	      if (YAHOO.mapTools.tools[YAHOO.mapComponent.currentTool].stopEvent) {
		      YAHOO.util.Event.stopEvent(evt);
	      }
      }

   return false;
};

var ISLANDS = null;

function clearIslandBoxes() {
    if (ISLANDS!= null && ISLANDS.length > 0) {
        for (var i=0;i<ISLANDS.length;i++) {
            try {
                YAHOO.mapComponent._container.removeChild($(ISLANDS[i].ISL84_ID));
            } catch (e) {}
        }
    }

    ISLANDS = null;
};

function showIslandName(e,obj) {

       YAHOO.util.Dom.setStyle('islandName','display','block');
         YAHOO.util.Dom.setStyle('islandName','position','absolute');
         w = YAHOO.util.Dom.getRegion('islandName')["right"]-YAHOO.util.Dom.getRegion('islandName')["left"];
         h = YAHOO.util.Dom.getRegion('islandName')["bottom"]-YAHOO.util.Dom.getRegion('islandName')["top"];


         YAHOO.util.Dom.setX('islandName',obj.x-5);

         YAHOO.util.Dom.setY('islandName',obj.y-5);

        $('islandName').innerHTML = obj.text;

}

function hideIslandName() {
       YAHOO.util.Dom.setStyle('islandName','display','none');
}

function createIslandBox(island,i) {
   var evtx = YAHOO.util.Dom.getX(YAHOO.mapComponent._container);
   var evty = YAHOO.util.Dom.getY(YAHOO.mapComponent._container);

   var minPoint = new Point(island.minx,island.miny);
   var maxPoint = new Point(island.maxx,island.maxy);

   var iMinPoint = minPoint.convertToImageCoords(YAHOO.mapComponent.currentEnvelope);
   var iMaxPoint = maxPoint.convertToImageCoords(YAHOO.mapComponent.currentEnvelope);

   var width = Math.abs(iMinPoint.getX()-iMaxPoint.getX());
   var height = Math.abs(iMinPoint.getY()-iMaxPoint.getY());

   var elem = new YAHOO.util.Element(document.createElement('div'),{id:island.ISL84_ID});
   elem.setStyle('width',width+"px");
   elem.setStyle('height',height+"px");


    var arVersion = navigator.appVersion.split("MSIE");
   var version = parseFloat(arVersion[1]);
   
   if ((version >= 5.5)) {
      var imgElem = new YAHOO.util.Element(document.createElement('img'),{src:'img/blank.gif',id:island.ISL84_ID+"_img"});
      imgElem.appendTo(elem);
      elem.setStyle('background','url(img/blank.gif)');
   } else {
      var imgElem = new YAHOO.util.Element(document.createElement('img'),{src:'img/blank.gif',id:island.ISL84_ID+"_img"});
      imgElem.appendTo(elem);
   }

   
 /*  if ((version >= 5.5) && (document.body.filters)) {
          elem.addListener('mouseover',function(e,arg) {
       // console.debug("in " + arg);
       showIslandName(e,arg);
        },{
            'text':lang=="el"?island.DISPLAYGR:island.DISPLAYEN,
            'x':iMinPoint.getX()+evtx,
            'y':iMinPoint.getY()-height+evty-5
          }
   );

      elem.addListener('mouseleave',function(e,arg) {
//        console.debug("out " + arg);
        hideIslandName();        
        });
   } else {

   elem.addListener('mouseover',function(e,arg) {
       // console.debug("in " + arg);
       showIslandName(e,arg);
        },{
            'text':lang=="el"?island.DISPLAYGR:island.DISPLAYEN,
            'x':iMinPoint.getX()+evtx,
            'y':iMinPoint.getY()-height+evty-5
          }
   );

      elem.addListener('mouseout',function(e,arg) {
//        console.debug("out " + arg);
        hideIslandName();        
        });
   }
   */

   elem.appendTo(
                  YAHOO.mapComponent._container,
                  YAHOO.util.Dom.getFirstChild(YAHOO.mapComponent._container)
                );


 

   elem.addClass('wptImg');

   var arVersion = navigator.appVersion.split("MSIE");
   var version = parseFloat(arVersion[1]);
   
   YAHOO.util.Dom.setX($(island.ISL84_ID),iMinPoint.getX()+evtx);
   YAHOO.util.Dom.setY($(island.ISL84_ID),iMinPoint.getY()-height+evty);
}

function createIslandBoxes() {

    $('wptBox').innerHTML = '';

    for (var i=0;i<ISLANDS.length;i++) {
        var pnt = new Point(ISLANDS[i].minx,ISLANDS[i].miny);
        var pnt2 = new Point(ISLANDS[i].minx,ISLANDS[i].miny);


         if (!pnt.isOutside(YAHOO.mapComponent.currentEnvelope)
                 &&
             !pnt2.isOutside(YAHOO.mapComponent.currentEnvelope)
                 ) {
            createIslandBox(ISLANDS[i],i);
        }
    }


     for (var i=0;i<ISLANDS.length;i++) {
        var pnt = new Point(ISLANDS[i].minx,ISLANDS[i].miny);
         if (!pnt.isOutside(YAHOO.mapComponent.currentEnvelope)) {
            var island = ISLANDS[i];
             new YAHOO.widget.Tooltip(island.ISL84_ID+"_tooltip", { 
      context:island.ISL84_ID, 
      text:lang=="el"?island.DISPLAYGR:island.DISPLAYEN,
      showDelay:20 } );

        }
    }

     


};

function loadIslands(env) {

             clearIslandBoxes();


     var qry = '<SPATIALQUERY subfields="#ALL#"><SPATIALFILTER relation="area_intersection">';
      qry += env.toAXL();
      qry += '</SPATIALFILTER></SPATIALQUERY>';

     YAHOO.mapComponent.service.queryFeatures("<LAYER id='40'/>"+qry,null,0, function(recs,res) {
             ISLANDS = [];

             if (res.results.length < 100) {
               for (var i=0;i<res.results.length;i++) {
                    if (res.results[i].ISL84_ID != 0) {
                        ISLANDS.push(res.results[i]);
                    }
                }
             }

             ISLANDS.sort(function (a,b) { return a.Shape_Area < b.Shape_Area ? -1 : ( a.Shape_Area > b.Shape_Area ? 1 : 0); });

             createIslandBoxes();

             },40);
};


/**
   Handler for the click event
**/
YAHOO.mapComponent.onMapClick = function (evt) {
   if (YAHOO.mapComponent._cancelClick) {
      YAHOO.mapComponent._cancelClick = false;
      return false;
   }

   var mapPnt = YAHOO.mapComponent.getEventPoint(evt).convertToMapCoords(YAHOO.mapComponent.currentEnvelope);
   if (YAHOO.mapComponent.currentTool == "zoomout") {
      YAHOO.mapComponent.setLoading("Zooming out...");
      YAHOO.mapComponent.changeExtent(YAHOO.mapComponent.currentEnvelope.zoomByFactor(-2));
      loadIslands(YAHOO.mapComponent.currentEnvelope.zoomByFactor(-2));
   } else if (YAHOO.mapComponent.currentTool == "zoomin") {
      YAHOO.mapComponent.setLoading("Zooming in...");
      YAHOO.mapComponent.changeExtent(YAHOO.mapComponent.currentEnvelope.centerToPoint(mapPnt).zoomByFactor(4));
      loadIslands(YAHOO.mapComponent.currentEnvelope.centerToPoint(mapPnt).zoomByFactor(4));
   } else if (YAHOO.mapComponent.currentTool == "identify") {
      queryByPoint(mapPnt);
   } 

   return true;
};

/**
   Handler for the mousedown event
**/
YAHOO.mapComponent.onMapMouseDown = function (evt) {
   var id_toks = YAHOO.util.Event.getTarget(evt).id.split('_');
   if (id_toks[0]=='waypoint') {
      if (YAHOO.mapComponent.currentTool == 'waypoints_delete') {
         var idx = -1;
         var len = YAHOO.mapComponent.wayPoints.length;
         for (var i=0; i<len;i++) {
            if (YAHOO.mapComponent.wayPoints[i].getId()==id_toks[0]+"_"+id_toks[1]) {
               idx = i;
               break;
            }
         }
         var pnt = YAHOO.mapComponent.wayPoints[idx];
         $('map_image_container').removeChild($(pnt.getId()));
         YAHOO.mapComponent.wayPoints = YAHOO.mapComponent.wayPoints.slice(0,idx).concat(
            YAHOO.mapComponent.wayPoints.slice(idx+1));
         YAHOO.mapComponent.redrawWaypoints();
         YAHOO.util.Event.stopEvent(evt);
         return false;
      } else if (YAHOO.mapComponent.currentTool == 'waypoints_move') {
         var idx = -1;
         var len = YAHOO.mapComponent.wayPoints.length;
         for (var i=0; i<len;i++) {
            if (YAHOO.mapComponent.wayPoints[i].getId()==id_toks[0]+"_"+id_toks[1]) {
               idx = i;
               break;
            }
         }
         YAHOO.mapComponent.movingWaypoint = idx;
         YAHOO.mapComponent._downPoint = YAHOO.mapComponent.getEventPoint(evt);
         YAHOO.util.Event.stopEvent(evt);
         return false;
      }
   }
   

   var pnt = YAHOO.mapComponent.getEventPoint(evt);   
   YAHOO.mapComponent._downPoint = pnt;
   var d = new Date();
   YAHOO.mapComponent._downTime = d.getTime();

   if (YAHOO.mapComponent.currentTool == "zoomin" || YAHOO.mapComponent.currentTool == 'select_by_rectangle') {
      YAHOO.mapComponent._selRect.style.visibility='visible';
      YAHOO.util.Dom.setStyle(YAHOO.mapComponent._selRect,'width','0px');
      YAHOO.util.Dom.setStyle(YAHOO.mapComponent._selRect,'height','0px');
      YAHOO.util.Event.stopEvent(evt);
   } else 
   if (YAHOO.mapComponent.currentTool == "waypoints_add") {
      var mapPnt = YAHOO.mapComponent.getEventPoint(evt).convertToMapCoords(YAHOO.mapComponent.currentEnvelope);
      
      var wPnt = new Point(mapPnt.getX(),mapPnt.getY());
      wPnt.setId("waypoint_"+YAHOO.util.Dom.generateId());
      YAHOO.mapComponent.wayPoints.push(wPnt);
      YAHOO.mapComponent.drawWaypoint(wPnt);
      YAHOO.util.Event.stopEvent(evt);
   } else 
   if (YAHOO.mapComponent.currentTool == "pan") {
      clearIslandBoxes();
      YAHOO.mapComponent.hideWaypoints();
      YAHOO.util.Event.stopEvent(evt);
   } 

   return true; 
};

/**
   Handler for the mouseup event
**/
YAHOO.mapComponent.onMapMouseUp = function (evt) {
   var d = new Date();
   var dt = d.getTime() - YAHOO.mapComponent._downTime;

   if (dt>300 && YAHOO.mapComponent._downPoint!=null) {
      YAHOO.mapComponent._cancelClick = true;
      
      var dn = YAHOO.mapComponent._downPoint;
      var up = YAHOO.mapComponent.getEventPoint(evt);

      var dx = up.getX()-dn.getX();
      var dy = up.getY()-dn.getY();     

      var x = YAHOO.util.Dom.getX('map_image_container');
      var y = YAHOO.util.Dom.getY('map_image_container');

      var pMin = null;
      var pMax = null;


      if (YAHOO.mapComponent.currentTool == "zoomin") {

         if ( dx>0 && dy >0 ) {
            pMin = new Point(dn.getX(),dn.getY());
            pMax = new Point(up.getX(),up.getY());
         } else 
         if ( dx>0 && dy < 0) {
            pMin = new Point(dn.getX(),dn.getY());
            pMax = new Point(dn.getX()+Math.abs(dx),dn.getY()-Math.abs(dy));
         } else
         if ( dx<0 && dy < 0) {
            pMin = new Point(up.getX(),up.getY());
            pMax = new Point(dn.getX(),dn.getY());
         } else 
         if (dx <0 && dy > 0){
            pMin = new Point(dn.getX()-Math.abs(dx),dn.getY());
            pMax = new Point(dn.getX(),dn.getY()+Math.abs(dy));
         }

         var xd = YAHOO.mapComponent.currentEnvelope.getXDistance();
         var yd = YAHOO.mapComponent.currentEnvelope.getYDistance();

         var rat = xd/yd;

         var env = new Envelope(pMin.convertToMapCoords(YAHOO.mapComponent.currentEnvelope),
                                pMax.convertToMapCoords(YAHOO.mapComponent.currentEnvelope));

         YAHOO.mapComponent.changeExtent(env);
      } else if (YAHOO.mapComponent.currentTool == "pan") {
         var x = YAHOO.mapComponent.getWidth()/2 - dx;
         var y = YAHOO.mapComponent.getHeight()/2 - dy;
         var pnt = new Point(x*1,y*1);
         

         var mapPnt = pnt.convertToMapCoords(YAHOO.mapComponent.currentEnvelope);

         YAHOO.mapComponent.setLoading(resMan.get('lblLoadingImage'));
         var env = YAHOO.mapComponent.currentEnvelope.centerToPoint(mapPnt);
         YAHOO.mapComponent.changeExtent(env);
      } 
      else if (YAHOO.mapComponent.currentTool == "select_by_rectangle") {
         if ( dx>0 && dy >0 ) {
            pMin = new Point(dn.getX(),dn.getY());
            pMax = new Point(up.getX(),up.getY());
         } else 
         if ( dx>0 && dy < 0) {
            pMin = new Point(dn.getX(),dn.getY());
            pMax = new Point(dn.getX()+Math.abs(dx),dn.getY()-Math.abs(dy));
         } else
         if ( dx<0 && dy < 0) {
            pMin = new Point(up.getX(),up.getY());
            pMax = new Point(dn.getX(),dn.getY());
         } else 
         if (dx <0 && dy > 0){
            pMin = new Point(dn.getX()-Math.abs(dx),dn.getY());
            pMax = new Point(dn.getX(),dn.getY()+Math.abs(dy));
         }

         var xd = YAHOO.mapComponent.currentEnvelope.getXDistance();
         var yd = YAHOO.mapComponent.currentEnvelope.getYDistance();

         var rat = xd/yd;

         var env = new Envelope(pMin.convertToMapCoords(YAHOO.mapComponent.currentEnvelope),
                                pMax.convertToMapCoords(YAHOO.mapComponent.currentEnvelope));

         
         queryByEnvelope(env);
      }
      else if (YAHOO.mapComponent.currentTool == "waypoints_move") {

         var pnt = YAHOO.mapComponent.wayPoints[YAHOO.mapComponent.movingWaypoint];
         var ppnt = up.convertToMapCoords(YAHOO.mapComponent.currentEnvelope);

         pnt.setX(ppnt.getX());
         pnt.setY(ppnt.getY());

         YAHOO.util.Dom.setX($(pnt.getId()),up.getX());
         YAHOO.util.Dom.setY($(pnt.getId()),up.getY());

         YAHOO.mapComponent.movingWaypoint = null;
         YAHOO.mapComponent.redrawWaypoints();
         YAHOO.util.Event.stopEvent(evt);
      }

   } else {
      YAHOO.mapComponent._cancelClick = false;
   }   

   YAHOO.util.Dom.setStyle(YAHOO.mapComponent._selRect,'visibility','hidden');
   YAHOO.mapComponent._downPoint = null;
   YAHOO.util.Event.stopEvent(evt);
};

/**
   Handler for the mouse move event
**/
YAHOO.mapComponent.onMapMouseMove = function (evt) {

   if (YAHOO.mapComponent.currentEnvelope) {
      
 hideIslandName();   
   var pnt = YAHOO.mapComponent.getEventPoint(evt);
   var ppnt = pnt.convertToMapCoords(YAHOO.mapComponent.currentEnvelope);

   var phi = carto.utils.degToRad(ppnt.getX());
   var lambda = carto.utils.degToRad(ppnt.getY());

   var phiDeg = parseInt((phi * 180) / Math.PI);
   var phiMin = parseInt(60 * ((( phi * 180) / Math.PI) - phiDeg ));
   var phiSec = parseFloat(3600 * (((phi * 180) / Math.PI) - phiDeg - (phiMin /60)));

   var lambdaDeg = parseInt((lambda * 180) / Math.PI);
   var lambdaMin = parseInt(60 * ((( lambda * 180) / Math.PI) - lambdaDeg ));
   var lambdaSec = parseFloat(3600 * (((lambda * 180) / Math.PI) - lambdaDeg - (lambdaMin/60)));

   window.status = "Lat="+phiDeg+"o" + " " +phiMin +"' " + Math.round(phiSec) +"'' Lon="+lambdaDeg+"o" + " " +lambdaMin +"' " + Math.round(lambdaSec) +"''";
   }

   if (YAHOO.mapComponent._downPoint==null) {
      return false;
   } 


   var dn = YAHOO.mapComponent._downPoint;
   var x = YAHOO.util.Dom.getX(YAHOO.mapComponent._container);
   var y = YAHOO.util.Dom.getY(YAHOO.mapComponent._container);
   var dx = pnt.getX()-dn.getX();
   var dy = pnt.getY()-dn.getY();

   if ( Math.abs(dx) > 10 && Math.abs(dy) > 10) {
      YAHOO.mapComponent._cancelClick = true;
   }
  
   if (YAHOO.mapComponent.currentTool == "zoomin"  || YAHOO.mapComponent.currentTool == 'select_by_rectangle' ) {
      var w = (Math.abs(dx)-1);
      var h = (Math.abs(dy)-1);

      YAHOO.util.Dom.setStyle(YAHOO.mapComponent._selRect,'width',w<0?0:w);
      YAHOO.util.Dom.setStyle(YAHOO.mapComponent._selRect,'height',h<0?0:h); 

      var xy = [];

      xy [0] = ( dn.getX() + x) - ( dx > 0 ? 0 : Math.abs(dx) ); 
      xy [1] = ( dn.getY() + y) - ( dy > 0 ? 0 : Math.abs(dy) ); 

      YAHOO.util.Dom.setXY(YAHOO.mapComponent._selRect,xy); 

   } 
   else if (YAHOO.mapComponent.currentTool == "pan") {
      YAHOO.util.Dom.setStyle($('map_image'),'margin-left',dx);
      YAHOO.util.Dom.setStyle($('map_image'),'margin-top',dy);
      YAHOO.util.Dom.setStyle($('map_image'),'width',YAHOO.mapComponent.getWidth());
   } 
   else if (YAHOO.mapComponent.currentTool == "waypoints_move") {
      var wpnt = YAHOO.mapComponent.wayPoints[YAHOO.mapComponent.movingWaypoint];
      var ppnt = pnt.convertToMapCoords(YAHOO.mapComponent.currentEnvelope);
      wpnt.setX(ppnt.getX());
      wpnt.setY(ppnt.getY());

      var elem = $(wpnt.getId());

      YAHOO.util.Dom.setX(elem,pnt.getX()+x-(16/2));
      YAHOO.util.Dom.setY(elem,pnt.getY()+y-(16/2));

      YAHOO.mapComponent.drawWaypointsLine();
      YAHOO.util.Event.stopEvent(evt);
      return false;
   }

   YAHOO.util.Event.stopEvent(evt);

   return false;
};

/////////////////////////////////////////////////
//
// Off image rendering (used for waypoints)
//
/////////////////////////////////////////////////

YAHOO.mapComponent.drawWaypointsLine = function() {

   var arVersion = navigator.appVersion.split("MSIE");
   var version = parseFloat(arVersion[1]);
   
   if ((version >= 5.5) && (document.body.filters)) {
      var vml = '<v:polyline points="';
      for (var i=0;i<YAHOO.mapComponent.wayPoints.length;i++) {
         var pnt = YAHOO.mapComponent.wayPoints[i].convertToImageCoords(YAHOO.mapComponent.currentEnvelope);
         vml += pnt.getX() + "," + pnt.getY() + ((i+1)<YAHOO.mapComponent.wayPoints.length?" ":"");
      }
      vml += '" stroked="true" filled="false" strokecolor="blue" o:connectortype="elbow" ';
      vml += ' style="position:absolute;left:0;top:0" strokeweight="2" ';
      vml += '/>';
      $('wptBox').innerHTML = vml;
   } else {
      var html = '<canvas id="canvas" style="float:left;position:absolute" ';
      html += ' width="'+YAHOO.mapComponent.getWidth()+'" height="'+YAHOO.mapComponent.getHeight()+'" ';
      html += '></canvas>';
      $('wptBox').innerHTML = html

      var cnv = $('canvas');

      YAHOO.util.Dom.setXY(cnv,YAHOO.util.Dom.getXY('map_image_container'));

      if (cnv.getContext){
         var ctx = cnv.getContext('2d');
         ctx.translate(0,0);        
         ctx.lineWidth = 3; 
         ctx.lineJoin = ['round'];
         ctx.strokeStyle = "rgba(0,0,255,1)";

         //ctx.beginPath();
         if (YAHOO.mapComponent.wayPoints.length>=2) {
            var pnt = YAHOO.mapComponent.wayPoints[0].convertToImageCoords(YAHOO.mapComponent.currentEnvelope);
            var pnt2 = YAHOO.mapComponent.wayPoints[1].convertToImageCoords(YAHOO.mapComponent.currentEnvelope);
            ctx.moveTo(pnt.getX(),pnt.getY());
            ctx.lineTo(pnt2.getX(),pnt2.getY());
         }
         for (var i=2;i<YAHOO.mapComponent.wayPoints.length;i++) {
            var pnt = YAHOO.mapComponent.wayPoints[i].convertToImageCoords(YAHOO.mapComponent.currentEnvelope);
            ctx.lineTo(pnt.getX(),pnt.getY());         
         }
         ctx.stroke();
      }
   }
   YAHOO.util.Dom.setStyle($('wptBox'),'visibility','visible');
};


YAHOO.mapComponent.drawWaypoint = function(waypoint) {
   var evtx = YAHOO.util.Dom.getX(YAHOO.mapComponent._container);
   var evty = YAHOO.util.Dom.getY(YAHOO.mapComponent._container);
   var ppnt = waypoint.convertToImageCoords(YAHOO.mapComponent.currentEnvelope);

   var elem = new YAHOO.util.Element(document.createElement('div'),{id:ppnt.getId()});

   elem.appendTo(
                  YAHOO.mapComponent._container,
                  YAHOO.util.Dom.getFirstChild(YAHOO.mapComponent._container)
                );

   elem.addClass('wptImg');

   var arVersion = navigator.appVersion.split("MSIE");
   var version = parseFloat(arVersion[1]);
   
   if ((version >= 5.5) && (version < 7) && (document.body.filters)) {
      var imgElem = new YAHOO.util.Element(document.createElement('span'),{id:ppnt.getId()+"_img"});
      imgElem.appendTo(elem);
      imgElem.addClass('wptIEImg');
   } else {
      var imgElem = new YAHOO.util.Element(document.createElement('img'),{src:'./img/waypoint.png',id:ppnt.getId()+"_img"});
      imgElem.appendTo(elem);
   }

   YAHOO.util.Dom.setX($(ppnt.getId()),ppnt.getX()+evtx-(16/2));
   YAHOO.util.Dom.setY($(ppnt.getId()),ppnt.getY()+evty-(16/2));

   YAHOO.mapComponent.drawWaypointsLine();
};

YAHOO.mapComponent.hideWaypoints = function() {
   for (var i=0;i<YAHOO.mapComponent.wayPoints.length;i++) {
      var pnt = YAHOO.mapComponent.wayPoints[i];
      YAHOO.util.Dom.setStyle($(pnt.getId()),'visibility','hidden');
   }

   YAHOO.util.Dom.setStyle($('wptBox'),'visibility','hidden');
};

YAHOO.mapComponent.redrawWaypoints = function() {
   var evtx = YAHOO.util.Dom.getX(YAHOO.mapComponent._container);
   var evty = YAHOO.util.Dom.getY(YAHOO.mapComponent._container);

   for (var i=0;i<YAHOO.mapComponent.wayPoints.length;i++) {
      var pnt = YAHOO.mapComponent.wayPoints[i];
      if (pnt==null) {

      } else {
         var ppnt = pnt.convertToImageCoords(YAHOO.mapComponent.currentEnvelope);
         var elem = $(ppnt.getId());
         YAHOO.util.Dom.setX(elem,ppnt.getX()+evtx-(16/2));
         YAHOO.util.Dom.setY(elem,ppnt.getY()+evty-(16/2));

         if (pnt.isOutside(YAHOO.mapComponent.currentEnvelope)) {
            YAHOO.util.Dom.setStyle(elem,'visibility','hidden');
         } else {
            YAHOO.util.Dom.setStyle(elem,'visibility','visible');
         }
      }
   }
 
   YAHOO.mapComponent.drawWaypointsLine();
};

/////////////////////////////////////////////////
//
// Property accessors and helper methods
//
/////////////////////////////////////////////////

/**
   Handler for the onGetImage event raised by the mapService
**/
YAHOO.mapComponent.onGetImage = function(img,env) {
   YAHOO.mapComponent.setImage(img);
   YAHOO.mapComponent.currentEnvelope = env;
   loadIslands(env);
   if (YAHOO.mapComponent.wayPoints.length > 0) {
      YAHOO.mapComponent.redrawWaypoints(true);
   };
//   YAHOO.mapService.dynamicLayers = [];
};

/**
   Set's the map image of the component

   @param url The url of the image to set
**/
YAHOO.mapComponent.setImage = function(url) {
   YAHOO.mapComponent.image.set('src',url);
};

/**
   Returns the width of the map component
**/
YAHOO.mapComponent.getWidth = function() {
	return YAHOO.util.Dom.getRegion(YAHOO.mapComponent._container)["right"]-
               YAHOO.util.Dom.getRegion(YAHOO.mapComponent._container)["left"];
};

/**
   Returns the height of the map component
**/
YAHOO.mapComponent.getHeight = function() {
	return YAHOO.util.Dom.getRegion(YAHOO.mapComponent._container)["bottom"]-
               YAHOO.util.Dom.getRegion(YAHOO.mapComponent._container)["top"];
};

/**
   Shows the loading pane with the specified text
**/
YAHOO.mapComponent.setLoading = function(text) {
  
   var creg = YAHOO.util.Dom.getRegion('map_image_container');
 
   var width = creg["right"]-creg["left"];
   var height = creg["bottom"] - creg["top"];

   var xy = YAHOO.util.Dom.getXY('map_image_container');

   YAHOO.util.Dom.setStyle(['loading'],'display','block');

   var reg = YAHOO.util.Dom.getRegion('loading');

   var w = Math.round((reg["right"]-reg["left"])/2);
   var h = Math.round((reg["bottom"] - reg["top"])/2);

   YAHOO.util.Dom.setX('loading',(xy[0] + Math.round(width/2))-w);
   YAHOO.util.Dom.setY('loading',(xy[1] + Math.round(height/2))-h);

   document.getElementById('loading_text').innerHTML = (text!=null?text:resMan.get('lblLoading'));
};

/**
   Hides the Loading pane
**/
YAHOO.mapComponent.setFinished = function() {
   YAHOO.util.Dom.setStyle(['loading'],'display','none');

};

/**
   Refreshes the map image to the specified envelope

   @param env The new envelope
**/
YAHOO.mapComponent.previous = null;

YAHOO.mapComponent.changeExtent = function(env,project) {

   YAHOO.mapComponent.previous = YAHOO.mapComponent.currentEnvelope;

     

   YAHOO.mapComponent.service.getImageWithEnvelope(
      YAHOO.mapComponent.getWidth(),
      YAHOO.mapComponent.getHeight(),
      env,true,YAHOO.mapComponent.onGetImage,project);
};

/**
   Refreshes the map image keeping the same extent

   @param reaspect Whether we want to reaspect the image (e.g. in case of resize)
**/
YAHOO.mapComponent.refreshImage = function(reaspect) {
   YAHOO.mapComponent.setLoading(resMan.get('lblLoadingImage'));
   YAHOO.mapComponent.changeExtent(YAHOO.mapComponent.currentEnvelope);
};

/**
   Pans the map to the specified direction
   
   @param direction The direction to pan right|left|up|down
**/
YAHOO.mapComponent.pan = function(direction) {
   var opMin = YAHOO.mapComponent.currentEnvelope.getMinPoint();
   var opMax = YAHOO.mapComponent.currentEnvelope.getMaxPoint();

   var mapWidth = YAHOO.mapComponent.currentEnvelope.getXDistance();
   var mapHeight = YAHOO.mapComponent.currentEnvelope.getYDistance();

   var dx = mapWidth*0.1;
   var dy = mapHeight*0.1;

   var pMin = null;
   var pMax = null;

   switch (direction) {
      case "right":
         pMin = new Point(opMin.getX()-dx,opMin.getY());
         pMax = new Point(opMax.getX()-dx,opMax.getY());
         break;
      case "left":
         pMin = new Point(opMin.getX()+dx,opMin.getY());
         pMax = new Point(opMax.getX()+dx,opMax.getY());
         break;
      case "up":
         pMin = new Point(opMin.getX(),opMin.getY()-dy);
         pMax = new Point(opMax.getX(),opMax.getY()-dy);
         break;
      case "down":
         pMin = new Point(opMin.getX(),opMin.getY()+dy);
         pMax = new Point(opMax.getX(),opMax.getY()+dy);
         break;
   }

   var env = new Envelope(pMin,pMax);

   YAHOO.mapComponent.setLoading("Panning...");
   YAHOO.mapComponent.changeExtent(env); 
};


/////////////////////////////////////////////////
//
// Binding listeners and initialization
//
/////////////////////////////////////////////////

/**
   We defer some initializations and listeners binding
   until we have a dom tree preventing YUI polling.
**/
function _init_component() {

   var a = Math.round(YAHOO.util.Dom.getViewportHeight()*0.6);

   var html = '';
   html += '               <div id="map_container" style="height:'+(a-50)+'px">';
   html += '                  <div id="mainToolbar" class="toolbar" style="display:block;width:100%;z-index:100"></div>';
   html += '                  <div id="waypointsToolbar" class="toolbar" style="display:none;z-index:10001"></div>';
   html += '                  <div id="islandName" style="display:none;z-index:10001"></div>';
   html += '                  <!-- start map image-->';
   html += '                  <div id="map_image_container" style="overflow:hidden;z-index:3">';
   html += '                     <img id="map_image" src="./img/blank.gif"/>';
   html += '                     <div id="loading">';
   html += '                        <img id="ld_image" src="./img/loading2.gif"/><br/>';
   html += '                        <span id="loading_text">Loading</span> ';
   html += '                     </div>';
   html += '                     <div id="selRect"></div>';
   html += '                     <div id="wptBox"></div>';
   html += '                  </div>';
   html += '                  <!-- end map image-->';
   html += '              </div>';

   $('container').innerHTML = html;
   
   YAHOO.mapComponent._selRect = $('selRect');
   YAHOO.mapComponent._container = $('map_image_container');
   
   YAHOO.util.Event.on(YAHOO.mapComponent._container, "mousedown", YAHOO.mapComponent.onMapMouseDown);
   YAHOO.util.Event.on(YAHOO.mapComponent._container, "mouseup", YAHOO.mapComponent.onMapMouseUp);
   YAHOO.util.Event.on(YAHOO.mapComponent._container, "mousemove", YAHOO.mapComponent.onMapMouseMove);
   YAHOO.util.Event.on(YAHOO.mapComponent._container, "click", YAHOO.mapComponent.onMapClick);

   YAHOO.util.Event.addListener('map_image', "load", function() {
      YAHOO.util.Dom.setStyle($('map_image'),'margin',0);
      YAHOO.mapComponent.setFinished();
   });
};

YAHOO.util.Event.onDOMReady(_init_component);  



YAHOO.mapComponent.getScale = function() {
   return YAHOO.mapComponent.getWidth()/YAHOO.mapComponent.currentEnvelope.getXDistance();
};

YAHOO.namespace("mapTools");
YAHOO.mapTools.downPoint = null;

YAHOO.mapTools.renderSelRect = function(cmp,evtUp,evtDown) {
	var pnt = evtUp;
	var dn = evtDown;
	var x = YAHOO.util.Dom.getX(cmp._container);
	var y = YAHOO.util.Dom.getY(cmp._container);
	var dx = pnt.getX()-dn.getX();
	var dy = pnt.getY()-dn.getY();
  
	var w = (Math.abs(dx)-1);
      	var h = (Math.abs(dy)-1);

      	YAHOO.util.Dom.setStyle(YAHOO.mapComponent._selRect,'width',w<0?0:w);
      	YAHOO.util.Dom.setStyle(YAHOO.mapComponent._selRect,'height',h<0?0:h); 

      	var xy = [];

      	xy [0] = ( dn.getX() + x) - ( dx > 0 ? 0 : Math.abs(dx) ); 
      	xy [1] = ( dn.getY() + y) - ( dy > 0 ? 0 : Math.abs(dy) ); 

      	YAHOO.util.Dom.setXY(cmp._selRect,xy); 
};


YAHOO.mapTools.tools = {

  /**
    * Zoomin tool
    */
   zoomin : {
               mouseUp : function(cmp,evtPoint){
			   var up = evtPoint;
			   var dx = Math.abs(up.getX()-YAHOO.mapTools.downPoint.getX());
			   var dy = Math.abs(up.getY()-YAHOO.mapTools.downPoint.getY());
				
			   if (dx < 5 && dy <5) {
     				cmp.changeExtent(cmp.currentEnvelope.centerToPoint(cmp.toMapCoords(evtPoint)).zoomByFactor(4));
			   } else {
                           	cmp.changeExtent(cmp.getRect(up,YAHOO.mapTools.downPoint));
			   }

                           YAHOO.util.Dom.setStyle(cmp._selRect,'visibility','hidden');
                         },
               mouseDown : function(cmp,evtPoint){
			 YAHOO.mapTools.downPoint = evtPoint;
		         cmp._selRect.style.visibility='visible';
         		 YAHOO.util.Dom.setStyle(cmp._selRect,'width','0px');
         		 YAHOO.util.Dom.setStyle(cmp._selRect,'height','0px');
                           },
		mouseMove : function(cmp,evtPoint){
				if (!YAHOO.mapTools.downPoint) {
					return;
				}
				YAHOO.mapTools.renderSelRect(cmp,evtPoint,YAHOO.mapTools.downPoint);
			},
               stopEvent : true
            },


	/**
	Zoom out
	*/

	zoomout : {
		stopEvent: true,
		mouseDown : function(cmp,evtPoint) {
		      cmp.changeExtent(cmp.currentEnvelope.zoomByFactor(-2));
		},
		mouseUp : function () { return ; },
		mouseMove : function () { return ;}
	},

	identify : { 
		stopEvent : true,
		mouseDown : function(cmp,evtPoint) {
			 queryByPoint(mapPnt.convertToMapCoords(cmp.currentEnvelope));
		},
		mouseUp : function () { return ; },
		mouseMove : function () { return ;}
	},

   /**
    * Select By Rectangle Tool
    */
   select_by_rectangle : { 
               mouseUp : function(cmp,evtPoint) {
                            var env = cmp.getRect(YAHOO.mapTools.downPoint,evtPoint);
                            initQueryByEnvelope(env);
                            YAHOO.util.Dom.setStyle(cmp._selRect,'visibility','hidden');
                         },
               mouseDown : function(cmp,evtPoint) {
			YAHOO.mapTools.tools["zoomin"].mouseDown(cmp,evtPoint);
		     },
               mouseMove : function(cmp,evtPoint) {
				if (!YAHOO.mapTools.downPoint) {
					return;
				}
				YAHOO.mapTools.renderSelRect(cmp,evtPoint,YAHOO.mapTools.downPoint);
		     },
               stopEvent : true
                         },

   /**
    * Pan tool
    */
   pan : {
               mouseUp : function(cmp,evtPoint){
                           var dn = YAHOO.mapTools.downPoint;
                           var up = evtPoint;

                           var dx = up.getX()-dn.getX();
                           var dy = up.getY()-dn.getY();     

                           var x = cmp.getWidth()/2 - dx;
                           var y = cmp.getHeight()/2 - dy;

                           var pnt = new Point(x*1,y*1);
   
                           var mapPnt = pnt.convertToMapCoords(cmp.currentEnvelope);
   
                           cmp.setLoading(resMan.get('lblLoadingImage'));
                           var env = cmp.currentEnvelope.centerToPoint(mapPnt);
                           cmp.changeExtent(env);

                           YAHOO.util.Dom.setStyle(cmp._selRect,'visibility','hidden');
                       },
                mouseDown : function (cmp,evtPoint) {
			 YAHOO.mapTools.downPoint = evtPoint;
                            },
		mouseMove : function (cmp,evtPoint) {
			if (!YAHOO.mapTools.downPoint){
				return;
			}

			var dn = YAHOO.mapTools.downPoint ;
			var up = evtPoint;

			var dx = up.getX()-dn.getX();
			var dy = up.getY()-dn.getY();     

			YAHOO.util.Dom.setStyle($('map_image'),'margin-left',dx);
			YAHOO.util.Dom.setStyle($('map_image'),'margin-top',dy);
			YAHOO.util.Dom.setStyle($('map_image'),'width',cmp.getWidth());
  		},
                stopEvent : true 
         },
	


	/**
	select point
	*/
	
	select_point : {
		stopEvent : true,
		mouseDown : function(cmp,evtPoint) {
			cmp.notifyForms(evtPoint.convertToMapCoords(cmp.currentEnvelope));
		},
		mouseUp : function() { return ;},
		mouseMove : function() { return ;}
	},

	/**
	 select by point
	 **/

	select_by_point : { 
		stopEvent : true,
		mouseDown : function (cmp,evtPoint) {
  			var pntMap = evtPoint.convertToMapCoords(cmp.currentEnvelope);
		        var pntMax = new Point(pntMap.getX()+10, pntMap.getY()+10);
		        var env = new Envelope(pntMap,pntMax);
		        initQueryByEnvelope(env);
		},
		mouseUp : function() { return ; },
		mouseMove : function() { return ;}
	},

	/**
	measure
	*/

	measure : {
		stopEvent : true,
		mouseDown : function (cmp,evtPoint) {
			YAHOO.mapTools.downPoint = evtPoint;
		},
		mouseUp : function () { return ; },
		mouseMove : function () { return ; } 
	}
};

/////////////////////////////////////////////////
//
// Toolbar construction methods and listeners
// for mousein/mouseout.
//
// Interaction is handled by onToolbarButtonClick
// which is not included here (should be implemented)
// on the appropriate UI file.
//
// Author: Tasos Vogiatzoglou
//
/////////////////////////////////////////////////

/**
   Generates the HTML for a button. As IE does not support
   directly PNG Alpha Transparency a hack is used to simulate
   the event (a span with a AlphaImage filter).

   The image of the button is specified as ./img/<buttonId>.png

   @param buttonId The id of the button to generate
**/
function toolbarButton(buttonId) {
   
   var html = '<td><span id="'+buttonId+'" class="tbButton">';

   var arVersion = navigator.appVersion.split("MSIE")
   var version = parseFloat(arVersion[1])

   if ((version >= 5.5) && (version < 7) && (document.body.filters)) {
      html += '<span class="tbIEImg" style="width:16px;height:16px;display:inline-block;';
      html += 'filter:progid:DXImageTransform.Microsoft.AlphaImageLoader';
      html += '(src=\'./img/' + buttonId + '.png\', sizingMethod=\'scale\');"></span>';
    } else {
      html += '<img src="./img/'+buttonId+'.png"/>';
   }

   html += '</span></td>';

   new YAHOO.widget.Tooltip(buttonId+"_tooltip", { 
      context:buttonId, 
      text:resMan.get(buttonId+"_tooltip"),
      showDelay:100 } );

   return html;
};

function toolbarSeparator() {
   return '<td><span class="tbSeparator"></span></td>';
};

function toolbarSpace() {
   return '<td><span style="width:30px;display;inline-block"></span></td>';
};

function createMainToolbar() {
   var html = "";
   html += toolbarButton('btnZoomIn');
   html += toolbarButton('btnZoomOut');
   html += toolbarSeparator();
   html += toolbarButton('btnInitial');
   html += toolbarButton('btnPrevious');
   html += toolbarSeparator();
   html += toolbarButton('btnPan');
   html += toolbarButton('btnLeft');
   html += toolbarButton('btnUp');
   html += toolbarButton('btnDown');
   html += toolbarButton('btnRight');
   html += toolbarSeparator();
   html += toolbarButton('btnWaypoints');
   html += toolbarButton('btnByRectangle');
   html += toolbarButton('btnIdentify');
   html += toolbarSeparator();
   html += toolbarButton('btnClearResults');
   html += toolbarSeparator();
   html += toolbarButton('btnHelp');

   $('mainToolbar').innerHTML = '<table id="mainToolbarContainer" cellpadding="0" cellspacing="0"><tr>'+html+'</tr></table>';
};

function createWaypointsToolbar() {
   var html = toolbarButton('btnWaypointsAddNode');
   html += toolbarButton('btnWaypointsDeleteNode');
   html += toolbarButton('btnWaypointsMoveNode');
   html += toolbarSeparator();
//   html += toolbarButton('btnWaypointsInGrid');
  // html += toolbarSeparator();
   //html += toolbarSpace();
   html += toolbarButton('btnWaypointsFinish');
   html += toolbarButton('btnWaypointsStop');

   $('waypointsToolbar').innerHTML = '<table id="waypointsToolbarContainer" cellpadding="0" cellspacing="0"><tr>'+html+'</tr></table>';
};

function handleToolbarIn(evt){
   var elm = YAHOO.util.Event.getTarget(evt);

   if (elm.className=='tbSeparator') {
      YAHOO.util.Event.stopEvent(evt);
      return false;
   }

   if ( elm.tagName == "IMG" || elm.className == "tbIEImg" ) {
      elm = elm.parentNode;
   }
   
   if (elm.className!="tbIEImg" && elm.className != 'tbButtonPressed') {
      elm.className = 'tbButtonHover';
   }

   YAHOO.util.Event.stopEvent(evt);
   return false;
   
};

function handleToolbarOut(evt){
   var elm = YAHOO.util.Event.getTarget(evt);

   if (elm.className=='tbSeparator') {
      YAHOO.util.Event.stopEvent(evt);
      return false;
   }

   if (elm!=null && (elm.tagName == "IMG" || elm.className == "tbIEImg")) {
      elm = elm.parentNode;
   }
  
   if (elm.className!="tbIEImg"  && elm.className != 'tbButtonPressed' ) {
      elm.className = 'tbButton';
   }

   YAHOO.util.Event.stopEvent(evt);
   return false;

};


function bindToolbars() {
   YAHOO.util.Event.on('mainToolbarContainer','mousemove',handleToolbarIn);
   YAHOO.util.Event.on('mainToolbarContainer','mouseout',handleToolbarOut);
   YAHOO.util.Event.on('mainToolbarContainer','click',onToolbarButtonClick);

   YAHOO.util.Event.on('waypointsToolbarContainer','mousemove',handleToolbarIn);
   YAHOO.util.Event.on('waypointsToolbarContainer','mouseout',handleToolbarOut);
   YAHOO.util.Event.on('waypointsToolbarContainer','click',onToolbarButtonClick);
};
    YAHOO.namespace('mapDialogs.alert');

    alert_old = window.alert;
    window.alert = function(str) {
        YAHOO.mapDialogs.alert.dlg.setBody(str);
        YAHOO.mapDialogs.alert.dlg.cfg.queueProperty('icon', YAHOO.widget.SimpleDialog.ICON_WARN);
        YAHOO.mapDialogs.alert.dlg.render(document.body);
        YAHOO.mapDialogs.alert.dlg.show();
    };


    YAHOO.util.Event.on(window, 'load', function() {

        var handleOK = function() {
            this.hide();
        };

        YAHOO.mapDialogs.alert.dlg = new YAHOO.widget.SimpleDialog('widget_alert', {
            visible:false,
            width: '20em',
            close: false,
            fixedcenter: true,
            modal: false,
            draggable: true,
            constraintoviewport: true, 
            icon: YAHOO.widget.SimpleDialog.ICON_WARN,
            buttons: [
                { text: 'Ok', handler: handleOK, isDefault: true }
                ]
        });
        YAHOO.mapDialogs.alert.dlg.setHeader("Alert!");
        YAHOO.mapDialogs.alert.dlg.setBody('Alert body passed to window.alert'); 
        YAHOO.mapDialogs.alert.dlg.render(document.body);
    });

      YAHOO.namespace('mapDialogs.confirm');
      YAHOO.mapDialogs.confirm.handleOk = function(){};
      YAHOO.mapDialogs.confirm.handleCancel = function(){};
/*
    window.confirm = function(title,str) {
         YAHOO.mapDialogs.confirm.dlg.setHeader(title);
         YAHOO.mapDialogs.confirm.dlg.setBody(str);
         YAHOO.mapDialogs.confirm.dlg.cfg.queueProperty('icon', YAHOO.widget.SimpleDialog.ICON_WARN);
         YAHOO.mapDialogs.confirm.dlg.render(document.body);
         YAHOO.mapDialogs.confirm.dlg.show();
         return false;
    };
*/

    YAHOO.util.Event.on(window, 'load', function() {

        var handleCancel = function() {
            this.hide();
            YAHOO.mapDialogs.confirm.handleCancel();
        };

        var handleOk = function() {
            this.hide();
            YAHOO.mapDialogs.confirm.handleOk();
         };

        YAHOO.mapDialogs.confirm.dlg = new YAHOO.widget.SimpleDialog('widget_confirm', {
            visible:false,
            width: '20em',
            close: false,
            fixedcenter: true,
            modal: true,
            draggable: true,
            constraintoviewport: true, 
            icon: YAHOO.widget.SimpleDialog.ICON_WARN,
            buttons: [
                { text:'Ok', handler: handleOk, isDefault: false },
                { text:'Cancel', handler: handleCancel, isDefault: true }
                ]
        });
        YAHOO.mapDialogs.confirm.dlg.setHeader("Please confirm");
        YAHOO.mapDialogs.confirm.dlg.setBody('Alert body passed to window.alert'); 
        YAHOO.mapDialogs.confirm.dlg.render(document.body);
    });
/////////////////////////////////////////////////
//
//
// GIS Client UI initialization functions
// and implementation
//
// Author: Tasos Vogiatzoglou
//
/////////////////////////////////////////////////


var waypointsToolbarVisible = false;
var selectedTool = null;

function openHelp() {
    window.open("help_"+lang+".html","help","");

}

function onToolbarButtonClick(e) {

   var elm = YAHOO.util.Event.getTarget(e);
   
   if (elm.className=='tbSeparator') {
      YAHOO.util.Event.stopEvent(evt);
      return false;
   }

   if (elm!=null && (elm.tagName == "IMG" || elm.className == "tbIEImg")) {
      elm = elm.parentNode;
   }

   switch (elm.id) {
      case "btnHelp":
          openHelp();
          break;
      case "btnLeft":
         YAHOO.mapComponent.pan('left');
         break;
      case "btnUp":
         YAHOO.mapComponent.pan('up');
         break;
      case "btnDown":
         YAHOO.mapComponent.pan('down');
         break;
      case "btnPrevious":
	if (YAHOO.mapComponent.previous) {
		YAHOO.mapComponent.changeExtent(YAHOO.mapComponent.previous);
		YAHOO.mapComponent.previous = null;
	}
	break;
      case "btnRight":
         YAHOO.mapComponent.pan('right');
         break;
      case "btnInitial":
         YAHOO.mapComponent.setLoading("Loading image...");
         YAHOO.mapComponent.changeExtent(YAHOO.mapComponent.service.initialExtent);
         break;
      case "btnWaypoints":
         YAHOO.util.Dom.setStyle('waypointsToolbar','display','block');
         YAHOO.util.Dom.setStyle('waypointsToolbar','position','absolute');
         w = YAHOO.util.Dom.getRegion('waypointsToolbar')["right"]-YAHOO.util.Dom.getRegion('waypointsToolbar')["left"];
         h = YAHOO.util.Dom.getRegion('waypointsToolbar')["bottom"]-YAHOO.util.Dom.getRegion('waypointsToolbar')["top"];


         YAHOO.util.Dom.setX('waypointsToolbar',
            YAHOO.util.Dom.getX('map_image_container')+YAHOO.mapComponent.getWidth()-w);

         YAHOO.util.Dom.setY('waypointsToolbar',
            YAHOO.util.Dom.getY('map_image_container'));

         waypointsToolbarVisible = true;

         break;
      case "btnClearResults":
         if (window.confirm(resMan.get('msgClearResults'))) {
            YAHOO.mapComponent.service.dynamicLayers = {};
            YAHOO.mapComponent.service.getLayerByName('XEE').setVisible(false);
            YAHOO.mapComponent.service.getLayerByName('charts').setVisible(false);
            YAHOO.mapComponent.refreshImage();

            $('featuresGrid').innerHTML = "";
         };
         break;
      case "btnWaypointsStop":
         if (window.confirm(resMan.get('msgWaypointsCancel'))) {
            YAHOO.util.Dom.setStyle('waypointsToolbar','display','none');
            waypointsToolbarVisible = false;
            for (var i=0;i<YAHOO.mapComponent.wayPoints.length;i++){
               $('map_image_container').removeChild($(YAHOO.mapComponent.wayPoints[i].getId()));
            }
            YAHOO.mapComponent.wayPoints = [];
            $('wptBox').innerHTML = "";

            YAHOO.mapComponent.service.dynamicLayers = {};
            YAHOO.mapComponent.service.getLayerByName('XEE').setVisible(false);
            YAHOO.mapComponent.service.getLayerByName('charts').setVisible(false);
            YAHOO.mapComponent.refreshImage();

            $('featuresGrid').innerHTML = "";

         };
         break;
      case "btnWaypointsFinish":
         executeWaypointQuery();
         break;
      default:
         if (selectedTool != elm.id) {
            if (selectedTool != null) {
               $(selectedTool).className = 'tbButton';
            }
            selectedTool = elm.id;
            elm.className = 'tbButtonPressed';
         }
         switch (elm.id) {
            case "btnZoomOut":
               YAHOO.mapComponent.currentTool = 'zoomout';   
               break;
            case "btnZoomIn":
               YAHOO.mapComponent.currentTool = 'zoomin';   
               break;
            case "btnPan":
               YAHOO.mapComponent.currentTool = 'pan';   
               break;
            case "btnByRectangle":
               YAHOO.mapComponent.currentTool = 'select_by_rectangle';   
               break;
            case "btnIdentify":
               YAHOO.mapComponent.currentTool = 'identify';
               break;
            case "btnWaypointsAddNode":
               YAHOO.mapComponent.currentTool = 'waypoints_add';
               break;
            case "btnWaypointsDeleteNode":
               YAHOO.mapComponent.currentTool = 'waypoints_delete';
               break;
            case "btnWaypointsMoveNode":
               YAHOO.mapComponent.currentTool = 'waypoints_move';
               break;

         };
         break;
   }
};

function checkSelectedLayers() {

   var layers = null;
      
   for (var i=0;i<YAHOO.mapComponent.service.layers.length;i++){
      var lr = YAHOO.mapComponent.service.layers[i];
      
      if (lr.isVisible()) {
         var nd = YAHOO.mapTOC.tree.getNodeByProperty('lyr',lr.getId());
         if (!layers) { layers = []; }
	 var st = lr.getName().substring(0,3);//lr.getId().substring(0,3);
         if ( st == 'XEE'|| st == 'enc') {
//            layers.push(YAHOO.mapComponent.service.getLayerId(lr.getName()));
            layers.push(lr);
         }
      }
   }

   return layers;
};


function queryByEnvelope(env) {

   $('featuresGrid').innerHTML = "";
   var lrs = checkSelectedLayers();

   if (!lrs) {
      return alert(resMan.get('msgToManyLayers'));
   }


   for (var i=0;i<lrs.length;i++) {
      var qry = '<SPATIALQUERY subfields="#ALL#"><SPATIALFILTER relation="area_intersection">';
      qry += env.toAXL();
      qry += '</SPATIALFILTER></SPATIALQUERY>';

      var lr = '<LAYER type="featureclass" name="select layer" visible="true" id="select">';
      lr += '<DATASET fromlayer="'+lrs[i].getId()+'"/>';
      lr += qry;
      lr += '<GROUPRENDERER>';
      lr += '<SIMPLERENDERER>';
      lr += '	  <SIMPLEPOLYGONSYMBOL boundarytransparency="1,0" filltransparency="1,0" filltype="bdiagonal" fillcolor="255,100,0" boundarycaptype="round" />';
      lr += '</SIMPLERENDERER>';
      lr += '<SIMPLELABELRENDERER field="SDE.XEE_AOI.MAP_NO">';
      lr += ' <TEXTSYMBOL antialiasing="true" font="Arial" fontstyle="regular" fontcolor="255,255,255" fontsize="10" glowing="255,0,0" />';
      lr += '</SIMPLELABELRENDERER>';
      lr += '</GROUPRENDERER>';
      lr += '</LAYER>';

      YAHOO.mapComponent.service.dynamicLayers["select_"+lrs[i]] = lr;

      YAHOO.mapComponent.service.queryFeatures("<LAYER id='"+lrs[i].getId()+"'/>"+qry,null,0, function(recs,res) {
       var tabView = new YAHOO.widget.TabView('featuresGrid');
       var fields = YAHOO.mapConfig.layers[res.layer.getName()].select;

         var content = "<div id='datagrid_container_"+res.layer.getName()+"'></div>";

         var tb = new YAHOO.widget.Tab({ label: resMan.get("layer_"+res.layer.getName()), content: content }) ;
         tabView.addTab(tb);
         tabView.activeIndex = 1;

         var colDef = [];
                 
                  var ds = new YAHOO.util.DataSource(res.results);
                  ds.responseType = YAHOO.util.DataSource.TYPE_JSARRAY;
                  ds.responseSchema = {fields: []};
 
                  for (var fi=0;fi<fields.length;fi++){
                        var k = fields[fi];
                        var fld = {key:k.key,label:resMan.get(res.layer.getName()+"."+k.key),sortable:true};
                        if (k.formatter) {
                           fld.formatter = k.formatter;
                        }
                        if (k.width) {
                           fld.width = k.width;
                        }
			if (k.label) {
			   fld.label = k.label;
			}


                        colDef.push(fld);
                     ds.responseSchema.fields.push(k.key);
                  }

                  ds.responseSchema.fields.push("minx");
                  ds.responseSchema.fields.push("miny");
                  ds.responseSchema.fields.push("maxx");
                  ds.responseSchema.fields.push("maxy");

      myDataTable = new YAHOO.widget.DataTable("datagrid_container_"+res.layer.getName(),colDef,ds);
      tabView.set("activeTab",tb);
	   	   },lrs[i]);
   }


   YAHOO.mapComponent.refreshImage();
};

function queryByPoint(pnt) {
   var minPoint = new Point(pnt.getX()-0.01,pnt.getY()-0.01);
   var maxPoint = new Point(pnt.getX()+0.01,pnt.getY()+0.01);
   queryByEnvelope(new Envelope(minPoint,maxPoint));
};

function executeWaypointQuery() {

   $('featuresGrid').innerHTML = "";
   var lrs = checkSelectedLayers();

   if (!lrs) {
      return alert(resMan.get('msgToManyLayers'));
   }

   for (var i=0;i<lrs.length;i++) {
   
      var qry = '<SPATIALQUERY  subfields="#ALL#"><SPATIALFILTER relation="area_intersection">';
      qry += '<POLYLINE><PATH>';
      for (var x=0;x<YAHOO.mapComponent.wayPoints.length;x++) {
         var pt = YAHOO.mapComponent.wayPoints[x];
         qry += '<POINT x="'+fts(pt.getX()) +'" y="'+fts(pt.getY()) +'"/>';
      }
      qry += '</PATH></POLYLINE>';
      qry += '</SPATIALFILTER></SPATIALQUERY>';

      var lr = '<LAYER type="featureclass" name="select layer" visible="true" id="select">';
      lr += '<DATASET fromlayer="'+lrs[i].getId()+'"/>';
      lr += qry;
      lr += '<GROUPRENDERER>';
      lr += '<SIMPLERENDERER>';
      lr += '	  <SIMPLEPOLYGONSYMBOL boundarytransparency="1,0" filltransparency="1,0" filltype="bdiagonal" fillcolor="255,100,0" boundarycaptype="round" />';
      lr += '</SIMPLERENDERER>';
      lr += '<SIMPLELABELRENDERER field="XEENUM">';
      lr += ' <TEXTSYMBOL antialiasing="true" font="Arial" fontstyle="regular" fontcolor="255,255,255" fontsize="10" glowing="255,0,0" />';
      lr += '</SIMPLELABELRENDERER>';
      lr += '</GROUPRENDERER>';
      lr += '</LAYER>';

      YAHOO.mapComponent.service.dynamicLayers["select_"+lrs[i]] = lr;
      YAHOO.mapComponent.service.queryFeatures("<LAYER id='"+lrs[i].getId()+"'/>"+qry,null,0, function(recs,res) {

       var tabView = new YAHOO.widget.TabView('featuresGrid');
       var fields = YAHOO.mapConfig.layers[res.layer.getName()].select;

         var content = "<div id='datagrid_container_"+res.layer.getId()+"'>";
        content += "</div>";

         var tb = new YAHOO.widget.Tab({ label: resMan.get("layer_"+res.layer.getName()), content: content }) ;
         tabView.addTab(tb);
         tabView.activeIndex = 1;

                  var colDef = [
                  ];
                 
                  var ds = new YAHOO.util.DataSource(res.results);
                  ds.responseType = YAHOO.util.DataSource.TYPE_JSARRAY;
                  ds.responseSchema = {
                     fields: []
                  };
 
                  for (var fi=0;fi<fields.length;fi++){
                        var k = fields[fi];
                        var fld = {key:k.key,label:resMan.get(res.layer.getName()+"."+k.key),sortable:true};
                        if (k.formatter) {
                           fld.formatter = k.formatter;
                        }
                        if (k.width) {
                           fld.width = k.width;
                        }
			if (k.label) {
			   fld.label = k.label;
			}


                        colDef.push(fld);
                     ds.responseSchema.fields.push(k.key);
                  }

                  ds.responseSchema.fields.push("minx");
                  ds.responseSchema.fields.push("miny");
                  ds.responseSchema.fields.push("maxx");
                  ds.responseSchema.fields.push("maxy");

      myDataTable = new YAHOO.widget.DataTable("datagrid_container_"+res.layer.getId(),colDef,ds);
      tabView.set("activeTab",tb);
	   	   },lrs[i]);
   }


   

   


      var wpt = '<LAYER type="acetate" name="ssss" visible="true" id="sssss">';
   wpt += '<OBJECT units="database">';
   wpt += '<POLYLINE><PATH>';
   for (var i=0;i<YAHOO.mapComponent.wayPoints.length;i++) {
      var pt = YAHOO.mapComponent.wayPoints[i];
      wpt += '<POINT x="'+fts(pt.getX())+'" y="'+fts(pt.getY())+'"/>';
   }
   wpt += '</PATH></POLYLINE>';
   wpt += '<SIMPLELINESYMBOL color="200,0,0" width="6" />'
    wpt += '</OBJECT>';
   wpt += '</LAYER>';
    
    YAHOO.mapComponent.service.dynamicLayers["wpt"] = wpt;
   
    YAHOO.mapComponent.refreshImage();

/*   YAHOO.mapComponent.service.dynamicLayers["select"] = lr;
   YAHOO.mapComponent.refreshImage();

   YAHOO.mapComponent.service.queryFeatures("<LAYER id='"+lrs[0]+"'/>"+qry,lrs[0],null,0,function (data) {
      var grid = new YAHOO.dataGrid.GridModel(resMan,'xee');
      grid.addColumn(new YAHOO.dataGrid.GridColumn('TITLE_GR','100%'));
      $('featuresGrid').innerHTML = grid.render(data);
   });

  */ 
};

function createPointLayer(point) {

var phi =  carto.utils.degToRad(point.getX());
var lambda =  carto.utils.degToRad(point.getY());

var i = parseInt;

var p1 = i((phi * 180) / Math.PI);
var p2 = i(60 * (	(	  (phi * 180) / Math.PI        )  - p1     ));
var p3 = parseInt(3600 * (((phi * 180) / Math.PI) - p1 - (p2 /60)));

var p = p1 + " "+p2+"\' " +p3+"\'\'";

var l1 = i((lambda * 180) / Math.PI);
var l2 = i(60 * (	(	  (lambda * 180) / Math.PI        )  - l1     ));
var l3 = parseInt(3600 * (((lambda * 180) / Math.PI) - l1 - (l2 /60)));

var l = l1 + " "+l2+"\' " +l3+"\'\'";

   var lr = '<LAYER type="acetate" name="ssss" visible="true" id="sssss">';
   lr += '<OBJECT units="database">';
   lr += '<POINT coords="'+fts(point.getX()) +' '+fts(point.getY()) +'">';
   lr += '<SIMPLEMARKERSYMBOL color="0,0,255" type="circle" antialiasing="true" width="10" shadow="true"/>';
   lr += '</POINT></OBJECT>';
   lr += '<OBJECT units="database">';
   lr += '<TEXT coords="'+(fts(point.getX()))+ ' ' + fts(point.getY()) + '" label= "'+p+"/"+l+'">';
   lr += '<TEXTMARKERSYMBOL fontstyle="regular" fontsize="14" font="Arial" antialiasing="true"/></TEXT>';
   lr += '</OBJECT>';
   lr += '</LAYER>';

   return lr;
};


/////////////////////////////////////////////////
//
// Coordinate text boxes implementation.
// 
// The user is not allowed to type letters in the 
// coordinate boxes, so listeners are bound to the 
// keypress events to prevent letters from being 
// entered.
//
/////////////////////////////////////////////////


/**
   Function that returns if a keycode represents a digit 
   (normal number buttons and numpad buttons)
**/
function is_digit(kc) {
   return ( 
            ( kc >=48 && kc <= 57 ) || //normal numerical buttons
            ( kc >=96 && kc <=105 )  //numpad numerical buttons
          );
};

/**
   Function that returns if a keycode represents a control char
**/
function is_control(kc) {
   return (
            ( kc == 9 ) || //backspace
            ( kc == 8 ) || //delete
            ( kc == 46) //tab
       );
};

/**
   Listener that supress non digit keystrokes (letters etc)
**/
function suppress_non_digits(e) {

   var kc = e.keyCode ? e.keyCode : e.keycode;

   if ($(this.id).value.length == 3 && !is_control(kc)) {
      YAHOO.util.Event.stopEvent(e);
      return false;
   }

   if (!is_digit(kc) && !is_control(kc)) {
      YAHOO.util.Event.stopEvent(e);
      return false;
   } 

   return true;
};

/**
   Listener that supress non digit keystrokes (letters etc)
   but allowing floating point.
**/
function suppress_non_float_digits(e) {
   var kc = e.keyCode ? e.keyCode : e.keycode;
   if (!is_digit(kc) && !is_control(kc) && kc!=190) {
      YAHOO.util.Event.stopEvent(e);
      return false;
   } 
   return true;
};

var phi_lambda_int_ids = ['txtPhiDeg','txtPhiMin','txtLambdaDeg','txtLambdaMin'];
var phi_lambda_float_ids = ['txtPhiSec','txtLambdaSec','txtX','txtY'];

var resizeTimeout=null;

function performLayout(){
   YAHOO.mapComponent.doLayout();

   if (waypointsToolbarVisible) {
      w = YAHOO.util.Dom.getRegion('waypointsToolbar')["right"]-YAHOO.util.Dom.getRegion('waypointsToolbar')["left"];
      h = YAHOO.util.Dom.getRegion('waypointsToolbar')["bottom"]-YAHOO.util.Dom.getRegion('waypointsToolbar')["top"];

      YAHOO.util.Dom.setX('waypointsToolbar',
          YAHOO.util.Dom.getX('map_image_container')+YAHOO.mapComponent.getWidth()-w);

      YAHOO.util.Dom.setY('waypointsToolbar',
          YAHOO.util.Dom.getY('map_image_container'));
   }

   YAHOO.mapComponent.refreshImage(false);
};

function handle_resize() {
   clearTimeout(YAHOO.mapComponent._layoutTimeout);
   resizeTimeout = setTimeout('performLayout()',100);
};


var selPoint = ['0','0'];

function initialize_autocomplete(){
     this.fnCustomFormatter = function(oResultItem, sQuery) {
        var sKey = oResultItem[0];
 //       var nQuantity = oResultItem[1];
        var sKeyQuery = sKey.substr(0, sQuery.length);
        var sKeyRemainder = sKey.substr(sQuery.length);
        var aMarkup = ["<div id='"+(oResultItem[3]+","+oResultItem[4])+"'class='sample-result'><div class='sample-quantity'>",
            "</div><span class='sample-query'>",
            sKeyQuery,
            "</span>",
            sKeyRemainder+" ("+oResultItem[1]+")",
            "</div>"];
        return (aMarkup.join(""));
    };


    oACDS = new YAHOO.widget.DS_XHR("/servlet/gazetter.jsp", ["ResultSet.Result","name","dname","lat","lon"]);
    oACDS.scriptQueryAppend = "lang="+lang;

    oACDS.responseType = YAHOO.widget.DS_XHR.TYPE_JSON;
    oACDS.maxCacheEntries = 1;
    oACDS.queryMatchSubset = true;
    oACDS.maxResultsDisplayed = 20;

   var handler = function  ( oSelf , elItem , oData ) {

      var itms = elItem.toString().split(',');
      selPoint[0] = itms[5];
      selPoint[1] = itms[4];

      var phi = carto.utils.degToRad(itms[4]);
      var lambda = carto.utils.degToRad(itms[5]);

      $('txtPhiDeg').value = parseInt((phi * 180) / Math.PI);
      $('txtPhiMin').value = parseInt(60 * ((( phi * 180) / Math.PI) - $('txtPhiDeg').value*1 ));
      $('txtPhiSec').value = parseFloat(3600 * (((phi * 180) / Math.PI) - $('txtPhiDeg').value*1 - ($('txtPhiMin').value*1 /60)));

      $('txtLambdaDeg').value = parseInt((lambda * 180) / Math.PI);
      $('txtLambdaMin').value = parseInt(60 * ((( lambda * 180) / Math.PI) - $('txtLambdaDeg').value*1 ));
      $('txtLambdaSec').value = parseFloat(3600 * (((lambda * 180) / Math.PI) - $('txtLambdaDeg').value*1 - ($('txtLambdaMin').value*1 /60)));

   };


    oAutoComp2 = new YAHOO.widget.AutoComplete('toponyms_txt','toponyms_results', oACDS);
    oAutoComp2.queryDelay = 0;
    oAutoComp2.prehighlightClassName = "yui-ac-prehighlight";
    oAutoComp2.formatResult = fnCustomFormatter;
    oAutoComp2.itemSelectEvent.subscribe(handler,this);
};

function showMoveTo(elem) {

   $('toponymBox').style.display = "none";
   $('latLonBox').style.display = "none";
   $('xyBox').style.display = "none";

   $(elem).style.display="block";
};

function gotoPoint(type) {
   var pnt = null;


   $('txtLambdaMin').value = $v('txtLambdaMin').length==0?"0":$v('txtLambdaMin');
   $('txtPhiMin').value = $v('txtPhiMin').length==0?"0":$v('txtPhiMin');

   if (type == 1 && ($v('txtPhiDeg').length > 0 && $v('txtPhiMin').length > 0 &&
       $v('txtLambdaDeg').length > 0 && $v('txtLambdaMin').length > 0)) {
      
      var  lambdaAng= carto.utils.parseAngular($v('txtPhiDeg'),$v('txtPhiMin'),$v('txtPhiSec'));
      var phiAng= carto.utils.parseAngular($v('txtLambdaDeg'),$v('txtLambdaMin'),$v('txtLambdaSec'));

      var phi_lambda = [];

      if (phiAng>0 && lambdaAng >0) {
      
        pnt = new Point(phiAng,lambdaAng);
        var pnt2 = pnt.convertToProjectedCoords();

         $('txtX').value = pnt2.getX();
         $('txtY').value = pnt2.getY();
      }
   } else if (type == 2 && ($v('txtX').length >0 && $v('txtY').length >0)) {
      pnt = new Point(parseFloat($v('txtX')), parseFloat($v('txtY')));
      pnt = pnt.convertToGeographicCoords();
      //pnt = new Point(pnt.getY(),pnt.getX());
   } else if (type == 3 && selPoint) {
      pnt = new Point(parseFloat(selPoint[0]),parseFloat(selPoint[1]));

    }

   if (pnt!= null ) { //&& !pnt.isOutside(YAHOO.mapComponent.service.initialExtent)) {
      YAHOO.mapComponent.setLoading(resMan.get('lblLoadingImage'));
      YAHOO.mapComponent.service.dynamicLayers["point"] = createPointLayer(pnt);
      YAHOO.mapComponent.changeExtent(YAHOO.mapComponent.service.initialExtent.centerToPoint(pnt).zoomByFactor(6),true);
   } else {
      alert(resMan.get('lblWrongCoords'));
   }

   $('toponymBox').style.display = "none";
   $('latLonBox').style.display = "none";
   $('xyBox').style.display = "none";

};

function localizeLabels() {
   var lbls = document.getElementsByTagName('LABEL');
   for (var i=0;i<lbls.length;i++) {
      lbls[i].innerHTML = resMan.get(lbls[i].id);
   }

   lbls = document.getElementsByTagName('BUTTON');
   for (var i=0;i<lbls.length;i++) {
      lbls[i].innerHTML = resMan.get(lbls[i].id);
   }

};

var service = null;

var searchPanel = null;




YAHOO.util.Event.onDOMReady(initialize);  


function $v(id){
	return document.getElementById(id).value;
}


function searchXEE() {

      var where = "";
	
      if ($v('txtXEENum')) {
       where += " XEENUM Like '" + $v('txtXEENum') + "%' AND";
     } 

      if ($v('txtXEETitle')) {
       where += (lang=='el'?" TITLE_GR": "TITLE_EN") + " Like '%" + $v('txtXEETitle') + "%' AND";
     } 
 
	
     if ($('ddlXEEScale').options[$('ddlXEEScale').selectedIndex].value!="-1") {
     var scale = $('ddlXEEScale').options[$('ddlXEEScale').selectedIndex].value;
     where += " SCALE =" + scale + " AND";
	}
      

     if ($v('txtXEEYearFirst')) {
       where += " YR1ST =" + $v('txtXEEYearFirst') + " AND";
     } 

     if ($v('txtXEEYearLast')) {
       where += " YRLAST =" + $v('txtXEEYearLast') + " AND";
     } 

	where = where.substring(0,where.length-3);

      var qry = '<SPATIALQUERY where="'+where+'" subfields="#ALL#">';
      qry += '</SPATIALQUERY>';

      var lr = '<LAYER type="featureclass" name="select layer" visible="true" id="select">';
      lr += '<DATASET fromlayer="'+YAHOO.mapComponent.service.getLayerId('XEE')+'"/>';
      lr += qry;
      lr += '<GROUPRENDERER>';
      lr += '<SIMPLERENDERER>';
      lr += '	  <SIMPLEPOLYGONSYMBOL boundarytransparency="1,0" filltransparency="1,0" filltype="bdiagonal" fillcolor="255,200,0" boundarycaptype="round" />';
      lr += '</SIMPLERENDERER>';
      lr += '<SIMPLELABELRENDERER field="MAP_NO">';
      lr += ' <TEXTSYMBOL antialiasing="true" font="Arial" fontstyle="regular" fontcolor="255,255,255" fontsize="10" glowing="255,0,0" />';
      lr += '</SIMPLELABELRENDERER>';
      lr += '</GROUPRENDERER>';
      lr += '</LAYER>';
      YAHOO.mapComponent.service.dynamicLayers["select_XEE"] = lr;

      YAHOO.mapComponent.service.queryFeatures("<LAYER id='"+YAHOO.mapComponent.service.getLayerId('XEE')+"'/>"+qry,null,0, function(recs,res) {
       var tabView = new YAHOO.widget.TabView('featuresGrid');
       var fields = YAHOO.mapConfig.layers[res.layer].select;

         var content = "<div id='datagrid_container_"+res.layer+"'></div>";

         var tb = new YAHOO.widget.Tab({ label: resMan.get("layer_"+res.layer), content: content }) ;
         tabView.addTab(tb);
         tabView.activeIndex = 1;

         var colDef = [];
                 
                  var ds = new YAHOO.util.DataSource(res.results);
                  ds.responseType = YAHOO.util.DataSource.TYPE_JSARRAY;
                  ds.responseSchema = {fields: []};
 
                  for (var fi=0;fi<fields.length;fi++){
                        var k = fields[fi];
                        var fld = {key:k.key,label:resMan.get(res.layer+"."+k.key),sortable:true};
                        if (k.formatter) {
                           fld.formatter = k.formatter;
                        }
                        if (k.width) {
                           fld.width = k.width;
                        }
			if (k.label) {
			   fld.label = k.label;
			}


                        colDef.push(fld);
                     ds.responseSchema.fields.push(k.key);
                  }

                  ds.responseSchema.fields.push("minx");
                  ds.responseSchema.fields.push("miny");
                  ds.responseSchema.fields.push("maxx");
                  ds.responseSchema.fields.push("maxy");

      myDataTable = new YAHOO.widget.DataTable("datagrid_container_"+res.layer,colDef,ds);
      tabView.set("activeTab",tb);
	   	   },'XEE');
   


   YAHOO.mapComponent.refreshImage();
searchPanel.hide();
};

function clearXEE() {
	$('txtXEENum').value = '';
	$('txtXEETitle').value = '';
	$('txtXEEYearFirst').value = '';
	$('txtXEEYearLast').value = '';
};

function searchLayer(layer) {
	if (layer == 'xee') {
		$('xee').style.display="block";
		$('enc').style.display="none";
	} else {
		$('xee').style.display="none";
		$('enc').style.display="block";
	}

	 searchPanel.show();
};


function populateDropDown(ddl,url,request) {
   var elem = document.getElementById(ddl);
	
   for (var i = (elem.options.length-1); i >= 0; i--){
		elem.options[i]=null;
   }

   var opt = document.createElement("OPTION")
   opt.text = resMan.get("lblSelectOne");
   opt.value = "-1";
   elem.options.add(opt)


   var myDataSource = new YAHOO.util.DataSource(url);
   myDataSource.responseType = YAHOO.util.DataSource.TYPE_JSON;
        myDataSource.responseSchema = {
            resultsList:"ResultSet.Result",
            fields: ["id","name"]
   };

   var oCallback = {
	   success: function(oRequest,oResponse,oPayload) {
         for (var i=0;i<oResponse.results.length;i++) {
            var re = oResponse.results[i];
            var opt = document.createElement("OPTION")
            opt.text = re.name;
            opt.value = re.id;
            elem.options.add(opt)
         }
      },
   	failure: function(oRequest,oResponse,oPayload) {
	   	alert("Unable to load data for " + ddl);
   	},
	   scope: this
   }
   myDataSource.sendRequest(request, oCallback.success);
};


function init() {

   createMainToolbar();
   createWaypointsToolbar();
   bindToolbars();

   localizeLabels();

   YAHOO.util.Event.addListener(phi_lambda_int_ids, "keydown", suppress_non_digits);
   YAHOO.util.Event.addListener(phi_lambda_float_ids,"keydown", suppress_non_float_digits);
   YAHOO.util.Event.addListener(window,'resize',handle_resize);

   YAHOO.mapComponent.setLoading(resMan.get('lblInitializing'));
   YAHOO.mapComponent.doLayout();

     service = new YAHOO.mapService.ImsService('xee_map_am_'+lang,'xee_map_am_'+lang);
   service.initService(function(env) {
      YAHOO.mapComponent.service = service;
      YAHOO.mapComponent.currentEnvelope = env
      YAHOO.mapComponent.refreshImage();
      YAHOO.mapTOC.service = service;
      YAHOO.mapTOC.component = YAHOO.mapComponent;
      YAHOO.mapTOC.refresh();
   });


   initialize_autocomplete();

 populateDropDown('ddlXEEScale','/servlet/getScale.jsp?','type=scale');

   searchPanel = new YAHOO.widget.Panel("searchByMetadata", {
	width:"350px", 
	fixedcenter: true, 
	constraintoviewport: true, 
	underlay:"shadow", 
	modal:true,
	close:true, 
	visible:false, 
	draggable:true} );
   searchPanel.render();


   
};

function initialize() {
	_init_component();
	init();
};


function searchEnc () {
};

function clearEnc () {
};

