         return x
 
     toLocal: ->
-        eval(@spec.id + " = $blab.sheet['" + @spec.id + "'].data")
-
-    fromLocal: ->
-        console.log "???", "$blab.sheet['" + @spec.id + "'].data = " + @spec.id
-        eval("$blab.sheet['" + @spec.id + "'].data = " + @spec.id)
-    
-
-class Plot
+        eval("#{@spec.id} = $blab.sheet['#{@spec.id}'].data")
+
+    fromLocal: (u)->
+        $blab.sheet[@spec.id].data = u
+
+    stringify: ->
+        s = JSON.stringify(@spec)
+        d = JSON.stringify(@data)
+        r = JSON.stringify(@rowHeaders)
+        c = JSON.stringify(@colHeaders)
+        "{spec:#{s}, data:#{d}, rowHeaders:#{r}, colHeaders:#{c}}"
+        
+class Figure
 
     constructor: (@spec) ->
 
         @sheet = $blab.sheet[@spec.id]
-
+        container = $("[data-sym=#{@spec.id}][data-type='figure']")[0]
+        
         @chart = c3.generate(
-          bindto: $("[data-sym=#{@spec.id}][data-type='figure']")[0]
-          data: json: @sheet.rowJson()
+            bindto: container
+            data: json: @sheet.rowJson()
         )
 
     update: ->
         @chart.load(json: @sheet.rowJson())
 
+    stringify: ->
+        JSON.stringify($blab.figure[@spec.id]["spec"])
+
 
 class Table
-    
+
     constructor: (@spec) ->
 
-        @sheet = $blab.sheet[@spec.id]
-        @data = @sheet.data
-
-        @table = new Handsontable $("[data-sym=#{@spec.id}][data-type='table']")[0],
-            data: @data
-            startRows: @data.length
-            startCols: @data[0].length
-            rowHeaders: @sheet.rowHeaders
-            colHeaders: @sheet.colHeaders 
+        sheet = $blab.sheet[@spec.id]
+
+        data = sheet.data
+        numRows = data.length
+        numCols = data[0].length
+        container = $("[data-sym=#{@spec.id}][data-type='table']")[0]
+
+        @table = new Handsontable container,
+            data: data
+            startRows: numRows
+            startCols: numCols
+            rowHeaders: sheet.rowHeaders
+            colHeaders: sheet.colHeaders 
             contextMenu: true
-            columns: ({type: 'numeric'} for k in [1..@data[0].length])
-            afterChange: (change, source) ->
-                compute() if source is "edit"
+            columns: ({type: 'numeric'} for k in [1..numCols])
+            afterChange: (change, source) =>
+                compute() if source is "edit" and @spec.compute
 
     update: ->
-        @data = @sheet.data
-        @table.loadData @data
+        @table.loadData $blab.sheet[@spec.id].data
         @table.render()
         
+    stringify: ->
+        JSON.stringify($blab.table[@spec.id]["spec"])
+
 
 class Slider
 
-    constructor: (@sheet, @spec) ->
-        
-        @container = $("[data-sym=#{@spec.id}][data-type='slider']")
-        @container.css("width", @spec.width)
-
-        @container.append("<div class='slider'></div>")
-        @slider = @container.find('.slider')
-
-        @container.append("<div class='label'></div>")
-        @label = @container.find('.label')
-        @label.html(@sheet.rowHeaders[0])
-
-        @container.append("<input type='text' readonly class='report'>")
-        @report = @container.find('.report')
-
+    constructor: (@spec) ->
+
+        @spec.width ?= 500
+        @spec.value ?= 1
+        @spec.min ?= 0
+        @spec.max ?= 10
+        @spec.step ?= 1
+
+        sheet = $blab.sheet[@spec.id]
+        
+        container = $("[data-sym=#{@spec.id}][data-type='slider']")
+        container.css("width", @spec.width)
+        container.append("<div class='slider'></div>")
+        container.append("<div class='label'></div>")
+        container.append("<input type='text' readonly class='report'>")
+
+        label = container.find('.label')
+        label.html(sheet.rowHeaders[0])
+
+        report = container.find('.report')
+
+        @slider = container.find('.slider')
         @slider.slider
-            value: 1
-            min: 0
-            max: 10
-            step: 1
-            slide: (event, ui) =>
-                @report.val ui.value
-                compute()
+            value: @spec.value
+            min: @spec.min
+            max: @spec.max
+            step: @spec.step
+            change: (event, ui) =>
+                report.val ui.value
+                compute() if @spec.compute
                 
-        @report.val @slider.slider('value')
+        report.val @slider.slider("value")
 
     update: ->
-        $blab.sheet[@spec.id].data[0][0] = @slider.slider('value')
-
+        $blab.sheet[@spec.id].data[0][0] =  @slider.slider("value")
+
+    stringify: ->
+        JSON.stringify($blab.slider[@spec.id]["spec"])
    
 ## From GUI
 
 # sheets
 
-sh = (id, data) -> new Sheet {id:id, data:data}
+$blab.sheet = []
+sh = (id, data) -> new Sheet {id:id}, data #{id:id, data:data}
+
+$blab.sheet["A"] = sh "A", [[1,2],[3,4]]
+
 $blab.sheet =
     A: sh "A", [[1,2],[3,4]]
     x: sh "x", [[5],[6]]

    for sl of $blab.slider
        $blab.slider[sl].update()

    # local copy of vars 
    for sh of $blab.sheet
        $blab.sheet[sh].toLocal()

    ## user code


class Sheet
    
    constructor: (@spec, @data, @colHeaders, @rowHeaders) ->

        @data ?= [[0]]
        numCols = @data[0].length
        numRows = @data.length

        @colHeaders ?= ("c#{k}" for k in [0...numCols])
        @rowHeaders ?= ("r#{k}" for k in [0...numRows])

    rowJson: ->
        x = {}
