diff --git a/Assignment_1.pdf b/Assignment_1.pdf
new file mode 100644
index 0000000000000000000000000000000000000000..a077aa47dfdcf1f56b670b6e8da419f8ac541ffe
Binary files /dev/null and b/Assignment_1.pdf differ
diff --git a/build.xml b/build.xml
new file mode 100644
index 0000000000000000000000000000000000000000..658996f9b1fa3d00605af37f0e167f0d8411ef3d
--- /dev/null
+++ b/build.xml
@@ -0,0 +1,43 @@
+<project name="Project" default="classes">
+    <target name="classes">
+        <mkdir dir="classes" />
+        <javac srcdir="src:test" destdir="classes" 
+            classpath="lib/junit-4.11.jar;lib/hamcrest-core-1.3.jar"
+            includeantruntime="false"/>
+    </target>
+    <target name="clean">
+        <delete dir="classes" />
+    </target>
+
+    <target name="run" depends="classes">
+        <java classname="swen90006.machine.SimpleDriver" 
+	    classpath="classes/;lib/junit-4.11.jar;lib/hamcrest-core-1.3.jar">
+	</java>
+    </target>
+
+    <target name="partitioning" depends="classes">
+        <junit printsummary="yes" fork="yes" haltonfailure="yes">
+	    <classpath>
+                <pathelement path="classes/"/>
+                <pathelement path="lib/junit-4.11.jar"/>
+                <pathelement path="lib/hamcrest-core-1.3.jar"/>
+            </classpath>
+            <formatter type="plain"/>
+            <test name="swen90006.machine.PartitioningTests"/>
+        </junit>
+    </target>
+
+    <target name="boundary" depends="classes">
+        <junit printsummary="yes" fork="yes" haltonfailure="yes">
+	    <classpath>
+                <pathelement path="classes/"/>
+                <pathelement path="lib/junit-4.11.jar"/>
+                <pathelement path="lib/hamcrest-core-1.3.jar"/>
+            </classpath>
+            <formatter type="plain"/>
+            <test name="swen90006.machine.BoundaryTests"/>
+        </junit>
+    </target>
+
+
+</project>
diff --git a/classes/swen90006/machine/BoundaryTests.class b/classes/swen90006/machine/BoundaryTests.class
new file mode 100644
index 0000000000000000000000000000000000000000..75ca15dbf4f906cd2b7beec235fa91a8de079579
Binary files /dev/null and b/classes/swen90006/machine/BoundaryTests.class differ
diff --git a/classes/swen90006/machine/BugException.class b/classes/swen90006/machine/BugException.class
new file mode 100644
index 0000000000000000000000000000000000000000..f118d84a4f1eb3cda19ec8de216e3dc339d6090c
Binary files /dev/null and b/classes/swen90006/machine/BugException.class differ
diff --git a/classes/swen90006/machine/InvalidInstructionException.class b/classes/swen90006/machine/InvalidInstructionException.class
new file mode 100644
index 0000000000000000000000000000000000000000..b825f28f0bae9bc7d1352fc96ae041000ea4a729
Binary files /dev/null and b/classes/swen90006/machine/InvalidInstructionException.class differ
diff --git a/classes/swen90006/machine/Machine.class b/classes/swen90006/machine/Machine.class
new file mode 100644
index 0000000000000000000000000000000000000000..bc67cdff3d66160515599de443f4aea563326bac
Binary files /dev/null and b/classes/swen90006/machine/Machine.class differ
diff --git a/classes/swen90006/machine/NoReturnValueException.class b/classes/swen90006/machine/NoReturnValueException.class
new file mode 100644
index 0000000000000000000000000000000000000000..8e5254e009b57eb2894b9bb735e33962cd163259
Binary files /dev/null and b/classes/swen90006/machine/NoReturnValueException.class differ
diff --git a/classes/swen90006/machine/PartitioningTests.class b/classes/swen90006/machine/PartitioningTests.class
new file mode 100644
index 0000000000000000000000000000000000000000..af52566636122d3ab4edeca3dfd4fb3e867aa1db
Binary files /dev/null and b/classes/swen90006/machine/PartitioningTests.class differ
diff --git a/classes/swen90006/machine/SimpleDriver.class b/classes/swen90006/machine/SimpleDriver.class
new file mode 100644
index 0000000000000000000000000000000000000000..e2898a8d0db987dacaa7428260b0686b6d57b7e3
Binary files /dev/null and b/classes/swen90006/machine/SimpleDriver.class differ
diff --git a/examples/array.s b/examples/array.s
new file mode 100644
index 0000000000000000000000000000000000000000..54b5878259fee8b451aebed898ebd70cda25caa0
--- /dev/null
+++ b/examples/array.s
@@ -0,0 +1,40 @@
+        ;; array program. Fills an array with the values 0 ... N-1
+        ;; and then interates through the array, summing its elements
+
+        ;; global constants:
+        ;;   R3 holds 'N', the length of the array
+        ;;   R2 holds 1, the increment value used below
+        MOV R3 10               ; N = 10
+        MOV R2 1                ;
+
+        ;;  create the array
+        ;; local variables
+        ;;   R1 holds 'i', which is a counter from 0 .. N-1
+        ;;   R0 holds 'p', the address of the array's ith element
+        MOV R1 0                ; i = 0;
+        MOV R0 100    
+
+        SUB R4 R3 R1            ; while(i != N)
+        JZ  R4 5                ; {
+        STR R0 0  R1            ;   *p = i;
+        ADD R1 R1 R2            ;   i = i + 1;
+        ADD R0 R0 R2            ;   p = p + 1;
+        JMP -5                  ; }
+
+        ;;  sum up the array
+        ;; local variables
+        ;;   R1 holds 'i', which is a counter from 0 .. N-1
+        ;;   R0 holds 'p', the address of the array's ith element
+        ;;   R5 holds 'sum', which always holds the sum of the array's first i elements
+        MOV R1 0                ; i = 0;
+        MOV R0 100    
+        MOV R5 0                ; sum = 0;
+
+        SUB R4 R3 R1            ; while(i != N)
+        JZ  R4 6                ; {
+        LDR R4 R0 0             ;   
+        ADD R5 R5 R4            ;   sum = sum + *p;
+        ADD R0 R0 R2            ;   p = p + 1;
+        ADD R1 R1 R2            ;   i = i + 1;
+        JMP -6                  ; }
+        RET R5                  ; return sum;
diff --git a/examples/factorial.s b/examples/factorial.s
new file mode 100644
index 0000000000000000000000000000000000000000..2928e12e5d977b84e4ccfbb637a1771c2bc44ed3
--- /dev/null
+++ b/examples/factorial.s
@@ -0,0 +1,22 @@
+        ;; factorial program, to calculate N!
+
+        ;; global constants:
+        ;;   R3 holds 'N', the thing we are computing factorial of
+        ;;   R2 holds 1, the increment value used below
+        MOV R3 12               ; N = 12
+        MOV R2 1                ;
+        
+        ;; local variables
+        ;;   R1 holds 'i', which is a counter from 0 .. N
+        ;;   R0 holds 'n', which is always equal to i! 
+        MOV R1 0                ; i = 0;
+        MOV R0 1                ; n = 1;
+
+        ;;  program body
+        ;;  loop invariant (see SWEN90010 next semester): n = i!
+        SUB R4 R3 R1            ; while(i != N)
+        JZ  R4 4                ; {
+        ADD R1 R1 R2            ;   i = i + 1;
+        MUL R0 R0 R1            ;   n = n * i;
+        JMP -4                  ; }
+        RET R0                  ; return n;
diff --git a/lib/hamcrest-core-1.3.jar b/lib/hamcrest-core-1.3.jar
new file mode 100644
index 0000000000000000000000000000000000000000..9d5fe16e3dd37ebe79a36f61f5d0e1a69a653a8a
Binary files /dev/null and b/lib/hamcrest-core-1.3.jar differ
diff --git a/lib/junit-4.11.jar b/lib/junit-4.11.jar
new file mode 100644
index 0000000000000000000000000000000000000000..aaf74448492932e95902b40a70c7a4da5bad4744
Binary files /dev/null and b/lib/junit-4.11.jar differ
diff --git a/machine.zip b/machine.zip
new file mode 100644
index 0000000000000000000000000000000000000000..1d51cbc55e5d55a7f69fea8a60be3eac510b9bd9
Binary files /dev/null and b/machine.zip differ
diff --git a/mutants/mutant-1/swen90006/machine/BugException.java b/mutants/mutant-1/swen90006/machine/BugException.java
new file mode 100644
index 0000000000000000000000000000000000000000..41cb9cab9f4bb06efde089f190abc13331b00b21
--- /dev/null
+++ b/mutants/mutant-1/swen90006/machine/BugException.java
@@ -0,0 +1,7 @@
+package swen90006.machine;
+
+public class BugException extends Exception {
+    public BugException(String msg){
+        super("You triggered one of the security bugs!\n" + msg);
+    }
+}
diff --git a/mutants/mutant-1/swen90006/machine/InvalidInstructionException.java b/mutants/mutant-1/swen90006/machine/InvalidInstructionException.java
new file mode 100644
index 0000000000000000000000000000000000000000..25e042bfb4bf0519927e165946fa9d03640c45fe
--- /dev/null
+++ b/mutants/mutant-1/swen90006/machine/InvalidInstructionException.java
@@ -0,0 +1,9 @@
+package swen90006.machine;
+
+public class InvalidInstructionException extends RuntimeException
+{
+  public String toString()
+  {
+      return "InvalidInstructionException";
+  }
+}
diff --git a/mutants/mutant-1/swen90006/machine/Machine.java b/mutants/mutant-1/swen90006/machine/Machine.java
new file mode 100644
index 0000000000000000000000000000000000000000..9bf57316d1c736ea2bd1c62bd6df3c6c0282f331
--- /dev/null
+++ b/mutants/mutant-1/swen90006/machine/Machine.java
@@ -0,0 +1,303 @@
+package swen90006.machine;
+
+import java.util.Arrays;
+import java.util.List;
+
+public class Machine 
+{
+  /** arithmetic instructions each take three registers as arguments with the
+   *  destination register appearing first
+   */
+
+  /** add rd rs1 rs2   =~   rd = rs1 + rs2 */
+  public static final String INSTRUCTION_ADD = "add";
+
+  /** sub rd rs1 rs2   =~   rd = rs1 - rs2 */    
+  public static final String INSTRUCTION_SUBTRACT = "sub";
+
+  /** mul rd rs1 rs2   =~   rd = rs1 * rs2 */        
+  public static final String INSTRUCTION_MULT = "mul";
+
+  /** div rd rs1 rs2   =~   rd = rs1 / rs2 */            
+  public static final String INSTRUCTION_DIVIDE = "div";
+
+  /** ret rs           =~   return rs */
+  public static final String INSTRUCTION_RETURN = "ret";
+
+  /** ldr rd rs offs  =~    rd = rs[offs] */
+  public static final String INSTRUCTION_LOAD = "ldr";
+
+  /** str ra offs rb   =~    ra[offs] = rb */
+  public static final String INSTRUCTION_STORE = "str";
+
+  /** mov rd val       =~    rd = val */
+  public static final String INSTRUCTION_MOVE = "mov";
+
+  /** jmp offs         =~    pc = pc + offs */
+  public static final String INSTRUCTION_JUMP = "jmp";
+
+  /** jz ra offs       =~   if (ra == 0) pc = pc + offs else pc = pc + 1 */
+  public static final String INSTRUCTION_JZ = "jz";
+    
+  public static final int NUM_REGS = 32;
+  public static final int MAX_REG = (NUM_REGS - 1);
+  public static final int MEMORY_SIZE = 65536; /* 4 x as much memory as a 64 */
+  public static final int MAX_ADDR = MEMORY_SIZE-1;
+    
+  private int[] memory;
+  private int[] regs;
+
+  private int count = 0; /* counts number of instructions executed so far */
+    
+  public Machine()
+  {
+    memory = new int[MEMORY_SIZE];
+    regs = new int[NUM_REGS];
+    count = 0;
+  }
+
+  private void do_add(int dest, int src1, int src2)
+  {
+    regs[dest] = regs[src1] + regs[src2];
+  }
+    
+  private void do_sub(int dest, int src1, int src2)
+  {
+    regs[dest] = regs[src1] - regs[src2];
+  }
+    
+  private void do_mult(int dest, int src1, int src2)
+  {
+    regs[dest] = regs[src1] * regs[src2];
+  }
+    
+  private void do_div(int dest, int src1, int src2)
+  {
+    if (regs[src2] == 0){
+      /* no op */
+    }else{
+      regs[dest] = regs[src1] / regs[src2];
+    }
+  }
+
+  private void do_load(int dest, int src, int offs) {
+    if (regs[src] + offs > MAX_ADDR){
+      /* no op */
+    }else if(regs[src] + offs < 0){
+      /* no op */
+    }else{
+      regs[dest] = memory[regs[src] + offs];
+    }
+  }
+
+  private void do_store(int a, int offs, int b)  {
+    if (regs[a] + offs > MAX_ADDR){
+      /* no op */
+    }else if(regs[a] + offs < 0){
+      /* no op */
+    }else{
+      memory[regs[a] + offs] = regs[b];
+    }
+  }
+
+  private void do_move(int rd, int val){
+    regs[rd] = val;
+  }
+
+  private int parseReg(String s) throws InvalidInstructionException
+  {
+    if (s.length() < 2){
+      throw new InvalidInstructionException();
+    }
+    if (s.charAt(0) != 'r'){
+      throw new InvalidInstructionException();
+    }
+    String numstr = s.substring(1);
+    int num = 0;
+    try {
+      num = Integer.parseInt(numstr);
+    } catch (Exception e){
+      throw new InvalidInstructionException();
+    }
+    validate_reg(num);
+    return num;
+  }
+
+  private int parseOffset(String s)
+    throws InvalidInstructionException
+  {
+    int num = 0;
+    try {
+      num = Integer.parseInt(s);
+    } catch (Exception e){
+      throw new InvalidInstructionException();
+    }
+    validate_offset(num);
+    return num;
+  }
+
+
+  private void validate_reg(int reg)
+    throws InvalidInstructionException
+  {
+    if (reg < 0 || reg > MAX_REG) {
+      throw new InvalidInstructionException();
+    }
+  }
+
+  private void validate_offset(int offset)
+    throws InvalidInstructionException
+  {
+    if (offset < -MAX_ADDR || offset > MAX_ADDR) {
+      throw new InvalidInstructionException();
+    }
+  }
+    
+  /** Execute an assembly program.
+   *
+   * @param prog is the program to execute as an iterable collection of strings, 
+   *        each of which is a single instruction.
+   * @return the program's return value.
+   * @throws Exception when program has unrecognised or 
+   *         invalid instructions, or when it returns no result when it finishes
+   */
+  int execute(List<String> instructions) 
+    throws InvalidInstructionException,
+	   NoReturnValueException
+  {
+
+    int instructionsExecuted = 0;
+    int pc = 0;
+    final int progLength = instructions.size();
+    while(true){
+      if (pc < 0 || pc >= progLength){
+	/* will cause NoReturnValueException to be thrown
+	 * but that is not a bug and and indeed is what the
+	 * VM is supposed to do if the pc becomes negative,
+	 * since in this case the program's execution
+	 * finishes early without a return value having
+	 * been produced. */
+	break;
+      }
+      String inst = instructions.get(pc);
+      /* strip leading and trailing whitespace */ 
+      inst = inst.toLowerCase().replaceAll("^\\s+","").replaceAll("\\s+$","");
+      /* strip out any comments */
+      String[] toks = inst.split(";");
+      inst = toks[0];
+
+      /* check for blank lines */
+      if (inst.equals("")){
+	pc = pc + 1;
+	count++;
+	continue;
+      }
+
+      instructionsExecuted++;
+      /* now  tokenize by splitting on whitespace */
+      toks = inst.split("\\s+");
+
+      /* check minimum number of tokens */
+      if (toks.length < 2){
+	throw new InvalidInstructionException();
+      }
+
+      if (toks[0].equals(INSTRUCTION_ADD)){
+	if (toks.length != 4){
+	  throw new InvalidInstructionException();
+	}
+	int rd = parseReg(toks[1]);
+	int rs1 = parseReg(toks[2]);
+	int rs2 = parseReg(toks[3]);
+	do_add(rd,rs1,rs2);
+      } else if (toks[0].equals(INSTRUCTION_SUBTRACT)){
+	if (toks.length != 4){
+	  throw new InvalidInstructionException();
+	}
+	int rd = parseReg(toks[1]);
+	int rs1 = parseReg(toks[2]);
+	int rs2 = parseReg(toks[3]);
+	do_sub(rd,rs1,rs2);
+      } else if (toks[0].equals(INSTRUCTION_MULT)){
+	if (toks.length != 4){
+	  throw new InvalidInstructionException();
+	}
+	int rd = parseReg(toks[1]);
+	int rs1 = parseReg(toks[2]);
+	int rs2 = parseReg(toks[3]);
+	do_mult(rd,rs1,rs2);
+      } else if (toks[0].equals(INSTRUCTION_DIVIDE)){
+	if (toks.length != 4){
+	  throw new InvalidInstructionException();
+	}
+	int rd = parseReg(toks[1]);
+	int rs1 = parseReg(toks[2]);
+	int rs2 = parseReg(toks[3]);
+	do_div(rd,rs1,rs2);
+      } else if (toks[0].equals(INSTRUCTION_RETURN)){
+	int rs = parseReg(toks[1]);
+	count++;
+	return regs[rs];
+      } else if (toks[0].equals(INSTRUCTION_LOAD)){
+	if (toks.length != 4){
+	  throw new InvalidInstructionException();
+	}
+	int rd = parseReg(toks[1]);
+	int rs = parseReg(toks[2]);
+	int offs = parseOffset(toks[3]);
+	do_load(rd,rs,offs);
+      } else if (toks[0].equals(INSTRUCTION_STORE)){
+	if (toks.length != 4){
+	  throw new InvalidInstructionException();
+	}
+	int ra = parseReg(toks[1]);
+	int offs = parseOffset(toks[2]);
+	int rb = parseReg(toks[3]);
+	do_store(ra,offs,rb);
+      } else if (toks[0].equals(INSTRUCTION_MOVE)){
+	if (toks.length != 3){
+	  throw new InvalidInstructionException();
+	}
+	int rd = parseReg(toks[1]);
+	int offs = parseOffset(toks[2]);
+	do_move(rd,offs);
+      } else if (toks[0].equals(INSTRUCTION_JUMP)){
+	if (toks.length != 2){
+	  throw new InvalidInstructionException();
+	}
+	int offs = parseOffset(toks[1]);
+	pc  = pc + offs;
+	count++;
+	continue; /* avoid default increment of pc below */
+      } else if (toks[0].equals(INSTRUCTION_JZ)){
+	if (toks.length != 3){
+	  throw new InvalidInstructionException();
+	}
+	int ra = parseReg(toks[1]);
+	int offs = parseOffset(toks[2]);
+	if (regs[ra] == 0){
+	  pc = pc + offs;
+	}else{
+	  pc = pc + 1;
+	}
+	count++;
+	continue; /* avoid default increment the pc below */
+      } else {
+	System.err.println("Unrecognised instruction: " + inst);
+	throw new InvalidInstructionException();
+      }
+      count++;
+      pc = pc + 1;
+    }
+
+    /* got here without returning already... */
+    throw new NoReturnValueException();
+  }
+
+  /**
+   * get the number of instructions successfully executed by the VM so far
+   */
+  public int getCount(){
+    return count;
+  }
+}
diff --git a/mutants/mutant-1/swen90006/machine/NoReturnValueException.java b/mutants/mutant-1/swen90006/machine/NoReturnValueException.java
new file mode 100644
index 0000000000000000000000000000000000000000..154907e85d6d8fa059da74d8fbfff17f29de28d3
--- /dev/null
+++ b/mutants/mutant-1/swen90006/machine/NoReturnValueException.java
@@ -0,0 +1,11 @@
+package swen90006.machine;
+
+public class NoReturnValueException extends RuntimeException
+{
+  public NoReturnValueException() {}
+
+  public String toString()
+  {
+    return "NoReturnValueException";
+  }
+}
diff --git a/mutants/mutant-1/swen90006/machine/SimpleDriver.java b/mutants/mutant-1/swen90006/machine/SimpleDriver.java
new file mode 100644
index 0000000000000000000000000000000000000000..bf288a4d2d3262d62316a7fa8adeb2a9f9a1dd6e
--- /dev/null
+++ b/mutants/mutant-1/swen90006/machine/SimpleDriver.java
@@ -0,0 +1,51 @@
+package swen90006.machine;
+
+import java.nio.charset.Charset;
+import java.nio.file.Path;
+import java.nio.file.Files;
+import java.nio.file.FileSystems;
+import java.util.List;
+
+public class SimpleDriver {
+
+    private static final int MEMORY_SIZE = Machine.MAX_ADDR+1;
+    
+    public static void main(String[] args) throws Exception
+    {
+        if (args.length != 1){
+            System.err.println("Usage: java SimpleDriver <inputfile>");
+	    System.err.println("\nMust have 1 argument instead of " + args.length);
+            System.exit(1);
+        }
+
+        Charset charset = Charset.forName("UTF-8");
+
+        List<String> lines = null;
+        try {
+            lines = Files.readAllLines(FileSystems.getDefault().getPath(args[0]), charset);
+        }catch (Exception e){
+            System.err.println("Invalid input file! (stacktrace follows)");
+            e.printStackTrace(System.err);
+            System.exit(1);
+        }
+
+        Machine m = null;
+        try {
+            System.out.println("There are this many instructions: " + lines.size());
+
+            m = new Machine();
+            
+            Integer res = null;
+            res = m.execute(lines);
+            System.out.println("Program result: " + res + "\n");
+
+        } catch (Exception e) {
+            System.err.println("Exception while executing program. (stacktrace follows)");
+            e.printStackTrace(System.err);
+            if (m != null){
+                System.err.println("Number of instructions executed before exception: " + m.getCount());
+            }
+            System.exit(1);
+        }
+    }
+}
diff --git a/mutants/mutant-2/swen90006/machine/BugException.java b/mutants/mutant-2/swen90006/machine/BugException.java
new file mode 100644
index 0000000000000000000000000000000000000000..41cb9cab9f4bb06efde089f190abc13331b00b21
--- /dev/null
+++ b/mutants/mutant-2/swen90006/machine/BugException.java
@@ -0,0 +1,7 @@
+package swen90006.machine;
+
+public class BugException extends Exception {
+    public BugException(String msg){
+        super("You triggered one of the security bugs!\n" + msg);
+    }
+}
diff --git a/mutants/mutant-2/swen90006/machine/InvalidInstructionException.java b/mutants/mutant-2/swen90006/machine/InvalidInstructionException.java
new file mode 100644
index 0000000000000000000000000000000000000000..25e042bfb4bf0519927e165946fa9d03640c45fe
--- /dev/null
+++ b/mutants/mutant-2/swen90006/machine/InvalidInstructionException.java
@@ -0,0 +1,9 @@
+package swen90006.machine;
+
+public class InvalidInstructionException extends RuntimeException
+{
+  public String toString()
+  {
+      return "InvalidInstructionException";
+  }
+}
diff --git a/mutants/mutant-2/swen90006/machine/Machine.java b/mutants/mutant-2/swen90006/machine/Machine.java
new file mode 100644
index 0000000000000000000000000000000000000000..9bf57316d1c736ea2bd1c62bd6df3c6c0282f331
--- /dev/null
+++ b/mutants/mutant-2/swen90006/machine/Machine.java
@@ -0,0 +1,303 @@
+package swen90006.machine;
+
+import java.util.Arrays;
+import java.util.List;
+
+public class Machine 
+{
+  /** arithmetic instructions each take three registers as arguments with the
+   *  destination register appearing first
+   */
+
+  /** add rd rs1 rs2   =~   rd = rs1 + rs2 */
+  public static final String INSTRUCTION_ADD = "add";
+
+  /** sub rd rs1 rs2   =~   rd = rs1 - rs2 */    
+  public static final String INSTRUCTION_SUBTRACT = "sub";
+
+  /** mul rd rs1 rs2   =~   rd = rs1 * rs2 */        
+  public static final String INSTRUCTION_MULT = "mul";
+
+  /** div rd rs1 rs2   =~   rd = rs1 / rs2 */            
+  public static final String INSTRUCTION_DIVIDE = "div";
+
+  /** ret rs           =~   return rs */
+  public static final String INSTRUCTION_RETURN = "ret";
+
+  /** ldr rd rs offs  =~    rd = rs[offs] */
+  public static final String INSTRUCTION_LOAD = "ldr";
+
+  /** str ra offs rb   =~    ra[offs] = rb */
+  public static final String INSTRUCTION_STORE = "str";
+
+  /** mov rd val       =~    rd = val */
+  public static final String INSTRUCTION_MOVE = "mov";
+
+  /** jmp offs         =~    pc = pc + offs */
+  public static final String INSTRUCTION_JUMP = "jmp";
+
+  /** jz ra offs       =~   if (ra == 0) pc = pc + offs else pc = pc + 1 */
+  public static final String INSTRUCTION_JZ = "jz";
+    
+  public static final int NUM_REGS = 32;
+  public static final int MAX_REG = (NUM_REGS - 1);
+  public static final int MEMORY_SIZE = 65536; /* 4 x as much memory as a 64 */
+  public static final int MAX_ADDR = MEMORY_SIZE-1;
+    
+  private int[] memory;
+  private int[] regs;
+
+  private int count = 0; /* counts number of instructions executed so far */
+    
+  public Machine()
+  {
+    memory = new int[MEMORY_SIZE];
+    regs = new int[NUM_REGS];
+    count = 0;
+  }
+
+  private void do_add(int dest, int src1, int src2)
+  {
+    regs[dest] = regs[src1] + regs[src2];
+  }
+    
+  private void do_sub(int dest, int src1, int src2)
+  {
+    regs[dest] = regs[src1] - regs[src2];
+  }
+    
+  private void do_mult(int dest, int src1, int src2)
+  {
+    regs[dest] = regs[src1] * regs[src2];
+  }
+    
+  private void do_div(int dest, int src1, int src2)
+  {
+    if (regs[src2] == 0){
+      /* no op */
+    }else{
+      regs[dest] = regs[src1] / regs[src2];
+    }
+  }
+
+  private void do_load(int dest, int src, int offs) {
+    if (regs[src] + offs > MAX_ADDR){
+      /* no op */
+    }else if(regs[src] + offs < 0){
+      /* no op */
+    }else{
+      regs[dest] = memory[regs[src] + offs];
+    }
+  }
+
+  private void do_store(int a, int offs, int b)  {
+    if (regs[a] + offs > MAX_ADDR){
+      /* no op */
+    }else if(regs[a] + offs < 0){
+      /* no op */
+    }else{
+      memory[regs[a] + offs] = regs[b];
+    }
+  }
+
+  private void do_move(int rd, int val){
+    regs[rd] = val;
+  }
+
+  private int parseReg(String s) throws InvalidInstructionException
+  {
+    if (s.length() < 2){
+      throw new InvalidInstructionException();
+    }
+    if (s.charAt(0) != 'r'){
+      throw new InvalidInstructionException();
+    }
+    String numstr = s.substring(1);
+    int num = 0;
+    try {
+      num = Integer.parseInt(numstr);
+    } catch (Exception e){
+      throw new InvalidInstructionException();
+    }
+    validate_reg(num);
+    return num;
+  }
+
+  private int parseOffset(String s)
+    throws InvalidInstructionException
+  {
+    int num = 0;
+    try {
+      num = Integer.parseInt(s);
+    } catch (Exception e){
+      throw new InvalidInstructionException();
+    }
+    validate_offset(num);
+    return num;
+  }
+
+
+  private void validate_reg(int reg)
+    throws InvalidInstructionException
+  {
+    if (reg < 0 || reg > MAX_REG) {
+      throw new InvalidInstructionException();
+    }
+  }
+
+  private void validate_offset(int offset)
+    throws InvalidInstructionException
+  {
+    if (offset < -MAX_ADDR || offset > MAX_ADDR) {
+      throw new InvalidInstructionException();
+    }
+  }
+    
+  /** Execute an assembly program.
+   *
+   * @param prog is the program to execute as an iterable collection of strings, 
+   *        each of which is a single instruction.
+   * @return the program's return value.
+   * @throws Exception when program has unrecognised or 
+   *         invalid instructions, or when it returns no result when it finishes
+   */
+  int execute(List<String> instructions) 
+    throws InvalidInstructionException,
+	   NoReturnValueException
+  {
+
+    int instructionsExecuted = 0;
+    int pc = 0;
+    final int progLength = instructions.size();
+    while(true){
+      if (pc < 0 || pc >= progLength){
+	/* will cause NoReturnValueException to be thrown
+	 * but that is not a bug and and indeed is what the
+	 * VM is supposed to do if the pc becomes negative,
+	 * since in this case the program's execution
+	 * finishes early without a return value having
+	 * been produced. */
+	break;
+      }
+      String inst = instructions.get(pc);
+      /* strip leading and trailing whitespace */ 
+      inst = inst.toLowerCase().replaceAll("^\\s+","").replaceAll("\\s+$","");
+      /* strip out any comments */
+      String[] toks = inst.split(";");
+      inst = toks[0];
+
+      /* check for blank lines */
+      if (inst.equals("")){
+	pc = pc + 1;
+	count++;
+	continue;
+      }
+
+      instructionsExecuted++;
+      /* now  tokenize by splitting on whitespace */
+      toks = inst.split("\\s+");
+
+      /* check minimum number of tokens */
+      if (toks.length < 2){
+	throw new InvalidInstructionException();
+      }
+
+      if (toks[0].equals(INSTRUCTION_ADD)){
+	if (toks.length != 4){
+	  throw new InvalidInstructionException();
+	}
+	int rd = parseReg(toks[1]);
+	int rs1 = parseReg(toks[2]);
+	int rs2 = parseReg(toks[3]);
+	do_add(rd,rs1,rs2);
+      } else if (toks[0].equals(INSTRUCTION_SUBTRACT)){
+	if (toks.length != 4){
+	  throw new InvalidInstructionException();
+	}
+	int rd = parseReg(toks[1]);
+	int rs1 = parseReg(toks[2]);
+	int rs2 = parseReg(toks[3]);
+	do_sub(rd,rs1,rs2);
+      } else if (toks[0].equals(INSTRUCTION_MULT)){
+	if (toks.length != 4){
+	  throw new InvalidInstructionException();
+	}
+	int rd = parseReg(toks[1]);
+	int rs1 = parseReg(toks[2]);
+	int rs2 = parseReg(toks[3]);
+	do_mult(rd,rs1,rs2);
+      } else if (toks[0].equals(INSTRUCTION_DIVIDE)){
+	if (toks.length != 4){
+	  throw new InvalidInstructionException();
+	}
+	int rd = parseReg(toks[1]);
+	int rs1 = parseReg(toks[2]);
+	int rs2 = parseReg(toks[3]);
+	do_div(rd,rs1,rs2);
+      } else if (toks[0].equals(INSTRUCTION_RETURN)){
+	int rs = parseReg(toks[1]);
+	count++;
+	return regs[rs];
+      } else if (toks[0].equals(INSTRUCTION_LOAD)){
+	if (toks.length != 4){
+	  throw new InvalidInstructionException();
+	}
+	int rd = parseReg(toks[1]);
+	int rs = parseReg(toks[2]);
+	int offs = parseOffset(toks[3]);
+	do_load(rd,rs,offs);
+      } else if (toks[0].equals(INSTRUCTION_STORE)){
+	if (toks.length != 4){
+	  throw new InvalidInstructionException();
+	}
+	int ra = parseReg(toks[1]);
+	int offs = parseOffset(toks[2]);
+	int rb = parseReg(toks[3]);
+	do_store(ra,offs,rb);
+      } else if (toks[0].equals(INSTRUCTION_MOVE)){
+	if (toks.length != 3){
+	  throw new InvalidInstructionException();
+	}
+	int rd = parseReg(toks[1]);
+	int offs = parseOffset(toks[2]);
+	do_move(rd,offs);
+      } else if (toks[0].equals(INSTRUCTION_JUMP)){
+	if (toks.length != 2){
+	  throw new InvalidInstructionException();
+	}
+	int offs = parseOffset(toks[1]);
+	pc  = pc + offs;
+	count++;
+	continue; /* avoid default increment of pc below */
+      } else if (toks[0].equals(INSTRUCTION_JZ)){
+	if (toks.length != 3){
+	  throw new InvalidInstructionException();
+	}
+	int ra = parseReg(toks[1]);
+	int offs = parseOffset(toks[2]);
+	if (regs[ra] == 0){
+	  pc = pc + offs;
+	}else{
+	  pc = pc + 1;
+	}
+	count++;
+	continue; /* avoid default increment the pc below */
+      } else {
+	System.err.println("Unrecognised instruction: " + inst);
+	throw new InvalidInstructionException();
+      }
+      count++;
+      pc = pc + 1;
+    }
+
+    /* got here without returning already... */
+    throw new NoReturnValueException();
+  }
+
+  /**
+   * get the number of instructions successfully executed by the VM so far
+   */
+  public int getCount(){
+    return count;
+  }
+}
diff --git a/mutants/mutant-2/swen90006/machine/NoReturnValueException.java b/mutants/mutant-2/swen90006/machine/NoReturnValueException.java
new file mode 100644
index 0000000000000000000000000000000000000000..154907e85d6d8fa059da74d8fbfff17f29de28d3
--- /dev/null
+++ b/mutants/mutant-2/swen90006/machine/NoReturnValueException.java
@@ -0,0 +1,11 @@
+package swen90006.machine;
+
+public class NoReturnValueException extends RuntimeException
+{
+  public NoReturnValueException() {}
+
+  public String toString()
+  {
+    return "NoReturnValueException";
+  }
+}
diff --git a/mutants/mutant-2/swen90006/machine/SimpleDriver.java b/mutants/mutant-2/swen90006/machine/SimpleDriver.java
new file mode 100644
index 0000000000000000000000000000000000000000..bf288a4d2d3262d62316a7fa8adeb2a9f9a1dd6e
--- /dev/null
+++ b/mutants/mutant-2/swen90006/machine/SimpleDriver.java
@@ -0,0 +1,51 @@
+package swen90006.machine;
+
+import java.nio.charset.Charset;
+import java.nio.file.Path;
+import java.nio.file.Files;
+import java.nio.file.FileSystems;
+import java.util.List;
+
+public class SimpleDriver {
+
+    private static final int MEMORY_SIZE = Machine.MAX_ADDR+1;
+    
+    public static void main(String[] args) throws Exception
+    {
+        if (args.length != 1){
+            System.err.println("Usage: java SimpleDriver <inputfile>");
+	    System.err.println("\nMust have 1 argument instead of " + args.length);
+            System.exit(1);
+        }
+
+        Charset charset = Charset.forName("UTF-8");
+
+        List<String> lines = null;
+        try {
+            lines = Files.readAllLines(FileSystems.getDefault().getPath(args[0]), charset);
+        }catch (Exception e){
+            System.err.println("Invalid input file! (stacktrace follows)");
+            e.printStackTrace(System.err);
+            System.exit(1);
+        }
+
+        Machine m = null;
+        try {
+            System.out.println("There are this many instructions: " + lines.size());
+
+            m = new Machine();
+            
+            Integer res = null;
+            res = m.execute(lines);
+            System.out.println("Program result: " + res + "\n");
+
+        } catch (Exception e) {
+            System.err.println("Exception while executing program. (stacktrace follows)");
+            e.printStackTrace(System.err);
+            if (m != null){
+                System.err.println("Number of instructions executed before exception: " + m.getCount());
+            }
+            System.exit(1);
+        }
+    }
+}
diff --git a/mutants/mutant-3/swen90006/machine/BugException.java b/mutants/mutant-3/swen90006/machine/BugException.java
new file mode 100644
index 0000000000000000000000000000000000000000..41cb9cab9f4bb06efde089f190abc13331b00b21
--- /dev/null
+++ b/mutants/mutant-3/swen90006/machine/BugException.java
@@ -0,0 +1,7 @@
+package swen90006.machine;
+
+public class BugException extends Exception {
+    public BugException(String msg){
+        super("You triggered one of the security bugs!\n" + msg);
+    }
+}
diff --git a/mutants/mutant-3/swen90006/machine/InvalidInstructionException.java b/mutants/mutant-3/swen90006/machine/InvalidInstructionException.java
new file mode 100644
index 0000000000000000000000000000000000000000..25e042bfb4bf0519927e165946fa9d03640c45fe
--- /dev/null
+++ b/mutants/mutant-3/swen90006/machine/InvalidInstructionException.java
@@ -0,0 +1,9 @@
+package swen90006.machine;
+
+public class InvalidInstructionException extends RuntimeException
+{
+  public String toString()
+  {
+      return "InvalidInstructionException";
+  }
+}
diff --git a/mutants/mutant-3/swen90006/machine/Machine.java b/mutants/mutant-3/swen90006/machine/Machine.java
new file mode 100644
index 0000000000000000000000000000000000000000..9bf57316d1c736ea2bd1c62bd6df3c6c0282f331
--- /dev/null
+++ b/mutants/mutant-3/swen90006/machine/Machine.java
@@ -0,0 +1,303 @@
+package swen90006.machine;
+
+import java.util.Arrays;
+import java.util.List;
+
+public class Machine 
+{
+  /** arithmetic instructions each take three registers as arguments with the
+   *  destination register appearing first
+   */
+
+  /** add rd rs1 rs2   =~   rd = rs1 + rs2 */
+  public static final String INSTRUCTION_ADD = "add";
+
+  /** sub rd rs1 rs2   =~   rd = rs1 - rs2 */    
+  public static final String INSTRUCTION_SUBTRACT = "sub";
+
+  /** mul rd rs1 rs2   =~   rd = rs1 * rs2 */        
+  public static final String INSTRUCTION_MULT = "mul";
+
+  /** div rd rs1 rs2   =~   rd = rs1 / rs2 */            
+  public static final String INSTRUCTION_DIVIDE = "div";
+
+  /** ret rs           =~   return rs */
+  public static final String INSTRUCTION_RETURN = "ret";
+
+  /** ldr rd rs offs  =~    rd = rs[offs] */
+  public static final String INSTRUCTION_LOAD = "ldr";
+
+  /** str ra offs rb   =~    ra[offs] = rb */
+  public static final String INSTRUCTION_STORE = "str";
+
+  /** mov rd val       =~    rd = val */
+  public static final String INSTRUCTION_MOVE = "mov";
+
+  /** jmp offs         =~    pc = pc + offs */
+  public static final String INSTRUCTION_JUMP = "jmp";
+
+  /** jz ra offs       =~   if (ra == 0) pc = pc + offs else pc = pc + 1 */
+  public static final String INSTRUCTION_JZ = "jz";
+    
+  public static final int NUM_REGS = 32;
+  public static final int MAX_REG = (NUM_REGS - 1);
+  public static final int MEMORY_SIZE = 65536; /* 4 x as much memory as a 64 */
+  public static final int MAX_ADDR = MEMORY_SIZE-1;
+    
+  private int[] memory;
+  private int[] regs;
+
+  private int count = 0; /* counts number of instructions executed so far */
+    
+  public Machine()
+  {
+    memory = new int[MEMORY_SIZE];
+    regs = new int[NUM_REGS];
+    count = 0;
+  }
+
+  private void do_add(int dest, int src1, int src2)
+  {
+    regs[dest] = regs[src1] + regs[src2];
+  }
+    
+  private void do_sub(int dest, int src1, int src2)
+  {
+    regs[dest] = regs[src1] - regs[src2];
+  }
+    
+  private void do_mult(int dest, int src1, int src2)
+  {
+    regs[dest] = regs[src1] * regs[src2];
+  }
+    
+  private void do_div(int dest, int src1, int src2)
+  {
+    if (regs[src2] == 0){
+      /* no op */
+    }else{
+      regs[dest] = regs[src1] / regs[src2];
+    }
+  }
+
+  private void do_load(int dest, int src, int offs) {
+    if (regs[src] + offs > MAX_ADDR){
+      /* no op */
+    }else if(regs[src] + offs < 0){
+      /* no op */
+    }else{
+      regs[dest] = memory[regs[src] + offs];
+    }
+  }
+
+  private void do_store(int a, int offs, int b)  {
+    if (regs[a] + offs > MAX_ADDR){
+      /* no op */
+    }else if(regs[a] + offs < 0){
+      /* no op */
+    }else{
+      memory[regs[a] + offs] = regs[b];
+    }
+  }
+
+  private void do_move(int rd, int val){
+    regs[rd] = val;
+  }
+
+  private int parseReg(String s) throws InvalidInstructionException
+  {
+    if (s.length() < 2){
+      throw new InvalidInstructionException();
+    }
+    if (s.charAt(0) != 'r'){
+      throw new InvalidInstructionException();
+    }
+    String numstr = s.substring(1);
+    int num = 0;
+    try {
+      num = Integer.parseInt(numstr);
+    } catch (Exception e){
+      throw new InvalidInstructionException();
+    }
+    validate_reg(num);
+    return num;
+  }
+
+  private int parseOffset(String s)
+    throws InvalidInstructionException
+  {
+    int num = 0;
+    try {
+      num = Integer.parseInt(s);
+    } catch (Exception e){
+      throw new InvalidInstructionException();
+    }
+    validate_offset(num);
+    return num;
+  }
+
+
+  private void validate_reg(int reg)
+    throws InvalidInstructionException
+  {
+    if (reg < 0 || reg > MAX_REG) {
+      throw new InvalidInstructionException();
+    }
+  }
+
+  private void validate_offset(int offset)
+    throws InvalidInstructionException
+  {
+    if (offset < -MAX_ADDR || offset > MAX_ADDR) {
+      throw new InvalidInstructionException();
+    }
+  }
+    
+  /** Execute an assembly program.
+   *
+   * @param prog is the program to execute as an iterable collection of strings, 
+   *        each of which is a single instruction.
+   * @return the program's return value.
+   * @throws Exception when program has unrecognised or 
+   *         invalid instructions, or when it returns no result when it finishes
+   */
+  int execute(List<String> instructions) 
+    throws InvalidInstructionException,
+	   NoReturnValueException
+  {
+
+    int instructionsExecuted = 0;
+    int pc = 0;
+    final int progLength = instructions.size();
+    while(true){
+      if (pc < 0 || pc >= progLength){
+	/* will cause NoReturnValueException to be thrown
+	 * but that is not a bug and and indeed is what the
+	 * VM is supposed to do if the pc becomes negative,
+	 * since in this case the program's execution
+	 * finishes early without a return value having
+	 * been produced. */
+	break;
+      }
+      String inst = instructions.get(pc);
+      /* strip leading and trailing whitespace */ 
+      inst = inst.toLowerCase().replaceAll("^\\s+","").replaceAll("\\s+$","");
+      /* strip out any comments */
+      String[] toks = inst.split(";");
+      inst = toks[0];
+
+      /* check for blank lines */
+      if (inst.equals("")){
+	pc = pc + 1;
+	count++;
+	continue;
+      }
+
+      instructionsExecuted++;
+      /* now  tokenize by splitting on whitespace */
+      toks = inst.split("\\s+");
+
+      /* check minimum number of tokens */
+      if (toks.length < 2){
+	throw new InvalidInstructionException();
+      }
+
+      if (toks[0].equals(INSTRUCTION_ADD)){
+	if (toks.length != 4){
+	  throw new InvalidInstructionException();
+	}
+	int rd = parseReg(toks[1]);
+	int rs1 = parseReg(toks[2]);
+	int rs2 = parseReg(toks[3]);
+	do_add(rd,rs1,rs2);
+      } else if (toks[0].equals(INSTRUCTION_SUBTRACT)){
+	if (toks.length != 4){
+	  throw new InvalidInstructionException();
+	}
+	int rd = parseReg(toks[1]);
+	int rs1 = parseReg(toks[2]);
+	int rs2 = parseReg(toks[3]);
+	do_sub(rd,rs1,rs2);
+      } else if (toks[0].equals(INSTRUCTION_MULT)){
+	if (toks.length != 4){
+	  throw new InvalidInstructionException();
+	}
+	int rd = parseReg(toks[1]);
+	int rs1 = parseReg(toks[2]);
+	int rs2 = parseReg(toks[3]);
+	do_mult(rd,rs1,rs2);
+      } else if (toks[0].equals(INSTRUCTION_DIVIDE)){
+	if (toks.length != 4){
+	  throw new InvalidInstructionException();
+	}
+	int rd = parseReg(toks[1]);
+	int rs1 = parseReg(toks[2]);
+	int rs2 = parseReg(toks[3]);
+	do_div(rd,rs1,rs2);
+      } else if (toks[0].equals(INSTRUCTION_RETURN)){
+	int rs = parseReg(toks[1]);
+	count++;
+	return regs[rs];
+      } else if (toks[0].equals(INSTRUCTION_LOAD)){
+	if (toks.length != 4){
+	  throw new InvalidInstructionException();
+	}
+	int rd = parseReg(toks[1]);
+	int rs = parseReg(toks[2]);
+	int offs = parseOffset(toks[3]);
+	do_load(rd,rs,offs);
+      } else if (toks[0].equals(INSTRUCTION_STORE)){
+	if (toks.length != 4){
+	  throw new InvalidInstructionException();
+	}
+	int ra = parseReg(toks[1]);
+	int offs = parseOffset(toks[2]);
+	int rb = parseReg(toks[3]);
+	do_store(ra,offs,rb);
+      } else if (toks[0].equals(INSTRUCTION_MOVE)){
+	if (toks.length != 3){
+	  throw new InvalidInstructionException();
+	}
+	int rd = parseReg(toks[1]);
+	int offs = parseOffset(toks[2]);
+	do_move(rd,offs);
+      } else if (toks[0].equals(INSTRUCTION_JUMP)){
+	if (toks.length != 2){
+	  throw new InvalidInstructionException();
+	}
+	int offs = parseOffset(toks[1]);
+	pc  = pc + offs;
+	count++;
+	continue; /* avoid default increment of pc below */
+      } else if (toks[0].equals(INSTRUCTION_JZ)){
+	if (toks.length != 3){
+	  throw new InvalidInstructionException();
+	}
+	int ra = parseReg(toks[1]);
+	int offs = parseOffset(toks[2]);
+	if (regs[ra] == 0){
+	  pc = pc + offs;
+	}else{
+	  pc = pc + 1;
+	}
+	count++;
+	continue; /* avoid default increment the pc below */
+      } else {
+	System.err.println("Unrecognised instruction: " + inst);
+	throw new InvalidInstructionException();
+      }
+      count++;
+      pc = pc + 1;
+    }
+
+    /* got here without returning already... */
+    throw new NoReturnValueException();
+  }
+
+  /**
+   * get the number of instructions successfully executed by the VM so far
+   */
+  public int getCount(){
+    return count;
+  }
+}
diff --git a/mutants/mutant-3/swen90006/machine/NoReturnValueException.java b/mutants/mutant-3/swen90006/machine/NoReturnValueException.java
new file mode 100644
index 0000000000000000000000000000000000000000..154907e85d6d8fa059da74d8fbfff17f29de28d3
--- /dev/null
+++ b/mutants/mutant-3/swen90006/machine/NoReturnValueException.java
@@ -0,0 +1,11 @@
+package swen90006.machine;
+
+public class NoReturnValueException extends RuntimeException
+{
+  public NoReturnValueException() {}
+
+  public String toString()
+  {
+    return "NoReturnValueException";
+  }
+}
diff --git a/mutants/mutant-3/swen90006/machine/SimpleDriver.java b/mutants/mutant-3/swen90006/machine/SimpleDriver.java
new file mode 100644
index 0000000000000000000000000000000000000000..bf288a4d2d3262d62316a7fa8adeb2a9f9a1dd6e
--- /dev/null
+++ b/mutants/mutant-3/swen90006/machine/SimpleDriver.java
@@ -0,0 +1,51 @@
+package swen90006.machine;
+
+import java.nio.charset.Charset;
+import java.nio.file.Path;
+import java.nio.file.Files;
+import java.nio.file.FileSystems;
+import java.util.List;
+
+public class SimpleDriver {
+
+    private static final int MEMORY_SIZE = Machine.MAX_ADDR+1;
+    
+    public static void main(String[] args) throws Exception
+    {
+        if (args.length != 1){
+            System.err.println("Usage: java SimpleDriver <inputfile>");
+	    System.err.println("\nMust have 1 argument instead of " + args.length);
+            System.exit(1);
+        }
+
+        Charset charset = Charset.forName("UTF-8");
+
+        List<String> lines = null;
+        try {
+            lines = Files.readAllLines(FileSystems.getDefault().getPath(args[0]), charset);
+        }catch (Exception e){
+            System.err.println("Invalid input file! (stacktrace follows)");
+            e.printStackTrace(System.err);
+            System.exit(1);
+        }
+
+        Machine m = null;
+        try {
+            System.out.println("There are this many instructions: " + lines.size());
+
+            m = new Machine();
+            
+            Integer res = null;
+            res = m.execute(lines);
+            System.out.println("Program result: " + res + "\n");
+
+        } catch (Exception e) {
+            System.err.println("Exception while executing program. (stacktrace follows)");
+            e.printStackTrace(System.err);
+            if (m != null){
+                System.err.println("Number of instructions executed before exception: " + m.getCount());
+            }
+            System.exit(1);
+        }
+    }
+}
diff --git a/mutants/mutant-4/swen90006/machine/BugException.java b/mutants/mutant-4/swen90006/machine/BugException.java
new file mode 100644
index 0000000000000000000000000000000000000000..41cb9cab9f4bb06efde089f190abc13331b00b21
--- /dev/null
+++ b/mutants/mutant-4/swen90006/machine/BugException.java
@@ -0,0 +1,7 @@
+package swen90006.machine;
+
+public class BugException extends Exception {
+    public BugException(String msg){
+        super("You triggered one of the security bugs!\n" + msg);
+    }
+}
diff --git a/mutants/mutant-4/swen90006/machine/InvalidInstructionException.java b/mutants/mutant-4/swen90006/machine/InvalidInstructionException.java
new file mode 100644
index 0000000000000000000000000000000000000000..25e042bfb4bf0519927e165946fa9d03640c45fe
--- /dev/null
+++ b/mutants/mutant-4/swen90006/machine/InvalidInstructionException.java
@@ -0,0 +1,9 @@
+package swen90006.machine;
+
+public class InvalidInstructionException extends RuntimeException
+{
+  public String toString()
+  {
+      return "InvalidInstructionException";
+  }
+}
diff --git a/mutants/mutant-4/swen90006/machine/Machine.java b/mutants/mutant-4/swen90006/machine/Machine.java
new file mode 100644
index 0000000000000000000000000000000000000000..9bf57316d1c736ea2bd1c62bd6df3c6c0282f331
--- /dev/null
+++ b/mutants/mutant-4/swen90006/machine/Machine.java
@@ -0,0 +1,303 @@
+package swen90006.machine;
+
+import java.util.Arrays;
+import java.util.List;
+
+public class Machine 
+{
+  /** arithmetic instructions each take three registers as arguments with the
+   *  destination register appearing first
+   */
+
+  /** add rd rs1 rs2   =~   rd = rs1 + rs2 */
+  public static final String INSTRUCTION_ADD = "add";
+
+  /** sub rd rs1 rs2   =~   rd = rs1 - rs2 */    
+  public static final String INSTRUCTION_SUBTRACT = "sub";
+
+  /** mul rd rs1 rs2   =~   rd = rs1 * rs2 */        
+  public static final String INSTRUCTION_MULT = "mul";
+
+  /** div rd rs1 rs2   =~   rd = rs1 / rs2 */            
+  public static final String INSTRUCTION_DIVIDE = "div";
+
+  /** ret rs           =~   return rs */
+  public static final String INSTRUCTION_RETURN = "ret";
+
+  /** ldr rd rs offs  =~    rd = rs[offs] */
+  public static final String INSTRUCTION_LOAD = "ldr";
+
+  /** str ra offs rb   =~    ra[offs] = rb */
+  public static final String INSTRUCTION_STORE = "str";
+
+  /** mov rd val       =~    rd = val */
+  public static final String INSTRUCTION_MOVE = "mov";
+
+  /** jmp offs         =~    pc = pc + offs */
+  public static final String INSTRUCTION_JUMP = "jmp";
+
+  /** jz ra offs       =~   if (ra == 0) pc = pc + offs else pc = pc + 1 */
+  public static final String INSTRUCTION_JZ = "jz";
+    
+  public static final int NUM_REGS = 32;
+  public static final int MAX_REG = (NUM_REGS - 1);
+  public static final int MEMORY_SIZE = 65536; /* 4 x as much memory as a 64 */
+  public static final int MAX_ADDR = MEMORY_SIZE-1;
+    
+  private int[] memory;
+  private int[] regs;
+
+  private int count = 0; /* counts number of instructions executed so far */
+    
+  public Machine()
+  {
+    memory = new int[MEMORY_SIZE];
+    regs = new int[NUM_REGS];
+    count = 0;
+  }
+
+  private void do_add(int dest, int src1, int src2)
+  {
+    regs[dest] = regs[src1] + regs[src2];
+  }
+    
+  private void do_sub(int dest, int src1, int src2)
+  {
+    regs[dest] = regs[src1] - regs[src2];
+  }
+    
+  private void do_mult(int dest, int src1, int src2)
+  {
+    regs[dest] = regs[src1] * regs[src2];
+  }
+    
+  private void do_div(int dest, int src1, int src2)
+  {
+    if (regs[src2] == 0){
+      /* no op */
+    }else{
+      regs[dest] = regs[src1] / regs[src2];
+    }
+  }
+
+  private void do_load(int dest, int src, int offs) {
+    if (regs[src] + offs > MAX_ADDR){
+      /* no op */
+    }else if(regs[src] + offs < 0){
+      /* no op */
+    }else{
+      regs[dest] = memory[regs[src] + offs];
+    }
+  }
+
+  private void do_store(int a, int offs, int b)  {
+    if (regs[a] + offs > MAX_ADDR){
+      /* no op */
+    }else if(regs[a] + offs < 0){
+      /* no op */
+    }else{
+      memory[regs[a] + offs] = regs[b];
+    }
+  }
+
+  private void do_move(int rd, int val){
+    regs[rd] = val;
+  }
+
+  private int parseReg(String s) throws InvalidInstructionException
+  {
+    if (s.length() < 2){
+      throw new InvalidInstructionException();
+    }
+    if (s.charAt(0) != 'r'){
+      throw new InvalidInstructionException();
+    }
+    String numstr = s.substring(1);
+    int num = 0;
+    try {
+      num = Integer.parseInt(numstr);
+    } catch (Exception e){
+      throw new InvalidInstructionException();
+    }
+    validate_reg(num);
+    return num;
+  }
+
+  private int parseOffset(String s)
+    throws InvalidInstructionException
+  {
+    int num = 0;
+    try {
+      num = Integer.parseInt(s);
+    } catch (Exception e){
+      throw new InvalidInstructionException();
+    }
+    validate_offset(num);
+    return num;
+  }
+
+
+  private void validate_reg(int reg)
+    throws InvalidInstructionException
+  {
+    if (reg < 0 || reg > MAX_REG) {
+      throw new InvalidInstructionException();
+    }
+  }
+
+  private void validate_offset(int offset)
+    throws InvalidInstructionException
+  {
+    if (offset < -MAX_ADDR || offset > MAX_ADDR) {
+      throw new InvalidInstructionException();
+    }
+  }
+    
+  /** Execute an assembly program.
+   *
+   * @param prog is the program to execute as an iterable collection of strings, 
+   *        each of which is a single instruction.
+   * @return the program's return value.
+   * @throws Exception when program has unrecognised or 
+   *         invalid instructions, or when it returns no result when it finishes
+   */
+  int execute(List<String> instructions) 
+    throws InvalidInstructionException,
+	   NoReturnValueException
+  {
+
+    int instructionsExecuted = 0;
+    int pc = 0;
+    final int progLength = instructions.size();
+    while(true){
+      if (pc < 0 || pc >= progLength){
+	/* will cause NoReturnValueException to be thrown
+	 * but that is not a bug and and indeed is what the
+	 * VM is supposed to do if the pc becomes negative,
+	 * since in this case the program's execution
+	 * finishes early without a return value having
+	 * been produced. */
+	break;
+      }
+      String inst = instructions.get(pc);
+      /* strip leading and trailing whitespace */ 
+      inst = inst.toLowerCase().replaceAll("^\\s+","").replaceAll("\\s+$","");
+      /* strip out any comments */
+      String[] toks = inst.split(";");
+      inst = toks[0];
+
+      /* check for blank lines */
+      if (inst.equals("")){
+	pc = pc + 1;
+	count++;
+	continue;
+      }
+
+      instructionsExecuted++;
+      /* now  tokenize by splitting on whitespace */
+      toks = inst.split("\\s+");
+
+      /* check minimum number of tokens */
+      if (toks.length < 2){
+	throw new InvalidInstructionException();
+      }
+
+      if (toks[0].equals(INSTRUCTION_ADD)){
+	if (toks.length != 4){
+	  throw new InvalidInstructionException();
+	}
+	int rd = parseReg(toks[1]);
+	int rs1 = parseReg(toks[2]);
+	int rs2 = parseReg(toks[3]);
+	do_add(rd,rs1,rs2);
+      } else if (toks[0].equals(INSTRUCTION_SUBTRACT)){
+	if (toks.length != 4){
+	  throw new InvalidInstructionException();
+	}
+	int rd = parseReg(toks[1]);
+	int rs1 = parseReg(toks[2]);
+	int rs2 = parseReg(toks[3]);
+	do_sub(rd,rs1,rs2);
+      } else if (toks[0].equals(INSTRUCTION_MULT)){
+	if (toks.length != 4){
+	  throw new InvalidInstructionException();
+	}
+	int rd = parseReg(toks[1]);
+	int rs1 = parseReg(toks[2]);
+	int rs2 = parseReg(toks[3]);
+	do_mult(rd,rs1,rs2);
+      } else if (toks[0].equals(INSTRUCTION_DIVIDE)){
+	if (toks.length != 4){
+	  throw new InvalidInstructionException();
+	}
+	int rd = parseReg(toks[1]);
+	int rs1 = parseReg(toks[2]);
+	int rs2 = parseReg(toks[3]);
+	do_div(rd,rs1,rs2);
+      } else if (toks[0].equals(INSTRUCTION_RETURN)){
+	int rs = parseReg(toks[1]);
+	count++;
+	return regs[rs];
+      } else if (toks[0].equals(INSTRUCTION_LOAD)){
+	if (toks.length != 4){
+	  throw new InvalidInstructionException();
+	}
+	int rd = parseReg(toks[1]);
+	int rs = parseReg(toks[2]);
+	int offs = parseOffset(toks[3]);
+	do_load(rd,rs,offs);
+      } else if (toks[0].equals(INSTRUCTION_STORE)){
+	if (toks.length != 4){
+	  throw new InvalidInstructionException();
+	}
+	int ra = parseReg(toks[1]);
+	int offs = parseOffset(toks[2]);
+	int rb = parseReg(toks[3]);
+	do_store(ra,offs,rb);
+      } else if (toks[0].equals(INSTRUCTION_MOVE)){
+	if (toks.length != 3){
+	  throw new InvalidInstructionException();
+	}
+	int rd = parseReg(toks[1]);
+	int offs = parseOffset(toks[2]);
+	do_move(rd,offs);
+      } else if (toks[0].equals(INSTRUCTION_JUMP)){
+	if (toks.length != 2){
+	  throw new InvalidInstructionException();
+	}
+	int offs = parseOffset(toks[1]);
+	pc  = pc + offs;
+	count++;
+	continue; /* avoid default increment of pc below */
+      } else if (toks[0].equals(INSTRUCTION_JZ)){
+	if (toks.length != 3){
+	  throw new InvalidInstructionException();
+	}
+	int ra = parseReg(toks[1]);
+	int offs = parseOffset(toks[2]);
+	if (regs[ra] == 0){
+	  pc = pc + offs;
+	}else{
+	  pc = pc + 1;
+	}
+	count++;
+	continue; /* avoid default increment the pc below */
+      } else {
+	System.err.println("Unrecognised instruction: " + inst);
+	throw new InvalidInstructionException();
+      }
+      count++;
+      pc = pc + 1;
+    }
+
+    /* got here without returning already... */
+    throw new NoReturnValueException();
+  }
+
+  /**
+   * get the number of instructions successfully executed by the VM so far
+   */
+  public int getCount(){
+    return count;
+  }
+}
diff --git a/mutants/mutant-4/swen90006/machine/NoReturnValueException.java b/mutants/mutant-4/swen90006/machine/NoReturnValueException.java
new file mode 100644
index 0000000000000000000000000000000000000000..154907e85d6d8fa059da74d8fbfff17f29de28d3
--- /dev/null
+++ b/mutants/mutant-4/swen90006/machine/NoReturnValueException.java
@@ -0,0 +1,11 @@
+package swen90006.machine;
+
+public class NoReturnValueException extends RuntimeException
+{
+  public NoReturnValueException() {}
+
+  public String toString()
+  {
+    return "NoReturnValueException";
+  }
+}
diff --git a/mutants/mutant-4/swen90006/machine/SimpleDriver.java b/mutants/mutant-4/swen90006/machine/SimpleDriver.java
new file mode 100644
index 0000000000000000000000000000000000000000..bf288a4d2d3262d62316a7fa8adeb2a9f9a1dd6e
--- /dev/null
+++ b/mutants/mutant-4/swen90006/machine/SimpleDriver.java
@@ -0,0 +1,51 @@
+package swen90006.machine;
+
+import java.nio.charset.Charset;
+import java.nio.file.Path;
+import java.nio.file.Files;
+import java.nio.file.FileSystems;
+import java.util.List;
+
+public class SimpleDriver {
+
+    private static final int MEMORY_SIZE = Machine.MAX_ADDR+1;
+    
+    public static void main(String[] args) throws Exception
+    {
+        if (args.length != 1){
+            System.err.println("Usage: java SimpleDriver <inputfile>");
+	    System.err.println("\nMust have 1 argument instead of " + args.length);
+            System.exit(1);
+        }
+
+        Charset charset = Charset.forName("UTF-8");
+
+        List<String> lines = null;
+        try {
+            lines = Files.readAllLines(FileSystems.getDefault().getPath(args[0]), charset);
+        }catch (Exception e){
+            System.err.println("Invalid input file! (stacktrace follows)");
+            e.printStackTrace(System.err);
+            System.exit(1);
+        }
+
+        Machine m = null;
+        try {
+            System.out.println("There are this many instructions: " + lines.size());
+
+            m = new Machine();
+            
+            Integer res = null;
+            res = m.execute(lines);
+            System.out.println("Program result: " + res + "\n");
+
+        } catch (Exception e) {
+            System.err.println("Exception while executing program. (stacktrace follows)");
+            e.printStackTrace(System.err);
+            if (m != null){
+                System.err.println("Number of instructions executed before exception: " + m.getCount());
+            }
+            System.exit(1);
+        }
+    }
+}
diff --git a/mutants/mutant-5/swen90006/machine/BugException.java b/mutants/mutant-5/swen90006/machine/BugException.java
new file mode 100644
index 0000000000000000000000000000000000000000..41cb9cab9f4bb06efde089f190abc13331b00b21
--- /dev/null
+++ b/mutants/mutant-5/swen90006/machine/BugException.java
@@ -0,0 +1,7 @@
+package swen90006.machine;
+
+public class BugException extends Exception {
+    public BugException(String msg){
+        super("You triggered one of the security bugs!\n" + msg);
+    }
+}
diff --git a/mutants/mutant-5/swen90006/machine/InvalidInstructionException.java b/mutants/mutant-5/swen90006/machine/InvalidInstructionException.java
new file mode 100644
index 0000000000000000000000000000000000000000..25e042bfb4bf0519927e165946fa9d03640c45fe
--- /dev/null
+++ b/mutants/mutant-5/swen90006/machine/InvalidInstructionException.java
@@ -0,0 +1,9 @@
+package swen90006.machine;
+
+public class InvalidInstructionException extends RuntimeException
+{
+  public String toString()
+  {
+      return "InvalidInstructionException";
+  }
+}
diff --git a/mutants/mutant-5/swen90006/machine/Machine.java b/mutants/mutant-5/swen90006/machine/Machine.java
new file mode 100644
index 0000000000000000000000000000000000000000..9bf57316d1c736ea2bd1c62bd6df3c6c0282f331
--- /dev/null
+++ b/mutants/mutant-5/swen90006/machine/Machine.java
@@ -0,0 +1,303 @@
+package swen90006.machine;
+
+import java.util.Arrays;
+import java.util.List;
+
+public class Machine 
+{
+  /** arithmetic instructions each take three registers as arguments with the
+   *  destination register appearing first
+   */
+
+  /** add rd rs1 rs2   =~   rd = rs1 + rs2 */
+  public static final String INSTRUCTION_ADD = "add";
+
+  /** sub rd rs1 rs2   =~   rd = rs1 - rs2 */    
+  public static final String INSTRUCTION_SUBTRACT = "sub";
+
+  /** mul rd rs1 rs2   =~   rd = rs1 * rs2 */        
+  public static final String INSTRUCTION_MULT = "mul";
+
+  /** div rd rs1 rs2   =~   rd = rs1 / rs2 */            
+  public static final String INSTRUCTION_DIVIDE = "div";
+
+  /** ret rs           =~   return rs */
+  public static final String INSTRUCTION_RETURN = "ret";
+
+  /** ldr rd rs offs  =~    rd = rs[offs] */
+  public static final String INSTRUCTION_LOAD = "ldr";
+
+  /** str ra offs rb   =~    ra[offs] = rb */
+  public static final String INSTRUCTION_STORE = "str";
+
+  /** mov rd val       =~    rd = val */
+  public static final String INSTRUCTION_MOVE = "mov";
+
+  /** jmp offs         =~    pc = pc + offs */
+  public static final String INSTRUCTION_JUMP = "jmp";
+
+  /** jz ra offs       =~   if (ra == 0) pc = pc + offs else pc = pc + 1 */
+  public static final String INSTRUCTION_JZ = "jz";
+    
+  public static final int NUM_REGS = 32;
+  public static final int MAX_REG = (NUM_REGS - 1);
+  public static final int MEMORY_SIZE = 65536; /* 4 x as much memory as a 64 */
+  public static final int MAX_ADDR = MEMORY_SIZE-1;
+    
+  private int[] memory;
+  private int[] regs;
+
+  private int count = 0; /* counts number of instructions executed so far */
+    
+  public Machine()
+  {
+    memory = new int[MEMORY_SIZE];
+    regs = new int[NUM_REGS];
+    count = 0;
+  }
+
+  private void do_add(int dest, int src1, int src2)
+  {
+    regs[dest] = regs[src1] + regs[src2];
+  }
+    
+  private void do_sub(int dest, int src1, int src2)
+  {
+    regs[dest] = regs[src1] - regs[src2];
+  }
+    
+  private void do_mult(int dest, int src1, int src2)
+  {
+    regs[dest] = regs[src1] * regs[src2];
+  }
+    
+  private void do_div(int dest, int src1, int src2)
+  {
+    if (regs[src2] == 0){
+      /* no op */
+    }else{
+      regs[dest] = regs[src1] / regs[src2];
+    }
+  }
+
+  private void do_load(int dest, int src, int offs) {
+    if (regs[src] + offs > MAX_ADDR){
+      /* no op */
+    }else if(regs[src] + offs < 0){
+      /* no op */
+    }else{
+      regs[dest] = memory[regs[src] + offs];
+    }
+  }
+
+  private void do_store(int a, int offs, int b)  {
+    if (regs[a] + offs > MAX_ADDR){
+      /* no op */
+    }else if(regs[a] + offs < 0){
+      /* no op */
+    }else{
+      memory[regs[a] + offs] = regs[b];
+    }
+  }
+
+  private void do_move(int rd, int val){
+    regs[rd] = val;
+  }
+
+  private int parseReg(String s) throws InvalidInstructionException
+  {
+    if (s.length() < 2){
+      throw new InvalidInstructionException();
+    }
+    if (s.charAt(0) != 'r'){
+      throw new InvalidInstructionException();
+    }
+    String numstr = s.substring(1);
+    int num = 0;
+    try {
+      num = Integer.parseInt(numstr);
+    } catch (Exception e){
+      throw new InvalidInstructionException();
+    }
+    validate_reg(num);
+    return num;
+  }
+
+  private int parseOffset(String s)
+    throws InvalidInstructionException
+  {
+    int num = 0;
+    try {
+      num = Integer.parseInt(s);
+    } catch (Exception e){
+      throw new InvalidInstructionException();
+    }
+    validate_offset(num);
+    return num;
+  }
+
+
+  private void validate_reg(int reg)
+    throws InvalidInstructionException
+  {
+    if (reg < 0 || reg > MAX_REG) {
+      throw new InvalidInstructionException();
+    }
+  }
+
+  private void validate_offset(int offset)
+    throws InvalidInstructionException
+  {
+    if (offset < -MAX_ADDR || offset > MAX_ADDR) {
+      throw new InvalidInstructionException();
+    }
+  }
+    
+  /** Execute an assembly program.
+   *
+   * @param prog is the program to execute as an iterable collection of strings, 
+   *        each of which is a single instruction.
+   * @return the program's return value.
+   * @throws Exception when program has unrecognised or 
+   *         invalid instructions, or when it returns no result when it finishes
+   */
+  int execute(List<String> instructions) 
+    throws InvalidInstructionException,
+	   NoReturnValueException
+  {
+
+    int instructionsExecuted = 0;
+    int pc = 0;
+    final int progLength = instructions.size();
+    while(true){
+      if (pc < 0 || pc >= progLength){
+	/* will cause NoReturnValueException to be thrown
+	 * but that is not a bug and and indeed is what the
+	 * VM is supposed to do if the pc becomes negative,
+	 * since in this case the program's execution
+	 * finishes early without a return value having
+	 * been produced. */
+	break;
+      }
+      String inst = instructions.get(pc);
+      /* strip leading and trailing whitespace */ 
+      inst = inst.toLowerCase().replaceAll("^\\s+","").replaceAll("\\s+$","");
+      /* strip out any comments */
+      String[] toks = inst.split(";");
+      inst = toks[0];
+
+      /* check for blank lines */
+      if (inst.equals("")){
+	pc = pc + 1;
+	count++;
+	continue;
+      }
+
+      instructionsExecuted++;
+      /* now  tokenize by splitting on whitespace */
+      toks = inst.split("\\s+");
+
+      /* check minimum number of tokens */
+      if (toks.length < 2){
+	throw new InvalidInstructionException();
+      }
+
+      if (toks[0].equals(INSTRUCTION_ADD)){
+	if (toks.length != 4){
+	  throw new InvalidInstructionException();
+	}
+	int rd = parseReg(toks[1]);
+	int rs1 = parseReg(toks[2]);
+	int rs2 = parseReg(toks[3]);
+	do_add(rd,rs1,rs2);
+      } else if (toks[0].equals(INSTRUCTION_SUBTRACT)){
+	if (toks.length != 4){
+	  throw new InvalidInstructionException();
+	}
+	int rd = parseReg(toks[1]);
+	int rs1 = parseReg(toks[2]);
+	int rs2 = parseReg(toks[3]);
+	do_sub(rd,rs1,rs2);
+      } else if (toks[0].equals(INSTRUCTION_MULT)){
+	if (toks.length != 4){
+	  throw new InvalidInstructionException();
+	}
+	int rd = parseReg(toks[1]);
+	int rs1 = parseReg(toks[2]);
+	int rs2 = parseReg(toks[3]);
+	do_mult(rd,rs1,rs2);
+      } else if (toks[0].equals(INSTRUCTION_DIVIDE)){
+	if (toks.length != 4){
+	  throw new InvalidInstructionException();
+	}
+	int rd = parseReg(toks[1]);
+	int rs1 = parseReg(toks[2]);
+	int rs2 = parseReg(toks[3]);
+	do_div(rd,rs1,rs2);
+      } else if (toks[0].equals(INSTRUCTION_RETURN)){
+	int rs = parseReg(toks[1]);
+	count++;
+	return regs[rs];
+      } else if (toks[0].equals(INSTRUCTION_LOAD)){
+	if (toks.length != 4){
+	  throw new InvalidInstructionException();
+	}
+	int rd = parseReg(toks[1]);
+	int rs = parseReg(toks[2]);
+	int offs = parseOffset(toks[3]);
+	do_load(rd,rs,offs);
+      } else if (toks[0].equals(INSTRUCTION_STORE)){
+	if (toks.length != 4){
+	  throw new InvalidInstructionException();
+	}
+	int ra = parseReg(toks[1]);
+	int offs = parseOffset(toks[2]);
+	int rb = parseReg(toks[3]);
+	do_store(ra,offs,rb);
+      } else if (toks[0].equals(INSTRUCTION_MOVE)){
+	if (toks.length != 3){
+	  throw new InvalidInstructionException();
+	}
+	int rd = parseReg(toks[1]);
+	int offs = parseOffset(toks[2]);
+	do_move(rd,offs);
+      } else if (toks[0].equals(INSTRUCTION_JUMP)){
+	if (toks.length != 2){
+	  throw new InvalidInstructionException();
+	}
+	int offs = parseOffset(toks[1]);
+	pc  = pc + offs;
+	count++;
+	continue; /* avoid default increment of pc below */
+      } else if (toks[0].equals(INSTRUCTION_JZ)){
+	if (toks.length != 3){
+	  throw new InvalidInstructionException();
+	}
+	int ra = parseReg(toks[1]);
+	int offs = parseOffset(toks[2]);
+	if (regs[ra] == 0){
+	  pc = pc + offs;
+	}else{
+	  pc = pc + 1;
+	}
+	count++;
+	continue; /* avoid default increment the pc below */
+      } else {
+	System.err.println("Unrecognised instruction: " + inst);
+	throw new InvalidInstructionException();
+      }
+      count++;
+      pc = pc + 1;
+    }
+
+    /* got here without returning already... */
+    throw new NoReturnValueException();
+  }
+
+  /**
+   * get the number of instructions successfully executed by the VM so far
+   */
+  public int getCount(){
+    return count;
+  }
+}
diff --git a/mutants/mutant-5/swen90006/machine/NoReturnValueException.java b/mutants/mutant-5/swen90006/machine/NoReturnValueException.java
new file mode 100644
index 0000000000000000000000000000000000000000..154907e85d6d8fa059da74d8fbfff17f29de28d3
--- /dev/null
+++ b/mutants/mutant-5/swen90006/machine/NoReturnValueException.java
@@ -0,0 +1,11 @@
+package swen90006.machine;
+
+public class NoReturnValueException extends RuntimeException
+{
+  public NoReturnValueException() {}
+
+  public String toString()
+  {
+    return "NoReturnValueException";
+  }
+}
diff --git a/mutants/mutant-5/swen90006/machine/SimpleDriver.java b/mutants/mutant-5/swen90006/machine/SimpleDriver.java
new file mode 100644
index 0000000000000000000000000000000000000000..bf288a4d2d3262d62316a7fa8adeb2a9f9a1dd6e
--- /dev/null
+++ b/mutants/mutant-5/swen90006/machine/SimpleDriver.java
@@ -0,0 +1,51 @@
+package swen90006.machine;
+
+import java.nio.charset.Charset;
+import java.nio.file.Path;
+import java.nio.file.Files;
+import java.nio.file.FileSystems;
+import java.util.List;
+
+public class SimpleDriver {
+
+    private static final int MEMORY_SIZE = Machine.MAX_ADDR+1;
+    
+    public static void main(String[] args) throws Exception
+    {
+        if (args.length != 1){
+            System.err.println("Usage: java SimpleDriver <inputfile>");
+	    System.err.println("\nMust have 1 argument instead of " + args.length);
+            System.exit(1);
+        }
+
+        Charset charset = Charset.forName("UTF-8");
+
+        List<String> lines = null;
+        try {
+            lines = Files.readAllLines(FileSystems.getDefault().getPath(args[0]), charset);
+        }catch (Exception e){
+            System.err.println("Invalid input file! (stacktrace follows)");
+            e.printStackTrace(System.err);
+            System.exit(1);
+        }
+
+        Machine m = null;
+        try {
+            System.out.println("There are this many instructions: " + lines.size());
+
+            m = new Machine();
+            
+            Integer res = null;
+            res = m.execute(lines);
+            System.out.println("Program result: " + res + "\n");
+
+        } catch (Exception e) {
+            System.err.println("Exception while executing program. (stacktrace follows)");
+            e.printStackTrace(System.err);
+            if (m != null){
+                System.err.println("Number of instructions executed before exception: " + m.getCount());
+            }
+            System.exit(1);
+        }
+    }
+}
diff --git a/src/swen90006/machine/BugException.java b/src/swen90006/machine/BugException.java
new file mode 100644
index 0000000000000000000000000000000000000000..41cb9cab9f4bb06efde089f190abc13331b00b21
--- /dev/null
+++ b/src/swen90006/machine/BugException.java
@@ -0,0 +1,7 @@
+package swen90006.machine;
+
+public class BugException extends Exception {
+    public BugException(String msg){
+        super("You triggered one of the security bugs!\n" + msg);
+    }
+}
diff --git a/src/swen90006/machine/InvalidInstructionException.java b/src/swen90006/machine/InvalidInstructionException.java
new file mode 100644
index 0000000000000000000000000000000000000000..25e042bfb4bf0519927e165946fa9d03640c45fe
--- /dev/null
+++ b/src/swen90006/machine/InvalidInstructionException.java
@@ -0,0 +1,9 @@
+package swen90006.machine;
+
+public class InvalidInstructionException extends RuntimeException
+{
+  public String toString()
+  {
+      return "InvalidInstructionException";
+  }
+}
diff --git a/src/swen90006/machine/Machine.java b/src/swen90006/machine/Machine.java
new file mode 100644
index 0000000000000000000000000000000000000000..9bf57316d1c736ea2bd1c62bd6df3c6c0282f331
--- /dev/null
+++ b/src/swen90006/machine/Machine.java
@@ -0,0 +1,303 @@
+package swen90006.machine;
+
+import java.util.Arrays;
+import java.util.List;
+
+public class Machine 
+{
+  /** arithmetic instructions each take three registers as arguments with the
+   *  destination register appearing first
+   */
+
+  /** add rd rs1 rs2   =~   rd = rs1 + rs2 */
+  public static final String INSTRUCTION_ADD = "add";
+
+  /** sub rd rs1 rs2   =~   rd = rs1 - rs2 */    
+  public static final String INSTRUCTION_SUBTRACT = "sub";
+
+  /** mul rd rs1 rs2   =~   rd = rs1 * rs2 */        
+  public static final String INSTRUCTION_MULT = "mul";
+
+  /** div rd rs1 rs2   =~   rd = rs1 / rs2 */            
+  public static final String INSTRUCTION_DIVIDE = "div";
+
+  /** ret rs           =~   return rs */
+  public static final String INSTRUCTION_RETURN = "ret";
+
+  /** ldr rd rs offs  =~    rd = rs[offs] */
+  public static final String INSTRUCTION_LOAD = "ldr";
+
+  /** str ra offs rb   =~    ra[offs] = rb */
+  public static final String INSTRUCTION_STORE = "str";
+
+  /** mov rd val       =~    rd = val */
+  public static final String INSTRUCTION_MOVE = "mov";
+
+  /** jmp offs         =~    pc = pc + offs */
+  public static final String INSTRUCTION_JUMP = "jmp";
+
+  /** jz ra offs       =~   if (ra == 0) pc = pc + offs else pc = pc + 1 */
+  public static final String INSTRUCTION_JZ = "jz";
+    
+  public static final int NUM_REGS = 32;
+  public static final int MAX_REG = (NUM_REGS - 1);
+  public static final int MEMORY_SIZE = 65536; /* 4 x as much memory as a 64 */
+  public static final int MAX_ADDR = MEMORY_SIZE-1;
+    
+  private int[] memory;
+  private int[] regs;
+
+  private int count = 0; /* counts number of instructions executed so far */
+    
+  public Machine()
+  {
+    memory = new int[MEMORY_SIZE];
+    regs = new int[NUM_REGS];
+    count = 0;
+  }
+
+  private void do_add(int dest, int src1, int src2)
+  {
+    regs[dest] = regs[src1] + regs[src2];
+  }
+    
+  private void do_sub(int dest, int src1, int src2)
+  {
+    regs[dest] = regs[src1] - regs[src2];
+  }
+    
+  private void do_mult(int dest, int src1, int src2)
+  {
+    regs[dest] = regs[src1] * regs[src2];
+  }
+    
+  private void do_div(int dest, int src1, int src2)
+  {
+    if (regs[src2] == 0){
+      /* no op */
+    }else{
+      regs[dest] = regs[src1] / regs[src2];
+    }
+  }
+
+  private void do_load(int dest, int src, int offs) {
+    if (regs[src] + offs > MAX_ADDR){
+      /* no op */
+    }else if(regs[src] + offs < 0){
+      /* no op */
+    }else{
+      regs[dest] = memory[regs[src] + offs];
+    }
+  }
+
+  private void do_store(int a, int offs, int b)  {
+    if (regs[a] + offs > MAX_ADDR){
+      /* no op */
+    }else if(regs[a] + offs < 0){
+      /* no op */
+    }else{
+      memory[regs[a] + offs] = regs[b];
+    }
+  }
+
+  private void do_move(int rd, int val){
+    regs[rd] = val;
+  }
+
+  private int parseReg(String s) throws InvalidInstructionException
+  {
+    if (s.length() < 2){
+      throw new InvalidInstructionException();
+    }
+    if (s.charAt(0) != 'r'){
+      throw new InvalidInstructionException();
+    }
+    String numstr = s.substring(1);
+    int num = 0;
+    try {
+      num = Integer.parseInt(numstr);
+    } catch (Exception e){
+      throw new InvalidInstructionException();
+    }
+    validate_reg(num);
+    return num;
+  }
+
+  private int parseOffset(String s)
+    throws InvalidInstructionException
+  {
+    int num = 0;
+    try {
+      num = Integer.parseInt(s);
+    } catch (Exception e){
+      throw new InvalidInstructionException();
+    }
+    validate_offset(num);
+    return num;
+  }
+
+
+  private void validate_reg(int reg)
+    throws InvalidInstructionException
+  {
+    if (reg < 0 || reg > MAX_REG) {
+      throw new InvalidInstructionException();
+    }
+  }
+
+  private void validate_offset(int offset)
+    throws InvalidInstructionException
+  {
+    if (offset < -MAX_ADDR || offset > MAX_ADDR) {
+      throw new InvalidInstructionException();
+    }
+  }
+    
+  /** Execute an assembly program.
+   *
+   * @param prog is the program to execute as an iterable collection of strings, 
+   *        each of which is a single instruction.
+   * @return the program's return value.
+   * @throws Exception when program has unrecognised or 
+   *         invalid instructions, or when it returns no result when it finishes
+   */
+  int execute(List<String> instructions) 
+    throws InvalidInstructionException,
+	   NoReturnValueException
+  {
+
+    int instructionsExecuted = 0;
+    int pc = 0;
+    final int progLength = instructions.size();
+    while(true){
+      if (pc < 0 || pc >= progLength){
+	/* will cause NoReturnValueException to be thrown
+	 * but that is not a bug and and indeed is what the
+	 * VM is supposed to do if the pc becomes negative,
+	 * since in this case the program's execution
+	 * finishes early without a return value having
+	 * been produced. */
+	break;
+      }
+      String inst = instructions.get(pc);
+      /* strip leading and trailing whitespace */ 
+      inst = inst.toLowerCase().replaceAll("^\\s+","").replaceAll("\\s+$","");
+      /* strip out any comments */
+      String[] toks = inst.split(";");
+      inst = toks[0];
+
+      /* check for blank lines */
+      if (inst.equals("")){
+	pc = pc + 1;
+	count++;
+	continue;
+      }
+
+      instructionsExecuted++;
+      /* now  tokenize by splitting on whitespace */
+      toks = inst.split("\\s+");
+
+      /* check minimum number of tokens */
+      if (toks.length < 2){
+	throw new InvalidInstructionException();
+      }
+
+      if (toks[0].equals(INSTRUCTION_ADD)){
+	if (toks.length != 4){
+	  throw new InvalidInstructionException();
+	}
+	int rd = parseReg(toks[1]);
+	int rs1 = parseReg(toks[2]);
+	int rs2 = parseReg(toks[3]);
+	do_add(rd,rs1,rs2);
+      } else if (toks[0].equals(INSTRUCTION_SUBTRACT)){
+	if (toks.length != 4){
+	  throw new InvalidInstructionException();
+	}
+	int rd = parseReg(toks[1]);
+	int rs1 = parseReg(toks[2]);
+	int rs2 = parseReg(toks[3]);
+	do_sub(rd,rs1,rs2);
+      } else if (toks[0].equals(INSTRUCTION_MULT)){
+	if (toks.length != 4){
+	  throw new InvalidInstructionException();
+	}
+	int rd = parseReg(toks[1]);
+	int rs1 = parseReg(toks[2]);
+	int rs2 = parseReg(toks[3]);
+	do_mult(rd,rs1,rs2);
+      } else if (toks[0].equals(INSTRUCTION_DIVIDE)){
+	if (toks.length != 4){
+	  throw new InvalidInstructionException();
+	}
+	int rd = parseReg(toks[1]);
+	int rs1 = parseReg(toks[2]);
+	int rs2 = parseReg(toks[3]);
+	do_div(rd,rs1,rs2);
+      } else if (toks[0].equals(INSTRUCTION_RETURN)){
+	int rs = parseReg(toks[1]);
+	count++;
+	return regs[rs];
+      } else if (toks[0].equals(INSTRUCTION_LOAD)){
+	if (toks.length != 4){
+	  throw new InvalidInstructionException();
+	}
+	int rd = parseReg(toks[1]);
+	int rs = parseReg(toks[2]);
+	int offs = parseOffset(toks[3]);
+	do_load(rd,rs,offs);
+      } else if (toks[0].equals(INSTRUCTION_STORE)){
+	if (toks.length != 4){
+	  throw new InvalidInstructionException();
+	}
+	int ra = parseReg(toks[1]);
+	int offs = parseOffset(toks[2]);
+	int rb = parseReg(toks[3]);
+	do_store(ra,offs,rb);
+      } else if (toks[0].equals(INSTRUCTION_MOVE)){
+	if (toks.length != 3){
+	  throw new InvalidInstructionException();
+	}
+	int rd = parseReg(toks[1]);
+	int offs = parseOffset(toks[2]);
+	do_move(rd,offs);
+      } else if (toks[0].equals(INSTRUCTION_JUMP)){
+	if (toks.length != 2){
+	  throw new InvalidInstructionException();
+	}
+	int offs = parseOffset(toks[1]);
+	pc  = pc + offs;
+	count++;
+	continue; /* avoid default increment of pc below */
+      } else if (toks[0].equals(INSTRUCTION_JZ)){
+	if (toks.length != 3){
+	  throw new InvalidInstructionException();
+	}
+	int ra = parseReg(toks[1]);
+	int offs = parseOffset(toks[2]);
+	if (regs[ra] == 0){
+	  pc = pc + offs;
+	}else{
+	  pc = pc + 1;
+	}
+	count++;
+	continue; /* avoid default increment the pc below */
+      } else {
+	System.err.println("Unrecognised instruction: " + inst);
+	throw new InvalidInstructionException();
+      }
+      count++;
+      pc = pc + 1;
+    }
+
+    /* got here without returning already... */
+    throw new NoReturnValueException();
+  }
+
+  /**
+   * get the number of instructions successfully executed by the VM so far
+   */
+  public int getCount(){
+    return count;
+  }
+}
diff --git a/src/swen90006/machine/NoReturnValueException.java b/src/swen90006/machine/NoReturnValueException.java
new file mode 100644
index 0000000000000000000000000000000000000000..154907e85d6d8fa059da74d8fbfff17f29de28d3
--- /dev/null
+++ b/src/swen90006/machine/NoReturnValueException.java
@@ -0,0 +1,11 @@
+package swen90006.machine;
+
+public class NoReturnValueException extends RuntimeException
+{
+  public NoReturnValueException() {}
+
+  public String toString()
+  {
+    return "NoReturnValueException";
+  }
+}
diff --git a/src/swen90006/machine/SimpleDriver.java b/src/swen90006/machine/SimpleDriver.java
new file mode 100644
index 0000000000000000000000000000000000000000..bf288a4d2d3262d62316a7fa8adeb2a9f9a1dd6e
--- /dev/null
+++ b/src/swen90006/machine/SimpleDriver.java
@@ -0,0 +1,51 @@
+package swen90006.machine;
+
+import java.nio.charset.Charset;
+import java.nio.file.Path;
+import java.nio.file.Files;
+import java.nio.file.FileSystems;
+import java.util.List;
+
+public class SimpleDriver {
+
+    private static final int MEMORY_SIZE = Machine.MAX_ADDR+1;
+    
+    public static void main(String[] args) throws Exception
+    {
+        if (args.length != 1){
+            System.err.println("Usage: java SimpleDriver <inputfile>");
+	    System.err.println("\nMust have 1 argument instead of " + args.length);
+            System.exit(1);
+        }
+
+        Charset charset = Charset.forName("UTF-8");
+
+        List<String> lines = null;
+        try {
+            lines = Files.readAllLines(FileSystems.getDefault().getPath(args[0]), charset);
+        }catch (Exception e){
+            System.err.println("Invalid input file! (stacktrace follows)");
+            e.printStackTrace(System.err);
+            System.exit(1);
+        }
+
+        Machine m = null;
+        try {
+            System.out.println("There are this many instructions: " + lines.size());
+
+            m = new Machine();
+            
+            Integer res = null;
+            res = m.execute(lines);
+            System.out.println("Program result: " + res + "\n");
+
+        } catch (Exception e) {
+            System.err.println("Exception while executing program. (stacktrace follows)");
+            e.printStackTrace(System.err);
+            if (m != null){
+                System.err.println("Number of instructions executed before exception: " + m.getCount());
+            }
+            System.exit(1);
+        }
+    }
+}
diff --git a/test/swen90006/machine/BoundaryTests.java b/test/swen90006/machine/BoundaryTests.java
new file mode 100644
index 0000000000000000000000000000000000000000..61ce1ca647f325fbf452047408c1e22d9befcb99
--- /dev/null
+++ b/test/swen90006/machine/BoundaryTests.java
@@ -0,0 +1,90 @@
+package swen90006.machine;
+
+import java.util.List;
+import java.util.ArrayList;
+import java.nio.charset.Charset;
+import java.nio.file.Path;
+import java.nio.file.Files;
+import java.nio.file.FileSystems;
+
+import org.junit.*;
+import static org.junit.Assert.*;
+
+public class BoundaryTests
+{
+  //Any method annotated with "@Before" will be executed before each test,
+  //allowing the tester to set up some shared resources.
+  @Before public void setUp()
+  {
+  }
+
+  //Any method annotated with "@After" will be executed after each test,
+  //allowing the tester to release any shared resources used in the setup.
+  @After public void tearDown()
+  {
+  }
+
+  //Any method annotation with "@Test" is executed as a test.
+  @Test public void aTest()
+  {
+    //the assertEquals method used to check whether two values are
+    //equal, using the equals method
+    final int expected = 2;
+    final int actual = 1 + 1;
+    assertEquals(expected, actual);
+  }
+
+  @Test public void anotherTest()
+  {
+    List<String> list = new ArrayList<String>();
+    list.add("a");
+    list.add("b");
+
+    //the assertTrue method is used to check whether something holds.
+    assertTrue(list.contains("a"));
+  }
+
+  //Test test opens a file and executes the machine
+  @Test public void aFileOpenTest()
+  {
+    final List<String> lines = readInstructions("examples/array.s");
+    Machine m = new Machine();
+    assertEquals(m.execute(lines), 45);
+  }
+  
+  //To test an exception, specify the expected exception after the @Test
+  @Test(expected = java.io.IOException.class) 
+    public void anExceptionTest()
+    throws Throwable
+  {
+    throw new java.io.IOException();
+  }
+
+  //This test should fail.
+  //To provide additional feedback when a test fails, an error message
+  //can be included
+  @Test public void aFailedTest()
+  {
+    //include a message for better feedback
+    final int expected = 2;
+    final int actual = 1 + 2;
+    assertEquals("Some failure message", expected, actual);
+  }
+
+  //Read in a file containing a program and convert into a list of
+  //string instructions
+  private List<String> readInstructions(String file)
+  {
+    Charset charset = Charset.forName("UTF-8");
+    List<String> lines = null;
+    try {
+      lines = Files.readAllLines(FileSystems.getDefault().getPath(file), charset);
+    }
+    catch (Exception e){
+      System.err.println("Invalid input file! (stacktrace follows)");
+      e.printStackTrace(System.err);
+      System.exit(1);
+    }
+    return lines;
+  }
+}
diff --git a/test/swen90006/machine/PartitioningTests.java b/test/swen90006/machine/PartitioningTests.java
new file mode 100644
index 0000000000000000000000000000000000000000..5494b44f4615351a610fc7b0b649d30b4b2d0a40
--- /dev/null
+++ b/test/swen90006/machine/PartitioningTests.java
@@ -0,0 +1,90 @@
+package swen90006.machine;
+
+import java.util.List;
+import java.util.ArrayList;
+import java.nio.charset.Charset;
+import java.nio.file.Path;
+import java.nio.file.Files;
+import java.nio.file.FileSystems;
+
+import org.junit.*;
+import static org.junit.Assert.*;
+
+public class PartitioningTests
+{
+  //Any method annotated with "@Before" will be executed before each test,
+  //allowing the tester to set up some shared resources.
+  @Before public void setUp()
+  {
+  }
+
+  //Any method annotated with "@After" will be executed after each test,
+  //allowing the tester to release any shared resources used in the setup.
+  @After public void tearDown()
+  {
+  }
+
+  //Any method annotation with "@Test" is executed as a test.
+  @Test public void aTest()
+  {
+    //the assertEquals method used to check whether two values are
+    //equal, using the equals method
+    final int expected = 2;
+    final int actual = 1 + 1;
+    assertEquals(expected, actual);
+  }
+
+  @Test public void anotherTest()
+  {
+    List<String> list = new ArrayList<String>();
+    list.add("a");
+    list.add("b");
+
+    //the assertTrue method is used to check whether something holds.
+    assertTrue(list.contains("a"));
+  }
+
+  //Test test opens a file and executes the machine
+  @Test public void aFileOpenTest()
+  {
+    final List<String> lines = readInstructions("examples/array.s");
+    Machine m = new Machine();
+    assertEquals(m.execute(lines), 45);
+  }
+  
+  //To test an exception, specify the expected exception after the @Test
+  @Test(expected = java.io.IOException.class) 
+    public void anExceptionTest()
+    throws Throwable
+  {
+    throw new java.io.IOException();
+  }
+
+  //This test should fail.
+  //To provide additional feedback when a test fails, an error message
+  //can be included
+  @Test public void aFailedTest()
+  {
+    //include a message for better feedback
+    final int expected = 2;
+    final int actual = 1 + 2;
+    assertEquals("Some failure message", expected, actual);
+  }
+
+  //Read in a file containing a program and convert into a list of
+  //string instructions
+  private List<String> readInstructions(String file)
+  {
+    Charset charset = Charset.forName("UTF-8");
+    List<String> lines = null;
+    try {
+      lines = Files.readAllLines(FileSystems.getDefault().getPath(file), charset);
+    }
+    catch (Exception e){
+      System.err.println("Invalid input file! (stacktrace follows)");
+      e.printStackTrace(System.err);
+      System.exit(1);
+    }
+    return lines;
+  }
+}