diff --git a/js/cam/assemblers/Assembler.js b/js/cam/assemblers/Assembler.js
index 2effb730d8c32b287d636fc30ef5b7d07d997ae2..72c5be6a2a5391edae71e50ab10819f696afde23 100644
--- a/js/cam/assemblers/Assembler.js
+++ b/js/cam/assemblers/Assembler.js
@@ -39,6 +39,7 @@ Assembler.prototype._buildAssemblerMeshes = function(callback){
         self[name] = new THREE.Mesh(geometry, assemblerMaterial);
         if (allLoaded()) callback();
     }
+
     this._loadSTls(doAdd);
 };
 
@@ -54,6 +55,79 @@ Assembler.prototype.setVisibility = function(visible){
     globals.three.render();
 };
 
+
+
+
+
+Assembler.prototype.postProcess = function(data, exporter){//override in subclasses
+
+    var rapidHeight = globals.cam.get("rapidHeight");
+    var safeHeight = globals.cam.get("safeHeight");
+    var wcs = globals.cam.get("originPosition");
+
+    var stockPosition = globals.cam.get("stockPosition");
+    var stockNum = 0;//position of stock in stock array
+    var multStockPositions = globals.cam.get("multipleStockPositions");
+    var stockSeparation = globals.cam.get("stockSeparation");
+    var stockArraySize = globals.cam.get("stockArraySize");
+    var self = this;
+
+    globals.lattice.rasterCells(globals.cam._getOrder(globals.cam.get("camStrategy")), function(cell){
+        if (!cell) return;
+        if (this.stockAttachedToEndEffector){
+            data += self._postGetStock(exporter);
+        } else {
+            var thisStockPosition = _.clone(stockPosition);
+            if (multStockPositions) {
+                thisStockPosition.x += stockNum % stockArraySize.y * stockSeparation;
+                thisStockPosition.y -= Math.floor(stockNum / stockArraySize.y) * stockSeparation;
+                stockNum += 1;
+                if (stockNum >= stockArraySize.x * stockArraySize.y) stockNum = 0;
+            }
+            data += self._postMoveXY(exporter, stockPosition.x-wcs.x, stockPosition.y-wcs.y);
+            data += self._postPickUpStock(exporter, thisStockPosition, rapidHeight, wcs, safeHeight);
+        }
+        var cellPosition = cell.getPosition();
+        data += self._postMoveXY(exporter, cellPosition.x-wcs.x, cellPosition.y-wcs.y);
+        data += self._postReleaseStock(cellPosition, cell, exporter, rapidHeight, wcs, safeHeight);
+        data += "\n";
+    });
+    return data;
+};
+
+Assembler.prototype._postMoveXY = function(exporter, x, y){
+    return exporter.rapidXY(x, y);
+};
+
+Assembler.prototype._postPickUpStock = function(exporter, stockPosition, rapidHeight, wcs, safeHeight){
+    var data = "";
+    data += exporter.rapidZ(stockPosition.z-wcs.z+safeHeight);
+    data += exporter.moveZ(stockPosition.z-wcs.z);
+    data += this._postGetStock(exporter);
+    data += exporter.moveZ(stockPosition.z-wcs.z+safeHeight);
+    data += exporter.rapidZ(rapidHeight);
+    return data;
+};
+
+Assembler.prototype._postGetStock = function(exporter){
+    return exporter.addComment("get stock");
+};
+
+Assembler.prototype._postReleaseStock = function(cellPosition, cell, exporter, rapidHeight, wcs, safeHeight){
+    var data = "";
+    data += exporter.rapidZ(cellPosition.z-wcs.z+safeHeight);
+    data += exporter.moveZ(cellPosition.z-wcs.z);
+    data += exporter.addComment(JSON.stringify(cell.indices));
+    data += exporter.moveZ(cellPosition.z-wcs.z+safeHeight);
+    data += exporter.rapidZ(rapidHeight);
+    return data;
+};
+
+
+
+
+
+
 Assembler.prototype.destroy = function(){
     this.stock.destroy();
     this.zAxis.parent.remove(this.zAxis);
diff --git a/js/cam/assemblers/StaplerAssembler.js b/js/cam/assemblers/StaplerAssembler.js
index a7495ab494397c392ff3dfad06c5078a605ce3ed..6e7e5293f1d8b9218e4ecfca8e5dcfd51034a400 100644
--- a/js/cam/assemblers/StaplerAssembler.js
+++ b/js/cam/assemblers/StaplerAssembler.js
@@ -4,6 +4,7 @@
 
 
 function StaplerAssembler(){
+    this.stockAttachedToEndEffector = true;//no need for "stock position"
     Assembler.call(this);
 }
 StaplerAssembler.prototype = Object.create(Assembler.prototype);
diff --git a/js/cells/DMACell.js b/js/cells/DMACell.js
index 954e515e6ec40d387d843fedccd8508a0df94737..a011aea62f66acbf3f72cd7a5caea2fa9f16cd6a 100644
--- a/js/cells/DMACell.js
+++ b/js/cells/DMACell.js
@@ -102,7 +102,7 @@ DMACell.prototype.setSuperCell = function(superCell, index){
 
     if (this.superCellIndex == this.superCell.getLength()) this.mesh.rotateZ(Math.PI);
     if (globals.appState.get("cellMode")=="part") {
-        this.parts = this.__initParts();
+        this.parts = this._initParts();
         this.draw();
     }
 };
diff --git a/js/lattice/GIKLattice.js b/js/lattice/GIKLattice.js
index ec285c1ce5f31c25e6076a2c21d929a4d7c91bcc..e8847f5ab47e31e730d73a72e60d25b3e48036f2 100644
--- a/js/lattice/GIKLattice.js
+++ b/js/lattice/GIKLattice.js
@@ -52,43 +52,43 @@ latticeSubclasses["GIKLattice"] = {
             return new GIKSuperCell(length, range, cells);
         },
 
-        _rasterGikCells: function(order, callback, var1, var2, var3, cells){
-            for (var i=this._getRasterLoopInit(var1);this._getRasterLoopCondition(i,var1);i+=this._getRasterLoopIterator(var1)){
-                for (var j=this._getRasterLoopInit(var2);this._getRasterLoopCondition(j,var2);j+=this._getRasterLoopIterator(var2)){
-                    for (var k=this._getRasterLoopInit(var3);this._getRasterLoopCondition(k,var3);k+=this._getRasterLoopIterator(var3)){
-                        var numToSkip = {x:0,y:0};
-                        if (var1.order == 0){
-                            if (var2.order == 1) numToSkip = this._doSuperCellCallback(cells, i, j, k, callback);
-                            else if (var2.order == 2) numToSkip = this._doSuperCellCallback(cells, i, k, j, callback);
-                        } else if (var1.order == 1){
-                            if (var2.order == 0) numToSkip = this._doSuperCellCallback(cells, j, i, k, callback);
-                            else if (var2.order == 2) numToSkip = this._doSuperCellCallback(cells, k, i, j, callback);
-                        } else {
-                            if (var2.order == 0) {
-                                numToSkip = this._doSuperCellCallback(cells, j, k, i, callback);
-                            }
-                            else if (var2.order == 1) {
-                                numToSkip = this._doSuperCellCallback(cells, k, j, i, callback);
-                            }
-                        }
-
-                    }
-                }
-            }
-        },
-
-        _doSuperCellCallback: function(cells, x, y, z, callback){
-            var cell = cells[x][y][z];
-            if (z%2 != 0) cell = cells[y][x][z];
-            if (!cell) {
-                callback(null, x, y, z);
-                return {x:0,y:0};
-            }
-            var superCell = cell.superCell;
-            callback(superCell, x, y, z);
-            if (z%2 != 0) return {x:0, y:superCell.getLength()};
-            return {x:superCell.getLength(), y:0};
-        },
+//        _rasterGikCells: function(order, callback, var1, var2, var3, cells){
+//            for (var i=this._getRasterLoopInit(var1);this._getRasterLoopCondition(i,var1);i+=this._getRasterLoopIterator(var1)){
+//                for (var j=this._getRasterLoopInit(var2);this._getRasterLoopCondition(j,var2);j+=this._getRasterLoopIterator(var2)){
+//                    for (var k=this._getRasterLoopInit(var3);this._getRasterLoopCondition(k,var3);k+=this._getRasterLoopIterator(var3)){
+//                        var numToSkip = {x:0,y:0};
+//                        if (var1.order == 0){
+//                            if (var2.order == 1) numToSkip = this._doSuperCellCallback(cells, i, j, k, callback);
+//                            else if (var2.order == 2) numToSkip = this._doSuperCellCallback(cells, i, k, j, callback);
+//                        } else if (var1.order == 1){
+//                            if (var2.order == 0) numToSkip = this._doSuperCellCallback(cells, j, i, k, callback);
+//                            else if (var2.order == 2) numToSkip = this._doSuperCellCallback(cells, k, i, j, callback);
+//                        } else {
+//                            if (var2.order == 0) {
+//                                numToSkip = this._doSuperCellCallback(cells, j, k, i, callback);
+//                            }
+//                            else if (var2.order == 1) {
+//                                numToSkip = this._doSuperCellCallback(cells, k, j, i, callback);
+//                            }
+//                        }
+//
+//                    }
+//                }
+//            }
+//        },
+//
+//        _doSuperCellCallback: function(cells, x, y, z, callback){
+//            var cell = cells[x][y][z];
+//            if (z%2 != 0) cell = cells[y][x][z];
+//            if (!cell) {
+//                callback(null, x, y, z);
+//                return {x:0,y:0};
+//            }
+//            var superCell = cell.superCell;
+//            callback(superCell, x, y, z);
+//            if (z%2 != 0) return {x:0, y:superCell.getLength()};
+//            return {x:superCell.getLength(), y:0};
+//        },
 
         _undo: function(){//remove all the mixins, this will help with debugging later
             var self = this;
diff --git a/js/menus/CamMenuView.js b/js/menus/CamMenuView.js
index 88023eb2af3fb03b041ed6179bcd769543f354a3..2d3ba1ee78f297a9c4cc6094ae29801e60e8955a 100644
--- a/js/menus/CamMenuView.js
+++ b/js/menus/CamMenuView.js
@@ -77,6 +77,7 @@ CamMenuView = Backbone.View.extend({
             <% if (!(machineName == "handOfGod")){ %>\
             <br/><a id="manualSelectOrigin" class=" btn btn-lg btn-default btn-imageCustom<% if (manualSelectOrigin){ %> btn-selected<% } %>"><img src="assets/imgs/cursor.png"></a>\
             <label>&nbsp;&nbsp;&nbsp;Manually select origin from existing cell</label><br/><br/>\
+            <% if (!assembler.stockAttachedToEndEffector){ %>\
             Stock (xyz): &nbsp;&nbsp;<input data-property="stockPosition" data-key="x" value="<%= stockPosition.x %>" placeholder="X" class="form-control floatInput assembler" type="text">\
             &nbsp;<input data-property="stockPosition" data-key="y" value="<%= stockPosition.y %>" placeholder="Y" class="form-control floatInput assembler" type="text">\
             &nbsp;<input data-property="stockPosition" data-key="z" value="<%= stockPosition.z %>" placeholder="Z" class="form-control floatInput assembler" type="text"><br/>\
@@ -97,6 +98,7 @@ CamMenuView = Backbone.View.extend({
                 &nbsp;<input data-property="stockArraySize" data-key="y" value="<%= stockArraySize.y %>" placeholder="Y" class="form-control intInput assembler" type="text"><br/><br/>\
                 Stock separation: &nbsp;&nbsp;<input data-property="stockSeparation" value="<%= stockSeparation %>" placeholder="X" class="form-control floatInput assembler" type="text"><br/><br/>\
             <% } %>\
+            <% } %>\
             Clearance Height: &nbsp;&nbsp;<input data-property="rapidHeight" value="<%= rapidHeight %>" placeholder="Z" class="form-control floatInput assembler" type="text"><br/>\
             <label class="checkbox" for="rapidPosRel">\
             <input id="rapidPosRel" data-property="rapidHeightRelative" type="checkbox" <% if (rapidHeightRelative){ %> checked="checked"<% } %> value="" data-toggle="checkbox" class="assembler custom-checkbox">\
diff --git a/js/models/AllAppPLists.js b/js/models/AllAppPLists.js
index fbccb975343252a20e1e77b56800d449d21a25a7..dca4e835cc463aafb2edcb197a2d78c150143d3c 100644
--- a/js/models/AllAppPLists.js
+++ b/js/models/AllAppPLists.js
@@ -172,7 +172,9 @@ function AppPList(){
         oneBitBot:{
             gcode: "G-Code",
             tinyG: "TinyG"
-        }
+        },
+        stapler: {gcode: "G-Code"},
+        staplerDual: {gcode: "G-Code"}
     },
 
     allScripts: {