From ed518f4868febbbe743a1dccad72369f12b8cd41 Mon Sep 17 00:00:00 2001
From: Jake Read <jake.read@cba.mit.edu>
Date: Tue, 10 Dec 2019 15:09:40 -0500
Subject: [PATCH] global hunks

---
 bootstrap.js        |   4 +-
 core/manager.js     |   3 +-
 core/scope.js       | 625 ++++------------------------------
 hunks/hunks.js      |   2 +-
 hunks/view.js       |  10 +-
 scratch/old-defs.js | 734 ++++++++++++++++++++++++++++++++++++++++
 scratch/old-view.js | 495 +++++++++++++++++++++++++++
 style.css           |   7 +
 view/blocks.js      | 800 +++-----------------------------------------
 9 files changed, 1361 insertions(+), 1319 deletions(-)
 create mode 100644 scratch/old-defs.js
 create mode 100644 scratch/old-view.js

diff --git a/bootstrap.js b/bootstrap.js
index 4910920..7a124fe 100644
--- a/bootstrap.js
+++ b/bootstrap.js
@@ -49,7 +49,9 @@ window.onload = () => {
   nrol.addHunk('view', 'tlview').then((vw) => {
     tlv = vw
     // manager wants view handle to render hunk DOM elements into plane ...
-    nrol.tlv = tlv 
+    // there's only one of each, so just
+    window.tlv = tlv
+    window.nrol = nrol 
   }).then(() => {
     // make ah graph,
     // outHunkIndex, outIndex, inHunkIndex, inIndex, debug
diff --git a/core/manager.js b/core/manager.js
index 404d564..80e4866 100644
--- a/core/manager.js
+++ b/core/manager.js
@@ -40,6 +40,7 @@ export default function Manager() {
   // we have hunks,
   let hunks = new Array()
   this.hunks = hunks
+  window.hunks = hunks // ohk we go global bigtime ok
 
   // we keep track of whether-or-not we have any connections ...
   this.isConnectedTo = false
@@ -267,7 +268,7 @@ export default function Manager() {
     if (hunk.dom !== null && hunk.dom !== undefined) {
       // this means that the hunk called self.document(), and has ahn hunk.dom element,
       // a div container to render into ...
-      $(this.tlv.plane).append(hunk.dom)
+      $(window.tlv.plane).append(hunk.dom)
     } // end if-have-dom
 
     // run init code (apres state setup!)
diff --git a/core/scope.js b/core/scope.js
index 7648496..d560ec8 100644
--- a/core/scope.js
+++ b/core/scope.js
@@ -16,13 +16,12 @@ import cm from '../view/contextmenu.js'
 import dt from '../view/domtools.js'
 import blocks from '../view/blocks.js'
 
+// scope is our UI tool: it draws *everything*
 export default function Scope(wrapper, tlv) {
   // toplevel scroll-around / playa
   let plane = $('<div>').addClass('plane').attr('id', 'NROLPLANE').get(0)
-  // HEADS UP: need these / somehow
-  ok: I think we start by figuring how to navigate between views / scopes / links ... 
+  plane.handle = tlv // the dom->graph handle is to the view -> plane.handle.scope = this
   tlv.plane = plane
-  plane.handle = tlv
   let cs = 1 // our current scale
   $(plane).css('background', 'url("asset/bg.png")').css('width', '100px').css('height', '100px')
   $(wrapper).append(plane)
@@ -209,67 +208,85 @@ export default function Scope(wrapper, tlv) {
   // and update those blocks only
   // wherein setting something in the view with (setUpdate) or whatever bubbles up the tree
 
-  this.check = () => {
-    // first off, if we wipe the whole thing,
-    // we don't have to handle anything else
-    if(tlv.hasCompleteRedraw){
-      console.log("SCOPE run for complete redraw")
-      console.time('redraw-complete')
-      blocks.wipeContext(tlv)
-      for(let i = 0; i < tlv.defs.length; i ++){
-        blocks.redrawDef(tlv.defs[i], plane)
-        tlv.defs[i].hasUpdate = false
+  let checkView = (view) => {
+      // first off, if we wipe the whole thing,
+      // we don't have to handle anything else
+      if(view.hasCompleteRedraw){
+        console.log("SCOPE run for complete redraw")
+        console.time('redraw-complete')
+        blocks.wipeContext(view)
+        for(let i = 0; i < view.defs.length; i ++){
+          blocks.redrawDef(view.defs[i])
+          view.defs[i].hasUpdate = false
+        }
+        blocks.redrawContexWires(view)
+        view.hasConnectivityChange = false
+        view.hasDefUpdate = false
+        view.hasCompleteRedraw = false
+        console.timeEnd('redraw-complete')
+        return
       }
-      blocks.redrawContexWires(tlv)
-      tlv.hasConnectivityChange = false
-      tlv.hasDefUpdate = false
-      tlv.hasCompleteRedraw = false
-      console.timeEnd('redraw-complete')
-      return
-    }
 
-    // otherwise, we should first handle def updates
-    // (this also counts new definitions)
-    // eventually will do / switch this per ll item
-    // defs w/ updates are for: state items, name changes,
-    // and probably connection / rewires (add / sub inputs)
-    if (tlv.hasDefUpdate) {
-      console.log('SCOPE run for hasDefUpdate')
-      console.time('redraw-defupdate')
-      for (let i = 0; i < tlv.defs.length; i++) {
-        if (tlv.defs[i].hasUpdate) {
-          // for now, we just redraw the entire definition, whenever we have updates for it
-          blocks.redrawDef(tlv.defs[i], plane)
-          // ah yeah, so we also occasionally load defs in here w/o having their link-drawing
-          // so we should just draw links from outputs as well as from inputs, then
-          // want a clean way to do that next...
-          tlv.defs[i].hasUpdate = false
+      // otherwise, we should first handle def updates
+      // (this also counts new definitions)
+      // eventually will do / switch this per ll item
+      // defs w/ updates are for: state items, name changes,
+      // and probably connection / rewires (add / sub inputs)
+      if (view.hasDefUpdate) {
+        console.log('SCOPE run for hasDefUpdate')
+        console.time('redraw-defupdate')
+        for (let i = 0; i < view.defs.length; i++) {
+          if (view.defs[i].hasUpdate) {
+            // for now, we just redraw the entire definition, whenever we have updates for it
+            blocks.redrawDef(view.defs[i])
+            // ah yeah, so we also occasionally load defs in here w/o having their link-drawing
+            // so we should just draw links from outputs as well as from inputs, then
+            // want a clean way to do that next...
+            view.defs[i].hasUpdate = false
+          }
         }
+        view.hasDefUpdate = false
+        console.timeEnd('redraw-defupdate')
       }
-      tlv.hasDefUpdate = false
-      console.timeEnd('redraw-defupdate')
-    }
 
-    // also, we do this globally. tough. scrape and move on
-    if(tlv.hasConnectivityChange){
-      console.log('SCOPE run for connectivity change')
-      console.time('redraw-connectivity')
-      blocks.redrawContexWires(tlv)
-      tlv.hasConnectivityChange = false
-      console.timeEnd('redraw-connectivity')
-    }
+      // also, we do this globally. tough. scrape and move on
+      if(view.hasConnectivityChange){
+        console.log('SCOPE run for connectivity change')
+        console.time('redraw-connectivity')
+        blocks.redrawContexWires(view)
+        view.hasConnectivityChange = false
+        console.timeEnd('redraw-connectivity')
+      }
 
-    if(tlv.hasDefPositionUpdate){
-      console.log('SCOPE run for reposition from view')
-      console.time('redraw-position')
-      for(let i = 0; i < tlv.defs.length; i ++){
-        if(tlv.defs[i].hasPositionUpdate){
-          blocks.repositionDef(tlv.defs[i])
-          tlv.defs[i].hasPositionUpdate = false
+      if(view.hasDefPositionUpdate){
+        console.log('SCOPE run for reposition from view')
+        console.time('redraw-position')
+        for(let i = 0; i < view.defs.length; i ++){
+          if(view.defs[i].hasPositionUpdate){
+            blocks.repositionDef(view.defs[i])
+            view.defs[i].hasPositionUpdate = false
+          }
+        }
+        view.hasDefPositionUpdate = false
+        console.timeEnd('redraw-position')
+      }
+  }
+
+  this.check = () => {
+    // check levels recursively,
+    checkView(tlv)
+    for(let def of tlv.defs){
+      // def.contains is a hook to the view object that operates the MVC for the context
+      // on the other side of this link ...
+      if(def.contains){
+        if(!def.contains.plane){
+          def.contains.plane = $('<div>').addClass('subplane').attr('id', `${def.name}_plane`).get(0)
+          $(plane).append(def.contains.plane)
+          // add this, as a block, to that link-def ? 
+        } else {
+          checkView(def.contains)
         }
       }
-      tlv.hasDefPositionUpdate = false
-      console.timeEnd('redraw-position')
     }
   }
 
@@ -285,499 +302,3 @@ export default function Scope(wrapper, tlv) {
   // ---------------------------------------------------------------------- END HOT NEWNESS
 
 }
-
-let oldTLV = () => {
-  // code just here for reference,
-
-  view.getCurrentBounds = () => {
-    let ct = dt.readTransform(view.plane)
-    let w = view.dom.clientWidth / ct.s
-    let h = view.dom.clientHeight / ct.s
-    let x1 = -ct.x / ct.s
-    let y1 = -ct.y / ct.s
-    let x2 = w - x1
-    let y2 = h - y1
-    // move & shimmy by
-    return {
-      x1: x1,
-      y1: y1,
-      x2: x2,
-      y2: y2,
-      w: w,
-      h: h
-    }
-  }
-
-  let zoomExtents = () => {
-    // collector
-    let psns = []
-    for (let def of view.defs) {
-      for (let fltr of def.floaters) {
-        fltr.calculateSizes()
-        psns.push({
-          x: fltr.x,
-          y: fltr.y,
-          x1: fltr.bb.x1,
-          y1: fltr.bb.y1,
-          x2: fltr.bb.x2,
-          y2: fltr.bb.y2
-        })
-      }
-    }
-    // ok then, probably bounds like
-    let minx = 0
-    let miny = 0
-    let maxx = 500
-    let maxy = 500
-    for (let ps of psns) {
-      if (ps.x + ps.x1 < minx) minx = ps.x + ps.x1
-      if (ps.x + ps.x2 > maxx) maxx = ps.x + ps.x2
-      if (ps.y + ps.y1 < miny) miny = ps.y + ps.y1
-      if (ps.y + ps.y2 > maxy) maxy = ps.y + ps.y2
-    }
-    // currently,
-    let ct = dt.readTransform(view.plane)
-    let wd = view.dom.clientWidth
-    let ht = view.dom.clientHeight
-    // so, scale is
-    let pfsx = (wd) / (maxx - minx)
-    let pfsy = (ht) / (maxy - miny)
-    let pfs = Math.min(pfsx, pfsy)
-    // and we can write
-    ct.s = pfs * 0.8 // breathing room,
-    ct.x = -minx * pfs
-    ct.y = -miny * pfs
-    // and then,
-    if (ct.s > 1) {
-      ct.s = 1
-      ct.x = -minx
-      ct.y = -miny
-    }
-    // also,
-    view.tls = ct.s
-    for (let def of view.defs) {
-      if (def.type === 'view' && def.name !== 'tlview') {
-        def.hunk.tls = ct.s
-      }
-    }
-    // contact,
-    dt.writeTransform(view.plane, ct)
-    dt.writeBackgroundTransform(view.dom, ct)
-    view.drawLinks()
-  } // end zoom extents
-
-  // trace should return, for an output, the next input.
-  // if the input is a link, it should try to traverse
-  let trace = (output, debug) => {
-    //console.log(`TRACE: tracing from ${output.name} in hunk ${output.parent.name} in view ${this.name}`)
-    // ok, traces through links / heirarchy, returning final destination
-    try {
-      if (debug) console.log(`TRACE: begin or recurse from ${output.name} in ${output.parent.name} from ${output.parent.parentView.name} of ${output.parent.parentView.interpreterName}`)
-      // of *connected* links
-      if (output.connections.length !== 1) {
-        // no connections exist, er, we can only do this for singleton lines
-        if (debug) console.log('TRACE: no connections...')
-        return false
-      }
-      let next = output.connections[0]
-      //console.log(`TRACE: NEXT:`, next)
-      if (next.parent.type === 'link') {
-        // this is the heirarchy dive
-        let thru = next.parent.reciprocalLink
-        if (thru) {
-          if (debug) console.log(`TRACE: next link`, thru)
-          // a mirror,
-          try {
-            let otp = thru.outputs[next.ind]
-            if (otp) {
-              // return / recurse
-              if (debug) console.log(`TRACE: diving -> ${otp.name}`)
-              return trace(otp, debug)
-            } else {
-              if (debug) console.log(`TRACE: terminates at link, but no reciprocal to dive`)
-              console.warn('on trace, found link, but no output on the other side')
-              return false
-            }
-          } catch (err) {
-            console.error('TRACE: err...')
-            console.error(err)
-            return false
-          }
-        } else {
-          // could try doing a globalOrganize, or refresh ... cumbersome
-          if (debug) console.log(`TRACE: terminates at link, but no reciprocal to dive`)
-          console.warn('on trace, at link boundary, find no reciprocal link')
-          return false
-        }
-      } else {
-        if (debug) console.log(`TRACE: finally returns ${next.name} in ${next.parent.name} from ${next.parent.parentView.name} of ${next.parent.parentView.interpreterName}`)
-        return next
-      }
-    } catch (err) {
-      console.error("yep")
-      console.error(err)
-    }
-  }
-
-  view.trace = trace
-
-  // notes on building a route:
-  // this is a pretty critical routine, and it's *perty neet*
-  // to make it real, needs to
-  //  - operate when possible paths (unoccupied & same-type) or partial paths already exist
-  //  - operate across multiple levels!
-  //  - in deep future: choose shortest (& least busy?) path through existing graph
-  //  - also: atm if links are not already spread (i.e. if link outputs don't match opposite inputs) ....
-  //   - then we add one side at, say, index 2, and the other at, say. index 5 ... no bueno
-
-  view.buildRoute = (output, input, debug) => {
-    return new Promise((resolve, reject) => {
-      // first, we can check
-      let pt = trace(output)
-      if (pt) {
-        resolve()
-        return
-      }
-      // ok, first off, are these things in the same view? can I find a view from an outputs?
-      let opv = output.parent.parentView
-      let ipv = input.parent.parentView
-      if (debug) console.log(`output parentview is ${opv.name} and input parent view is ${ipv.name}`)
-      if (opv === ipv) {
-        // we r on par
-        if (debug) console.log(`BR: inputs are the same to ${view.name}`)
-        opv.requestAddLink(output, input).then(() => {
-          resolve()
-        })
-      } else {
-        // ok, we have two views, and some string of links between them
-        // let's first see if we can just find the route,
-        // to find another bug (courtesy of the def-replace-polymorphism bugfarm)
-        // we should run a .go before this...
-        view.globalOrganize()
-        // now,
-        if (debug) console.log(`BR: GO completes, now build for:`)
-        if (debug) console.log(`BR: from ${output.name} in ${output.parent.name} to ${input.name} in ${input.parent.name}`)
-        let finroute = []
-        // we are the top level ... but we should hunt by link,
-        var recurse = (view, entrance, trace) => {
-          if (debug) console.log(`BR: recurse to ${view.name}`)
-          for (let df of view.defs) {
-            if (df.type === 'link' && df !== entrance) {
-              if (df.reciprocalLink) {
-                if (debug) console.log(`BR: pushes to ntrace of len ${trace.length} exit for ${df.reciprocalLink.name}`)
-                let borkit = JSON.parse(JSON.stringify(trace))
-                borkit.push({
-                  entrance: {
-                    link: df.name,
-                    view: view.name
-                  },
-                  exit: {
-                    link: df.reciprocalLink.name,
-                    view: df.reciprocalLink.parentView.name
-                  }
-                })
-                if (df.reciprocalLink.parentView === ipv) {
-                  if (debug) console.log(`BR: Makes view ${df.reciprocalLink.parentView.name} and ${ipv.name}`)
-                  finroute = JSON.parse(JSON.stringify(borkit));
-                } else {
-                  recurse(df.reciprocalLink.parentView, df.reciprocalLink, JSON.parse(JSON.stringify(borkit)))
-                }
-              } else {
-                if (debug) console.log(`BR: no reciprocal link for ${df.name} within ${view.name}`)
-              }
-            } // not a link
-          }
-        }
-        recurse(opv, null, [])
-        // ...
-        if (debug) console.log(`BR: recursion ran to completion, route is len ${finroute.length}`)
-        if (debug) console.log(`BR: the route:`, finroute)
-        if (finroute.length < 1) {
-          if (debug) console.log(`BR: no route returned...`)
-          console.error("no route to build...")
-          reject()
-        }
-        // should we resolve those objects? probably safe to assume that view names are unique,
-        // these are the kinds of code snippets that happen when jake is betwixt cpp and js
-        let resolver = (obj) => {
-          // jeez
-          let realView = view.defs.find((cand) => {
-            return cand.name === obj.view
-          })
-          let handle = view
-          if (realView.name !== "tlview") handle = realView.hunk
-          let realLink = handle.defs.find((cand) => {
-            return cand.name === obj.link
-          })
-          obj.view = handle
-          obj.link = realLink
-        }
-        for (let item of finroute) {
-          resolver(item.entrance)
-          resolver(item.exit)
-        }
-        if (debug) console.log("BR: resolved to", finroute)
-        // OK: we gotem
-        // so!
-        view.constructRoute(output, input, finroute).then(() => {
-          resolve()
-        })
-      } // end not-same-view case,
-    })
-  }
-
-  let rndByte = () => {
-    return Math.round(Math.random() * 255)
-  }
-
-  view.constructRoute = (output, input, route) => {
-    return new Promise((resolve, reject) => {
-      // entrance to 0th is from the
-      let lcounter = 0
-      let wrap = async () => {
-        // to start,
-        // do first in route's entrance ...
-        let entview = route[0].entrance.view
-        let entlink = route[0].entrance.link
-        let entiplist = entlink.states[2].value
-        entiplist += `, auto_${rndByte()}_${entlink.outputs.length} (${output.type})`
-        await entview.requestStateChange(entlink.states[2], entiplist)
-        // it's new now, recall ?
-        entlink = entview.defs[entlink.ind]
-        await entview.requestAddLink(output, entlink.inputs[entlink.inputs.length - 1])
-        // cover insides,
-        for (let rt = 0; rt < route.length - 1; rt++) {
-          let midview = route[rt].exit.view
-          if (midview !== route[rt + 1].entrance.view) throw new Error("these should bridge... ")
-          // ok,
-          let from = route[rt].exit.link
-          let to = route[rt + 1].entrance.link
-          // and so,
-          let tolist = to.states[2].value
-          tolist += `, auto_${rndByte()}_${to.outputs.length} (${output.type})`
-          console.log("FOR ST CHANGE TO", tolist)
-          await midview.requestStateChange(to.states[2], tolist)
-          to = midview.defs[to.ind]
-          // similarely,
-          let fromlist = from.states[3].value
-          fromlist += `, auto_${rndByte()}_${from.outputs.length} (${output.type})`
-          console.log("FOR ST CHANGE TO", fromlist)
-          await midview.requestStateChange(from.states[3], fromlist)
-          from = midview.defs[from.ind]
-          // goddang, so then
-          await midview.requestAddLink(from.outputs[from.outputs.length - 1], to.inputs[to.inputs.length - 1])
-        }
-        // cover outside,
-        let outview = route[route.length - 1].exit.view
-        let outlink = route[route.length - 1].exit.link
-        let exitoplist = outlink.states[3].value
-        exitoplist += `, auto_${rndByte()}_${entlink.outputs.length} (${output.type})`
-        await outview.requestStateChange(outlink.states[3], exitoplist)
-        // again, it new
-        outlink = outview.defs[outlink.ind]
-        await outview.requestAddLink(outlink.outputs[outlink.outputs.length - 1], input)
-        console.log("FIN")
-        resolve()
-      }
-      wrap()
-    })
-  }
-
-  view.globalOrganize = (debug) => {
-    if (debug) console.log("GO: KICKOFF ORGANIZING PARTY")
-    // this is a request made:
-    /*
-    (1) when any view refreshes,
-    (2) when we load a new patch
-    (3) when we load a new system
-    (4) when we build a route with .buildRoute(output, input)
-    - this doesn't change topologies, or make any requests to managers,
-    - it just organizes visually
-    */
-    // we need to recurse here,
-    let recursor = (scope, order) => {
-      if (debug) console.log(`Global Organize: recurses ${scope.name} at ${order}`)
-      // scope is a view (hunk)
-      // order is nth- level down tree, with us (toplevel) at root 0
-      if (debug) console.log(`GO: scope defs, tl defs`)
-      for (let df of scope.defs) {
-        if (df.type === 'link' && df.grouptype !== 'edgecased') {
-          // find recirprocal view relationship via trace, which returns an input, thru links,
-          // given some output
-          if (debug) console.log(`GO: trace from ${df.name} in ${scope.name}`)
-          let rvi = trace(df.outputs[1], debug)
-          if (debug) console.log(`GO: trace returns`, rvi)
-          if (rvi) {
-            // we have ah link definition, and ah view definition, connected by routing,
-            // so we are safe to do
-            let rvd = rvi.parent
-            // if the rvd is a manager, this is the bottom level -> a link thru to a manager,
-            if (rvd.type === 'manager') continue
-            // and,
-            if (debug) console.log(`GO: wrap ${df.name} around ${rvd.name}`)
-            df.wrapon(rvd)
-            rvd.unwrap()
-            // find the dataport
-            let dtprt = trace(df.outputs[0])
-            if (dtprt) {
-              dtprt.parent.unwrap()
-            }
-            // now, if we have ll data,
-            if (rvd.hunk.hasRefreshed) {
-              // find the interior link (by search for ol state)
-              let oind = df.states.find((cnd) => {
-                return cnd.name === 'otherLink'
-              }).value
-              if (!oind) throw new Error('cannot find link oind state for hookup')
-              // doth it ?
-              let internalLink = rvd.hunk.defs[oind]
-              if (internalLink) {
-                if (internalLink.type !== 'link') {
-                  console.error('link mixup alert')
-                  console.error(internalLink);
-                }
-                // hook em up
-                df.reciprocalLink = internalLink
-                internalLink.reciprocalLink = df
-                // and do,
-                internalLink.edgecase()
-                // still logging these, bc it's nice 2 kno
-                if (debug) console.log(`GO cn link ${df.name} to ${internalLink.name}`)
-                // done w/ internal, now we can
-                recursor(rvd.hunk, ++order)
-              } else {
-                console.error("organizing ... cannot find a reciprocal link")
-              }
-            }
-          }
-        }
-      }
-      // and roll zerbraHeirarchy in here also, using order ...
-    }
-    // kickoff w/
-    recursor(view, 1)
-    view.zebraHeirarchy()
-  } // end globalOrganize
-
-  view.zebraHeirarchy = (debug) => {
-    // we can go about this just by the way the visual relationship is organized,
-    let traverse = (view, lvl) => {
-      if (lvl > 6) {
-        console.warn('zebraHeirarchy traverses 6+ levels, you sure about this? exiting to avoid infinite loop')
-        return
-      }
-      lvl++
-      if (debug) console.log(`ZH traverses to ${view.name} at lvl${lvl}`)
-      for (let df of view.defs) {
-        if (df.type === 'link') {
-          if (df.floatGroupType === 'wrappedon') {
-            // this link 'contains' a view,
-            if (lvl % 2 === 0) {
-              if (debug) console.log(`ZH sets ${view.name} to f0`)
-              $(df.reciprocalView.dom).css('background-color', '#f0f0f0')
-              //$(df.deg.native).children('.view').css('background-color', '#f0f0f0')
-            } else {
-              if (debug) console.log(`ZH sets ${view.name} to e0`)
-              $(df.reciprocalView.dom).css('background-color', '#e0e0e0')
-              //$(df.deg.native).children('.view').css('background-color', '#e0e0e0')
-            }
-            traverse(df.reciprocalView, lvl)
-          }
-        }
-      }
-    }
-    traverse(view, 0)
-  }
-
-  view.expandLink = (linkDef) => {
-    return new Promise((resolve, reject) => {
-      // to avoid mayhem, do
-      linkDef.floaters[0].fix()
-      // and then,
-      view.requestAddHunk('view').then((viewDef) => {
-        // jquery moves automatically ?
-        console.log('EL: the view', viewDef.name)
-        console.log('EL: the link', linkDef.name)
-        // now we'd like to find a route from the view to the link
-        // since we're global, we could try to build the 1st link,
-        view.buildRoute(viewDef.outputs[0], linkDef.inputs[1]).then(() => {
-          console.log("EL: Build Route Down Complete")
-          return view.buildRoute(linkDef.outputs[1], viewDef.inputs[0])
-        }).then(() => {
-          console.log("EL: Build Route UP Complete")
-          view.globalOrganize()
-          resolve(viewDef)
-        }).catch((err) => {
-          console.error('EL: probable error during route construction')
-          reject(err)
-        })
-      })
-    })
-  } // end expand recipe
-
-  /* QUEEN HANDLERS */
-
-  window.onresize = () => {
-    view.onresize()
-  }
-
-  // built fast, should live with patchset
-  view.restoreEntireSystem = (name, debug) => {
-    // force it
-    debug = true
-    return new Promise((resolve, reject) => {
-      view.patchset.getSystem(name).then((sys) => {
-        if (debug) console.log('RESTORE SYSTEM: sys object', sys)
-        // startup, track views to look for
-        let recount = [];
-        // ah recursor:
-        let recursor = (scope, slice) => {
-          if (debug) console.log(`RESTORE SYSTEM: ${scope.name}`)
-          scope.patchset.mergePatch(slice, false).then(() => {
-            // done here,
-            recount.splice(recount.indexOf(scope.name), 1)
-            // check if more to do
-            for (let df of scope.defs) {
-              if (df.type === 'link') {
-                if (debug) console.log('RESTORE SYSTEM: found this link', df.name)
-                // match link / contains to ...
-                let vw = trace(df.outputs[1])
-                if (vw) {
-                  // this is a hack,
-                  // if we're going to add more shit, we should increase by at least ...
-                  if (vw.name === 'tlview') continue
-                  vw = vw.parent.hunk
-                  // if there's lower level work to do... (if this link 'contains' another patch, recursing)
-                  let nl = slice.hunks[df.ind].contains
-                  if (nl) {
-                    if (debug) console.log('RESTORE SYSTEM: would like to load', nl)
-                    recount.push(vw.name);
-                    vw.refresh().then(() => {
-                      if (debug) console.log('RESTORE SYSTEM: refreshed the context for, now recursing')
-                      recursor(vw, nl)
-                    })
-                  } else {
-                    if (debug) {
-                      console.log(`RESTORE SYSTEM: nothing contained in next link`)
-                    }
-                  }
-                } else {
-                  if (debug) console.log(`RESTORE SYSTEM: no return from trace`)
-                }
-              }
-            }
-            //console.warn("RECOUNT NOW: ", recount)
-            if (recount.length < 1) {
-              //console.warn("RESTORE COMPLETE")
-              resolve()
-            }
-          })
-        }
-        // startup,
-        recount.push(view.name)
-        recursor(view, sys)
-      })
-    })
-  }
-
-}
diff --git a/hunks/hunks.js b/hunks/hunks.js
index f08c78d..a8a6b60 100644
--- a/hunks/hunks.js
+++ b/hunks/hunks.js
@@ -66,7 +66,7 @@ function Hunkify(hunk) {
   // making ah dom element,
   hunk.document = () => {
     hunk.dom = $('<div>').addClass('hunk').get(0)
-    hunk.dom.handle = hunk
+    hunk.dom.hunk = hunk
     return hunk.dom
   }
 
diff --git a/hunks/view.js b/hunks/view.js
index 6f76cb5..50bd61a 100644
--- a/hunks/view.js
+++ b/hunks/view.js
@@ -880,7 +880,6 @@ function View() {
         patch.hunks.push(hnk)
       }
       resolve(patch)
-      reject('nah')
     })
   }
 
@@ -951,7 +950,8 @@ function View() {
       let recursor = async (n) => {
         // we want to walk the list of outputs in the patch, and reconn.
         for (let op in patch.hunks[n].outputs) {
-          if (!defs[n].outputs[op]) break
+          if (!defs[n].outputs[op]) break // if the thing-actually-loaded doesn't have an output here, pass
+          if (!patch.hunks[n].outputs[op].conn) break // during some serializations / deserializations, empty arrays are culled, so
           for (let cn of patch.hunks[n].outputs[op].conn) {
             if (debug) console.log('mergeLinkList would like to conn', n, op, 'to', cn)
             // now! we would like to see about whether / not this link already exist.
@@ -1008,13 +1008,15 @@ function View() {
   // some view that exists in the browser level
   // and return ... ?
   this.routelink = (link) => {
+    // oof async so nice
     return new Promise(async (resolve, reject) => {
       // *and* need to do some intelligent work to trace our way up to
       // the top level view, where we would be able to instate a view ...
       // *should* check if trace up exists, but basically:
       try {
-        let view = await this.requestAddHunk('view')
-        console.log('view', view)
+        let vdef = await this.requestAddHunk('view')
+        // almost definitely the easiest way to handle this is to give our local defs
+        // a .hunk, this way (1) we know they're local - the view will always be local -
         await this.requestAddLink(view.outputs[0], link.inputs[1])
         await this.requestAddLink(link.inputs[1], view.outputs[0])
         resolve(view)
diff --git a/scratch/old-defs.js b/scratch/old-defs.js
new file mode 100644
index 0000000..0f803b7
--- /dev/null
+++ b/scratch/old-defs.js
@@ -0,0 +1,734 @@
+// ---------------------------------------------------------------------- END HOT NEWNESS
+// ---------------------------------------------------------------------- END HOT NEWNESS
+// ---------------------------------------------------------------------- END HOT NEWNESS
+// ---------------------------------------------------------------------- END HOT NEWNESS
+// ---------------------------------------------------------------------- END HOT NEWNESS
+
+// new this -
+function HunkDefinition(spec, view, dt, debug) {
+  // the basics,
+  this.ind = spec.ind
+  this.name = spec.name
+  this.type = spec.type
+  this.inputs = new Array()
+  this.outputs = new Array()
+  this.states = new Array()
+  // yep,
+  this.parentView = view
+
+  // dom elements group, containing (but not limited to)
+  this.deg = {
+    core: {}
+  }
+  this.isExploded = false
+  this.floatGroupType = 'collected'
+
+  // core ...
+  this.deg.core = $('<div>').addClass('defcore').attr('id', `${this.name}_${this.ind}`).get(0)
+  let title = $(`<div>${this.name}</div>`).addClass('deftitle').addClass('header').get(0)
+  $(title).append($(`<span style="float:right">(${this.type})</span>`))
+
+  $(this.deg.core).append(title)
+  if (spec.states.length > 0) {
+    let statedefom = $('<div>').addClass('states')
+    for (let st in spec.states) {
+      let state = new StateDefinition(spec.states[st], st, this, view, debug)
+      this.states.push(state)
+      $(statedefom).append(state.de)
+    }
+    $(this.deg.core).append(statedefom)
+  }
+
+  // init our floater array, and startup with 0th entry (one floater per def == standard)
+  this.floaters = []
+  this.floaters.push(new Floater(view, 'std'))
+
+  // write inputs
+  if (spec.inputs.length > 0) {
+    // idom, odom want title bars ...
+    let idom = $('<div>').addClass('inputs')
+    $(idom).append($(`<div>inputs >></div>`).addClass('inputheader').addClass('header'))
+    for (let ip in spec.inputs) {
+      let input = new InputDefinition(spec.inputs[ip], ip, this, debug)
+      this.inputs.push(input)
+      $(idom).append(input.de)
+    }
+    this.deg.inputs = $(idom).get(0)
+    this.floaters[0].take(this.deg.inputs, this, true)
+  }
+  // write outputs,
+  if (spec.outputs.length > 0) {
+    let odom = $('<div>').addClass('outputs')
+    $(odom).append($(`<div>>> outputs</div>`).addClass('outputheader').addClass('header'))
+    for (let op in spec.outputs) {
+      let output = new OutputDefinition(spec.outputs[op], op, this, view, dt, debug)
+      this.outputs.push(output)
+      $(odom).append(output.de)
+    }
+    this.deg.outputs = $(odom).get(0)
+    this.floaters[0].take(this.deg.outputs, this, true)
+  }
+
+  // title right-click handler
+  title.oncontextmenu = (evt) => {
+    evt.preventDefault()
+    evt.stopPropagation()
+    // write menu for requesting delete and copy
+    let menu = $('<div>').addClass('contextmenu').get(0)
+    $(menu).append($('<li><i class="em em-coffin"></i> remove hunk</li>').on('click', (evt) => {
+      view.requestRemoveHunk(this.ind)
+      $(menu).remove()
+    }))
+    $(menu).append($('<li><i class="em em-abc"></i> rename hunk</li>').on('click', (evt) => {
+      $(evt.target).text('')
+      let tinput = $('<input>').attr('type', 'text').attr('size', 24).attr('value', 'new name').get(0)
+      $(evt.target).append(tinput)
+      $(tinput).focus()
+      $(tinput).select()
+      $(tinput).on('keyup', (evt) => {
+        if (evt.keyCode == 13) {
+          view.requestRenameHunk(this.ind, tinput.value).then((def) => {
+            console.log('cleared new name for', def)
+            $(menu).remove()
+          })
+        }
+      })
+    }))
+    $(menu).append($('<li><i class="em em-repeat_one"></i> copy hunk</li>').on('click', (evt) => {
+      // todo: maybe this should copy state and req it down?
+      view.requestAddHunk(this.type)
+      $(menu).remove()
+    }))
+    // place it,
+    // title.offsetWidth is 400
+    // de.style.left, de.style.top, de.clientWidth,
+    let ct = dt.readTransform(this.deg.core)
+    let mp = {
+      s: 1,
+      x: ct.x,
+      y: ct.y - 31 * 3 - 10
+    }
+    if (this.containsButtons())
+      mp.y -= 25
+    if (view.isTopLevel) {
+      // write it,
+      $(menu).append($('<li><i class="em em-arrows_counterclockwise"></i> reload from source</li>').on('click', (evt) => {
+        view.reloadHunk(this.ind, false)
+      }))
+      mp.y -= 31
+    }
+    dt.writeTransform(menu, mp)
+    $(view.plane).append(menu)
+  }
+
+  // take the core, not stalling,
+  this.floaters[0].take(this.deg.core, this, false)
+
+  /* ---------------------------    ---------------------------- */
+  /* ------------------------- PHYSICS ------------------------- */
+  /* ---------------------------    ---------------------------- */
+
+  this.highlight = () => {
+    $(this.deg.core).find('.deftitle').css('background-color', '#969696')
+    if (this.deg.inputs)
+      $(this.deg.inputs).find('.inputheader').css('background-color', 'white').css('color', 'black')
+    if (this.deg.outputs)
+      $(this.deg.outputs).find('.outputheader').css('background-color', 'white').css('color', 'black')
+    if (this.deg.native)
+      $(this.deg.native).find('.nativeheader').css('background-color', 'white').css('color', 'black')
+  }
+
+  this.unhighlight = () => {
+    $(this.deg.core).find('.deftitle').css('background-color', '#303030')
+    if (this.deg.inputs)
+      $(this.deg.inputs).find('.inputheader').css('background-color', 'red').css('color', 'white')
+    if (this.deg.outputs)
+      $(this.deg.outputs).find('.outputheader').css('background-color', 'blue').css('color', 'white')
+    if (this.deg.native)
+      $(this.deg.native).find('.nativeheader').css('background-color', 'green').css('color', 'white')
+  }
+
+  /* ---------------------------    ---------------------------- */
+  /* ------------------------- UPDATES ------------------------- */
+  /* ---------------------------    ---------------------------- */
+
+  // UPDATE Index
+  this.newInd = (ind) => {
+    this.ind = ind
+    // and those titles, and ids ...
+    $(this.de).attr('id', `${this.name}_${this.ind}`)
+    $(title).text(`${this.name}`)
+    title.append($(`<span style="float:right">(${this.type})</span>`).get(0))
+    for (let ip of this.inputs) {
+      ip.onNewParentInfo()
+    }
+    for (let op of this.outputs) {
+      op.onNewParentInfo()
+    }
+    for (let st of this.states) {
+      st.onNewParentInfo()
+    }
+  }
+
+  // UPDATE Name
+  this.updateName = (newName) => {
+    this.name = newName
+    $(this.de).attr('id', `${this.name}_${this.ind}`)
+    $(title).text(`${this.name}`)
+    title.append($(`<span style="float:right">(${this.type})</span>`).get(0))
+    for (let ip of this.inputs) {
+      ip.onNewParentInfo()
+    }
+    for (let op of this.outputs) {
+      op.onNewParentInfo()
+    }
+    for (let st of this.states) {
+      st.onNewParentInfo()
+    }
+  }
+
+  this.cleanup = () => {
+    cleanButtons()
+    cleanFloaters()
+    for (let od in this.deg) {
+      $(this.deg[od]).remove()
+    }
+  }
+
+  let cleanFloaters = () => {
+    for (let flt of this.floaters) {
+      flt.cleanup()
+    }
+    this.floaters.length = 0
+  }
+
+  this.containsButtons = () => {
+    for (let fl of this.floaters) {
+      for (let it of fl.bag) {
+        if (it.type === 'button')
+          return true
+      }
+    }
+    return false
+  }
+
+  let cleanButtons = () => {
+    // sloppy! there is probably one in one of the cores,
+    try {
+      // max 5...
+      for (let i = 0; i < 5; i++) {
+        let bindex = this.floaters[0].bag.findIndex((cnd) => {
+          return cnd.type === 'button'
+        })
+        if (bindex !== -1) {
+          // also going to get that typeset issue ...
+          // pls to god this is reworked before a bug resulting appears
+          // rm from the dom,
+          $(this.floaters[0].bag[bindex].de).remove()
+          this.floaters[0].bag.splice(bindex, 1)
+        } else {
+          break
+        }
+      }
+      // now we can
+      this.floaters[0].onChange()
+    } catch (err) {
+      console.error(`couldn't clean buttons from ${this.name}, for reasons:`, err)
+    }
+  }
+
+  /* ---------------------------    ---------------------------- */
+  /* ----------------- RM/ADD/ECT to FLOATERS ------------------ */
+  /* ---------------------------    ---------------------------- */
+
+  this.collect = () => {
+    // restore state, collect .deg under one hood (what of buttons?)
+    console.error('not yet collecting')
+  }
+
+  this.unwrap = () => {
+    // never twice
+    if (this.floatGroupType === 'unwrapped')
+      return
+    // otherwise
+    this.floatGroupType = 'unwrapped'
+    // free willy
+    // ok, can we just murder everything and start from scratch?
+    // still have those .deg elements, so ...
+    // will have to write a remove
+    //console.log('UNWRAP')
+    cleanFloaters()
+    // (unrwapped) has a core with the core, outputs, and native
+    let cflt = new Floater(view, 'unwrapped')
+    if (this.deg.outputs) {
+      cflt.take(this.deg.outputs, this, true)
+    }
+    if (this.deg.native) {
+      if (this.type === 'view' && view) {
+        //console.log('ommitting view deg from this def')
+      } else {
+        cflt.take(this.deg.native, this, true)
+      }
+    }
+    cflt.take(this.deg.core, this)
+    if (this.deg.native) {
+      if (this.type === 'view' && view) {
+        //console.log('ommitting view deg from this def')
+      } else {
+        cflt.fitNativeToFloater()
+      }
+    }
+    this.floaters.push(cflt)
+    // if there are inputs, they are separate
+    if (this.deg.inputs) {
+      let iflt = new Floater(view, 'unwrapped')
+      iflt.take(this.deg.inputs, this)
+      this.floaters.push(iflt)
+    }
+    // and kick that
+    view.floop.reset()
+  }
+
+  // for links, accept a view domain element, add to ur floater, wrap that floater
+  this.wrapon = (viewDef) => {
+    // don't do it twice
+    if (this.floatGroupType === 'wrappedon')
+      return
+    // set state
+    this.floatGroupType = 'wrappedon'
+    // errs when not a link,
+    if (this.type !== 'link')
+      throw new Error('non-links doth not wrap')
+    // first stat, we want to keep this ref,
+    this.reciprocalView = viewDef.hunk
+    // ok, and we want viewdef objects to highlight ...
+    // if we're not gathered to start, that's probably bad news
+    if (this.floaters.length > 1)
+      console.error('wyd here? many floaters during a wrap', this.floaters)
+    // get the floater's bag-item containing that view ...
+    let vflt = viewDef.floaters.find((cnd) => {
+      return cnd.typeset.includes('native')
+    })
+    if (!vflt)
+      throw new Error('could not find view floater on swap')
+    //
+    let vbagindex = vflt.bag.findIndex((cnd) => {
+      return cnd.type === 'native'
+    })
+    if (vbagindex === -1)
+      throw new Error('could not find floater native item on swap')
+    let vbagitem = vflt.bag.splice(vbagindex, 1)[0]
+    // before we do this, let's push out some extra space
+    // this *is a hack*
+    let bnds = view.getCurrentBounds()
+    view.requestResize(1800, bnds.h + 600)
+    // we need to make sure it's in the link's plane, jquery is smart about this,
+    //console.log(view.plane, vbagitem.de)
+    $(view.plane).append(vbagitem.de)
+    // the link's 1st floater,
+    let flt = this.floaters[0]
+    flt.grouptype = 'wrapped'
+    // flt.take au manuel
+    flt.bag.push(vbagitem)
+    flt.typeset.push('native')
+    vbagitem.de.onResizeCustomCallback = flt.onElementResize
+    // can just do recalc now?
+    flt.onChange()
+    // and also,
+    vflt.onChange()
+    // and *also*
+    this.removeButton('<i class="em em-squid"></i>')
+    this.addButton('<i class="em em-shell"></i>', (evt) => {
+      console.error('no collapse yet')
+    })
+  }
+
+  this.edgecase = () => {
+    // check
+    if (this.floatGroupType === 'edgecased')
+      return
+    // or set
+    this.floatGroupType = 'edgecased'
+    // also links only pls,
+    if (this.type !== 'link')
+      throw new Error('non-links doth not edge')
+    // almost forgot, we want to get rid of this button:
+    cleanButtons()
+    // similar to the unwrap spec,
+    // we're also assuming at this point that this view isn't wrapped around a view
+    cleanFloaters()
+    // now we want a left floater,
+    // free willy
+    let lflt = new Floater(view, 'edges')
+    lflt.take(this.deg.core, this, true)
+    lflt.take(this.deg.outputs, this, true)
+    lflt.makeEdges()
+    this.floaters.push(lflt)
+    // and the right,
+    let rflt = new Floater(view, 'edges')
+    rflt.take(this.deg.inputs, this, true)
+    rflt.makeEdges()
+    this.floaters.push(rflt)
+    // ok,
+    view.floop.reset()
+    // put inputs / outputs at edges of view body
+    // put core below inputs, at left
+    // make message box of the view sit low
+    // handle view resizes ?
+  }
+
+  // adden em
+  this.addButton = (text, callback) => {
+    // write a button,
+    let btn = $(`<div>${text}</div>`).addClass('defbutton').get(0)
+    $(btn).on('click', callback).on('mouseover', (evt) => {
+      document.body.style.cursor = 'pointer'
+    }).on('mouseout', (evt) => [document.body.style.cursor = 'auto'])
+    // ok ok, then ...
+    // we find the floater that contains the core,
+    let coreFloater = this.floaters.find((cnd) => {
+      return cnd.typeset.includes('core')
+    })
+    if (!coreFloater)
+      throw new Error(`couldn't find a floater for this def button`, text)
+    // attach the button element to its bag ...
+    coreFloater.take(btn, this)
+  }
+
+  this.removeButton = (text, callback) => {
+    // find the core-containing floater
+    // we find the floater that contains the core,
+    let coreFloater = this.floaters.find((cnd) => {
+      return cnd.typeset.includes('core')
+    })
+    if (!coreFloater)
+      throw new Error(`couldn't find a floater for this def button`, text)
+    let success = false
+    // au manuel splice outta the bag
+    for (let item in coreFloater.bag) {
+      let itm = coreFloater.bag[item]
+      if (itm.type === 'button') {
+        if ($(itm.de).html() === text) {
+          // splice it out,
+          coreFloater.bag.splice(item, 1)
+          $(itm.de).remove()
+          coreFloater.onChange()
+          success = true
+        }
+      }
+    }
+    if (!success)
+      console.error(`couldn't remove the button having text ${text}`)
+
+  }
+
+  // absorbing a native hunk's domain element,
+  this.takeNative = (hunk) => {
+    this.hunk = hunk
+    // wants a wrapper,
+    this.deg.native = $('<div>').addClass('nativewrap').get(0)
+    // wrapper includes this title bar,
+    $(this.deg.native).append($(`<div>${this.name}'s html element</div>`).addClass('nativeheader').addClass('header'))
+    // and the hunk's element goes in that wrapper.
+    $(this.deg.native).append(this.hunk.dom)
+    // now we can hook it 2 a floater ... this will depend on our state, which we can mod later
+    // atm, we'll put it with the core,
+    let coreFloater = this.floaters.find((cnd) => {
+      return cnd.typeset.includes('core')
+    })
+    if (!coreFloater)
+      throw new Error(`couldn't find a floater for this def native`)
+    // hook it
+    coreFloater.take(this.deg.native, this, false, this.hunk.onresize)
+    // has this handle,
+    this.hunk.requestResize = (x, y) => {
+      // set manual and call update,
+      // doesn't matter which hunk this is in...
+      // console.log(`REQRESIZE hunk ${this.name} requesting size of ${x}, ${y}`)
+      // console.log('native', this.deg.native)
+      this.deg.native.requestResize(x, y)
+      view.tick()
+    }
+    // now we should be able to,
+    this.hunk.onload()
+  }
+
+  // add special case buttons, just this so far
+  if (this.type === 'link') {
+    // todo:
+    let expander = () => {
+      this.addButton('<i class="em em-squid"></i>', (evt) => {
+        // ???
+        view.tlv.expandLink(this).then((view) => {
+          console.log("EXPANDEEED --> expandLink promise completes", view)
+        }).catch((err) => {
+          console.log("EXP catches err", err)
+        })
+      })
+    }
+    expander()
+  }
+
+  this.fixWithDataPort = () => {
+    if (this.floaters[0].isFixed) {
+      // find the data port,
+      let dp = view.tlv.trace(this.outputs[0])
+      if (dp) {
+        dp.parent.floaters[0].fixTo(this.floaters[0].fx + 500, this.floaters[0].fy - 100)
+      } else {
+        console.error("no data port from trace")
+      }
+    } else {
+      console.error("won't fix with data port: not fixed")
+    }
+  }
+
+} // end def def
+
+/* ---------------------------    ---------------------------- */
+/* ------------------------ INPUT DEF ------------------------ */
+/* ---------------------------    ---------------------------- */
+
+function InputDefinition(ipspec, ind, def, debug) {
+  // keep track of name and type,
+  this.name = ipspec.name
+  this.type = ipspec.type
+  this.parent = def
+  this.ind = parseInt(ind)
+  // a dom element
+  this.de = $(`<li>${this.name} (${this.type})</li>`).addClass('input').get(0)
+  this.de.id = `${this.parent.name}_${this.parent.ind}_input_${this.name}`
+  this.onNewParentInfo = () => {
+    this.de.id = `${this.parent.name}_${this.parent.ind}_input_${this.name}`
+  }
+  // we also keep a list,
+  this.connections = new Array()
+  this.disconnect = (output) => {
+    let index = this.connections.findIndex((cand) => {
+      return (cand.parent.ind === output.parent.ind && cand.name === output.name && cand.type === output.type)
+    })
+    if (index === -1)
+      throw new Error('during output disconnect, input cannot find output...')
+    this.connections.splice(index, 1)
+  }
+  this.disconnectAll = () => {
+    for (let op of this.connections) {
+      op.disconnect(this)
+    }
+    this.connections.length = 0
+  }
+  // to get this object via the dom, circular... apparently that is fine ?
+  this.de.hookup = this
+}
+
+/* ---------------------------    ---------------------------- */
+/* ----------------------- OUTPUT DEF ------------------------ */
+/* ---------------------------    ---------------------------- */
+
+function OutputDefinition(opspec, ind, def, view, dt, debug) {
+  // keep track of name and type,
+  this.parent = def
+  this.name = opspec.name
+  this.type = opspec.type
+  this.ind = parseInt(ind)
+  // a dom element
+  this.de = $(`<li>(${this.type}) ${this.name}</li>`).addClass('output').get(0)
+  this.de.id = `${this.parent.name}_${this.parent.ind}_output_${this.name}`
+  this.onNewParentInfo = () => {
+    this.de.id = `${this.parent.name}_${this.parent.ind}_output_${this.name}`
+  }
+  // outputs handle all of the dragging-etc
+  if (opspec.connections !== undefined) {
+    this.specConnections = opspec.connections
+  }
+  this.connections = new Array() // of inputdefs, !
+  this.connect = (inputdef) => {
+    inputdef.connections.push(this)
+    this.connections.push(inputdef)
+  }
+  this.disconnect = (inputdef) => {
+    inputdef.disconnect(this)
+    let iof = this.connections.findIndex((cand) => {
+      return (cand.name === inputdef.name && cand.parent.ind === inputdef.parent.ind)
+    })
+    if (iof === -1)
+      throw new Error('could not find input to disconnect')
+    this.connections.splice(iof, 1)
+    return true
+  }
+  this.disconnectAll = () => {
+    for (let ip of this.connections) {
+      ip.disconnect(this)
+    }
+    this.connections.length = 0
+  }
+  // the dragging
+  this.floater = {}
+  this.hasFloater = false
+  // ondrag, attached later
+  let evtDrag = (evt) => {
+    evt.preventDefault()
+    evt.stopPropagation()
+    let pt = dt.readTransform(view.tlv.plane)
+    let thet = dt.readTransform(this.floater)
+    // ... set delta
+    thet.x += evt.movementX / pt.s
+    thet.y += evt.movementY / pt.s
+    dt.writeTransform(this.floater, thet)
+    view.drawLinks()
+  }
+  // to remove the below
+  let dragMouseUp = (evt) => {
+    if (debug)
+      console.log('MOUSEUP ON', evt.target.id)
+    // 1st, make sure it's an input
+    if ($(evt.target).is('.input')) {
+      // HERE: searcheth by input id text? or
+      let hk = evt.target.hookup
+      // hookups are hooks to the input's def-object
+      // console.log('ah hookup looks like:', hk)
+      if (!hk)
+        throw new Error('missing some data at this input...')
+      // use a dom data flag, to find that input and output id?
+      // are we in the same context?
+      if (hk.parent.parentView === this.parent.parentView) {
+        view.requestAddLink(this, hk)
+      } else {
+        console.warn("UI Route Builder Begins...")
+        this.parent.parentView.tlv.buildRoute(this, hk).then(() => {
+          console.warn("UI Route Builder Resolves !")
+        })
+      }
+      // do things to conn, then
+    }
+    // cleanup
+    document.removeEventListener('mouseup', dragMouseUp)
+    document.removeEventListener('mousemove', evtDrag)
+    // remove the floater flag
+    this.hasFloater = false
+    // remove the floater itself
+    $(view.plane).find('#floater').remove()
+    view.drawLinks()
+  }
+  // eeeeehntr for link-hookup-dragging
+  this.de.onmousedown = (evt) => {
+    evt.stopPropagation()
+    evt.preventDefault()
+    if (debug)
+      console.log('mousedown for', this)
+    // this and that flag will be read-in on drawlinks, to draw that link
+    this.floater = $('<div>').attr('id', 'floater').append(this.type).get(0)
+    this.hasFloater = true
+    this.floater.style.zIndex = '1'
+    // set initial position by the outputs' position,
+    let dparent = $(this.de).parent().get(0)
+    let opp = dt.readTransform(dparent)
+    // top-level plane ...
+    let pt = dt.readTransform(view.tlv.plane)
+    // plonk: have to do this now or else clientHeight / width are 0
+    view.plane.appendChild(this.floater)
+    // init out floater position, and put it in the dom
+    dt.writeTransform(this.floater, {
+      s: 1,
+      x: opp.x - ((this.floater.clientWidth + 5)),
+      y: opp.y + this.floater.clientHeight * (this.ind + 0.5) // - ((fltheight * pt.s) / 2) / pt.s
+    })
+    // handlers to drag, and remove
+    document.addEventListener('mousemove', evtDrag)
+    // and delete / act when mouse comes up
+    document.addEventListener('mouseup', dragMouseUp)
+  }
+}
+
+/* ---------------------------    ---------------------------- */
+/* ------------------------ STATE DEF ------------------------ */
+/* ---------------------------    ---------------------------- */
+
+function StateDefinition(stspec, ind, def, view, debug) {
+  this.parent = def
+  this.name = stspec.name
+  this.type = stspec.type
+  this.ind = parseInt(ind)
+  // business,
+  this.value = stspec.value
+  // ok,
+  this.de = $('<div>' + this.name + " (" + this.type + ")" + '</div>').addClass('stateItem').get(0)
+  this.de.id = `${this.parent.name}_${this.parent.ind}_state_${this.name}`
+  this.onNewParentInfo = () => {
+    this.de.id = `${this.parent.name}_${this.parent.ind}_state_${this.name}`
+  }
+  // ui for these ... we can just cover the basics of js types because yonder serializations
+  // etc will throw errors for other types. of course, this could help more, but we're in a rush
+  switch (typeof this.value) {
+    case 'string':
+      //dom.append($('<br>').get(0))
+      let strinput = $('<input>').attr('type', 'text').attr('size', 32).attr('value', this.value).css('width', '240px').get(0)
+      strinput.addEventListener('change', (evt) => {
+        // ask for a change,
+        // TODO HERE NOW: this is the state change request you want to write
+        // do it like writeMessage() instead
+        // requestStateChange(def.id, state, strinput.value)
+        // but assert that we don't change the definition unless
+        view.requestStateChange(this, strinput.value)
+        strinput.value = this.value
+      })
+      this.de.append(strinput)
+      this.set = (value) => {
+        if (typeof value === 'string') {
+          strinput.value = value
+          this.value = value
+        } else {
+          throw new Error('bad type put into state dom')
+        }
+      }
+      break // end string types
+    case 'number':
+      let ninput = $('<input>').addClass('stateNumInput').attr('type', 'text').attr('size', 24).attr('value', this.value.toString()).css('width', '100px').get(0)
+      ninput.addEventListener('change', (evt) => {
+        // ask for a change, watch for float or for int ...
+        if (isIntType(this.type)) {
+          view.requestStateChange(this, parseInt(ninput.value))
+        } else {
+          view.requestStateChange(this, parseFloat(ninput.value))
+        }
+        // but assert that we don't change the definition unless
+        ninput.value = this.value
+      })
+      this.de.append(ninput)
+      this.set = (value) => {
+        if (typeof value === 'number') {
+          // quite sure js does this conversion no problem
+          ninput.value = value
+          this.value = value
+        } else {
+          throw new Error('bad type put into state dom')
+        }
+      }
+      break // end numnber type
+    case 'boolean':
+      let span = $('<span style="float:right;">' + this.value.toString() + '</span>').get(0)
+      $(this.de).addClass('stateBooleanItem')
+      this.de.append(span)
+      this.de.addEventListener('click', (evt) => {
+        // read the current 'state' (as written) and send the opposite
+        let txt = $(span).text()
+        if (txt === 'true') {
+          view.requestStateChange(this, false)
+        } else {
+          view.requestStateChange(this, true)
+        }
+      })
+      this.set = (value) => {
+        if (typeof value === 'boolean') {
+          $(span).text(value.toString())
+          this.value = value
+        } else {
+          throw new Error('bad type put into state dom')
+        }
+      }
+      break // end boolean type
+    default:
+      console.error(`unaccounted for type at input pull for state change, ${typeof state.value}`)
+      break
+  }
+}
diff --git a/scratch/old-view.js b/scratch/old-view.js
new file mode 100644
index 0000000..8891d14
--- /dev/null
+++ b/scratch/old-view.js
@@ -0,0 +1,495 @@
+let oldTLV = () => {
+  // code just here for reference,
+
+  view.getCurrentBounds = () => {
+    let ct = dt.readTransform(view.plane)
+    let w = view.dom.clientWidth / ct.s
+    let h = view.dom.clientHeight / ct.s
+    let x1 = -ct.x / ct.s
+    let y1 = -ct.y / ct.s
+    let x2 = w - x1
+    let y2 = h - y1
+    // move & shimmy by
+    return {
+      x1: x1,
+      y1: y1,
+      x2: x2,
+      y2: y2,
+      w: w,
+      h: h
+    }
+  }
+
+  let zoomExtents = () => {
+    // collector
+    let psns = []
+    for (let def of view.defs) {
+      for (let fltr of def.floaters) {
+        fltr.calculateSizes()
+        psns.push({
+          x: fltr.x,
+          y: fltr.y,
+          x1: fltr.bb.x1,
+          y1: fltr.bb.y1,
+          x2: fltr.bb.x2,
+          y2: fltr.bb.y2
+        })
+      }
+    }
+    // ok then, probably bounds like
+    let minx = 0
+    let miny = 0
+    let maxx = 500
+    let maxy = 500
+    for (let ps of psns) {
+      if (ps.x + ps.x1 < minx) minx = ps.x + ps.x1
+      if (ps.x + ps.x2 > maxx) maxx = ps.x + ps.x2
+      if (ps.y + ps.y1 < miny) miny = ps.y + ps.y1
+      if (ps.y + ps.y2 > maxy) maxy = ps.y + ps.y2
+    }
+    // currently,
+    let ct = dt.readTransform(view.plane)
+    let wd = view.dom.clientWidth
+    let ht = view.dom.clientHeight
+    // so, scale is
+    let pfsx = (wd) / (maxx - minx)
+    let pfsy = (ht) / (maxy - miny)
+    let pfs = Math.min(pfsx, pfsy)
+    // and we can write
+    ct.s = pfs * 0.8 // breathing room,
+    ct.x = -minx * pfs
+    ct.y = -miny * pfs
+    // and then,
+    if (ct.s > 1) {
+      ct.s = 1
+      ct.x = -minx
+      ct.y = -miny
+    }
+    // also,
+    view.tls = ct.s
+    for (let def of view.defs) {
+      if (def.type === 'view' && def.name !== 'tlview') {
+        def.hunk.tls = ct.s
+      }
+    }
+    // contact,
+    dt.writeTransform(view.plane, ct)
+    dt.writeBackgroundTransform(view.dom, ct)
+    view.drawLinks()
+  } // end zoom extents
+
+  // trace should return, for an output, the next input.
+  // if the input is a link, it should try to traverse
+  let trace = (output, debug) => {
+    //console.log(`TRACE: tracing from ${output.name} in hunk ${output.parent.name} in view ${this.name}`)
+    // ok, traces through links / heirarchy, returning final destination
+    try {
+      if (debug) console.log(`TRACE: begin or recurse from ${output.name} in ${output.parent.name} from ${output.parent.parentView.name} of ${output.parent.parentView.interpreterName}`)
+      // of *connected* links
+      if (output.connections.length !== 1) {
+        // no connections exist, er, we can only do this for singleton lines
+        if (debug) console.log('TRACE: no connections...')
+        return false
+      }
+      let next = output.connections[0]
+      //console.log(`TRACE: NEXT:`, next)
+      if (next.parent.type === 'link') {
+        // this is the heirarchy dive
+        let thru = next.parent.reciprocalLink
+        if (thru) {
+          if (debug) console.log(`TRACE: next link`, thru)
+          // a mirror,
+          try {
+            let otp = thru.outputs[next.ind]
+            if (otp) {
+              // return / recurse
+              if (debug) console.log(`TRACE: diving -> ${otp.name}`)
+              return trace(otp, debug)
+            } else {
+              if (debug) console.log(`TRACE: terminates at link, but no reciprocal to dive`)
+              console.warn('on trace, found link, but no output on the other side')
+              return false
+            }
+          } catch (err) {
+            console.error('TRACE: err...')
+            console.error(err)
+            return false
+          }
+        } else {
+          // could try doing a globalOrganize, or refresh ... cumbersome
+          if (debug) console.log(`TRACE: terminates at link, but no reciprocal to dive`)
+          console.warn('on trace, at link boundary, find no reciprocal link')
+          return false
+        }
+      } else {
+        if (debug) console.log(`TRACE: finally returns ${next.name} in ${next.parent.name} from ${next.parent.parentView.name} of ${next.parent.parentView.interpreterName}`)
+        return next
+      }
+    } catch (err) {
+      console.error("yep")
+      console.error(err)
+    }
+  }
+
+  view.trace = trace
+
+  // notes on building a route:
+  // this is a pretty critical routine, and it's *perty neet*
+  // to make it real, needs to
+  //  - operate when possible paths (unoccupied & same-type) or partial paths already exist
+  //  - operate across multiple levels!
+  //  - in deep future: choose shortest (& least busy?) path through existing graph
+  //  - also: atm if links are not already spread (i.e. if link outputs don't match opposite inputs) ....
+  //   - then we add one side at, say, index 2, and the other at, say. index 5 ... no bueno
+
+  view.buildRoute = (output, input, debug) => {
+    return new Promise((resolve, reject) => {
+      // first, we can check
+      let pt = trace(output)
+      if (pt) {
+        resolve()
+        return
+      }
+      // ok, first off, are these things in the same view? can I find a view from an outputs?
+      let opv = output.parent.parentView
+      let ipv = input.parent.parentView
+      if (debug) console.log(`output parentview is ${opv.name} and input parent view is ${ipv.name}`)
+      if (opv === ipv) {
+        // we r on par
+        if (debug) console.log(`BR: inputs are the same to ${view.name}`)
+        opv.requestAddLink(output, input).then(() => {
+          resolve()
+        })
+      } else {
+        // ok, we have two views, and some string of links between them
+        // let's first see if we can just find the route,
+        // to find another bug (courtesy of the def-replace-polymorphism bugfarm)
+        // we should run a .go before this...
+        view.globalOrganize()
+        // now,
+        if (debug) console.log(`BR: GO completes, now build for:`)
+        if (debug) console.log(`BR: from ${output.name} in ${output.parent.name} to ${input.name} in ${input.parent.name}`)
+        let finroute = []
+        // we are the top level ... but we should hunt by link,
+        var recurse = (view, entrance, trace) => {
+          if (debug) console.log(`BR: recurse to ${view.name}`)
+          for (let df of view.defs) {
+            if (df.type === 'link' && df !== entrance) {
+              if (df.reciprocalLink) {
+                if (debug) console.log(`BR: pushes to ntrace of len ${trace.length} exit for ${df.reciprocalLink.name}`)
+                let borkit = JSON.parse(JSON.stringify(trace))
+                borkit.push({
+                  entrance: {
+                    link: df.name,
+                    view: view.name
+                  },
+                  exit: {
+                    link: df.reciprocalLink.name,
+                    view: df.reciprocalLink.parentView.name
+                  }
+                })
+                if (df.reciprocalLink.parentView === ipv) {
+                  if (debug) console.log(`BR: Makes view ${df.reciprocalLink.parentView.name} and ${ipv.name}`)
+                  finroute = JSON.parse(JSON.stringify(borkit));
+                } else {
+                  recurse(df.reciprocalLink.parentView, df.reciprocalLink, JSON.parse(JSON.stringify(borkit)))
+                }
+              } else {
+                if (debug) console.log(`BR: no reciprocal link for ${df.name} within ${view.name}`)
+              }
+            } // not a link
+          }
+        }
+        recurse(opv, null, [])
+        // ...
+        if (debug) console.log(`BR: recursion ran to completion, route is len ${finroute.length}`)
+        if (debug) console.log(`BR: the route:`, finroute)
+        if (finroute.length < 1) {
+          if (debug) console.log(`BR: no route returned...`)
+          console.error("no route to build...")
+          reject()
+        }
+        // should we resolve those objects? probably safe to assume that view names are unique,
+        // these are the kinds of code snippets that happen when jake is betwixt cpp and js
+        let resolver = (obj) => {
+          // jeez
+          let realView = view.defs.find((cand) => {
+            return cand.name === obj.view
+          })
+          let handle = view
+          if (realView.name !== "tlview") handle = realView.hunk
+          let realLink = handle.defs.find((cand) => {
+            return cand.name === obj.link
+          })
+          obj.view = handle
+          obj.link = realLink
+        }
+        for (let item of finroute) {
+          resolver(item.entrance)
+          resolver(item.exit)
+        }
+        if (debug) console.log("BR: resolved to", finroute)
+        // OK: we gotem
+        // so!
+        view.constructRoute(output, input, finroute).then(() => {
+          resolve()
+        })
+      } // end not-same-view case,
+    })
+  }
+
+  let rndByte = () => {
+    return Math.round(Math.random() * 255)
+  }
+
+  view.constructRoute = (output, input, route) => {
+    return new Promise((resolve, reject) => {
+      // entrance to 0th is from the
+      let lcounter = 0
+      let wrap = async () => {
+        // to start,
+        // do first in route's entrance ...
+        let entview = route[0].entrance.view
+        let entlink = route[0].entrance.link
+        let entiplist = entlink.states[2].value
+        entiplist += `, auto_${rndByte()}_${entlink.outputs.length} (${output.type})`
+        await entview.requestStateChange(entlink.states[2], entiplist)
+        // it's new now, recall ?
+        entlink = entview.defs[entlink.ind]
+        await entview.requestAddLink(output, entlink.inputs[entlink.inputs.length - 1])
+        // cover insides,
+        for (let rt = 0; rt < route.length - 1; rt++) {
+          let midview = route[rt].exit.view
+          if (midview !== route[rt + 1].entrance.view) throw new Error("these should bridge... ")
+          // ok,
+          let from = route[rt].exit.link
+          let to = route[rt + 1].entrance.link
+          // and so,
+          let tolist = to.states[2].value
+          tolist += `, auto_${rndByte()}_${to.outputs.length} (${output.type})`
+          console.log("FOR ST CHANGE TO", tolist)
+          await midview.requestStateChange(to.states[2], tolist)
+          to = midview.defs[to.ind]
+          // similarely,
+          let fromlist = from.states[3].value
+          fromlist += `, auto_${rndByte()}_${from.outputs.length} (${output.type})`
+          console.log("FOR ST CHANGE TO", fromlist)
+          await midview.requestStateChange(from.states[3], fromlist)
+          from = midview.defs[from.ind]
+          // goddang, so then
+          await midview.requestAddLink(from.outputs[from.outputs.length - 1], to.inputs[to.inputs.length - 1])
+        }
+        // cover outside,
+        let outview = route[route.length - 1].exit.view
+        let outlink = route[route.length - 1].exit.link
+        let exitoplist = outlink.states[3].value
+        exitoplist += `, auto_${rndByte()}_${entlink.outputs.length} (${output.type})`
+        await outview.requestStateChange(outlink.states[3], exitoplist)
+        // again, it new
+        outlink = outview.defs[outlink.ind]
+        await outview.requestAddLink(outlink.outputs[outlink.outputs.length - 1], input)
+        console.log("FIN")
+        resolve()
+      }
+      wrap()
+    })
+  }
+
+  view.globalOrganize = (debug) => {
+    if (debug) console.log("GO: KICKOFF ORGANIZING PARTY")
+    // this is a request made:
+    /*
+    (1) when any view refreshes,
+    (2) when we load a new patch
+    (3) when we load a new system
+    (4) when we build a route with .buildRoute(output, input)
+    - this doesn't change topologies, or make any requests to managers,
+    - it just organizes visually
+    */
+    // we need to recurse here,
+    let recursor = (scope, order) => {
+      if (debug) console.log(`Global Organize: recurses ${scope.name} at ${order}`)
+      // scope is a view (hunk)
+      // order is nth- level down tree, with us (toplevel) at root 0
+      if (debug) console.log(`GO: scope defs, tl defs`)
+      for (let df of scope.defs) {
+        if (df.type === 'link' && df.grouptype !== 'edgecased') {
+          // find recirprocal view relationship via trace, which returns an input, thru links,
+          // given some output
+          if (debug) console.log(`GO: trace from ${df.name} in ${scope.name}`)
+          let rvi = trace(df.outputs[1], debug)
+          if (debug) console.log(`GO: trace returns`, rvi)
+          if (rvi) {
+            // we have ah link definition, and ah view definition, connected by routing,
+            // so we are safe to do
+            let rvd = rvi.parent
+            // if the rvd is a manager, this is the bottom level -> a link thru to a manager,
+            if (rvd.type === 'manager') continue
+            // and,
+            if (debug) console.log(`GO: wrap ${df.name} around ${rvd.name}`)
+            df.wrapon(rvd)
+            rvd.unwrap()
+            // find the dataport
+            let dtprt = trace(df.outputs[0])
+            if (dtprt) {
+              dtprt.parent.unwrap()
+            }
+            // now, if we have ll data,
+            if (rvd.hunk.hasRefreshed) {
+              // find the interior link (by search for ol state)
+              let oind = df.states.find((cnd) => {
+                return cnd.name === 'otherLink'
+              }).value
+              if (!oind) throw new Error('cannot find link oind state for hookup')
+              // doth it ?
+              let internalLink = rvd.hunk.defs[oind]
+              if (internalLink) {
+                if (internalLink.type !== 'link') {
+                  console.error('link mixup alert')
+                  console.error(internalLink);
+                }
+                // hook em up
+                df.reciprocalLink = internalLink
+                internalLink.reciprocalLink = df
+                // and do,
+                internalLink.edgecase()
+                // still logging these, bc it's nice 2 kno
+                if (debug) console.log(`GO cn link ${df.name} to ${internalLink.name}`)
+                // done w/ internal, now we can
+                recursor(rvd.hunk, ++order)
+              } else {
+                console.error("organizing ... cannot find a reciprocal link")
+              }
+            }
+          }
+        }
+      }
+      // and roll zerbraHeirarchy in here also, using order ...
+    }
+    // kickoff w/
+    recursor(view, 1)
+    view.zebraHeirarchy()
+  } // end globalOrganize
+
+  view.zebraHeirarchy = (debug) => {
+    // we can go about this just by the way the visual relationship is organized,
+    let traverse = (view, lvl) => {
+      if (lvl > 6) {
+        console.warn('zebraHeirarchy traverses 6+ levels, you sure about this? exiting to avoid infinite loop')
+        return
+      }
+      lvl++
+      if (debug) console.log(`ZH traverses to ${view.name} at lvl${lvl}`)
+      for (let df of view.defs) {
+        if (df.type === 'link') {
+          if (df.floatGroupType === 'wrappedon') {
+            // this link 'contains' a view,
+            if (lvl % 2 === 0) {
+              if (debug) console.log(`ZH sets ${view.name} to f0`)
+              $(df.reciprocalView.dom).css('background-color', '#f0f0f0')
+              //$(df.deg.native).children('.view').css('background-color', '#f0f0f0')
+            } else {
+              if (debug) console.log(`ZH sets ${view.name} to e0`)
+              $(df.reciprocalView.dom).css('background-color', '#e0e0e0')
+              //$(df.deg.native).children('.view').css('background-color', '#e0e0e0')
+            }
+            traverse(df.reciprocalView, lvl)
+          }
+        }
+      }
+    }
+    traverse(view, 0)
+  }
+
+  view.expandLink = (linkDef) => {
+    return new Promise((resolve, reject) => {
+      // to avoid mayhem, do
+      linkDef.floaters[0].fix()
+      // and then,
+      view.requestAddHunk('view').then((viewDef) => {
+        // jquery moves automatically ?
+        console.log('EL: the view', viewDef.name)
+        console.log('EL: the link', linkDef.name)
+        // now we'd like to find a route from the view to the link
+        // since we're global, we could try to build the 1st link,
+        view.buildRoute(viewDef.outputs[0], linkDef.inputs[1]).then(() => {
+          console.log("EL: Build Route Down Complete")
+          return view.buildRoute(linkDef.outputs[1], viewDef.inputs[0])
+        }).then(() => {
+          console.log("EL: Build Route UP Complete")
+          view.globalOrganize()
+          resolve(viewDef)
+        }).catch((err) => {
+          console.error('EL: probable error during route construction')
+          reject(err)
+        })
+      })
+    })
+  } // end expand recipe
+
+  /* QUEEN HANDLERS */
+
+  window.onresize = () => {
+    view.onresize()
+  }
+
+  // built fast, should live with patchset
+  view.restoreEntireSystem = (name, debug) => {
+    // force it
+    debug = true
+    return new Promise((resolve, reject) => {
+      view.patchset.getSystem(name).then((sys) => {
+        if (debug) console.log('RESTORE SYSTEM: sys object', sys)
+        // startup, track views to look for
+        let recount = [];
+        // ah recursor:
+        let recursor = (scope, slice) => {
+          if (debug) console.log(`RESTORE SYSTEM: ${scope.name}`)
+          scope.patchset.mergePatch(slice, false).then(() => {
+            // done here,
+            recount.splice(recount.indexOf(scope.name), 1)
+            // check if more to do
+            for (let df of scope.defs) {
+              if (df.type === 'link') {
+                if (debug) console.log('RESTORE SYSTEM: found this link', df.name)
+                // match link / contains to ...
+                let vw = trace(df.outputs[1])
+                if (vw) {
+                  // this is a hack,
+                  // if we're going to add more shit, we should increase by at least ...
+                  if (vw.name === 'tlview') continue
+                  vw = vw.parent.hunk
+                  // if there's lower level work to do... (if this link 'contains' another patch, recursing)
+                  let nl = slice.hunks[df.ind].contains
+                  if (nl) {
+                    if (debug) console.log('RESTORE SYSTEM: would like to load', nl)
+                    recount.push(vw.name);
+                    vw.refresh().then(() => {
+                      if (debug) console.log('RESTORE SYSTEM: refreshed the context for, now recursing')
+                      recursor(vw, nl)
+                    })
+                  } else {
+                    if (debug) {
+                      console.log(`RESTORE SYSTEM: nothing contained in next link`)
+                    }
+                  }
+                } else {
+                  if (debug) console.log(`RESTORE SYSTEM: no return from trace`)
+                }
+              }
+            }
+            //console.warn("RECOUNT NOW: ", recount)
+            if (recount.length < 1) {
+              //console.warn("RESTORE COMPLETE")
+              resolve()
+            }
+          })
+        }
+        // startup,
+        recount.push(view.name)
+        recursor(view, sys)
+      })
+    })
+  }
+
+}
diff --git a/style.css b/style.css
index 8c0ea3a..70fef02 100644
--- a/style.css
+++ b/style.css
@@ -70,6 +70,13 @@ body {
 	height: 10px;
 }
 
+.subplane{
+	position: absolute;
+	background-color: #c1c1c1;;
+	width: 800px;
+	height: 800px;
+}
+
 #programMenu {
 	position: absolute;
 	width: 245px;
diff --git a/view/blocks.js b/view/blocks.js
index c99f83e..da3537c 100644
--- a/view/blocks.js
+++ b/view/blocks.js
@@ -258,31 +258,40 @@ let rebuildDef = (def, position) => {
     def.blocks.push(stateblock)
   }
 
-  // claim dom elements, global search
-  let native = $(def.context.plane).find('.hunk').toArray().find((cand) => {
-    return cand.handle.ind === def.ind
-  })
-  if (native) {
-    // issa block,
-    $(native).addClass('block')
-    // ok, I think I want to position this above everything else,
-    native.position = () => {
-      // this is more difficult, as we are looking @ the other blocks,
-      let y = 0
-      for (let bl of def.blocks) {
-        if ($(bl).is('.input') || $(bl).is('.output') || $(bl).is('.hunk')){
-          continue
-        } else {
-          y += bl.clientHeight + 5
+  // find yourself in t h e g l o b a l d o m a i n
+  if(def.context === window.tlv){
+    let hunk = window.hunks[def.ind]
+    if(!((hunk.name === def.name) && (hunk.type === def.type))) throw new Error('this should never be the case')
+    def.hunk = hunk
+    // additionally,
+    // claim dom elements, global search
+    let native = $(def.context.plane).find('.hunk').toArray().find((cand) => {
+      return cand.hunk.ind === def.ind
+    })
+    if (native) {
+      // issa block,
+      $(native).addClass('block')
+      native.handle = def
+      // ok, I think I want to position this above everything else,
+      native.position = () => {
+        // this is more difficult, as we are looking @ the other blocks,
+        let y = 0
+        for (let bl of def.blocks) {
+          if ($(bl).is('.input') || $(bl).is('.output') || $(bl).is('.hunk')){
+            continue
+          } else {
+            y += bl.clientHeight + 5
+          }
         }
+        return { x: 0, y: y }
       }
-      return { x: 0, y: y }
+      // attach to title,
+      titleblock.take(native)
+      def.blocks.push(native)
     }
-    // attach to title,
-    titleblock.take(native)
-    def.blocks.push(native)
   }
 
+
   // now the hairier work,
   if(def.type == 'link'){
     let squid = $('<div>').addClass('loosebutton').addClass('block').get(0)
@@ -294,13 +303,19 @@ let rebuildDef = (def, position) => {
     def.blocks.push(squid)
     let open = (evt) =>{
       // returns the view that connects to this link,
-      def.context.routelink(def).then((view) => {
+      def.context.routelink(def).then((vdef) => {
         console.log('route ok')
-        // we *do* want to walk these, so,
-        def.contains = view 
+        // we have vdev.tlv, so, the definition has a handle to the
+        // top level view, why?
+        // we *do* want to walk these, so we want a handle to
+        // the view element - not just its def ...
+        def.contains = vdef.hunk
+        console.log('"view"', view)
         // toggle button state,
         $(squid).html('<i class="em em-shell"></i> collapse link')
         $(squid).one('click', close)
+        // nooow...
+        //view.refresh()
       }).catch((err) => {
         console.error(err)
       })
@@ -371,13 +386,13 @@ let repositionDef = (def) => {
 // use block.wires ... if exists,
 // but there is an order issue: we need to see about inputs also, update on both ends
 
-let redrawDef = (def, plane) => {
+let redrawDef = (def) => {
   console.log('redraw for def', def.name)
   // this wipes and redraws,
   rebuildDef(def)
   // place them all in the context,
   for (let bl of def.blocks) {
-    $(plane).append(bl)
+    $(def.context.plane).append(bl)
   }
   // arrange (should draw links as well)
   repositionDef(def)
@@ -402,738 +417,3 @@ export default {
   redrawContexWires, // when context link topology changes
   wipeContext // to shutdown / cleanup
 }
-
-// ---------------------------------------------------------------------- END HOT NEWNESS
-// ---------------------------------------------------------------------- END HOT NEWNESS
-// ---------------------------------------------------------------------- END HOT NEWNESS
-// ---------------------------------------------------------------------- END HOT NEWNESS
-// ---------------------------------------------------------------------- END HOT NEWNESS
-
-// new this -
-function HunkDefinition(spec, view, dt, debug) {
-  // the basics,
-  this.ind = spec.ind
-  this.name = spec.name
-  this.type = spec.type
-  this.inputs = new Array()
-  this.outputs = new Array()
-  this.states = new Array()
-  // yep,
-  this.parentView = view
-
-  // dom elements group, containing (but not limited to)
-  this.deg = {
-    core: {}
-  }
-  this.isExploded = false
-  this.floatGroupType = 'collected'
-
-  // core ...
-  this.deg.core = $('<div>').addClass('defcore').attr('id', `${this.name}_${this.ind}`).get(0)
-  let title = $(`<div>${this.name}</div>`).addClass('deftitle').addClass('header').get(0)
-  $(title).append($(`<span style="float:right">(${this.type})</span>`))
-
-  $(this.deg.core).append(title)
-  if (spec.states.length > 0) {
-    let statedefom = $('<div>').addClass('states')
-    for (let st in spec.states) {
-      let state = new StateDefinition(spec.states[st], st, this, view, debug)
-      this.states.push(state)
-      $(statedefom).append(state.de)
-    }
-    $(this.deg.core).append(statedefom)
-  }
-
-  // init our floater array, and startup with 0th entry (one floater per def == standard)
-  this.floaters = []
-  this.floaters.push(new Floater(view, 'std'))
-
-  // write inputs
-  if (spec.inputs.length > 0) {
-    // idom, odom want title bars ...
-    let idom = $('<div>').addClass('inputs')
-    $(idom).append($(`<div>inputs >></div>`).addClass('inputheader').addClass('header'))
-    for (let ip in spec.inputs) {
-      let input = new InputDefinition(spec.inputs[ip], ip, this, debug)
-      this.inputs.push(input)
-      $(idom).append(input.de)
-    }
-    this.deg.inputs = $(idom).get(0)
-    this.floaters[0].take(this.deg.inputs, this, true)
-  }
-  // write outputs,
-  if (spec.outputs.length > 0) {
-    let odom = $('<div>').addClass('outputs')
-    $(odom).append($(`<div>>> outputs</div>`).addClass('outputheader').addClass('header'))
-    for (let op in spec.outputs) {
-      let output = new OutputDefinition(spec.outputs[op], op, this, view, dt, debug)
-      this.outputs.push(output)
-      $(odom).append(output.de)
-    }
-    this.deg.outputs = $(odom).get(0)
-    this.floaters[0].take(this.deg.outputs, this, true)
-  }
-
-  // title right-click handler
-  title.oncontextmenu = (evt) => {
-    evt.preventDefault()
-    evt.stopPropagation()
-    // write menu for requesting delete and copy
-    let menu = $('<div>').addClass('contextmenu').get(0)
-    $(menu).append($('<li><i class="em em-coffin"></i> remove hunk</li>').on('click', (evt) => {
-      view.requestRemoveHunk(this.ind)
-      $(menu).remove()
-    }))
-    $(menu).append($('<li><i class="em em-abc"></i> rename hunk</li>').on('click', (evt) => {
-      $(evt.target).text('')
-      let tinput = $('<input>').attr('type', 'text').attr('size', 24).attr('value', 'new name').get(0)
-      $(evt.target).append(tinput)
-      $(tinput).focus()
-      $(tinput).select()
-      $(tinput).on('keyup', (evt) => {
-        if (evt.keyCode == 13) {
-          view.requestRenameHunk(this.ind, tinput.value).then((def) => {
-            console.log('cleared new name for', def)
-            $(menu).remove()
-          })
-        }
-      })
-    }))
-    $(menu).append($('<li><i class="em em-repeat_one"></i> copy hunk</li>').on('click', (evt) => {
-      // todo: maybe this should copy state and req it down?
-      view.requestAddHunk(this.type)
-      $(menu).remove()
-    }))
-    // place it,
-    // title.offsetWidth is 400
-    // de.style.left, de.style.top, de.clientWidth,
-    let ct = dt.readTransform(this.deg.core)
-    let mp = {
-      s: 1,
-      x: ct.x,
-      y: ct.y - 31 * 3 - 10
-    }
-    if (this.containsButtons())
-      mp.y -= 25
-    if (view.isTopLevel) {
-      // write it,
-      $(menu).append($('<li><i class="em em-arrows_counterclockwise"></i> reload from source</li>').on('click', (evt) => {
-        view.reloadHunk(this.ind, false)
-      }))
-      mp.y -= 31
-    }
-    dt.writeTransform(menu, mp)
-    $(view.plane).append(menu)
-  }
-
-  // take the core, not stalling,
-  this.floaters[0].take(this.deg.core, this, false)
-
-  /* ---------------------------    ---------------------------- */
-  /* ------------------------- PHYSICS ------------------------- */
-  /* ---------------------------    ---------------------------- */
-
-  this.highlight = () => {
-    $(this.deg.core).find('.deftitle').css('background-color', '#969696')
-    if (this.deg.inputs)
-      $(this.deg.inputs).find('.inputheader').css('background-color', 'white').css('color', 'black')
-    if (this.deg.outputs)
-      $(this.deg.outputs).find('.outputheader').css('background-color', 'white').css('color', 'black')
-    if (this.deg.native)
-      $(this.deg.native).find('.nativeheader').css('background-color', 'white').css('color', 'black')
-  }
-
-  this.unhighlight = () => {
-    $(this.deg.core).find('.deftitle').css('background-color', '#303030')
-    if (this.deg.inputs)
-      $(this.deg.inputs).find('.inputheader').css('background-color', 'red').css('color', 'white')
-    if (this.deg.outputs)
-      $(this.deg.outputs).find('.outputheader').css('background-color', 'blue').css('color', 'white')
-    if (this.deg.native)
-      $(this.deg.native).find('.nativeheader').css('background-color', 'green').css('color', 'white')
-  }
-
-  /* ---------------------------    ---------------------------- */
-  /* ------------------------- UPDATES ------------------------- */
-  /* ---------------------------    ---------------------------- */
-
-  // UPDATE Index
-  this.newInd = (ind) => {
-    this.ind = ind
-    // and those titles, and ids ...
-    $(this.de).attr('id', `${this.name}_${this.ind}`)
-    $(title).text(`${this.name}`)
-    title.append($(`<span style="float:right">(${this.type})</span>`).get(0))
-    for (let ip of this.inputs) {
-      ip.onNewParentInfo()
-    }
-    for (let op of this.outputs) {
-      op.onNewParentInfo()
-    }
-    for (let st of this.states) {
-      st.onNewParentInfo()
-    }
-  }
-
-  // UPDATE Name
-  this.updateName = (newName) => {
-    this.name = newName
-    $(this.de).attr('id', `${this.name}_${this.ind}`)
-    $(title).text(`${this.name}`)
-    title.append($(`<span style="float:right">(${this.type})</span>`).get(0))
-    for (let ip of this.inputs) {
-      ip.onNewParentInfo()
-    }
-    for (let op of this.outputs) {
-      op.onNewParentInfo()
-    }
-    for (let st of this.states) {
-      st.onNewParentInfo()
-    }
-  }
-
-  this.cleanup = () => {
-    cleanButtons()
-    cleanFloaters()
-    for (let od in this.deg) {
-      $(this.deg[od]).remove()
-    }
-  }
-
-  let cleanFloaters = () => {
-    for (let flt of this.floaters) {
-      flt.cleanup()
-    }
-    this.floaters.length = 0
-  }
-
-  this.containsButtons = () => {
-    for (let fl of this.floaters) {
-      for (let it of fl.bag) {
-        if (it.type === 'button')
-          return true
-      }
-    }
-    return false
-  }
-
-  let cleanButtons = () => {
-    // sloppy! there is probably one in one of the cores,
-    try {
-      // max 5...
-      for (let i = 0; i < 5; i++) {
-        let bindex = this.floaters[0].bag.findIndex((cnd) => {
-          return cnd.type === 'button'
-        })
-        if (bindex !== -1) {
-          // also going to get that typeset issue ...
-          // pls to god this is reworked before a bug resulting appears
-          // rm from the dom,
-          $(this.floaters[0].bag[bindex].de).remove()
-          this.floaters[0].bag.splice(bindex, 1)
-        } else {
-          break
-        }
-      }
-      // now we can
-      this.floaters[0].onChange()
-    } catch (err) {
-      console.error(`couldn't clean buttons from ${this.name}, for reasons:`, err)
-    }
-  }
-
-  /* ---------------------------    ---------------------------- */
-  /* ----------------- RM/ADD/ECT to FLOATERS ------------------ */
-  /* ---------------------------    ---------------------------- */
-
-  this.collect = () => {
-    // restore state, collect .deg under one hood (what of buttons?)
-    console.error('not yet collecting')
-  }
-
-  this.unwrap = () => {
-    // never twice
-    if (this.floatGroupType === 'unwrapped')
-      return
-    // otherwise
-    this.floatGroupType = 'unwrapped'
-    // free willy
-    // ok, can we just murder everything and start from scratch?
-    // still have those .deg elements, so ...
-    // will have to write a remove
-    //console.log('UNWRAP')
-    cleanFloaters()
-    // (unrwapped) has a core with the core, outputs, and native
-    let cflt = new Floater(view, 'unwrapped')
-    if (this.deg.outputs) {
-      cflt.take(this.deg.outputs, this, true)
-    }
-    if (this.deg.native) {
-      if (this.type === 'view' && view) {
-        //console.log('ommitting view deg from this def')
-      } else {
-        cflt.take(this.deg.native, this, true)
-      }
-    }
-    cflt.take(this.deg.core, this)
-    if (this.deg.native) {
-      if (this.type === 'view' && view) {
-        //console.log('ommitting view deg from this def')
-      } else {
-        cflt.fitNativeToFloater()
-      }
-    }
-    this.floaters.push(cflt)
-    // if there are inputs, they are separate
-    if (this.deg.inputs) {
-      let iflt = new Floater(view, 'unwrapped')
-      iflt.take(this.deg.inputs, this)
-      this.floaters.push(iflt)
-    }
-    // and kick that
-    view.floop.reset()
-  }
-
-  // for links, accept a view domain element, add to ur floater, wrap that floater
-  this.wrapon = (viewDef) => {
-    // don't do it twice
-    if (this.floatGroupType === 'wrappedon')
-      return
-    // set state
-    this.floatGroupType = 'wrappedon'
-    // errs when not a link,
-    if (this.type !== 'link')
-      throw new Error('non-links doth not wrap')
-    // first stat, we want to keep this ref,
-    this.reciprocalView = viewDef.hunk
-    // ok, and we want viewdef objects to highlight ...
-    // if we're not gathered to start, that's probably bad news
-    if (this.floaters.length > 1)
-      console.error('wyd here? many floaters during a wrap', this.floaters)
-    // get the floater's bag-item containing that view ...
-    let vflt = viewDef.floaters.find((cnd) => {
-      return cnd.typeset.includes('native')
-    })
-    if (!vflt)
-      throw new Error('could not find view floater on swap')
-    //
-    let vbagindex = vflt.bag.findIndex((cnd) => {
-      return cnd.type === 'native'
-    })
-    if (vbagindex === -1)
-      throw new Error('could not find floater native item on swap')
-    let vbagitem = vflt.bag.splice(vbagindex, 1)[0]
-    // before we do this, let's push out some extra space
-    // this *is a hack*
-    let bnds = view.getCurrentBounds()
-    view.requestResize(1800, bnds.h + 600)
-    // we need to make sure it's in the link's plane, jquery is smart about this,
-    //console.log(view.plane, vbagitem.de)
-    $(view.plane).append(vbagitem.de)
-    // the link's 1st floater,
-    let flt = this.floaters[0]
-    flt.grouptype = 'wrapped'
-    // flt.take au manuel
-    flt.bag.push(vbagitem)
-    flt.typeset.push('native')
-    vbagitem.de.onResizeCustomCallback = flt.onElementResize
-    // can just do recalc now?
-    flt.onChange()
-    // and also,
-    vflt.onChange()
-    // and *also*
-    this.removeButton('<i class="em em-squid"></i>')
-    this.addButton('<i class="em em-shell"></i>', (evt) => {
-      console.error('no collapse yet')
-    })
-  }
-
-  this.edgecase = () => {
-    // check
-    if (this.floatGroupType === 'edgecased')
-      return
-    // or set
-    this.floatGroupType = 'edgecased'
-    // also links only pls,
-    if (this.type !== 'link')
-      throw new Error('non-links doth not edge')
-    // almost forgot, we want to get rid of this button:
-    cleanButtons()
-    // similar to the unwrap spec,
-    // we're also assuming at this point that this view isn't wrapped around a view
-    cleanFloaters()
-    // now we want a left floater,
-    // free willy
-    let lflt = new Floater(view, 'edges')
-    lflt.take(this.deg.core, this, true)
-    lflt.take(this.deg.outputs, this, true)
-    lflt.makeEdges()
-    this.floaters.push(lflt)
-    // and the right,
-    let rflt = new Floater(view, 'edges')
-    rflt.take(this.deg.inputs, this, true)
-    rflt.makeEdges()
-    this.floaters.push(rflt)
-    // ok,
-    view.floop.reset()
-    // put inputs / outputs at edges of view body
-    // put core below inputs, at left
-    // make message box of the view sit low
-    // handle view resizes ?
-  }
-
-  // adden em
-  this.addButton = (text, callback) => {
-    // write a button,
-    let btn = $(`<div>${text}</div>`).addClass('defbutton').get(0)
-    $(btn).on('click', callback).on('mouseover', (evt) => {
-      document.body.style.cursor = 'pointer'
-    }).on('mouseout', (evt) => [document.body.style.cursor = 'auto'])
-    // ok ok, then ...
-    // we find the floater that contains the core,
-    let coreFloater = this.floaters.find((cnd) => {
-      return cnd.typeset.includes('core')
-    })
-    if (!coreFloater)
-      throw new Error(`couldn't find a floater for this def button`, text)
-    // attach the button element to its bag ...
-    coreFloater.take(btn, this)
-  }
-
-  this.removeButton = (text, callback) => {
-    // find the core-containing floater
-    // we find the floater that contains the core,
-    let coreFloater = this.floaters.find((cnd) => {
-      return cnd.typeset.includes('core')
-    })
-    if (!coreFloater)
-      throw new Error(`couldn't find a floater for this def button`, text)
-    let success = false
-    // au manuel splice outta the bag
-    for (let item in coreFloater.bag) {
-      let itm = coreFloater.bag[item]
-      if (itm.type === 'button') {
-        if ($(itm.de).html() === text) {
-          // splice it out,
-          coreFloater.bag.splice(item, 1)
-          $(itm.de).remove()
-          coreFloater.onChange()
-          success = true
-        }
-      }
-    }
-    if (!success)
-      console.error(`couldn't remove the button having text ${text}`)
-
-  }
-
-  // absorbing a native hunk's domain element,
-  this.takeNative = (hunk) => {
-    this.hunk = hunk
-    // wants a wrapper,
-    this.deg.native = $('<div>').addClass('nativewrap').get(0)
-    // wrapper includes this title bar,
-    $(this.deg.native).append($(`<div>${this.name}'s html element</div>`).addClass('nativeheader').addClass('header'))
-    // and the hunk's element goes in that wrapper.
-    $(this.deg.native).append(this.hunk.dom)
-    // now we can hook it 2 a floater ... this will depend on our state, which we can mod later
-    // atm, we'll put it with the core,
-    let coreFloater = this.floaters.find((cnd) => {
-      return cnd.typeset.includes('core')
-    })
-    if (!coreFloater)
-      throw new Error(`couldn't find a floater for this def native`)
-    // hook it
-    coreFloater.take(this.deg.native, this, false, this.hunk.onresize)
-    // has this handle,
-    this.hunk.requestResize = (x, y) => {
-      // set manual and call update,
-      // doesn't matter which hunk this is in...
-      // console.log(`REQRESIZE hunk ${this.name} requesting size of ${x}, ${y}`)
-      // console.log('native', this.deg.native)
-      this.deg.native.requestResize(x, y)
-      view.tick()
-    }
-    // now we should be able to,
-    this.hunk.onload()
-  }
-
-  // add special case buttons, just this so far
-  if (this.type === 'link') {
-    // todo:
-    let expander = () => {
-      this.addButton('<i class="em em-squid"></i>', (evt) => {
-        // ???
-        view.tlv.expandLink(this).then((view) => {
-          console.log("EXPANDEEED --> expandLink promise completes", view)
-        }).catch((err) => {
-          console.log("EXP catches err", err)
-        })
-      })
-    }
-    expander()
-  }
-
-  this.fixWithDataPort = () => {
-    if (this.floaters[0].isFixed) {
-      // find the data port,
-      let dp = view.tlv.trace(this.outputs[0])
-      if (dp) {
-        dp.parent.floaters[0].fixTo(this.floaters[0].fx + 500, this.floaters[0].fy - 100)
-      } else {
-        console.error("no data port from trace")
-      }
-    } else {
-      console.error("won't fix with data port: not fixed")
-    }
-  }
-
-} // end def def
-
-/* ---------------------------    ---------------------------- */
-/* ------------------------ INPUT DEF ------------------------ */
-/* ---------------------------    ---------------------------- */
-
-function InputDefinition(ipspec, ind, def, debug) {
-  // keep track of name and type,
-  this.name = ipspec.name
-  this.type = ipspec.type
-  this.parent = def
-  this.ind = parseInt(ind)
-  // a dom element
-  this.de = $(`<li>${this.name} (${this.type})</li>`).addClass('input').get(0)
-  this.de.id = `${this.parent.name}_${this.parent.ind}_input_${this.name}`
-  this.onNewParentInfo = () => {
-    this.de.id = `${this.parent.name}_${this.parent.ind}_input_${this.name}`
-  }
-  // we also keep a list,
-  this.connections = new Array()
-  this.disconnect = (output) => {
-    let index = this.connections.findIndex((cand) => {
-      return (cand.parent.ind === output.parent.ind && cand.name === output.name && cand.type === output.type)
-    })
-    if (index === -1)
-      throw new Error('during output disconnect, input cannot find output...')
-    this.connections.splice(index, 1)
-  }
-  this.disconnectAll = () => {
-    for (let op of this.connections) {
-      op.disconnect(this)
-    }
-    this.connections.length = 0
-  }
-  // to get this object via the dom, circular... apparently that is fine ?
-  this.de.hookup = this
-}
-
-/* ---------------------------    ---------------------------- */
-/* ----------------------- OUTPUT DEF ------------------------ */
-/* ---------------------------    ---------------------------- */
-
-function OutputDefinition(opspec, ind, def, view, dt, debug) {
-  // keep track of name and type,
-  this.parent = def
-  this.name = opspec.name
-  this.type = opspec.type
-  this.ind = parseInt(ind)
-  // a dom element
-  this.de = $(`<li>(${this.type}) ${this.name}</li>`).addClass('output').get(0)
-  this.de.id = `${this.parent.name}_${this.parent.ind}_output_${this.name}`
-  this.onNewParentInfo = () => {
-    this.de.id = `${this.parent.name}_${this.parent.ind}_output_${this.name}`
-  }
-  // outputs handle all of the dragging-etc
-  if (opspec.connections !== undefined) {
-    this.specConnections = opspec.connections
-  }
-  this.connections = new Array() // of inputdefs, !
-  this.connect = (inputdef) => {
-    inputdef.connections.push(this)
-    this.connections.push(inputdef)
-  }
-  this.disconnect = (inputdef) => {
-    inputdef.disconnect(this)
-    let iof = this.connections.findIndex((cand) => {
-      return (cand.name === inputdef.name && cand.parent.ind === inputdef.parent.ind)
-    })
-    if (iof === -1)
-      throw new Error('could not find input to disconnect')
-    this.connections.splice(iof, 1)
-    return true
-  }
-  this.disconnectAll = () => {
-    for (let ip of this.connections) {
-      ip.disconnect(this)
-    }
-    this.connections.length = 0
-  }
-  // the dragging
-  this.floater = {}
-  this.hasFloater = false
-  // ondrag, attached later
-  let evtDrag = (evt) => {
-    evt.preventDefault()
-    evt.stopPropagation()
-    let pt = dt.readTransform(view.tlv.plane)
-    let thet = dt.readTransform(this.floater)
-    // ... set delta
-    thet.x += evt.movementX / pt.s
-    thet.y += evt.movementY / pt.s
-    dt.writeTransform(this.floater, thet)
-    view.drawLinks()
-  }
-  // to remove the below
-  let dragMouseUp = (evt) => {
-    if (debug)
-      console.log('MOUSEUP ON', evt.target.id)
-    // 1st, make sure it's an input
-    if ($(evt.target).is('.input')) {
-      // HERE: searcheth by input id text? or
-      let hk = evt.target.hookup
-      // hookups are hooks to the input's def-object
-      // console.log('ah hookup looks like:', hk)
-      if (!hk)
-        throw new Error('missing some data at this input...')
-      // use a dom data flag, to find that input and output id?
-      // are we in the same context?
-      if (hk.parent.parentView === this.parent.parentView) {
-        view.requestAddLink(this, hk)
-      } else {
-        console.warn("UI Route Builder Begins...")
-        this.parent.parentView.tlv.buildRoute(this, hk).then(() => {
-          console.warn("UI Route Builder Resolves !")
-        })
-      }
-      // do things to conn, then
-    }
-    // cleanup
-    document.removeEventListener('mouseup', dragMouseUp)
-    document.removeEventListener('mousemove', evtDrag)
-    // remove the floater flag
-    this.hasFloater = false
-    // remove the floater itself
-    $(view.plane).find('#floater').remove()
-    view.drawLinks()
-  }
-  // eeeeehntr for link-hookup-dragging
-  this.de.onmousedown = (evt) => {
-    evt.stopPropagation()
-    evt.preventDefault()
-    if (debug)
-      console.log('mousedown for', this)
-    // this and that flag will be read-in on drawlinks, to draw that link
-    this.floater = $('<div>').attr('id', 'floater').append(this.type).get(0)
-    this.hasFloater = true
-    this.floater.style.zIndex = '1'
-    // set initial position by the outputs' position,
-    let dparent = $(this.de).parent().get(0)
-    let opp = dt.readTransform(dparent)
-    // top-level plane ...
-    let pt = dt.readTransform(view.tlv.plane)
-    // plonk: have to do this now or else clientHeight / width are 0
-    view.plane.appendChild(this.floater)
-    // init out floater position, and put it in the dom
-    dt.writeTransform(this.floater, {
-      s: 1,
-      x: opp.x - ((this.floater.clientWidth + 5)),
-      y: opp.y + this.floater.clientHeight * (this.ind + 0.5) // - ((fltheight * pt.s) / 2) / pt.s
-    })
-    // handlers to drag, and remove
-    document.addEventListener('mousemove', evtDrag)
-    // and delete / act when mouse comes up
-    document.addEventListener('mouseup', dragMouseUp)
-  }
-}
-
-/* ---------------------------    ---------------------------- */
-/* ------------------------ STATE DEF ------------------------ */
-/* ---------------------------    ---------------------------- */
-
-function StateDefinition(stspec, ind, def, view, debug) {
-  this.parent = def
-  this.name = stspec.name
-  this.type = stspec.type
-  this.ind = parseInt(ind)
-  // business,
-  this.value = stspec.value
-  // ok,
-  this.de = $('<div>' + this.name + " (" + this.type + ")" + '</div>').addClass('stateItem').get(0)
-  this.de.id = `${this.parent.name}_${this.parent.ind}_state_${this.name}`
-  this.onNewParentInfo = () => {
-    this.de.id = `${this.parent.name}_${this.parent.ind}_state_${this.name}`
-  }
-  // ui for these ... we can just cover the basics of js types because yonder serializations
-  // etc will throw errors for other types. of course, this could help more, but we're in a rush
-  switch (typeof this.value) {
-    case 'string':
-      //dom.append($('<br>').get(0))
-      let strinput = $('<input>').attr('type', 'text').attr('size', 32).attr('value', this.value).css('width', '240px').get(0)
-      strinput.addEventListener('change', (evt) => {
-        // ask for a change,
-        // TODO HERE NOW: this is the state change request you want to write
-        // do it like writeMessage() instead
-        // requestStateChange(def.id, state, strinput.value)
-        // but assert that we don't change the definition unless
-        view.requestStateChange(this, strinput.value)
-        strinput.value = this.value
-      })
-      this.de.append(strinput)
-      this.set = (value) => {
-        if (typeof value === 'string') {
-          strinput.value = value
-          this.value = value
-        } else {
-          throw new Error('bad type put into state dom')
-        }
-      }
-      break // end string types
-    case 'number':
-      let ninput = $('<input>').addClass('stateNumInput').attr('type', 'text').attr('size', 24).attr('value', this.value.toString()).css('width', '100px').get(0)
-      ninput.addEventListener('change', (evt) => {
-        // ask for a change, watch for float or for int ...
-        if (isIntType(this.type)) {
-          view.requestStateChange(this, parseInt(ninput.value))
-        } else {
-          view.requestStateChange(this, parseFloat(ninput.value))
-        }
-        // but assert that we don't change the definition unless
-        ninput.value = this.value
-      })
-      this.de.append(ninput)
-      this.set = (value) => {
-        if (typeof value === 'number') {
-          // quite sure js does this conversion no problem
-          ninput.value = value
-          this.value = value
-        } else {
-          throw new Error('bad type put into state dom')
-        }
-      }
-      break // end numnber type
-    case 'boolean':
-      let span = $('<span style="float:right;">' + this.value.toString() + '</span>').get(0)
-      $(this.de).addClass('stateBooleanItem')
-      this.de.append(span)
-      this.de.addEventListener('click', (evt) => {
-        // read the current 'state' (as written) and send the opposite
-        let txt = $(span).text()
-        if (txt === 'true') {
-          view.requestStateChange(this, false)
-        } else {
-          view.requestStateChange(this, true)
-        }
-      })
-      this.set = (value) => {
-        if (typeof value === 'boolean') {
-          $(span).text(value.toString())
-          this.value = value
-        } else {
-          throw new Error('bad type put into state dom')
-        }
-      }
-      break // end boolean type
-    default:
-      console.error(`unaccounted for type at input pull for state change, ${typeof state.value}`)
-      break
-  }
-}
-- 
GitLab