diff --git a/src/com/t_oster/liblasercut/drivers/MPC6515Cutter.java b/src/com/t_oster/liblasercut/drivers/MPC6515Cutter.java
index 080235c86bad602dcdd3dd3a9a219f249a3b0b6d..362671ed2e9284cf2e61d9d55dc6f43f7d7aac7d 100644
--- a/src/com/t_oster/liblasercut/drivers/MPC6515Cutter.java
+++ b/src/com/t_oster/liblasercut/drivers/MPC6515Cutter.java
@@ -3,22 +3,47 @@
  * Copyright (C) 2011 - 2013 Thomas Oster <thomas.oster@rwth-aachen.de>
  * RWTH Aachen University - 52062 Aachen, Germany
  *
- * LibLaserCut is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
+ *     LibLaserCut is free software: you can redistribute it and/or modify
+ *     it under the terms of the GNU Lesser General Public License as published by
+ *     the Free Software Foundation, either version 3 of the License, or
+ *     (at your option) any later version.
  *
- * LibLaserCut is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with LibLaserCut. If not, see <http://www.gnu.org/licenses/>.
+ *     LibLaserCut is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU Lesser General Public License for more details.
  *
+ *     You should have received a copy of the GNU Lesser General Public License
+ *     along with LibLaserCut.  If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+/*
+ * TODO:
+ * - check if x and/or y coordinates must be flipped
+ * - after the previous point, make sure that the bounding boxes correspond to the new coordinates
+ * - the origin is wrong! How does it relate to setting the machines origin?
+ * - VERIFY: allow speed change at any time
+ * - VERIFY: allow power setting change at any time
+ * - VERIFY: additional parameter for "corner power"
+ * - remove unused functions
+ * - rename remaining functions if generic
+ * - option for MOL filename
+ * - connect to the USB uploader (option for executable path)
+ * - read settings from machine and update configuration
+ * - machine photo
+ * - line offset for cutting!
+ * - what is the use of the USB camera option?
+ * - part distribution
+ * - optional machine margin
+ * - optional preferred material position
+ * - test for Z control, z endstop?
+ * - test remaining parameters
+ * - convert position information to integer format throughout to keep 100% precision in relative movements
  */
+
 package com.t_oster.liblasercut.drivers;
 
+import com.apple.crypto.provider.Debug;
 import com.t_oster.liblasercut.IllegalJobException;
 import com.t_oster.liblasercut.JobPart;
 import com.t_oster.liblasercut.LaserCutter;
@@ -28,9 +53,11 @@ import com.t_oster.liblasercut.ProgressListener;
 import com.t_oster.liblasercut.Raster3dPart;
 import com.t_oster.liblasercut.RasterPart;
 import com.t_oster.liblasercut.VectorCommand;
+import static com.t_oster.liblasercut.VectorCommand.CmdType.LINETO;
+import static com.t_oster.liblasercut.VectorCommand.CmdType.MOVETO;
+import static com.t_oster.liblasercut.VectorCommand.CmdType.SETPROPERTY;
 import com.t_oster.liblasercut.VectorPart;
-import java.io.BufferedOutputStream;
-import java.io.ByteArrayOutputStream;
+import com.t_oster.liblasercut.platform.Util;
 import java.io.File;
 import java.io.IOException;
 import java.io.RandomAccessFile;
@@ -44,20 +71,33 @@ import java.util.List;
 public class MPC6515Cutter extends LaserCutter
 {
 
-  private static Double[] SUPPORTED_RESOLUTIONS = new Double[]
-  {
-    200d, 500d, 1000d
-  };
+  private static Double[] SUPPORTED_RESOLUTIONS = new Double[]{200d,500d,1000d};
   private static final String BED_WIDTH = "bed width";
   private static final String BED_HEIGHT = "bed height";
-  private static String[] PROPERTIES = new String[]
-  {
+  private static final String CORNER_POWER_FACTOR = "corner power factor";
+  private static String[] PROPERTIES = new String[]{
     BED_WIDTH,
     BED_HEIGHT,
+    CORNER_POWER_FACTOR,
   };
-  private double bedWidth = 300;
-  private double bedHeight = 210;
+ 
+  private double bedWidth = 900;
+  private double bedHeight = 600;
+  private double cornerPowerFactor = 0.8;
 
+  private double currentPower = 40;
+  private double currentSpeed = 80;
+  
+  private double firstX = 0.0, firstY = 0.0, prevX = 0.0, prevY = 0.0;
+  private double bboxMinX = 0.0, bboxMinY = 0.0, bboxMaxX = 0.0, bboxMaxY = 0.0, bboxWidth, bboxHeight;
+  boolean firstVector;
+  
+  private int motionBlockStart = -1;
+  private int motionBlockSize;
+  private int nMotionBlocks;
+  private int nMoveRelative;
+  
+  
   @Override
   public double getBedWidth()
   {
@@ -80,90 +120,260 @@ public class MPC6515Cutter extends LaserCutter
     this.bedHeight = bedHeight;
   }
 
-  private void molWriteHeader(RandomAccessFile out) throws IOException
+  private void molCmdBeginMotionBlock(RandomAccessFile out) throws IOException
   {
-    out.seek(0);
-    // 0: Size of entire file in bytes (must be patched later)
-    out.writeInt(Integer.reverseBytes(0x00000000));
-    // 4: Unknown, fixed value
-    out.writeInt(Integer.reverseBytes(0x00000022));
-    // 8: Unknown, fixed value
-    out.write(0x02);
-    // 9: Unknown, fixed value
-    out.write(0x02);
-    // a: Unknown, fixed value
-    out.write(0x01);
-    // b: Unknown, fixed value
-    out.write(0x04);
-    // c: Unknown, fixed value
-    out.writeInt(Integer.reverseBytes(0x00000001));
-    // 10: This word changes when the size of the file changes, i.e. when lines are added
-    // This line corresponds to the number of "move relative" commands in the entire file counting
-    // "unknown 07" and "unknown 09" as well. Is that coincidence? What would this value be good for?
-    out.writeInt(Integer.reverseBytes(0x00000000));
-    // 14: Unknown, fixed value
-    out.writeInt(Integer.reverseBytes(0x00000001));
-    // 18: Unknown, fixed value
-    out.writeInt(Integer.reverseBytes(0x00000000));
-    // 1c: Unknown, fixed value
-    out.writeInt(Integer.reverseBytes(0x00000000));
-    // 20: Describing the stepper resolution in x and y
-    out.writeInt(Integer.reverseBytes(-20833));
-    out.writeInt(Integer.reverseBytes(-20833));
-    // 28: Unknown, fixed value
-    out.writeInt(Integer.reverseBytes(0x00481095));
-    // 2c: Unknown, fixed value
-    out.writeInt(Integer.reverseBytes(0x471a0000));
-    // Unknown bunch of zeros, likely reserved for later use
-    out.seek(0x00000070);
-    // 70: Unknown, fixed value
-    out.writeInt(Integer.reverseBytes(1));
-    // 74: Unknown, fixed value
-    out.writeInt(Integer.reverseBytes(2));
-    // 78: Unknown, fixed value, maybe the number of blocks in this file?
-    out.writeInt(Integer.reverseBytes(3));
-    // 7c: Unknown, fixed value
-    out.writeInt(Integer.reverseBytes(5));
+    molWriteBytes(out, 0x46, 0x09, 0x00, 0x80);
+    molWriteInt(out, -1);  // number of words in motion block
+    motionBlockStart = (int)out.getChannel().position();
+    motionBlockSize = 0;
+    nMotionBlocks++;
+  }
+
+  private void molCmdEndMotionBlock(RandomAccessFile out) throws IOException
+  {
+    int n = (int) out.getChannel().position();
+    out.seek(motionBlockStart-8);
+    molCmd(out, 0x46, 0x09, 0x00, 0x80,  (n-motionBlockStart)/4);
+    out.seek(n);    
+  }
+  
+  private boolean molInMotionBlock()
+  {
+    return (motionBlockStart!=-1);
+  }
+
+  private void molCmdTestMotionBlock(RandomAccessFile out, int nWords) throws IOException
+  {
+    if (motionBlockSize + nWords >= 512) {
+      molCmdEndMotionBlock(out);
+      molCmdBeginMotionBlock(out);
+    }
+    motionBlockSize += nWords;
+  }
+  
+  private void molCmdLaserOn(RandomAccessFile out) throws IOException
+  {
+    molCmdTestMotionBlock(out, 2);
+    molWriteBytes(out, 0x06, 0x06, 0x00, 0x01);
+    molWriteInt(out, 1);
+  }
+
+  private void molCmdLaserOff(RandomAccessFile out) throws IOException
+  {
+    molCmdTestMotionBlock(out, 2);
+    molWriteBytes(out, 0x06, 0x06, 0x00, 0x01);
+    molWriteInt(out, 0);
+  }
+  
+  private void molCmdBlowerOn(RandomAccessFile out) throws IOException
+  {
+    molCmdTestMotionBlock(out, 2);
+    molWriteBytes(out, 0x06, 0x0b, 0x00, 0x01);
+    molWriteBytes(out, 0x01, 0x02, 0x00, 0x00);
+  }
+
+  private void molCmdBlowerOff(RandomAccessFile out) throws IOException
+  {
+    molCmdTestMotionBlock(out, 2);
+    molWriteBytes(out, 0x06, 0x0b, 0x00, 0x01);
+    molWriteBytes(out, 0x00, 0x02, 0x00, 0x00);
+  }
+  
+  private void molCmdAccelerate(RandomAccessFile out) throws IOException
+  {
+    molCmdTestMotionBlock(out, 2);
+    molWriteBytes(out, 0x01, 0x46, 0x00, 0x01);
+    molWriteInt(out, 1);
+  }
+
+  private void molCmdDecelerate(RandomAccessFile out) throws IOException
+  {
+    molCmdTestMotionBlock(out, 2);
+    molWriteBytes(out, 0x01, 0x46, 0x00, 0x01);
+    molWriteInt(out, 2);
   }
 
+  private void molCmdBeginSubroutine(RandomAccessFile out, int n) throws IOException
+  {
+    molWriteBytes(out, 0x48, 0x00, 0x30, 0x01);
+    molWriteInt(out, n);
+  }
+
+  private void molCmdEndSubroutine(RandomAccessFile out, int n) throws IOException
+  {
+    molWriteBytes(out, 0x48, 0x00, 0x40, 0x01);
+    molWriteInt(out, n);
+  }
+
+  private void molCmdSetSpeeds(RandomAccessFile out, double aMin, double aMax, double aAccel) throws IOException
+  {
+    molCmdTestMotionBlock(out, 4);
+    molWriteBytes(out, 0x01, 0x03, 0x00, 0x03);
+    molWriteFloat(out, (float)aMin);
+    molWriteFloat(out, (float)aMax);
+    molWriteFloat(out, (float)aAccel);
+  }
+  
+  private void molCmdMoveRelative(RandomAccessFile out, int dx, int dy) throws IOException
+  {
+    molCmdTestMotionBlock(out, 4);
+    molWriteBytes(out, 0x00, 0x60, 0x02, 0x03);
+    molWriteBytes(out, 0x04, 0x03, 0x00, 0x00); // x and y axis
+    molWriteInt(out, dx);
+    molWriteInt(out, dy);
+    nMoveRelative++;
+  }
+  
   private void molWriteFloat(RandomAccessFile out, float v) throws IOException
   {
     // LEETRO float: [eeeeeeee|smmmmmmm|mmmmmmm0|00000000]
     //     IEEE 754: [seeeeeee|emmmmmmm|mmmmmmmm|mmmmmmmm]
     int i = Float.floatToRawIntBits(v);
-
-    int ieeeMantissa = (i & 0x7fffff);
-    int ieeeExponent = ((i >> 23) & 0xff);
-    int ieeeSign = ((i >> 31) & 1);
-
+    
+    int ieeeMantissa = ( i & 0x7fffff );
+    int ieeeExponent = ( (i>>23) & 0xff );
+    int ieeeSign     = ( (i>>31) & 1 );
+    
     int c30Mantissa = ieeeMantissa;
-    int c30Exponent = (ieeeExponent == 0) ? -128 : ieeeExponent - 127;
+    int c30Exponent = (ieeeExponent==0) ? -128 : ieeeExponent - 127;
     int c30Sign = ieeeSign; // ??? float = -float
-
+    
     i = (c30Mantissa & 0x7fffff) | ((c30Sign & 1) << 23) | ((c30Exponent & 0xff) << 24);
-
+    
     out.writeInt(Integer.reverseBytes(i));
   }
 
+  private void molWritePercent(RandomAccessFile out, float v) throws IOException
+  {
+    molWriteFloat(out, v*208.33f);
+  }
+
+  private void molWriteInt(RandomAccessFile out, int a) throws IOException
+  {
+    out.writeInt(Integer.reverseBytes(a));
+  }
+
+  private void molWriteMm(RandomAccessFile out, float v) throws IOException
+  {
+    molWriteInt(out, (int)(v*208.33f));
+  }
+
+  private void molWriteBytes(RandomAccessFile out, int arg0, int arg1, int arg2, int arg3) throws IOException
+  {
+    out.write(arg0); out.write(arg1); out.write(arg2); out.write(arg3);
+  }
+
+  // unkonwn command
+  private void molCmd(RandomAccessFile out, int maj, int min, int fill, int n, int arg0, int arg1) throws IOException
+  {
+    out.write(maj); out.write(min); out.write(fill); out.write(n);
+    out.writeInt(Integer.reverseBytes(arg0));
+    out.writeInt(Integer.reverseBytes(arg1));
+  }
+
+  // unkonwn command
+  private void molCmd(RandomAccessFile out, int maj, int min, int fill, int n, int arg0, int arg1, float arg2, float arg3, float arg4, float arg5, float arg6) throws IOException
+  {
+    out.write(maj); out.write(min); out.write(fill); out.write(n);
+    out.writeInt(Integer.reverseBytes(arg0));
+    out.writeInt(Integer.reverseBytes(arg1));
+    molWriteFloat(out, arg2);
+    molWriteFloat(out, arg3);
+    molWriteFloat(out, arg4);
+    molWriteFloat(out, arg5);
+    molWriteFloat(out, arg6);
+  }
+
+  // unkonwn command
+  private void molCmd(RandomAccessFile out, int maj, int min, int fill, int n, int arg0) throws IOException
+  {
+    out.write(maj); out.write(min); out.write(fill); out.write(n);
+    out.writeInt(Integer.reverseBytes(arg0));
+  }
+
+  // unkonwn command
+  private void molCmd(RandomAccessFile out, int maj, int min, int fill, int n, float arg0, float arg1, float arg2, float arg3, int arg4) throws IOException
+  {
+    out.write(maj); out.write(min); out.write(fill); out.write(n);
+    molWriteFloat(out, arg0);
+    molWriteFloat(out, arg1);
+    molWriteFloat(out, arg2);
+    molWriteFloat(out, arg3);
+    out.writeInt(Integer.reverseBytes(arg4));
+  }
+
+  // unkonwn command
+  private void molCmd(RandomAccessFile out, int maj, int min, int fill, int n, float arg0, float arg1, float arg2) throws IOException
+  {
+    out.write(maj); out.write(min); out.write(fill); out.write(n);
+    molWriteFloat(out, arg0);
+    molWriteFloat(out, arg1);
+    molWriteFloat(out, arg2);
+  }
+
+  // unkonwn command
+  private void molCmd(RandomAccessFile out, int maj, int min, int fill, int n, int arg0, float arg1, float arg2) throws IOException
+  {
+    out.write(maj); out.write(min); out.write(fill); out.write(n);
+    out.writeInt(Integer.reverseBytes(arg0));
+    molWriteFloat(out, arg1);
+    molWriteFloat(out, arg2);
+  }
+
+  // unkonwn command
+  private void molCmd(RandomAccessFile out, int maj, int min, int fill, int n, float arg0, float arg1, float arg2, float arg3, float arg4, float arg5, int arg6) throws IOException
+  {
+    out.write(maj); out.write(min); out.write(fill); out.write(n);
+    molWriteFloat(out, arg0);
+    molWriteFloat(out, arg1);
+    molWriteFloat(out, arg2);
+    molWriteFloat(out, arg3);
+    molWriteFloat(out, arg4);
+    molWriteFloat(out, arg5);
+    out.writeInt(Integer.reverseBytes(arg6));
+  }
+
+  private void molSetSpeed(RandomAccessFile out, float a, float b, float c) throws IOException
+  {
+    molCmd(out, 0x01, 0x03, 0x00, 0x03,  a, b, c);
+  }
+  
+  private void molMoveRelative(RandomAccessFile out, int a, float b, float c) throws IOException
+  {
+    molCmd(out, 0x00, 0x60, 0x02, 0x03,  a, b, c);
+  }
+  
+  // unkonwn command 00
+  private void molCmd00(RandomAccessFile out, int a, float b, float c) throws IOException
+  {
+    out.write(0x48); out.write(0x00); out.write(0x50); out.write(0x80);
+    out.writeInt(Integer.reverseBytes(3));
+    out.writeInt(Integer.reverseBytes(a));
+    molWriteFloat(out, b);
+    molWriteFloat(out, c);
+  }
+  
+  // unkonwn command 00
+  private void molCmd00(RandomAccessFile out, int a) throws IOException
+  {
+    out.write(0x48); out.write(0x00); out.write(0x50); out.write(0x80);
+    out.writeInt(Integer.reverseBytes(1));
+    out.writeInt(Integer.reverseBytes(a));
+  }
+  
   // unkonwn command 01
   private void molCmd01(RandomAccessFile out, int a, float b) throws IOException
   {
-    out.write(8);
-    out.write(1);
-    out.write(0x60);
-    out.write(0x80);
+    out.write(0x48); out.write(1); out.write(0x60); out.write(0x80);
     out.writeInt(Integer.reverseBytes(2));
     out.writeInt(Integer.reverseBytes(a));
     molWriteFloat(out, b);
   }
-
+  
   // unkonwn command 01
   private void molCmd01(RandomAccessFile out, int a, float b, float c, float d, float e, float f) throws IOException
   {
-    out.write(8);
-    out.write(1);
-    out.write(0x60);
-    out.write(0x80);
+    out.write(0x48); out.write(1); out.write(0x60); out.write(0x80);
     out.writeInt(Integer.reverseBytes(6));
     out.writeInt(Integer.reverseBytes(a));
     molWriteFloat(out, b);
@@ -172,207 +382,585 @@ public class MPC6515Cutter extends LaserCutter
     molWriteFloat(out, e);
     molWriteFloat(out, f);
   }
-
+  
+  // unkonwn command 03
+  private void molCmd03(RandomAccessFile out, float a, float b, float c) throws IOException
+  {
+    out.write(0x41); out.write(0x03); out.write(0x00); out.write(3);
+    molWriteFloat(out, a);
+    molWriteFloat(out, b);
+    molWriteFloat(out, c);
+  }
+  
   // unkonwn command 05
   private void molCmd05(RandomAccessFile out) throws IOException
   {
-    out.write(8);
-    out.write(5);
-    out.write(0x20);
-    out.write(0);
+    out.write(0x48); out.write(5); out.write(0x20); out.write(0);
   }
-
+  
+  // unkonwn command 06
+  private void molCmd06(RandomAccessFile out) throws IOException
+  {
+    out.write(0x48); out.write(6); out.write(0x20); out.write(0);
+  }
+  
   // unkonwn command 07
   private void molCmd07(RandomAccessFile out) throws IOException
   {
-    out.write(8);
-    out.write(7);
-    out.write(0x20);
-    out.write(0);
+    out.write(0x48); out.write(7); out.write(0x20); out.write(0);
   }
-
+  
   // unkonwn command 08
   private void molCmd08(RandomAccessFile out) throws IOException
   {
-    out.write(8);
-    out.write(8);
-    out.write(0x20);
-    out.write(0);
+    out.write(0x48); out.write(8); out.write(0x20); out.write(0);
   }
-
+  
+  // unkonwn command 09
+  private void molCmd09(RandomAccessFile out, int a) throws IOException
+  {
+    out.write(0x48); out.write(0x09); out.write(0x20); out.write(1);
+    out.writeInt(Integer.reverseBytes(a));
+  }
+  
+  // unkonwn command 0d
+  private void molCmd0d(RandomAccessFile out, int a) throws IOException
+  {
+    out.write(0x46); out.write(0x0d); out.write(0x00); out.write(1);
+    out.writeInt(Integer.reverseBytes(a));
+  }
+  
   // unkonwn command 0e
   private void molCmd0e(RandomAccessFile out, float a, float b, float c) throws IOException
   {
-    out.write(6);
-    out.write(0x0e);
-    out.write(0);
-    out.write(3);
+    out.write(0x46); out.write(0x0e); out.write(0); out.write(3);
     molWriteFloat(out, a);
     molWriteFloat(out, b);
     molWriteFloat(out, c);
   }
+  
+  // unkonwn command 60
+  private void molCmd60(RandomAccessFile out, int a, float b, float c) throws IOException
+  {
+    out.write(0x40); out.write(0x60); out.write(0x04); out.write(3);
+    out.writeInt(Integer.reverseBytes(a));
+    molWriteFloat(out, b);
+    molWriteFloat(out, c);
+  }
+  
+  // unkonwn command 60
+  private void molCmd60_2(RandomAccessFile out, int a, float b, float c) throws IOException
+  {
+    out.write(0x40); out.write(0x60); out.write(0x02); out.write(3);
+    out.writeInt(Integer.reverseBytes(a));
+    molWriteFloat(out, b);
+    molWriteFloat(out, c);
+  }
+    
+  // molMoveRel(out, 5.0f, 200.0f, 5.0f, 700.0f, -100.0f, 0.0f);
+  private void molMoveRel(RandomAccessFile out, double startSpeed, double maxSpeed, double endSpeed, double accel, double dx, double dy)
+     throws IOException
+  {
+    double lenRampUp   = 0.5 * (maxSpeed-startSpeed) * (maxSpeed+startSpeed) / accel;
+    double lenRampDown = 0.5 * (maxSpeed-endSpeed)   * (maxSpeed+endSpeed)   / accel;
+    double len = Math.sqrt(dx*dx+dy*dy);
+    double lenConst = len - lenRampUp - lenRampDown;
+    
+    if (len<1.0)
+      return;
+    
+    if (lenConst>=1.0) {
+      lenRampUp = lenRampUp / len;
+      lenConst = lenConst / len;
+      lenRampDown = lenRampDown /len;
+      molCmdAccelerate(out);
+      molCmdSetSpeeds(out, startSpeed, maxSpeed, accel);
+      molCmdMoveRelative(out, (int)(dx*lenRampUp), (int)(dy*lenRampUp));
+      molCmdSetSpeeds(out, maxSpeed, maxSpeed, accel);
+      molCmdMoveRelative(out, (int)(dx - dx*lenRampUp - dx*lenRampDown), (int)(dy - dy*lenRampUp - dy*lenRampDown));
+      molCmdDecelerate(out);
+      molCmdSetSpeeds(out, endSpeed, maxSpeed, accel);
+      molCmdMoveRelative(out, (int)(dx*lenRampDown), (int)(dy*lenRampDown));
+    } else {
+      double scale = (lenRampUp+lenConst/2.0) / lenRampUp;
+      lenRampUp   =   (lenRampUp+lenConst/2.0) / len;
+      lenRampDown = (lenRampDown+lenConst/2.0) / len;
+      maxSpeed = (maxSpeed-startSpeed)*scale + startSpeed;
 
-  private void molWriteConfig(RandomAccessFile out) throws IOException
-  {
-    //The configuration chunk still has a bunch of unknown commands, few of them seem to change
-    //for a single machine configuration.  
-    out.seek(0x200);
-
-    // 200: Unknown, fixed value
-    molCmd05(out);
-    // 204: Unknown, fixed value, the default driver for the X-axis is #4 (maybe related?)
-    molCmd01(out, 4, 4.0f);
-    // 214: Unknown, fixed value, the default driver for the Y-axis is #3 (maybe related?)
-    molCmd01(out, 3, 3.0f);
-    // 224: Unknown, fixed value
-    molCmd08(out);
-    // 228: Unknown, fixed value
-    molCmd07(out);
-    // 22c: Unknown
-    // arg1 is unknown, but repeats in 'unknown 11'
-    // arg2 is the start speed for all head movements as describen in the settings
-    // arg3 is the maximum speed for moving around "quickly"
-    // arg4 is the acceleration value to get to the above speed (space acc)
-    // arg5 is the value for acceleration from the settings
-    // arg6 is unknown and nowhere to be found, probably the slow acceleration default
-    molCmd01(out, 603, 5.0f, 200.0f, 700.0f, 500.0f, 350.0f);
-    // 24c: Set the Stepper sizes
-    // arg1 is the number of steps required in X direction
-    // arg2 is the same for Y
-    // arg3 is likely the same in Z direction
-    molCmd0e(out, 208.333f, 208.333f, 800.0f);
-    /*
-     Unknown, fixed value, maybe explicitly switching the laser off?
-     0000025c: : unknown 06:  0
-
-     Object origin. Cutting a 100x100 object on a 900x600 table would move the laser head
-     to the top right corner of a centered work piece. (772 see "move rel")
-     00000264: : unknown 07: 772, x:500.005mm, y:350.002mm
-
-     Motion parameters:
-     arg1 is the initial speed
-     arg2 is the maximum speed 
-     arg3 is the acceleration
-     00000274: : unknown 08 a:1041(5%), b:41666(200%), c:145833(700%)
-
-     Object size. Our test object is 100x100, so this command moves to the bottom left corner.
-     00000284: : unknown 09: 772, x:-100mm, y:-100mm
-
-     Unknown, fixed value
-     00000294: : unknown 10:  3, 2.000000, 2.000000
-
-     Unknown, fixed value, 603 also appears at 0x0000022c
-     000002a8: : unknown 11:  603
-
-     Unknown, fixed value
-     000002b4: : unknown 12
-
-     */
-  }
-
-  private void molFixHeader(RandomAccessFile out) throws IOException
-  {
-    // Size of entire file in bytes (must be patched later)
+      if (Math.abs(dx*lenRampUp)>=1.0||Math.abs(dy*lenRampUp)>1.0) {
+        molCmdAccelerate(out);
+        molCmdSetSpeeds(out, startSpeed, maxSpeed, accel);
+        molCmdMoveRelative(out, (int)(dx*lenRampUp), (int)(dy*lenRampUp));
+      }
+      if (Math.abs(dx*lenRampDown)>=1.0||Math.abs(dy*lenRampDown)>=1.0) {
+        molCmdDecelerate(out);
+        molCmdSetSpeeds(out, endSpeed, maxSpeed, accel);
+        molCmdMoveRelative(out, (int)(dx*lenRampDown), (int)(dy*lenRampDown));
+      }
+    }    
+  }
+
+  private void molSetPowerAndSpeed(RandomAccessFile out, double cornerPower, double maxPower, double startSpeed, double maxSpeed) throws IOException
+  {
+  // Laser Power
+    molWriteBytes(out, 0x46, 0x0e, 0x00, 0x05);
+    molWriteInt(out, (int)(cornerPower*100));  // (40.000000%) corner power
+    molWriteInt(out, (int)(maxPower*100));  // (40.000000%) maximum power
+    molWriteFloat(out, (float)(startSpeed*208.33)); // (5%) cutting start speed
+    molWriteFloat(out, (float)(maxSpeed*208.33)); // (100%) maximum cutting speed
+    molWriteInt(out, 0);  // unknown
+  // Laser Power Long
+    molWriteBytes(out, 0x46, 0x0e, 0x00, 0x07);
+    molWriteInt(out, (int)(cornerPower*100));  // (40.000000%) corner power
+    molWriteInt(out, (int)(maxPower*100));  // (40.000000%) maximum power
+    molWriteInt(out, (int)(cornerPower*100));  // (40.000000%) corner power (second head?)
+    molWriteInt(out, (int)(maxPower*100));  // (40.000000%) maximum power (second head?)
+    molWriteFloat(out, (float)(startSpeed*208.33)); // (5%) cutting start speed
+    molWriteFloat(out, (float)(maxSpeed*208.33)); // (100%) maximum cutting speed
+    molWriteInt(out, 0);  // unknown
+  }
+  
+  private void molChangePowerAndSpeed(RandomAccessFile out, double cornerPower, double maxPower, double startSpeed, double maxSpeed) throws IOException
+  {
+    boolean inBlock = molInMotionBlock();
+    if (inBlock) {
+      molCmdLaserOff(out);
+      molCmdBlowerOff(out);
+      molCmdEndMotionBlock(out);
+    }
+    molSetPowerAndSpeed(out, cornerPower, maxPower, startSpeed, maxSpeed);
+    if (inBlock) {
+      molCmdBeginMotionBlock(out);
+    }
+  }
+
+  // 
+  // .MOL file header
+  // 
+  private void molWriteBlock0000(RandomAccessFile out) throws IOException
+  {
+    nMotionBlocks = 0;
+    nMoveRelative = 0;
+    
     out.seek(0x00000000);
-    out.writeInt(Integer.reverseBytes((int) out.length()));
-    // 10: This word changes when the size of the file changes, i.e. when lines are added
-    // This line corresponds to the number of "move relative" commands in the entire file counting
-    // "unknown 07" and "unknown 09" as well. Is that coincidence? What would this value be good for?
-    out.seek(0x00000010);
-    out.writeInt(Integer.reverseBytes(0x00000000/*FIXME*/));
+    molWriteInt(out, 0x00001000);  // 0000: file size in bytes
+    molWriteInt(out, 34);  // 0004: ?
+    molWriteBytes(out, 0x02, 0x02, 0x01, 0x04);  // 0008: ?
+    molWriteInt(out, 1);  // 000c: ?
+    //molWriteInt(out, 41);  // 0010: somehow related to the file size or the number of commands
+    molWriteInt(out, 2000);  // 0010: somehow related to the file size or the number of commands
+    molWriteInt(out, 0x00000101);  // 0014: ? also 257 (bitfield?) -> user origin is top right!
+    //molWriteInt(out, 0x00000001);  // 0014: ? also 257 (bitfield?) -> fixed origin
+    // 201, 401, 801, 100, 102: top right relative: no change
+    // 001, (somewhat) center relative
+    
+    molWriteInt(out, (int)(100*-208.33));  // 0018: ? (no change)
+    molWriteInt(out, (int)(100*-208.33));  // 001c: ?
+    molWriteInt(out, (int)(bboxWidth*-208.33));   // 0020: artwork width in steps
+    molWriteInt(out, (int)(bboxHeight*-208.33));  // 0024: artwork height in steps
+    molWriteInt(out, 0x00481095);  // 0028: ?
+    molWriteInt(out, 0x471a0000);  // 002c: ?
+    molWriteInt(out, 0);  // 0030: 0
+    molWriteInt(out, 0);  // 0034: 0
+    molWriteInt(out, 0);  // 0038: 0
+    molWriteInt(out, 0);  // 003c: 0
+    molWriteInt(out, 0);  // 0040: 0
+    molWriteInt(out, 0);  // 0044: 0
+    molWriteInt(out, 0);  // 0048: 0
+    molWriteInt(out, 0);  // 004c: 0
+    molWriteInt(out, 0);  // 0050: 0
+    molWriteInt(out, 0);  // 0054: 0
+    molWriteInt(out, 0);  // 0058: 0
+    molWriteInt(out, 0);  // 005c: 0
+    molWriteInt(out, 0);  // 0060: 0
+    molWriteInt(out, 0);  // 0064: 0
+    molWriteInt(out, 0);  // 0068: 0
+    molWriteInt(out, 0);  // 006c: 0
+    molWriteInt(out, 1);  // 0070: block number of 200 block (home position and start vector)
+    molWriteInt(out, 2);  // 0074: block number of 400 block (test outline)
+    molWriteInt(out, 3);  // 0078: block number of 600 block (cut outline)
+    molWriteInt(out, 5);  // 007c: block number of A00 block (cut artwork)
+  }
+
+  // 
+  // .MOL file fixup
+  // 
+  private void molFixBlock0000(RandomAccessFile out) throws IOException
+  {
+    // align file to the next 512 byte boundary for easy USB transfer
+    int len = (int)out.length();
+    int blockLen = (len+511)&0xfffffe00;
+    if (len<blockLen) {
+      out.seek(blockLen-4);
+      molWriteInt(out, 0);
+    }
+    out.seek(0);
+    molWriteInt(out, blockLen);
+    out.seek(4);
+    molWriteInt(out, nMotionBlocks + 30); // 0004: ???? seems to loosely correspond
+    out.seek(0x0010);
+    molWriteInt(out, nMoveRelative); // 0010: ???? seems to loosely correspond
+    // FIXME: we must also fixup the movement counter in 0x00000010!
+  }
+
+  // 
+  // .MOL file data block at 0x00000200
+  // 
+  private void molWriteBlock0200(RandomAccessFile out) throws IOException
+  {
+    out.seek(0x00000200);
+  // 0200: Unknown Command 1
+    molWriteBytes(out, 0x48, 0x05, 0x20, 0x00);
+  // 0204: Unknown Command 2
+    molWriteBytes(out, 0x48, 0x01, 0x60, 0x80);
+    molWriteInt(out, 2);  // Length = 2 words
+    molWriteInt(out, 4);
+    molWriteFloat(out, 4f);
+  // 0214: Unknown Command 2
+    molWriteBytes(out, 0x48, 0x01, 0x60, 0x80);
+    molWriteInt(out, 2);  // Length = 2 words
+    molWriteInt(out, 3);
+    molWriteFloat(out, 3f);
+  // 0224: Unknown Command 3
+    molWriteBytes(out, 0x48, 0x08, 0x20, 0x00);
+  // 0228: Unknown Command 4
+    molWriteBytes(out, 0x48, 0x07, 0x20, 0x00);
+  // 022c: Unknown Command 2
+    molWriteBytes(out, 0x48, 0x01, 0x60, 0x80);
+    molWriteInt(out, 6);  // Length = 6 words
+    molWriteInt(out, 603);
+    molWriteFloat(out, 1041f); // (5%) start speed for all head movements
+    molWriteFloat(out, 41666f); // (200%) maximum speed for moving around quickly
+    molWriteFloat(out, 145833f); // (700%) acceleration value to get to the above speed
+    molWriteFloat(out, 104166f); // (500%) value for acceleration from the settings
+    molWriteFloat(out, 72916f); // (350%) 
+  // 024c: steps required
+    molWriteBytes(out, 0x46, 0x0e, 0x00, 0x03);
+    molWriteFloat(out, 208.333f);  // x steps per mm
+    molWriteFloat(out, 208.333f);  // y steps per mm
+    molWriteFloat(out, 800f);  // z steps per mm
+  // 025c: Unknown Command 6
+    molWriteBytes(out, 0x48, 0x09, 0x20, 0x01);
+    molWriteInt(out, 0);
+  // 0264: Artwork Origin
+    molWriteBytes(out, 0x40, 0x60, 0x04, 0x03);
+    molWriteBytes(out, 0x04, 0x03, 0x00, 0x00);  // Select motion axes
+    // Verify setting for origin andsize, coordinate flipping, etc.
+    //molWriteMm(out, (float)(0.5*(bedWidth+bboxWidth))); // FIXME: (500.005mm) (table width + artwork width) / 2
+    //molWriteMm(out, (float)(0.5*(bedHeight+bboxHeight))); // FIXME: (350.002mm) (table height + artwork height) / 2
+    molWriteMm(out, (float)100); // FIXME: (500.005mm) (table width + artwork width) / 2
+    // if user origin or fixed origin is set, this seems to do nothing (is there some offset origin?)
+    molWriteMm(out, (float)100); // FIXME: (350.002mm) (table height + artwork height) / 2
+    nMoveRelative++;
+  // 0274: Set Speed
+    molWriteBytes(out, 0x41, 0x03, 0x00, 0x03);
+    molWriteFloat(out, 1041f); // (5%) start
+    molWriteFloat(out, 41666f); // (200%) max
+    molWriteFloat(out, 145833f); // (700%) accel
+  // 0284: Start Corner
+    // TODO: Verify setting for origin and size, coordinate flipping, etc.
+    molWriteBytes(out, 0x40, 0x60, 0x02, 0x03);
+    molWriteBytes(out, 0x04, 0x03, 0x00, 0x00);  // Select motion axes
+    molWriteMm(out, (float)(-bboxWidth)); // FIXME: (-100mm) left
+    molWriteMm(out, (float)(-bboxHeight)); // FIXME: (-100mm) bottom
+  // 0294: Unknown Command 10
+    molWriteBytes(out, 0x48, 0x00, 0x50, 0x80);
+    molWriteInt(out, 3);  // Length = 3 words
+    molWriteInt(out, 3);
+    molWriteInt(out, 0x81000000);
+    molWriteInt(out, 0x81000000);
+  // 02a8: Unknown Command 10
+    molWriteBytes(out, 0x48, 0x00, 0x50, 0x80);
+    molWriteInt(out, 1);  // Length = 1 words
+    molWriteInt(out, 603);
+  // 02b4: Unknown Command 12
+    molWriteBytes(out, 0x48, 0x06, 0x20, 0x00);
+  }
+
+  private void molFixBlock0200(RandomAccessFile out) throws IOException
+  {
+  }
+
+  // 
+  // .MOL file data block at 0x00000400
+  // 
+  private void molWriteBlock0400(RandomAccessFile out) throws IOException
+  {
+    out.seek(0x00000400);
+    molCmdBeginSubroutine(out, 1);
+  // 0408: Unknown Command 2
+    molWriteBytes(out, 0x48, 0x01, 0x60, 0x80);
+    molWriteInt(out, 6);  // Length = 6 words
+    molWriteInt(out, 603);
+    molWriteFloat(out, 1041f); // (5%) start speed for all head movements
+    molWriteFloat(out, 41666f); // (200%) maximum speed for moving around quickly
+    molWriteFloat(out, 145833f); // (700%) acceleration value to get to the above speed
+    molWriteFloat(out, 104166f); // (500%) value for acceleration from the settings
+    molWriteFloat(out, 72916f); // (350%) 
+  // 0428: Begin Motion Block
+    molCmdBeginMotionBlock(out);
+  // motion  
+    // TODO: verify that the correct origin is used, verify if correct after flipping coordinates
+    molMoveRel(out, 1041f, 41666f, 1473.12f, 145833f, -bboxWidth*208.33, 0f); // FIXME: (5%, 200%, 7%, 700%, -100mm, 0mm [rcr])
+    molMoveRel(out, 1473.12f, 41666f, 1473.12f, 145833f, 0f, -bboxHeight*208.33); // FIXME: (7%, 200%, 7%, 700%, 0mm, -100mm [rcr])
+    molMoveRel(out, 1473.12f, 41666f, 1473.12f, 145833f, bboxWidth*208.33, 0f); // FIXME: (7%, 200%, 7%, 700%, 100mm, 0mm [rcr])
+    molMoveRel(out, 1473.12f, 41666f, 1041f, 145833f, 0f, bboxHeight*208.33); // FIXME: (7%, 200%, 5%, 700%, 0mm, 100mm [rcr])
+  // 05f0: End Of Motion Block (started at 0430, 112 words)
+    molCmdEndMotionBlock(out);
+    molCmdEndSubroutine(out, 1);
+  }
+  
+  // 
+  // .MOL file data block at 0x00000400
+  // 
+  private void molFixBlock0400(RandomAccessFile out) throws IOException
+  {
+  }
+
+  // 
+  // .MOL file data block at 0x00000600
+  // 
+  private void molWriteBlock0600(RandomAccessFile out) throws IOException
+  {
+    out.seek(0x00000600);
+    molCmdBeginSubroutine(out, 2);
+  // 0608: Unknown Command 2
+    molWriteBytes(out, 0x48, 0x01, 0x60, 0x80);
+    molWriteInt(out, 6);  // Length = 6 words
+    molWriteInt(out, 603);
+    molWriteFloat(out, 1041f); // (5%) start speed for all head movements
+    molWriteFloat(out, 41666f); // (200%) maximum speed for moving around quickly
+    molWriteFloat(out, 145833f); // (700%) acceleration value to get to the above speed
+    molWriteFloat(out, 104166f); // (500%) value for acceleration from the settings
+    molWriteFloat(out, 72916f); // (350%) 
+  // 0628: Laser Power
+    molWriteBytes(out, 0x46, 0x0e, 0x00, 0x05);
+    molWriteInt(out, 4000);  // (40.000000%) corner power
+    molWriteInt(out, 4000);  // (40.000000%) maximum power
+    molWriteFloat(out, 1041f); // (5%) cutting start speed
+    molWriteFloat(out, 5208f); // (25%) maximum cutting speed
+    molWriteInt(out, 0);  // unknown
+  // 0640: Laser Power Long
+    molWriteBytes(out, 0x46, 0x0e, 0x00, 0x07);
+    molWriteInt(out, 4000);  // (40.000000%) corner power
+    molWriteInt(out, 4000);  // (40.000000%) maximum power
+    molWriteInt(out, 4000);  // (40.000000%) ?
+    molWriteInt(out, 4000);  // (40.000000%) ?
+    molWriteFloat(out, 1041f); // (5%) cutting start speed
+    molWriteFloat(out, 5208f); // (25%) maximum cutting speed
+    molWriteInt(out, 0);  // unknown
+  // 0660: Begin Motion Block
+    molCmdBeginMotionBlock(out);
+    molMoveRel(out, 1041f, 5208f, 1014.73f, 104166f, 417f, 417f); // (5%, 25%, 5%, 500%, 2.00163mm, 2.00163mm [rcr])
+    molCmdLaserOn(out); // 06d8
+    // TODO: verify that the correct origin is used, verify if correct after flipping coordinates
+    molMoveRel(out, 1014.73f, 5208f, 1473.12f, 104166f, (-bboxWidth-4.0)*208.33, 0f); // FIXME: (5%, 25%, 7%, 500%, -104.003mm, 0mm [rcr])
+    molMoveRel(out, 1473.12f, 5208f, 1473.12f, 104166f, 0f, (-bboxHeight-4.0)*208.33); // FIXME: (7%, 25%, 7%, 500%, 0mm, -104.003mm [rcr])
+    molMoveRel(out, 1473.12f, 5208f, 1473.12f, 104166f, (bboxWidth+4.0)*208.33, 0f); // FIXME: (7%, 25%, 7%, 500%, 104.003mm, 0mm [rcr])
+    molMoveRel(out, 1473.12f, 5208f, 1041f, 104166f, 0f, (bboxHeight+4.0)*208.33); // FIXME: (7%, 25%, 5%, 500%, 0mm, 104.003mm [rcr])
+    molCmdLaserOff(out); // 08a0
+  // 08a8: End Of Motion Block (started at 0668, 144 words)
+    molCmdEndMotionBlock(out);
+    molCmdEndSubroutine(out, 2);
+  }
+    
+  // 
+  // .MOL file data block at 0x00000600
+  // 
+  private void molFixBlock0600(RandomAccessFile out) throws IOException
+  {
   }
 
   @Override
   public void sendJob(LaserJob job, ProgressListener pl, List<String> warnings) throws IllegalJobException, Exception
   {
     // This is a first try in Java. All data is saved into ~/RUN.MOL until we figure out the USB communication
-
-    // - delete the file
-    try
+    currentPower = 40.0;
+    currentSpeed = 80.0;
+    motionBlockStart = -1;
+    
+    pl.taskChanged(this, "checking...");
+    checkJob(job);
+    
+    // find the size of the entire artwork
+    firstVector = true;
+    for (JobPart p : job.getParts())
     {
-      File f = new File("/Users/matt/RUN.MOL");
-      if (f.exists())
+      // FIXME: use job.getMinX(), job.getMaxX(), etc.
+      if (p instanceof VectorPart)
       {
-        f.delete();
+        double resolution = p.getDPI();
+        for (VectorCommand c : ((VectorPart) p).getCommandList())
+        {
+          switch (c.getType())
+          {
+            case LINETO:
+            case MOVETO:
+            {
+              double dx, x = Util.px2mm(c.getX(), resolution);
+              double dy, y = this.bedHeight - Util.px2mm(c.getY(), resolution);
+              if (firstVector) {
+                firstVector = false;
+                bboxMinX = bboxMaxX = firstX = prevX = x;
+                bboxMinY = bboxMaxY = firstY = prevY = y;
+              } else {
+                if (x<bboxMinX) bboxMinX = x;
+                if (x>bboxMaxX) bboxMaxX = x;
+                if (y<bboxMinY) bboxMinY = y;
+                if (y>bboxMaxY) bboxMaxY = y;
+              }
+              break;
+            }
+          }
+        }
       }
     }
-    catch (Exception e)
-    {
+    bboxWidth  = bboxMaxX - bboxMinX;
+    bboxHeight = bboxMaxY - bboxMinY;
+    
+    pl.progressChanged(this, 20);
+    pl.taskChanged(this, "buffering...");
+    
+    // - delete the file
+    try {
+      File f = new File("/Users/matt/RUN.MOL");
+      if (f.exists()) {
+        f.delete();
+      }
+    } catch (Exception e) {
     }
-
+    
     // - create a random access file (some data can only be patched after the entire file was written)
     File file;
     file = new File("/Users/matt/RUN.MOL");
     RandomAccessFile out = new RandomAccessFile(file, "rw");
+    
+    // taken from MOL file 0030.MOL
+    molWriteBlock0000(out);
+    
+    molWriteBlock0200(out);
+    
+    molWriteBlock0400(out);
+    
+    molWriteBlock0600(out);
+
+  // 
+  // .MOL file data block at 0x00000a00
+  // 
+    out.seek(0x00000a00);
+    molCmdBeginSubroutine(out, 3);
+  // 0a08: Unknown Command 13
+    molWriteBytes(out, 0x46, 0x0d, 0x00, 0x01);
+    molWriteInt(out, 3000);
+  // 0a10: Unknown Command 14
+    molWriteBytes(out, 0x41, 0x4a, 0x00, 0x02);
+    molWriteInt(out, 4);
+    molWriteInt(out, 0);
+  // 0a1c: Unknown Command 15
+    molWriteBytes(out, 0x41, 0x4b, 0x00, 0x01);
+    molWriteInt(out, 516);
+  // 0a24: Unknown Command 14
+    molWriteBytes(out, 0x41, 0x4a, 0x00, 0x02);
+    molWriteInt(out, 3);
+    molWriteInt(out, 0);
+  // 0a30: Unknown Command 15
+    molWriteBytes(out, 0x41, 0x4b, 0x00, 0x01);
+    molWriteInt(out, 515);
+  // first vector will set the speed and start the motion block!
+    
+    // generate the commands to draw the artwork
+    firstVector = true;
+    for (JobPart p : job.getParts())
+    {
+      if (p instanceof RasterPart)
+      {
+        throw new IllegalJobException("The MPC6515 currently does not support engraving");
+      }
+      else if (p instanceof Raster3dPart)
+      {
+        throw new IllegalJobException("The MPC6515 currently does not support 3d engraving");
+      }
+      if (p instanceof VectorPart)
+      {
+        double resolution = p.getDPI();
+        for (VectorCommand c : ((VectorPart) p).getCommandList())
+        {
+          switch (c.getType())
+          {
+            case LINETO:
+            case MOVETO:
+            {
+              double dx, x = Util.px2mm(c.getX(), resolution);
+              double dy, y = this.bedHeight - Util.px2mm(c.getY(), resolution);
+              // FIXME: job.getStartX() job.getStartY(), what do they do? Will that help us here?
+              if (firstVector) {
+                firstVector = false;
+                // 0a38: Laser Power
+                Debug.println("Setting power and speed");
+                molSetPowerAndSpeed(out, currentPower*cornerPowerFactor, currentPower, 5.0, currentSpeed);
+                // 0a70: Begin Motion Block
+                molCmdBeginMotionBlock(out);
+                molCmdBlowerOn(out);
+                // TODO: what exactly is the origin at this point?
+                firstX = prevX = x;
+                firstY = prevY = y;
+                if (firstX!=bboxMinX || firstY!=bboxMinY) {
+                  // TODO: if this is a LINETO, move to the origin, then cut to the coordinate
+                  molMoveRel(out, 936.9f, 20833f, 936.9f, 145833f, (firstX-bboxMinX)*208.33, (firstY-bboxMinY)*208.33);
+                }
+              } else {
+                dx = x - prevX; prevX = x;
+                dy = y - prevY; prevY = y;
+                if (dx!=0.0 || dy!=0.0) {
+                  if (c.getType()==VectorCommand.CmdType.LINETO) {
+                    molCmdLaserOn(out);
+                    molMoveRel(out, 936.9f, currentSpeed*208.33, 936.9f, 104166f, dx*208.33, dy*208.33);
+                    molCmdLaserOff(out);
+                  } else {
+                    molMoveRel(out, 936.9f, 35406.7f, 936.9f, 145833f, dx*208.33, dy*208.33);
+                  }
+                }
+              }
+              break;
+            }
+            case SETPROPERTY:
+            {
+              PowerSpeedFocusFrequencyProperty prop = (PowerSpeedFocusFrequencyProperty) c.getProperty();
+              currentPower = prop.getPower(); //power in 0-100
+              currentSpeed = prop.getSpeed(); //speed in 0-100
+              Debug.println("Set Power to " + Double.toString(currentPower) + "  Speed to " + Double.toString(currentSpeed));
+              //out.write(prop.getPower());//power in 0-100
+              //out.write(prop.getSpeed());//speed in 0-100
+              //out.write((int) prop.getFocus());//focus in mm
+              //out.write(prop.getFrequency());//frequency in Hz
+              if (!firstVector) {
+                Debug.println("Changing power and speed");
+                molChangePowerAndSpeed(out, currentPower*cornerPowerFactor, currentPower, 5.0, currentSpeed);
+              }
+              break;
+            }
+          }
+        }
+      }
+    }
+    if (molInMotionBlock()) {
+      // don't write this blcok if no vectors were sent at all...
+      molCmdLaserOff(out);
+      molCmdBlowerOff(out);
+      molCmdEndMotionBlock(out);
+    }
+    molCmdEndSubroutine(out, 3);
 
-    // - write the standard header
-    molWriteHeader(out);
-
-    // - write the configuration block
-    molWriteConfig(out);
-
-    /*
-     pl.taskChanged(this, "checking...");
-     checkJob(job);
-     pl.progressChanged(this, 20);
-     pl.taskChanged(this, "buffering...");
-     ByteArrayOutputStream buffer = new ByteArrayOutputStream();
-     BufferedOutputStream out = new BufferedOutputStream(buffer);
-     //TODO: write MOL header to out
-     for (JobPart p : job.getParts())
-     {
-     if (p instanceof RasterPart)
-     {
-     throw new IllegalJobException("The MPC6515 currently does not support engraving");
-     }
-     else if (p instanceof Raster3dPart)
-     {
-     throw new IllegalJobException("The MPC6515 currently does not support 3d engraving");
-     }
-     if (p instanceof VectorPart)
-     {
-     double resolution = p.getDPI();
-     for (VectorCommand c : ((VectorPart) p).getCommandList())
-     {
-     switch (c.getType())
-     {
-     case LINETO:
-     {
-     //TODO: WRITE IN MOL FORMAT
-     out.write(10);
-     out.write(c.getX());//x in dots (relative to resolution)
-     out.write(c.getY());//y in dots (relative to resolution)
-     break;
-     }
-     case MOVETO:
-     {
-     //TODO: WRITE IN MOL FORMAT
-     out.write(20);
-     out.write(c.getX());//x in dots (relative to resolution)
-     out.write(c.getY());//y in dots (relative to resolution)
-     break;
-     }
-     case SETPROPERTY:
-     {
-     //TODO: WRITE IN MOL FORMAT
-     PowerSpeedFocusFrequencyProperty prop = (PowerSpeedFocusFrequencyProperty) c.getProperty();
-     out.write(10);
-     out.write(prop.getPower());//power in 0-100
-     out.write(prop.getSpeed());//speed in 0-100
-     out.write((int) prop.getFocus());//focus in mm
-     out.write(prop.getFrequency());//frequency in Hz
-     break;
-     }
-     }
-     }
-     }
-     }
-     */
-
-    // - fix all positions that require patching
-    molFixHeader(out);
-
-    //TODO: write MOL footer to out
+    molFixBlock0600(out);
+    
+    molFixBlock0400(out);
+    
+    molFixBlock0200(out);
+    
+    molFixBlock0000(out);
+    
+    out.close();
+    
     pl.progressChanged(this, 80);
     pl.taskChanged(this, "sending...");
     //TODO: contents of buffer.toByteArray() to laser-cutter
@@ -419,9 +1007,13 @@ public class MPC6515Cutter extends LaserCutter
     {
       setBedHeight((Double) value);
     }
+    else if (CORNER_POWER_FACTOR.equals(key))
+    {
+      cornerPowerFactor = (Double)value;
+    }
     else
     {
-      System.err.println("ERROR: Unknown property '" + key + "' for MPC6151 driver");
+      System.err.println("ERROR: Unknown property '"+key+"' for MPC6151 driver");
     }
   }
 
@@ -436,10 +1028,15 @@ public class MPC6515Cutter extends LaserCutter
     {
       return getBedHeight();
     }
+    else if (CORNER_POWER_FACTOR.equals(key))
+    {
+      return cornerPowerFactor;
+    }
     else
     {
-      System.err.println("ERROR: Unknown property '" + key + "' for MPC6151 driver");
+      System.err.println("ERROR: Unknown property '"+key+"' for MPC6151 driver");
     }
     return null;
   }
-}
\ No newline at end of file
+
+}