           compacted.push(delta)
     @deltas = compacted
 
-  getDeltasAt: (range) ->
+  getDeltasAt: (start, length) ->
     changes = []
     index = 0
-    if typeof range == 'number'
-      range = new JetRetain(range, range + 1)
+    if typeof length == 'undefined'
+      if typeof start == 'number'
+        range = new JetRetain(start, start + 1)
+      else
+        range = JetRetain.copy(start)
     else
-      range = JetRetain.copy(range)
+      range = new JetRetain(start, start + length)
     for delta in @deltas
       if range.start == range.end then break
       console.assert(JetDelta.isRetain(delta) || JetDelta.isInsert(delta), "Invalid change in delta", this)

  composeAttributes: (attributes) ->
    return if !attributes?
    for key, value of attributes
      if value?
        @attributes[key] = value
      else
        delete @attributes[key]

  numAttributes: () ->
    _.keys(@attributes).length

    console.assert(JetDelta.isDelta(deltaA), "Decompose2 called when deltaA is not a JetDelta, type: " + typeof deltaA)
    console.assert(JetDelta.isDelta(deltaC), "Decompose2 called when deltaC is not a JetDelta, type: " + typeof deltaC)
    console.assert(deltaA.startLength == deltaC.startLength, "startLength #{deltaA.startLength} / startLength #{deltaC.startLength} mismatch")
    console.assert(_.all(deltaA.deltas, ((delta) -> return delta.text?)), "DeltA has retain in decompose")
    console.assert(_.all(deltaC.deltas, ((delta) -> return delta.text?)), "DeltC has retain in decompose")


    decomposeAttributes = (attrA, attrC) ->
      decomposedAttributes = {}
      for key, value of attrC
        if attrA[key] == undefined or attrA[key] != value
          decomposedAttributes[key] = value
      for key, value of attrA
        if attrC[key] == undefined
          decomposedAttributes[key] = null
      return decomposedAttributes

    deltaToText = (delta) ->
      return _.map(delta.deltas, (delta) ->
        return if delta.text? then delta.text else ""
      ).join('')

    diffTexts = (oldText, newText) ->
      diff = dmp.diff_main(oldText, newText)
      if (diff.length > 2)
        dmp.diff_cleanupSemantic(diff)
        dmp.diff_cleanupEfficiency(diff)
      return diff

    diffToDelta = (diff) ->
      console.assert(diff.length > 0, "diffToDelta called with diff with length <= 0")
      originalLength = 0
      finalLength = 0
      deltas = []
      # For each difference apply them separately so we do not disrupt the cursor
      for [operation, value] in diff
        switch operation
          when diff_match_patch.DIFF_DELETE
            # Deletes implied
            originalLength += value.length
          when diff_match_patch.DIFF_INSERT
            deltas.push(new JetInsert(value))
            finalLength += value.length
          when diff_match_patch.DIFF_EQUAL
            deltas.push(new JetRetain(originalLength, originalLength + value.length))
            originalLength += value.length
            finalLength += value.length
      return new JetDelta(originalLength, finalLength, deltas)

    textA = deltaToText(deltaA)
    textC = deltaToText(deltaC)
    unless textA == '' and textC == ''
      diff = diffTexts(textA, textC)
      insertDelta = diffToDelta(diff)
    else
      insertDelta = new JetDelta(0, 0, [])
    deltas = []
    offset = 0
    _.each(insertDelta.deltas, (delta) ->
      deltasInC = deltaC.getDeltasAt(offset, delta.getLength())
      offsetC = 0
      _.each(deltasInC, (deltaInC) ->
        if JetDelta.isInsert(delta)
          d = new JetInsert(delta.text.substring(offsetC, deltaInC.getLength()), deltaInC.attributes)
          deltas.push(d)
        else if JetDelta.isRetain(delta)
          deltasInA = deltaA.getDeltasAt(delta.start + offsetC, deltaInC.getLength())
          offsetA = 0
          _.each(deltasInA, (deltaInA) ->
            attributes = decomposeAttributes(deltaInA.attributes, deltaInC.attributes)
            start = delta.start + offsetA + offsetC
            e = new JetRetain(start, start + deltaInA.getLength(), attributes)
            deltas.push(e)
            offsetA += deltaInA.getLength()
          )
        else
          console.error("Invalid delta in deltaB when composing", deltaB)
        offsetC += deltaInC.getLength()
      )
      offset += delta.getLength()
    )

    deltaB = new JetDelta(insertDelta.startLength, insertDelta.endLength, deltas)
    deltaB.compact()
    return deltaB



  # We compute the follow according to the following rules:
  # 1. Insertions in deltaA become retained characters in the follow set
