   composeAttributes: (attributes) ->
     return if !attributes?
     for key, value of attributes
-      @attributes[key] = if value? then value else undefined
+      if value?
+        @attributes[key] = value
+      else
+        delete @attributes[key]
 
   toString: ->
     attr_str = ""

    deltaC.compact()
    console.assert(JetDelta.isDelta(deltaC), "Composed returning invalid JetDelta", deltaC)
    return deltaC
  
  # We compute the follow according to the following rules: 
  # 1. Insertions in deltaA become retained characters in the follow set
  # 2. Insertions in deltaB become inserted characters in the follow set
  # 3. Characters retained in deltaA and deltaB become retained characters in

  toString: ->
    return "{(#{@startLength}->#{@endLength})[#{@deltas.join(', ')}]}"

JetSync =
  # Inserts in deltaB are given priority. Retains in deltaB are indexes into A,
  # and we take whatever is there (insert or retain).
  compose: (deltaA, deltaB) ->
    console.assert(JetDelta.isDelta(deltaA), "Compose called when deltaA is not a JetDelta, type: " + typeof deltaA)
    console.assert(JetDelta.isDelta(deltaB), "Compose called when deltaB is not a JetDelta, type: " + typeof deltaB)
    console.assert(deltaA.endLength == deltaB.startLength, "startLength #{deltaB.startLength} / endlength #{deltaA.endLength} mismatch")

    deltaA = JetDelta.copy(deltaA)
    deltaB = JetDelta.copy(deltaB)
    deltaA.normalizeChanges()
