          (let [node (zip/node zipper), node-weight (-> node measure measure-key), new-weight (+ node-weight total-weight)]
            (if (string? node)
              (if (pred new-weight node)
-               (throw (IndexOutOfBoundsException. (str "Node index out of range")))
+               (throw (IndexOutOfBoundsException. (str "Node index out of range: " new-weight)))
                [(-> zipper zip/remove zip/root) node (reassemble acc)])
              (let [left (zip/down zipper), right (zip/right left)]
                (cond (nil? right) (recur acc left total-weight)

(defn rope->string
  "Flat string from Rope at root"
  [root]
  (->> (rope-seq root) (filter string?) (reduce str)))

(defn rebalance
  "Create rebalanced copy of the Rope, using the algorithm described in \"Ropes: an Alternative to Strings\".

              (if (<= weight l-index)
                (recur (zip/right next) (- l-index weight))
                (recur next l-index)))
            :default (throw (IndexOutOfBoundsException. (str "Rope index out of range: " index)))))))

(defn rope-seq
  "Lazy sequence of all Rope nodes at root, depth-first order"
