whole_func_string: function outlineExpand (p, subject1, options) {
      options = options || {}
      var pane = options.pane
      var already = !!options.already
      var immediate = options.immediate
  
      UI.log.info('@outlineExpand, dom is now ' + dom.location)
        // remove callback to prevent unexpected repaint
      sf.removeCallback('done', 'expand')
      sf.removeCallback('fail', 'expand')
  
      var subject = kb.canon(subject1)
      // var requTerm = subject.uri ? kb.sym(UI.rdf.uri.docpart(subject.uri)) : subject
  
      function render () {
        subject = kb.canon(subject)
        if (!p || !p.parentNode || !p.parentNode.parentNode) return false
  
        var newTable
        UI.log.info('@@ REPAINTING ')
        if (!already) { // first expand
          newTable = propertyTable(subject, undefined, pane, options)
        } else {
          UI.log.info(' ... p is  ' + p)
          for (newTable = p.firstChild; newTable.nextSibling; newTable = newTable.nextSibling) {
            UI.log.info(' ... checking node ' + newTable)
            if (newTable.nodeName === 'table') break
          }
          newTable = propertyTable(subject, newTable, pane, options)
        }
        already = true
        if (UI.utils.ancestor(p, 'TABLE') && UI.utils.ancestor(p, 'TABLE').style.backgroundColor === 'white') {
          newTable.style.backgroundColor = '#eee'
        } else {
          newTable.style.backgroundColor = 'white'
        }
        try {
          if (YAHOO.util.Event.off) YAHOO.util.Event.off(p, 'mousedown', 'dragMouseDown')
        } catch (e) {
          console.log('YAHOO ' + e)
        }
        UI.utils.emptyNode(p).appendChild(newTable)
        thisOutline.focusTd = p // I don't know why I couldn't use 'this'...because not defined in callbacks
        UI.log.debug('expand: Node for ' + subject + ' expanded')
            // fetch seeAlso when render()
            // var seeAlsoStats = sf.store.statementsMatching(subject, UI.ns.rdfs('seeAlso'))
            // seeAlsoStats.map(function (x) {sf.lookUpThing(x.object, subject,false);})
        var seeAlsoWhat = kb.each(subject, UI.ns.rdfs('seeAlso'))
        for (var i = 0; i < seeAlsoWhat.length; i++) {
          if (i === 25) {
            UI.log.warn('expand: Warning: many (' +
                  seeAlsoWhat.length + ') seeAlso links for ' + subject)
                // break; Not sure what limits the AJAX system has here
          }
          sf.lookUpThing(seeAlsoWhat[i], subject)
        }
      }
  
      function expand (uri) {
        if (arguments[3]) return true // already fetched indicator
        var cursubj = kb.canon(subject) // canonical identifier may have changed
        UI.log.info('@@ expand: relevant subject=' + cursubj + ', uri=' + uri + ', already=' + already)
        // var term = kb.sym(uri)
        var docTerm = kb.sym(UI.rdf.uri.docpart(uri))
        if (uri.indexOf('#') >= 0) { throw new Error('Internal error: hash in ' + uri) }
  
        var relevant = function () { // Is the loading of this URI relevam to the display of subject?
          if (!cursubj.uri) return true // bnode should expand()
          var as = kb.uris(cursubj)
          if (!as) return false
          for (var i = 0; i < as.length; i++) { // canon'l uri or any alias
            for (var rd = UI.rdf.uri.docpart(as[i]); rd; rd = kb.HTTPRedirects[rd]) {
              if (uri === rd) return true
            }
          }
          if (kb.anyStatementMatching(cursubj, undefined, undefined, docTerm)) return true // Kenny: inverse?
          return false
        }
        if (relevant()) {
          UI.log.success('@@ expand OK: relevant subject=' + cursubj + ', uri=' + uri + ', source=' +
                already)
  
          render()
          return false //  @@@@@@@@@@@ Will this allow just the first
        }
        return true
      }
          // Body of outlineExpand
  
      if (options.solo) {
        dom.title = UI.utils.label(subject)
      }
      UI.log.debug('outlineExpand: dereferencing ' + subject)
      var status = dom.createElement('span')
      p.appendChild(status)
      sf.addCallback('done', expand) // @@@@@@@ This can really mess up existing work
      sf.addCallback('fail', expand) // Need to do if there s one a gentle resync of page with store
  
      var returnConditions = [] // this is quite a general way to do cut and paste programming
        // I might make a class for this
      if (subject.uri && subject.uri.split(':')[0] === 'rdf') { // what is this? -tim
        render()
        return
      }
  
      for (var i = 0; i < returnConditions.length; i++) {
        var returnCode
        if (returnCode === returnConditions[i](subject)) {
          render()
          UI.log.debug('outline 1815')
          if (returnCode[1]) outlineElement.removeChild(outlineElement.lastChild)
          return
        }
      }
      if (subject.uri && !immediate && !UI.widgets.isAudio(subject) &&
          !UI.widgets.isVideo(subject) && // Never parse videos as data
          !kb.holds(subject, UI.ns.rdf('type'), $rdf.Util.mediaTypeClass('application/pdf'))) { // or PDF
          // Wait till at least the main URI is loaded before expanding:
        sf.nowOrWhenFetched(subject.doc(), undefined, function (ok, body) {
          if (ok) {
            sf.lookUpThing(subject)
            render() // inital open, or else full if re-open
            if (options.solo) { // Update window title with new information
              dom.title = UI.utils.label(subject)
            }
          } else {
            var message = dom.createElement('pre')
            message.textContent = body
            message.setAttribute('style', 'background-color: #fee;')
            message.textContent = 'Outline.expand: Unable to fetch ' + subject.doc() + ': ' + body
            p.appendChild(message)
          }
        })
      } else {
        render()
      };
    }
func_code_string: function outlineExpand (p, subject1, options) {
      options = options || {}
      var pane = options.pane
      var already = !!options.already
      var immediate = options.immediate
  
      UI.log.info('@outlineExpand, dom is now ' + dom.location)
        // remove callback to prevent unexpected repaint
      sf.removeCallback('done', 'expand')
      sf.removeCallback('fail', 'expand')
  
      var subject = kb.canon(subject1)
      // var requTerm = subject.uri ? kb.sym(UI.rdf.uri.docpart(subject.uri)) : subject
  
      function render () {
        subject = kb.canon(subject)
        if (!p || !p.parentNode || !p.parentNode.parentNode) return false
  
        var newTable
        UI.log.info('@@ REPAINTING ')
        if (!already) { // first expand
          newTable = propertyTable(subject, undefined, pane, options)
        } else {
          UI.log.info(' ... p is  ' + p)
          for (newTable = p.firstChild; newTable.nextSibling; newTable = newTable.nextSibling) {
            UI.log.info(' ... checking node ' + newTable)
            if (newTable.nodeName === 'table') break
          }
          newTable = propertyTable(subject, newTable, pane, options)
        }
        already = true
        if (UI.utils.ancestor(p, 'TABLE') && UI.utils.ancestor(p, 'TABLE').style.backgroundColor === 'white') {
          newTable.style.backgroundColor = '#eee'
        } else {
          newTable.style.backgroundColor = 'white'
        }
        try {
          if (YAHOO.util.Event.off) YAHOO.util.Event.off(p, 'mousedown', 'dragMouseDown')
        } catch (e) {
          console.log('YAHOO ' + e)
        }
        UI.utils.emptyNode(p).appendChild(newTable)
        thisOutline.focusTd = p // I don't know why I couldn't use 'this'...because not defined in callbacks
        UI.log.debug('expand: Node for ' + subject + ' expanded')
            // fetch seeAlso when render()
            // var seeAlsoStats = sf.store.statementsMatching(subject, UI.ns.rdfs('seeAlso'))
            // seeAlsoStats.map(function (x) {sf.lookUpThing(x.object, subject,false);})
        var seeAlsoWhat = kb.each(subject, UI.ns.rdfs('seeAlso'))
        for (var i = 0; i < seeAlsoWhat.length; i++) {
          if (i === 25) {
            UI.log.warn('expand: Warning: many (' +
                  seeAlsoWhat.length + ') seeAlso links for ' + subject)
                // break; Not sure what limits the AJAX system has here
          }
          sf.lookUpThing(seeAlsoWhat[i], subject)
        }
      }
  
      function expand (uri) {
        if (arguments[3]) return true // already fetched indicator
        var cursubj = kb.canon(subject) // canonical identifier may have changed
        UI.log.info('@@ expand: relevant subject=' + cursubj + ', uri=' + uri + ', already=' + already)
        // var term = kb.sym(uri)
        var docTerm = kb.sym(UI.rdf.uri.docpart(uri))
        if (uri.indexOf('#') >= 0) { throw new Error('Internal error: hash in ' + uri) }
  
        var relevant = function () { // Is the loading of this URI relevam to the display of subject?
          if (!cursubj.uri) return true // bnode should expand()
          var as = kb.uris(cursubj)
          if (!as) return false
          for (var i = 0; i < as.length; i++) { // canon'l uri or any alias
            for (var rd = UI.rdf.uri.docpart(as[i]); rd; rd = kb.HTTPRedirects[rd]) {
              if (uri === rd) return true
            }
          }
          if (kb.anyStatementMatching(cursubj, undefined, undefined, docTerm)) return true // Kenny: inverse?
          return false
        }
        if (relevant()) {
          UI.log.success('@@ expand OK: relevant subject=' + cursubj + ', uri=' + uri + ', source=' +
                already)
  
          render()
          return false //  @@@@@@@@@@@ Will this allow just the first
        }
        return true
      }
          // Body of outlineExpand
  
      if (options.solo) {
        dom.title = UI.utils.label(subject)
      }
      UI.log.debug('outlineExpand: dereferencing ' + subject)
      var status = dom.createElement('span')
      p.appendChild(status)
      sf.addCallback('done', expand) // @@@@@@@ This can really mess up existing work
      sf.addCallback('fail', expand) // Need to do if there s one a gentle resync of page with store
  
      var returnConditions = [] // this is quite a general way to do cut and paste programming
        // I might make a class for this
      if (subject.uri && subject.uri.split(':')[0] === 'rdf') { // what is this? -tim
        render()
        return
      }
  
      for (var i = 0; i < returnConditions.length; i++) {
        var returnCode
        if (returnCode === returnConditions[i](subject)) {
          render()
          UI.log.debug('outline 1815')
          if (returnCode[1]) outlineElement.removeChild(outlineElement.lastChild)
          return
        }
      }
      if (subject.uri && !immediate && !UI.widgets.isAudio(subject) &&
          !UI.widgets.isVideo(subject) && // Never parse videos as data
          !kb.holds(subject, UI.ns.rdf('type'), $rdf.Util.mediaTypeClass('application/pdf'))) { // or PDF
          // Wait till at least the main URI is loaded before expanding:
        sf.nowOrWhenFetched(subject.doc(), undefined, function (ok, body) {
          if (ok) {
            sf.lookUpThing(subject)
            render() // inital open, or else full if re-open
            if (options.solo) { // Update window title with new information
              dom.title = UI.utils.label(subject)
            }
          } else {
            var message = dom.createElement('pre')
            message.textContent = body
            message.setAttribute('style', 'background-color: #fee;')
            message.textContent = 'Outline.expand: Unable to fetch ' + subject.doc() + ': ' + body
            p.appendChild(message)
          }
        })
      } else {
        render()
      };
    }
func_documentation_string: function TabulatorMousedown