    var db = new Array();

    var hasParts = false;
    var hasChapters = false;
    var thisRecord;
    var inPrefaceyThing = false;
    var i;

    for (i=1; i < inputArray.length-1; i++) {
      thisRecord = inputArray[i];

      hasParts = (thisRecord[0] == "0");
      if (hasParts) break;

      hasChapters = hasChapters || (thisRecord.charAt(0) == "2");
    }

    var PART, CHAPP, H1, H2;

    if      (hasParts)     {PART = 0; CHAPP = 1; H1 = 2; H2 = 3;}
    else if (hasChapters)  {CHAPP = 0; H1 = 1; H2 = 2;}
    else                   {CHAPP = 0; H1 = 0; H2 = 1;}


    // TYPE::TITLE::"URL"
    // becomes db[i] = new dbRecord(HASCHILD, "TITLE", "URL", DEPTH, "")

    var thisType, nextType;
    var thisRecord, nextRecord;
    for (i=1; i < inputArray.length-2; i++) {

      thisRecord = inputArray[i];
      nextRecord = inputArray[i+1];

      thisType = thisRecord.charAt(0);
      nextType = nextRecord.charAt(0);
      if (nextType == "x") {
        hasChild = false;
      } else {
        hasChild = (thisType < nextType);
      }

      if      (thisType == "0") {depth = PART;  inPrefaceyThing = false;}
      else if (thisType == "1") {depth = 0;     inPrefaceyThing = true;}
      else if (thisType == "2") {depth = CHAPP; inPrefaceyThing = false;}
      else if (thisType == "3") {inPrefaceyThing ? depth = 1 : depth = H1}
      else                      {inPrefaceyThing ? depth = 2 : depth = H2}

      title = thisRecord.substring(3, thisRecord.lastIndexOf('::'));
      url   = thisRecord.substring(thisRecord.lastIndexOf('::\"')+ 3, thisRecord.length-1);

      db[i] = new dbRecord(hasChild, title, url, depth, "");
    }

    if (nextType != "x") {
      title = nextRecord.substring(3, nextRecord.lastIndexOf('::'));
      url   = nextRecord.substring(nextRecord.lastIndexOf('::\"')+ 3, nextRecord.length-1);
      if      (nextType == "0") depth = PART;
      else if (nextType == "1") depth = 0;
      else if (nextType == "2") depth = CHAPP;
      else if (nextType == "3") {inPrefaceyThing ? depth = 1 : depth = H1}
      else                      {inPrefaceyThing ? depth = 2 : depth = H2}
      db[i]   = new dbRecord(false, title, url, depth, "");
    }

    // object constructor for each outline entry
    function dbRecord(mother,display,URL,indent,statusMsg){
        this.mother = mother   // is this item a parent?
        this.display = display // text to display
        this.URL = URL         // link tied to text; if empty string, item appears as straight text
        this.indent = indent   // how many levels nested?
        this.statusMsg = statusMsg  // descriptive text for status bar
        return this
    }

    // pre-load all images into cache
    var fillerImg = new Image(1,1)
    fillerImg.src = "/img/filler.gif"
    var collapsedImg = new Image(widgetWidth,widgetHeight)
    collapsedImg.src = collapsedWidget
    var expandedImg = new Image(widgetWidth,widgetHeight)
    expandedImg.src = expandedWidget
    var endpointImg = new Image(widgetWidth,widgetHeight)
    endpointImg.src = endpointWidget

    var mycookie = document.cookie
    function setCurrState(setting) {
       mycookie = document.cookie = "currState=" + escape(setting)
    }

    function getCurrState() {
       var label = "currState="
       var labelLen = label.length
       var cLen = mycookie.length
       var i = 0
       while (i < cLen) {
          var j = i + labelLen
          if (mycookie.substring(i,j) == label) {
             var cEnd = mycookie.indexOf(";",j)
             if (cEnd ==     -1) {
                cEnd = mycookie.length
             }
             return unescape(mycookie.substring(j,cEnd))
          }
          i++
       }
       return ""
    }

    function toggle(n) {
        if (n != 0) {
            var newString = ""
            var currState = getCurrState() // of whole outline
            var expanded = currState.charAt(n-1) // of clicked item
            newString += currState.substring(0,n-1)
            newString += expanded ^ 1 // Bitwise XOR clicked item
            newString += currState.substring(n,currState.length)
            setCurrState(newString) // write new state back to cookie
        }
    }

    function getGIF(n) {
        var mom = db[n].mother  // is entry a parent?
        var expanded = getCurrState().charAt(n-1) // of clicked item
        if (!mom) {
            return endpointWidget
        } else {
            if (expanded == 1) {
                return expandedWidget
            }
        }
        return collapsedWidget
    }

    // returns the proper status line text based on the icon style
    function getGIFStatus(n) {
        var mom = db[n].mother  // is entry a parent
        var expanded = getCurrState().charAt(n-1) // of rolled item
        if (!mom) {
            return "No tiene t&oacute;picos."
        } else {
            if (expanded == 1) {
                return "Haga click aqu&iacute; para cerrar los t&oacute;picos del tema."
            }
        }
        return "Haga click aqu&iacute; para ver los t&oacute;picos del tema."
    }

    // initialize 'current state' storage field
    if (getCurrState() == "" || getCurrState().length != (db.length-1)) {
        initState = ""
        for (i = 1; i < db.length; i++) {
            initState += "0"
        }
        setCurrState(initState)
    }
