         @nb.delete_cell(index + 1)
 
         # TODO: If this cell was focused and our cursors were in this cell, we put them back:
-        
+
 
         #console.log("set_cell: done", misc.mswalltime(t))
 
     # Notebook Doc Format: line 0 is meta information in JSON.
-    # Rest of file has one line for each cell for rest of file, in the following format:
+    # Rest of file has one line for each cell for rest of file, in JSON format.
     #
-    #     cell input text (with newlines replaced) [special unicode character] json object for cell, without input
-    #
-    # We split the line as above so that if/when there are merge conflicts
-    # that result in json corruption, which we then reject, only the *output*
-    # is impacted. The odds of corruption in the output is much less.
-    #
+    remove_images: (cell) =>
+        return # for now
+        if cell.outputs?
+            for out in cell.outputs
+                if out.data?
+                    for k, v of out.data
+                        if k.slice(0,6) == 'image/'
+                            delete out.data[k]
+
+    restore_images: (cell) =>
+        return
+
     cell_to_line: (cell) =>
         cell = misc.copy(cell)
-        source = misc.to_json(cell.source)
-        delete cell['source']
-        line = source + diffsync.MARKERS.output + misc.to_json(cell)
-        #console.log("\n\ncell=", misc.to_json(cell))
-        #console.log("line=", line)
-        return line
+        @remove_images(cell)
+        return misc.to_json(cell)
 
     line_to_cell: (line) =>
-        v = line.split(diffsync.MARKERS.output)
         try
-            if v[0] == 'undefined'  # backwards incompatibility...
-                source = undefined
-            else
-                source = JSON.parse(v[0])
+            cell = misc.from_json(line)
+            @restore_images(cell)
+            return cell
         catch e
-            console.log("line_to_cell('#{line}') -- source ERROR=", e)
-            return
-        try
-            cell = JSON.parse(v[1])
-            cell.source = source
-        catch e
-            console.log("line_to_cell('#{line}') -- output ERROR=", e)
-        #console.log("\n\nlin=", line)
-        #console.log("cell=", misc.to_json(cell))
-        return cell
+            console.warn("line_to_cell('#{line}') -- source ERROR=", e)
+            return
 
     # Convert the visible displayed notebook into a textual sync-friendly string
     nb_to_string: () =>

        @status("Displaying Jupyter Notebook")
        if @doc.live() == ""
            # set the synchronized string from the visible notebook
            ## TODO here
            @doc.live(@nb_to_string())
        else
            # set the visible notebook from the synchronized string

        @con      = @element.find(".smc-jupyter-notebook-connecting")
        @setup () =>
            # TODO: We have to do this stupid thing because in IPython's notebook.js they don't systematically use
            # set_dirty, sometimes instead just directly setting the flag.  So there's no simple way to know exactly
            # when the notebook is dirty. (TODO: fix all this via upstream patches.)

            @_autosync_interval = setInterval(@autosync, @opts.sync_interval)
            @_cursor_interval   = setInterval(@broadcast_cursor_pos, @opts.cursor_interval)
