diff --git a/css/main.css b/css/main.css
index e9adf2cfc2ab6c47798096e73768ad2e529cd0a2..0b56c36a7070298da67bc957dd2bf836b7348401 100644
--- a/css/main.css
+++ b/css/main.css
@@ -145,3 +145,14 @@ hr {
   border-color: #888 -moz-use-text-color #888;
 }
 
+
+#gcodeEditor {
+    font-family: Courier, monospace;
+    font-size: 13px;
+    line-height: 30px;
+    resize: none;
+    height: 600px;
+    width: 100%;
+    border-width: 0px;
+    background-color: rgba(255,255,255,0.5);
+}
diff --git a/js/cam/Assembler.js b/js/cam/Assembler.js
index 6f9a82adceded6a68d55c9848b209672fe81dc24..7c3e7ffe2890b3076b9ad106348af4f568397296 100644
--- a/js/cam/Assembler.js
+++ b/js/cam/Assembler.js
@@ -6,28 +6,62 @@ Assembler = Backbone.Model.extend({
 
     defaults: {
         camStrategy: "xRaster",
-        camProcess: "shopbot"
+        camProcess: "shopbot",
+        exporter: null,
+        dataOut: "",
+        needsPostProcessing: true,
+        editsMadeToProgram: false//warn the user that they will override changes
     },
 
     initialize: function(){
 
         //bind events
+        this.listenTo(this, "change:camProcess", this._setNeedsPostProcessing);
+        this.listenTo(dmaGlobals.appState, "change:units", this._setNeedsPostProcessing);
 
     },
 
-    processAndSave: function(){
+    _setNeedsPostProcessing: function(){
+        this.set("needsPostProcessing", true);
+    },
+
+    setProgramEditsMade: function(){
+        this.set("editsMadeToProgram", true);
+    },
+
+    postProcess: function(){
         var exporter;
         if (this.get("camProcess") == "shopbot") exporter = new ShopbotExporter();
         else if (this.get("camProcess") == "gcode") exporter = new GCodeExporter();
         if (exporter) {
             var data = "";
             data += exporter.makeHeader();
+            data += "\n\n";
+            data += exporter.addComment("begin program");
+            data += "\n";
             data += exporter.moveZ(3);
             data += exporter.move3(1, 4, 5);
+            data += "\n\n";
+            data += exporter.addComment("end program");
+            data += "\n";
             data += exporter.makeFooter();
-            exporter.save(data);
+            this.set("dataOut", data);
+            this.set("exporter", exporter);
         }
         else console.warn("cam process not supported");
+        this.set("needsPostProcessing", false);
+        return {data:data, exporter:exporter};
+    },
+
+    save: function(data, exporter){
+        if (this.get("needsPostProcessing")){
+            var output = this.postProcess();
+            output.exporter.save(output.data);
+            return;
+        }
+        if (!data) data = this.get("dataOut");
+        if (!exporter) exporter = this.get("exporter");
+        exporter.save(data);
     },
 
     destroy: function(){
diff --git a/js/cam/GCodeExporter.js b/js/cam/GCodeExporter.js
index 74c23e818c53e84adf5a68b21dc2d48efac918d5..968641e83a308aa049df92679d78660b0c7db80e 100644
--- a/js/cam/GCodeExporter.js
+++ b/js/cam/GCodeExporter.js
@@ -13,16 +13,12 @@ GCodeExporter.prototype.makeHeader = function(){
     data += this.addLine("G54", [], "work offset");
 //    data += this.addLine("G49", [], "cancel tool length comp");
     data += this.addLine("G40", [], "cancel tool radius comp");
-    data += this.addLine("M09", [], "coolant off");
-
-
+//    data += this.addLine("M09", [], "coolant off");
 
     data += this.goHome();
 
     //set rapid and feed speeds
 
-    data += "\n";
-    data += "\n";
     return data;
 };
 
@@ -38,6 +34,10 @@ GCodeExporter.prototype.addLine = function(command, params, comment){
     return data;
 };
 
+GCodeExporter.prototype.addComment = function(comment){
+    return "(" + comment + ")" + "\n";
+};
+
 GCodeExporter.prototype.rapid3 = function(x, y, z){
     return this.move3(x,y,z);
 };
@@ -59,6 +59,8 @@ GCodeExporter.prototype.moveZ = function(z){
 
 GCodeExporter.prototype.makeFooter = function(){
     var data = "";
+    data += "\n";
+    data += "\n";
     data += this.goHome();
     data += this.addLine("M30", [], "program stop");
 
diff --git a/js/cam/ShopbotExporter.js b/js/cam/ShopbotExporter.js
index a3d3ac1d80d54e17d43d7290e1fa909f1c6738d9..2852fabbd303df01c1c25839f05d1ce30c4ba86a 100644
--- a/js/cam/ShopbotExporter.js
+++ b/js/cam/ShopbotExporter.js
@@ -10,11 +10,9 @@ ShopbotExporter.prototype.makeHeader = function(){
     data += this.addLine("FG", [], "single step mode");
     data += this.goHome();
     data += this.addLine("SA", [], "absolute distances");
-    data += this.addLine("SM", [4, 1], "move/cut mode (as opposed to preview mode)");
+    data += this.addLine("SM", [], "move/cut mode (as opposed to preview mode)");
     data += this.addLine("JS", [4, 1], "jog speed- xy, z inches per sec");
-    data += this.addLine("MS", [4, 1], "move speed- xy, z inches per sec");
-    data += "\n";
-    data += "\n";
+    data += this.addLine("MS", [2, 0.5], "move speed- xy, z inches per sec");
     return data;
 };
 
@@ -29,6 +27,10 @@ ShopbotExporter.prototype.addLine = function(command, params, comment){
     return data;
 };
 
+ShopbotExporter.prototype.addComment = function(comment){
+    return "'" + comment + "\n";
+};
+
 ShopbotExporter.prototype.rapid3 = function(x, y, z){
     return this.addLine("J3", [x,y,z]);
 };
@@ -47,7 +49,7 @@ ShopbotExporter.prototype.moveZ = function(z){
 
 ShopbotExporter.prototype.makeFooter = function(){
     var data = "";
-
+    data += this.goHome();
     return data;
 };
 
diff --git a/js/main.js b/js/main.js
index dad9fc39a598f4b67b376c80e07bf1d751ceb19b..8288646a1f1d67c833ca072b12726533f6f2e268 100644
--- a/js/main.js
+++ b/js/main.js
@@ -14,10 +14,11 @@ $(function(){
     //init threeJS and geometry models
     dmaGlobals.three = new ThreeModel();
 
+    dmaGlobals.appState = new AppState();
     dmaGlobals.lattice = new Lattice();
     dmaGlobals.lattice._updateLatticeType();//todo get rid of this
     dmaGlobals.assembler = new Assembler();
-    dmaGlobals.appState = new AppState();
+    dmaGlobals.appState.delayedInit();
 
 
     //ui
diff --git a/js/menus/CamMenuView.js b/js/menus/CamMenuView.js
index 9178d0aab6aef78d12a717853380e91d550317e2..2e8bc61c306f72a1c550712a24727daba2acd4ed 100644
--- a/js/menus/CamMenuView.js
+++ b/js/menus/CamMenuView.js
@@ -10,7 +10,7 @@ CamMenuView = Backbone.View.extend({
     events: {
         "click .camProcess":                            "_selectCamProcess",
         "click .units":                                 "_changeUnits",
-        "click #saveCam":                               "_processAndSave"
+        "click #saveCam":                               "_save"
     },
 
 
@@ -34,9 +34,9 @@ CamMenuView = Backbone.View.extend({
         this.model.set("units", $(e.target).data("type"));
     },
 
-    _processAndSave: function(e){
+    _save: function(e){
         e.preventDefault();
-        this.assembler.processAndSave();
+        this.assembler.save();
     },
 
     render: function(){
@@ -63,7 +63,7 @@ CamMenuView = Backbone.View.extend({
                     <% }); %>\
                 </ul>\
             </div><br/><br/>\
-            <a href="#" id="saveCam" class=" btn btn-block btn-lg btn-default">Process and Save</a><br/>\
+            <a href="#" id="saveCam" class=" btn btn-block btn-lg btn-default">Save</a><br/>\
         ')
 
 });
\ No newline at end of file
diff --git a/js/menus/SendMenuView.js b/js/menus/SendMenuView.js
index e4a6cb90a3f77c8c4c33770705c9ad0bac8891f9..15fe73834bed6919e6fda2af97b493e30f539087 100644
--- a/js/menus/SendMenuView.js
+++ b/js/menus/SendMenuView.js
@@ -7,20 +7,29 @@ SendMenuView = Backbone.View.extend({
     el: "#menuContent",
 
     events: {
+        "click #saveSendMenu":                                       "_save"
     },
 
-    initialize: function(options){
+    initialize: function(){
+
 
         _.bindAll(this, "render");
     },
 
+    _save: function(e){
+        e.preventDefault();
+        dmaGlobals.assembler.save();
+    },
+
     render: function(){
         if (this.model.get("currentTab") != "send") return;
-        this.$el.html(this.template());
+        if (dmaGlobals.assembler.get("needsPostProcessing")) dmaGlobals.assembler.postProcess();
+        this.$el.html(this.template(dmaGlobals.assembler.toJSON()));
     },
 
     template: _.template('\
-        send commands to machine\
+        <a href="#" id="saveSendMenu" class=" btn btn-block btn-lg btn-default">Save</a><br/>\
+        <textarea id="gcodeEditor"><%= dataOut %></textarea>\
         ')
 
 });
\ No newline at end of file
diff --git a/js/models/AppState.js b/js/models/AppState.js
index 0f613718b91c184927c67f2b9e8506299252c0bd..09b7b2bd1153be60f1882a95d4d69b1439569227 100644
--- a/js/models/AppState.js
+++ b/js/models/AppState.js
@@ -117,8 +117,11 @@ AppState = Backbone.Model.extend({
     },
 
     initialize: function(){
+    },
+
+    delayedInit: function(){
 
-        _.bindAll(this, "_handleKeyStroke");
+         _.bindAll(this, "_handleKeyStroke");
 
         //bind events
         $(document).bind('keydown', {state:true}, this._handleKeyStroke);