         (let [val (get-in db p)
               val (if (nil? val) (default-fn) val)]
           (assoc-in db p (handler val v)))))))
+
+
+(defn undoable
+  "A Middleware factory which stores an undo checkpoint.
+  \"explanation\" can be either a string or a function. If it is a
+  function then it must be:  (db event-vec) -> string.
+  \"explanation\" can be nil. in which case no
+  "
+  [explanation]
+  (fn middleware
+    [handler]
+    (fn undoable-handler
+      [db event-vec]
+      (let [explanation (cond
+                          (fn? explanation)     (explanation db event-vec)
+                          (string? explanation) explanation
+                          (nil? explanation)    ""
+                          :else (warn "re-frame: undoable given bad parameter. Got: " explanation))]
+      (store-now! explanation)
+      (handler db event-vec)))))
 
 
 (defn enrich


(defn pure
  "Acts as an adaptor, allowing handlers to be writen as pure functions.
  The re-frame router will pass in an atom as the first parameter. This middleware
  adapts that to the value within the atom.
  If you strip away the error/efficiency checks, this middleware is just:
     (reset! app-db (handler @app-db event-vec))"
  [handler]
  (fn pure-handler
    [app-db event-vec]



(defn path
  "A middleware factory which supplies a sub-tree of `db` to the handler.
  Supplies a narrowed view.
  Assumes \"pure\" is in the middleware pipeline prior.
  Grafts the result back into db.
  If a get-in of the path results in a nil, then \"default-fn\" will be called to supply a value.
