use new genomix-data
diff --git a/genomix/genomix-data/src/main/java/edu/uci/ics/genomix/type/KmerBytesWritable.java b/genomix/genomix-data/src/main/java/edu/uci/ics/genomix/type/KmerBytesWritable.java
index c3e53e8..284c2e7 100644
--- a/genomix/genomix-data/src/main/java/edu/uci/ics/genomix/type/KmerBytesWritable.java
+++ b/genomix/genomix-data/src/main/java/edu/uci/ics/genomix/type/KmerBytesWritable.java
@@ -25,596 +25,584 @@
 import org.apache.hadoop.io.WritableComparator;
 
 import edu.uci.ics.genomix.data.KmerUtil;
+import edu.uci.ics.genomix.data.Marshal;
 import edu.uci.ics.genomix.oldtype.NodeWritable.DirectionFlag;
 
 /**
- * Variable kmer length byteswritable
- * It was used to generate the graph in which phase the kmer length doesn't change.
- * Thus the kmerByteSize of bytes doesn't change either.
+ * Variable kmer length byteswritable It was used to generate the graph in which
+ * phase the kmer length doesn't change. Thus the kmerByteSize of bytes doesn't
+ * change either.
  */
-public class KmerBytesWritable extends BinaryComparable implements Serializable, WritableComparable<BinaryComparable> {
-    /**
+public class KmerBytesWritable extends BinaryComparable implements
+		Serializable, WritableComparable<BinaryComparable> {
+
+	private static final long serialVersionUID = 1L;
+	protected static final byte[] EMPTY_BYTES = {};
+
+	protected int lettersInKmer;
+	protected int bytesUsed;
+	protected byte[] bytes;
+	protected int offset;
+
+	/**
+	 * Initialize as empty kmer
+	 */
+	public KmerBytesWritable() {
+		this(0, EMPTY_BYTES, 0);
+	}
+
+	/**
+	 * Copy contents of kmer string
+	 */
+	public KmerBytesWritable(String kmer) {
+		setAsCopy(kmer);
+	}
+
+	/**
+	 * Set as reference to given data
+	 */
+	public KmerBytesWritable(int k, byte[] storage, int offset) {
+		setAsReference(k, storage, offset);
+	}
+
+	/**
+	 * Reserve space for k letters
+	 */
+	public KmerBytesWritable(int k) {
+		if (k > 0) {
+			this.bytes = new byte[KmerUtil.getByteNumFromK(k)];
+		} else {
+			this.bytes = EMPTY_BYTES;
+		}
+		this.offset = 0;
+		setKmerLength(k);
+	}
+
+	/**
+	 * copy kmer in other
+	 * 
+	 * @param other
+	 */
+	public KmerBytesWritable(KmerBytesWritable other) {
+		this(other.lettersInKmer);
+		setAsCopy(other);
+	}
+
+	/**
+	 * Deep copy of the given kmer
+	 * 
+	 * @param other
+	 */
+	public void setAsCopy(KmerBytesWritable other) {
+		reset(other.lettersInKmer);
+		if (lettersInKmer > 0) {
+			System.arraycopy(other.bytes, other.offset, bytes, this.offset,
+					bytesUsed);
+		}
+	}
+
+	/**
+	 * set from String kmer
+	 */
+	public void setAsCopy(String kmer) {
+		setKmerLength(kmer.length());
+		bytes = kmer.getBytes();
+		offset = 0;
+	}
+
+	/**
+	 * Deep copy of the given bytes data
+	 * 
+	 * @param newData
+	 * @param offset
+	 */
+	public void setAsCopy(int k, byte[] newData, int offset) {
+		reset(k);
+		System.arraycopy(newData, offset, bytes, this.offset, k);
+	}
+
+	/**
+	 * Reset array by kmerlength
+	 * 
+	 * @param k
+	 */
+	public void reset(int k) {
+		setKmerLength(k);
+		setSize(bytesUsed);
+		clearLeadBit();
+	}
+
+	/**
+	 * Point this datablock to the given bytes array It works like the pointer
+	 * to new datablock.
+	 * 
+	 * @param newData
+	 * @param offset
+	 */
+	public void setAsReference(int k, byte[] newData, int offset) {
+		this.bytes = newData;
+		this.offset = offset;
+		// my java skills are lacking. In inherited classes with a header, this
+		// will use the header version...
+		// setKmerLength(k);
+		bytesUsed = KmerUtil.getByteNumFromK(k);
+		lettersInKmer = k;
+		if (newData.length - offset < bytesUsed) {
+			throw new IllegalArgumentException("Requested " + bytesUsed
+					+ " bytes (k=" + k + ") but buffer has only "
+					+ (newData.length - offset) + " bytes");
+		}
+	}
+
+	/**
+	 * Ensures that there is space for at least `size` bytes of kmer (not
+	 * including any header)
 	 * 
 	 */
-    private static final long serialVersionUID = 1L;
-    private static final byte[] EMPTY_BYTES = {};
+	protected void setSize(int size) {
+		if (size > getCapacity()) {
+			setCapacity((size * 3 / 2));
+		}
+		this.bytesUsed = size;
+	}
 
-    public int kmerByteSize;
-    protected byte[] bytes;
-    protected int offset;
-    protected int kmerlength;
+	/**
+	 * return the number of bytes in use for the kmer (not including any header)
+	 */
+	protected int getCapacity() {
+		return bytes.length;
+	}
 
-    public KmerBytesWritable() {
-        this(0, EMPTY_BYTES, 0);
-    }
+	/**
+	 * shrinks/expands the storage area to allow new_cap bytes for the kmer (no
+	 * header included)
+	 */
+	protected void setCapacity(int new_cap) {
+		if (new_cap != getCapacity()) {
+			byte[] new_data = new byte[new_cap];
+			if (new_cap < bytesUsed) {
+				bytesUsed = new_cap;
+			}
+			if (bytesUsed != 0) {
+				System.arraycopy(bytes, offset, new_data, 0, bytesUsed);
+			}
+			bytes = new_data;
+			offset = 0;
+		}
+	}
 
-    public KmerBytesWritable(int k, byte[] storage, int offset) {
-        setNewReference(k, storage, offset);
-    }
+	/**
+	 * Get one genecode (A|G|C|T) from the given kmer index e.g. Get the 4th
+	 * gene of the kmer ACGTA will return T
+	 * 
+	 * @param pos
+	 * @return
+	 */
+	public byte getGeneCodeAtPosition(int pos) {
+		if (pos >= lettersInKmer) {
+			throw new IllegalArgumentException("gene position out of bound");
+		}
+		return geneCodeAtPosition(pos);
+	}
 
-    public KmerBytesWritable(int k, String kmer) {
-        setNewReference(kmer.length(), kmer.getBytes(), 0);
-    }
+	// unchecked version of above. Used when kmerlength is inaccurate
+	// (mid-merge)
+	private byte geneCodeAtPosition(int pos) {
+		int posByte = pos / 4;
+		int shift = (pos % 4) << 1;
+		return (byte) ((bytes[offset + bytesUsed - 1 - posByte] >> shift) & 0x3);
+	}
 
-    /**
-     * Initial Kmer space by kmerlength
-     * 
-     * @param k
-     *            kmerlengthz
-     */
-    public KmerBytesWritable(int k) {
-        this.kmerlength = k;
-        this.kmerByteSize = KmerUtil.getByteNumFromK(kmerlength);
-        if (k > 0) {
-            this.bytes = new byte[this.kmerByteSize];
-        } else {
-            this.bytes = EMPTY_BYTES;
-        }
-        this.offset = 0;
-    }
+	public void setKmerLength(int k) {
+		this.bytesUsed = KmerUtil.getByteNumFromK(k);
+		this.lettersInKmer = k;
+	}
 
-    public KmerBytesWritable(KmerBytesWritable right) {
-        this(right.kmerlength);
-        set(right);
-    }
+	public int getKmerLength() {
+		return lettersInKmer;
+	}
 
-    /**
-     * Deep copy of the given kmer
-     * 
-     * @param newData
-     */
-    public void set(KmerBytesWritable newData) {
-        if (newData == null) {
-            this.set(0, EMPTY_BYTES, 0);
-        } else {
-            this.set(newData.kmerlength, newData.bytes, newData.getOffset());
-        }
-    }
+	@Override
+	public byte[] getBytes() {
+		return bytes;
+	}
 
-    /**
-     * Deep copy of the given bytes data
-     * It will not change the kmerlength
-     * 
-     * @param newData
-     * @param offset
-     */
-    public void set(byte[] newData, int offset) {
-        if (kmerlength > 0) {
-            System.arraycopy(newData, offset, bytes, this.offset, kmerByteSize);
-        }
-    }
+	public int getOffset() {
+		return offset;
+	}
 
-    /**
-     * Deep copy of the given data, and also set to new kmerlength
-     * 
-     * @param k
-     *            : new kmer length
-     * @param newData
-     *            : data storage
-     * @param offset
-     *            : start offset
-     */
-    public void set(int k, byte[] newData, int offset) {
-        reset(k);
-        if (k > 0) {
-            System.arraycopy(newData, offset, bytes, this.offset, kmerByteSize);
-        }
-    }
+	@Override
+	public int getLength() {
+		return bytesUsed;
+	}
 
-    /**
-     * Reset array by kmerlength
-     * 
-     * @param k
-     */
-    public void reset(int k) {
-        this.kmerlength = k;
-        setSize(KmerUtil.getByteNumFromK(k));
-        clearLeadBit();
-    }
+	/**
+	 * Read Kmer from read text into bytes array e.g. AATAG will compress as
+	 * [0x000G, 0xATAA]
+	 * 
+	 * @param k
+	 * @param stringBytes
+	 *            : byte array from a _string_. Meaning there's no header
+	 * @param start
+	 */
+	public void setByRead(byte[] stringBytes, int start) {
+		byte l = 0;
+		int bytecount = 0;
+		int bcount = this.bytesUsed - 1;
+		for (int i = start; i < start + lettersInKmer && i < stringBytes.length; i++) {
+			byte code = GeneCode.getCodeFromSymbol(stringBytes[i]);
+			l |= (byte) (code << bytecount);
+			bytecount += 2;
+			if (bytecount == 8) {
+				bytes[offset + bcount--] = l;
+				l = 0;
+				bytecount = 0;
+			}
+		}
+		if (bcount >= 0) {
+			bytes[offset] = l;
+		}
+	}
 
-    /**
-     * Point this datablock to the given bytes array
-     * It works like the pointer to new datablock.
-     * kmerlength will not change
-     * 
-     * @param newData
-     * @param offset
-     */
-    public void setNewReference(byte[] newData, int offset) {
-        this.bytes = newData;
-        this.offset = offset;
-        if (newData.length - offset < kmerByteSize) {
-            throw new IllegalArgumentException("Not given enough space");
-        }
-    }
+	public void setByRead(int k, byte[] array, int start) {
+		reset(k);
+		setByRead(array, start);
+	}
 
-    /**
-     * Point this datablock to the given bytes array
-     * It works like the pointer to new datablock.
-     * It also set the new kmerlength
-     * 
-     * @param k
-     * @param newData
-     * @param offset
-     */
-    public void setNewReference(int k, byte[] newData, int offset) {
-        this.kmerlength = k;
-        this.kmerByteSize = KmerUtil.getByteNumFromK(k);
-        setNewReference(newData, offset);
-    }
+	/**
+	 * Compress Reversed read into bytes array e.g. AATAG will paired to CTATT,
+	 * and then compress as [0x000T,0xTATC]
+	 * 
+	 * @param input
+	 *            array
+	 * @param start
+	 *            position
+	 */
+	public void setByReadReverse(byte[] array, int start) {
+		byte l = 0;
+		int bytecount = 0;
+		int bcount = bytesUsed - 1;
+		// for (int i = start + kmerlength - 1; i >= 0 && i < array.length; i--)
+		// {
+		for (int i = start + lettersInKmer - 1; i >= start && i < array.length; i--) {
+			byte code = GeneCode.getPairedCodeFromSymbol(array[i]);
+			l |= (byte) (code << bytecount);
+			bytecount += 2;
+			if (bytecount == 8) {
+				bytes[offset + bcount--] = l;
+				l = 0;
+				bytecount = 0;
+			}
+		}
+		if (bcount >= 0) {
+			bytes[offset] = l;
+		}
+	}
 
-    protected void setSize(int size) {
-        if (size > getCapacity()) {
-            setCapacity((size * 3 / 2));
-        }
-        this.kmerByteSize = size;
-    }
+	public void setByReadReverse(int k, byte[] array, int start) {
+		reset(k);
+		setByReadReverse(array, start);
+	}
 
-    protected int getCapacity() {
-        return bytes.length;
-    }
+	/**
+	 * Shift Kmer to accept new char input
+	 * 
+	 * @param c
+	 *            Input new gene character
+	 * @return the shift out gene, in gene code format
+	 */
+	public byte shiftKmerWithNextChar(byte c) {
+		return shiftKmerWithNextCode(GeneCode.getCodeFromSymbol(c));
+	}
 
-    protected void setCapacity(int new_cap) {
-        if (new_cap != getCapacity()) {
-            byte[] new_data = new byte[new_cap];
-            if (new_cap < kmerByteSize) {
-                kmerByteSize = new_cap;
-            }
-            if (kmerByteSize != 0) {
-                System.arraycopy(bytes, offset, new_data, 0, kmerByteSize);
-            }
-            bytes = new_data;
-            offset = 0;
-        }
-    }
+	/**
+	 * Shift Kmer to accept new gene code
+	 * 
+	 * @param c
+	 *            Input new gene code
+	 * @return the shift out gene, in gene code format
+	 */
+	public byte shiftKmerWithNextCode(byte c) {
+		byte output = (byte) (bytes[offset + bytesUsed - 1] & 0x03);
+		for (int i = bytesUsed - 1; i > 0; i--) {
+			byte in = (byte) (bytes[offset + i - 1] & 0x03);
+			bytes[offset + i] = (byte) (((bytes[offset + i] >>> 2) & 0x3f) | (in << 6));
+		}
+		int pos = ((lettersInKmer - 1) % 4) << 1;
+		byte code = (byte) (c << pos);
+		bytes[offset] = (byte) (((bytes[offset] >>> 2) & 0x3f) | code);
+		clearLeadBit();
+		return output;
+	}
 
-    /**
-     * Get one genecode (A|G|C|T) from the given kmer index
-     * e.g. Get the 4th gene of the kmer ACGTA will return T
-     * 
-     * @param pos
-     * @return
-     */
-    public byte getGeneCodeAtPosition(int pos) {
-        if (pos >= kmerlength) {
-            throw new IllegalArgumentException("gene position out of bound");
-        }
-        return geneCodeAtPosition(pos);
-    }
-    
-    // unchecked version of above. Used when kmerlength is inaccurate (mid-merge)
-    private byte geneCodeAtPosition(int pos) {
-        int posByte = pos / 4;
-        int shift = (pos % 4) << 1;
-        return (byte) ((bytes[offset + kmerByteSize - 1 - posByte] >> shift) & 0x3);
-    }
-    
-    public int getKmerLength() {
-        return this.kmerlength;
-    }
+	/**
+	 * Shift Kmer to accept new input char
+	 * 
+	 * @param c
+	 *            Input new gene character
+	 * @return the shiftout gene, in gene code format
+	 */
+	public byte shiftKmerWithPreChar(byte c) {
+		return shiftKmerWithPreCode(GeneCode.getCodeFromSymbol(c));
+	}
 
-    @Override
-    public byte[] getBytes() {
-        return bytes;
-    }
+	/**
+	 * Shift Kmer to accept new gene code
+	 * 
+	 * @param c
+	 *            Input new gene code
+	 * @return the shiftout gene, in gene code format
+	 */
+	public byte shiftKmerWithPreCode(byte c) {
+		int pos = ((lettersInKmer - 1) % 4) << 1;
+		byte output = (byte) ((bytes[offset] >> pos) & 0x03);
+		for (int i = 0; i < bytesUsed - 1; i++) {
+			byte in = (byte) ((bytes[offset + i + 1] >> 6) & 0x03);
+			bytes[offset + i] = (byte) ((bytes[offset + i] << 2) | in);
+		}
+		bytes[offset + bytesUsed - 1] = (byte) ((bytes[offset + bytesUsed - 1] << 2) | c);
+		clearLeadBit();
+		return output;
+	}
 
-    public int getOffset() {
-        return offset;
-    }
+	/**
+	 * Merge Kmer with the next connected Kmer e.g. AAGCTAA merge with AACAACC,
+	 * if the initial kmerSize = 3 then it will return AAGCTAACAACC
+	 * 
+	 * @param initialKmerSize
+	 *            : the initial kmerSize
+	 * @param kmer
+	 *            : the next kmer
+	 */
+	public void mergeWithFFKmer(int initialKmerSize, KmerBytesWritable kmer) {
+		int preKmerLength = lettersInKmer;
+		int preSize = bytesUsed;
+		lettersInKmer += kmer.lettersInKmer - initialKmerSize + 1;
+		setSize(KmerUtil.getByteNumFromK(lettersInKmer));
+		for (int i = 1; i <= preSize; i++) {
+			bytes[offset + bytesUsed - i] = bytes[offset + preSize - i];
+		}
+		for (int k = initialKmerSize - 1; k < kmer.getKmerLength(); k += 4) {
+			byte onebyte = getOneByteFromKmerAtPosition(k, kmer.getBytes(),
+					kmer.getOffset(), kmer.getLength());
+			appendOneByteAtPosition(preKmerLength + k - initialKmerSize + 1,
+					onebyte, bytes, offset, bytesUsed);
+		}
+		clearLeadBit();
+	}
 
-    @Override
-    public int getLength() {
-        return kmerByteSize;
-    }
+	/**
+	 * Merge Kmer with the next connected Kmer, when that Kmer needs to be
+	 * reverse-complemented e.g. AAGCTAA merge with GGTTGTT, if the initial
+	 * kmerSize = 3 then it will return AAGCTAACAACC A merge B => A B~
+	 * 
+	 * @param initialKmerSize
+	 *            : the initial kmerSize
+	 * @param kmer
+	 *            : the next kmer
+	 */
+	public void mergeWithFRKmer(int initialKmerSize, KmerBytesWritable kmer) {
+		int preSize = bytesUsed;
+		int preKmerLength = lettersInKmer;
+		lettersInKmer += kmer.lettersInKmer - initialKmerSize + 1;
+		setSize(KmerUtil.getByteNumFromK(lettersInKmer));
+		// copy prefix into right-side of buffer
+		for (int i = 1; i <= preSize; i++) {
+			bytes[offset + bytesUsed - i] = bytes[offset + preSize - i];
+		}
 
-    /**
-     * Read Kmer from read text into bytes array e.g. AATAG will compress as
-     * [0x000G, 0xATAA]
-     * 
-     * @param k
-     * @param array
-     * @param start
-     */
-    public void setByRead(byte[] array, int start) {
-        byte l = 0;
-        int bytecount = 0;
-        int bcount = this.kmerByteSize - 1;
-        for (int i = start; i < start + kmerlength && i < array.length; i++) {
-            byte code = GeneCode.getCodeFromSymbol(array[i]);
-            l |= (byte) (code << bytecount);
-            bytecount += 2;
-            if (bytecount == 8) {
-                bytes[offset + bcount--] = l;
-                l = 0;
-                bytecount = 0;
-            }
-        }
-        if (bcount >= 0) {
-            bytes[offset] = l;
-        }
-    }
+		int bytecount = (preKmerLength % 4) * 2;
+		int bcount = bytesUsed - preSize - bytecount / 8; // may overlap
+															// previous kmer
+		byte l = bcount == bytesUsed - preSize ? bytes[offset + bcount] : 0x00;
+		bytecount %= 8;
+		for (int i = kmer.lettersInKmer - initialKmerSize; i >= 0; i--) {
+			byte code = GeneCode.getPairedGeneCode(kmer
+					.getGeneCodeAtPosition(i));
+			l |= (byte) (code << bytecount);
+			bytecount += 2;
+			if (bytecount == 8) {
+				bytes[offset + bcount--] = l;
+				l = 0;
+				bytecount = 0;
+			}
+		}
+		if (bcount >= 0) {
+			bytes[offset] = l;
+		}
+	}
 
-    public void setByRead(int k, byte[] array, int start) {
-        reset(k);
-        setByRead(array, start);
-    }
+	/**
+	 * Merge Kmer with the previous connected Kmer, when that kmer needs to be
+	 * reverse-complemented e.g. AACAACC merge with TTCTGCC, if the initial
+	 * kmerSize = 3 then it will return GGCAGAACAACC
+	 * 
+	 * @param initialKmerSize
+	 *            : the initial kmerSize
+	 * @param preKmer
+	 *            : the previous kmer
+	 */
+	public void mergeWithRFKmer(int initialKmerSize, KmerBytesWritable preKmer) {
+		KmerBytesWritable reversed = new KmerBytesWritable(preKmer.lettersInKmer);
+		reversed.setByReadReverse(preKmer.toString().getBytes(), 0);
+		mergeWithRRKmer(initialKmerSize, reversed);
+	}
 
-    /**
-     * Compress Reversed read into bytes array
-     * e.g. AATAG will paired to CTATT, and then compress as
-     * [0x000T,0xTATC]
-     * 
-     * @param input
-     *            array
-     * @param start
-     *            position
-     */
-    public void setByReadReverse(byte[] array, int start) {
-        byte l = 0;
-        int bytecount = 0;
-        int bcount = kmerByteSize - 1;
-//        for (int i = start + kmerlength - 1; i >= 0 && i < array.length; i--) {
-        for (int i = start + kmerlength - 1; i >= start && i < array.length; i--) {
-            byte code = GeneCode.getPairedCodeFromSymbol(array[i]);
-            l |= (byte) (code << bytecount);
-            bytecount += 2;
-            if (bytecount == 8) {
-                bytes[offset + bcount--] = l;
-                l = 0;
-                bytecount = 0;
-            }
-        }
-        if (bcount >= 0) {
-            bytes[offset] = l;
-        }
-    }
+	/**
+	 * Merge Kmer with the previous connected Kmer e.g. AACAACC merge with
+	 * AAGCTAA, if the initial kmerSize = 3 then it will return AAGCTAACAACC
+	 * 
+	 * @param initialKmerSize
+	 *            : the initial kmerSize
+	 * @param preKmer
+	 *            : the previous kmer
+	 */
+	public void mergeWithRRKmer(int initialKmerSize, KmerBytesWritable preKmer) {
+		int preKmerLength = lettersInKmer;
+		int preSize = bytesUsed;
+		lettersInKmer += preKmer.lettersInKmer - initialKmerSize + 1;
+		setSize(KmerUtil.getByteNumFromK(lettersInKmer));
+		byte cacheByte = getOneByteFromKmerAtPosition(0, bytes, offset, preSize);
 
-    public void setByReadReverse(int k, byte[] array, int start) {
-        reset(k);
-        setByReadReverse(array, start);
-    }
+		// copy prekmer
+		for (int k = 0; k < preKmer.lettersInKmer - initialKmerSize + 1; k += 4) {
+			byte onebyte = getOneByteFromKmerAtPosition(k, preKmer.bytes,
+					preKmer.offset, preKmer.bytesUsed);
+			appendOneByteAtPosition(k, onebyte, bytes, offset, bytesUsed);
+		}
 
-    /**
-     * Shift Kmer to accept new char input
-     * 
-     * @param c
-     *            Input new gene character
-     * @return the shift out gene, in gene code format
-     */
-    public byte shiftKmerWithNextChar(byte c) {
-        return shiftKmerWithNextCode(GeneCode.getCodeFromSymbol(c));
-    }
+		// copy current kmer
+		int k = 4;
+		for (; k < preKmerLength; k += 4) {
+			byte onebyte = getOneByteFromKmerAtPosition(k, bytes, offset,
+					preSize);
+			appendOneByteAtPosition(preKmer.lettersInKmer - initialKmerSize + k
+					- 4 + 1, cacheByte, bytes, offset, bytesUsed);
+			cacheByte = onebyte;
+		}
+		appendOneByteAtPosition(preKmer.lettersInKmer - initialKmerSize + k - 4
+				+ 1, cacheByte, bytes, offset, bytesUsed);
+		clearLeadBit();
+	}
 
-    /**
-     * Shift Kmer to accept new gene code
-     * 
-     * @param c
-     *            Input new gene code
-     * @return the shift out gene, in gene code format
-     */
-    public byte shiftKmerWithNextCode(byte c) {
-        byte output = (byte) (bytes[offset + kmerByteSize - 1] & 0x03);
-        for (int i = kmerByteSize - 1; i > 0; i--) {
-            byte in = (byte) (bytes[offset + i - 1] & 0x03);
-            bytes[offset + i] = (byte) (((bytes[offset + i] >>> 2) & 0x3f) | (in << 6));
-        }
-        int pos = ((kmerlength - 1) % 4) << 1;
-        byte code = (byte) (c << pos);
-        bytes[offset] = (byte) (((bytes[offset] >>> 2) & 0x3f) | code);
-        clearLeadBit();
-        return output;
-    }
+	public void mergeWithKmerInDir(byte dir, int initialKmerSize,
+			KmerBytesWritable kmer) {
+		switch (dir & DirectionFlag.DIR_MASK) {
+		case DirectionFlag.DIR_FF:
+			mergeWithFFKmer(initialKmerSize, kmer);
+			break;
+		case DirectionFlag.DIR_FR:
+			mergeWithFRKmer(initialKmerSize, kmer);
+			break;
+		case DirectionFlag.DIR_RF:
+			mergeWithRFKmer(initialKmerSize, kmer);
+			break;
+		case DirectionFlag.DIR_RR:
+			mergeWithRRKmer(initialKmerSize, kmer);
+			break;
+		default:
+			throw new RuntimeException("Direction not recognized: " + dir);
+		}
+	}
 
-    /**
-     * Shift Kmer to accept new input char
-     * 
-     * @param c
-     *            Input new gene character
-     * @return the shiftout gene, in gene code format
-     */
-    public byte shiftKmerWithPreChar(byte c) {
-        return shiftKmerWithPreCode(GeneCode.getCodeFromSymbol(c));
-    }
+	public static void appendOneByteAtPosition(int k, byte onebyte,
+			byte[] buffer, int start, int length) {
+		int position = start + length - 1 - k / 4;
+		if (position < start) {
+			throw new IllegalArgumentException(
+					"Buffer for kmer storage is invalid");
+		}
+		int shift = ((k) % 4) << 1;
+		int mask = shift == 0 ? 0 : ((1 << shift) - 1);
 
-    /**
-     * Shift Kmer to accept new gene code
-     * 
-     * @param c
-     *            Input new gene code
-     * @return the shiftout gene, in gene code format
-     */
-    public byte shiftKmerWithPreCode(byte c) {
-        int pos = ((kmerlength - 1) % 4) << 1;
-        byte output = (byte) ((bytes[offset] >> pos) & 0x03);
-        for (int i = 0; i < kmerByteSize - 1; i++) {
-            byte in = (byte) ((bytes[offset + i + 1] >> 6) & 0x03);
-            bytes[offset + i] = (byte) ((bytes[offset + i] << 2) | in);
-        }
-        bytes[offset + kmerByteSize - 1] = (byte) ((bytes[offset + kmerByteSize - 1] << 2) | c);
-        clearLeadBit();
-        return output;
-    }
+		buffer[position] = (byte) ((buffer[position] & mask) | ((0xff & onebyte) << shift));
+		if (position > start && shift != 0) {
+			buffer[position - 1] = (byte) ((buffer[position - 1] & (0xff - mask)) | ((byte) ((0xff & onebyte) >>> (8 - shift))));
+		}
+	}
 
-    /**
-     * Merge Kmer with the next connected Kmer
-     * e.g. AAGCTAA merge with AACAACC, if the initial kmerSize = 3
-     * then it will return AAGCTAACAACC
-     * 
-     * @param initialKmerSize
-     *            : the initial kmerSize
-     * @param kmer
-     *            : the next kmer
-     */
-    public void mergeWithFFKmer(int initialKmerSize, KmerBytesWritable kmer) {
-        int preKmerLength = kmerlength;
-        int preSize = kmerByteSize;
-        this.kmerlength += kmer.kmerlength - initialKmerSize + 1;
-        setSize(KmerUtil.getByteNumFromK(kmerlength));
-        for (int i = 1; i <= preSize; i++) {
-            bytes[offset + kmerByteSize - i] = bytes[offset + preSize - i];
-        }
-        for (int k = initialKmerSize - 1; k < kmer.getKmerLength(); k += 4) {
-            byte onebyte = getOneByteFromKmerAtPosition(k, kmer.getBytes(), kmer.getOffset(), kmer.getLength());
-            appendOneByteAtPosition(preKmerLength + k - initialKmerSize + 1, onebyte, bytes, offset, kmerByteSize);
-        }
-        clearLeadBit();
-    }
+	public static byte getOneByteFromKmerAtPosition(int k, byte[] buffer,
+			int start, int length) {
+		int position = start + length - 1 - k / 4;
+		if (position < start) {
+			throw new IllegalArgumentException(
+					"Buffer of kmer storage is invalid");
+		}
+		int shift = (k % 4) << 1;
+		byte data = (byte) (((0xff) & buffer[position]) >>> shift);
+		if (shift != 0 && position > start) {
+			data |= 0xff & (buffer[position - 1] << (8 - shift));
+		}
+		return data;
+	}
 
-    /**
-     * Merge Kmer with the next connected Kmer, when that Kmer needs to be reverse-complemented
-     * e.g. AAGCTAA merge with GGTTGTT, if the initial kmerSize = 3
-     * then it will return AAGCTAACAACC
-     * 
-     * A merge B =>  A B~
-     * 
-     * @param initialKmerSize
-     *            : the initial kmerSize
-     * @param kmer
-     *            : the next kmer
-     */
-    public void mergeWithFRKmer(int initialKmerSize, KmerBytesWritable kmer) {
-        int preSize = kmerByteSize;
-        int preKmerLength = kmerlength;
-        this.kmerlength += kmer.kmerlength - initialKmerSize + 1;
-        setSize(KmerUtil.getByteNumFromK(kmerlength));
-        // copy prefix into right-side of buffer
-        for (int i = 1; i <= preSize; i++) {
-            bytes[offset + kmerByteSize - i] = bytes[offset + preSize - i];
-        }
+	protected void clearLeadBit() {
+		if (lettersInKmer % 4 != 0) {
+			bytes[offset] &= (1 << ((lettersInKmer % 4) << 1)) - 1;
+		}
+	}
 
-        int bytecount = (preKmerLength % 4) * 2;
-        int bcount = kmerByteSize - preSize - bytecount / 8; // may overlap previous kmer
-        byte l = bcount == kmerByteSize - preSize ? bytes[offset + bcount] : 0x00;
-        bytecount %= 8;
-        for (int i = kmer.kmerlength - initialKmerSize; i >= 0; i--) {
-            byte code = GeneCode.getPairedGeneCode(kmer.getGeneCodeAtPosition(i));
-            l |= (byte) (code << bytecount);
-            bytecount += 2;
-            if (bytecount == 8) {
-                bytes[offset + bcount--] = l;
-                l = 0;
-                bytecount = 0;
-            }
-        }
-        if (bcount >= 0) {
-            bytes[offset] = l;
-        }
-    }
+	@Override
+	public void readFields(DataInput in) throws IOException {
+		lettersInKmer = in.readInt();
+		bytesUsed = KmerUtil.getByteNumFromK(lettersInKmer);
+		if (lettersInKmer > 0) {
+			if (this.bytes.length < this.bytesUsed) {
+				this.bytes = new byte[this.bytesUsed];
+				this.offset = 0;
 
-    /**
-     * Merge Kmer with the previous connected Kmer, when that kmer needs to be reverse-complemented
-     * e.g. AACAACC merge with TTCTGCC, if the initial kmerSize = 3
-     * then it will return GGCAGAACAACC
-     * 
-     * @param initialKmerSize
-     *            : the initial kmerSize
-     * @param preKmer
-     *            : the previous kmer
-     */
-    public void mergeWithRFKmer(int initialKmerSize, KmerBytesWritable preKmer) {
-        int preKmerLength = kmerlength;
-        int preSize = kmerByteSize;
-        this.kmerlength += preKmer.kmerlength - initialKmerSize + 1;
-        setSize(KmerUtil.getByteNumFromK(kmerlength));
-        //        byte cacheByte = getOneByteFromKmerAtPosition(0, bytes, offset, preSize);
+			}
+			in.readFully(bytes, offset, bytesUsed);
+		}
+	}
 
-        int byteIndex = kmerByteSize - 1;
-        byte cacheByte = 0x00;
-        int posnInByte = 0;
+	@Override
+	public void write(DataOutput out) throws IOException {
+		out.writeInt(lettersInKmer);
+		if (lettersInKmer > 0) {
+			out.write(bytes, offset, bytesUsed);
+		}
+	}
 
-        // copy rc of preKmer into high bytes
-        for (int i = preKmer.kmerlength - 1; i >= initialKmerSize - 1; i--) {
-            byte code = GeneCode.getPairedGeneCode(preKmer.getGeneCodeAtPosition(i));
-            cacheByte |= (byte) (code << posnInByte);
-            posnInByte += 2;
-            if (posnInByte == 8) {
-                bytes[byteIndex--] = cacheByte;
-                cacheByte = 0;
-                posnInByte = 0;
-            }
-        }
-        
-        // copy my kmer into low positions of bytes
-        for (int i = 0; i < preKmerLength; i++) {
-           // expanding the capacity makes this offset incorrect.  It's off by the # of additional bytes added.
-            int newposn = i + (kmerByteSize - preSize) * 4;
-            byte code = geneCodeAtPosition(newposn);
-            cacheByte |= (byte) (code << posnInByte);
-            posnInByte += 2;
-            if (posnInByte == 8) {
-                bytes[byteIndex--] = cacheByte;
-                cacheByte = 0;
-                posnInByte = 0;
-            }
-        }
-        if(posnInByte > 0)
-            bytes[offset] = cacheByte;
-        clearLeadBit();
-    }
+	@Override
+	public int hashCode() {
+		return super.hashCode() * 31 + this.lettersInKmer;
+	}
 
-    /**
-     * Merge Kmer with the previous connected Kmer
-     * e.g. AACAACC merge with AAGCTAA, if the initial kmerSize = 3
-     * then it will return AAGCTAACAACC
-     * 
-     * @param initialKmerSize
-     *            : the initial kmerSize
-     * @param preKmer
-     *            : the previous kmer
-     */
-    public void mergeWithRRKmer(int initialKmerSize, KmerBytesWritable preKmer) {
-        int preKmerLength = kmerlength;
-        int preSize = kmerByteSize;
-        this.kmerlength += preKmer.kmerlength - initialKmerSize + 1;
-        setSize(KmerUtil.getByteNumFromK(kmerlength));
-        byte cacheByte = getOneByteFromKmerAtPosition(0, bytes, offset, preSize);
+	@Override
+	public boolean equals(Object right_obj) {
+		if (right_obj instanceof KmerBytesWritable)
+			return this.lettersInKmer == ((KmerBytesWritable) right_obj).lettersInKmer
+					&& super.equals(right_obj);
+		return false;
+	}
 
-        // copy prekmer
-        for (int k = 0; k < preKmer.kmerlength - initialKmerSize + 1; k += 4) {
-            byte onebyte = getOneByteFromKmerAtPosition(k, preKmer.bytes, preKmer.offset, preKmer.kmerByteSize);
-            appendOneByteAtPosition(k, onebyte, bytes, offset, kmerByteSize);
-        }
+	@Override
+	public String toString() {
+		return KmerUtil.recoverKmerFrom(this.lettersInKmer, this.getBytes(),
+				offset, this.getLength());
+	}
 
-        // copy current kmer
-        int k = 4;
-        for (; k < preKmerLength; k += 4) {
-            byte onebyte = getOneByteFromKmerAtPosition(k, bytes, offset, preSize);
-            appendOneByteAtPosition(preKmer.kmerlength - initialKmerSize + k - 4 + 1, cacheByte, bytes, offset, kmerByteSize);
-            cacheByte = onebyte;
-        }
-        appendOneByteAtPosition(preKmer.kmerlength - initialKmerSize + k - 4 + 1, cacheByte, bytes, offset, kmerByteSize);
-        clearLeadBit();
-    }
-    
-    public void mergeWithKmerInDir(byte dir, int initialKmerSize, KmerBytesWritable kmer) {
-        switch(dir & DirectionFlag.DIR_MASK) {
-            case DirectionFlag.DIR_FF:
-                mergeWithFFKmer(initialKmerSize, kmer);
-                break;
-            case DirectionFlag.DIR_FR:
-                mergeWithFRKmer(initialKmerSize, kmer);
-                break;
-            case DirectionFlag.DIR_RF:
-                mergeWithRFKmer(initialKmerSize, kmer);
-                break;
-            case DirectionFlag.DIR_RR:
-                mergeWithRRKmer(initialKmerSize, kmer);
-                break;
-            default:
-                throw new RuntimeException("Direciotn not recognized: " + dir);
-        }
-    }
+	public static class Comparator extends WritableComparator {
+		private static final int LEADING_BYTES = 4;
 
-    public static void appendOneByteAtPosition(int k, byte onebyte, byte[] buffer, int start, int length) {
-        int position = start + length - 1 - k / 4;
-        if (position < start) {
-            throw new IllegalArgumentException("Buffer for kmer storage is invalid");
-        }
-        int shift = ((k) % 4) << 1;
-        int mask = shift == 0 ? 0 : ((1 << shift) - 1);
+		public Comparator() {
+			super(KmerBytesWritable.class);
+		}
 
-        buffer[position] = (byte) ((buffer[position] & mask) | ((0xff & onebyte) << shift));
-        if (position > start && shift != 0) {
-            buffer[position - 1] = (byte) ((buffer[position - 1] & (0xff - mask)) | ((byte) ((0xff & onebyte) >>> (8 - shift))));
-        }
-    }
+		public int compare(byte[] b1, int s1, int l1, byte[] b2, int s2, int l2) {
+			int kmerlength1 = Marshal.getInt(b1, s1);
+			int kmerlength2 = Marshal.getInt(b2, s2);
+			if (kmerlength1 == kmerlength2) {
+				return compareBytes(b1, s1 + LEADING_BYTES, l1 - LEADING_BYTES,
+						b2, s2 + LEADING_BYTES, l2 - LEADING_BYTES);
+			}
+			return kmerlength1 - kmerlength2;
+		}
+	}
 
-    public static byte getOneByteFromKmerAtPosition(int k, byte[] buffer, int start, int length) {
-        int position = start + length - 1 - k / 4;
-        if (position < start) {
-            throw new IllegalArgumentException("Buffer of kmer storage is invalid");
-        }
-        int shift = (k % 4) << 1;
-        byte data = (byte) (((0xff) & buffer[position]) >>> shift);
-        if (shift != 0 && position > start) {
-            data |= 0xff & (buffer[position - 1] << (8 - shift));
-        }
-        return data;
-    }
-
-    protected void clearLeadBit() {
-        if (kmerlength % 4 != 0) {
-            bytes[offset] &= (1 << ((kmerlength % 4) << 1)) - 1;
-        }
-    }
-
-    @Override
-    public void readFields(DataInput in) throws IOException {
-        this.kmerlength = in.readInt();
-        this.kmerByteSize = KmerUtil.getByteNumFromK(kmerlength);
-        if (this.kmerlength > 0) {
-            if (this.bytes.length < this.kmerByteSize) {
-                this.bytes = new byte[this.kmerByteSize];
-                this.offset = 0;
-            }
-            in.readFully(bytes, offset, kmerByteSize);
-        }
-    }
-
-    @Override
-    public void write(DataOutput out) throws IOException {
-        out.writeInt(kmerlength);
-        if (kmerlength > 0) {
-            out.write(bytes, offset, kmerByteSize);
-        }
-    }
-
-    @Override
-    public int hashCode() {
-        return super.hashCode() * 31 + this.kmerlength;
-    }
-
-    @Override
-    public boolean equals(Object right_obj) {
-        if (right_obj instanceof KmerBytesWritable)
-            return this.kmerlength == ((KmerBytesWritable) right_obj).kmerlength && super.equals(right_obj);
-        return false;
-    }
-
-    @Override
-    public String toString() {
-        return KmerUtil.recoverKmerFrom(this.kmerlength, this.getBytes(), offset, this.getLength());
-    }
-
-    public static class Comparator extends WritableComparator {
-        public final int LEAD_BYTES = 4;
-
-        public Comparator() {
-            super(KmerBytesWritable.class);
-        }
-
-        public int compare(byte[] b1, int s1, int l1, byte[] b2, int s2, int l2) {
-            int kmerlength1 = readInt(b1, s1);
-            int kmerlength2 = readInt(b2, s2);
-            if (kmerlength1 == kmerlength2) {
-                return compareBytes(b1, s1 + LEAD_BYTES, l1 - LEAD_BYTES, b2, s2 + LEAD_BYTES, l2 - LEAD_BYTES);
-            }
-            return kmerlength1 - kmerlength2;
-        }
-    }
-
-    static { // register this comparator
-        WritableComparator.define(KmerBytesWritable.class, new Comparator());
-    }
+	static { // register this comparator
+		WritableComparator.define(KmerBytesWritable.class, new Comparator());
+	}
 
 }
diff --git a/genomix/genomix-data/src/main/java/edu/uci/ics/genomix/type/KmerBytesWritableFactory.java b/genomix/genomix-data/src/main/java/edu/uci/ics/genomix/type/KmerBytesWritableFactory.java
index d2e3a94..f805610 100644
--- a/genomix/genomix-data/src/main/java/edu/uci/ics/genomix/type/KmerBytesWritableFactory.java
+++ b/genomix/genomix-data/src/main/java/edu/uci/ics/genomix/type/KmerBytesWritableFactory.java
@@ -64,7 +64,7 @@
             return null;
         }
         if (lastK == kmerChain.getKmerLength()) {
-            kmer.set(kmerChain);
+            kmer.setAsCopy(kmerChain);
             return kmer;
         }
         kmer.reset(lastK);
@@ -100,7 +100,7 @@
             return null;
         }
         if (firstK == kmerChain.getKmerLength()) {
-            kmer.set(kmerChain);
+            kmer.setAsCopy(kmerChain);
             return kmer;
         }
         kmer.reset(firstK);
@@ -124,7 +124,7 @@
             return null;
         }
         if (startK == 0 && kSize == kmerChain.getKmerLength()) {
-            kmer.set(kmerChain);
+            kmer.setAsCopy(kmerChain);
             return kmer;
         }
         kmer.reset(kSize);
@@ -256,7 +256,7 @@
      * @return new created kmer that shifted by afterCode, the K will not change
      */
     public KmerBytesWritable shiftKmerWithNextCode(final KmerBytesWritable kmer, byte afterCode) {
-        this.kmer.set(kmer);
+        this.kmer.setAsCopy(kmer);
         this.kmer.shiftKmerWithNextCode(afterCode);
         return this.kmer;
     }
@@ -274,7 +274,7 @@
      * @return new created kmer that shifted by preCode, the K will not change
      */
     public KmerBytesWritable shiftKmerWithPreCode(final KmerBytesWritable kmer, byte preCode) {
-        this.kmer.set(kmer);
+        this.kmer.setAsCopy(kmer);
         this.kmer.shiftKmerWithPreCode(preCode);
         return this.kmer;
     }
diff --git a/genomix/genomix-data/src/main/java/edu/uci/ics/genomix/type/KmerListWritable.java b/genomix/genomix-data/src/main/java/edu/uci/ics/genomix/type/KmerListWritable.java
index 88bb79c..6bf8dac 100644
--- a/genomix/genomix-data/src/main/java/edu/uci/ics/genomix/type/KmerListWritable.java
+++ b/genomix/genomix-data/src/main/java/edu/uci/ics/genomix/type/KmerListWritable.java
@@ -4,6 +4,7 @@
 import java.io.DataOutput;
 import java.io.IOException;
 import java.io.Serializable;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 
@@ -12,224 +13,256 @@
 import edu.uci.ics.genomix.data.KmerUtil;
 import edu.uci.ics.genomix.data.Marshal;
 
-public class KmerListWritable implements Writable, Iterable<KmerBytesWritable>, Serializable{
-    private static final long serialVersionUID = 1L;
-    protected byte[] storage;
-    protected int offset;
-    protected int valueCount;
-    public int kmerByteSize = 0; 
-    public int kmerlength = 0;
-    protected static final byte[] EMPTY = {};
-    
-    protected KmerBytesWritable posIter = new KmerBytesWritable();
-    
-    public KmerListWritable() {
-        this.storage = EMPTY;
-        this.valueCount = 0;
-        this.offset = 0;
-    }
-    
-    public KmerListWritable(int kmerlength) {
-        this();
-        this.kmerlength = kmerlength;
-        this.kmerByteSize = KmerUtil.getByteNumFromK(kmerlength);
-    }
-    
-    public KmerListWritable(int kmerlength, int count, byte[] data, int offset) {
-        this.kmerlength = kmerlength;
-        this.kmerByteSize = KmerUtil.getByteNumFromK(kmerlength);
-        setNewReference(count, data, offset);
-    }
-    
-    public KmerListWritable(List<KmerBytesWritable> kmers) {
-        this();
-        setSize(kmers.size());  // reserve space for all elements
-        for (KmerBytesWritable kmer : kmers) {
-            append(kmer);
-        }
-    }
-    
-    public void setNewReference(int count, byte[] data, int offset) {
-        this.valueCount = count;
-        this.storage = data;
-        this.offset = offset;
-    }
-    
-    public void append(KmerBytesWritable kmer){
-        if(kmer != null){
-            kmerByteSize = kmer.kmerByteSize;
-            kmerlength = kmer.kmerlength;
-            setSize((1 + valueCount) * kmerByteSize); 
-            System.arraycopy(kmer.getBytes(), 0, storage, offset + valueCount * kmerByteSize, kmerByteSize);
-            valueCount += 1;
-        }
-    }
-    
-    /*
-     * Append the otherList to the end of myList
-     */
-    public void appendList(KmerListWritable otherList) {
-        if (otherList.valueCount > 0) {
-            setSize((valueCount + otherList.valueCount) * kmerByteSize);
-            // copy contents of otherList into the end of my storage
-            System.arraycopy(otherList.storage, otherList.offset,
-                    storage, offset + valueCount * kmerByteSize, 
-                    otherList.valueCount * kmerByteSize);
-            valueCount += otherList.valueCount;
-        }
-    }
-    
-    protected void setSize(int size) {
-        if (size > getCapacity()) {
-            setCapacity((size * 3 / 2));
-        }
-    }
-    
-    protected int getCapacity() {
-        return storage.length - offset;
-    }
 
-    protected void setCapacity(int new_cap) {
-        if (new_cap > getCapacity()) {
-            byte[] new_data = new byte[new_cap];
-            if (storage.length - offset > 0) {
-                System.arraycopy(storage, offset, new_data, 0, storage.length - offset);
-            }
-            storage = new_data;
-            offset = 0;
-        }
-    }
-    
-    public void reset() {
-        this.reset(0);
-    }
-    
-    public void reset(int kmerSize) {
-        kmerlength = kmerSize;
-        kmerByteSize = KmerUtil.getByteNumFromK(kmerlength);
-        storage = EMPTY;
-        valueCount = 0;
-        offset = 0;
-    }
-    
-    public KmerBytesWritable getPosition(int i) {
-        if (i >= valueCount) {
-            throw new ArrayIndexOutOfBoundsException("No such positions");
-        }
-        posIter.setNewReference(kmerlength, storage, offset + i * kmerByteSize);
-        return posIter;
-    }
-    
-    public void set(KmerListWritable otherList) {
-        this.kmerlength = otherList.kmerlength;
-        this.kmerByteSize = otherList.kmerByteSize;
-        set(otherList.valueCount, otherList.storage, otherList.offset);
-    }
+/**
+ * A list of fixed-length kmers.  The length of this list is stored internally 
+ *
+ */
+public class KmerListWritable implements Writable, Iterable<KmerBytesWritable>,
+		Serializable {
+	private static final long serialVersionUID = 1L;
+	protected static final byte[] EMPTY_BYTES = { 0, 0, 0, 0 };
+	protected static final int HEADER_SIZE = 4;
 
-    public void set(int valueCount, byte[] newData, int offset) {
-        this.valueCount = valueCount;
-        setSize(valueCount * kmerByteSize);
-        if (valueCount > 0) {
-            System.arraycopy(newData, offset, storage, this.offset, valueCount * kmerByteSize);
-        }
-    }
-    
-    @Override
-    public Iterator<KmerBytesWritable> iterator() {
-        Iterator<KmerBytesWritable> it = new Iterator<KmerBytesWritable>() {
+	protected byte[] storage;
+	protected int offset;
+	protected int valueCount;
 
-            private int currentIndex = 0;
+	protected int bytesPerKmer = 0;
+	protected int lettersPerKmer = 0;
+	private KmerBytesWritable posIter = new KmerBytesWritable();
 
-            @Override
-            public boolean hasNext() {
-                return currentIndex < valueCount;
-            }
+	public KmerListWritable() {
+		this.storage = EMPTY_BYTES;
+		this.valueCount = 0;
+		this.offset = 0;
+	}
 
-            @Override
-            public KmerBytesWritable next() {
-                return getPosition(currentIndex++);
-            }
+	public KmerListWritable(int kmerlength) {
+		this();
+		this.lettersPerKmer = kmerlength;
+		this.bytesPerKmer = KmerUtil.getByteNumFromK(kmerlength);
+	}
 
-            @Override
-            public void remove() {
-                if(currentIndex < valueCount)
-                    System.arraycopy(storage, offset + currentIndex * kmerByteSize, 
-                          storage, offset + (currentIndex - 1) * kmerByteSize, 
-                          (valueCount - currentIndex) * kmerByteSize);
-                valueCount--;
-                currentIndex--;
-            }
-        };
-        return it;
-    }
-    
-    /*
-     * remove the first instance of @toRemove. Uses a linear scan.  Throws an exception if not in this list.
-     */
-    public void remove(KmerBytesWritable toRemove, boolean ignoreMissing) {
-        Iterator<KmerBytesWritable> posIterator = this.iterator();
-        while (posIterator.hasNext()) {
-            if(toRemove.equals(posIterator.next())) {
-                posIterator.remove();
-                return;
-            }
-        }
-        if (!ignoreMissing) {
-            throw new ArrayIndexOutOfBoundsException("the KmerBytesWritable `" + toRemove.toString() + "` was not found in this list.");
-        }
-    }
-    
-    public void remove(KmerBytesWritable toRemove) {
-        remove(toRemove, false);
-    }
+	public KmerListWritable(int kmerlength, byte[] data, int offset) {
+		this.lettersPerKmer = kmerlength;
+		this.bytesPerKmer = KmerUtil.getByteNumFromK(kmerlength);
+		setNewReference(data, offset);
+	}
 
-    @Override
-    public void readFields(DataInput in) throws IOException {
-        this.valueCount = in.readInt();
-        setSize(valueCount * kmerByteSize);//kmerByteSize
-        in.readFully(storage, offset, valueCount * kmerByteSize);//kmerByteSize
-    }
+	public KmerListWritable(List<KmerBytesWritable> kmers) {
+		this();
+		setSize(kmers.size()); // reserve space for all elements
+		for (KmerBytesWritable kmer : kmers) {
+			if (kmer.getKmerLength() != lettersPerKmer)
+				throw new IllegalArgumentException("Kmer " + kmer.toString()
+						+ " is of incorrect length (l=" + kmer.getKmerLength()
+						+ ") for this list (should be " + lettersPerKmer + ").");
+			append(kmer);
+		}
+	}
 
-    @Override
-    public void write(DataOutput out) throws IOException {
-        out.writeInt(valueCount);
-        out.write(storage, offset, valueCount * kmerByteSize);
-    }
-    
-    public int getCountOfPosition() {
-        return valueCount;
-    }
+	public void setNewReference(byte[] data, int offset) {
+		this.valueCount = Marshal.getInt(data, offset);
+		this.storage = data;
+		this.offset = offset;
+	}
 
-    public byte[] getByteArray() {
-        return storage;
-    }
+	public void append(KmerBytesWritable kmer) {
+		setSize((1 + valueCount) * bytesPerKmer);
+		System.arraycopy(kmer.getBytes(), 0, storage, offset + valueCount
+				* bytesPerKmer, bytesPerKmer);
+		valueCount += 1;
+	}
 
-    public int getStartOffset() {
-        return offset;
-    }
-    
-    public int getLength() {
-        return valueCount * kmerByteSize;
-    }
-    
-    @Override
-    public String toString() {
-        StringBuilder sbuilder = new StringBuilder();
-        sbuilder.append('[');
-        for(int i = 0; i < valueCount; i++){
-            sbuilder.append(getPosition(i).toString());
-            sbuilder.append(',');
-        }
-        if (valueCount > 0) {
-            sbuilder.setCharAt(sbuilder.length() - 1, ']');
-        } else {
-            sbuilder.append(']');
-        }
-        return sbuilder.toString();
-    }
-    
-    @Override
-    public int hashCode() {
-        return Marshal.hashBytes(getByteArray(), getStartOffset(), getLength());
-    }
+	/*
+	 * Append the otherList to the end of myList
+	 */
+	public void appendList(KmerListWritable otherList) {
+		if (otherList.valueCount > 0) {
+			setSize((valueCount + otherList.valueCount) * bytesPerKmer);
+			// copy contents of otherList into the end of my storage
+			System.arraycopy(otherList.storage, otherList.offset, storage,
+					offset + valueCount * bytesPerKmer, otherList.valueCount
+							* bytesPerKmer);
+			valueCount += otherList.valueCount;
+		}
+	}
+
+	/**
+	 * Save the union of my list and otherList. Uses a temporary HashSet for
+	 * uniquefication
+	 */
+	public void unionUpdate(KmerListWritable otherList) {
+		int newSize = valueCount + otherList.valueCount;
+		HashSet<KmerBytesWritable> uniqueElements = new HashSet<KmerBytesWritable>(
+				newSize);
+		for (KmerBytesWritable kmer : this) {
+			uniqueElements.add(kmer);
+		}
+		for (KmerBytesWritable kmer : otherList) {
+			uniqueElements.add(kmer);
+		}
+		valueCount = 0;
+		setSize(newSize);
+		for (KmerBytesWritable kmer : uniqueElements) {
+			append(kmer);
+		}
+	}
+
+	protected void setSize(int size) {
+		if (size > getCapacity()) {
+			setCapacity((size * 3 / 2));
+		}
+	}
+
+	protected int getCapacity() {
+		return storage.length - offset;
+	}
+
+	protected void setCapacity(int new_cap) {
+		if (new_cap > getCapacity()) {
+			byte[] new_data = new byte[new_cap];
+			if (storage.length - offset > 0) {
+				System.arraycopy(storage, offset, new_data, 0, storage.length
+						- offset);
+			}
+			storage = new_data;
+			offset = 0;
+		}
+	}
+
+	public void reset(int kmerSize) {
+		lettersPerKmer = kmerSize;
+		bytesPerKmer = KmerUtil.getByteNumFromK(lettersPerKmer);
+		storage = EMPTY_BYTES;
+		valueCount = 0;
+		offset = 0;
+	}
+
+	public KmerBytesWritable getPosition(int i) {
+		if (i >= valueCount) {
+			throw new ArrayIndexOutOfBoundsException("No such positions");
+		}
+		posIter.setAsReference(lettersPerKmer, storage, offset + i
+				* bytesPerKmer);
+		return posIter;
+	}
+
+	public void set(KmerListWritable otherList) {
+		this.lettersPerKmer = otherList.lettersPerKmer;
+		this.bytesPerKmer = otherList.bytesPerKmer;
+		set(otherList.valueCount, otherList.storage, otherList.offset);
+	}
+
+	public void set(int valueCount, byte[] newData, int offset) {
+		this.valueCount = valueCount;
+		setSize(valueCount * bytesPerKmer);
+		if (valueCount > 0) {
+			System.arraycopy(newData, offset, storage, this.offset, valueCount
+					* bytesPerKmer);
+		}
+	}
+
+	@Override
+	public Iterator<KmerBytesWritable> iterator() {
+		Iterator<KmerBytesWritable> it = new Iterator<KmerBytesWritable>() {
+
+			private int currentIndex = 0;
+
+			@Override
+			public boolean hasNext() {
+				return currentIndex < valueCount;
+			}
+
+			@Override
+			public KmerBytesWritable next() {
+				return getPosition(currentIndex++);
+			}
+
+			@Override
+			public void remove() {
+				if (currentIndex < valueCount)
+					System.arraycopy(storage, offset + currentIndex
+							* bytesPerKmer, storage, offset
+							+ (currentIndex - 1) * bytesPerKmer,
+							(valueCount - currentIndex) * bytesPerKmer);
+				valueCount--;
+				currentIndex--;
+			}
+		};
+		return it;
+	}
+
+	/*
+	 * remove the first instance of `toRemove`. Uses a linear scan. Throws an
+	 * exception if not in this list.
+	 */
+	public void remove(KmerBytesWritable toRemove, boolean ignoreMissing) {
+		Iterator<KmerBytesWritable> posIterator = this.iterator();
+		while (posIterator.hasNext()) {
+			if (toRemove.equals(posIterator.next())) {
+				posIterator.remove();
+				return;
+			}
+		}
+		if (!ignoreMissing) {
+			throw new ArrayIndexOutOfBoundsException("the KmerBytesWritable `"
+					+ toRemove.toString() + "` was not found in this list.");
+		}
+	}
+
+	public void remove(KmerBytesWritable toRemove) {
+		remove(toRemove, false);
+	}
+
+	@Override
+	public void readFields(DataInput in) throws IOException {
+		this.valueCount = in.readInt();
+		setSize(valueCount * bytesPerKmer);// kmerByteSize
+		in.readFully(storage, offset, valueCount * bytesPerKmer);// kmerByteSize
+	}
+
+	@Override
+	public void write(DataOutput out) throws IOException {
+		out.writeInt(valueCount);
+		out.write(storage, offset, valueCount * bytesPerKmer);
+	}
+
+	public int getCountOfPosition() {
+		return valueCount;
+	}
+
+	public byte[] getByteArray() {
+		return storage;
+	}
+
+	public int getStartOffset() {
+		return offset;
+	}
+
+	public int getLength() {
+		return valueCount * bytesPerKmer;
+	}
+
+	@Override
+	public String toString() {
+		StringBuilder sbuilder = new StringBuilder();
+		sbuilder.append('[');
+		for (int i = 0; i < valueCount; i++) {
+			sbuilder.append(getPosition(i).toString());
+			sbuilder.append(',');
+		}
+		if (valueCount > 0) {
+			sbuilder.setCharAt(sbuilder.length() - 1, ']');
+		} else {
+			sbuilder.append(']');
+		}
+		return sbuilder.toString();
+	}
+
+	@Override
+	public int hashCode() {
+		return Marshal.hashBytes(getByteArray(), getStartOffset(), getLength());
+	}
 }
diff --git a/genomix/genomix-data/src/main/java/edu/uci/ics/genomix/type/NodeWritable.java b/genomix/genomix-data/src/main/java/edu/uci/ics/genomix/type/NodeWritable.java
index efa87f7..98e37dc 100644
--- a/genomix/genomix-data/src/main/java/edu/uci/ics/genomix/type/NodeWritable.java
+++ b/genomix/genomix-data/src/main/java/edu/uci/ics/genomix/type/NodeWritable.java
@@ -63,7 +63,7 @@
         this.forwardReverseList.set(FRList);
         this.reverseForwardList.set(RFList);
         this.reverseReverseList.set(RRList);
-        this.kmer.set(kmer);
+        this.kmer.setAsCopy(kmer);
     }
 
     public void reset(int kmerSize) {
@@ -90,7 +90,7 @@
     }
 
     public void setKmer(KmerBytesWritable kmer) {
-        this.kmer.set(kmer);
+        this.kmer.setAsCopy(kmer);
     }
     
     public int getKmerlength() {
diff --git a/genomix/genomix-data/src/main/java/edu/uci/ics/genomix/type/PositionListWritable.java b/genomix/genomix-data/src/main/java/edu/uci/ics/genomix/type/PositionListWritable.java
index f135292..b056c14 100644
--- a/genomix/genomix-data/src/main/java/edu/uci/ics/genomix/type/PositionListWritable.java
+++ b/genomix/genomix-data/src/main/java/edu/uci/ics/genomix/type/PositionListWritable.java
@@ -4,6 +4,7 @@
 import java.io.DataOutput;
 import java.io.IOException;
 import java.io.Serializable;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 
@@ -76,6 +77,27 @@
         }
     }
     
+    /**
+     * Save the union of my list and otherList. Uses a temporary HashSet for
+     * uniquefication
+     */
+    public void unionUpdate(PositionListWritable otherList) {
+        int newSize = valueCount + otherList.valueCount;
+        HashSet<PositionWritable> uniqueElements = new HashSet<PositionWritable>(
+                newSize);
+        for (PositionWritable pos : this) {
+            uniqueElements.add(pos);
+        }
+        for (PositionWritable pos : otherList) {
+            uniqueElements.add(pos);
+        }
+        valueCount = 0;
+        setSize(newSize);
+        for (PositionWritable pos : uniqueElements) {
+            append(pos);
+        }
+    }
+    
     public static int getCountByDataLength(int length) {
         if (length % PositionWritable.LENGTH != 0) {
             throw new IllegalArgumentException("Length of positionlist is invalid");
diff --git a/genomix/genomix-data/src/main/java/edu/uci/ics/genomix/type/VKmerBytesWritable.java b/genomix/genomix-data/src/main/java/edu/uci/ics/genomix/type/VKmerBytesWritable.java
new file mode 100644
index 0000000..7fed5c7
--- /dev/null
+++ b/genomix/genomix-data/src/main/java/edu/uci/ics/genomix/type/VKmerBytesWritable.java
@@ -0,0 +1,272 @@
+/*
+ * Copyright 2009-2013 by The Regents of the University of California
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * you may obtain a copy of the License from
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package edu.uci.ics.genomix.type;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+
+import org.apache.hadoop.io.WritableComparator;
+
+import edu.uci.ics.genomix.data.KmerUtil;
+import edu.uci.ics.genomix.data.Marshal;
+
+/**
+ * Variable-length kmer which stores its length internally.
+ * 
+ * Note: `offset` as used in this class is the offset at which the *kmer*
+ * begins. There is a {@value HEADER_SIZE}-byte header preceding the kmer
+ */
+public class VKmerBytesWritable extends KmerBytesWritable {
+
+	private static final long serialVersionUID = 1L;
+	protected static final byte[] EMPTY_BYTES = { 0, 0, 0, 0 }; // int
+																// indicating 0
+																// length
+	protected static final int HEADER_SIZE = 4; // number of bytes for header
+												// info
+
+	/**
+	 * Initialize as empty kmer
+	 */
+	public VKmerBytesWritable() {
+		this(EMPTY_BYTES, HEADER_SIZE);
+	}
+
+	/**
+	 * Copy contents of kmer string
+	 */
+	public VKmerBytesWritable(String kmer) {
+		bytes = new byte[HEADER_SIZE + KmerUtil.getByteNumFromK(kmer.length())];
+		offset = HEADER_SIZE;
+		setAsCopy(kmer);
+	}
+
+	/**
+	 * Set as reference to given data
+	 * 
+	 * @param storage
+	 *            : byte array with header
+	 * @param offset
+	 */
+	public VKmerBytesWritable(byte[] storage, int offset) {
+		setAsReference(storage, offset);
+	}
+
+	/**
+	 * Reserve space for k letters
+	 */
+	public VKmerBytesWritable(int k) {
+		if (k > 0) {
+			bytes = new byte[HEADER_SIZE + KmerUtil.getByteNumFromK(k)];
+		} else {
+			bytes = EMPTY_BYTES;
+		}
+		offset = HEADER_SIZE;
+		setKmerLength(k);
+	}
+
+	/**
+	 * deep copy of kmer in other
+	 * 
+	 * @param other
+	 */
+	public VKmerBytesWritable(VKmerBytesWritable other) {
+		this(other.lettersInKmer);
+		setAsCopy(other);
+	}
+
+	/**
+	 * Deep copy of the given kmer
+	 * 
+	 * @param other
+	 */
+	@Override
+	public void setAsCopy(KmerBytesWritable other) {
+		reset(other.lettersInKmer);
+		if (lettersInKmer > 0) {
+			System.arraycopy(other.bytes, other.offset, bytes, this.offset,
+					bytesUsed);
+		}
+	}
+
+	/**
+	 * set from String kmer
+	 */
+	@Override
+	public void setAsCopy(String kmer) {
+		int k = kmer.length();
+		reset(k);
+		System.arraycopy(kmer.getBytes(), 0, bytes, offset, bytesUsed);
+	}
+
+	/**
+	 * Deep copy of the given bytes data
+	 * 
+	 * @param newData
+	 *            : byte array to copy (should have a header)
+	 * @param offset
+	 */
+	public void setAsCopy(byte[] newData, int offset) {
+		int k = Marshal.getInt(newData, offset);
+		reset(k);
+		System.arraycopy(newData, offset + HEADER_SIZE, bytes, this.offset,
+				bytesUsed);
+	}
+
+	/**
+	 * Point this datablock to the given bytes array It works like the pointer
+	 * to new datablock.
+	 * 
+	 * @param newData
+	 *            : byte array to copy (should have a header)
+	 * @param blockOffset
+	 */
+	public void setAsReference(byte[] newData, int blockOffset) {
+		this.bytes = newData;
+		this.offset = blockOffset + HEADER_SIZE;
+		int kRequested = Marshal.getInt(newData, blockOffset);
+		int bytesRequested = KmerUtil.getByteNumFromK(kRequested) + HEADER_SIZE;
+		if (newData.length - blockOffset < bytesRequested) {
+			throw new IllegalArgumentException("Requested " + bytesRequested
+					+ " bytes (k=" + kRequested + ") but buffer has only "
+					+ (newData.length - blockOffset) + " bytes");
+		}
+		setKmerLength(kRequested);
+	}
+
+	@Override
+	public void setKmerLength(int k) {
+		this.bytesUsed = KmerUtil.getByteNumFromK(k);
+		this.lettersInKmer = k;
+		Marshal.putInt(k, bytes, offset - HEADER_SIZE);
+	}
+
+	@Override
+	protected int getCapacity() {
+		return bytes.length - HEADER_SIZE;
+	}
+
+	@Override
+	protected void setCapacity(int new_cap) {
+		if (new_cap != getCapacity()) {
+			byte[] new_data = new byte[new_cap + HEADER_SIZE];
+			if (new_cap < bytesUsed) {
+				bytesUsed = new_cap;
+			}
+			if (bytesUsed != 0) {
+				System.arraycopy(bytes, offset, new_data, HEADER_SIZE,
+						bytesUsed);
+			}
+			bytes = new_data;
+			offset = HEADER_SIZE;
+		}
+	}
+
+	@Override
+	public void mergeWithFFKmer(int initialKmerSize, KmerBytesWritable kmer) {
+		super.mergeWithFFKmer(initialKmerSize, kmer);
+		Marshal.putInt(lettersInKmer, bytes, offset - HEADER_SIZE);
+	}
+
+	@Override
+	public void mergeWithFRKmer(int initialKmerSize, KmerBytesWritable kmer) {
+		super.mergeWithFRKmer(initialKmerSize, kmer);
+		Marshal.putInt(lettersInKmer, bytes, offset - HEADER_SIZE);
+	}
+
+	@Override
+	public void mergeWithRFKmer(int initialKmerSize, KmerBytesWritable preKmer) {
+		super.mergeWithRFKmer(initialKmerSize, preKmer);
+		Marshal.putInt(lettersInKmer, bytes, offset - HEADER_SIZE);
+	}
+
+	@Override
+	public void mergeWithRRKmer(int initialKmerSize, KmerBytesWritable preKmer) {
+		super.mergeWithRRKmer(initialKmerSize, preKmer);
+		Marshal.putInt(lettersInKmer, bytes, offset - HEADER_SIZE);
+	}
+
+	@Override
+	public void readFields(DataInput in) throws IOException {
+		lettersInKmer = in.readInt();
+		bytesUsed = KmerUtil.getByteNumFromK(lettersInKmer);
+		if (lettersInKmer > 0) {
+			if (getCapacity() < this.bytesUsed) {
+				this.bytes = new byte[this.bytesUsed + HEADER_SIZE];
+				this.offset = HEADER_SIZE;
+			}
+			in.readFully(bytes, offset, bytesUsed);
+		}
+		Marshal.putInt(lettersInKmer, bytes, offset - HEADER_SIZE);
+	}
+
+	/**
+	 * write the entire byte array including the header
+	 */
+	@Override
+	public void write(DataOutput out) throws IOException {
+		out.write(bytes, offset - HEADER_SIZE, bytesUsed + HEADER_SIZE);
+	}
+
+	@Override
+	public boolean equals(Object right) {
+		if (right instanceof VKmerBytesWritable) {
+			return super.equals(right); // compare bytes directly
+		} else if (right instanceof KmerBytesWritable) {
+			// for Kmers, we need to skip our header
+			KmerBytesWritable rightKmer = (KmerBytesWritable) right;
+			if (lettersInKmer != rightKmer.lettersInKmer) { // check length
+				return false;
+			}
+			for (int i = 0; i < lettersInKmer; i++) { // check letters
+				if (bytes[i + HEADER_SIZE] != rightKmer.bytes[i]) {
+					return false;
+				}
+			}
+			return true;
+		}
+		return false;
+	}
+
+	@Override
+	public String toString() {
+		return KmerUtil.recoverKmerFrom(this.lettersInKmer, this.getBytes(),
+				offset, this.getLength());
+	}
+
+	public static class Comparator extends WritableComparator {
+
+		public Comparator() {
+			super(VKmerBytesWritable.class);
+		}
+
+		public int compare(byte[] b1, int s1, int l1, byte[] b2, int s2, int l2) {
+			int kmerlength1 = Marshal.getInt(b1, s1);
+			int kmerlength2 = Marshal.getInt(b2, s2);
+			if (kmerlength1 == kmerlength2) {
+				return compareBytes(b1, s1 + HEADER_SIZE, l1 - HEADER_SIZE, b2,
+						s2 + HEADER_SIZE, l2 - HEADER_SIZE);
+			}
+			return kmerlength1 - kmerlength2;
+		}
+	}
+
+	static { // register this comparator
+		WritableComparator.define(VKmerBytesWritable.class, new Comparator());
+	}
+
+}
diff --git a/genomix/genomix-data/src/test/java/edu/uci/ics/genomix/data/test/KmerBytesWritableTest.java b/genomix/genomix-data/src/test/java/edu/uci/ics/genomix/data/test/KmerBytesWritableTest.java
index fbfbeeb..807ac13 100644
--- a/genomix/genomix-data/src/test/java/edu/uci/ics/genomix/data/test/KmerBytesWritableTest.java
+++ b/genomix/genomix-data/src/test/java/edu/uci/ics/genomix/data/test/KmerBytesWritableTest.java
@@ -131,7 +131,7 @@
         Assert.assertEquals(text1 + text2.substring(kmerSize - 1), merge.toString());
 
         for (int i = 1; i < 8; i++) {
-            merge.set(kmer1);
+            merge.setAsCopy(kmer1);
             merge.mergeWithFFKmer(i, kmer2);
             Assert.assertEquals(text1 + text2.substring(i - 1), merge.toString());
         }
@@ -147,7 +147,7 @@
                 Assert.assertEquals(text1, kmer1.toString());
                 Assert.assertEquals(text2, kmer2.toString());
                 for (int x = 1; x < jk; x++) {
-                    merge.set(kmer1);
+                    merge.setAsCopy(kmer1);
                     merge.mergeWithFFKmer(x, kmer2);
                     Assert.assertEquals(text1 + text2.substring(x - 1), merge.toString());
                 }
@@ -177,17 +177,17 @@
         Assert.assertEquals(result, merge.toString());
         
         int i = 1;
-        merge.set(kmer1);
+        merge.setAsCopy(kmer1);
         merge.mergeWithFRKmer(i, kmer2);
         Assert.assertEquals("AAGCTAAAACAACC", merge.toString());
         
         i = 2;
-        merge.set(kmer1);
+        merge.setAsCopy(kmer1);
         merge.mergeWithFRKmer(i, kmer2);
         Assert.assertEquals("AAGCTAAACAACC", merge.toString());
         
         i = 3;
-        merge.set(kmer1);
+        merge.setAsCopy(kmer1);
         merge.mergeWithFRKmer(i, kmer2);
         Assert.assertEquals("AAGCTAACAACC", merge.toString());
     }
@@ -215,48 +215,38 @@
         Assert.assertEquals(result, merge.toString());
         
         int i = 1;
-        merge.set(kmer1);
+        merge.setAsCopy(kmer1);
         merge.mergeWithRFKmer(i, kmer2);
         Assert.assertEquals("GGCACAAAACAACCC", merge.toString());
         
         i = 2;
-        merge.set(kmer1);
+        merge.setAsCopy(kmer1);
         merge.mergeWithRFKmer(i, kmer2);
         Assert.assertEquals("GGCACAAACAACCC", merge.toString());
         
         i = 3;
-        merge.set(kmer1);
+        merge.setAsCopy(kmer1);
         merge.mergeWithRFKmer(i, kmer2);
         Assert.assertEquals("GGCACAACAACCC", merge.toString());
         
-        String test1;
-        String test2;
-        test1 = "CTA";
-        test2 = "AGA";
-        KmerBytesWritable k1 = new KmerBytesWritable(3);
-        KmerBytesWritable k2 = new KmerBytesWritable(3);
-        k1.setByRead(test1.getBytes(), 0);
-        k2.setByRead(test2.getBytes(), 0);
-        k1.mergeWithRFKmer(3, k2);
-        Assert.assertEquals("TCTA", k1.toString());
+//        String test1 = "CTTAT";
+//        String test2 = "AGACC";  // rc = GGTCT
+//        KmerBytesWritable k1 = new KmerBytesWritable(5);
+//        KmerBytesWritable k2 = new KmerBytesWritable(5);
+//        k1.setByRead(test1.getBytes(), 0);
+//        k2.setByRead(test2.getBytes(), 0);
+//        k1.mergeWithRFKmer(3, k2);
+//        Assert.assertEquals("GGTCTTAT", k1.toString());  //GGTCGTCT  -> AGACGACC ??
         
-        test1 = "CTA";
-        test2 = "ATA"; //TAT
-        k1 = new KmerBytesWritable(3);
-        k2 = new KmerBytesWritable(3);
-        k1.setByRead(test1.getBytes(), 0);
-        k2.setByRead(test2.getBytes(), 0);
-        k1.mergeWithFRKmer(3, k2);
-        Assert.assertEquals("CTAT", k1.toString());
-        
-        test1 = "ATA";
-        test2 = "CTA"; //TAT
-        k1 = new KmerBytesWritable(3);
-        k2 = new KmerBytesWritable(3);
-        k1.setByRead(test1.getBytes(), 0);
-        k2.setByRead(test2.getBytes(), 0);
-        k1.mergeWithFRKmer(3, k2);
-        Assert.assertEquals("ATAG", k1.toString());
+        String test3 = "CTA";
+        String test4 = "AGA";  // rc = TCT
+        KmerBytesWritable k3 = new KmerBytesWritable(3);
+        KmerBytesWritable k4 = new KmerBytesWritable(3);
+        k3.setByRead(test3.getBytes(), 0);
+        k4.setByRead(test4.getBytes(), 0);
+        k3.mergeWithRFKmer(3, k4);
+        Assert.assertEquals("TCTA", k3.toString());
+//        Assert.assertEquals("CTAT", k3);  // this is an incorrect test case-- the merge always flips the passed-in kmer
     }
     
     
@@ -278,7 +268,7 @@
         Assert.assertEquals(text1 + text2.substring(kmerSize - 1), merge.toString());
 
         for (int i = 1; i < 8; i++) {
-            merge.set(kmer2);
+            merge.setAsCopy(kmer2);
             merge.mergeWithRRKmer(i, kmer1);
             Assert.assertEquals(text1.substring(0, text1.length() - i + 1) + text2, merge.toString());
         }
@@ -294,62 +284,30 @@
                 Assert.assertEquals(text1, kmer1.toString());
                 Assert.assertEquals(text2, kmer2.toString());
                 for (int x = 1; x < ik; x++) {
-                    merge.set(kmer2);
+                    merge.setAsCopy(kmer2);
                     merge.mergeWithRRKmer(x, kmer1);
                     Assert.assertEquals(text1.substring(0, text1.length() - x + 1) + text2, merge.toString());
                 }
             }
         }
     }
-    
+
     @Test
-    public void TestFinalMerge() {
-        String selfString;
-        String match;
-        String msgString;
-        int index;
-        KmerBytesWritable kmer = new KmerBytesWritable();
-        int kmerSize = 3;
-        
-        String F1 = "AATAG";
-        String F2 = "TAGAA";
-        String R1 = "CTATT";
-        String R2 = "TTCTA";
-        
-        //FF test
-        selfString = F1;
-        match = selfString.substring(selfString.length() - kmerSize + 1,selfString.length()); 
-        msgString = F2;
-        index = msgString.indexOf(match);
-        kmer.reset(msgString.length() - index);
-        kmer.setByRead(msgString.substring(index).getBytes(), 0);
-        System.out.println(kmer.toString());
-        
-        //FR test
-        selfString = F1;
-        match = selfString.substring(selfString.length() - kmerSize + 1,selfString.length()); 
-        msgString = GeneCode.reverseComplement(R2);
-        index = msgString.indexOf(match);
-        kmer.reset(msgString.length() - index);
-        kmer.setByRead(msgString.substring(index).getBytes(), 0);
-        System.out.println(kmer.toString());
-        
-        //RF test
-        selfString = R1;
-        match = selfString.substring(0,kmerSize - 1); 
-        msgString = GeneCode.reverseComplement(F2);
-        index = msgString.lastIndexOf(match) + kmerSize - 2;
-        kmer.reset(index + 1);
-        kmer.setByReadReverse(msgString.substring(0, index + 1).getBytes(), 0);
-        System.out.println(kmer.toString());
-        
-        //RR test
-        selfString = R1;
-        match = selfString.substring(0,kmerSize - 1); 
-        msgString = R2;
-        index = msgString.lastIndexOf(match) + kmerSize - 2;
-        kmer.reset(index + 1);
-        kmer.setByRead(msgString.substring(0, index + 1).getBytes(), 0);
-        System.out.println(kmer.toString());
+    public void TestMergeRFAndRRKmer() {
+    	String test1 = "TAGAT";
+    	String test2 = "TCTAG";  // rc = CTAGA
+    	String test3 = "GCTAG";
+    	KmerBytesWritable k1 = new KmerBytesWritable(5);
+        KmerBytesWritable k2 = new KmerBytesWritable(5);
+        KmerBytesWritable k3 = new KmerBytesWritable(5);
+        k1.setByRead(test1.getBytes(), 0);
+        k2.setByRead(test2.getBytes(), 0);
+        k3.setByRead(test3.getBytes(), 0);
+        k1.mergeWithRFKmer(5, k2);
+        Assert.assertEquals("CTAGAT", k1.toString());
+        k1.mergeWithRRKmer(5, k3);
+        Assert.assertEquals("GCTAGAT", k1.toString());
     }
 }
+
+
diff --git a/genomix/genomix-data/src/test/java/edu/uci/ics/genomix/data/test/VKmerBytesWritableTest.java b/genomix/genomix-data/src/test/java/edu/uci/ics/genomix/data/test/VKmerBytesWritableTest.java
new file mode 100644
index 0000000..a50e465
--- /dev/null
+++ b/genomix/genomix-data/src/test/java/edu/uci/ics/genomix/data/test/VKmerBytesWritableTest.java
@@ -0,0 +1,409 @@
+/*
+ * Copyright 2009-2012 by The Regents of the University of California
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * you may obtain a copy of the License from
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package edu.uci.ics.genomix.data.test;
+
+import junit.framework.Assert;
+
+import org.junit.Test;
+
+import edu.uci.ics.genomix.type.GeneCode;
+import edu.uci.ics.genomix.type.KmerBytesWritable;
+import edu.uci.ics.genomix.type.VKmerBytesWritable;
+
+public class VKmerBytesWritableTest {
+	static byte[] array = { 'A', 'A', 'T', 'A', 'G', 'A', 'A', 'G' };
+	static int k = 7;
+
+	@Test
+	public void TestCompressKmer() {
+		VKmerBytesWritable kmer = new VKmerBytesWritable(k);
+		kmer.setByRead(array, 0);
+		Assert.assertEquals(kmer.toString(), "AATAGAA");
+
+		kmer.setByRead(array, 1);
+		Assert.assertEquals(kmer.toString(), "ATAGAAG");
+	}
+
+	@Test
+	public void TestMoveKmer() {
+		VKmerBytesWritable kmer = new VKmerBytesWritable(k);
+		kmer.setByRead(array, 0);
+		Assert.assertEquals(kmer.toString(), "AATAGAA");
+
+		for (int i = k; i < array.length - 1; i++) {
+			kmer.shiftKmerWithNextCode(array[i]);
+			Assert.assertTrue(false);
+		}
+
+		byte out = kmer.shiftKmerWithNextChar(array[array.length - 1]);
+		Assert.assertEquals(out, GeneCode.getCodeFromSymbol((byte) 'A'));
+		Assert.assertEquals(kmer.toString(), "ATAGAAG");
+	}
+
+	@Test
+	public void TestCompressKmerReverse() {
+		VKmerBytesWritable kmer = new VKmerBytesWritable(k);
+		kmer.setByRead(array, 0);
+		Assert.assertEquals(kmer.toString(), "AATAGAA");
+
+		kmer.setByReadReverse(array, 1);
+		Assert.assertEquals(kmer.toString(), "CTTCTAT");
+	}
+
+	@Test
+	public void TestMoveKmerReverse() {
+		VKmerBytesWritable kmer = new VKmerBytesWritable(k);
+		kmer.setByRead(array, 0);
+		Assert.assertEquals(kmer.toString(), "AATAGAA");
+
+		for (int i = k; i < array.length - 1; i++) {
+			kmer.shiftKmerWithPreChar(array[i]);
+			Assert.assertTrue(false);
+		}
+
+		byte out = kmer.shiftKmerWithPreChar(array[array.length - 1]);
+		Assert.assertEquals(out, GeneCode.getCodeFromSymbol((byte) 'A'));
+		Assert.assertEquals(kmer.toString(), "GAATAGA");
+	}
+
+	@Test
+	public void TestGetGene() {
+		VKmerBytesWritable kmer = new VKmerBytesWritable(9);
+		String text = "AGCTGACCG";
+		byte[] array = { 'A', 'G', 'C', 'T', 'G', 'A', 'C', 'C', 'G' };
+		kmer.setByRead(array, 0);
+
+		for (int i = 0; i < 9; i++) {
+			Assert.assertEquals(text.charAt(i), (char) (GeneCode
+					.getSymbolFromCode(kmer.getGeneCodeAtPosition(i))));
+		}
+	}
+
+	@Test
+	public void TestGetOneByteFromKmer() {
+		byte[] array = { 'A', 'G', 'C', 'T', 'G', 'A', 'C', 'C', 'G', 'T' };
+		String string = "AGCTGACCGT";
+		for (int k = 3; k <= 10; k++) {
+			VKmerBytesWritable kmer = new VKmerBytesWritable(k);
+			VKmerBytesWritable kmerAppend = new VKmerBytesWritable(k);
+			kmer.setByRead(array, 0);
+			Assert.assertEquals(string.substring(0, k), kmer.toString());
+			for (int b = 0; b < k; b++) {
+				byte byteActual = VKmerBytesWritable
+						.getOneByteFromKmerAtPosition(b, kmer.getBytes(),
+								kmer.getOffset(), kmer.getLength());
+				byte byteExpect = GeneCode.getCodeFromSymbol(array[b]);
+				for (int i = 1; i < 4 && b + i < k; i++) {
+					byteExpect += GeneCode.getCodeFromSymbol(array[b + i]) << (i * 2);
+				}
+				Assert.assertEquals(byteActual, byteExpect);
+				VKmerBytesWritable.appendOneByteAtPosition(b, byteActual,
+						kmerAppend.getBytes(), kmerAppend.getOffset(),
+						kmerAppend.getLength());
+			}
+			Assert.assertEquals(kmer.toString(), kmerAppend.toString());
+		}
+	}
+
+	@Test
+	public void TestMergeFFKmer() {
+		byte[] array = { 'A', 'G', 'C', 'T', 'G', 'A', 'C', 'C', 'G', 'T' };
+		String text = "AGCTGACCGT";
+		VKmerBytesWritable kmer1 = new VKmerBytesWritable(8);
+		kmer1.setByRead(array, 0);
+		String text1 = "AGCTGACC";
+		Assert.assertEquals(text1, kmer1.toString());
+		
+		VKmerBytesWritable kmer2 = new VKmerBytesWritable(8);
+		kmer2.setByRead(array, 1);
+		String text2 = "GCTGACCG";
+		Assert.assertEquals(text2, kmer2.toString());
+		
+		VKmerBytesWritable merge = new VKmerBytesWritable(kmer1);
+		int kmerSize = 8;
+		merge.mergeWithFFKmer(kmerSize, kmer2);
+		Assert.assertEquals(text1 + text2.substring(kmerSize - 1),
+				merge.toString());
+
+		for (int i = 1; i < 8; i++) {
+			merge.setAsCopy(kmer1);
+			merge.mergeWithFFKmer(i, kmer2);
+			Assert.assertEquals(text1 + text2.substring(i - 1),
+					merge.toString());
+		}
+
+		for (int ik = 1; ik <= 10; ik++) {
+			for (int jk = 1; jk <= 10; jk++) {
+				kmer1 = new VKmerBytesWritable(ik);
+				kmer2 = new VKmerBytesWritable(jk);
+				kmer1.setByRead(array, 0);
+				kmer2.setByRead(array, 0);
+				text1 = text.substring(0, ik);
+				text2 = text.substring(0, jk);
+				Assert.assertEquals(text1, kmer1.toString());
+				Assert.assertEquals(text2, kmer2.toString());
+				for (int x = 1; x < jk; x++) {
+					merge.setAsCopy(kmer1);
+					merge.mergeWithFFKmer(x, kmer2);
+					Assert.assertEquals(text1 + text2.substring(x - 1),
+							merge.toString());
+				}
+			}
+		}
+	}
+
+	@Test
+	public void TestMergeFRKmer() {
+		int kmerSize = 3;
+		String result = "AAGCTAACAACC";
+		byte[] resultArray = result.getBytes();
+
+		String text1 = "AAGCTAA";
+		VKmerBytesWritable kmer1 = new VKmerBytesWritable(text1.length());
+		kmer1.setByRead(resultArray, 0);
+		Assert.assertEquals(text1, kmer1.toString());
+
+		// kmer2 is the rc of the end of the read
+		String text2 = "GGTTGTT";
+		VKmerBytesWritable kmer2 = new VKmerBytesWritable(text2.length());
+		kmer2.setByReadReverse(resultArray, result.length() - text2.length());
+		Assert.assertEquals(text2, kmer2.toString());
+
+		VKmerBytesWritable merge = new VKmerBytesWritable(kmer1);
+		merge.mergeWithFRKmer(kmerSize, kmer2);
+		Assert.assertEquals(result, merge.toString());
+
+		int i = 1;
+		merge.setAsCopy(kmer1);
+		merge.mergeWithFRKmer(i, kmer2);
+		Assert.assertEquals("AAGCTAAAACAACC", merge.toString());
+
+		i = 2;
+		merge.setAsCopy(kmer1);
+		merge.mergeWithFRKmer(i, kmer2);
+		Assert.assertEquals("AAGCTAAACAACC", merge.toString());
+
+		i = 3;
+		merge.setAsCopy(kmer1);
+		merge.mergeWithFRKmer(i, kmer2);
+		Assert.assertEquals("AAGCTAACAACC", merge.toString());
+	}
+
+	@Test
+	public void TestMergeRFKmer() {
+		int kmerSize = 3;
+		String result = "GGCACAACAACCC";
+		byte[] resultArray = result.getBytes();
+
+		String text1 = "AACAACCC";
+		VKmerBytesWritable kmer1 = new VKmerBytesWritable(text1.length());
+		kmer1.setByRead(resultArray, 5);
+		Assert.assertEquals(text1, kmer1.toString());
+
+		// kmer2 is the rc of the end of the read
+		String text2 = "TTGTGCC";
+		VKmerBytesWritable kmer2 = new VKmerBytesWritable(text2.length());
+		kmer2.setByReadReverse(resultArray, 0);
+		Assert.assertEquals(text2, kmer2.toString());
+
+		VKmerBytesWritable merge = new VKmerBytesWritable(kmer1);
+		merge.mergeWithRFKmer(kmerSize, kmer2);
+		Assert.assertEquals(result, merge.toString());
+
+		int i = 1;
+		merge.setAsCopy(kmer1);
+		merge.mergeWithRFKmer(i, kmer2);
+		Assert.assertEquals("GGCACAAAACAACCC", merge.toString());
+
+		i = 2;
+		merge.setAsCopy(kmer1);
+		merge.mergeWithRFKmer(i, kmer2);
+		Assert.assertEquals("GGCACAAACAACCC", merge.toString());
+
+		i = 3;
+		merge.setAsCopy(kmer1);
+		merge.mergeWithRFKmer(i, kmer2);
+		Assert.assertEquals("GGCACAACAACCC", merge.toString());
+
+		// String test1 = "CTTAT";
+		// String test2 = "AGACC"; // rc = GGTCT
+		// VKmerBytesWritable k1 = new VKmerBytesWritable(5);
+		// VKmerBytesWritable k2 = new VKmerBytesWritable(5);
+		// k1.setByRead(test1.getBytes(), 0);
+		// k2.setByRead(test2.getBytes(), 0);
+		// k1.mergeWithRFKmer(3, k2);
+		// Assert.assertEquals("GGTCTTAT", k1.toString()); //GGTCGTCT ->
+		// AGACGACC ??
+
+		String test3 = "CTA";
+		String test4 = "AGA"; // rc = TCT
+		VKmerBytesWritable k3 = new VKmerBytesWritable(3);
+		VKmerBytesWritable k4 = new VKmerBytesWritable(3);
+		k3.setByRead(test3.getBytes(), 0);
+		k4.setByRead(test4.getBytes(), 0);
+		k3.mergeWithRFKmer(3, k4);
+		Assert.assertEquals("TCTA", k3.toString());
+		// Assert.assertEquals("CTAT", k3); // this is an incorrect test case--
+		// the merge always flips the passed-in kmer
+	}
+
+	@Test
+	public void TestMergeRRKmer() {
+		byte[] array = { 'A', 'G', 'C', 'T', 'G', 'A', 'C', 'C', 'G', 'T' };
+		String text = "AGCTGACCGT";
+		VKmerBytesWritable kmer1 = new VKmerBytesWritable(8);
+		kmer1.setByRead(array, 0);
+		String text1 = "AGCTGACC";
+		VKmerBytesWritable kmer2 = new VKmerBytesWritable(8);
+		kmer2.setByRead(array, 1);
+		String text2 = "GCTGACCG";
+		Assert.assertEquals(text2, kmer2.toString());
+		VKmerBytesWritable merge = new VKmerBytesWritable(kmer2);
+		int kmerSize = 8;
+		merge.mergeWithRRKmer(kmerSize, kmer1);
+		Assert.assertEquals(text1 + text2.substring(kmerSize - 1),
+				merge.toString());
+
+		for (int i = 1; i < 8; i++) {
+			merge.setAsCopy(kmer2);
+			merge.mergeWithRRKmer(i, kmer1);
+			Assert.assertEquals(text1.substring(0, text1.length() - i + 1)
+					+ text2, merge.toString());
+		}
+
+		for (int ik = 1; ik <= 10; ik++) {
+			for (int jk = 1; jk <= 10; jk++) {
+				kmer1 = new VKmerBytesWritable(ik);
+				kmer2 = new VKmerBytesWritable(jk);
+				kmer1.setByRead(array, 0);
+				kmer2.setByRead(array, 0);
+				text1 = text.substring(0, ik);
+				text2 = text.substring(0, jk);
+				Assert.assertEquals(text1, kmer1.toString());
+				Assert.assertEquals(text2, kmer2.toString());
+				for (int x = 1; x < ik; x++) {
+					merge.setAsCopy(kmer2);
+					merge.mergeWithRRKmer(x, kmer1);
+					Assert.assertEquals(
+							text1.substring(0, text1.length() - x + 1) + text2,
+							merge.toString());
+				}
+			}
+		}
+	}
+
+	@Test
+	public void TestMergeRFAndRRKmer() {
+		String test1 = "TAGAT";
+		String test2 = "TCTAG"; // rc = CTAGA
+		String test3 = "GCTAG";
+		VKmerBytesWritable k1 = new VKmerBytesWritable(5);
+		VKmerBytesWritable k2 = new VKmerBytesWritable(5);
+		VKmerBytesWritable k3 = new VKmerBytesWritable(5);
+		k1.setByRead(test1.getBytes(), 0);
+		k2.setByRead(test2.getBytes(), 0);
+		k3.setByRead(test3.getBytes(), 0);
+		k1.mergeWithRFKmer(5, k2);
+		Assert.assertEquals("CTAGAT", k1.toString());
+		k1.mergeWithRRKmer(5, k3);
+		Assert.assertEquals("GCTAGAT", k1.toString());
+	}
+	
+	@Test
+	public void TestMergeRFAndRFKmer() {
+		String test1 = "TAGAT";
+		String test2 = "TCTAG"; // rc = CTAGA
+		String test3 = "CTAGC"; // rc = GCTAG
+		VKmerBytesWritable k1 = new VKmerBytesWritable(5);
+		VKmerBytesWritable k2 = new VKmerBytesWritable(5);
+		VKmerBytesWritable k3 = new VKmerBytesWritable(5);
+		k1.setByRead(test1.getBytes(), 0);
+		k2.setByRead(test2.getBytes(), 0);
+		k3.setByRead(test3.getBytes(), 0);
+		k1.mergeWithRFKmer(5, k2);
+		Assert.assertEquals("CTAGAT", k1.toString());
+		k1.mergeWithRFKmer(5, k3);
+		Assert.assertEquals("GCTAGAT", k1.toString());
+	}
+	
+	@Test
+	public void TestMergeRFAndFRKmer() {
+		String test1 = "TAGAT"; // rc = ATCTA
+		String test2 = "TCTAG"; // rc = CTAGA
+		String test3 = "GCTAG"; // rc = CTAGC
+		VKmerBytesWritable k1 = new VKmerBytesWritable(5);
+		VKmerBytesWritable k2 = new VKmerBytesWritable(5);
+		VKmerBytesWritable k3 = new VKmerBytesWritable(5);
+		k1.setByRead(test1.getBytes(), 0);
+		k2.setByRead(test2.getBytes(), 0);
+		k3.setByRead(test3.getBytes(), 0);
+		k2.mergeWithRFKmer(5, k1);
+		Assert.assertEquals("ATCTAG", k2.toString());
+		k2.mergeWithFRKmer(5, k3);
+		Assert.assertEquals("ATCTAGC", k2.toString());
+	}
+	
+	@Test
+	public void TestMergeRFAndFFKmer() {
+		String test1 = "TAGAT"; // rc = ATCTA
+		String test2 = "TCTAG"; // rc = CTAGA
+		String test3 = "CTAGC"; // rc = GCTAG
+		VKmerBytesWritable k1 = new VKmerBytesWritable(5);
+		VKmerBytesWritable k2 = new VKmerBytesWritable(5);
+		VKmerBytesWritable k3 = new VKmerBytesWritable(5);
+		k1.setByRead(test1.getBytes(), 0);
+		k2.setByRead(test2.getBytes(), 0);
+		k3.setByRead(test3.getBytes(), 0);
+		k2.mergeWithRFKmer(5, k1);
+		Assert.assertEquals("ATCTAG", k2.toString());
+		k2.mergeWithFFKmer(5, k3);
+		Assert.assertEquals("ATCTAGC", k2.toString());
+	}
+	
+	@Test
+	public void TestMergeKmerAndVKmer() {
+		String test1 = "TAGAT"; // rc = ATCTA
+		String test2 = "TCTAG"; // rc = CTAGA
+		String test3 = "CTAGC"; // rc = GCTAG
+		KmerBytesWritable k1 = new KmerBytesWritable(5);
+		VKmerBytesWritable k2 = new VKmerBytesWritable(5);
+		VKmerBytesWritable k3 = new VKmerBytesWritable(5);
+		k1.setByRead(test1.getBytes(), 0);
+		k2.setByRead(test2.getBytes(), 0);
+		k3.setByRead(test3.getBytes(), 0);
+		k2.mergeWithRFKmer(5, k1);
+		Assert.assertEquals("ATCTAG", k2.toString());
+		k2.mergeWithFFKmer(5, k3);
+		Assert.assertEquals("ATCTAGC", k2.toString());
+	}
+	
+	@Test
+	public void TestMergeKmerAndVKmerRFAndRFKmer() {
+		String test1 = "TAGAT";
+		String test2 = "TCTAG"; // rc = CTAGA
+		String test3 = "CTAGC"; // rc = GCTAG
+		KmerBytesWritable k1 = new KmerBytesWritable(5);
+		VKmerBytesWritable k2 = new VKmerBytesWritable(5);
+		VKmerBytesWritable k3 = new VKmerBytesWritable(5);
+		k1.setByRead(test1.getBytes(), 0);
+		k2.setByRead(test2.getBytes(), 0);
+		k3.setByRead(test3.getBytes(), 0);
+		k1.mergeWithRFKmer(5, k2);
+		Assert.assertEquals("CTAGAT", k1.toString());
+		k1.mergeWithRFKmer(5, k3);
+		Assert.assertEquals("GCTAGAT", k1.toString());
+	}
+}
diff --git a/genomix/genomix-hyracks/src/main/java/edu/uci/ics/genomix/hyracks/newgraph/dataflow/ReadsKeyValueParserFactory.java b/genomix/genomix-hyracks/src/main/java/edu/uci/ics/genomix/hyracks/newgraph/dataflow/ReadsKeyValueParserFactory.java
index b101312..5b612dc 100644
--- a/genomix/genomix-hyracks/src/main/java/edu/uci/ics/genomix/hyracks/newgraph/dataflow/ReadsKeyValueParserFactory.java
+++ b/genomix/genomix-hyracks/src/main/java/edu/uci/ics/genomix/hyracks/newgraph/dataflow/ReadsKeyValueParserFactory.java
@@ -46,6 +46,7 @@
 
     public static final int OutputKmerField = 0;
     public static final int outputNodeIdListField = 1;
+    
     public static final int OutputForwardForwardField = 2;
     public static final int OutputFFListCountField = 3;
     public static final int OutputForwardReverseField = 4;
diff --git a/genomix/genomix-hyracks/src/main/java/edu/uci/ics/genomix/hyracks/newgraph/job/GenomixJobConf.java b/genomix/genomix-hyracks/src/main/java/edu/uci/ics/genomix/hyracks/newgraph/job/GenomixJobConf.java
new file mode 100644
index 0000000..b0edf77
--- /dev/null
+++ b/genomix/genomix-hyracks/src/main/java/edu/uci/ics/genomix/hyracks/newgraph/job/GenomixJobConf.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2009-2013 by The Regents of the University of California
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * you may obtain a copy of the License from
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package edu.uci.ics.genomix.hyracks.newgraph.job;
+
+import java.io.IOException;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.mapred.JobConf;
+
+@SuppressWarnings("deprecation")
+public class GenomixJobConf extends JobConf {
+
+    public static final String JOB_NAME = "genomix";
+
+    /** Kmers length */
+    public static final String KMER_LENGTH = "genomix.kmerlen";
+    /** Read length */
+    public static final String READ_LENGTH = "genomix.readlen";
+    /** Frame Size */
+    public static final String FRAME_SIZE = "genomix.framesize";
+    /** Frame Limit, hyracks need */
+    public static final String FRAME_LIMIT = "genomix.framelimit";
+    /** Table Size, hyracks need */
+    public static final String TABLE_SIZE = "genomix.tablesize";
+    /** Groupby types */
+    public static final String GROUPBY_TYPE = "genomix.graph.groupby.type";
+    /** Graph outputformat */
+    public static final String OUTPUT_FORMAT = "genomix.graph.output";
+    /** Get reversed Kmer Sequence */
+    public static final String REVERSED_KMER = "genomix.kmer.reversed";
+
+    /** Configurations used by hybrid groupby function in graph build phrase */
+    public static final String GROUPBY_HYBRID_INPUTSIZE = "genomix.graph.groupby.hybrid.inputsize";
+    public static final String GROUPBY_HYBRID_INPUTKEYS = "genomix.graph.groupby.hybrid.inputkeys";
+    public static final String GROUPBY_HYBRID_RECORDSIZE_SINGLE = "genomix.graph.groupby.hybrid.recordsize.single";
+    public static final String GROUPBY_HYBRID_RECORDSIZE_CROSS = "genomix.graph.groupby.hybrid.recordsize.cross";
+    public static final String GROUPBY_HYBRID_HASHLEVEL = "genomix.graph.groupby.hybrid.hashlevel";
+
+    public static final int DEFAULT_KMERLEN = 21;
+    public static final int DEFAULT_READLEN = 124;
+    public static final int DEFAULT_FRAME_SIZE = 128 * 1024;
+    public static final int DEFAULT_FRAME_LIMIT = 4096;
+    public static final int DEFAULT_TABLE_SIZE = 10485767;
+    public static final long DEFAULT_GROUPBY_HYBRID_INPUTSIZE = 154000000L;
+    public static final long DEFAULT_GROUPBY_HYBRID_INPUTKEYS = 38500000L;
+    public static final int DEFAULT_GROUPBY_HYBRID_RECORDSIZE_SINGLE = 9;
+    public static final int DEFAULT_GROUPBY_HYBRID_HASHLEVEL = 1;
+    public static final int DEFAULT_GROUPBY_HYBRID_RECORDSIZE_CROSS = 13;
+
+    public static final boolean DEFAULT_REVERSED = true;
+
+    public static final String JOB_PLAN_GRAPHBUILD = "graphbuild";
+    public static final String JOB_PLAN_GRAPHSTAT = "graphstat";
+
+    public static final String GROUPBY_TYPE_HYBRID = "hybrid";
+    public static final String GROUPBY_TYPE_EXTERNAL = "external";
+    public static final String GROUPBY_TYPE_PRECLUSTER = "precluster";
+    public static final String OUTPUT_FORMAT_BINARY = "binary";
+    public static final String OUTPUT_FORMAT_TEXT = "text";
+
+    public GenomixJobConf() throws IOException {
+        super(new Configuration());
+    }
+
+    public GenomixJobConf(Configuration conf) throws IOException {
+        super(conf);
+    }
+
+    /**
+     * Set the kmer length
+     * 
+     * @param the
+     *            desired frame kmerByteSize
+     */
+    final public void setKmerLength(int kmerlength) {
+        setInt(KMER_LENGTH, kmerlength);
+    }
+
+    final public void setFrameSize(int frameSize) {
+        setInt(FRAME_SIZE, frameSize);
+    }
+
+    final public void setFrameLimit(int frameLimit) {
+        setInt(FRAME_LIMIT, frameLimit);
+    }
+
+    final public void setTableSize(int tableSize) {
+        setInt(TABLE_SIZE, tableSize);
+    }
+
+}