   [model id f & args]
   (apply -update-actions* model #(= (:id %) id) f args))
 
+(defn -reset-model-to-initial-state
+  "dev-model must be a ratom. Sends special devtools action understood by wrapped reconciler."
+  [dev-model]
+  ((:dispatch-action @dev-model) :-reset-model))
+
+(defn -replay
+  "dev-model must be a ratom. Replays all the enabled actions from the initial model."
+  [dev-model]
+  (-reset-model-to-initial-state dev-model)
+
+  (let [actions (:actions @dev-model)]
+    (swap! dev-model assoc :actions (list))
+    (doseq [action actions]
+      (if (:enabled? action)
+        ((:dispatch-action @dev-model) action)
+        (swap! dev-model update :actions concat [action])))))
+
 (defn -toggle-action
   "dev-model is a ratom."
   [dev-model id]
-  (swap! dev-model
-         -update-action id
-         update :enabled? not))
+  (swap! dev-model -update-action id update :enabled? not)
+  (-replay dev-model))
 
 (defn -devtools-view
   "dev-model must be a ratom."

                     :box-shadow "-2px 0 7px 0 rgba(0, 0, 0, 0.5)"}}
       [-devtools-view dev-model]]])])

(defn wrap-dispatch-action
  "Attaches signal source to action."
  [dispatch-action source-signal-id]
  (fn wrapped-dispatch-action
    [action]
    (dispatch-action {:source-signal-id source-signal-id
                      :action           action})))

(defn wrap-control
  "dev-model must be a ratom."
  [control dev-model]
  (fn wrapped-control
    [model signal dispatch]
    (let [[signal-id _signal_ :as signal-event] (-signal-event signal)
          wrapped-dispatch (wrap-dispatch-action dispatch signal-id)]
      (swap! dev-model update :signals concat [signal-event])
      (control model signal wrapped-dispatch))))

(defn wrap-reconcile
  "dev-model must be a ratom."
  [reconcile dev-model]
  (fn wrapped-reconcile
    [model wrapped-action]
    ; catch initial model
    (when-not (:initial-model-saved? @dev-model)
      (swap! dev-model assoc
             :initial-model model
             :initial-model-saved? true))

    ; handle action
    (let [[source-signal-id unwrapped-action]
          (match wrapped-action
                 ; ok, we have a wrapped action, thanks to devtools controller middleware
                 {:source-signal-id signal-id :action action}
                 [signal-id action]

                 ; for other actions: generate an "unknown signal" event (e.g. for easier action dispatching from REPL)
                 action
                 (let [[unknown-singal-id _signal_ :as unknown-signal-event] (-signal-event :-unknown-signal)]
                   (swap! dev-model update :signals concat [unknown-signal-event])
                   [unknown-singal-id action]))
          event (-action-event source-signal-id unwrapped-action)]
      (swap! dev-model update :actions concat [event])
      (reconcile model unwrapped-action))))
                       :background-color "#2A2F3A"
                       :padding-left     "5px"
                       :color            "white"}}
     [:header
      #_[:button {:style    {:cursor "pointer" :text-decoration "underline"}
                  :on-click #(-replay dev-model)} "REPLAY"]]

     [:div
      (doall
        (for [[signal-id signal] (reverse (:signals @dev-model))]
          ^{:key signal-id}
          [:div {:title "Signal"}
           "⤤ "
           (if (coll? signal)
             [:span [:strong (pr-str (first signal))] " " (clojure.string/join " " (rest signal))]
             [:strong (pr-str signal)])

           (for [{:keys [id enabled? action]} (filter #(= (:source-signal-id %) signal-id)
                                                      (:actions @dev-model))]
             ^{:key id}
             [:div {:style    {:cursor      "pointer"
                               :margin-left "10px"
                               :color       (if enabled? "inherit" "grey")}
                    :on-click #(-toggle-action dev-model id)
                    :title    "Click to enable/disable this action"}

              (if (coll? action)
                [:div "⇣" [:strong (pr-str (first action))] " " (clojure.string/join " " (rest action))]
                [:div "⇣" [:strong (pr-str action)]])])]))]
     [:hr]
     [:strong "initial model:"]
     [:div (pr-str (:initial-model @dev-model))]]))

