     (let [ua-product (ua-product-fn)]
       (try
         (let [sb (js/goog.string.StringBuffer.)]
+          ;; TODO capture err as well?
           (binding [cljs.core/*print-newline* false
                     cljs.core/*print-fn* (fn [x] (.append sb x))]
             (let [result-value (*eval-js* code)]

(defn exponential-backoff [attempt]
  (* 1000 (min (js/Math.pow 2 attempt) 20)))

(defn ws-connect [& [websocket-url']]
  ;; TODO take care of forwarding print output to the connection
  (let [websocket (goog.net.WebSocket.)
        url (str (make-url websocket-url'))]
    (patch-goog-base)

  (swap! reload-promise-chain #(.then % (fn [_] (Promise. f)))))

;; --------------------------------------------------------------
;; REPL print forwarding
;; --------------------------------------------------------------

(goog-define print-output "console,repl")

(defn print-receivers [outputs]
  (->> (string/split outputs #",")
       (map string/trim)
       (filter (complement string/blank?))
       (map keyword)
       distinct))

(defmulti out-print (fn [k args] k))
(defmethod out-print :console [_ args]
  (.apply (.-log js/console) js/console (garray/clone (to-array args))))

(defmulti err-print (fn [k args] k))
(defmethod err-print :console [_ args]
  (.apply (.-error js/console) js/console (garray/clone (to-array args))))

(defn setup-printing! []
  (let [printers (print-receivers print-output)]
    (set-print-fn! (fn [& args] (doseq [p printers] (out-print p args))))
    (set-print-err-fn! (fn [& args] (doseq [p printers] (err-print p args))))))

#_ (printing-receivers "console,repl")

;; --------------------------------------------------------------
;; Websocket REPL
;; --------------------------------------------------------------

