add bubble's addReadIDs
diff --git a/genomix/genomix-data/src/main/java/edu/uci/ics/genomix/type/NodeWritable.java b/genomix/genomix-data/src/main/java/edu/uci/ics/genomix/type/NodeWritable.java
index 6cfbb2e..fc8b9ca 100644
--- a/genomix/genomix-data/src/main/java/edu/uci/ics/genomix/type/NodeWritable.java
+++ b/genomix/genomix-data/src/main/java/edu/uci/ics/genomix/type/NodeWritable.java
@@ -353,13 +353,56 @@
         mergeCoverage(other);
         internalKmer.mergeWithKmerInDir(dir, KmerBytesWritable.lettersInKmer, other.internalKmer);
     }
-    
-    public void addWithNode(final NodeWritable other){
-        addEdges(other);
+
+    /**
+     * merge all metadata from `other` into this, as if `other` were the same node as this.
+     * We don't touch the internal kmer but we do add edges, coverage, and start/end readids.
+     */
+    public void addFromNode(byte dir, final NodeWritable other) {
+        addEdges(dir, other);
         addCoverage(other);
+        addStartAndEndReadIDs(dir, other);
     }
-    
-    
+
+    /**
+     * Add `other`'s readids to my own accounting for any differences in orientation and overall length.
+     * differences in length will lead to relative offsets, where the incoming readids will be found in the
+     * new sequence at the same relative position (e.g., 10% of the total length from 5' start).
+     */
+    private void addStartAndEndReadIDs(byte dir, final NodeWritable other) {
+        int K = KmerBytesWritable.lettersInKmer;
+        int otherLength = other.internalKmer.lettersInKmer;
+        int thisLength = internalKmer.lettersInKmer;
+        float lengthFactor = (float) thisLength / (float) otherLength;
+        int newOtherOffset, newThisOffset;
+        switch (dir & DirectionFlag.DIR_MASK) {
+            case DirectionFlag.DIR_FF:
+            case DirectionFlag.DIR_RR:
+                newOtherOffset = 0;
+                // stream theirs in, adjusting to the new total length
+                for (PositionWritable p : other.startReads) {
+                    startReads.append(p.getMateId(), p.getReadId(),
+                            (int) (newOtherOffset + p.getPosId() * lengthFactor));
+                }
+                for (PositionWritable p : other.endReads) {
+                    endReads.append(p.getMateId(), p.getReadId(), (int) (newOtherOffset + p.getPosId() * lengthFactor));
+                }
+                break;
+            case DirectionFlag.DIR_FR:
+            case DirectionFlag.DIR_RF:
+                newOtherOffset = (int) ((otherLength - 1) * lengthFactor);
+                // stream theirs in, offset and flipped
+                for (PositionWritable p : other.startReads) {
+                    endReads.append(p.getMateId(), p.getReadId(), (int) (newOtherOffset - p.getPosId() * lengthFactor));
+                }
+                for (PositionWritable p : other.endReads) {
+                    startReads.append(p.getMateId(), p.getReadId(),
+                            (int) (newOtherOffset - p.getPosId() * lengthFactor));
+                }
+                break;
+        }
+    }
+
     /**
      * update my edge list
      */
@@ -424,10 +467,22 @@
                 break;
         }
     }
-    
-    public void addEdges(NodeWritable other){
-        for(byte dir : DirectionFlag.values){
-            edges[dir].unionUpdate(other.edges[dir]);
+
+    private void addEdges(byte dir, NodeWritable other) {
+        switch (dir & DirectionFlag.DIR_MASK) {
+            case DirectionFlag.DIR_FF:
+            case DirectionFlag.DIR_RR:
+                for (byte d : DirectionFlag.values) {
+                    edges[d].unionUpdate(other.edges[d]);
+                }
+                break;
+            case DirectionFlag.DIR_FR:
+            case DirectionFlag.DIR_RF:
+                edges[DirectionFlag.DIR_FF].unionUpdate(other.edges[DirectionFlag.DIR_RF]);
+                edges[DirectionFlag.DIR_FR].unionUpdate(other.edges[DirectionFlag.DIR_RR]);
+                edges[DirectionFlag.DIR_RF].unionUpdate(other.edges[DirectionFlag.DIR_FF]);
+                edges[DirectionFlag.DIR_RR].unionUpdate(other.edges[DirectionFlag.DIR_FR]);
+                break;
         }
     }
 
diff --git a/genomix/genomix-pregelix/src/main/java/edu/uci/ics/genomix/pregelix/operator/bubblemerge/BubbleMergeVertex.java b/genomix/genomix-pregelix/src/main/java/edu/uci/ics/genomix/pregelix/operator/bubblemerge/BubbleMergeVertex.java
index e1ecb0c..819bac0 100644
--- a/genomix/genomix-pregelix/src/main/java/edu/uci/ics/genomix/pregelix/operator/bubblemerge/BubbleMergeVertex.java
+++ b/genomix/genomix-pregelix/src/main/java/edu/uci/ics/genomix/pregelix/operator/bubblemerge/BubbleMergeVertex.java
@@ -162,7 +162,7 @@
                 float fracDissimilar = topCoverageMessage.computeDissimilar(curMessage);
                 if(fracDissimilar < dissimilarThreshold){ //if similar with top node, delete this node and put it in deletedSet 
                     //add coverage to top node
-                    topCoverageMessage.getNode().addWithNode(curMessage.getNode());
+                    topCoverageMessage.getNode().addFromNode(curMessage.getNode());
                     deletedSet.add(curMessage);
                     it.remove();
                 }