  function _adjustHeightOfElement(theElement, from, to, frames, currentFrame, callback)
  {
    if (currentFrame > frames)
    {
      theElement.style.height = 'auto';        
      callback();
      return;
    }
    
    var decrement = Math.ceil((from - to) / frames);
    var newHeight = from - (decrement * currentFrame);
    theElement.style.height = newHeight + 'px';
    theElement.style.overflow = 'hidden';
    setTimeout(function(){ _adjustHeightOfElement(theElement, from, to, frames, currentFrame + 1, callback)}, 10);
  }

  function firstChildElementOfType(theElement, childType)
  {
    for (var i = 0; i < theElement.childNodes.length; i++)
    {
      var node = theElement.childNodes[i];
      if (node.nodeType == 1 && node.nodeName == childType.toUpperCase())
      {
        return node;
      }
    }  
  }
  
  var _cache = new Array();
  function getCachedVisibleHeight(theElement)
  {
    theElement = firstChildElementOfType(theElement, 'ul');
    if (! theElement)
      return 0;

    if (! _cache[theElement.id])
    {
      _cache[theElement.id] = theElement.offsetHeight + 12;
    }
    return _cache[theElement.id];
  }

  function _showElement(element)
  {
    element.className = 'visible';
    var h = getCachedVisibleHeight(element);
    element.style.height = '17px';
    element.style.overflow = 'hidden';                                
    _adjustHeightOfElement(element, 17, h, (h - 12) / 10, 0, function(){ doneAnimating = true;});

  }
  
  doneAnimating = true;
  function hideElementThenShowElement(elementToHide, elementToShow)
  {
    var h = elementToHide.offsetHeight - 12;
    _adjustHeightOfElement(elementToHide, h, 17, h / 10, 0,
                           function()
                           {
                             elementToHide.className = 'hidden';
                             elementToShow.className = 'visible';                                                                  
                             _showElement(elementToShow);
                           });
  }
  
  function toggleVisibility(thisElement)
  {
    if (! doneAnimating)
      return;

    doneAnimating = false;

    var disclosureElement = thisElement.parentNode.parentNode;
    var clickedListElement = thisElement.parentNode;
    for (var i = 0; i < disclosureElement.childNodes.length; i++)
    {
      var node = disclosureElement.childNodes[i];
      if (node.nodeType == 1 && node.className != 'hidden')
      {
        if (node != clickedListElement)
          hideElementThenShowElement(node, clickedListElement);
        else
          doneAnimating = true;
        return;
      }
    }
    _showElement(clickedListElement);
  }
