 (defn product-join-prop [key-len]
   (prop/for-all [min-keys gen/s-pos-int
                  actions (gen/vector (gen-action key-len))
-                 movements (gen/vector (gen-next key-len))] ;; TODO implement Join.seek
+                 movements (gen/vector (gen-movement key-len))]
                 (run-product-join-prop min-keys key-len actions movements)))
-
-(defn magic-run-product-join-prop [min-keys key-len actions]
-  (let [tree (apply-to-tree (tree min-keys key-len) actions)
-        itr1 (iterator->keys (iterator tree))
-        iterator-results (for [i1 itr1
-                               i2 itr1]
-                           (vec (concat i1 i2)))
-        iterator-a (js/aurora.join.magic-iterator tree (let [arr (array)]
-                                                         (dotimes [x key-len]
-                                                           (.push arr x))
-                                                         (dotimes [x key-len]
-                                                           (.push arr nil))
-                                                         arr
-                                                         ))
-        iterator-b (js/aurora.join.magic-iterator tree (let [arr (array)]
-                                                         (dotimes [x key-len]
-                                                           (.push arr nil))
-                                                         (dotimes [x key-len]
-                                                           (.push arr x))
-                                                         arr
-                                                         ))
-        join-itr (js/aurora.join.join-iterator #js [iterator-a iterator-b])
-        join-results (js/aurora.join.all-join-results join-itr)]
-    (= iterator-results (map vec join-results))))
 
 (comment
   (dc/quick-check 1000 (least-prop 1))

          (aset outer-key outer-ix (aget key outer-ix)))
        (.maintain this)))

(deftype Join [current-key iterators ^:mutable end?]
  Object
  (maintain [this]
            ;; if all equal, done
            ;; if all blocked but max, .next on max
            ;; if all blocked, set end? true
            ;; otherwise seek smallest non-blocked to max, recur
            )
  (reset [this]
         (debug)
         (debug :reset)
         (dotimes [i (alength current-key)]
           (aset current-key i least))
         (dotimes [i (alength iterators)]
           (.reset (aget iterators i)))
         (set! end? false)
         (.maintain this))
  (key [this]
       (when (false? end?)
         current-key))
  (next [this]
        ;; .next on smallest non-blocked iter
        ;; maintain
        )
  (seek [this key]
        ;; .seek on all iters
        ;; maintain
        ))

(defn join [iterators num-vars iterator->var->nextable? iterator->var->present?]
  (let [seek-key (least-key num-vars)

(defn apply-to-iterator [iterator movements]
  (for [movement movements]
    (case (nth movement 0)
      :next (do
              (.next iterator)
              (.key iterator))
      :seek (do
              (.seek iterator (nth movement 1))
              (.key iterator)))))

(defn apply-to-elems [elems movements]
  (let [cur-elems (atom elems)]
    (for [movement movements]
      (case (nth movement 0)
        :next (do
                (swap! cur-elems rest)
                (or (first (first @cur-elems)) (first (last elems))))
        :seek (do
                (reset! cur-elems (drop-while #(key-lt (nth % 0) (nth movement 1)) elems))
                (or (first (first @cur-elems)) (first (last elems))))))))

(defn run-iterator-prop [min-keys key-len actions movements]
  (let [tree (apply-to-tree (tree min-keys key-len) actions)
