nus-yam/ex-repair huggingface dataset:
Program: 178414
Project: 178414
Buggy source:
/** 
 * {@inheritDoc}
 * @see ClickHandler#onClick(ClickEvent)
 */
public void onClick(ClickEvent event){
  if (event.getSource() == hr && hr.isEnabled()) {
    getTextArea().setFocus(true);
    Range range=getTextArea().getDocument().getSelection().getRangeAt(0);
    if (range != null) {
      range=EditorUtils.normalizeCaretPosition(range);
      int[] path=EditorUtils.toIntArray(EditorUtils.getLocator(range.getStartContainer()));
      int siteId=clientJupiter.getSiteId();
      TreeCompositeOperation seq=null;
      if (range.getStartOffset() == 0) {
        TreeOperation newP=new TreeNewParagraph(siteId,path[0]);
        TreeOperation updateP=new TreeUpdateElement(siteId,new int[]{path[0]},Tree.NODE_NAME,"String_Node_Str");
        TreeOperation newP2=new TreeNewParagraph(siteId,path[0]);
        seq=new TreeCompositeOperation(newP,updateP,newP2);
      }
 else {
        TreeOperation splitP=new TreeInsertParagraph(siteId,range.getStartOffset(),path);
        TreeOperation newP=new TreeNewParagraph(siteId,path[0] + 1);
        TreeOperation updateP=new TreeUpdateElement(siteId,new int[]{path[0] + 1},Tree.NODE_NAME,"String_Node_Str");
        seq=new TreeCompositeOperation(splitP,newP,updateP);
      }
      clientJupiter.generate(seq);
    }
  }
}

Fixed version (ground truth):
/** 
 * {@inheritDoc}
 * @see ClickHandler#onClick(ClickEvent)
 */
public void onClick(ClickEvent event){
  if (event.getSource() == hr && hr.isEnabled()) {
    getTextArea().setFocus(true);
    Range range=getTextArea().getDocument().getSelection().getRangeAt(0);
    if (range != null) {
      range=EditorUtils.normalizeCaretPosition(range);
      int[] path=EditorUtils.toIntArray(EditorUtils.getLocator(range.getStartContainer()));
      int siteId=clientJupiter.getSiteId();
      TreeCompositeOperation seq=null;
      if (range.getStartOffset() == 0) {
        TreeOperation newP=new TreeNewParagraph(siteId,path[0]);
        TreeOperation updateP=new TreeUpdateElement(siteId,new int[]{path[0]},Tree.NODE_NAME,"String_Node_Str");
        TreeOperation newP2=new TreeNewParagraph(siteId,path[0]);
        seq=new TreeCompositeOperation(newP,updateP,newP2);
      }
 else {
        TreeOperation splitP=new TreeInsertParagraph(siteId,range.getStartOffset(),path);
        TreeOperation newP=new TreeNewParagraph(siteId,path[0] + 1);
        TreeOperation updateP=new TreeUpdateElement(siteId,new int[]{path[0] + 1},Tree.NODE_NAME,"String_Node_Str");
        seq=new TreeCompositeOperation(splitP,newP,updateP);
      }
      seq.setSiteId(siteId);
      clientJupiter.generate(seq);
    }
  }
}
Program: 178415
Project: 178415
Buggy source:
protected TreeOperation handleTreeComposite(TreeCompositeOperation op1){
  ArrayList<TreeOperation> l=new ArrayList<TreeOperation>();
  Iterator<TreeOperation> it=op1.operations.iterator();
  TreeOperation to=this;
  TreeOperation n=it.next();
  l.add((TreeOperation)to.transform(n));
  while (it.hasNext()) {
    to=(TreeOperation)n.transform(to);
    n=it.next();
    l.add((TreeOperation)to.transform(n));
  }
  return new TreeCompositeOperation(l);
}

Fixed version (ground truth):
protected TreeOperation handleTreeComposite(TreeCompositeOperation op1){
  ArrayList<TreeOperation> l=new ArrayList<TreeOperation>();
  Iterator<TreeOperation> it=op1.getOperations().iterator();
  TreeOperation to=this;
  TreeOperation n=it.next();
  l.add((TreeOperation)to.transform(n));
  while (it.hasNext()) {
    to=(TreeOperation)n.transform(to);
    n=it.next();
    l.add((TreeOperation)to.transform(n));
  }
  return new TreeCompositeOperation(l);
}
Program: 178416
Project: 178416
Buggy source:
/** 
 * @param operation a tree operation
 * @param isRemote {@code true} if the {@code TreeOperation} is received from server, and {@code false} if it's generated locally
 * @return the DOM operation equivalent to the given tree operation
 */
public DomOperation createDomOperation(TreeOperation operation,boolean isRemote){
  if (operation instanceof TreeInsertText) {
    return new DomInsertText(operation);
  }
 else   if (operation instanceof TreeDeleteText) {
    return new DomDeleteText(operation);
  }
 else   if (operation instanceof TreeInsertParagraph) {
    return new DomInsertParagraph(operation);
  }
 else   if (operation instanceof TreeNewParagraph) {
    return new DomNewParagraph(operation);
  }
 else   if (operation instanceof TreeMergeParagraph) {
    return new DomMergeParagraph(operation);
  }
 else   if (operation instanceof TreeStyle) {
    return new DomStyle(operation,isRemote);
  }
 else   if (operation instanceof TreeUpdateElement) {
    return new DomUpdateElement(operation);
  }
  return null;
}

Fixed version (ground truth):
/** 
 * @param operation a tree operation
 * @param isRemote {@code true} if the {@code TreeOperation} is received from server, and {@code false} if it's generated locally
 * @return the DOM operation equivalent to the given tree operation
 */
public DomOperation createDomOperation(TreeOperation operation,boolean isRemote){
  if (operation instanceof TreeInsertText) {
    return new DomInsertText(operation);
  }
 else   if (operation instanceof TreeDeleteText) {
    return new DomDeleteText(operation);
  }
 else   if (operation instanceof TreeInsertParagraph) {
    return new DomInsertParagraph(operation);
  }
 else   if (operation instanceof TreeNewParagraph) {
    return new DomNewParagraph(operation);
  }
 else   if (operation instanceof TreeMergeParagraph) {
    return new DomMergeParagraph(operation);
  }
 else   if (operation instanceof TreeStyle) {
    return new DomStyle(operation,isRemote);
  }
 else   if (operation instanceof TreeUpdateElement) {
    return new DomUpdateElement(operation);
  }
 else   if (operation instanceof TreeCompositeOperation) {
    return new DomCompositeOperation(operation,isRemote);
  }
  return null;
}
Program: 178417
Project: 178417
Buggy source:
@Override public Range execute(Document document){
  TreeUpdateElement op=getOperation();
  String newNodeName=op.getValue();
  Node node=getTargetNode(document);
  Range caret=document.createRange();
  caret.setStart(node,op.getPosition());
  if (shouldUpdate(node.getNodeName(),newNodeName)) {
    Node newNode=document.createElement(newNodeName);
    for (int i=0; i < node.getChildCount(); i++) {
      newNode.appendChild(node.getChild(i));
    }
    if (node.getParentElement() != null) {
      node.getParentElement().replaceChild(newNode,node);
    }
    caret.setStart(newNode,0);
  }
  caret.collapse(true);
  return caret;
}

Fixed version (ground truth):
@Override public Range execute(Document document){
  TreeUpdateElement op=getOperation();
  String newNodeName=op.getValue();
  Node node=getTargetNode(document);
  Range caret=document.createRange();
  caret.setStart(node,op.getPosition());
  if (shouldUpdate(node.getNodeName(),newNodeName)) {
    Node newNode=document.createElement(newNodeName);
    newNode.appendChild(Element.as(node).extractContents());
    if (node.getParentElement() != null) {
      node.getParentElement().replaceChild(newNode,node);
    }
    caret.setStart(newNode,0);
  }
  caret.collapse(true);
  return caret;
}
Program: 178418
Project: 178418
Buggy source:
/** 
 * {@inheritDoc}
 * @see ChangeHandler#onChange(ChangeEvent)
 */
public void onChange(ChangeEvent event){
  if (event.getSource() == levels && levels.isEnabled()) {
    String level=levels.getValue(levels.getSelectedIndex());
    getTextArea().setFocus(true);
    Range range=getTextArea().getDocument().getSelection().getRangeAt(0);
    logRange(null,range);
    if ("String_Node_Str".equalsIgnoreCase(range.getStartContainer().getNodeName())) {
      range.setStart(range.getStartContainer().getChild(range.getStartOffset()),0);
      range.collapse(true);
      logRange("String_Node_Str",range);
    }
    if (range != null) {
      Node node=range.getStartContainer();
      node=DOMUtils.getInstance().getNearestBlockContainer(node);
      log.fine("String_Node_Str" + node.getNodeName());
      TreeOperation op=treeOperationFactory.createHeadingOrParagraphOperation(clientJupiter.getSiteId(),range,level);
      if (op != null) {
        clientJupiter.generate(op);
      }
    }
  }
}

Fixed version (ground truth):
/** 
 * {@inheritDoc}
 * @see ChangeHandler#onChange(ChangeEvent)
 */
public void onChange(ChangeEvent event){
  if (event.getSource() == levels && levels.isEnabled()) {
    String level=levels.getValue(levels.getSelectedIndex());
    getTextArea().setFocus(true);
    Range range=getTextArea().getDocument().getSelection().getRangeAt(0);
    logRange(null,range);
    if ("String_Node_Str".equalsIgnoreCase(range.getStartContainer().getNodeName())) {
      range.setStart(range.getStartContainer().getChild(range.getStartOffset()),0);
      range.collapse(true);
      logRange("String_Node_Str",range);
    }
    if (range != null) {
      Node node=range.getStartContainer();
      node=DOMUtils.getInstance().getNearestBlockContainer(node);
      log.fine("String_Node_Str" + node.getNodeName());
      range.setStart(node,0);
      range.setEnd(range.getEndContainer(),range.getEndOffset());
      TreeOperation op=treeOperationFactory.createHeadingOrParagraphOperation(clientJupiter.getSiteId(),range,level);
      if (op != null) {
        clientJupiter.generate(op);
      }
    }
  }
}
Program: 178419
Project: 178419
Buggy source:
@Override public Range execute(Document document){
  TreeUpdateElement op=getOperation();
  String newNodeName=op.getValue();
  Node node=getTargetNode(document);
  Range caret=document.createRange();
  caret.setStart(node,op.getPosition());
  if (shouldUpdate(node.getNodeName(),newNodeName)) {
    Node newNode=document.createElement(newNodeName);
    for (int i=0; i < node.getChildCount(); i++) {
      newNode.appendChild(node.getChild(i));
    }
    if (node.getParentElement() != null) {
      node.getParentElement().replaceChild(newNode,node);
    }
    caret.setStart(newNode,op.getPosition());
  }
  caret.collapse(true);
  return caret;
}

Fixed version (ground truth):
@Override public Range execute(Document document){
  TreeUpdateElement op=getOperation();
  String newNodeName=op.getValue();
  Node node=getTargetNode(document);
  Range caret=document.createRange();
  caret.setStart(node,op.getPosition());
  if (shouldUpdate(node.getNodeName(),newNodeName)) {
    Node newNode=document.createElement(newNodeName);
    for (int i=0; i < node.getChildCount(); i++) {
      newNode.appendChild(node.getChild(i));
    }
    if (node.getParentElement() != null) {
      node.getParentElement().replaceChild(newNode,node);
    }
    caret.setStart(newNode,0);
  }
  caret.collapse(true);
  return caret;
}
Program: 178420
Project: 178420
Buggy source:
/** 
 * @param range a DOM range
 * @return the list of empty and non empty text nodes that are completely or partially (at least one character) included inthe given range
 */
public static Map<String,List<Text>> getTextNodes(Range range){
  Map<String,List<Text>> textNodesMap=new HashMap<String,List<Text>>();
  Node leaf=DOMUtils.getInstance().getFirstLeaf(range);
  Node lastLeaf=DOMUtils.getInstance().getLastLeaf(range);
  List<Text> nonEmptyTextNodes=new ArrayList<Text>();
  List<Text> emptyTextNodes=new ArrayList<Text>();
  if (isTextNode(leaf) && (leaf != range.getStartContainer() || range.getStartOffset() < leaf.getNodeValue().length())) {
    if (isNonEmptyTextNode(leaf)) {
      nonEmptyTextNodes.add((Text)leaf);
    }
 else     if (isEmptyTextNode(leaf)) {
      emptyTextNodes.add((Text)leaf);
    }
  }
  while (leaf != lastLeaf) {
    leaf=DOMUtils.getInstance().getNextLeaf(leaf);
    if (isNonEmptyTextNode(leaf)) {
      nonEmptyTextNodes.add((Text)leaf);
    }
 else     if (isEmptyTextNode(leaf)) {
      emptyTextNodes.add((Text)leaf);
    }
  }
  int lastIndex=nonEmptyTextNodes.size() - 1;
  if (lastIndex >= 0 && range.getEndOffset() == 0 && nonEmptyTextNodes.get(lastIndex) == range.getEndContainer()) {
    nonEmptyTextNodes.remove(lastIndex);
  }
  textNodesMap.put(NON__EMPTY,nonEmptyTextNodes);
  lastIndex=emptyTextNodes.size() - 1;
  if (lastIndex >= 0 && range.getEndOffset() == 0 && emptyTextNodes.get(lastIndex) == range.getEndContainer()) {
    emptyTextNodes.remove(lastIndex);
  }
  textNodesMap.put(EMPTY,emptyTextNodes);
  return textNodesMap;
}

Fixed version (ground truth):
/** 
 * @param range a DOM range
 * @return the list of empty and non empty text nodes that are completely or partially (at least one character) included inthe given range
 */
public static Map<String,List<Text>> getTextNodes(Range range){
  Map<String,List<Text>> textNodesMap=new HashMap<String,List<Text>>();
  Node leaf=DOMUtils.getInstance().getFirstLeaf(range);
  Node lastLeaf=DOMUtils.getInstance().getLastLeaf(range);
  List<Text> nonEmptyTextNodes=new ArrayList<Text>();
  List<Text> emptyTextNodes=new ArrayList<Text>();
  if (isNonEmptyTextNode(leaf) && (leaf != range.getStartContainer() || range.getStartOffset() < leaf.getNodeValue().length())) {
    nonEmptyTextNodes.add((Text)leaf);
  }
  if (isEmptyTextNode(leaf)) {
    emptyTextNodes.add((Text)leaf);
  }
  while (leaf != lastLeaf) {
    leaf=DOMUtils.getInstance().getNextLeaf(leaf);
    if (isNonEmptyTextNode(leaf)) {
      nonEmptyTextNodes.add((Text)leaf);
    }
 else     if (isEmptyTextNode(leaf)) {
      emptyTextNodes.add((Text)leaf);
    }
  }
  int lastIndex=nonEmptyTextNodes.size() - 1;
  if (lastIndex >= 0 && range.getEndOffset() == 0 && nonEmptyTextNodes.get(lastIndex) == range.getEndContainer()) {
    nonEmptyTextNodes.remove(lastIndex);
  }
  textNodesMap.put(NON__EMPTY,nonEmptyTextNodes);
  textNodesMap.put(EMPTY,emptyTextNodes);
  return textNodesMap;
}
Program: 178422
Project: 178422
Buggy source:
/** 
 * @return The suite of all the client tests to be run.
 */
public static Test suite(){
  TestSuite suite=new TestSuite("String_Node_Str");
  suite.addTestSuite(RtPluginCaretPositionTest.class);
  return suite;
}

Fixed version (ground truth):
/** 
 * @return The suite of all the client tests to be run.
 */
public static Test suite(){
  TestSuite suite=new TestSuite("String_Node_Str");
  suite.addTestSuite(CaretPositionTest.class);
  suite.addTestSuite(CaretPositionInEmptyTextTest.class);
  return suite;
}
Program: 178423
Project: 178423
Buggy source:
/** 
 * @param range the selection range, usually a collapsed range which is the caret position
 * @return all the non-empty text nodes from the right of the caret within the same paragraph
 */
private static List<Text> getRightTextNodesInSameP(Range range){
  Range rightRange=range.cloneRange();
  Node parentPNode=getAncestorParagraph(range.getEndContainer());
  rightRange.setEnd(parentPNode,parentPNode.getChildCount());
  return getNonEmptyTextNodes(rightRange);
}

Fixed version (ground truth):
/** 
 * @param range the selection range, usually a collapsed range which is the caret position, placed inside a paragraph
 * @return all the non-empty text nodes from the right of the caret within the same paragraph
 */
private static Map<String,List<Text>> getRightTextNodesInSameP(Range range){
  Range rightRange=range.cloneRange();
  Node parentPNode=getAncestorParagraph(range.getEndContainer());
  rightRange.setEnd(parentPNode,parentPNode.getChildCount());
  return getTextNodes(rightRange);
}
Program: 178424
Project: 178424
Buggy source:
/** 
 * @param node a DOM node
 * @return {@code true} if the given node is of type {@link Node#TEXT_NODE} and it's not empty, {@code false}otherwise
 */
public static boolean isNonEmptyTextNode(Node node){
  return node != null && node.getNodeType() == Node.TEXT_NODE && node.getNodeValue().length() > 0;
}

Fixed version (ground truth):
/** 
 * @param node a DOM node
 * @return {@code true} if the given node is of type {@link Node#TEXT_NODE} and it's not empty, {@code false}otherwise
 */
public static boolean isNonEmptyTextNode(Node node){
  return isTextNode(node) && node.getNodeValue().length() > 0;
}
Program: 178425
Project: 178425
Buggy source:
/** 
 * Converts a DOM range to an list of operation targets.
 * @param range a DOM range
 * @return the corresponding list of operation targets
 */
public static List<OperationTarget> getIntermediaryTargets(Range range){
  List<OperationTarget> operationTargets=new ArrayList<OperationTarget>();
  List<Text> textNodes=getNonEmptyTextNodes(range);
  for (int i=0; i < textNodes.size(); i++) {
    Text text=textNodes.get(i);
    int startIndex=0;
    if (text == range.getStartContainer()) {
      startIndex=range.getStartOffset();
    }
    int endIndex=text.getLength();
    if (text == range.getEndContainer()) {
      endIndex=range.getEndOffset();
    }
    operationTargets.add(0,new OperationTarget(TreeHelper.getLocator(text),startIndex,endIndex,text.getLength()));
  }
  return operationTargets;
}

Fixed version (ground truth):
/** 
 * Converts a DOM range to an list of operation targets.
 * @param range a DOM range
 * @return the corresponding list of operation targets
 */
public static List<OperationTarget> getIntermediaryTargets(Range range){
  List<OperationTarget> operationTargets=new ArrayList<OperationTarget>();
  List<Text> textNodes=getTextNodes(range).get(NON__EMPTY);
  for (int i=0; i < textNodes.size(); i++) {
    Text text=textNodes.get(i);
    int startIndex=0;
    if (text == range.getStartContainer()) {
      startIndex=range.getStartOffset();
    }
    int endIndex=text.getLength();
    if (text == range.getEndContainer()) {
      endIndex=range.getEndOffset();
    }
    operationTargets.add(0,new OperationTarget(TreeHelper.getLocator(text),startIndex,endIndex,text.getLength()));
  }
  return operationTargets;
}
Program: 178426
Project: 178426
Buggy source:
/** 
 * @param range the selection range, usually a collapsed range which is the caret position
 * @return all the non-empty text nodes from the left of the caret within the same paragraph
 */
private static List<Text> getLeftTextNodesInSameP(Range range){
  Range leftRange=range.cloneRange();
  leftRange.setEnd(range.getStartContainer(),range.getStartOffset());
  Node parentPNode=getAncestorParagraph(range.getStartContainer());
  leftRange.setStart(parentPNode,0);
  return getNonEmptyTextNodes(leftRange);
}

Fixed version (ground truth):
/** 
 * @param range the selection range, usually a collapsed range which is the caret position, placed inside a paragraph
 * @return all the non-empty text nodes from the left of the caret within the same paragraph
 */
private static Map<String,List<Text>> getLeftTextNodesInSameP(Range range){
  Range leftRange=range.cloneRange();
  leftRange.setEnd(range.getStartContainer(),range.getStartOffset());
  Node parentPNode=getAncestorParagraph(range.getStartContainer());
  leftRange.setStart(parentPNode,0);
  return getTextNodes(leftRange);
}
Program: 178428
Project: 178428
Buggy source:
public TreeOperation handleBackspaceOnElement(Range caret){
  Node startContainer=caret.getStartContainer();
  List<Integer> path=TreeHelper.getLocator(startContainer);
  TreeOperation op=null;
  Element rightParagraph;
  Node leftParagraph;
  Element element=Element.as(startContainer);
  if (P.equalsIgnoreCase(element.getNodeName())) {
    rightParagraph=element;
    leftParagraph=rightParagraph.getPreviousSibling();
    if (leftParagraph != null) {
      int lBrCount=Element.as(leftParagraph).getElementsByTagName(BR).getLength();
      int rBrCount=rightParagraph.getElementsByTagName(BR).getLength();
      op=new TreeMergeParagraph(clientJupiter.getSiteId(),path.get(0),leftParagraph.getChildCount() - lBrCount,rightParagraph.getChildCount() - rBrCount);
      op.setPath(TreeHelper.toIntArray(path));
    }
 else {
      log.fine("String_Node_Str" + element.getTagName() + "String_Node_Str");
    }
  }
 else {
    rightParagraph=Element.as(getAncestorParagraph(element));
    op=skipBackspaceOnEmptyTexts(element,path,rightParagraph,rightParagraph.getPreviousSibling());
  }
  return op;
}

Fixed version (ground truth):
public TreeOperation handleBackspaceOnElement(Range caret){
  Node startContainer=caret.getStartContainer();
  List<Integer> path=TreeHelper.getLocator(startContainer);
  TreeOperation op=null;
  Element rightParagraph;
  Node leftParagraph;
  Element element=Element.as(startContainer);
  if (P.equalsIgnoreCase(element.getNodeName())) {
    rightParagraph=element;
    leftParagraph=rightParagraph.getPreviousSibling();
    if (leftParagraph != null) {
      int lBrCount=Element.as(leftParagraph).getElementsByTagName(BR).getLength();
      int rBrCount=rightParagraph.getElementsByTagName(BR).getLength();
      op=new TreeMergeParagraph(clientJupiter.getSiteId(),path.get(0),leftParagraph.getChildCount() - lBrCount,rightParagraph.getChildCount() - rBrCount);
      op.setPath(TreeHelper.toIntArray(path));
    }
 else {
      log.fine("String_Node_Str" + element.getTagName() + "String_Node_Str");
    }
  }
 else {
    log.severe("String_Node_Str");
    rightParagraph=Element.as(getAncestorParagraph(element));
    op=skipBackspaceOnEmptyTexts(element,path,rightParagraph,rightParagraph.getPreviousSibling());
  }
  return op;
}
Program: 178429
Project: 178429
Buggy source:
private TreeOperation handleBackspaceOrDeleteKeyOnEmptyTexts(boolean isBackspace,Node node,List<Integer> path,Node rightParagraph,Node leftParagraph){
  org.xwiki.gwt.dom.client.Document document=getTextArea().getDocument();
  Range range=document.createRange();
  if (isBackspace) {
    range.setStart(document.getBody().getFirstChild(),0);
    range.setEndBefore(node);
  }
 else {
    range.setStartAfter(node);
    Node lastChild=document.getBody().getLastChild();
    range.setEnd(lastChild,lastChild.getChildCount());
  }
  TreeOperation op=null;
  List<Text> nonEmptyTextNodes=getNonEmptyTextNodes(range);
  if (nonEmptyTextNodes.size() > 0) {
    int idx=isBackspace ? nonEmptyTextNodes.size() - 1 : 0;
    Node nonEmptyTextNode=nonEmptyTextNodes.get(idx);
    log.fine("String_Node_Str" + nonEmptyTextNode.getNodeValue());
    if (node.getParentNode() == nonEmptyTextNode.getParentNode()) {
      int deletePos=isBackspace ? nonEmptyTextNode.getNodeValue().length() - 1 : 0;
      op=new TreeDeleteText(clientJupiter.getSiteId(),deletePos,TreeHelper.toIntArray(path));
    }
 else {
      if ((isBackspace && leftParagraph != null) || (!isBackspace && rightParagraph != null)) {
        int lBbrCount=Element.as(leftParagraph).getElementsByTagName(BR).getLength();
        int rBbrCount=Element.as(rightParagraph).getElementsByTagName(BR).getLength();
        int mergePos=isBackspace ? path.get(0) : path.get(0) + 1;
        op=new TreeMergeParagraph(clientJupiter.getSiteId(),mergePos,leftParagraph.getChildCount() - lBbrCount,rightParagraph.getChildCount() - rBbrCount);
        op.setPath(TreeHelper.toIntArray(path));
      }
    }
  }
  return op;
}

Fixed version (ground truth):
private TreeOperation handleBackspaceOrDeleteKeyOnEmptyTexts(boolean isBackspace,Node node,List<Integer> path,Node rightParagraph,Node leftParagraph){
  org.xwiki.gwt.dom.client.Document document=getTextArea().getDocument();
  Range range=document.createRange();
  if (isBackspace) {
    range.setStart(document.getBody().getFirstChild(),0);
    range.setEndBefore(node);
  }
 else {
    range.setStartAfter(node);
    Node lastChild=document.getBody().getLastChild();
    range.setEnd(lastChild,lastChild.getChildCount());
  }
  TreeOperation op=null;
  List<Text> nonEmptyTextNodes=getTextNodes(range).get(NON__EMPTY);
  if (nonEmptyTextNodes.size() > 0) {
    int idx=isBackspace ? nonEmptyTextNodes.size() - 1 : 0;
    Node nonEmptyTextNode=nonEmptyTextNodes.get(idx);
    log.fine("String_Node_Str" + nonEmptyTextNode.getNodeValue());
    if (node.getParentNode() == nonEmptyTextNode.getParentNode()) {
      int deletePos=isBackspace ? nonEmptyTextNode.getNodeValue().length() - 1 : 0;
      op=new TreeDeleteText(clientJupiter.getSiteId(),deletePos,TreeHelper.toIntArray(path));
    }
 else {
      if ((isBackspace && leftParagraph != null) || (!isBackspace && rightParagraph != null)) {
        op=treeOperationFactory.createTreeMergeParagraph(isBackspace,clientJupiter.getSiteId(),leftParagraph,rightParagraph,path);
      }
    }
  }
  return op;
}
Program: 178430
Project: 178430
Buggy source:
public TreeOperation handleBackspaceOnTextNode(Range caret){
  int pos=caret.getStartOffset();
  Node startContainer=caret.getStartContainer();
  List<Integer> path=TreeHelper.getLocator(startContainer);
  TreeOperation op=null;
  Node ancestorBelowParagraph=getAncestorBelowParagraph(startContainer);
  Element rightParagraph=ancestorBelowParagraph.getParentElement();
  Node leftParagraph=rightParagraph.getPreviousSibling();
  Text textNode=Text.as(startContainer);
  if (pos == 0) {
    if (leftParagraph != null) {
      op=skipBackspaceOnEmptyTexts(textNode,path,rightParagraph,leftParagraph);
    }
 else {
      log.fine("String_Node_Str");
    }
  }
 else {
    pos=pos - 1;
    op=new TreeDeleteText(clientJupiter.getSiteId(),pos,TreeHelper.toIntArray(path));
  }
  return op;
}

Fixed version (ground truth):
public TreeOperation handleBackspaceOnTextNode(Range caret){
  int pos=caret.getStartOffset();
  Node startContainer=caret.getStartContainer();
  List<Integer> path=TreeHelper.getLocator(startContainer);
  TreeOperation op=null;
  Node ancestorBelowParagraph=getAncestorBelowParagraph(startContainer);
  Element rightParagraph=ancestorBelowParagraph.getParentElement();
  Node leftParagraph=rightParagraph.getPreviousSibling();
  Text textNode=Text.as(startContainer);
  if (pos == 0) {
    if (leftParagraph != null) {
      op=maybeMergeParagraphs(true,textNode,path,rightParagraph,leftParagraph);
    }
 else {
      log.fine("String_Node_Str");
    }
  }
 else {
    pos=pos - 1;
    op=new TreeDeleteText(clientJupiter.getSiteId(),pos,TreeHelper.toIntArray(path));
  }
  return op;
}
Program: 178431
Project: 178431
Buggy source:
public TreeOperation handleDeleteOnTextNode(Range caret){
  int pos=caret.getStartOffset();
  Node startContainer=caret.getStartContainer();
  Text textNode=Text.as(startContainer);
  List<Integer> path=TreeHelper.getLocator(startContainer);
  TreeOperation op=null;
  final Node ancestorParagraph=getAncestorParagraph(startContainer);
  Element leftParagraph=Element.as(ancestorParagraph);
  Element rightParagraph=leftParagraph.getNextSiblingElement();
  if (textNode.getLength() > 0) {
    if (textNode.getLength() == pos) {
      op=skipDeleteOnEmptyTexts(textNode,path,leftParagraph,rightParagraph);
    }
 else {
      op=new TreeDeleteText(clientJupiter.getSiteId(),pos,TreeHelper.toIntArray(path));
    }
  }
 else {
    op=skipDeleteOnEmptyTexts(textNode,path,leftParagraph,rightParagraph);
  }
  return op;
}

Fixed version (ground truth):
public TreeOperation handleDeleteOnTextNode(Range caret){
  int pos=caret.getStartOffset();
  Node startContainer=caret.getStartContainer();
  Text textNode=Text.as(startContainer);
  List<Integer> path=TreeHelper.getLocator(startContainer);
  TreeOperation op=null;
  final Node ancestorParagraph=getAncestorParagraph(startContainer);
  Element leftParagraph=Element.as(ancestorParagraph);
  Element rightParagraph=leftParagraph.getNextSiblingElement();
  if (pos < textNode.getLength()) {
    op=new TreeDeleteText(clientJupiter.getSiteId(),pos,TreeHelper.toIntArray(path));
  }
 else {
    op=maybeMergeParagraphs(false,textNode,path,rightParagraph,leftParagraph);
  }
  return op;
}
Program: 178432
Project: 178432
Buggy source:
@Override public void beforeSend(Message message){
  log.fine("String_Node_Str");
  TreeOperation operation=(TreeOperation)message.getOperation();
  DomOperation domOperation=domOperationFactory.createDomOperation(operation);
  if (domOperation != null) {
    applySelection(domOperation.execute((Document)nativeNode.getOwnerDocument()));
  }
 else {
    updateDOM();
  }
}

Fixed version (ground truth):
@Override public void beforeSend(Message message){
  log.fine("String_Node_Str");
  TreeOperation operation=(TreeOperation)message.getOperation();
  DomOperation domOperation=domOperationFactory.createDomOperation(operation,false);
  if (domOperation != null) {
    applySelection(domOperation.execute((Document)nativeNode.getOwnerDocument()));
  }
 else {
    updateDOM();
  }
}
Program: 178433
Project: 178433
Buggy source:
@Override public void afterReceive(Message receivedMessage){
  log.fine("String_Node_Str" + receivedMessage);
  TreeOperation operation=(TreeOperation)receivedMessage.getOperation();
  DomOperation domOperation=domOperationFactory.createDomOperation(operation);
  if (domOperation != null) {
    TreeOperation[] selectionEndPoints=saveSelection();
    domOperation.execute((Document)nativeNode.getOwnerDocument());
    restoreSelection(selectionEndPoints,operation);
  }
 else {
    updateDOM();
  }
}

Fixed version (ground truth):
@Override public void afterReceive(Message receivedMessage){
  log.fine("String_Node_Str" + receivedMessage);
  TreeOperation operation=(TreeOperation)receivedMessage.getOperation();
  DomOperation domOperation=domOperationFactory.createDomOperation(operation,true);
  if (domOperation != null) {
    TreeOperation[] selectionEndPoints=saveSelection();
    domOperation.execute((Document)nativeNode.getOwnerDocument());
    restoreSelection(selectionEndPoints,operation);
  }
 else {
    updateDOM();
  }
}
Program: 178434
Project: 178434
Buggy source:
/** 
 * @param operation a tree operation
 * @return the DOM operation equivalent to the given tree operation
 */
public DomOperation createDomOperation(TreeOperation operation){
  if (operation instanceof TreeInsertText) {
    return new DomInsertText(operation);
  }
 else   if (operation instanceof TreeDeleteText) {
    return new DomDeleteText(operation);
  }
 else   if (operation instanceof TreeInsertParagraph) {
    return new DomInsertParagraph(operation);
  }
 else   if (operation instanceof TreeNewParagraph) {
    return new DomNewParagraph(operation);
  }
 else   if (operation instanceof TreeMergeParagraph) {
    return new DomMergeParagraph(operation);
  }
 else   if (operation instanceof TreeStyle) {
    return new DomStyle(operation);
  }
  return null;
}

Fixed version (ground truth):
/** 
 * @param operation a tree operation
 * @param isRemote {@code true} if the {@code TreeOperation} is received from server, and {@code false} if it's generated locally
 * @return the DOM operation equivalent to the given tree operation
 */
public DomOperation createDomOperation(TreeOperation operation,boolean isRemote){
  if (operation instanceof TreeInsertText) {
    return new DomInsertText(operation);
  }
 else   if (operation instanceof TreeDeleteText) {
    return new DomDeleteText(operation);
  }
 else   if (operation instanceof TreeInsertParagraph) {
    return new DomInsertParagraph(operation);
  }
 else   if (operation instanceof TreeNewParagraph) {
    return new DomNewParagraph(operation);
  }
 else   if (operation instanceof TreeMergeParagraph) {
    return new DomMergeParagraph(operation);
  }
 else   if (operation instanceof TreeStyle) {
    return new DomStyle(operation,isRemote);
  }
  return null;
}
Program: 178435
Project: 178435
Buggy source:
/** 
 * Creates a new DOM operation equivalent to the given Tree operation.
 * @param operation a Tree operation
 */
public DomStyle(TreeOperation operation){
  super(operation);
}

Fixed version (ground truth):
/** 
 * Creates a new DOM operation equivalent to the given Tree operation.
 * @param operation a Tree operation
 * @param isRemote true if tree operation was remotely generated (received from server)
 */
public DomStyle(TreeOperation operation,boolean isRemote){
  super(operation);
  this.isRemote=isRemote;
}
Program: 178436
Project: 178436
Buggy source:
@Override protected TextFragment execute(Text text,int startIndex,int endIndex,String parameter){
  boolean addStyle=isExecuted();
  return addStyle ? removeStyle(text,startIndex,endIndex) : addStyle(text,startIndex,endIndex);
}

Fixed version (ground truth):
@Override protected TextFragment execute(Text text,int startIndex,int endIndex,String parameter){
  boolean addStyle=isExecuted();
  if (DomStyle.this.isRemote()) {
    return addStyle ? new TextFragment(text,startIndex,endIndex) : addStyle(text,startIndex,endIndex);
  }
 else {
    return addStyle ? removeStyle(text,startIndex,endIndex) : addStyle(text,startIndex,endIndex);
  }
}
Program: 178437
Project: 178437
Buggy source:
private TreeOperation skipDeleteOnEmptyTexts(Node node,Node rightParagraph,Node leftParagraph){
  return handleBackspaceOrDeleteKeyOnEmptyTexts(false,node,rightParagraph,leftParagraph);
}

Fixed version (ground truth):
/** 
 * Skips empty texts on delete
 * @param emptyText the empty text node
 * @param leftParagraph the left paragraph which is the ancestor of the emptyText node
 * @param rightParagraph the right paragraph
 * @return a {@link TreeOperation} or {@code null}
 */
private TreeOperation skipDeleteOnEmptyTexts(Node emptyText,Node leftParagraph,Node rightParagraph){
  return handleBackspaceOrDeleteKeyOnEmptyTexts(false,emptyText,rightParagraph,leftParagraph);
}
Program: 178438
Project: 178438
Buggy source:
private TreeOperation skipBackspaceOnEmptyTexts(Node node,Node rightParagraph,Node leftParagraph){
  return handleBackspaceOrDeleteKeyOnEmptyTexts(true,node,rightParagraph,leftParagraph);
}

Fixed version (ground truth):
/** 
 * Skips empty texts on backspace
 * @param emptyText the empty text node
 * @param rightParagraph the right paragraph which is the ancestor of the emptyText node
 * @param leftParagraph the left paragraph
 * @return a {@link TreeOperation} or {@code null}
 */
private TreeOperation skipBackspaceOnEmptyTexts(Node emptyText,Node rightParagraph,Node leftParagraph){
  return handleBackspaceOrDeleteKeyOnEmptyTexts(true,emptyText,rightParagraph,leftParagraph);
}
Program: 178441
Project: 178441
Buggy source:
public TreeOperation handleDeleteOnTextNode(Range caret){
  int pos=caret.getStartOffset();
  Node startContainer=caret.getStartContainer();
  Text textNode=Text.as(startContainer);
  List<Integer> path=TreeHelper.getLocator(startContainer);
  TreeOperation op=null;
  Element leftParagraph;
  Element rightParagraph;
  final Node ancestorBelowParagraph=getAncestorBelowParagraph(startContainer);
  leftParagraph=ancestorBelowParagraph.getParentElement();
  rightParagraph=leftParagraph.getNextSiblingElement();
  boolean isMerge=false;
  if (textNode != ancestorBelowParagraph) {
    isMerge=ancestorBelowParagraph == ancestorBelowParagraph.getParentNode().getLastChild();
    isMerge=isMerge && textNode == ancestorBelowParagraph.getLastChild();
  }
 else {
    isMerge=textNode == ancestorBelowParagraph.getParentElement().getLastChild();
  }
  isMerge=isMerge && ((rightParagraph != null) && (!rightParagraph.getClassName().toLowerCase().contains("String_Node_Str")));
  if (textNode.getLength() > 0) {
    if (textNode.getLength() == pos) {
      if (isMerge) {
        int lBrCount=leftParagraph.getElementsByTagName(BR).getLength();
        int rBrCount=rightParagraph.getElementsByTagName(BR).getLength();
        op=new TreeMergeParagraph(clientJupiter.getSiteId(),path.get(0) + 1,leftParagraph.getChildCount() - lBrCount,rightParagraph.getChildCount() - rBrCount);
        op.setPath(TreeHelper.toIntArray(path));
      }
 else {
        log.fine("String_Node_Str");
      }
    }
 else {
      op=new TreeDeleteText(clientJupiter.getSiteId(),pos,TreeHelper.toIntArray(path));
    }
  }
 else {
    op=skipDeleteOnEmptyTexts(textNode,path,leftParagraph,rightParagraph);
  }
  return op;
}

Fixed version (ground truth):
public TreeOperation handleDeleteOnTextNode(Range caret){
  int pos=caret.getStartOffset();
  Node startContainer=caret.getStartContainer();
  Text textNode=Text.as(startContainer);
  List<Integer> path=TreeHelper.getLocator(startContainer);
  TreeOperation op=null;
  final Node ancestorParagraph=getAncestorParagraph(startContainer);
  Element leftParagraph=Element.as(ancestorParagraph);
  Element rightParagraph=leftParagraph.getNextSiblingElement();
  if (textNode.getLength() > 0) {
    if (textNode.getLength() == pos) {
      op=skipDeleteOnEmptyTexts(textNode,path,leftParagraph,rightParagraph);
    }
 else {
      op=new TreeDeleteText(clientJupiter.getSiteId(),pos,TreeHelper.toIntArray(path));
    }
  }
 else {
    op=skipDeleteOnEmptyTexts(textNode,path,leftParagraph,rightParagraph);
  }
  return op;
}
Program: 178444
Project: 178444
Buggy source:
@Override public void beforeSend(Message message){
  log.fine("String_Node_Str");
  TreeOperation operation=(TreeOperation)message.getOperation();
  if (operation instanceof TreeDeleteText) {
    return;
  }
  DomOperation domOperation=domOperationFactory.createDomOperation(operation);
  if (domOperation != null) {
    applySelection(domOperation.execute((Document)nativeNode.getOwnerDocument()));
  }
 else {
    updateDOM();
  }
}

Fixed version (ground truth):
@Override public void beforeSend(Message message){
  log.fine("String_Node_Str");
  TreeOperation operation=(TreeOperation)message.getOperation();
  DomOperation domOperation=domOperationFactory.createDomOperation(operation);
  if (domOperation != null) {
    applySelection(domOperation.execute((Document)nativeNode.getOwnerDocument()));
  }
 else {
    updateDOM();
  }
}
Program: 178445
Project: 178445
Buggy source:
/** 
 * Saves the current selection using two   {@link TreeInsertText} operations.
 * @return two {@link TreeInsertText} operations that represent the start and end of the selection
 * @see TreeClientCallback#restoreSelection(TreeOperation[])
 */
private TreeOperation[] saveSelection(){
  TreeOperation[] selection=new TreeCaretPosition[2];
  Range start=((Document)nativeNode.getOwnerDocument()).getSelection().getRangeAt(0);
  start=EditorUtils.normalizeCaretPosition(start);
  Range end=start.cloneRange();
  start.collapse(true);
  end.collapse(false);
  selection[0]=treeOperationFactory.createCaretPosition(siteId,start);
  selection[1]=treeOperationFactory.createCaretPosition(siteId,end);
  return selection;
}

Fixed version (ground truth):
/** 
 * Saves the current selection using two   {@link TreeInsertText} operations.
 * @return two {@link TreeInsertText} operations that represent the start and end of the selection
 * @see TreeClientCallback#restoreSelection(TreeOperation[])
 */
private TreeOperation[] saveSelection(){
  TreeOperation[] selection=new TreeCaretPosition[2];
  Range start=((Document)nativeNode.getOwnerDocument()).getSelection().getRangeAt(0);
  start=EditorUtils.normalizeCaretPosition(start);
  Range end=start.cloneRange();
  start.collapse(true);
  end.collapse(false);
  selection[0]=treeOperationFactory.createCaretPosition(siteId,start,start.getStartOffset());
  selection[1]=treeOperationFactory.createCaretPosition(siteId,end,end.getEndOffset());
  return selection;
}
Program: 178446
Project: 178446
Buggy source:
/** 
 * @param siteId the client id
 * @param location the native DOM caret position
 * @return a new {@link TreeCaretPosition} operation
 */
public TreeCaretPosition createCaretPosition(int siteId,Range location){
  List<Integer> path=TreeHelper.getLocator(location.getStartContainer());
  return new TreeCaretPosition(siteId,location.getStartOffset(),TreeHelper.toIntArray(path));
}

Fixed version (ground truth):
/** 
 * @param siteId the client id
 * @param location the native DOM caret position
 * @param offset
 * @return a new {@link TreeCaretPosition} operation
 */
public TreeCaretPosition createCaretPosition(int siteId,Range location,int offset){
  List<Integer> path=TreeHelper.getLocator(location.getStartContainer());
  return new TreeCaretPosition(siteId,offset,TreeHelper.toIntArray(path));
}
Program: 178447
Project: 178447
Buggy source:
@Override public Range execute(Document document){
  Node targetNode=getTargetNode(document);
  if (Node.TEXT_NODE == targetNode.getNodeType()) {
    Text.as(targetNode).deleteData(getOperation().getPosition(),1);
  }
 else   if (Node.ELEMENT_NODE == targetNode.getNodeType()) {
  }
  return null;
}

Fixed version (ground truth):
@Override public Range execute(Document document){
  Node targetNode=getTargetNode(document);
  if (Node.TEXT_NODE == targetNode.getNodeType()) {
    Text.as(targetNode).deleteData(getOperation().getPosition(),1);
  }
 else   if (Node.ELEMENT_NODE == targetNode.getNodeType()) {
  }
  Range caret=document.createRange();
  caret.setStart(targetNode,getOperation().getPosition());
  caret.collapse(true);
  return caret;
}
Program: 178448
Project: 178448
Buggy source:
/** 
 * Skips empty texts on delete
 * @param emptyText the empty text node
 * @param leftParagraph the left paragraph which is the ancestor of the emptyText node
 * @param rightParagraph the right paragraph
 * @return a {@link TreeOperation} or {@code null}
 */
private TreeOperation skipDeleteOnEmptyTexts(Node emptyText,Node leftParagraph,Node rightParagraph){
  return handleBackspaceOrDeleteKeyOnEmptyTexts(false,emptyText,rightParagraph,leftParagraph);
}

Fixed version (ground truth):
/** 
 * Skips empty texts on delete
 * @param node the node
 * @param path the node's locator - passed only to avoid computing it again
 * @param leftParagraph the left paragraph which is the ancestor of the emptyText node
 * @param rightParagraph the right paragraph
 * @return a {@link TreeOperation} or {@code null}
 */
private TreeOperation skipDeleteOnEmptyTexts(Node node,List<Integer> path,Node leftParagraph,Node rightParagraph){
  return handleBackspaceOrDeleteKeyOnEmptyTexts(false,node,path,rightParagraph,leftParagraph);
}
Program: 178449
Project: 178449
Buggy source:
public TreeOperation handleBackspaceOnElement(Range caret){
  int pos=caret.getStartOffset();
  Node startContainer=caret.getStartContainer();
  List<Integer> path=TreeHelper.getLocator(startContainer);
  TreeOperation op=null;
  Element rightParagraph;
  Node n;
  Node leftParagraph;
  Element element=Element.as(startContainer);
  boolean merge=false;
  if (P.equalsIgnoreCase(element.getNodeName())) {
    rightParagraph=element;
    merge=true;
  }
 else {
    log.severe("String_Node_Str");
    n=getAncestorBelowParagraph(startContainer);
    rightParagraph=n.getParentElement();
    if (pos == 0 && SPAN.equalsIgnoreCase(element.getNodeName())) {
      merge=(element == n && n == rightParagraph.getFirstChild());
    }
  }
  leftParagraph=rightParagraph.getPreviousSibling();
  merge=merge && (leftParagraph != null);
  if (merge) {
    int lBrCount=Element.as(leftParagraph).getElementsByTagName(BR).getLength();
    int rBrCount=rightParagraph.getElementsByTagName(BR).getLength();
    op=new TreeMergeParagraph(clientJupiter.getSiteId(),path.get(0),leftParagraph.getChildCount() - lBrCount,rightParagraph.getChildCount() - rBrCount);
    op.setPath(TreeHelper.toIntArray(path));
  }
 else {
    log.fine("String_Node_Str" + element.getTagName() + "String_Node_Str");
  }
  return op;
}

Fixed version (ground truth):
public TreeOperation handleBackspaceOnElement(Range caret){
  Node startContainer=caret.getStartContainer();
  List<Integer> path=TreeHelper.getLocator(startContainer);
  TreeOperation op=null;
  Element rightParagraph;
  Node leftParagraph;
  Element element=Element.as(startContainer);
  if (P.equalsIgnoreCase(element.getNodeName())) {
    rightParagraph=element;
    leftParagraph=rightParagraph.getPreviousSibling();
    if (leftParagraph != null) {
      int lBrCount=Element.as(leftParagraph).getElementsByTagName(BR).getLength();
      int rBrCount=rightParagraph.getElementsByTagName(BR).getLength();
      op=new TreeMergeParagraph(clientJupiter.getSiteId(),path.get(0),leftParagraph.getChildCount() - lBrCount,rightParagraph.getChildCount() - rBrCount);
      op.setPath(TreeHelper.toIntArray(path));
    }
 else {
      log.fine("String_Node_Str" + element.getTagName() + "String_Node_Str");
    }
  }
 else {
    rightParagraph=Element.as(getAncestorParagraph(element));
    op=skipBackspaceOnEmptyTexts(element,path,rightParagraph,rightParagraph.getPreviousSibling());
  }
  return op;
}
Program: 178451
Project: 178451
Buggy source:
public TreeOperation handleBackspaceOnTextNode(Range caret){
  int pos=caret.getStartOffset();
  Node startContainer=caret.getStartContainer();
  List<Integer> path=TreeHelper.getLocator(startContainer);
  TreeOperation op=null;
  Node ancestorBelowParagraph=getAncestorBelowParagraph(startContainer);
  Element rightParagraph=ancestorBelowParagraph.getParentElement();
  Node leftParagraph=rightParagraph.getPreviousSibling();
  Text textNode=Text.as(startContainer);
  if (pos == 0) {
    if (leftParagraph != null) {
      boolean merge=false;
      if (textNode != ancestorBelowParagraph && textNode == ancestorBelowParagraph.getFirstChild()) {
        merge=true;
      }
      if (textNode == ancestorBelowParagraph && ancestorBelowParagraph == rightParagraph.getFirstChild()) {
        merge=true;
      }
      if (merge) {
        int lBrCount=Element.as(leftParagraph).getElementsByTagName(BR).getLength();
        int rBrCount=rightParagraph.getElementsByTagName(BR).getLength();
        op=new TreeMergeParagraph(clientJupiter.getSiteId(),path.get(0),leftParagraph.getChildCount() - lBrCount,rightParagraph.getChildCount() - rBrCount);
        op.setPath(TreeHelper.toIntArray(path));
      }
 else {
        op=skipBackspaceOnEmptyTexts(textNode,rightParagraph,leftParagraph);
      }
    }
 else {
      log.fine("String_Node_Str");
    }
  }
 else {
    pos=pos - 1;
    op=new TreeDeleteText(clientJupiter.getSiteId(),pos,TreeHelper.toIntArray(path));
  }
  return op;
}

Fixed version (ground truth):
public TreeOperation handleBackspaceOnTextNode(Range caret){
  int pos=caret.getStartOffset();
  Node startContainer=caret.getStartContainer();
  List<Integer> path=TreeHelper.getLocator(startContainer);
  TreeOperation op=null;
  Node ancestorBelowParagraph=getAncestorBelowParagraph(startContainer);
  Element rightParagraph=ancestorBelowParagraph.getParentElement();
  Node leftParagraph=rightParagraph.getPreviousSibling();
  Text textNode=Text.as(startContainer);
  if (pos == 0) {
    if (leftParagraph != null) {
      boolean merge=false;
      if (textNode != ancestorBelowParagraph && textNode == ancestorBelowParagraph.getFirstChild()) {
        merge=true;
      }
      if (textNode == ancestorBelowParagraph && ancestorBelowParagraph == rightParagraph.getFirstChild()) {
        merge=true;
      }
      if (merge) {
        int lBrCount=Element.as(leftParagraph).getElementsByTagName(BR).getLength();
        int rBrCount=rightParagraph.getElementsByTagName(BR).getLength();
        op=new TreeMergeParagraph(clientJupiter.getSiteId(),path.get(0),leftParagraph.getChildCount() - lBrCount,rightParagraph.getChildCount() - rBrCount);
        op.setPath(TreeHelper.toIntArray(path));
      }
 else {
        op=skipBackspaceOnEmptyTexts(textNode,path,rightParagraph,leftParagraph);
      }
    }
 else {
      log.fine("String_Node_Str");
    }
  }
 else {
    pos=pos - 1;
    op=new TreeDeleteText(clientJupiter.getSiteId(),pos,TreeHelper.toIntArray(path));
  }
  return op;
}
Program: 178452
Project: 178452
Buggy source:
/** 
 * Skips empty texts on backspace
 * @param emptyText the empty text node
 * @param rightParagraph the right paragraph which is the ancestor of the emptyText node
 * @param leftParagraph the left paragraph
 * @return a {@link TreeOperation} or {@code null}
 */
private TreeOperation skipBackspaceOnEmptyTexts(Node emptyText,Node rightParagraph,Node leftParagraph){
  return handleBackspaceOrDeleteKeyOnEmptyTexts(true,emptyText,rightParagraph,leftParagraph);
}

Fixed version (ground truth):
/** 
 * Skips empty texts on backspace
 * @param node the node
 * @param path the node's locator - passed only to avoid computing it again
 * @param rightParagraph the right paragraph which is the ancestor of the emptyText node
 * @param leftParagraph the left paragraph
 * @return a {@link TreeOperation} or {@code null}
 */
private TreeOperation skipBackspaceOnEmptyTexts(Node node,List<Integer> path,Node rightParagraph,Node leftParagraph){
  return handleBackspaceOrDeleteKeyOnEmptyTexts(true,node,path,rightParagraph,leftParagraph);
}