// Path: src/jbenchmarker/core/Document.java
// public abstract class Document {
//     
// 
//     public Document() {
//     }
//     
//     /* 
//      * View of the document (without metadata)
//      */
//     abstract public String view();
//     
//     /**
//      * Applies an operation
//      */ 
//     public void apply(Operation op) {
//         applyLocal(op);
//     }
//     
//     abstract protected void applyLocal(Operation op);
// }
// 
// Path: src/jbenchmarker/core/Operation.java
// public abstract class Operation {
//     private TraceOperation originalOp;       // Trace operation issuing this one
// 
//     public TraceOperation getOriginalOp() {
//         return originalOp;
//     }
// 
//     public void setOriginalOp(TraceOperation originalOp) {
//         this.originalOp = originalOp;
//     }
//     
//     public Operation(TraceOperation o) {
//         this.originalOp = o;
//     }
// 
//     @Override
//     public boolean equals(Object obj) {
//         if (obj == null) {
//             return false;
//         }
//         if (getClass() != obj.getClass()) {
//             return false;
//         }
//         final Operation other = (Operation) obj;
//         if (this.originalOp != other.originalOp && (this.originalOp == null || !this.originalOp.equals(other.originalOp))) {
//             return false;
//         }
//         return true;
//     }
// 
//     @Override
//     public int hashCode() {
//         int hash = 3;
//         hash = 17 * hash + (this.originalOp != null ? this.originalOp.hashCode() : 0);
//         return hash;
//     }
//     
//     abstract public Operation clone();
// }
// 
// Path: src/jbenchmarker/trace/TraceOperation.java
// public class TraceOperation {
//     public enum OpType { ins, del }; 
//     
//     private int replica;                  // replica number
//     private OpType type;                  // type of operation : insert or delete
//     private int position;                 // position in the document
//     private int offset;                   // length of a del
//     private String content;          // content of an ins
//     private VectorClock VC;               // Vector clock 
// 
//     
//     public VectorClock getVC() {
//         return VC;
//     }
// 
//     public String getContent() {
//         return content;
//     }
// 
//     public int getOffset() {
//         return offset;
//     }
// 
//     public int getPosition() {
//         return position;
//     }
// 
// 
//     public int getReplica() {
//         return replica;
//     }
// 
// 
//     public OpType getType() {
//         return type;
//     }
// 
//     public TraceOperation(OpType type, int replica, int position, int offset, String content, VectorClock VC) {
//         this.type = type;
//         this.replica = replica;
//         this.position = position;
//         this.offset = offset;
//         this.content = content;
//         this.VC = VC;
//     }
// 
//     /*
//      * Construction of an insert operation 
//      */
//     static public TraceOperation insert(int replica, int position, String content, VectorClock VC) {
//         return new TraceOperation(OpType.ins, replica, position, 0, content, VC);
//     }
//     
//     /*
//      * Construction of an insert operation 
//      */
//     static public TraceOperation delete(int replica, int position, int offset, VectorClock VC) {
//         return new TraceOperation(OpType.del, replica, position, offset, null, VC);
//     }
// 
//     @Override
//     public boolean equals(Object obj) {
//         if (obj == null) {
//             return false;
//         }
//         if (getClass() != obj.getClass()) {
//             return false;
//         }
//         final TraceOperation other = (TraceOperation) obj;
//         if (this.replica != other.replica) {
//             return false;
//         }
//         if (this.type != other.type) {
//             return false;
//         }
//         if (this.position != other.position) {
//             return false;
//         }
//         if (this.offset != other.offset) {
//             return false;
//         }
//         if ((this.content == null) ? (other.content != null) : !this.content.equals(other.content)) {
//             return false;
//         }
//         if (this.VC != other.VC && (this.VC == null || !this.VC.equals(other.VC))) {
//             return false;
//         }
//         return true;
//     }
// 
//     @Override
//     public int hashCode() {
//         int hash = 7;
//         hash = 53 * hash + this.replica;
//         hash = 53 * hash + (this.type != null ? this.type.hashCode() : 0);
//         hash = 53 * hash + this.position;
//         hash = 53 * hash + this.offset;
//         hash = 53 * hash + (this.content != null ? this.content.hashCode() : 0);
//         hash = 53 * hash + (this.VC != null ? this.VC.hashCode() : 0);
//         return hash;
//     }
// 
//     @Override
//     public String toString() {
//         return "TraceOperation{" + "replica=" + replica + ", VC=" + VC + ", type=" + type + ", position=" + position + (type==OpType.del ? ", offset=" + offset : ", content=" + content) + '}';
//     }
//     
//     
// }


import jbenchmarker.trace.TraceOperation;
import jbenchmarker.core.Document;
import jbenchmarker.core.Operation;
import java.lang.Integer;
import java.util.*;
import java.util.ArrayList;
import java.util.Random;
        idTable.add(End); document.add(' ');
    }
    
    @Override
    public String view() {
        StringBuilder s = new StringBuilder();
        for (char c : document)
            s.append(c);
        return s.substring(1, s.length()-1);
    }

    int dicho(LogootIdentifier idToSearch) {
        int startIndex = 0, endIndex = idTable.size()-1, middleIndex;
        do {
            middleIndex = startIndex + (endIndex - startIndex) / 2;
            int c = idTable.get(middleIndex).compareTo(idToSearch);
            if (c == 0) {
                return middleIndex;
            } else if (c < 0) {
                startIndex = middleIndex + 1;
            } else {
                endIndex = middleIndex - 1;
            }
        } while (startIndex < endIndex);
        return (idTable.get(startIndex).compareTo(idToSearch) < 0) ? 
                startIndex + 1 : startIndex;
    }
    
    
    @Override
// Path: src/jbenchmarker/core/Document.java
// public abstract class Document {
//     
// 
//     public Document() {
//     }
//     
//     /* 
//      * View of the document (without metadata)
//      */
//     abstract public String view();
//     
//     /**
//      * Applies an operation
//      */ 
//     public void apply(Operation op) {
//         applyLocal(op);
//     }
//     
//     abstract protected void applyLocal(Operation op);
// }
// 
// Path: src/jbenchmarker/core/Operation.java
// public abstract class Operation {
//     private TraceOperation originalOp;       // Trace operation issuing this one
// 
//     public TraceOperation getOriginalOp() {
//         return originalOp;
//     }
// 
//     public void setOriginalOp(TraceOperation originalOp) {
//         this.originalOp = originalOp;
//     }
//     
//     public Operation(TraceOperation o) {
//         this.originalOp = o;
//     }
// 
//     @Override
//     public boolean equals(Object obj) {
//         if (obj == null) {
//             return false;
//         }
//         if (getClass() != obj.getClass()) {
//             return false;
//         }
//         final Operation other = (Operation) obj;
//         if (this.originalOp != other.originalOp && (this.originalOp == null || !this.originalOp.equals(other.originalOp))) {
//             return false;
//         }
//         return true;
//     }
// 
//     @Override
//     public int hashCode() {
//         int hash = 3;
//         hash = 17 * hash + (this.originalOp != null ? this.originalOp.hashCode() : 0);
//         return hash;
//     }
//     
//     abstract public Operation clone();
// }
// 
// Path: src/jbenchmarker/trace/TraceOperation.java
// public class TraceOperation {
//     public enum OpType { ins, del }; 
//     
//     private int replica;                  // replica number
//     private OpType type;                  // type of operation : insert or delete
//     private int position;                 // position in the document
//     private int offset;                   // length of a del
//     private String content;          // content of an ins
//     private VectorClock VC;               // Vector clock 
// 
//     
//     public VectorClock getVC() {
//         return VC;
//     }
// 
//     public String getContent() {
//         return content;
//     }
// 
//     public int getOffset() {
//         return offset;
//     }
// 
//     public int getPosition() {
//         return position;
//     }
// 
// 
//     public int getReplica() {
//         return replica;
//     }
// 
// 
//     public OpType getType() {
//         return type;
//     }
// 
//     public TraceOperation(OpType type, int replica, int position, int offset, String content, VectorClock VC) {
//         this.type = type;
//         this.replica = replica;
//         this.position = position;
//         this.offset = offset;
//         this.content = content;
//         this.VC = VC;
//     }
// 
//     /*
//      * Construction of an insert operation 
//      */
//     static public TraceOperation insert(int replica, int position, String content, VectorClock VC) {
//         return new TraceOperation(OpType.ins, replica, position, 0, content, VC);
//     }
//     
//     /*
//      * Construction of an insert operation 
//      */
//     static public TraceOperation delete(int replica, int position, int offset, VectorClock VC) {
//         return new TraceOperation(OpType.del, replica, position, offset, null, VC);
//     }
// 
//     @Override
//     public boolean equals(Object obj) {
//         if (obj == null) {
//             return false;
//         }
//         if (getClass() != obj.getClass()) {
//             return false;
//         }
//         final TraceOperation other = (TraceOperation) obj;
//         if (this.replica != other.replica) {
//             return false;
//         }
//         if (this.type != other.type) {
//             return false;
//         }
//         if (this.position != other.position) {
//             return false;
//         }
//         if (this.offset != other.offset) {
//             return false;
//         }
//         if ((this.content == null) ? (other.content != null) : !this.content.equals(other.content)) {
//             return false;
//         }
//         if (this.VC != other.VC && (this.VC == null || !this.VC.equals(other.VC))) {
//             return false;
//         }
//         return true;
//     }
// 
//     @Override
//     public int hashCode() {
//         int hash = 7;
//         hash = 53 * hash + this.replica;
//         hash = 53 * hash + (this.type != null ? this.type.hashCode() : 0);
//         hash = 53 * hash + this.position;
//         hash = 53 * hash + this.offset;
//         hash = 53 * hash + (this.content != null ? this.content.hashCode() : 0);
//         hash = 53 * hash + (this.VC != null ? this.VC.hashCode() : 0);
//         return hash;
//     }
// 
//     @Override
//     public String toString() {
//         return "TraceOperation{" + "replica=" + replica + ", VC=" + VC + ", type=" + type + ", position=" + position + (type==OpType.del ? ", offset=" + offset : ", content=" + content) + '}';
//     }
//     
//     
// }


// Path: src/jbenchmarker/logoot/LogootDocument.java
import jbenchmarker.trace.TraceOperation;
import jbenchmarker.core.Document;
import jbenchmarker.core.Operation;
import java.lang.Integer;
import java.util.*;
import java.util.ArrayList;
import java.util.Random;

        idTable.add(End); document.add(' ');
    }
    
    @Override
    public String view() {
        StringBuilder s = new StringBuilder();
        for (char c : document)
            s.append(c);
        return s.substring(1, s.length()-1);
    }

    int dicho(LogootIdentifier idToSearch) {
        int startIndex = 0, endIndex = idTable.size()-1, middleIndex;
        do {
            middleIndex = startIndex + (endIndex - startIndex) / 2;
            int c = idTable.get(middleIndex).compareTo(idToSearch);
            if (c == 0) {
                return middleIndex;
            } else if (c < 0) {
                startIndex = middleIndex + 1;
            } else {
                endIndex = middleIndex - 1;
            }
        } while (startIndex < endIndex);
        return (idTable.get(startIndex).compareTo(idToSearch) < 0) ? 
                startIndex + 1 : startIndex;
    }
    
    
    @Override
    public void applyLocal(Operation op) {