





  
    
// NextBio name space 
var nbApi = {};

nbApi.apiKey = "";
nbApi.nameSpace = "nbApi";
nbApi.images = {};
nbApi.debug = false;
nbApi.elsevier = false;
nbApi.system = "PUBLIC";

nbApi.debugMode = function(debug)
{           
  nbApi.setDebugMode(debug);
};
nbApi.setDebugMode = function(debug)
{           
  nbApi.debug = debug == true;
};
nbApi.getDebugMode = function()
{           
  return nbApi.debug == true;
};


  
    
// NextBio API utility functions
// requires jsApi.jsp

// LoadFrame(config, bAlert) - load from server in an iFrame 
// configuration parameters:
// config.target - required. Id of a div, span, td, etc. to receive results loaded from server  
// config.url - required. URL of a web service processing AJAX call  
// config.query - optional. List of parameters for the URL (see above)
// config.success - optional. A callback function that will be excuted in case of a successfull call, after results are loaded to the target 
//    success(args) - where args is described below. 
// config.failure - optional. A callback function that will be executed in case of a failed call:  
//    failure(args) - where args is described below. 
// config.args - optional. A string that will be passsed as a parameter to success() and/or failure() callbacks if either one is specified.
// bAlert - optional. True if we want to display alerts.
nbApi.loadFrame = function(config)
{
  var bAlert = nbApi.getDebugMode();
  if (config == null)
  {
    if (bAlert)
      alert("Nextbio API: No configuration object.");
    return false;
  }
  if (config.url == null)
  {
    if (bAlert)
      alert("Nextbio API: Configuration object contains no URL.");
    return false;
  }   
  var target = document.getElementById(config.target);
  if (target == null)
  {
    if (bAlert)
      alert("Nextbio API: Target with id=" + congig.target + " was not found on this page.");
    return;
  } 
  var id = "nbTagCloud_" + config.target;
  var url = config.url;
  if (config.query != null)
    url += "?" + config.query; 
  var target = document.getElementById(config.target);
  target.innerHTML = "<iframe id=\'" + id + "\' style=\'" + config.style + "\'></iframe>";
  target = document.getElementById(id);
  target.src = url;
};
// LoadScript(config, bAlert) - load from server as a javascript script
// configuration parameters:
// config.target - required. Id of a div, span, td, etc. to receive results loaded from server  
// config.url - required. URL of a web service processing AJAX call  
// config.query - optional. List of parameters for the URL (see above)
// config.success - optional. A callback function that will be excuted in case of a successfull call, after results are loaded to the target 
//    success(args) - where args is described below. 
// config.failure - optional. A callback function that will be executed in case of a failed call:  
//    failure(args) - where args is described below. 
// config.args - optional. A string that will be passsed as a parameter to success() and/or failure() callbacks if either one is specified.
// bAlert - optional. True if we want to display alerts.
nbApi.loadScript = function(config)
{
  var bAlert = nbApi.getDebugMode();
  if (config == null)
  {
    if (bAlert)
      alert("Nextbio API: No configuration object.");
    return false;
  }
  var target = document.getElementById(config.target);
  if (target == null)
  {
    if (bAlert)
      alert("Nextbio API: Target doesn't exist.");
    return false;
  }
  if (config.url == null)
  {
    if (bAlert)
      alert("Nextbio API: Configuration object contains no URL.");
    return false;
  }                                                      
  var message;
  if (config.message != null)
  {
    if (config.messageStyle == null)
      message = config.message; 
    else
      message = '<span style="' + config.messageStyle + '">' + config.message + '</span>';
    nbApi.setInnerHtml(config.target, message);
    target.style.cursor = "wait";
  }
  var url = config.url;
  var params = "targetId=" + config.target + "&callback=" + config.callbackName; 
// setup timeout callback
  var timeoutId = null;
  if (config.timeout != null && config.timeout > 0)
  {
    timeoutId = nbApi.createId("nextbioTimeout");  
    var timeout = setTimeout(function(){nbApi.loadTimeoutHandler(config.target, timeoutId, config.timeoutCallback)}, config.timeout);
    target.setAttribute(timeoutId, timeout);
    params += "&timeoutId=" + timeoutId;
    if (config.timeoutTerminate == true)
    {
      params += "&timeoutTerminate=true";
    }
  }  

  if (config.query == null)
    config.query = params;
  else
    config.query += "&" + params;
  url += "?" + config.query; 
  target.nextbioScriptCallback = config.callback;
  nbApi.importScript(url, config.iFrameId);
};
nbApi.updateTargetHTML = function(json)
{
  if (json == null || json.target == null) 
    return;
  var target = document.getElementById(json.target);
  if (target == null || target.getAttribute("nextbio_allowUpdate") != "true")
    return;

  if (json.timeoutId != null)
  {
    var timeoutId = target.getAttribute(json.timeoutId);
    if (timeoutId == null || timeoutId.length == 0)
    {
      if (json.timeoutTerminate == true)
      {
        return;
      }
    }
    else
    {
      clearTimeout(timeoutId);
      target.setAttribute(json.timeoutId, null);
    }
  } 
  target.innerHTML = "";
  target.nextbioIsLoaded = false;

  var bLoaded = json.response != null && json.response.length > 0;
  if (bLoaded)
  {
    target.nextbioIsLoaded = true;
    if (target.nextbioHeader != null && target.nextbioHeader.length > 0)
    {
      var header = document.createElement("div");
      if (target.nextbioHeaderClassName != null)
        header.className = target.nextbioHeaderClassName;
      header.innerHTML = target.nextbioHeader;
      target.appendChild(header);
    }
    var body = document.createElement("div");
    body.className = target.nextbioTargetClassName;
    body.innerHTML = json.response;
    target.appendChild(body);
    if (target.nextbioFooter != null && target.nextbioFooter.length > 0)
    {
      var footer = document.createElement("div");
      if (target.nextbioFooterClassName != null)
        footer.className = target.nextbioFooterClassName;
      footer.innerHTML = target.nextbioFooter;
      target.appendChild(footer);
    }
  }
  target.style.cursor = "auto";

  if (target.nextbioScriptCallback != null)
    target.nextbioScriptCallback(json.target, bLoaded, json);
};
nbApi.updateTargetText = function(json)
{
  if (json == null || json.target == null || json.response == null)
    return;
  var target = document.getElementbyId(json.target);
  if (json.timeoutId != null)
  {
    var timeoutId = target.getAttribute(json.timeoutId);
    if (timeoutId == null || timeoutId.length == 0)
    {
      if (json.timeoutTerminate == true)
      {
        return;
      }
    }
    else
    {
      clearTimeout(timeoutId);
      target.setAttribute(json.timeoutId, null);
    }
  } 
  target.innerText = json.response;
  target.textContent = json.response;
  target.style.cursor = "auto";
};

nbApi.setInnerHtml = function(id, html)
{
  if (id == null || html == null)
    return;
  var el = document.getElementById(id);
  if (el == null)
    return;
  el.innerHTML = html;
};
nbApi.setInnerText = function(id, text)
{
  if (id == null || text == null)
    return;
  var el = document.getElementById(id);
  if (el == null)
    return;
  el.innerText = text;
  el.textContent = text;
};
nbApi.setAttr = function(id, attr, text)
{
  if (id == null ||attr == null || text == null)
    return;
  var el = document.getElementById(id);
  if (el == null)
    return;
  el.setAttribute(attr, text);
};
nbApi.normalizeString = function(str)
{
  if (str == null)
    return "";
  str = str.replace(/^\s+/, "");  
  str = str.replace(/\s+$/, "");  
  str = str.replace(/\s+/g, " ");
  return str;  
};
nbApi.trim = function(str)
{
  if (str == null)
    return "";
  str = str.replace(/^\s+/, "");  
  str = str.replace(/\s+$/, "");  
  return str;  
};
// Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
nbApi.addClass = function(element, newClassName)
{
  if (element == null)
    return;
  var className = element.className;
  if (className == null || className.length == 0)
  {
    element.className = newClassName;
    return;
  }
  var nameArray = element.className.split(/\s+/);
  var out = newClassName;
  for (i = 0; i < nameArray.length; i++)
  {
    if (nameArray[i] != newClassName)
    {
      out += " " + nameArray[i];
    }
    
  }
  out = nbApi.trim(out);
  element.className = out;
};
nbApi.removeClass = function(element, className)
{
  if (element == null)
    return;
  if (className == null)
    return;

  var nameArray = element.className.split(/\s+/);
  var out = "";
  for (i = 0; i < nameArray.length; i++)
  {
    if (nameArray[i] != className)
    {
      if (i > 0)
        out += " ";
      out += nameArray[i];
    }
    
  }
  out = nbApi.trim(out);
  if (out.length > 0)
    element.className = out;
  else
    element.className = null;
};

nbApi.getWindowHeight = function() 
{
	var myHeight = 0;
   if( typeof( window.innerWidth ) == 'number' ) {
     //Non-IE
     myHeight = window.innerHeight;
   } else if( document.documentElement &&
       ( document.documentElement.clientWidth || document.documentElement.clientHeight ) ) {
     //IE 6+ in 'standards compliant mode'
     myHeight = document.documentElement.clientHeight;
   } else if( document.body && ( document.body.clientWidth || document.body.clientHeight ) ) {
     //IE 4 compatible
     myHeight = document.body.clientHeight;
   }
   return myHeight;
};

nbApi.getWindowWidth = function() 
{
	var myWidth = 0;
   if( typeof( window.innerWidth ) == 'number' ) {
     //Non-IE
     myWidth = window.innerWidth;
   } else if( document.documentElement &&
       ( document.documentElement.clientWidth || document.documentElement.clientHeight ) ) {
     //IE 6+ in 'standards compliant mode'
     myWidth = document.documentElement.clientWidth;
   } else if( document.body && ( document.body.clientWidth || document.body.clientHeight ) ) {
     //IE 4 compatible
     myWidth = document.body.clientWidth;
   }
   return myWidth;
};

nbApi.getElementLeft = function(eElement) 
{
   if (!eElement && this)                    // if argument is invalid
   {                                         // (not specified, is null or is 0)
      eElement = this;                       // and function is a method
   }                                         // identify the element as the method owner

   var bIE = document.all ? true : false; // initialize var to identify IE

   var nLeftPos = eElement.offsetLeft;       // initialize var to store calculations
   var eParElement = eElement.offsetParent;  // identify first offset parent element

   while (eParElement != null)
   {                                         // move up through element hierarchy

      if(bIE)                             // if browser is IE, then...
      {
         if( (eParElement.tagName != "TABLE") && (eParElement.tagName != "BODY") )
         {                                   // if parent is not a table or the body, then...
            nLeftPos += eParElement.clientLeft; // append cell border width to calcs
         }
      }
      else                                   // if browser is Gecko, then...
      {
         if(eParElement.tagName == "TABLE")  // if parent is a table, then...
         {                                   // get its border as a number
            var nParBorder = parseInt(eParElement.border);
            if(isNaN(nParBorder))            // if no valid border attribute, then...
            {                                // check the table's frame attribute
               var nParFrame = eParElement.getAttribute('frame');
               if(nParFrame != null)         // if frame has ANY value, then...
               {
                  nLeftPos += 1;             // append one pixel to counter
               }
            }
            else if(nParBorder > 0)          // if a border width is specified, then...
            {
               nLeftPos += nParBorder;       // append the border width to counter
            }
         }
      }
      nLeftPos += eParElement.offsetLeft;    // append left offset of parent
      eParElement = eParElement.offsetParent; // and move up the element hierarchy
   }                                         // until no more offset parents exist
   if (scroll) {
   		eParElement = eElement;
   		while (eParElement) {
   			if (eParElement.scrollLeft) {
   				nLeftPos -= eParElement.scrollLeft;
   			}
   			eParElement = eParElement.parentNode;
   		}
   }
   return nLeftPos;                          // return the number calculated
};


// get the top offset of the element.  If scroll is true, take scrolling into account
nbApi.getElementTop = function(eElement, scroll) 
{
   if (!eElement && this)                    // if argument is invalid
   {                                         // (not specified, is null or is 0)
      eElement = this;                       // and function is a method
   }                                         // identify the element as the method owner

   var bIE = document.all ? true : false; // initialize var to identify IE

   var nTopPos = eElement.offsetTop;         // initialize var to store calculations
   var eParElement = eElement.offsetParent;  // identify first offset parent element

   while (eParElement != null)
   {                                         // move up through element hierarchy
      if(bIE)                             // if browser is IE, then...
      {
         if( (eParElement.tagName != "TABLE") && (eParElement.tagName != "BODY") )
         {                                   // if parent a table cell, then...
            nTopPos += eParElement.clientTop; // append cell border width to calcs
         }
      }
      else                                   // if browser is Gecko, then...
      {
         if(eParElement.tagName == "TABLE")  // if parent is a table, then...
         {                                   // get its border as a number
            var nParBorder = parseInt(eParElement.border);
            if(isNaN(nParBorder))            // if no valid border attribute, then...
            {                                // check the table's frame attribute
               var nParFrame = eParElement.getAttribute('frame');
               if(nParFrame != null)         // if frame has ANY value, then...
               {
                  nTopPos += 1;              // append one pixel to counter
               }
            }
            else if(nParBorder > 0)          // if a border width is specified, then...
            {
               nTopPos += nParBorder;        // append the border width to counter
            }
         }
      }

      nTopPos += eParElement.offsetTop;      // append top offset of parent
      eParElement = eParElement.offsetParent; // and move up the element hierarchy
   }                                         // until no more offset parents exist
   if (scroll) {
   		eParElement = eElement;
   		while (eParElement) {
   			if (eParElement.scrollTop) {
   				nTopPos -= eParElement.scrollTop;
   			}
   			eParElement = eParElement.parentNode;
   		}
   }
   return nTopPos;                           // return the number calculated
};
// get scroll factor for the element
nbApi.getScrollLeft = function()
{
  if (typeof( window.pageXOffset ) == 'number')
    return window.pageXOffset;
  if (document.body != null && document.body.scrollLeft)
    return document.body.scrollLeft;  
  if (document.documentElement != null && document.documentElement.scrollLeft)
    return document.documentElement.scrollLeft;
  return 0;    
};

nbApi.getScrollTop = function()
{
  if (typeof( window.pageYOffset ) == 'number')
    return window.pageYOffset;
  if (document.body != null && document.body.scrollTop)
    return document.body.scrollTop;  
  if (document.documentElement != null && document.documentElement.scrollTop)
    return document.documentElement.scrollTop;
  return 0;    
};

nbApi.onEvent = function(event, containerId, param, extra)
{
  if (event == null || containerId == null)
    return;
  var container = document.getElementById(containerId);
  if (container == null)
    return;  
  if (event.type.toLowerCase() == "click")
  {
    if (container.nextbioOnClick != null)
      container.nextbioOnClick(event, containerId, param, extra, container.nextbioUrlContext);
  }
  else if (event.type.toLowerCase() == "mouseover")
  {
    if (container.nextbioOnMouseOver != null)
      container.nextbioOnMouseOver(event, containerId, param, container.nextbioOnMouseOverParam, container.nextbioUrlContext);
  }
  else if (event.type.toLowerCase() == "mouseout")
  {
    if (container.nextbioOnMouseOut != null)
      container.nextbioOnMouseOut(event, containerId, param, container.nextbioOnMouseOutParam, container.nextbioUrlContext);
  }
};
nbApi.showFrame = function(event, popupId, param, extra, urlContext)
{
  if (event == null || popupId == null || param == null)
    return;
  var popup = document.getElementById(popupId + "_frame_popup");
  if (popup == null)
    return;  
  var container = document.getElementById(popupId + "_frame_container");
  if (container == null)
    return; 
  var url;
  if (urlContext == null)
    urlContext = "http://www.nextbio.com/b";
  if ("" == "1.0.ui2")
  {
    url = urlContext + "/home/home.nb?q=" + encodeURIComponent(param) + "&" + extra;
  }
  else
  {
    url = urlContext + "/search/ov/" + encodeURIComponent(param) + "?" + extra;
  }
  var frameProperties = nbApi.getFrameProperties(popupId);
  if (frameProperties == null)
  {
    nbApi.removeFrame(popupId);
    var frame = document.createElement("iframe");
    frame.id = popupId + "_frame";
    frame.style.width = container.style.width;
    frame.style.height = container.style.height;
    frame.frameBorder = 0;
    container.appendChild(frame);
    frame.src = url; 
    popup.style.display = "";
    return;
  }
  if (frameProperties.iFrame == true)
  {
    nbApi.removeFrame(popupId);
    var winWidth = nbApi.getWindowWidth();
    var winHeight = nbApi.getWindowHeight();
    var frameWidth = Math.min(winWidth - 50, frameProperties.width);
    var frameHeight = Math.min(winHeight - 50, frameProperties.height);
    frameWidth = Math.max(frameWidth, 200);
    frameHeight = Math.max(frameHeight, 150);
    var frameTop = Math.floor((winHeight - frameHeight)/2) + nbApi.getScrollTop() - 20; 
    var frameLeft = Math.floor((winWidth - frameWidth)/2) + nbApi.getScrollLeft() - 10; 
    frameTop = Math.max(frameTop, 0);
    frameLeft = Math.max(frameLeft, 0);
    
    popup.style.top = frameTop + "px";
    popup.style.left = frameLeft + "px";
    var frame = document.createElement("iframe");
    frame.id = popupId + "_frame";
    container.style.width = frame.style.width = frameWidth + "px";
    container.style.height = frame.style.height = frameHeight + "px";
    frame.frameBorder = 0;
    container.appendChild(frame);
    frame.src = url; 
    popup.style.display = "";
    return;
  }

  var screenWidth = screen.availWidth != null ? screen.availWidth : screen.width;
  var screenHeight = screen.availHeight != null ? screen.availHeight : screen.height - 100; // to account for non-client area of a window. 
  var frameWidth = Math.min(screenWidth - 50, frameProperties.width);
  var frameHeight = Math.min(screenHeight - 50, frameProperties.height);
  frameWidth = Math.max(frameWidth, 200);
  frameHeight = Math.max(frameHeight, 200);
  var frameTop = frameProperties.top < 0 ? Math.floor((screenHeight - frameHeight)/2) : frameProperties.top; 
  var frameLeft = frameProperties.left < 0 ? Math.floor((screenWidth - frameWidth)/2) : frameProperties.left; 
  frameTop = Math.max(frameTop, 0);
  frameLeft = Math.max(frameLeft, 0);

  var winParams = "resizable=yes,scrollbars=yes,status=yes,toolbar=yes,location=yes,menubar=no,top=" + frameTop + ",left=" + frameLeft + ",width=" + frameWidth + ",height=" + frameHeight;
  var target = frameProperties.target;
  try
  {
    if (window[target] != null)
      window[target].close();
  }
  catch (error){}
  var newWindow = window.open(url, target, winParams);
  if (target != null)
    window[target] = newWindow; 
};
nbApi.hideFrame = function(popupId)
{
  if (popupId == null)
    return;
  var popup = document.getElementById(popupId + "_frame_popup");
  if (popup == null)
    return;  
  popup.style.display = "none";
  nbApi.removeFrame(popupId);
};
nbApi.removeFrame = function(popupId)
{
  if (popupId == null)
    return;
  var frame = document.getElementById(popupId + "_frame");
  if (frame == null)
    return;
  var container = frame.parentNode;
  if (container == null)
    return;
  container.removeChild(frame);
};
nbApi.getFrameProperties = function(popupId)
{
  if (popupId == null)
    return null;
  var popup = document.getElementById(popupId);  
  if (popup == null)
    return null;
  var properties = {
    target: popup.nextbioTarget,
    iFrame: popup.nextbioIFrame,
    top: popup.nextbioTop,
    left: popup.nextbioLeft,
    width: popup.nextbioWidth, 
    height: popup.nextbioHeight
  };
  return properties;
};

// importScript(url) - load javascript dynamically
// url - url of a javascript file
nbApi.importScript = function(url, iFrameId)
{
  var bAlert = nbApi.getDebugMode();
  if (url == null)
  {
    if (bAlert)
      alert("Nextbio API: importScript: No URL.");
    return;
  }
  if (iFrameId != null)
  {
    var iFrame = document.getElementById(iFrameId);
    if (iFrame == null)
    {
      if (bAlert)
        alert("Nextbio API: importScript: iFrame with id '" + iFrameId + "' not found.");
      return;
    }
    var script = iFrame.contentWindow.document.createElement("script");
    script.type = "text/javascript";
    iFrame.contentWindow.document.body.appendChild(script);
    script.src = url;
  }
  else 
  {
    var script = document.createElement("script");
    script.type = "text/javascript";
    document.body.appendChild(script);
    script.src = url;
  }
};

//================ extensions ==========
nbApi.findParentByClassName = function(obj, className)
{
  if (obj == null || className == null)
    return null;
  while (obj != null)
  {
    if (obj.nodeType == 1 && obj.className != null && nbApi.trim(obj.className) == className)
      return obj;  
    obj = obj.parentNode;
  }  
  return null;
};

nbApi.findParentByTagName = function(obj, tagName)
{
  if (obj == null || tagName == null)
    return null;
  tagName = tagName.toLowerCase();
  obj = obj.parentNode;
  while (obj != null)
  {   
    var objTagName = nbApi.trim(obj.tagName);
    if (objTagName != null)
      objTagName = objTagName.toLowerCase();
    if (obj.nodeType == 1 && objTagName == tagName)
      return obj;  
    obj = obj.parentNode;
  }  
  return null;
};

nbApi.show = function (targetId, bShow)
{
  var element = document.getElementById(targetId);
  if (element != null)
    element.style.display = bShow?"inline":"none";
};

nbApi.findElementsByName = function(name, type)
{
  var group = document.getElementsByName(name);
  if ((group == null || group.length == 0) && type != null)
    group = document.getElementsByTagName(type);
  if (group == null || group.length == 0)
    return group;
  var out = new Array();
  var j = 0;            
  for (i = 0; i < group.length; i++)
  {
    var nameAttr = group[i].getAttribute("name");
    if (nameAttr == name)
    {
      out[j] = group[i];
      j++;
    }
  }
  return out;
};

nbApi.findPosition = function(obj) 
{
  var left = 0;
  var top = 0;
	var iter = obj;
  if (obj.offsetParent) 
  {
  	do 
    {
  		left += obj.offsetLeft;
  		top += obj.offsetTop;
  	} while (obj = obj.offsetParent);
  }
  else
  {
    left = obj.offsetLeft;
    top = obj.offsetTop;   
  }

	while (iter) 
  {
    if (iter.tagName && iter.tagName.toLowerCase() == "body")
    {
      break;
    }
  	if (iter.scrollLeft) 
    {
  		left -= iter.scrollLeft;
  	}
  	if (iter.scrollTop) 
    {
  		top -= iter.scrollTop;
  	}
  	iter = iter.parentNode;
	}
//   left = nbApi.getElementLeft(obj, true);
//   top = nbApi.getElementTop(obj, true);
  return {left: left, top: top};
};

nbApi.createId = function(id) 
{
  var date1 = new Date();
  date1.setFullYear(2000,1,1);
  var date2 = new Date();
  id += date2.getTime() - date1.getTime();
  return id;
};

nbApi.loadTimeoutHandler = function(targetId, timeoutId, timeoutCallback)
{
  var bAlert = nbApi.getDebugMode();
  if (targetId == null)
  {
    if (bAlert)
      alert("Nextbio API: Timeout Handler: No target id.");
    return false;
  }
  if (timeoutId == null)
  {
    if (bAlert)
      alert("Nextbio API: Timeout Handler: No timeout id.");
    return false;
  }
  var target = document.getElementById(targetId);
  if (target == null)
  {
    if (bAlert)
      alert("Nextbio API: Timeout Handler: Target doesn't exist.");
    return false;
  }
  target.setAttribute(timeoutId, null);

  if (timeoutCallback == null)
  {
    return true;
  }
  return timeoutCallback(target);
};
/**
 * Determine the URL for a given search.  When calling from code that only runs within the nextbio
 * context, consider using searchUrl() instead.
 * @param root The root for the current contect e.g. "/b"
 * @param page The search page, e.g. "disc" or "lit"
 * @param searchTerm The term being searched for e.g. "esr1"
 * @param query the query arguments to appear after the ?, e.g. "id=1234&type=gene"
 * @return search URL
 */
nbApi.searchUrl = function(root,page,searchTerm,query, doNotEncode) 
{
  var encTerm = doNotEncode ? searchTerm : encodeURIComponent(searchTerm);
  // there is a problem on our server if the url contains an encoded % (%25) or / (%2F)
  // if the search term contains a %, included it as part of the q, otherwise
  // we include it as part of the URL
  if (searchTerm.indexOf('%') >= 0 || searchTerm.indexOf('/') >= 0 || searchTerm.indexOf('+') >= 0) {
      return root + "/search/" + page + ".nb?" + _nextbio_setParam(query,"q",encTerm);
  }
  if (query == null || query.length == 0) {
      query = "";
  } else {
      query = "?" + query;
  }
  return root + "/search/" + page + "/" + encTerm + query;
};
/**
 * Return the standard icon for a given type
 * @param type, type, e.g. "gene", "biogroup"
 * @param opaque if true, use IE6 opaque icons if available.  These icons will work on a white
 * background.  This should only be set if the use of the Png class doesn't prevent
 * blue backgrounds
 * @return base url for the icon
 */
nbApi.getIcon = function(type, root, bLabel, opaque) 
{
  if (type == null || root == null)
    return null;
  type = type.toLowerCase();

  if (bLabel == true)
    root += "/labels/";
  else
    root += "/icons/";  
    
  opaque = (opaque && navigator.userAgent.indexOf("MSIE 6") > 0)?"_opq":"";

  if (type == "gene" || type == "feature" || type == "genes") return root + "gene" + opaque + ".png";
  if (type == "tissue" || type == "tissues") return root + "tissue" + opaque + ".png";
  if (type == "treatment" || type == "compound" || type == "treatments") return root + "treatment" + opaque + ".png";
  if (type == "disease" || type == "diseases") return root + "disease" + opaque + ".png";
  if (type == "bioset") return root + "bioset" + opaque + ".png";
  if (type == "biogroup" || type == "biogroups") return root + "biogroup" + opaque + ".png";
  if (type == "biosource") return root + "biosource.png";
  if (type == "biodesign") return root + "biodesign.png";
  if (type == "genemode") return root + "genemode.png";
  if (type == "snp") return root + "snp" + opaque + ".png";
  if (type == "author") return root + "author" + opaque + ".png";
  if (type == "study") return root + "study" + opaque + ".png";
  if (type == "organism") return root + "organism" + opaque + ".png";
  return root + "unknown.png";
};
nbApi.setCookie = function(cookieName, value, time)
{
    var cookie=cookieName + "=" + escape(value) + ";path=/;";
    if (time != null)
    {
      var date=new Date();
      date.setFullYear(date.getFullYear() + time);
      cookie += ";expires=" + date.toGMTString();
    }
    document.cookie=cookie;
}
nbApi.getCookie = function(cookieName)
{
  if (document.cookie.length > 0)
  {
    cookieStart = document.cookie.indexOf(cookieName + "=");
    if (cookieStart != -1)
    { 
    cookieStart = cookieStart + cookieName.length + 1; 
    cookieEnd = document.cookie.indexOf(";", cookieStart);
    if (cookieEnd == -1) cookieEnd = document.cookie.length;
    return unescape(document.cookie.substring(cookieStart, cookieEnd));
    } 
  }
  return "";
}

  
    
// NextBio autocomplete widget support 
// requires jsApi.jsp, jsUtils.jsp

// preload images
nbApi.imgPath = "http://www.nextbio.com/b/s/img3";
nbApi.images.biogroup = new Image();
nbApi.images.biogroup.src = nbApi.getIcon("biogroup", nbApi.imgPath, true);

nbApi.images.compound = new Image();
nbApi.images.compound.src = nbApi.getIcon("compound", nbApi.imgPath, true);

nbApi.images.disease = new Image();
nbApi.images.disease.src = nbApi.getIcon("disease", nbApi.imgPath, true);

nbApi.images.gene = new Image();
nbApi.images.gene.src = nbApi.getIcon("gene", nbApi.imgPath, true);

nbApi.images.tissue = new Image();
nbApi.images.tissue.src = nbApi.getIcon("tissue", nbApi.imgPath, true);

nbApi.images.biosource = new Image();
nbApi.images.biosource.src = nbApi.getIcon("biosource", nbApi.imgPath, true);

nbApi.images.biodesign = new Image();
nbApi.images.biodesign.src = nbApi.getIcon("biodesign", nbApi.imgPath, true);

nbApi.images.genemode = new Image();
nbApi.images.genemode.src = nbApi.getIcon("genemode", nbApi.imgPath, true);

nbApi.images.snp = new Image();
nbApi.images.snp.src = nbApi.getIcon("snp", nbApi.imgPath, true);

nbApi.images.author = new Image();
nbApi.images.author.src = nbApi.getIcon("author", nbApi.imgPath, true);

nbApi.images.organism = new Image();
nbApi.images.organism.src = nbApi.getIcon("organism", nbApi.imgPath, true);
  
nbApi.images.unknown = new Image();
nbApi.images.unknown.src = nbApi.getIcon("unknown", nbApi.imgPath, true);
  
nbApi.getAutocompleteConfig = function()
{        
  var config = {
    callback: function(targetId, bLoaded, json){
      var target = document.getElementById(targetId); 
      target.style.display = "inline";
    },
    message: null,
    searchBox: null,
    searchBoxId: null,
    targetId: null, //drop list id
    target: null,   // drop list
    numResults: null, // number of results to request from server
    getItemsDelay: 250,
    defaultText: "Search...",
    defaultTextClass: "",  // class to set when showing defaultText
    serviceUrl: "http://www.nextbio.com/b/autocomplete/autocomplete.nbs",
    header: null,   // header to display on top of the drop list
    headerClassName: null,   // CSS class to display header
    headerStyle: null,   // style to display header
    footer: null,   // footer to display at the bottom of the drop list
    footerClassName: null,   // CSS class to display footer
    footerStyle: null,   // style to display footer
    pageId: "ov", // default page id for onclick url
    focus: false, // if true, set focus to input after creating it
    className: "nbApiAutocompleteList", // class for the drop list
    callbackName: encodeURIComponent("nbApi.updateTargetHTML"),
    onKeyup: function(event){return nbApi.autocompleteOnKeyUp(event);},
    onKeydown: function(event){return nbApi.autocompleteOnKeyDown(event);},
    onClick: function(owner, cfg){return nbApi.autocompleteOnClickHandler(owner, cfg);},
    onBlur: function(event){return nbApi.autocompleteOnBlur(event);},
    onFocus: function(event){return nbApi.autocompleteOnFocus(event);},
    itemType: null, // name of type of item (e.g. "GENE"), or array of types (e.g. ["GENE","BIOGROUP"]) to lookup
    addedQuery: null, // additional arguments to be added to the query
    // parameters prefixed with nb are intended for internal NextBio use only, not for
    // the public API
    nbMessageId: null // Use this to look up a message on the server for the bottom of the autocomplete
  };     
  return config;
};
nbApi.autocompleteGetItems = function(owner, cfg, bNow)
{ 
  if (owner == null || cfg == null)
  {
    return true;
  }
  if (bNow != true)
  {
    if (cfg != null && cfg.targetId != null)
    {
      var target = document.getElementById(cfg.targetId);
      if (target != null)
        target.setAttribute("nextbio_allowUpdate", "true");
    }
    if (cfg.getItemsTimeout != null)
    {
      clearTimeout(cfg.getItemsTimeout);
      cfg.getItemsTimeout = null;
    }
    cfg.getItemsTimeout = setTimeout(function(){nbApi.autocompleteGetItems(owner, cfg, true)}, cfg.getItemsDelay);  
    return true;
  }
  cfg.getItemsTimeout = null;
  var query = nbApi.normalizeString(owner.value);
  if (query == null || query.length == 0)
    return;
  if (query == cfg.query)
  {
    nbApi.autocompleteShowList(cfg, true);
    return;
  }
  cfg.query = query;  
  query = "query=" + encodeURIComponent(query);
  query += "&apiKey=" + nbApi.apiKey;
  query += "&nameSpace=" +  "nbApi";
  query += "&boxId=" +  owner.id;
  if (cfg.nbMessageId) query += "&messageId="+cfg.nbMessageId;
  if (cfg.itemType) {
    if (typeof cfg.itemType == 'object') { // array
      for (var i=0; i<cfg.itemType.length; i++) {
        query += "&itemType=" + cfg.itemType[i];
      }
    } else {
      query += "&itemType="+cfg.itemType;
    }
  }
  if (cfg.numResults) {
    query += "&numResults=" + cfg.numResults;
  }
  if (cfg.addedQuery) {
    query += "&" + cfg.addedQuery;
  }
  var config = 
  {
    target: cfg.targetId,
    callbackName: cfg.callbackName,
    callback: function(target, bLoaded, json){nbApi.autocompleteShowList(cfg, true)},
    url: cfg.serviceUrl,
    query: query,
    message: cfg.message,
    messageStyle: cfg.messageStyle
  };  
  cfg.currentItem = null;
  nbApi.loadScript(config);  
  return true;
};
// create autocomplete box base on configuration object
// if existing boxId is supplied - use existing input control
// if targetId is supplied - create a box inside the target div 
nbApi.attachAutocomplete = function(config)
{   
  var bAlert = nbApi.getDebugMode();
  var searchBox = null;     
  // add target div here
  if (config.searchBoxId == null)
  {
    if (bAlert == true)
      alert("Nextbio Autocomplete: search box id not specified.");
    return;    
  }
  // if search box exists - convert it to autocomplete
  searchBox = document.getElementById(config.searchBoxId);
  if (searchBox == null)
  {
    if (bAlert == true)
      alert("Nextbio Autocomplete: search box not found.");
    return;
  }
  var dropListId = config.searchBoxId + "_drop_list";
  config.searchBox = searchBox;
  config.targetId = dropListId;
  searchBox.nextbioConfig = config;
  searchBox.setAttribute("autocomplete", "off");
  config.onKeyupChain = searchBox.onkeyup;
  searchBox.onkeyup = config.onKeyup;
  config.onKeydownChain = searchBox.onkeydown;
  searchBox.onkeydown = config.onKeydown;
  config.onBlurChain = searchBox.onblur;
  searchBox.onblur = config.onBlur;
  config.onFocusChain = searchBox.onfocus;
  searchBox.onfocus = config.onFocus;
  config.onClickChain = searchBox.onclick;
  searchBox.onclick = config.onClick;
  var value = nbApi.normalizeString(searchBox.value);
  if (value == null || value.length == 0)
  {
    searchBox.value = config.defaultText;
  }  
  // add div for drop list
  var target = document.createElement("div");
  config.target = target;
  target.id = dropListId;
  target.style.display = "none";
  target.style.position = "absolute";
  target.className = "nbApiAutocompleteList";
  var position = nbApi.findPosition(searchBox);
  target.style.width = searchBox.offsetWidth + "px";
  target.style.left = position.left + "px";
  var top = position.top + searchBox.offsetHeight;
  target.style.top = top + "px";
  target.nextbioTargetClassName = config.className;
  target.nextbioAutocompleteConfig = config;
  document.body.appendChild(target);
  config.onClickBodyChain = document.body.onclick;
  document.body.onclick = function(event){nbApi.autocompleteOnClickBody(event, config)};
  config.onKeyPressBodyChain = document.body.onkeypress;
  document.body.onkeypress = function(event){nbApi.autocompleteOnKeyPressBody(event, config)};
  config.onClickWindowChain = window.onclick;
  window.onclick = function(event){nbApi.autocompleteOnClickWindow(event, config)};
  config.onKeyPressWindowChain = window.onkeypress;
  window.onkeypress = function(event){nbApi.autocompleteOnKeyPressWindow(event, config)};
  config.onResizeWindowChain = window.onresize;
  window.onresize = function(event){nbApi.autocompleteOnResizeWindow(event, config)};

  if (config.focus) {
    searchBox.focus();
  }
};

// default onclick action for autocomplete drop list
// prepare a configuration object and call an onClick method provided in autocomplete configuration object.
nbApi.autocompleteOnClick = function(owner)
{ 
  if (owner == null)
    return false;
  var config = nbApi.autocompleteFindConfig(owner);
  if (config == null || config.onClick == null)
    return false;
  var cfg = {};
  cfg.uid = owner.getAttribute("nextbioUid"); 
  cfg.searchBoxId = config.searchBoxId; 
  cfg.searchBox = config.searchBox; 
  cfg.targetId = config.targetId;
  cfg.target = config.target;
  cfg.id = owner.getAttribute("nextbioId"); 
  cfg.name = owner.getAttribute("nextbioName"); 
  cfg.symbol = owner.getAttribute("nextbioSymbol"); 
  cfg.alias = owner.getAttribute("nextbioAlias"); 
  cfg.synonym = owner.getAttribute("nextbioSynonym");
  cfg.type = owner.getAttribute("nextbioType");
  cfg.pageId = config.pageId;
  return config.onClick(owner, cfg);
};
nbApi.autocompleteOnClickHandler = function(owner, config)
{ 
  if (owner == null || config == null)
    return false;

  var page = config.pageId;
  var type = config.type;
  if (config.searchBox != null)
  {
    config.searchBox.value = config.symbol;
  }
  if (type != null && type.toLowerCase() == "author")
  {
    window.location = "http://www.nextbio.com/b/search/author/" + encodeURIComponent(config.symbol); 
  }
  else
  {
    if (config.id == null || config.type == null || config.type == "text")
    {
      window.location = nbApi.searchUrl("http://www.nextbio.com/b","ov",config.symbol);
    }
    else
    {
      window.location = nbApi.searchUrl("http://www.nextbio.com/b",page,config.symbol,
        "id=" + encodeURIComponent(config.id) + 
        "&type=" + config.type +
        "&synonym=" + encodeURIComponent(config.synonym));
    }
  }
  nbApi.autocompleteShowList(config, false);
  nbApi.autocompleteDeselectItem(config.currentItem, true);
  return true;
};
// default mouseover action for autocomplete drop list
nbApi.autocompleteOnMouseOver = function(owner)
{   
  nbApi.autocompleteSelectItem(owner);
};
// default mouseout action for autocomplete drop list
nbApi.autocompleteOnMouseOut = function(owner)
{   
  nbApi.autocompleteDeselectItem(owner);
};
// select drop list item
nbApi.autocompleteSelectItem = function(owner, force)
{   
  var config = nbApi.autocompleteFindConfig(owner);
  if (config == null || config.lock && force != true)
    return;
  if (force != true)
    config.lock = true;  

  var items = nbApi.findElementsByName(config.searchBoxId + "_autocomplete_item", "tr");
  var i = 0;
  for (i = 0; i < items.length; i++)
  {
    nbApi.removeClass(items[i], 'nbApiAutocompleteSelectedItem');
  }  
  nbApi.addClass(owner, 'nbApiAutocompleteSelectedItem');
  config.currentItem = owner;  
  if (force != true)
    config.lock = false;  
};
// select next drop list item
nbApi.autocompleteSelectNextItem = function(config)
{   
  if (config == null || config.lock)
    return;
  config.lock = true;  
  var currentItem = config.currentItem;  
  var items = nbApi.findElementsByName(config.searchBoxId + "_autocomplete_item", "tr");
  var index = -1;
  var i = 0;

  for (i = 0; i < items.length; i++)
  {
    if (items[i] === currentItem)
    {
      index = i;
      break;
    }
  }  
  index++;
  var nextItem = null;
  if (index >= items.length)
    index = items.length - 1;
  nextItem = items[index];
//  nbApi.autocompleteDeselectItem(config.currentItem);
  nbApi.autocompleteSelectItem(nextItem, true);
  config.lock = false;  
};

// select previous drop list item
nbApi.autocompleteSelectPrevItem = function(config)
{   
  if (config == null || config.lock)
    return;
  config.lock = true;  
  var currentItem = config.currentItem;  
  var items = nbApi.findElementsByName(config.searchBoxId + "_autocomplete_item", "tr");
  var index = items.length;
  var i = 0;
  for (i = 0; i < items.length; i++)
  {
    if (items[i] === currentItem)
    {
      index = i;
      break;
    }
  }  
  index--;
  var prevItem = null;
  if (index < 0)
    index = 0;
  prevItem = items[index];
//  nbApi.autocompleteDeselectItem(config.currentItem);
  nbApi.autocompleteSelectItem(prevItem, true);
  config.lock = false;  
};
// deselect drop list item
nbApi.autocompleteDeselectItem = function(owner, force)
{   
  nbApi.removeClass(owner, 'nbApiAutocompleteSelectedItem');
  var config = nbApi.autocompleteFindConfig(owner);
  if (config == null)
    return;
  if (force == true || config.currentItem == owner)
    config.currentItem = null;  
};

nbApi.autocompleteOnKeyUp = function(event)
{ 
  if (event == null)
  { 
    event = window.event;
  }
  var owner = event.target;
  if (owner == null)
    owner = event.srcElement;
  if (owner == null)
  {
    return true;
  }
  var config = owner.nextbioConfig;  
  var key = null;
  if (event.keyCode != null)
    key = event.keyCode;
  else if (event.which != null)
    key = event.which;

  if (key == null)
    return true;

  var rc = true;
  var query = nbApi.normalizeString(owner.value);
  var empty = (query == null || query.length == 0);
  if (empty || key == 27) 
  {
    if (config != null && config.targetId != null)
    {
      nbApi.autocompleteShowList(config, false);
      nbApi.autocompleteDeselectItem(config.currentItem, true);
    }
    return true;
  }
  else if (key == 13) 
  {
    if (config != null && config.targetId != null)
    {
      var target = document.getElementById(config.targetId);
      if (target != null)
        target.setAttribute("nextbio_allowUpdate", "false");
      if (config.currentItem != null)
      {
        nbApi.autocompleteOnClick(config.currentItem);
        return false;
      }
      nbApi.autocompleteShowList(config, false);
    }
    return true;
  }
  else if (config != null && config.target != null && config.target.nextbioIsLoaded == true)
  {
    if (key == 40) // down arrow
    {                                                         
      nbApi.autocompleteShowList(config, true);
      nbApi.autocompleteSelectNextItem(config);
      return true; 
    }
    if (key == 38) // up arrow
    {
      nbApi.autocompleteShowList(config, true);
      nbApi.autocompleteSelectPrevItem(config);
      return true;
    }
  }
  if (key != 37 && key != 39) // left and right arrows
  {
    rc = nbApi.autocompleteGetItems(owner, config);
  }
  if (config.onKeyupChain != null)
    return config.onKeyupChain(event);
  return rc;
};

nbApi.autocompleteOnKeyDown = function(event)
{ 
  if (event == null)
  { 
    event = window.event;
  }
  var owner = event.target;
  if (owner == null)
    owner = event.srcElement;
  if (owner == null)
  {
    return true;
  }
  var key = null;
  if (event.keyCode != null)
    key = event.keyCode;
  else if (event.which != null)
    key = event.which;

  var config = owner.nextbioConfig;
  var value = nbApi.normalizeString(owner.value);
  if (value == config.defaultText)
  {
    owner.value = "";
  }  
  if (key == 13) // enter
  {
    if (config != null && config.targetId != null)
    {
      var target = document.getElementById(config.targetId);
      if (target != null)
        target.setAttribute("nextbio_allowUpdate", "false");
      
      if (config.currentItem != null)
      {
        nbApi.autocompleteOnClick(config.currentItem);
        return false;
      }
      nbApi.autocompleteShowList(config, false);
    }
    return true;
  }
  if (config.onKeydownChain != null)
    return config.onKeydownChain(event);
  return true;

};

// find autocomplete config object for any object within drop list
nbApi.autocompleteFindConfig = function(owner)
{ 
  if (owner == null)
    return false;
  var parent = nbApi.findParentByTagName(owner, "div");  
  var config = null;  
  while (parent != null)
  {
    config = parent.nextbioAutocompleteConfig;
    if (config != null)
      break;
    parent = nbApi.findParentByTagName(parent, "div");
  }  
  return config;
};

nbApi.autocompleteOnClickBody = function(event, config)
{
  nbApi.autocompleteShowList(config, false);
  nbApi.autocompleteDeselectItem(config.currentItem, true);
  if (config != null && config.onClickBodyChain != null)
    return config.onClickBodyChain(event);
  return true;
};
nbApi.autocompleteOnClickWindow = function(event, config)
{
  nbApi.autocompleteShowList(config, false);
  nbApi.autocompleteDeselectItem(config.currentItem, true);
  if (config != null && config.onClickWindowChain != null)
    return config.onClickWindowChain(event);
  return true;
};
nbApi.autocompleteOnKeyPressBody = function(event, config)
{
  if (event == null)
  { 
    event = window.event;
  }
  var key = null;
  if (event.keyCode != null)
    key = event.keyCode;
  else if (event.which != null)
    key = event.which;
  if (key == 27)  // escape key
  {
    nbApi.autocompleteShowList(config, false);
    nbApi.autocompleteDeselectItem(config.currentItem, true);
  }
  if (config != null && config.onKeyPressBodyChain != null)
    return config.onKeyPressBodyChain(event);
  return true;
};
nbApi.autocompleteOnKeyPressWindow = function(event, config)
{
  if (event == null)
  { 
    event = window.event;
  }
  var key = null;
  if (event.keyCode != null)
    key = event.keyCode;
  else if (event.which != null)
    key = event.which;
  if (key == 27)  // escape key
  {
    nbApi.autocompleteShowList(config, false);
    nbApi.autocompleteDeselectItem(config.currentItem, true);
  }
  if (config != null && config.onKeyPressWindowChain != null)
    return config.onKeyPressWindowChain(event);
  return true;
};

nbApi.autocompleteOnResizeWindow = function(event, config)
{
  if (event == null)
  { 
    event = window.event;
  }
  if (config == null)
  {
    return;
  }
  if (config.target == null || config.searchBox == null)
  {
    if (config.onResizeWindowChain != null)
      return config.onResizeWindowChain(event);
    return true;
  }
  var position = nbApi.findPosition(config.searchBox);
  config.target.style.width = config.searchBox.offsetWidth + "px";
  config.target.style.left = position.left + "px";
  var top = position.top + config.searchBox.offsetHeight;
  config.target.style.top = top + "px";
  if (config.onResizeWindowChain != null)
    return config.onResizeWindowChain(event);
  return true;
};

nbApi.autocompleteOnScrollWindow = function(config)
{
  if (config == null)
  {
    return;
  }
  var position = nbApi.findPosition(config.searchBox);
  config.target.style.width = config.searchBox.offsetWidth + "px";
  config.target.style.left = position.left + "px";
  var top = position.top + config.searchBox.offsetHeight;
  config.target.style.top = top + "px";
  window.nbScrollTimeout = setTimeout(function(){nbApi.autocompleteOnScrollWindow(config)}, 200);  
  return true;
};

nbApi.autocompleteOnBlur = function(event)
{
  if (event == null)
  { 
    event = window.event;
  }
  var owner = event.target;
  if (owner == null)
    owner = event.srcElement;
  if (owner == null)
  {
    return true;
  }
  var config = owner.nextbioConfig;
  var value = nbApi.normalizeString(owner.value);
  if (value == null || value.length == 0)
  {
    owner.value = config.defaultText;
    if (config.defaultTextClass) {
      nbApi.addClass(owner, config.defaultTextClass);
    }
  }  
  if (config.onBlurChain != null)
    return config.onBlurChain(event);
  return true;
};  

nbApi.autocompleteOnFocus = function(event)
{
  if (event == null)
  { 
    event = window.event;
  }
  var owner = event.target;
  if (owner == null)
    owner = event.srcElement;
  if (owner == null)
  {
    return true;
  }
  var config = owner.nextbioConfig;
  var value = nbApi.normalizeString(owner.value);
  if (value == config.defaultText)
  {
    owner.value = "";
    if (config.defaultTextClass) {
      nbApi.removeClass(owner, config.defaultTextClass);
    }
  }  
  if (config.onFocusChain != null && config.onFocusChain != nbApi.autocompleteOnFocus)
    return config.onFocusChain(event);
  return true;
};  

nbApi.autocompleteShowList = function(config, bShow)
{
  if (config == null || config.target == null || config.searchBox == null)
    return;
  var position = nbApi.findPosition(config.searchBox);
  config.target.style.width = config.searchBox.offsetWidth + "px";
  config.target.style.left = position.left + "px";
  var top = position.top + config.searchBox.offsetHeight;
  config.target.style.top = top + "px";

  nbApi.show(config.targetId, bShow);
  if (window.nbScrollTimeout)
  {
    clearTimeout(window.nbScrollTimeout);
    window.nbScrollTimeout = null;
  }
  if (bShow)
  {
    window.nbScrollTimeout = setTimeout(function(){nbApi.autocompleteOnScrollWindow(config)}, 200);  
  }
};

nbApi.createAutocomplete = function(cfg, debugMode)
{
  nbApi.setDebugMode(debugMode == true);
  var config = nbApi.getAutocompleteConfig();
  var idx;
  for (idx in cfg)
  {
    config[idx] = cfg[idx];
  }
  nbApi.attachAutocomplete(config);
};

  
    
// NextBio effects JavaScript library 
// requires jsApi.jsp, jsUtils.jsp

nbApi.highlightSteps = 25;
nbApi.highlightColor = "#93B6E0";
nbApi.highlightDuration = 1000;

  /**
   * Highlight an element by color-flashing it's background
   * @param el, element, e.g. <div>, <span>
   * @param step, step number in the highlight sequence. For internal use only.    
   */
  nbApi.highlight = function(el, step, target, startTime) 
  { 
  	
  		
  		
  			return;
  		
    


  };
  
  /**
   * Convert RGB string to a JSON object with R, G and B values
   * @param rgb, RGB string, i.e. "#ffeebb"
   */
  nbApi.rgb2json = function(rgb)
  {
    if (rgb == null || rgb.length == 0 || rgb.indexOf("#") != 0)
      return {r: 0, g: 0, b: 0};
    var rStr, gStr, bStr;
    rStr = gStr = bStr ="00";
    rStr = rgb.substr(1, 2); 
    if (rgb.length > 3)  
      gStr = rgb.substr(3, 2);
    if (rgb.length > 5)  
      bStr = rgb.substr(5, 2);
    
    var json = {r: parseInt(rStr, 16), g: parseInt(gStr, 16), b: parseInt(bStr, 16)};
    return json;  
  }

  /**
   * Convert RGB values to a JSON object with H, S and L (hue, saturation and luminosity) values
   * @param R, R-value, integer
   * @param G, G-value, integer
   * @param B, B-value, integer
   */
  nbApi.rgb2hsl = function(R, G, B)
  {  
    var H, S, L;
    var var_R = ( R / 255 );                     //RGB from 0 to 255
    var var_G = ( G / 255 );
    var var_B = ( B / 255 );
    
    var var_Min = Math.min( var_R, var_G, var_B );    //Min. value of RGB
    var var_Max = Math.max( var_R, var_G, var_B );    //Max. value of RGB
    var del_Max = var_Max - var_Min;             //Delta RGB value
    
    L = ( var_Max + var_Min ) / 2 ;
    if ( del_Max == 0 )                     //This is a gray, no chroma...
    {
       H = 0;                                //HSL results from 0 to 1
       S = 0;
    }
    else                                    //Chromatic data...
    {
      if ( L < 0.5 ) 
        S = del_Max / ( var_Max + var_Min );
      else           
        S = del_Max / ( 2 - var_Max - var_Min );
      
      var del_R = ( ( ( var_Max - var_R ) / 6 ) + ( del_Max / 2 ) ) / del_Max;
      var del_G = ( ( ( var_Max - var_G ) / 6 ) + ( del_Max / 2 ) ) / del_Max;
      var del_B = ( ( ( var_Max - var_B ) / 6 ) + ( del_Max / 2 ) ) / del_Max;
      
      if ( var_R == var_Max ) 
        H = del_B - del_G;
      else if ( var_G == var_Max ) 
        H = ( 1 / 3 ) + del_R - del_B;
      else if ( var_B == var_Max ) 
        H = ( 2 / 3 ) + del_G - del_R;
      
      if ( H < 0 ) 
        H += 1;
      if ( H > 1 )
        H -= 1;
    }  
    return {h: H, s: S, l: L}
  }  
  
  /**
   * Convert HSL values to a JSON object with R, G and B values
   * @param H, H-value, integer
   * @param S, S-value, integer
   * @param L, L-value, integer
   */
  nbApi.hsl2rgb = function(H, S, L)
  {
    var R, G, B, var_1, var_2;
    if ( S == 0 )                       //HSL from 0 to 1
    {
       R = L * 255;                      //RGB results from 0 to 255
       G = L * 255;
       B = L * 255;
    }
    else
    {
      if ( L < 0.5 ) 
        var_2 = L * ( 1 + S );
      else           
        var_2 = ( L + S ) - ( S * L );
      
      var_1 = 2 * L - var_2;
      
      R = 255 * nbApi.Hue_2_RGB( var_1, var_2, H + ( 1 / 3 ) );
      G = 255 * nbApi.Hue_2_RGB( var_1, var_2, H );
      B = 255 * nbApi.Hue_2_RGB( var_1, var_2, H - ( 1 / 3 ) );
    }
    return {r: new Number(R).toFixed(0), g: new Number(G).toFixed(0), b: new Number(B).toFixed(0)}; 
  }

  /**
   * Internal helper function
   */
  nbApi.Hue_2_RGB = function( v1, v2, vH )             //Function Hue_2_RGB
  {
    if ( vH < 0 ) 
      vH += 1;
    if ( vH > 1 ) 
      vH -= 1;
    if ( ( 6 * vH ) < 1 ) 
      return v1 + ( v2 - v1 ) * 6 * vH;
    if ( ( 2 * vH ) < 1 ) 
      return v2;
    if ( ( 3 * vH ) < 2 ) 
      return v1 + ( v2 - v1 ) * ( ( 2 / 3 ) - vH ) * 6;
    return v1;
  }


         


