Portal.Portlet.ResultsSearchController = Portal.Portlet.extend({

	init: function(path, name, notifier) {
		var oThis = this;
		console.info("Created ResultsSearchController");
		this.base(path, name, notifier);
	},	
		
	send: {
		'ResetSendTo': null,
		'LastQueryKey': null,
		'needSavedSelectedItemCount': null
	},
		
	listen: {
		
		/* messages from message bus*/
		
		'Cmd' : function(sMessage, oData, sSrc) {
			this.ProcessCmd(sMessage, oData, sSrc);
		},		
		
		// when result citations are selected, the list of selected ids are intercepted here
		'SelectedItemCountChanged' : function(sMessage, oData, sSrc){
			Portal.Portlet.ResultsSearchController.selectedItemCount = oData.count * 1;
		},
		
		// for SendTo File (processing after getting any initial selected item count from DbConnector)
		'SavedSelectedItemCount' : function(sMessage, oData, sSrc) {
			var SavedSelectedItemCount = oData.count;
			
			this.ProcessSavedSelectedItemCount(SavedSelectedItemCount, sMessage, oData, sSrc);
		},
		
		'RunLastQuery' : function(sMessage, oData, sSrc){
			if (this.getInput("RunLastQuery")){
				this.setValue ("RunLastQuery", 'true');
			}
		}
		
	},//listen
	
	ProcessCmd: function(sMessage, oData, sSrc){
    	Portal.Portlet.ResultsSearchController.cmd = oData.cmd;
	
		if (oData.cmd == 'Link'){
			if (this.getInput("LastQueryKey")){
				this.send.LastQueryKey({'qk': this.getValue("LastQueryKey")});
			}
		}
		else if (oData.cmd == 'File'){
			// asks for initial selected items count from dbconnector
			this.send.needSavedSelectedItemCount();
		}
		else if (oData.cmd == 'My NCBI Collections'){
			// asks for initial selected items count from dbconnector
			this.send.needSavedSelectedItemCount();
		}
	}, // ProcessCmd
	
	ProcessSavedSelectedItemCount: function(SavedSelectedItemCount, sMessage, oData, sSrc){
	    // get the count of items about to be processed 
	    var Count;
		if (Portal.Portlet.ResultsSearchController.selectedItemCount > 0){
			Count = Portal.Portlet.ResultsSearchController.selectedItemCount;
		}
		else if (SavedSelectedItemCount > 0){
			Count = SavedSelectedItemCount;
		}
		else{
			Count = this.getValue("ResultCount");
		}
		
	    if (Portal.Portlet.ResultsSearchController.cmd == 'My NCBI Collections'){
	        this.ProcessSavedItemsForCollections (Count, oData);
	    }
		else if (Portal.Portlet.ResultsSearchController.cmd == 'File'){
			this.ProcessSavedItemsForFile (Count, oData);
		}
	}, // ProcessSavedSelectedItemCount
	
	ProcessSavedItemsForCollections: function(Count, oData){
		// show message if item count is above limit
		if(Count > Portal.Portlet.ResultsSearchController.upperLimit){
		    // create message
			var message = "The maximum number of records that can be added to a My NCBI Collection is " 
			+ Portal.Portlet.ResultsSearchController.upperLimitText 
			+ ".\n"
			+ "Are you sure you want to save the first "
			+ Portal.Portlet.ResultsSearchController.upperLimitText
			+ " records to a Collection?\n";
			
			// if user confirms they want to add items, let them proceed to MY NCBI, otherwise cancel
    		if(confirm(message)){
    			Portal.requestSubmit(); 
    		}
    		else{
    			this.send.ResetSendTo({'value': ''});
    		}
		}
		else{
		    Portal.requestSubmit(); 
		}
		
	}, //ProcessSavedItemsForCollections
	
	ProcessSavedItemsForFile: function(Count, oData){
	    
		console.info("Count before send to file: " + Count);
		if (Count > Portal.Portlet.ResultsSearchController.upperLimit){
			if(confirm('Are you sure you want to download ' + Count + ' records?')){
				Portal.requestSubmit(); 
			}
			else{
				this.send.ResetSendTo({'value': ''});
			}
		}
		else{
			Portal.requestSubmit(); 
		}
	} //ProcessSavedItemsForFile

},
{
	selectedItemCount: 0,
	upperLimit: 5000,
	upperLimitText: '5,000',
	cmd: ''
});

//
//		 Gene_ResultsSearchController: Describe portlet here
//

//		 Notes:
//		   - text commented as // are instructions and hints to the programmer
//		   - replace text commented as /* */ with your code
//		   - please retain uncommented code

		Portal.Portlet.Gene_ResultsSearchController = Portal.Portlet.ResultsSearchController.extend({

		   // Init function.
		   // init() called when page loads. Required for all portlet JS objects.
		   //
		   init: function(path, name, notifier) {
		      //var oThis = this;  // Use <oThis> instead of <this> for registering callbacks
		      console.info("Created derived ResultsSearchController - Gene");
		      this.base(path, name, notifier);  // Call superclass constructor
           }
		});

// Client-side class for Index portlet
//

Portal.Portlet.Gene_LimitsTab = Portal.Portlet.extend({
    
  init: function(path, name, notifier) {
      var oThis = this;
      this._last = 0;
      this.base(path, name, notifier);
      this._chromosome_limit = $('chromosome_limit');
      this._list = $('orgTaxInfoList') || $('orgTermList');
      if (this._list && 
         ($('orgTerm') && $('orgTerm').value.length  > 0)) {
         this.checkOrgKey(this._list);  
         if (this._list == $('orgTaxInfoList')){
	       this.fillChromosomeList();
	     }  
      }
    },  
    
      listen: {
      
      "chromosome<change>" : function(event, target, name){
           var sel = $('chromosome');
           var val = sel[sel.selectedIndex].value;
           var _array = val.split("|");         
           this.setValue("chr_to", _array.pop());
         },
    
        // non-DCMS or DCMS user typing ahead...
        "orgTerm<keypress>": function(event, target, name) {
      	if (this._list){
          this.checkOrgKey(this._list);
        }
        // Ignore <return>
        if ((event.keyCode || event.which) == 13) {
           event.preventDefault();
        }
      },
        // non-DCMS needs orgTerm updated
        "orgTaxInfoList<change>": function(event, target, name) {
           this.update(target);
           if ($('current_chrom') != "" ){
               this.setValue("current_chrom", "");
           }    
           this.fillChromosomeList();
        },
        
        //DCMS user needs orgTerm updated
        "orgTermList<change>": function(event, target, name) {
           this.update(target);
      },
        //  DCMS user clicked to add OrgTerm
        "dcms_addOrgTerm<click>": function(e, target, src) {
        var theOrgTerm = '"' + this.getOrgTerm() + '"' ;
        this.send.TermLogicalOp({'op': "AND", 'key': theOrgTerm + '[Organism]' });
        setAll('TaxonTable', false);
        
      },
      
      "orgClear<click>": function(e,target,src){
      
        document.forms[0].orgTerm.value ='';
        var sel = document.getElementById('chromosome');
        sel.options.length = 0;
        sel.innerHTML = '';
        this.showChromosomes("hidden");
        sel = document.getElementById('orgTaxInfoList');
        sel.selectedIndex = -1;
        this.setValue("chr_from", "");
        this.setValue("chr_to", "");
        this.setValue("current_chrom", "");
       
      },
      
      // so limits message contains the full match name
      'Cmd':function(sMessage,oData,sSrc){
          if (oData.cmd == 'Go' && (this._list != null) && 
          (this._list == $('orgTaxInfoList')) && this._list.selectedIndex > -1){
             this.update(this._list);
          }      
       }      
      
    },
      // this for DCMS to add org term to query box
      send: {
    TermLogicalOp: null
        },
        
               
	  // Schedule call to get chromosome list
      fillChromosomeList: function() {
         // Clear previous timer
        try {
           clearTimeout(Portal.Portlet.Gene_LimitsTab.timerObj);
        } catch (e) { }

        // Set new timer
        var oThis = this;
        Portal.Portlet.Gene_LimitsTab.timerObj =
          setTimeout(function() { oThis.getChromosomes();}, 500); // Return immediately
      },
      
      // get the chroms for non-DCMS query 
      getChromosomes: function () {
        var taxaInfo = this.getTaxInfo();
        this.showChromosomes("loading");

        var args = {
          "taxid":          taxaInfo.id
        };
        var site = document.forms[0]['p$st'].value;

        // Issue asynchronous call to xmlhttprequest service
        var resp = xmlHttpCall(site, this.path, "GetChrom4TaxIdByHttp", args, this.receive, {"org" : taxaInfo.name}, this);  
      },
      
      //for non DCMS-user get the tax info to pass to getChromosomes 
      getTaxInfoOld: function (){
      
      var sel = document.forms[0].orgTaxInfoList;
      var idx = -1;
      var taxid= '';
      var name = '';
      if(sel != null ){
        idx = sel.selectedIndex; 
      } 
      if(idx >= 0){
        for ( ; idx >= 0; idx = sel.selectedIndex){
          if(sel.options[idx].selected) {
            taxid = sel.options[idx].value;
            name = sel.options[idx].id;
            sel.options[idx].selected=false;
            //this is for IE stupidity
            if (sel.type == "select-one"){
              sel.selectedIndex = -1;
            } 
          } 
        } 
      } 
      return {"id": taxid, "name" : name};
    },
      getTaxInfo: function (){
      
      var sel = document.forms[0].orgTaxInfoList;
      var idx = -1;
      var taxid= '';
      var name = '';
      if(sel != null ){
        idx = sel.selectedIndex; 
      } 
      if(idx >= 0){
         name = sel.options[idx].id;
         taxid = sel.options[idx].value;       
      } 
      return {"id": taxid, "name" : name};
    },
      // for DCMS user 
      
      getOrgTerm: function () {
      var sel = document.forms[0].orgTermList;
      var idx = -1;
      var oterm = '';
      if(sel != null ){
        idx = sel.selectedIndex; 
      }
      if(idx >= 0){
        for ( ; idx >= 0; idx = sel.selectedIndex){
          if(sel.options[idx].selected) {
            oterm = sel.options[idx].value;
            sel.options[idx].selected=false;
            //this is for IE stupidity
            if (sel.type == "select-one"){
              sel.selectedIndex = -1;
            }
          }
        }
      }
      return oterm;
    },
      
      
      // receive xmlhttprequest for non-dcms user chrom limit
      receive: function(responseObject, userArgs) {
		 
         //resp is a JSON where the result is in theChromosomes 
         var resp = eval( "(" + responseObject.responseText + ")" );
         
         // theChromosomes is a string containing an JSON array
         var chromosomes = eval( "("+ (resp.theChromosomes || "[]") +")" );
         var theList = $('chromosome');

	     // Clear the list and refill it
	     theList.options.length = 0;
         var i = 0;      
         for (var i = 0; i < chromosomes.length; i++) {
           var chr = chromosomes[i];
           console.info("Chr " + i +": " + chr);
      	   theList.options[i] = new Option(chr[1], chr[0]);	   
         }
         theList.disabled = false;
      	 this.showChromosomes(theList.options.length > 0 ? "enabled" : "none");
      	 if (theList.options.length > 0) { 
      	 	 var prev_chrom = this.getValue("current_chrom");
      	 	 if (prev_chrom){
      	 	 	for (var ixi = 0; ixi < theList.options.length; ++ixi) {
      	           if (theList.options[ixi].value == prev_chrom){
      	               theList.selectedIndex = ixi;
      	               break;
      	            }
      	        }
      	 	  }
      	 	  else {	
      	         var _array = theList.options[0].value.split("|");         
                 this.setValue("chr_to", _array.pop());
                 if (this.getValue("chr_from") == "" || this.getValue("chr_from") == "0"){
                   this.setValue("chr_from", "1");
                 }
             }
             //this.update(this._list);
        }        
    },
    
	// Set class for chromosome_limit that indicates chromosome load state
    showChromosomes: function(className) {
       var classes = ["none", "hidden", "loading", "enabled"];
       
       for (var i = 0; i < classes.length; i++) {
          utils.removeClass(this._chromosome_limit, classes[i]);
       }
       utils.addClass(this._chromosome_limit, className);
    },
    
      checkOrgKey: function (list) {
      if (!list) { return; }
      var form = document.forms[0];
      // orgTerm is the text area name in both dcms & non-dcms forms
      var field = document.forms[0].orgTerm;
      //var list = document.forms[0].listname.value;
      var str = field.value.toLowerCase();
      
      if (str == "") {
        this.select(list, 0);
        this._last = 0;
        return;
      }
      if (str.length == 1){
        var let = str.charAt(0);
        var i = this.firstLetterBinSrch(let, list);
        if (i != -1){
          while (i != 0 && (list.options[i].text.toLowerCase().charAt(0)) == let){
            if (i > 0) {
              --i;
             }             
          }
          if (i > 0) this._last = ++i;
    
          this.select(list, i);
         
          return;
        }
      }
      
      for (var i = this._last; i < list.options.length; ++i) {
        if (list.options[i].text.toLowerCase().indexOf(str) == 0) {
          this._last = i;
          this.select(list, i);
          
          return;
        }
      }
    },
      
      firstLetterBinSrch: function(letter, list) {
      
      var form = document.forms[0];
      var field = form.orgTerm;
      
      var start = 0;
      var stop =  list.options.length;
      var offset = 0;
      var index = -1;
      var str = list.options[start].text.toLowerCase();
      
      while (start <= stop){
        offset = parseInt(((start + stop)/2));
        str = list.options[(start+offset)].text.toLowerCase();
        if (letter == str.charAt(0)) {
          index = (start+offset);
          break;
        }
        else if (letter < str.charAt(0)){
          --stop;
          
        }
        else if (letter > str.charAt(0)){
          ++start;
        }    
      }
      return index;
    },
      
      
    update: function (list) {
      var form = document.forms[0];
      var field = form.orgTerm;
      field.value = list.options[list.selectedIndex].text;
    },
      
    select: function (list, i) {
      if (list.selectedIndex != i) {
         list.selectedIndex = i;
         if (list == $('orgTaxInfoList')){
           this.fillChromosomeList();  // <change> doesn't fire if you set this manually
         }
       
      }
    }
  
  });



function fmtY(y) {if(y<1900) y+=1900; return y;}
function fmtM(m) {m++; if(m<10) m='0'+m; return m;}
function fmtD(d) {if(d<10) d='0'+d; return d;}

function OnRelDateChange(field)
{
 // get field_index - we'll need it to access adjacent elements[]
 var el = document.forms[0].elements;
 for(field_index=0;field_index<el.length;field_index++) {
   if(el[field_index]==field) break;
 }

 var v=field.options[field.selectedIndex].value.toLowerCase();
 if(v.length==0) {
   // 1st line (e.g. "Publication Date") selected: clear the range
   for(j=1;j<=6;j++) el[field_index+j].value="";
   return;
 }

 // convert the string like "X Days/Weeks/Months/Years" to (d,m,y) deltas
 var arr=v.split();
 var n=1; // the number of time units - could be anywhere in the string
 for(j=0;j<arr.length;j++) {
  var t=parseInt(arr[j]);
  if(t>0 && !isNaN(t)) {n=t;break;}
 }
 var y=0,m=0,d=0;
 if     (v.indexOf("week" )>=0) d=n*7;
 else if(v.indexOf("month")>=0) m=n;
 else if(v.indexOf("year" )>=0) y=n;
 else if(v.indexOf("today")< 0) d=n; // else: all remain 0, which makes "today" range

 // To = today
 var dt = new Date();
 el[field_index+4].value=fmtY(dt.getYear ());
 el[field_index+5].value=fmtM(dt.getMonth());
 el[field_index+6].value=fmtD(dt.getDate ());

 // From = today - (y,m,d)
 var msPerDay=24.0*3600.0*1000.0;
 if(m>dt.getMonth()) {y=1;m=m-12;}
 dt.setTime (      dt.getTime ()  - d*msPerDay );
 dt.setMonth(      dt.getMonth()  - m );
 dt.setYear ( fmtY(dt.getYear ()) - y ); // in 2000, Netscape's getYear() returns 100
 el[field_index+1].value=fmtY(dt.getYear ());
 el[field_index+2].value=fmtM(dt.getMonth());
 el[field_index+3].value=fmtD(dt.getDate ());
}


// Clear all checkboxes inside target node
function setAll(nodeName, value)
{   if (!document.getElementById) return false   
      var node= document.getElementById(nodeName)  
      
      if (node) {   
        var cbs = node.getElementsByTagName("INPUT") 
        for (var i = 0; i < cbs.length; i++){
          var cb = cbs[i]     
          if (cb.getAttribute("TYPE").toUpperCase() == "CHECKBOX") {
            cb.checked = value   
          } else {   
            cb.value = ""; 
          }
        }
      }
  return false;
}

      

// for DCMS to toggle the org limit style
function toggle_menu () {
  
  var sel = document.forms[0].orgstyle; 
  
  for (var i=0; i < sel.length; ++i){
    if (sel.options[i].selected == true){
      var sel_div  = document.getElementById(sel.options[i].value);
      if (sel.options[i].value.indexOf("OrgsInScope") == 0){
        setAll('TaxonTble', false);
      }
      //sel_div.style.position = "absolute";
      sel_div.style.visibility = "";
      sel_div.style.display = "block";
      //sel_div.style.top = "350px";
      //sel_div.style.left = "150px";
      //sel_div.style.z-index ="1";
    }
    else {
      var sel_div  = document.getElementById(sel.options[i].value);
      //sel_div.style.position = "absolute";
      sel_div.style.visibility = "hidden";
      sel_div.style.display = "none";
      //sel_div.style.top = "0px";
      //sel_div.style.left = "0px";
      //sel_div.style.z-index = "0";
    }
  }
}

Portal.Portlet.MessageBar = Portal.Portlet.extend ({
	init: function (path, name, notifier)
	{
		this.base (path, name, notifier);
	},
	
	send: {
		"TabCmd": null,
		"Cmd": null,
		"Term": null
	},
	
	listen: {
		//upon clicking 'see details', sends name of details tab.
		"Details<click>":  function(e, target, name) {
			this.send.TabCmd({'tab': this.getValue("Details:tab")});
		},
		
		"CorrectedQuery<click>": function(e, target, name) {
		    this.send.Term ({'term': target.getAttribute('term')})
		    this.send.Cmd ({'cmd': 'CorrectSpelling'})
		}
	}
});

Portal.Portlet.Entrez_DisplayBar = Portal.Portlet.extend({

	init: function(path, name, notifier) {
		console.info("Created DisplayBar");
		this.base(path, name, notifier);
		
		// save the original display/presentation value when page loads
		Portal.Portlet.Entrez_DisplayBar.originalPresentation = this.getValue("LastPresentation");
		console.info("Original Presentation is: " + Portal.Portlet.Entrez_DisplayBar.originalPresentation);
		
	},
	
	
	send: {
   
   		'PresentationChange': null,
		'TabCmd': null,
		'Cmd': null, 
		'PageSizeChanged': null
	},
	
	
	
	listen: {
		
		/* browser events */
			
		"sPresentation<change>": function(e, target, name){
			//get attribute values of selected option
			var dbfrom = target.options[target.selectedIndex].getAttribute('dbfrom');
			var dbto = target.options[target.selectedIndex].getAttribute('dbto');
			var cmd = target.options[target.selectedIndex].getAttribute('cmd');
			var readablename = target.options[target.selectedIndex].getAttribute('readablename');
			
			//call function to process
			this.ProcessPresentationChange(dbfrom, dbto, cmd, readablename, e, target, name);
		},
		
		
		"sPageSize<change>": function(e, target, name){		
			this.ProcessPageSizeChange(e, target, name);
		},
		
		
		"sSort<change>": function(e, target, name){
			this.ProcessSortChange(e, target, name);
		},
		
		
		"sSendTo<change>": function(e, target, name){
			var sendto = target.value;
			this.setValue("SendTo", sendto);
			
			this.SendToChanged(sendto, e, target, name); 
		},
		
		
		/* messages from message bus*/
		
		'Cmd' : function(sMessage, oData, sSrc) {
		    this.ProcessCmdChange(sMessage, oData, sSrc);
		},
		
		'ResetSendTo' : function(sMessage, oData, sSrc) {
			this.setValue("SendTo", oData.value);
				// reset sendto in selector
			var sSendToInputs = this.getInputs("sSendTo");
			for (var j = 0; j < sSendToInputs.length; j++){
				sSendToInputs[j].value = '';
			}
		},
		
		'newPresentation' : function(sMessage, oData, sSrc) {
			this.setValue("Presentation", oData.value);
		},
		
		'newPageSize' : function(sMessage, oData, sSrc) {
			this.setValue("PageSize", oData.value);
		},
		
		'newSort' : function(sMessage, oData, sSrc) {
			this.setValue("Sort", oData.value);
		}
	
	},
	
	ProcessPresentationChange: function(dbfrom, dbto, cmd, readablename, e, target, name) {		
		//send Cmd
		this.send.Cmd({
			'cmd': cmd
		});
		
		//Send link information and cmd
		this.send.PresentationChange({
			'dbfrom': dbfrom,
			'dbto': dbto,
			'linkname': target.value,
			'readablename': readablename
		});	
		
		// set Presentation
		this.setValue("Presentation", target.value);
	},
	
	
	ProcessPageSizeChange: function(e, target, name){
		//send Cmd
		this.send.Cmd({
			'cmd': target.getAttribute('cmd')
		});	
		//send PageSizeChanged
		this.send.PageSizeChanged({
			'size': target.value
		});	
		//set PageSize
		this.setValue("PageSize", target.value);
	},
	
	
	ProcessSortChange: function(e, target, name){
		//send Cmd
		this.send.Cmd({
			'cmd': target.getAttribute('cmd')
		});	
		//set Sort
		this.setValue("Sort", target.value);
	},
	
	
	SendToChanged: function(sendto, e, target, name) {
		if(sendto == 'Remove from Clipboard'){
			if(confirm('Are you sure you want to delete these items from Clipboard?')){
				this.send.Cmd({'cmd': sendto});
				document.forms[0].submit();
			}
			else{
				this.setValue("SendTo", '');
				// reset sendto in selector
				var sSendToInputs = this.getInputs("sSendTo");
				for (var j = 0; j < sSendToInputs.length; j++){
					sSendToInputs[j].value = '';
				}
			}
		}
		else if(sendto == 'File'){
			this.send.Cmd({'cmd': sendto});
		}
		else if(sendto == 'Mail'){
			this.send.Cmd({'cmd': sendto});
			this.send.TabCmd({'tab': 'E-mail'});
			document.forms[0].submit();
		}
		else if(sendto == 'My NCBI Collections'){
			this.send.Cmd({'cmd': sendto});
		}
		else if(sendto == ''){
			this.send.Cmd({'cmd': sendto});
		}
		else{
			this.send.Cmd({'cmd': sendto});
			document.forms[0].submit();
		}
	},
	
	'ProcessCmdChange': function(sMessage, oData, sSrc){
	    if (oData.cmd == 'PageChanged'){
			/* Reset Send To on page change to avoid sendto having previous value due to 
			using browser back button after viewing text format reports.*/
			this.setValue("SendTo", '');
				// reset sendto in selector
			var sSendToInputs = this.getInputs("sSendTo");
			for (var j = 0; j < sSendToInputs.length; j++){
				sSendToInputs[j].value = '';
			}
		}
		
		this.BackButtonCompatibilityForCmdChange(oData.cmd);
	},
	
	'BackButtonCompatibilityForCmdChange': function(cmd){
	    // for back button compatibility, keep presentation to old value for any cmds 
			// except when cmd indicates value was changed from DisplayBar.
		if (cmd != 'DisplayChanged' && cmd != 'Link' && cmd != 'SendMail'){
			// set Presentation
			this.setValue("Presentation", Portal.Portlet.Entrez_DisplayBar.originalPresentation);
		}
	}
},
{
	originalPresentation: ''
});


Portal.Portlet.Gene_DisplayBar = Portal.Portlet.Entrez_DisplayBar.extend({

	init: function(path, name, notifier) {
		this.base(path, name, notifier);
	}
});




Portal.Portlet.SearchController = Portal.Portlet.extend({
   
   init: function(path, name, notifier) {
      console.info("Created SearchController");
      this.base(path, name, notifier);
   },
   
   listen: {
   
		'QueryKey' : function(sMessage, oData, sSrc) {
			this.ReceivedQueryKey(sMessage, oData, sSrc);
		},
        
        'scTerm' : function(sMessage, oData, sSrc) {
			this.ReceivedTerm(sMessage, oData, sSrc);
        }
    },
   
    ReceivedQueryKey : function (sMessage, oData, sSrc){
       this.setValue('QueryKey', oData.qk);
    },
   
    ReceivedTerm : function (sMessage, oData, sSrc){
       this.setValue('Term', oData.term);
    }
});

Portal.Portlet.CommandTab = Portal.Portlet.extend ({
	init: function (path, name, notifier)
	{
		 console.info ("Created CommandTab");
		this.base (path, name, notifier);
	},
	
	send: {
		"Cmd": null,
		"TabCmd": null
	},
	
	listen: {
		//upon click on tab, sends name of tab that was clicked,
		// and the command that indicates that a tab was clicked.
		"Tab<click>":  function(e, target, name) {
			this.send.TabCmd({'tab': target.getAttribute("tab")});
			this.send.Cmd({'cmd': 'CommandTabClicked'});
		},
		
	
		"LimitCheckBox<click>":  function(e, target, name) {
			console.info ("LimitsActive: " + this.getValue("LimitsActive"));
			if (target.checked){
				this.setValue("LimitsActive", 'true');
				console.info ("LimitsActive: " + this.getValue("LimitsActive"));
			}
			else{
				this.setValue("LimitsActive", 'false');
				console.info ("LimitsActive: " + this.getValue("LimitsActive"));
			}
				
		},
		
		'PreserveTabCmd' : function(e, target, name) {
			this.send.TabCmd({'tab': this.getValue("LastTabCmd")});	
		}
	}
});

Portal.Portlet.DbConnector = Portal.Portlet.extend({

	init: function(path, name, notifier) {
		var oThis = this;
		console.info("Created DbConnector");
		this.base(path, name, notifier);
		
		// reset Db value to original value on page load. Since LastDb is the same value as Db on page load and LastDb is not changed on
		// the client, this value can be used to reset Db. This is a fix for back button use.
		if (this.getValue("Db") != this.getValue("LastDb")){
		    this.setValue("Db", this.getValue("LastDb"));
		}
     
		// the SelectedIdList and id count from previous iteration (use a different attribute from IdsFromResult to prevent back button issues)
		Portal.Portlet.DbConnector.originalIdList = this.getValue("LastIdsFromResult");
		console.info("originalIdList " + Portal.Portlet.DbConnector.originalIdList);
		// if there is an IdList from last iteration set the count
		if (Portal.Portlet.DbConnector.originalIdList != ''){
			Portal.Portlet.DbConnector.originalCount = Portal.Portlet.DbConnector.originalIdList.split(/,/).length;
		}

		notifier.setListener(this, 'HistoryCmd', 
        	function(oListener, custom_data, sMessage, oNotifierObj) {
           		var sbTabCmd = $N(oThis.path + '.TabCmd');
           		sbTabCmd[0].value = custom_data.tab;
        	}
    		, null);
    
	},

	send: {
   		'SelectedItemCountChanged': null,
   		'newUidSelectionList': null,
   		'SavedSelectedItemCount': null
	},

	listen: {
	
		//message from Display bar on Presentation change 
		'PresentationChange' : function(sMessage, oData, sSrc){
			
			// set link information only if it exists
			if (oData.dbfrom){
				console.info("Inside PresentationChange in DbConnector: " + oData.readablename);
				this.setValue("Db", oData.dbto);
				this.setValue("LinkSrcDb", oData.dbfrom);
				this.setValue("LinkName", oData.linkname);
				this.setValue("LinkReadableName", oData.readablename);
			}
			//document.forms[0].submit();
		},
		
		// various commands associated with clicking different form control elements
		'Cmd' : function(sMessage, oData, sSrc){
			console.info("Inside Cmd in DbConnector: " + oData.cmd);
			this.setValue("Cmd", oData.cmd);
			
			// back button fix, clear TabCmd
			if (oData.cmd == 'Go' || oData.cmd == 'PageChanged' || oData.cmd == 'FilterChanged' || 
			oData.cmd == 'DisplayChanged' || oData.cmd == 'HistorySearch' || oData.cmd == 'Text' || 
			oData.cmd == 'File' || oData.cmd == 'Printer' || oData.cmd == 'Order' || 
			oData.cmd == 'Add to Clipboard' || oData.cmd == 'Remove from Clipboard' || 
			oData.cmd.toLowerCase().match('details')){
				this.setValue("TabCmd", '');
				console.info("Inside Cmd in DbConnector, reset TabCmd: " + this.getValue('TabCmd'));
			}

		},
		
		
		// the term to be shown in the search bar, and used from searching
		'Term' : function(sMessage, oData, sSrc){
			console.info("Inside Term in DbConnector: " + oData.term);
			this.setValue("Term", oData.term);
		},
		
		
		// to indicate the Command Tab to be in
		'TabCmd' : function(sMessage, oData, sSrc){
			console.info("Inside TABCMD in DbConnector: " + oData.tab);
			this.setValue("TabCmd", oData.tab);
			console.info("DbConnector TabCmd: " + this.getValue("TabCmd"));
		},
		
		
		// message sent from SearchBar when db is changed while in a Command Tab
		'DbChanged' : function(sMessage, oData, sSrc){
			console.info("Inside DbChanged in DbConnector");
			this.setValue("Db", oData.db);
		},
		
		// Handles item select/deselect events
		// Argument is { 'id': item-id, 'selected': true or false }
		'ItemSelectionChanged' : function(sMessage, oData, oSrc) {
			var sSelection = this.getValue("IdsFromResult");
			var bAlreadySelected = (new RegExp("\\b" + oData.id + "\\b").exec(sSelection) != null);
	       	var count =0;
	       	
			if (oData.selected && !bAlreadySelected) {
				sSelection += ((sSelection > "") ? "," : "") + oData.id;
			   	this.setValue("IdsFromResult", sSelection);
			   	if (sSelection.length > 0){
			   		count = sSelection.split(',').length;
			   	}
			   	this.send.SelectedItemCountChanged({'count': count});
			   	this.send.newUidSelectionList({'list': sSelection});
		   	} else if (!oData.selected && bAlreadySelected) {
				sSelection = sSelection.replace(new RegExp("^"+oData.id+"\\b,?|,?\\b"+oData.id+"\\b"), '');
		   	   	this.setValue("IdsFromResult", sSelection);
				console.info("Message ItemSelectionChanged - IdsFromResult after change:  " + this.getValue("IdsFromResult"));
			   	if (sSelection.length > 0){
			   		count = sSelection.split(',').length;
			   	}
				console.info("Message ItemSelectionChanged - IdsFromResult length:  " + count);   
				this.send.SelectedItemCountChanged({'count': count});
			   	this.send.newUidSelectionList({'list': sSelection});
		   	}
		},
				
		// FIXME: This is the "old message" that is being phased out.
		// when result citations are selected, the list of selected ids are intercepted here,
		// and notification sent that selected item count has changed.
		'newSelection' : function(sMessage, oData, sSrc){
		
			// Check if we already have such IDs in the list
			var newList = new Array();
			var haveNow = new Array();
			if(Portal.Portlet.DbConnector.originalIdList){
				haveNow = Portal.Portlet.DbConnector.originalIdList.split(',');
				newList = haveNow;
			}
			
			var cameNew = new Array();
			if (oData.selectionList.length > 0) {
				cameNew = oData.selectionList;
			}
			
			if (cameNew.length > 0) {
				for(var ind=0;ind<cameNew.length;ind++) {
					var found = 0;
					for(var i=0;i<haveNow.length;i++) {
						if (cameNew[ind] == haveNow[i]) {
							found = 1;
							break;
						}
					}
						//Add this ID if it is not in the list
					if (found == 0) {
						newList.push(cameNew[ind]);
					}
				}
			}
			else {
				newList = haveNow;
			}

				// if there was an IdList from last iteration add new values to old
			var count = 0;
			if ((newList.length > 0) && (newList[0].length > 0)){
				count = newList.length;
			}
			
			console.info("id count = " + count);
			this.setValue("IdsFromResult", newList.join(","));
			
			this.send.SelectedItemCountChanged({'count': count});
			this.send.newUidSelectionList({'list': newList.join(",")});
		},


		// empty local idlist when list was being collected for other purposes.
		//used by Mesh and Journals (empty UidList should not be distributed, otherwise Journals breaks)
		// now used by all reports for remove from clipboard function.
		'ClearIdList' : function(sMessage, oData, sSrc){
			this.setValue("IdsFromResult", '');
			this.send.SelectedItemCountChanged({'count': '0'});
			this.send.newUidSelectionList({'list': ''});
		}, 


		// back button fix: when search backend click go or hot enter on term field,
		//it also sends db. this db should be same as dbconnector's db
		'SearchBarSearch' : function(sMessage, oData, sSrc){
			if (this.getValue("Db") != oData.db){
				this.setValue("Db", oData.db);
			}
		},
		
		// back button fix: whrn links is selected from DisplayBar,
		//ResultsSearchController sends the LastQueryKey from the results on the page
		// (should not be needed by Entrez 3 code)
		'LastQueryKey' : function(sMessage, oData, sSrc){
			if (this.getInput("LastQueryKey")){
				this.setValue("LastQueryKey", oData.qk);
			}
		},
		
		'QueryKey' : function(sMessage, oData, sSrc){
			if (this.getInput("QueryKey")){
				this.setValue("QueryKey", oData.qk);
			}
		},
		
		
		//ResultsSearchController asks for the initial item count in case of send to file 
		'needSavedSelectedItemCount' : function(sMessage, oData, sSrc){
			var count = 0;
			if(this.getInput("IdsFromResult")){
				if (this.getValue("IdsFromResult").length > 0){
					count = this.getValue("IdsFromResult").split(',').length;
				}
				console.info("sending SavedSelectedItemCount from IdsFromResult: " + count);
			}
			else{
				count = Portal.Portlet.DbConnector.originalCount;
				console.info("sending SavedSelectedItemCount from OriginalCount: " + count);
			}
			this.send.SavedSelectedItemCount({'count': count});
		},
		
		// Force form submit, optionally passing db, term and cmd parameters
		'ForceSubmit': function (sMessage, oData, sSrc)
		{
		    if (oData.db)
    			this.setValue("Db", oData.db);
		    if (oData.cmd)
    			this.setValue("Cmd", oData.cmd);
		    if (oData.term)
    			this.setValue("Term", oData.term);
    		Portal.requestSubmit ();
		},
		
		'LinkName': function (sMessage, oData, sSrc){
		    this.setValue("LinkName", oData.linkname);
		}
		
	}, //listen
	
	/* other portlet functions */
	
	// DisplayBar in new design wants selected item count
	'SelectedItemCount': function(){
	    var count = 0;
		if(this.getInput("IdsFromResult")){
			if (this.getValue("IdsFromResult") != ''){
				count = this.getValue("IdsFromResult").split(',').length;
			}
		}
		else{
			count = Portal.Portlet.DbConnector.originalCount;
		}
		return count;
	}
		
},
{
	originalIdList: '',
	originalCount: 0
});

function getEntrezSelectedItemCount() {
    return $PN('DbConnector').SelectedItemCount();
}

Portal.Portlet.SearchBar = Portal.Portlet.extend ({
  
	init: function (path, name, notifier) {
		console.info ("Created SearchBar"); 
		this.base (path, name, notifier);

        Portal.Portlet.SearchBar.originalTerm = this.getValue("Term");
        Portal.Portlet.SearchBar.originalDb = this.getValue("Db");
        
        // listen for autocomplete selection event 
        var AutoCompSelectFnc = function(){ 
            Portal.$send('AutoCompSelect'); 
        } 
        jQuery("#search_term").bind("ncbiautocompleteenter", AutoCompSelectFnc ).bind("ncbiautocompleteoptionclick", AutoCompSelectFnc ); 

	},

	// Define message sender methods here.
	// If you just want to send a message the standard way, simply
	// supply "null" as the implementation. 
	// 
	send: {
		"Cmd": null,
		"Term": null,
		"TabCmd": null,
		"DbChanged": null, 
		"SearchBarSearch": null,
		"AutoCompSelect": null
	},

	// Define messages and events
	listen: {

		// Global message bus
		'IndexLogicalOp': function(sMessage, oData, sSrc) {
		    this.ReceivedIndexLogicalOp(sMessage, oData, sSrc);
		},

		'TermLogicalOp': function(sMessage, oData, sSrc) {
		    this.ReceivedTermLogicalOp(sMessage, oData, sSrc);
		},

		'LimitsGoClicked': function(sMessage, oData, sSrc) {
            this.ReceivedLimitsGoClicked(sMessage, oData, sSrc);
		},

		'Cmd': function(sMessage, oData, sSrc) {
		    this.ReceivedCmd(sMessage, oData, sSrc);
		},
		
		'AppendTerm': function(sMessage, oData, sSrc) {
		    this.ReceivedAppendTerm(sMessage, oData, sSrc);
		},
		
		'ClearSearchBarTerm': function(sMessage, oData, sSrc) {
			this.setValue("Term", '');
		}, 
		
		'AutoCompleteControl': function(sMessage, oData, sSrc) {
		    this.ChangeAutoCompleteState(sMessage, oData, sSrc);
        },
        
        'AutoCompSelect': function(sMessage, oData, sSrc) {
		    this.AutoCompleteOptionSelected();
        },
		
		// Browser events
		"Term<keypress>": function(event, target, name) {
		    this.TermKeyPress(event, target, name);
		},
      
		// Cmd is set to Go, so ResultsView of other database can choose component based 
		// on value of Cmd. The existing search term is also passed down.
		"Go<click>": function(e, target, name) {
            this.GoClick(e, target, name);
		},
		
		"Preview<click>": function(e, target, name) {
		 	this.PreviewClick(e, target, name);
		},
	  
		// to indicate that the db field was the submitter, this will also set future 
		// TabCmd to current TabCmd and keep the existing search term.
		"Db<change>": function(e, target, name) {
		    this.DbChange(e, target, name);
		},
		
		// On Clear button click, set focus to search box and clear the term
		"Clear<click>": function (e, target, name) {
		    this.ClearClick(e, target, name);
		}
    
		
	}, //listen
	
	/* other functions */
	
	'ReceivedIndexLogicalOp': function(sMessage, oData, sSrc){
		var sbTerm = this.getValue("Term");
		var oTerm = this.getInput("Term");
		var newValue = oData.key;

		console.info ("In Indexlogocalop in SearchBar");

		if (sbTerm != "") {
			newValue = sbTerm + ' ' + oData.op + ' ' + oData.key;
		}
		this.setValue("Term", newValue);
		if (oTerm) {
		   oTerm.focus();
		}
	},
	
	'ReceivedTermLogicalOp': function(sMessage, oData, sSrc){
	    var sbTerm = this.getValue("Term");
		var bNotBlank = sbTerm != "";
		
		if (bNotBlank)
		   sbTerm = '(' + sbTerm + ') ' + oData.op + ' (';
		
		sbTerm += oData.key;
		
		if (bNotBlank)
		   sbTerm += ')';
 
		this.setValue("Term", sbTerm);  
		this.send.Term({'term' : sbTerm});
		this.getInput("Term").focus();
	},
	
	'ReceivedLimitsGoClicked': function(sMessage, oData, sSrc){
		this.send.Cmd({ 'cmd' : this.getValue("Go:cmd") });
		this.send.Term({ 'term' : this.getValue("Term") });
		// for back button fix, when go is clicked, also send db in searchbar, for checking against dbconnector
		this.send.SearchBarSearch({ 'db' : this.getValue("Db") });
		Portal.requestSubmit();
	},
	
	'ReceivedCmd': function(sMessage, oData, sSrc){
	    if (oData.cmd == 'CommandTabClicked'){
	        this.send.Term({'term': this.getValue("Term") });
			// for back button fix, when Tab is clicked, also send db in searchbar
			if (this.getValue("Db")){
				this.send.DbChanged({ 'db' : this.getValue("Db") });
			}
		}
	},
	
	'ReceivedAppendTerm': function(sMessage, oData, sSrc){
	    var newTerm = Portal.Portlet.SearchBar.originalTerm;
	    if (Portal.Portlet.SearchBar.originalTerm != '' && oData.op != ''){
	        newTerm += ' ' + oData.op + ' ';
	    }
	    newTerm += oData.term;
	    //this.setValue("Term", newTerm); 
		this.send.Term({'term': newTerm });
		// for back button fix, send original db
		this.send.SearchBarSearch({ 'db' : Portal.Portlet.SearchBar.originalDb });
	},
	
	'TermKeyPress': function(event, target, name){
	    event = event || utils.fixEvent (window.event);
		if ((event.keyCode || event.which) == 13) 
		{
			// Emulate Go command.
    
			console.info ("In term keypress: CMD  in SearchBar");
			this.send.Cmd({ 'cmd' : this.getValue("Term:cmd") });

			// In History Tab, Term field should send command Preview
			if (this.getValue("Term:cmd") == 'Preview')
			{
				this.send.TabCmd({ 'tab' : this.getValue("Db:tab") });
			}
    
			console.info ("In term keypress : TERM in SearchBar");
			this.send.Term({ 'term': this.getValue("Term") });

		    // for back button fix, when go is clicked, also send db in searchbar, for checking against dbconnector
		    this.send.SearchBarSearch({ 'db' : this.getValue("Db") });
        
			event.returnValue = false;
			if (event.stopPropagation != undefined)
                  event.stopPropagation ();   
			if (event.preventDefault != undefined)
                  event.preventDefault ();   
			Portal.requestSubmit (); 
			return false;
		}
	},
	
	'GoClick': function(e, target, name){
	 	this.send.Cmd({ 'cmd' : this.getValue("Go:cmd") });
	   	this.send.Term({ 'term' : this.getValue("Term") });
		// for back button fix, when go is clicked, also send db in searchbar, for checking against dbconnector
	 	this.send.SearchBarSearch({ 'db' : this.getValue("Db") });
	},
	
	'PreviewClick': function(e, target, name){
        this.send.Cmd({ 'cmd' : 'Preview' });
	   	this.send.Term({ 'term' : this.getValue("Term") });
	   	this.send.TabCmd({ 'tab' : this.getValue("Preview:tab") });
		// for back button fix, when go is clicked, also send db in searchbar, for checking against dbconnector
	 	this.send.SearchBarSearch({ 'db' : this.getValue("Db") });
	},
	
	'DbChange': function(e, target, name){
	 	this.send.Cmd({ 'cmd' : this.getValue("Db:cmd") });
		console.info ("In DB SearchBar: " + this.getValue("Db:cmd"));
		this.send.TabCmd({ 'tab' : this.getValue("Db:tab") });
		this.send.DbChanged({ 'db' : this.getValue("Db") });
		this.send.Term({ 'term' : this.getValue("Term") });
		
		if (this.getValue("Db:cmd") == ''){
    		if (this.getValue("Term:suggest") == 'true'){
    		    // change to if the current database has a dictionary 
    		    this.EnableDisableAutocomplete();
            }
        }
	},
	
	'ClearClick': function(e, target, name){
	    this.setValue ("Term", "");
        var term = this.getInput ("Term");
        if (term) 
            term.focus ();
    },
    
    'ChangeAutoCompleteState': function(sMessage, oData, sSrc){
        this.setValue("Term:suggest", 'false');
        var site = document.forms[0]['p$st'].value;
        var resp = xmlHttpCall(site, this.realname, "AutoCompleteControl", {"ShowAutoComplete": 'false'}, this.receive, {}, this);
    },        
        
    'receive': function(responseObject, userArgs) {
    },
    
    'AutoCompleteOptionSelected': function(){
        /*if (this.getInput("AutoSuggestUsed")){
            this.setValue("AutoSuggestUsed", 'true');
        }*/
        
	    this.send.Cmd({ 'cmd' : this.getValue("Go:cmd") });
	   	this.send.Term({ 'term' : this.getValue("Term") });
		// for back button fix, when go is clicked, also send db in searchbar, for checking against dbconnector
	 	this.send.SearchBarSearch({ 'db' : this.getValue("Db") });
	 	Portal.requestSubmit(); 
	},
	
	'EnableDisableAutocomplete': function(){
	    var site = document.forms[0]['p$st'].value;
        var resp2 = xmlHttpCall(site, this.realname, "SetAutoCompleteDictionary", {"Db": this.getValue("Db")}, this.receiveDictionary, {}, this);
	},
	
	'receiveDictionary': function(responseObject, userArgs){ 
        try {
            // deserialize the string with the JSON object
            var response = '(' + responseObject.responseText + ')';
            var JSONobject = eval(response);
            
            var dict = JSONobject.Dictionary || "";
            
            // turn autocomplete off or on if database is changed in selector.
            if(dict != ''){
               jQuery("#search_term").ncbiautocomplete("option","isEnabled",true).ncbiautocomplete("option","dictionary",dict);
            }
            else{
               jQuery("#search_term").ncbiautocomplete("turnOff",true);    
            }
        }
        catch (e){
        
        }
    }
	
}, // portlet instance

{
	originalTerm: '',
	originalDb: ''
});

function EntrezSearchBarAutoComplCtrl(){
    Portal.$send('AutoCompleteControl');
}


// Requires: toggle.js, cssQuery-p.js, notify.js

// Fanfold design pattern is:
//  <div class="fanfold">
//     <h1>
//     <div> (Controlled by h1)
//     <h1>
//     <div> (Controlled by prev h1)
//     ...
//  </div><!--/.fanfold-->
//
// Every h1 is a Toggle src for all elements below it.
// Elements may opt out by setting class name "ffnohide"

Fanfold = function(node) {
   var thisNode, h1Id, thisDiv, i;
   var kids = node.childNodes;
   //var notifier = Notifier.getInstance();
   var oThis = this;
 
   thisNode = node.firstChild;
 
   for (thisNode = node.firstChild; thisNode; thisNode = thisNode.nextSibling) {
      if (thisNode.tagName) {
         // New control element
         if (thisNode.tagName.toLowerCase() == 'h1') {

            // Find or make id for this H1
            h1Id = thisNode.id = thisNode.id ? thisNode.id : utils.createNewId();
            new Toggle(thisNode);
         } else {
            // New controlled element
            // class name "ffnohide" lets nodes opt out of being controlled
            if (h1Id && !utils.hasClass(thisNode, "ffnohide")) {
               Toggle.addTarget(h1Id, thisNode);
            }
         }
      }
   }
}

Fanfold.onload = function() {
   // Only initialize once. (If someone registers initializer > 1 time,
   // initialization still only happens once.)
//   utils.jsLoader.sBase = "/entrez/query/Gene/";
//   utils.jsLoader.load(["notify.js", "cssQuery-p.js", "toggle.js"]);

   if (!document.fanfold_initialized) {
      document.fanfold_initialized = 1;
      var ffs = cssQuery("div.fanfold");
      for (var i in ffs) {
         new Fanfold(ffs[i]);
      }
   }
}

utils.addEvent(window, 'load', Fanfold.onload, false);


/*
Text Link/Image Map Tooltip Script- 
¿ Dynamic Drive (www.dynamicdrive.com)
For full source code, installation instructions,
100's more DHTML scripts, and Terms Of
Use, visit dynamicdrive.com
*/

if (!document.layers&&!document.all)
event="test"

var saved_width;


function showtip(current,e,text)
{
    text=unescape(text);
  if (document.all) {
    text=text.replace(new RegExp("<BR>","gi")," \n");
    text=text.replace(new RegExp("<[^>]+>","g"),'');
    current.title=text
  } else if (document.layers) {
    document.tooltip.document.write('<layer bgColor="yellow" style="border:1px solid black;font-size:12px;">'+text+'</layer>')
    document.tooltip.document.close()
    if (e.pageX+5+document.tooltip.width>window.pageXOffset + window.innerWidth) 
      document.tooltip.pageX = window.pageXOffset + window.innerWidth-document.tooltip.clip.width
    else
      document.tooltip.pageX=e.pageX+5
    if (e.pageY+5+document.tooltip.clip.height>window.pageYOffset + window.innerHeight) 
      document.tooltip.pageY = e.pageY-document.tooltip.clip.height
    else
      document.tooltip.pageY=e.pageY+5
    document.tooltip.visibility="show"
  } else if (document.getElementById) {
    text=text.replace(new RegExp("<BR>","g"),"<br>");
    thetitle=text.split('<br>')
    if (thetitle.length>1) {
      tipNode=document.getElementById('tooltip');
      dynamiccontentNS6(tipNode,text);
      tipNode.style.backgroundColor='yellow';

      var width,height;
      if (window.document.body && typeof(window.document.body.clientWidth) == 'number') {
        // Gecko 1.0 (Netscape 7) and Internet Explorer 5+
        width = window.document.body.clientWidth;  
        height = window.document.body.clientHeight;  
      } else if (typeof(window.innerWidth) == 'number') {
        // Navigator 4.x, Netscape 6.x, CompuServe 7 and Opera
        width = window.innerWidth;
        height = window.innerHeight;
      }

     saved_width = tipNode.style.width;
     tipNode.style.width = tipNode.offsetWidth;

     if (e.pageX+5+tipNode.offsetWidth>window.pageXOffset + width )
        tipNode.style.left = window.pageXOffset + width-tipNode.offsetWidth
      else
        tipNode.style.left=e.pageX+5
      if (e.pageY+5+tipNode.offsetHeight>window.pageYOffset + height )
        tipNode.style.top = e.pageY-tipNode.offsetHeight
      else
        tipNode.style.top=e.pageY+5

      tipNode.style.visibility="visible"

    } else {
      text=text.replace(new RegExp("<[^>]+>","g"),'');
      current.title=text
    }
  }
}

function hidetip(){
  if (document.all) {
  }
  else if (document.layers) {
    document.tooltip.visibility="hidden"
  }
  else if (document.getElementById) {
    tipNode=document.getElementById('tooltip');
    if (tipNode){  
      tipNode.style.visibility="hidden"
      tipNode.style.left = 0
      tipNode.style.top = 0
      tipNode.style.width = saved_width
    }
  }
}


// For NLM interop
document.domain = "nlm.nih.gov";
function call_opener(id,symbols,descriptions,species, research_info)
{ 
   opener.add_link(id, symbols, descriptions.substr(0,2000),species, research_info.substr(0,2000));
   window.close(); 
}
