no more inherited Kmers
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 c345836..26c4088 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,8 +25,6 @@
 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;
 
 /**
  * Fixed, static-length Kmer used as the key and edge values of each
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 7fed5c7..133724b 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
@@ -18,255 +18,563 @@
 import java.io.DataInput;
 import java.io.DataOutput;
 import java.io.IOException;
+import java.io.Serializable;
 
+import org.apache.hadoop.io.BinaryComparable;
+import org.apache.hadoop.io.WritableComparable;
 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-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 {
+public class VKmerBytesWritable extends BinaryComparable implements Serializable, WritableComparable<BinaryComparable> {
+    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
 
-	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
+    protected int lettersInKmer;
+    protected int bytesUsed;
+    protected byte[] bytes;
+    protected int kmerStartOffset;
 
-	/**
-	 * Initialize as empty kmer
-	 */
-	public VKmerBytesWritable() {
-		this(EMPTY_BYTES, HEADER_SIZE);
-	}
+    /**
+     * Initialize as empty kmer
+     */
+    public VKmerBytesWritable() {
+        this(EMPTY_BYTES, 0);
+    }
 
-	/**
-	 * Copy contents of kmer string
-	 */
-	public VKmerBytesWritable(String kmer) {
-		bytes = new byte[HEADER_SIZE + KmerUtil.getByteNumFromK(kmer.length())];
-		offset = HEADER_SIZE;
-		setAsCopy(kmer);
-	}
+    /**
+     * Copy contents of kmer string
+     */
+    public VKmerBytesWritable(String kmer) {
+        bytes = new byte[HEADER_SIZE + KmerUtil.getByteNumFromK(kmer.length())];
+        kmerStartOffset = 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);
-	}
+    /**
+     * 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);
-	}
+    /**
+     * Reserve space for k letters
+     */
+    public VKmerBytesWritable(int k) {
+        if (k > 0) {
+            bytes = new byte[HEADER_SIZE + KmerUtil.getByteNumFromK(k)];
+        } else if (k == 0) {
+            bytes = EMPTY_BYTES;
+        } else {
+            throw new IllegalArgumentException("Invalid K (" + k + ").");
+        }
+        kmerStartOffset = HEADER_SIZE;
+        setKmerLength(k);
+    }
 
-	/**
-	 * deep copy of kmer in other
-	 * 
-	 * @param other
-	 */
-	public VKmerBytesWritable(VKmerBytesWritable other) {
-		this(other.lettersInKmer);
-		setAsCopy(other);
-	}
+    /**
+     * 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);
-		}
-	}
+    /**
+     * Deep copy of the given kmer
+     * 
+     * @param other
+     */
+    public void setAsCopy(VKmerBytesWritable other) {
+        reset(other.lettersInKmer);
+        if (lettersInKmer > 0) {
+            System.arraycopy(other.bytes, other.kmerStartOffset, bytes, this.kmerStartOffset, 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);
-	}
+    /**
+     * set from String kmer
+     */
+    public void setAsCopy(String kmer) {
+        int k = kmer.length();
+        reset(k);
+        System.arraycopy(kmer.getBytes(), 0, bytes, kmerStartOffset, 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);
-	}
+    /**
+     * 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.kmerStartOffset, 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);
-	}
+    /**
+     * 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) {
+        bytes = newData;
+        kmerStartOffset = 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);
-	}
+    /**
+     * Reset array by kmerlength
+     * 
+     * @param k
+     */
+    public void reset(int k) {
+        setKmerLength(k);
+        setSize(bytesUsed);
+        clearLeadBit();
+    }
 
-	@Override
-	protected int getCapacity() {
-		return bytes.length - HEADER_SIZE;
-	}
+    protected void clearLeadBit() {
+        if (lettersInKmer % 4 != 0) {
+            bytes[kmerStartOffset] &= (1 << ((lettersInKmer % 4) << 1)) - 1;
+        }
+    }
 
-	@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;
-		}
-	}
+    /**
+     * 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 || pos < 0) {
+            throw new ArrayIndexOutOfBoundsException("Gene position (" + pos + ") out of bounds for k=" + lettersInKmer);
+        }
+        return geneCodeAtPosition(pos);
+    }
 
-	@Override
-	public void mergeWithFFKmer(int initialKmerSize, KmerBytesWritable kmer) {
-		super.mergeWithFFKmer(initialKmerSize, kmer);
-		Marshal.putInt(lettersInKmer, bytes, offset - HEADER_SIZE);
-	}
+    /**
+     * unchecked version of getGeneCodeAtPosition. Used when kmerlength is
+     * inaccurate (mid-merge)
+     */
+    private byte geneCodeAtPosition(int pos) {
+        int posByte = pos / 4;
+        int shift = (pos % 4) << 1;
+        return (byte) ((bytes[kmerStartOffset + bytesUsed - 1 - posByte] >> shift) & 0x3);
+    }
 
-	@Override
-	public void mergeWithFRKmer(int initialKmerSize, KmerBytesWritable kmer) {
-		super.mergeWithFRKmer(initialKmerSize, kmer);
-		Marshal.putInt(lettersInKmer, bytes, offset - HEADER_SIZE);
-	}
+    /**
+     * 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));
+    }
 
-	@Override
-	public void mergeWithRFKmer(int initialKmerSize, KmerBytesWritable preKmer) {
-		super.mergeWithRFKmer(initialKmerSize, preKmer);
-		Marshal.putInt(lettersInKmer, bytes, offset - HEADER_SIZE);
-	}
+    /**
+     * 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[kmerStartOffset + bytesUsed - 1] & 0x03);
+        for (int i = bytesUsed - 1; i > 0; i--) {
+            byte in = (byte) (bytes[kmerStartOffset + i - 1] & 0x03);
+            bytes[kmerStartOffset + i] = (byte) (((bytes[kmerStartOffset + i] >>> 2) & 0x3f) | (in << 6));
+        }
+        int pos = ((lettersInKmer - 1) % 4) << 1;
+        byte code = (byte) (c << pos);
+        bytes[kmerStartOffset] = (byte) (((bytes[kmerStartOffset] >>> 2) & 0x3f) | code);
+        clearLeadBit();
+        return output;
+    }
 
-	@Override
-	public void mergeWithRRKmer(int initialKmerSize, KmerBytesWritable preKmer) {
-		super.mergeWithRRKmer(initialKmerSize, preKmer);
-		Marshal.putInt(lettersInKmer, bytes, offset - HEADER_SIZE);
-	}
+    /**
+     * 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 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);
-	}
+    /**
+     * 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[kmerStartOffset] >> pos) & 0x03);
+        for (int i = 0; i < bytesUsed - 1; i++) {
+            byte in = (byte) ((bytes[kmerStartOffset + i + 1] >> 6) & 0x03);
+            bytes[kmerStartOffset + i] = (byte) ((bytes[kmerStartOffset + i] << 2) | in);
+        }
+        bytes[kmerStartOffset + bytesUsed - 1] = (byte) ((bytes[kmerStartOffset + bytesUsed - 1] << 2) | c);
+        clearLeadBit();
+        return output;
+    }
 
-	/**
-	 * 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);
-	}
+    public int getKmerLength() {
+        return lettersInKmer;
+    }
 
-	@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 byte[] getBytes() {
+        return bytes;
+    }
 
-	@Override
-	public String toString() {
-		return KmerUtil.recoverKmerFrom(this.lettersInKmer, this.getBytes(),
-				offset, this.getLength());
-	}
+    /**
+     * Return the (hyracks-specific) data block offset. This includes the header.
+     */
+    public int getBlockOffset() {
+        return kmerStartOffset - HEADER_SIZE;
+    }
 
-	public static class Comparator extends WritableComparator {
+    /**
+     * Return the data block offset where the kmer data begins. This excludes the header.
+     */
+    public int getKmerOffset() {
+        return kmerStartOffset;
+    }
 
-		public Comparator() {
-			super(VKmerBytesWritable.class);
-		}
+    @Override
+    public int getLength() {
+        return bytesUsed;
+    }
 
-		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;
-		}
-	}
+    public void setKmerLength(int k) {
+        this.bytesUsed = KmerUtil.getByteNumFromK(k);
+        this.lettersInKmer = k;
+        saveHeader(k);
+    }
 
-	static { // register this comparator
-		WritableComparator.define(VKmerBytesWritable.class, new Comparator());
-	}
+    protected int getKmerByteCapacity() {
+        return bytes.length - HEADER_SIZE;
+    }
+
+    protected void setKmerByteCapacity(int new_cap) {
+        if (new_cap != getKmerByteCapacity()) {
+            byte[] new_data = new byte[new_cap + HEADER_SIZE];
+            if (new_cap < bytesUsed) {
+                bytesUsed = new_cap;
+            }
+            if (bytesUsed != 0) {
+                System.arraycopy(bytes, kmerStartOffset, new_data, HEADER_SIZE, bytesUsed);
+            }
+            bytes = new_data;
+            kmerStartOffset = HEADER_SIZE;
+        }
+    }
+
+    private void saveHeader(int length) {
+        Marshal.putInt(length, bytes, kmerStartOffset - HEADER_SIZE);
+    }
+
+    @Override
+    public void readFields(DataInput in) throws IOException {
+        lettersInKmer = in.readInt();
+        bytesUsed = KmerUtil.getByteNumFromK(lettersInKmer);
+        if (lettersInKmer > 0) {
+            if (getKmerByteCapacity() < this.bytesUsed) {
+                this.bytes = new byte[this.bytesUsed + HEADER_SIZE];
+                this.kmerStartOffset = HEADER_SIZE;
+            }
+            in.readFully(bytes, kmerStartOffset, bytesUsed);
+        }
+    }
+
+    /**
+     * write the entire byte array including the header
+     */
+    @Override
+    public void write(DataOutput out) throws IOException {
+        out.write(bytes, kmerStartOffset - HEADER_SIZE, bytesUsed + HEADER_SIZE);
+    }
+
+    @Override
+    public boolean equals(Object right) {
+        if (right instanceof VKmerBytesWritable) {
+            return lettersInKmer == ((VKmerBytesWritable) right).lettersInKmer && super.equals(right); // compare bytes directly
+        }
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return KmerUtil.recoverKmerFrom(this.lettersInKmer, bytes, kmerStartOffset, bytesUsed);
+    }
+
+    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());
+    }
+
+    /**
+     * Ensures that there is space for at least `size` bytes of kmer (not
+     * including any header)
+     */
+    protected void setSize(int size) {
+        if (size > getKmerByteCapacity()) {
+            setKmerByteCapacity((size * 3 / 2));
+        }
+        this.bytesUsed = size;
+    }
+
+    public void setByRead(int k, byte[] stringBytes, int start) {
+        reset(k);
+        setByRead(stringBytes, start);
+    }
+
+    /**
+     * Read Kmer from read text into bytes array e.g. AATAG will compress as
+     * [0x000G, 0xATAA]
+     * 
+     * @param stringBytes
+     * @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[kmerStartOffset + bcount--] = l;
+                l = 0;
+                bytecount = 0;
+            }
+        }
+        if (bcount >= 0) {
+            bytes[kmerStartOffset] = l;
+        }
+    }
+
+    public void setByReadReverse(int k, byte[] stringBytes, int start) {
+        reset(k);
+        setByReadReverse(stringBytes, 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[kmerStartOffset + bcount--] = l;
+                l = 0;
+                bytecount = 0;
+            }
+        }
+        if (bcount >= 0) {
+            bytes[kmerStartOffset] = l;
+        }
+    }
+
+    /**
+     * 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, VKmerBytesWritable kmer) {
+        int preKmerLength = lettersInKmer;
+        int preSize = bytesUsed;
+        lettersInKmer += kmer.lettersInKmer - initialKmerSize + 1;
+        setSize(KmerUtil.getByteNumFromK(lettersInKmer));
+        for (int i = 1; i <= preSize; i++) {
+            bytes[kmerStartOffset + bytesUsed - i] = bytes[kmerStartOffset + preSize - i];
+        }
+        for (int k = initialKmerSize - 1; k < kmer.getKmerLength(); k += 4) {
+            byte onebyte = KmerBytesWritable.getOneByteFromKmerAtPosition(k, kmer.bytes, kmer.kmerStartOffset,
+                    kmer.bytesUsed);
+            KmerBytesWritable.appendOneByteAtPosition(preKmerLength + k - initialKmerSize + 1, onebyte, bytes,
+                    kmerStartOffset, bytesUsed);
+        }
+        clearLeadBit();
+        saveHeader(lettersInKmer);
+    }
+
+    /**
+     * 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, VKmerBytesWritable 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[kmerStartOffset + bytesUsed - i] = bytes[kmerStartOffset + preSize - i];
+        }
+
+        int bytecount = (preKmerLength % 4) * 2;
+        int bcount = bytesUsed - preSize - bytecount / 8; // may overlap
+                                                          // previous kmer
+        byte l = bcount == bytesUsed - preSize ? bytes[kmerStartOffset + 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[kmerStartOffset + bcount--] = l;
+                l = 0;
+                bytecount = 0;
+            }
+        }
+        if (bcount >= 0) {
+            bytes[kmerStartOffset] = l;
+        }
+        saveHeader(lettersInKmer);
+    }
+
+    /**
+     * 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, VKmerBytesWritable preKmer) {
+        VKmerBytesWritable reversed = new VKmerBytesWritable(preKmer.lettersInKmer);
+        reversed.setByReadReverse(preKmer.toString().getBytes(), 0);
+        mergeWithRRKmer(initialKmerSize, reversed);
+    }
+
+    /**
+     * 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, VKmerBytesWritable preKmer) {
+        int preKmerLength = lettersInKmer;
+        int preSize = bytesUsed;
+        lettersInKmer += preKmer.lettersInKmer - initialKmerSize + 1;
+        setSize(KmerUtil.getByteNumFromK(lettersInKmer));
+        byte cacheByte = KmerBytesWritable.getOneByteFromKmerAtPosition(0, bytes, kmerStartOffset, preSize);
+
+        // copy prekmer
+        for (int k = 0; k < preKmer.lettersInKmer - initialKmerSize + 1; k += 4) {
+            byte onebyte = KmerBytesWritable.getOneByteFromKmerAtPosition(k, preKmer.bytes, preKmer.kmerStartOffset,
+                    preKmer.bytesUsed);
+            KmerBytesWritable.appendOneByteAtPosition(k, onebyte, bytes, kmerStartOffset, bytesUsed);
+        }
+
+        // copy current kmer
+        int k = 4;
+        for (; k < preKmerLength; k += 4) {
+            byte onebyte = KmerBytesWritable.getOneByteFromKmerAtPosition(k, bytes, kmerStartOffset, preSize);
+            KmerBytesWritable.appendOneByteAtPosition(preKmer.lettersInKmer - initialKmerSize + k - 4 + 1, cacheByte,
+                    bytes, kmerStartOffset, bytesUsed);
+            cacheByte = onebyte;
+        }
+        KmerBytesWritable.appendOneByteAtPosition(preKmer.lettersInKmer - initialKmerSize + k - 4 + 1, cacheByte,
+                bytes, kmerStartOffset, bytesUsed);
+        clearLeadBit();
+    }
+
+    public void mergeWithKmerInDir(byte dir, int initialKmerSize, VKmerBytesWritable 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);
+        }
+    }
 
 }
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
index a50e465..b2545e3 100644
--- 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
@@ -24,386 +24,376 @@
 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;
+    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");
+    @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");
-	}
+        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");
+    @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);
-		}
+        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");
-	}
+        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");
+    @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");
-	}
+        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");
+    @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);
-		}
+        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");
-	}
+        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);
+    @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))));
-		}
-	}
+        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 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 = KmerBytesWritable.getOneByteFromKmerAtPosition(b, kmer.getBytes(),
+                        kmer.getKmerOffset(), 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);
+                KmerBytesWritable.appendOneByteAtPosition(b, byteActual, kmerAppend.getBytes(),
+                        kmerAppend.getKmerOffset(), 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());
+    @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());
 
-		for (int i = 1; i < 8; i++) {
-			merge.setAsCopy(kmer1);
-			merge.mergeWithFFKmer(i, kmer2);
-			Assert.assertEquals(text1 + text2.substring(i - 1),
-					merge.toString());
-		}
+        VKmerBytesWritable kmer2 = new VKmerBytesWritable(8);
+        kmer2.setByRead(array, 1);
+        String text2 = "GCTGACCG";
+        Assert.assertEquals(text2, kmer2.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());
-				}
-			}
-		}
-	}
+        VKmerBytesWritable merge = new VKmerBytesWritable(kmer1);
+        int kmerSize = 8;
+        merge.mergeWithFFKmer(kmerSize, kmer2);
+        Assert.assertEquals(text1 + text2.substring(kmerSize - 1), merge.toString());
 
-	@Test
-	public void TestMergeFRKmer() {
-		int kmerSize = 3;
-		String result = "AAGCTAACAACC";
-		byte[] resultArray = result.getBytes();
+        for (int i = 1; i < 8; i++) {
+            merge.setAsCopy(kmer1);
+            merge.mergeWithFFKmer(i, kmer2);
+            Assert.assertEquals(text1 + text2.substring(i - 1), merge.toString());
+        }
 
-		String text1 = "AAGCTAA";
-		VKmerBytesWritable kmer1 = new VKmerBytesWritable(text1.length());
-		kmer1.setByRead(resultArray, 0);
-		Assert.assertEquals(text1, kmer1.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());
+                }
+            }
+        }
+    }
 
-		// 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());
+    @Test
+    public void TestMergeFRKmer() {
+        int kmerSize = 3;
+        String result = "AAGCTAACAACC";
+        byte[] resultArray = result.getBytes();
 
-		VKmerBytesWritable merge = new VKmerBytesWritable(kmer1);
-		merge.mergeWithFRKmer(kmerSize, kmer2);
-		Assert.assertEquals(result, merge.toString());
+        String text1 = "AAGCTAA";
+        VKmerBytesWritable kmer1 = new VKmerBytesWritable(text1.length());
+        kmer1.setByRead(resultArray, 0);
+        Assert.assertEquals(text1, kmer1.toString());
 
-		int i = 1;
-		merge.setAsCopy(kmer1);
-		merge.mergeWithFRKmer(i, kmer2);
-		Assert.assertEquals("AAGCTAAAACAACC", merge.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());
 
-		i = 2;
-		merge.setAsCopy(kmer1);
-		merge.mergeWithFRKmer(i, kmer2);
-		Assert.assertEquals("AAGCTAAACAACC", merge.toString());
+        VKmerBytesWritable merge = new VKmerBytesWritable(kmer1);
+        merge.mergeWithFRKmer(kmerSize, kmer2);
+        Assert.assertEquals(result, merge.toString());
 
-		i = 3;
-		merge.setAsCopy(kmer1);
-		merge.mergeWithFRKmer(i, kmer2);
-		Assert.assertEquals("AAGCTAACAACC", merge.toString());
-	}
+        int i = 1;
+        merge.setAsCopy(kmer1);
+        merge.mergeWithFRKmer(i, kmer2);
+        Assert.assertEquals("AAGCTAAAACAACC", merge.toString());
 
-	@Test
-	public void TestMergeRFKmer() {
-		int kmerSize = 3;
-		String result = "GGCACAACAACCC";
-		byte[] resultArray = result.getBytes();
+        i = 2;
+        merge.setAsCopy(kmer1);
+        merge.mergeWithFRKmer(i, kmer2);
+        Assert.assertEquals("AAGCTAAACAACC", merge.toString());
 
-		String text1 = "AACAACCC";
-		VKmerBytesWritable kmer1 = new VKmerBytesWritable(text1.length());
-		kmer1.setByRead(resultArray, 5);
-		Assert.assertEquals(text1, kmer1.toString());
+        i = 3;
+        merge.setAsCopy(kmer1);
+        merge.mergeWithFRKmer(i, kmer2);
+        Assert.assertEquals("AAGCTAACAACC", merge.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());
+    @Test
+    public void TestMergeRFKmer() {
+        int kmerSize = 3;
+        String result = "GGCACAACAACCC";
+        byte[] resultArray = result.getBytes();
 
-		VKmerBytesWritable merge = new VKmerBytesWritable(kmer1);
-		merge.mergeWithRFKmer(kmerSize, kmer2);
-		Assert.assertEquals(result, merge.toString());
+        String text1 = "AACAACCC";
+        VKmerBytesWritable kmer1 = new VKmerBytesWritable(text1.length());
+        kmer1.setByRead(resultArray, 5);
+        Assert.assertEquals(text1, kmer1.toString());
 
-		int i = 1;
-		merge.setAsCopy(kmer1);
-		merge.mergeWithRFKmer(i, kmer2);
-		Assert.assertEquals("GGCACAAAACAACCC", merge.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());
 
-		i = 2;
-		merge.setAsCopy(kmer1);
-		merge.mergeWithRFKmer(i, kmer2);
-		Assert.assertEquals("GGCACAAACAACCC", merge.toString());
+        VKmerBytesWritable merge = new VKmerBytesWritable(kmer1);
+        merge.mergeWithRFKmer(kmerSize, kmer2);
+        Assert.assertEquals(result, merge.toString());
 
-		i = 3;
-		merge.setAsCopy(kmer1);
-		merge.mergeWithRFKmer(i, kmer2);
-		Assert.assertEquals("GGCACAACAACCC", merge.toString());
+        int i = 1;
+        merge.setAsCopy(kmer1);
+        merge.mergeWithRFKmer(i, kmer2);
+        Assert.assertEquals("GGCACAAAACAACCC", 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 ??
+        i = 2;
+        merge.setAsCopy(kmer1);
+        merge.mergeWithRFKmer(i, kmer2);
+        Assert.assertEquals("GGCACAAACAACCC", merge.toString());
 
-		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
-	}
+        i = 3;
+        merge.setAsCopy(kmer1);
+        merge.mergeWithRFKmer(i, kmer2);
+        Assert.assertEquals("GGCACAACAACCC", merge.toString());
 
-	@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());
+        // 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 ??
 
-		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());
-		}
+        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
+    }
 
-		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 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());
 
-	@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());
-	}
+        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 TestMergeThreeVKmersRF_FF() {
+        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 TestMergeThreeVKmerRF_RF() {
+        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());
+    }
 }