 (def failed 2)
 
 ;; lower and upper are inclusive
-;; lower is aliased to iterator, must not be mutated
-(deftype Contains [iterator seek-key ^:mutable lower ^:mutable upper ixes pushed|split pushed-nodes pushed-ixes split-lowers split-uppers]
+(deftype Contains [iterator ^:mutable lower ^:mutable upper ixes pushed|split pushed-nodes pushed-ixes split-lowers split-uppers]
   Object
   (reset [this]
          (.reset iterator)
-         (dotimes [i (alength seek-key)]
-           (aset seek-key i least))
-         (set! lower (.seek-gte iterator seek-key))
-         (dotimes [i (alength upper)]
+         (dotimes [i (alength lower)]
+           (aset lower i least)
            (aset upper i greatest))
+         (let [key (.seek-gte iterator lower)]
+           (aset lower 0 (aget key 0)))
          (aclear pushed-nodes)
          (aclear pushed-ixes)
          (aclear split-lowers)
          (aclear split-uppers))
   (propagate [this los his]
-             (if (nil? lower)
-               failed
-               (do
-                 (dotimes [i (alength ixes)]
-                   (aset seek-key i (aget los (aget ixes i))))
-                 (when (key-lt lower seek-key)
-                   (set! lower (.seek-gte iterator seek-key)))
-                 (if (or (nil? lower)
-                         (key-lt upper lower))
+             (check (key-lte los his) (pr-str los his))
+             (check (key-lte lower upper) (pr-str lower upper))
+             (debug :before-propagate lower upper los his)
+             (let [this-changed? false]
+               (loop [i 0]
+                 (when (< i (alength ixes))
+                   (let [ix (aget ixes i)
+                         old-lo (aget lower i)
+                         old-hi (aget upper i)
+                         new-lo (aget los ix)
+                         new-hi (aget his ix)]
+                     (when (val-lt old-lo new-lo)
+                       (aset lower i new-lo)
+                       (set!! this-changed? true))
+                     (when (val-lt new-hi old-hi)
+                       (aset upper i new-hi)
+                       (set!! this-changed? true))
+                     (when (identical? new-lo new-hi)
+                       (recur (+ i 1))))))
+               ;; TODO only seek on change, including split as change
+               (let [key (.seek-gte iterator lower)
+                     that-changed? false]
+                 (debug :propagate-with key)
+                 (if (or (nil? key)
+                         (key-lt upper key))
                    failed
-                   (let [changed? false]
-                     (dotimes [i (alength ixes)]
-                       (let [ix (aget ixes i)
-                             new-lo (aget lower i)
-                             old-hi (aget his ix)
-                             new-hi (aget upper i)]
-                         (when (val-lt (aget los ix) new-lo)
-                           (aset los ix new-lo)
-                           (set!! changed? true))
-                         (if (val-lt new-hi old-hi)
-                           (do
+                   (loop [i 0]
+                     (let [ix (aget ixes i)
+                           old-lo (aget los ix)
+                           old-hi (aget his ix)
+                           new-lo (aget key i)
+                           new-hi (aget upper i)]
+                       (if (val-lt old-hi new-lo)
+                         failed
+                         (do
+                           (aset lower i new-lo)
+                           (when (val-lt old-lo new-lo)
+                             (aset los ix new-lo)
+                             (set!! that-changed? true))
+                           (when (val-lt new-hi old-hi)
                              (aset his ix new-hi)
-                             (set!! changed? true))
-                           (aset upper i old-hi))))
-                     (if (true? changed?)
-                       changed
-                       unchanged))))))
+                             (set!! that-changed? true))
+                           (if (and (< (+ i 1) (alength ixes)) (identical? new-lo new-hi))
+                             (recur (+ i 1))
+                             (do
+                               (debug :after-propagate lower upper los his)
+                               (check (key-lte los his) (pr-str los his))
+                               (check (key-lte lower upper) (pr-str lower upper))
+                               (if (true? that-changed?)
+                                 changed
+                                 unchanged)))))))))))
   (push [this]
         (apush pushed|split true)
         (apush pushed-nodes (.-node iterator))

    (alength (time (iterator->keys j)))
  )

  (let [tree1 (tree 10)
        _ (.assoc! tree1 #js ["a" "b"] 0)
        _ (.assoc! tree1 #js ["b" "c"] 0)
        _ (.assoc! tree1 #js ["c" "d"] 0)
        _ (.assoc! tree1 #js ["d" "b"] 0)
        tree2 (tree 10)
        _ (.assoc! tree2 #js ["b" "a"] 0)
        _ (.assoc! tree2 #js ["c" "b"] 0)
        _ (.assoc! tree2 #js ["d" "c"] 0)
        _ (.assoc! tree2 #js ["b" "d"] 0)
        join-itr (join #js [(iterator tree1) (iterator tree2)] 3 #js [#js [true false true]
                                                                      #js [false true true]])
        ]
     (map vec (iterator->keys join-itr))
    )

 )

            [cemerick.double-check.properties :as prop :include-macros true]
            [cemerick.pprng :as pprng]
            clojure.set)
  (:require-macros [aurora.macros :refer [debug check apush apush* amake aclear typeof set!! dofrom]]))

;; COMPARISONS

