switch VKmer to use a saner offset
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 2738b43..2d2907c 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
@@ -29,582 +29,618 @@
 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 = {};
+	private static final long serialVersionUID = 1L;
+	protected static final byte[] EMPTY_BYTES = {};
 
-    protected int lettersInKmer;
-    protected int bytesUsed;
-    protected byte[] bytes;
-    protected int offset;
+	protected int lettersInKmer;
+	protected int bytesUsed;
+	protected byte[] bytes;
+	protected int offset;
 
-    /**
-     * Initialize as empty kmer
-     */
-    public KmerBytesWritable() {
-        this(0, EMPTY_BYTES, 0);
-    }
+	/**
+	 * Initialize as empty kmer
+	 */
+	public KmerBytesWritable() {
+		this(0, EMPTY_BYTES, 0);
+	}
 
-    /**
-     * Copy contents of kmer string
-     */
-    public KmerBytesWritable(String kmer) {
-        setAsCopy(kmer);
-    }
+	/**
+	 * 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);
-    }
+	/**
+	 * 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);
-    }
+	/**
+	 * 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);
-    }
+	/**
+	 * 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, lettersInKmer);
-        }
-    }
+	/**
+	 * 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;
-    }
+	/**
+	 * 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);
-    }
+	/**
+	 * 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();
-    }
+	/**
+	 * 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;
-        setKmerLength(k);
-        if (newData.length - offset < bytesUsed) {
-            throw new IllegalArgumentException("Requested " + bytesUsed + " bytes (k=" + k
-                    + ") but buffer has only " + (newData.length - offset) + " bytes");
-        }
-    }
+	/**
+	 * 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");
+		}
+	}
 
-    protected void setSize(int size) {
-        if (size > getCapacity()) {
-            setCapacity((size * 3 / 2));
-        }
-        this.bytesUsed = size;
-    }
+	/**
+	 * Ensures that there is space for at least `size` bytes of kmer (not
+	 * including any header)
+	 * 
+	 */
+	protected void setSize(int size) {
+		if (size > getCapacity()) {
+			setCapacity((size * 3 / 2));
+		}
+		this.bytesUsed = size;
+	}
 
-    protected int getCapacity() {
-        return bytes.length;
-    }
+	/**
+	 * return the number of bytes in use for the kmer (not including any header)
+	 */
+	protected int getCapacity() {
+		return bytes.length;
+	}
 
-    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;
-        }
-    }
+	/**
+	 * 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;
+		}
+	}
 
-    /**
-     * 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);
-    }
+	/**
+	 * 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);
+	}
 
-    // 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);
-    }
+	// 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);
+	}
 
-    public void setKmerLength(int k) {
-        this.bytesUsed = KmerUtil.getByteNumFromK(k);
-        this.lettersInKmer = k;
-    }
+	public void setKmerLength(int k) {
+		this.bytesUsed = KmerUtil.getByteNumFromK(k);
+		this.lettersInKmer = k;
+	}
 
-    public int getKmerLength() {
-        return lettersInKmer;
-    }
+	public int getKmerLength() {
+		return lettersInKmer;
+	}
 
-    @Override
-    public byte[] getBytes() {
-        return bytes;
-    }
+	@Override
+	public byte[] getBytes() {
+		return bytes;
+	}
 
-    public int getOffset() {
-        return offset;
-    }
+	public int getOffset() {
+		return offset;
+	}
 
-    @Override
-    public int getLength() {
-        return bytesUsed;
-    }
+	@Override
+	public int getLength() {
+		return bytesUsed;
+	}
 
-    /**
-     * 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;
-        }
-    }
+	/**
+	 * 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;
+		}
+	}
 
-    public void setByRead(int k, byte[] array, int start) {
-        reset(k);
-        setByRead(array, start);
-    }
+	public void setByRead(int k, byte[] array, int start) {
+		reset(k);
+		setByRead(array, start);
+	}
 
-    /**
-     * 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;
-        }
-    }
+	/**
+	 * 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;
+		}
+	}
 
-    public void setByReadReverse(int k, byte[] array, int start) {
-        reset(k);
-        setByReadReverse(array, start);
-    }
+	public void setByReadReverse(int k, byte[] array, int start) {
+		reset(k);
+		setByReadReverse(array, start);
+	}
 
-    /**
-     * 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));
-    }
+	/**
+	 * 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));
+	}
 
-    /**
-     * 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;
-    }
+	/**
+	 * 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;
+	}
 
-    /**
-     * 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));
-    }
+	/**
+	 * 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));
+	}
 
-    /**
-     * 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;
-    }
+	/**
+	 * 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;
+	}
 
-    /**
-     * 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();
-    }
+	/**
+	 * 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();
+	}
 
-    /**
-     * 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];
-        }
+	/**
+	 * 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];
+		}
 
-        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;
-        }
-    }
+		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;
+		}
+	}
 
-    /**
-     * 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 = lettersInKmer;
-        int preSize = bytesUsed;
-        lettersInKmer += preKmer.lettersInKmer - initialKmerSize + 1;
-        setSize(KmerUtil.getByteNumFromK(lettersInKmer));
-        //        byte cacheByte = getOneByteFromKmerAtPosition(0, bytes, offset, preSize);
+	/**
+	 * 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 = lettersInKmer;
+		int preSize = bytesUsed;
+		lettersInKmer += preKmer.lettersInKmer - initialKmerSize + 1;
+		setSize(KmerUtil.getByteNumFromK(lettersInKmer));
+		// byte cacheByte = getOneByteFromKmerAtPosition(0, bytes, offset,
+		// preSize);
 
-        int byteIndex = bytesUsed - 1;
-        byte cacheByte = 0x00;
-        int posnInByte = 0;
+		int byteIndex = bytesUsed - 1;
+		byte cacheByte = 0x00;
+		int posnInByte = 0;
 
-        // copy rc of preKmer into high bytes
-        for (int i = preKmer.lettersInKmer - 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 rc of preKmer into high bytes
+		for (int i = preKmer.lettersInKmer - 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 + (bytesUsed - preSize) * 4;
-            byte code = geneCodeAtPosition(newposn);
-            cacheByte |= (byte) (code << posnInByte);
-            posnInByte += 2;
-            if (posnInByte == 8) {
-                bytes[byteIndex--] = cacheByte;
-                cacheByte = 0;
-                posnInByte = 0;
-            }
-        }
-        bytes[offset] = cacheByte;
-        clearLeadBit();
-    }
+		// 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 + (bytesUsed - preSize) * 4;
+			byte code = geneCodeAtPosition(newposn);  // TODO: this evaluation may be reading from a place we just overwrote :( 
+			cacheByte |= (byte) (code << posnInByte);
+			posnInByte += 2;
+			if (posnInByte == 8) {
+				bytes[byteIndex--] = cacheByte;
+				cacheByte = 0;
+				posnInByte = 0;
+			}
+		}
+		if (posnInByte > 0)
+			bytes[offset] = cacheByte;
+		clearLeadBit();
+	}
 
-    /**
-     * 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);
+	/**
+	 * 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);
 
-        // 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);
-        }
+		// 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);
+		}
 
-        // 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();
-    }
+		// 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();
+	}
 
-    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);
-        }
-    }
+	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);
+		}
+	}
 
-    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 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);
 
-        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))));
-        }
-    }
+		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 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;
-    }
+	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 (lettersInKmer % 4 != 0) {
-            bytes[offset] &= (1 << ((lettersInKmer % 4) << 1)) - 1;
-        }
-    }
+	protected void clearLeadBit() {
+		if (lettersInKmer % 4 != 0) {
+			bytes[offset] &= (1 << ((lettersInKmer % 4) << 1)) - 1;
+		}
+	}
 
-    @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;
-                
-            }
-            in.readFully(bytes, offset, bytesUsed);
-        }
-    }
+	@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;
 
-    @Override
-    public void write(DataOutput out) throws IOException {
-        out.writeInt(lettersInKmer);
-        if (lettersInKmer > 0) {
-            out.write(bytes, offset, bytesUsed);
-        }
-    }
+			}
+			in.readFully(bytes, offset, bytesUsed);
+		}
+	}
 
-    @Override
-    public int hashCode() {
-        return super.hashCode() * 31 + this.lettersInKmer;
-    }
+	@Override
+	public void write(DataOutput out) throws IOException {
+		out.writeInt(lettersInKmer);
+		if (lettersInKmer > 0) {
+			out.write(bytes, offset, bytesUsed);
+		}
+	}
 
-    @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;
-    }
+	@Override
+	public int hashCode() {
+		return super.hashCode() * 31 + this.lettersInKmer;
+	}
 
-    @Override
-    public String toString() {
-        return KmerUtil.recoverKmerFrom(this.lettersInKmer, this.getBytes(), offset, this.getLength());
-    }
+	@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;
+	}
 
-    public static class Comparator extends WritableComparator {
-    	private static final int LEADING_BYTES = 4;
+	@Override
+	public String toString() {
+		return KmerUtil.recoverKmerFrom(this.lettersInKmer, this.getBytes(),
+				offset, this.getLength());
+	}
 
-        public Comparator() {
-            super(KmerBytesWritable.class);
-        }
+	public static class Comparator extends WritableComparator {
+		private static final int LEADING_BYTES = 4;
 
-        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 Comparator() {
+			super(KmerBytesWritable.class);
+		}
 
-    static { // register this comparator
-        WritableComparator.define(KmerBytesWritable.class, new Comparator());
-    }
+		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;
+		}
+	}
+
+	static { // register this comparator
+		WritableComparator.define(KmerBytesWritable.class, new Comparator());
+	}
 
 }
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
index cd982ef..0e26b77 100644
--- 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
@@ -46,7 +46,7 @@
 	 * Initialize as empty kmer
 	 */
 	public VKmerBytesWritable() {
-		this(EMPTY_BYTES, 0);
+		this(EMPTY_BYTES, HEADER_SIZE);
 	}
 
 	/**
@@ -54,12 +54,16 @@
 	 */
 	public VKmerBytesWritable(String kmer) {
 		bytes = new byte[HEADER_SIZE + KmerUtil.getByteNumFromK(kmer.length())];
-		offset = 0;
+		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);
@@ -74,7 +78,7 @@
 		} else {
 			bytes = EMPTY_BYTES;
 		}
-		offset = 0;
+		offset = HEADER_SIZE;
 		setKmerLength(k);
 	}
 
@@ -97,21 +101,8 @@
 	public void setAsCopy(KmerBytesWritable other) {
 		reset(other.lettersInKmer);
 		if (lettersInKmer > 0) {
-			System.arraycopy(other.bytes, other.offset, bytes, this.offset
-					+ HEADER_SIZE, lettersInKmer);
-		}
-	}
-
-	/**
-	 * Deep copy of the given kmer
-	 * 
-	 * @param other
-	 */
-	public void setAsCopy(VKmerBytesWritable other) {
-		reset(other.lettersInKmer);
-		if (lettersInKmer > 0) {
-			System.arraycopy(other.bytes, other.offset + HEADER_SIZE, bytes,
-					this.offset + HEADER_SIZE, lettersInKmer);
+			System.arraycopy(other.bytes, other.offset, bytes, this.offset,
+					bytesUsed);
 		}
 	}
 
@@ -122,21 +113,7 @@
 	public void setAsCopy(String kmer) {
 		int k = kmer.length();
 		reset(k);
-		System.arraycopy(kmer.getBytes(), 0, bytes, offset + HEADER_SIZE, k);
-	}
-
-	/**
-	 * Deep copy of the given bytes data
-	 * 
-	 * @param k
-	 * @param newData
-	 *            : presumed NOT to have a header
-	 * @param offset
-	 */
-	@Override
-	public void setAsCopy(int k, byte[] newData, int offset) {
-		reset(k);
-		System.arraycopy(newData, offset, bytes, this.offset + HEADER_SIZE, k);
+		System.arraycopy(kmer.getBytes(), 0, bytes, offset, bytesUsed);
 	}
 
 	/**
@@ -149,8 +126,7 @@
 	public void setAsCopy(byte[] newData, int offset) {
 		int k = Marshal.getInt(newData, offset);
 		reset(k);
-		System.arraycopy(newData, offset + HEADER_SIZE, bytes, this.offset
-				+ HEADER_SIZE, k);
+		System.arraycopy(newData, offset + HEADER_SIZE, bytes, this.offset, bytesUsed);
 	}
 
 	/**
@@ -163,9 +139,9 @@
 	 */
 	public void setAsReference(byte[] newData, int offset) {
 		this.bytes = newData;
-		this.offset = offset;
+		this.offset = offset + HEADER_SIZE;
 		int kRequested = Marshal.getInt(newData, offset);
-		int bytesRequested = KmerUtil.getByteNumFromK(kRequested);
+		int bytesRequested = KmerUtil.getByteNumFromK(kRequested) + HEADER_SIZE;
 		if (newData.length - offset < bytesRequested) {
 			throw new IllegalArgumentException("Requested " + bytesRequested
 					+ " bytes (k=" + kRequested + ") but buffer has only "
@@ -176,164 +152,86 @@
 
 	@Override
 	public void setKmerLength(int k) {
-		this.bytesUsed = HEADER_SIZE + KmerUtil.getByteNumFromK(k);
+		this.bytesUsed = KmerUtil.getByteNumFromK(k);
 		this.lettersInKmer = k;
-		Marshal.putInt(k, bytes, offset);
+		Marshal.putInt(k, bytes, offset - HEADER_SIZE);
 	}
-
+	
 	@Override
-	public void setByRead(byte[] stringBytes, int start) {
-		offset += HEADER_SIZE;
-		super.setByRead(stringBytes, start);
-		offset -= HEADER_SIZE;
+	protected int getCapacity() {
+		return bytes.length - HEADER_SIZE;
 	}
-
+	
 	@Override
-	public void setByReadReverse(byte[] array, int start) {
-		offset += HEADER_SIZE;
-		super.setByReadReverse(array, start);
-		offset -= HEADER_SIZE;
+	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 byte shiftKmerWithNextCode(byte c) {
-		offset += HEADER_SIZE;
-		byte retval = super.shiftKmerWithNextCode(c);
-		offset -= HEADER_SIZE;
-		return retval;
-
-	}
-
-	@Override
-	public byte shiftKmerWithPreCode(byte c) {
-		offset += HEADER_SIZE;
-		byte retval = super.shiftKmerWithPreCode(c);
-		offset -= HEADER_SIZE;
-		return retval;
-	}
 
 	@Override
 	public void mergeWithFFKmer(int initialKmerSize, KmerBytesWritable kmer) {
-		offset += HEADER_SIZE;
 		super.mergeWithFFKmer(initialKmerSize, kmer);
-		offset -= HEADER_SIZE;
-		Marshal.putInt(lettersInKmer, bytes, offset);
-	}
-
-	/**
-	 * Merge with kmer that's FF to me. See KmerBytesWritable.mergeWithFFKmer.
-	 */
-	public void mergeWithFFKmer(int initialKmerSize, VKmerBytesWritable kmer) {
-		offset += HEADER_SIZE;
-		kmer.offset += HEADER_SIZE;
-		super.mergeWithFFKmer(initialKmerSize, kmer);
-		offset -= HEADER_SIZE;
-		kmer.offset -= HEADER_SIZE;
-		Marshal.putInt(lettersInKmer, bytes, offset);
+		Marshal.putInt(lettersInKmer, bytes, offset - HEADER_SIZE);
 	}
 
 	@Override
 	public void mergeWithFRKmer(int initialKmerSize, KmerBytesWritable kmer) {
-		offset += HEADER_SIZE;
 		super.mergeWithFRKmer(initialKmerSize, kmer);
-		offset -= HEADER_SIZE;
-		Marshal.putInt(lettersInKmer, bytes, offset);
-	}
-
-	/**
-	 * Merge with kmer that's FR to me. See KmerBytesWritable.mergeWithFRKmer.
-	 */
-	public void mergeWithFRKmer(int initialKmerSize, VKmerBytesWritable kmer) {
-		offset += HEADER_SIZE;
-		kmer.offset += HEADER_SIZE;
-		super.mergeWithFRKmer(initialKmerSize, kmer);
-		offset -= HEADER_SIZE;
-		kmer.offset -= HEADER_SIZE;
-		Marshal.putInt(lettersInKmer, bytes, offset);
+		Marshal.putInt(lettersInKmer, bytes, offset - HEADER_SIZE);
 	}
 
 	@Override
 	public void mergeWithRFKmer(int initialKmerSize, KmerBytesWritable preKmer) {
-		offset += HEADER_SIZE;
 		super.mergeWithRFKmer(initialKmerSize, preKmer);
-		offset -= HEADER_SIZE;
-		Marshal.putInt(lettersInKmer, bytes, offset);
-	}
-
-	/**
-	 * Merge with kmer that's RF to me. See KmerBytesWritable.mergeWithRFKmer.
-	 */
-	public void mergeWithRFKmer(int initialKmerSize, VKmerBytesWritable preKmer) {
-		offset += HEADER_SIZE;
-		preKmer.offset += HEADER_SIZE;
-		super.mergeWithRFKmer(initialKmerSize, preKmer);
-		offset -= HEADER_SIZE;
-		preKmer.offset -= HEADER_SIZE;
-		Marshal.putInt(lettersInKmer, bytes, offset);
+		Marshal.putInt(lettersInKmer, bytes, offset - HEADER_SIZE);
 	}
 
 	@Override
 	public void mergeWithRRKmer(int initialKmerSize, KmerBytesWritable preKmer) {
-		offset += HEADER_SIZE;
 		super.mergeWithRRKmer(initialKmerSize, preKmer);
-		offset -= HEADER_SIZE;
-		Marshal.putInt(lettersInKmer, bytes, offset);
-	}
-
-	/**
-	 * Merge with kmer that's RR to me. See KmerBytesWritable.mergeWithRRKmer.
-	 */
-	public void mergeWithRRKmer(int initialKmerSize, VKmerBytesWritable preKmer) {
-		offset += HEADER_SIZE;
-		preKmer.offset += HEADER_SIZE;
-		super.mergeWithRRKmer(initialKmerSize, preKmer);
-		offset -= HEADER_SIZE;
-		preKmer.offset -= HEADER_SIZE;
-		Marshal.putInt(lettersInKmer, bytes, offset);
-	}
-
-	@Override
-	protected void clearLeadBit() {
-		offset += HEADER_SIZE;
-		super.clearLeadBit();
-		offset -= HEADER_SIZE;
+		Marshal.putInt(lettersInKmer, bytes, offset - HEADER_SIZE);
 	}
 
 	@Override
 	public void readFields(DataInput in) throws IOException {
 		lettersInKmer = in.readInt();
-		bytesUsed = HEADER_SIZE + KmerUtil.getByteNumFromK(lettersInKmer);
+		bytesUsed = KmerUtil.getByteNumFromK(lettersInKmer);
 		if (lettersInKmer > 0) {
-			if (this.bytes.length < this.bytesUsed) {
-				this.bytes = new byte[this.bytesUsed];
-				this.offset = 0;
+			if (getCapacity() < this.bytesUsed) {
+				this.bytes = new byte[this.bytesUsed + HEADER_SIZE];
+				this.offset = HEADER_SIZE;
 			}
-			in.readFully(bytes, offset + HEADER_SIZE, bytesUsed - HEADER_SIZE);
+			in.readFully(bytes, offset, bytesUsed);
 		}
-		Marshal.putInt(lettersInKmer, bytes, offset);
+		Marshal.putInt(lettersInKmer, bytes, offset - HEADER_SIZE);
 	}
 
 	@Override
 	public void write(DataOutput out) throws IOException {
-		out.writeInt(lettersInKmer);
-		if (lettersInKmer > 0) {
-			out.write(bytes, offset + HEADER_SIZE, bytesUsed - HEADER_SIZE);
-		}
+		out.write(bytes, offset - HEADER_SIZE, bytesUsed + HEADER_SIZE);
 	}
 
 	@Override
 	public boolean equals(Object right) {
 		if (right instanceof VKmerBytesWritable) {
-			return this.lettersInKmer == ((VKmerBytesWritable) right).lettersInKmer
-					&& super.equals(right);
+			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) {
-				// break early
+			if (lettersInKmer != rightKmer.lettersInKmer) { // check length
 				return false;
 			}
-			for (int i = 0; i < lettersInKmer; i++) {
+			for (int i = 0; i < lettersInKmer; i++) { // check letters
 				if (bytes[i + HEADER_SIZE] != rightKmer.bytes[i]) {
 					return false;
 				}
@@ -346,7 +244,7 @@
 	@Override
 	public String toString() {
 		return KmerUtil.recoverKmerFrom(this.lettersInKmer, this.getBytes(),
-				offset + HEADER_SIZE, this.getLength());
+				offset, this.getLength());
 	}
 
 	public static class Comparator extends WritableComparator {
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 3a8fb93..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
@@ -229,14 +229,24 @@
         merge.mergeWithRFKmer(i, kmer2);
         Assert.assertEquals("GGCACAACAACCC", merge.toString());
         
-        String test1 = "CTA";
-        String 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("CTAT", k1);
+//        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 ??
+        
+        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
     }
     
     
@@ -282,4 +292,22 @@
         }
     }
 
+    @Test
+    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..0506a08
--- /dev/null
+++ b/genomix/genomix-data/src/test/java/edu/uci/ics/genomix/data/test/VKmerBytesWritableTest.java
@@ -0,0 +1,323 @@
+/*
+ * 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.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());
+	}
+}