 
                              :booker {:next [:invoice-generator (fn [msg] :notifier)]}}}}})
 
-  (def browser-components1 {:components {:input-validator #(doto % (println "(input-validator)"))
-                                         :input-sanitizer #(doto % (println "(input-sanitizer)"))}
-                            :tunnels {:server #(doto % (println "(browser -> server)"))}})
-
-  (def server-components1 {:components {:auth-checker #(doto % (println "(auth-checker)"))
-                                        :booker #(doto % (println "(booker)"))
-                                        :invoice-generator #(doto % (println "(invoice-generator)"))
+
+  ;;; via fns
+
+  (do (def browser-components1 {:components {:input-validator #(doto % (println "(input-validator)"))
+                                             :input-sanitizer #(doto % (println "(input-sanitizer)"))}
+                                :tunnels {:server #(doto % (println "(browser -> server)"))}})
+
+      (def server-components1 {:components {:auth-checker #(doto % (println "(auth-checker)"))
+                                            :booker #(doto % (println "(booker)"))
+                                            :invoice-generator #(doto % (println "(invoice-generator)"))
                                         ;;;:notifier #(doto % (println "(notifier)"))
-                                        :DEFAULT #(doto % (println "(DEFAULT)"))}
-                           :tunnels {:browser #(doto % (println "(server -> browser)"))}})
-
-  (def browser-router1 (make-router ruleset1 browser-components1 :unit :browser))
-  (def server-router1 (make-router ruleset1 server-components1 :unit :server))
-
-  (def message1 (message :book-flight {:foo :bar}))
-
-  (->> message1
+                                            :DEFAULT #(doto % (println "(DEFAULT)"))}
+                               :tunnels {:browser #(doto % (println "(server -> browser)"))}})
+
+      (def browser-router1 (make-router ruleset1 browser-components1 :unit :browser))
+      (def server-router1 (make-router ruleset1 server-components1 :unit :server)))
+
+  (->> (message :book-flight {:foo :bar})
        (route browser-router1)
        first
        (route browser-router1)

(defn route [{:keys [dispatch?] :as router} msg]
  (let [resmsgs (advance router msg)]
    (if dispatch?
      (map (partial dispatch router) resmsgs)
      resmsgs)))

(defn message [route map & {:keys [max-transitions]

       (route server-router1))


  ;;; via core.async

  (do (def browser-comp-ch     (a/chan))
      (def browser-comp-ch-pub (a/pub browser-comp-ch #(peek (:ow.starbuck.message-router/component %))))
      (def browser-router-ch   (a/chan))

      (def server-comp-ch     (a/chan))
      (def server-comp-ch-pub (a/pub server-comp-ch #(peek (:ow.starbuck.message-router/component %))))
      (def server-router-ch   (a/chan))

      (def browser-components2 {:components {:input-validator browser-comp-ch
                                             :input-sanitizer browser-comp-ch}
                                :tunnels {:server #(do (println % "(browser -> server)")
                                                       (a/put! server-router-ch %))}})

      (def server-components2 {:components {:auth-checker server-comp-ch
                                            :booker server-comp-ch
                                            :invoice-generator server-comp-ch
                                            ;;;:notifier server-comp-ch
                                            :DEFAULT server-comp-ch}
                               :tunnels {:browser #(do (println % "(server -> browser)")
                                                       (a/put! browser-router-ch %))}})

      (def browser-router2 (make-router ruleset1 browser-components2 :unit :browser))
      (def server-router2 (make-router ruleset1 server-components2 :unit :server))

      (defn start-async-component [comp-kw input-pub output-ch]
        (let [sub-ch (a/sub input-pub comp-kw (a/chan))
              timeout (+ 20000 (rand-int 2000))]
          (a/go-loop [[msg _] (a/alts! [sub-ch (a/timeout timeout)])]
            (println "got component msg in" comp-kw "-" msg)
            (when msg
              (a/put! output-ch (update msg :visited-components #(conj % [comp-kw (java.util.Date.)])))
              (recur (a/alts! [sub-ch (a/timeout timeout)]))))))

      (defn start-async-router [router router-kw input-ch output-ch]
        (let [timeout (+ 20000 (rand-int 2000))]
          (a/go-loop [[msg _] (a/alts! [input-ch (a/timeout timeout)])]
            (println "got router msg in" router-kw "-" msg)
            (when msg
              (route router msg)
              (recur (a/alts! [input-ch (a/timeout timeout)])))))))

  (do (doseq [c #{:input-validator :input-sanitizer}]
        (start-async-component c browser-comp-ch-pub browser-router-ch))

      (doseq [c #{:auth-checker :booker :invoice-generator :notifier}]
        (start-async-component c server-comp-ch-pub server-router-ch))

      (start-async-router browser-router2 :browser browser-router-ch browser-comp-ch)
      (start-async-router server-router2 :server server-router-ch server-comp-ch))

  (->> (message :book-flight {:foo :bar})
       #_(route browser-router2)    ;; you can start like this
       (a/put! browser-router-ch) ;; or this
       )

  )
