                        (fn [m] (assoc m timeout-at ; to provide snapshot'ability.
                                       (conj (get-in % [:timeouts timeout-at])
                                             timeout-ch)))))
-    (timeout-handler ago-world)))
+    (timeout-handler ago-world)
+    timeout-ch))
+
+; --------------------------------------------------------
+
+(defn copy-sma-map [sma-map] ; Copy a hash-map of <buf-id => state-machine-array>.
+  (apply hash-map (mapcat (fn [[buf-id sma]] [buf-id (aclone sma)]) sma-map)))
+
+(defn ago-snapshot [ago-world]
+  (let [ago-world-now @ago-world]
+    (-> ago-world-now ; The mutable sma's need explicit cloning.
+        (assoc :smas (copy-sma-map (:smas ago-world-now)))
+        (assoc :smas-new (copy-sma-map (:smas-new ago-world-now))))))
+
+(defn ago-restore [ago-world snapshot]
+    (let [ss (ago-snapshot (atom snapshot)) ; Re-snapshot so snapshot stays immutable.
+          [recycled-smas reborn-smas] (ago-judge-state-machines (:bufs ss)
+                                                                (:smas ss)
+                                                                (:smas @ago-world))
+          [recycled-smasN reborn-smasN] (ago-judge-state-machines (:bufs ss)
+                                                                  (:smas-new ss)
+                                                                  (:smas-new @ago-world))
+          branch-id (- ((:gen-id @ago-world)))] ; Negative in case snapshot re-restored.
+      (swap! ago-world #(-> %
+                            (assoc :seqv (conj (:seqv ss) branch-id 0))
+                            (assoc :bufs (:bufs ss))
+                            (assoc :smas recycled-smas)
+                            (assoc :smas-new recycled-smasN)
+                            (assoc :closed (:closed ss))
+                            (assoc :logical-ms (:logical-ms ss))
+                            (assoc :physical-ms (now))
+                            (assoc :timeouts (:timeouts ss))))
+      (doseq [[sma-old ss-buf-id] reborn-smas]
+        (ago-revive-state-machine ago-world sma-old ss-buf-id))
+      (doseq [[sma-old ss-buf-id] reborn-smasN]
+        (ago-revive-state-machine ago-world sma-old ss-buf-id))
+      (when (seq (:timeouts @ago-world))
+        (timeout-handler ago-world))
+      ago-world))


; --------------------------------------------------------

(defn copy-sma-map [sma-map] ; Copy a hash-map of <buf-id => state-machine-array>.
  (apply hash-map (mapcat (fn [[buf-id sma]] [buf-id (aclone sma)])
                          sma-map)))

(defn ago-snapshot [ago-world]
  (let [ago-world-now @ago-world]
    (-> ago-world-now ; The mutable sma's need explicit cloning.
        (assoc :smas (copy-sma-map (:smas ago-world-now)))
        (assoc :smas-new (copy-sma-map (:smas-new ago-world-now))))))

(defn ago-restore [ago-world snapshot]
    (let [ss (ago-snapshot (atom snapshot)) ; Re-snapshot so snapshot stays immutable.
          [recycled-smas reborn-smas] (ago-judge-state-machines (:bufs ss)
                                                                (:smas ss)
                                                                (:smas @ago-world))
          [recycled-smasN reborn-smasN] (ago-judge-state-machines (:bufs ss)
                                                                  (:smas-new ss)
                                                                  (:smas-new @ago-world))
          branch-id (- ((:gen-id @ago-world)))] ; Negative in case snapshot re-restored.
      (swap! ago-world
             #(-> %
                  (assoc :seqv (conj (:seqv ss) branch-id 0))
                  (assoc :bufs (:bufs ss))
                  (assoc :smas recycled-smas)
                  (assoc :smas-new recycled-smasN)
                  (assoc :closed (:closed ss))
                  (assoc :logical-ms (:logical-ms ss))
                  (assoc :physical-ms (now))))
      (doseq [[sma-old ss-buf-id] reborn-smas]
        (ago-revive-state-machine ago-world sma-old ss-buf-id))
      (doseq [[sma-old ss-buf-id] reborn-smasN]
        (ago-revive-state-machine ago-world sma-old ss-buf-id))
      ago-world))

; --------------------------------------------------------

(def curr-js-timeout-id (atom nil)) ; Value is nil or js-timeout-id.

(defn timeout-handler [ago-world]

                              (protocols/close! ch))
                            (recur (dissoc timeouts soonest-ms)))
                        timeouts)))]
    (swap! ago-world #(assoc % :timeouts timeouts2))
    (when-let [[soonest-ms chs] (first timeouts2)]
      (let [tid (js/setTimeout (fn [] (timeout-handler ago-world))
                               (- soonest-ms logical-ms))]
        (reset! curr-js-timeout-id tid)))))

(defn ago-timeout [ago-world delay-ms] ; Logical milliseconds from now.
  (let [timeout-at (+ delay-ms (:logical-ms @ago-world))
