jacked-up debug works on grouped streams and states

--- src/clj/marceline/storm/trident.clj
+++ src/clj/marceline/storm/trident.clj
@@ -1,6 +1,8 @@
 (ns marceline.storm.trident
-  (:import [storm.trident.operation.builtin Debug]
+  (:import [storm.trident TridentState]
+           [storm.trident.operation.builtin Debug]
            [storm.trident.tuple TridentTuple TridentTupleView]
+           [storm.trident.fluent GroupedStream]
            [backtype.storm.tuple Values Fields]
            [backtype.storm.utils RotatingMap TimeCacheMap]
            [marceline.storm.trident.clojure
@@ -422,9 +424,12 @@

 (defn debug
   [stream]
-  (.each stream
-         (.getOutputFields stream)
-         (Debug.)))
+  (condp isa? (class stream)
+    GroupedStream (debug (.toStream stream))
+    TridentState (do (debug (.newValuesStream stream)) stream)
+    (.each stream
+           (.getOutputFields stream)
+           (Debug.))))

 (defn broadcast
   [stream]


Tweak coll->chan abstraction

Tweak coll->chan abstraction

--- src/cljs/asciinema_player/core.cljs
+++ src/cljs/asciinema_player/core.cljs
@@ -37,45 +37,38 @@
   [state {:keys [lines cursor]}]
   (merge-with merge state {:lines lines :cursor cursor}))

+
 (defn coll->chan
-  "Returns a channel that emits values from the given collection.
+  "Returns a channel that emits frames from the given collection.
   The difference from core.async/to-chan is this function expects elements of
-  the collection to be tuples of [delay data], and it emits data after
-  delay (sec) for each element."
-  [coll]
-  (let [ch (chan)]
-    (go
-      (loop [coll coll]
-        (when-let [[delay data] (first coll)]
-          (<! (timeout (* 1000 delay)))
-          (>! ch data)
-          (recur (rest coll))))
-      (close! ch))
-    ch))
-
-(defn frames->chan
-  "Returns a channel that emits frames from the given collection."
-  [frames]
-  (let [ch (chan)
-        start (js/Date.)]
-    (go
-      (loop [frames frames
-             virtual-time 0
-             pending-diff {}]
-        (when-let [[delay diff] (first frames)]
-          (let [wall-time (elapsed-time-since start)
-                new-virtual-time (+ virtual-time delay)
-                ahead (- new-virtual-time wall-time)]
-            (if (pos? ahead)
-              (do
-                (when-not (empty? pending-diff)
-                  (>! ch pending-diff))
-                (<! (timeout (* 1000 ahead)))
-                (>! ch diff)
-                (recur (rest frames) new-virtual-time {}))
-              (recur (rest frames) new-virtual-time (merge-with merge pending-diff diff))))))
-      (close! ch))
-    ch))
+  the collection to be tuples of [delay data], and it emits data after delay
+  (sec) for each element. It tries to always stay 'on the schedule' by measuring
+  elapsed time and skipping elements if necessary. When reducer and init given
+  it reduces consecutive elements instead of skipping."
+  ([coll] (coll->chan coll (fn [_ v] v) nil))
+  ([coll reducer init]
+   (let [ch (chan)
+         start (js/Date.)]
+     (go
+       (loop [coll coll
+              virtual-time 0
+              pending-diff init]
+         (if-let [[delay diff] (first coll)]
+           (let [wall-time (elapsed-time-since start)
+                 new-virtual-time (+ virtual-time delay)
+                 ahead (- new-virtual-time wall-time)]
+             (if (pos? ahead)
+               (do
+                 (when-not (empty? pending-diff)
+                   (>! ch pending-diff))
+                 (<! (timeout (* 1000 ahead)))
+                 (>! ch diff)
+                 (recur (rest coll) new-virtual-time init))
+               (recur (rest coll) new-virtual-time (reducer pending-diff diff)))))
+         (when-not (empty? pending-diff)
+           (>! ch pending-diff)))
+       (close! ch))
+     ch)))

 (defn prev-diff
   "Returns a combined diff from frames up to (and including) given time (in
@@ -122,7 +115,7 @@
         play-from (:play-from state)
         speed (:speed state)
         frames (-> (:frames state) (next-frames play-from) (frames-at-speed speed))
-        diff-chan (frames->chan frames)
+        diff-chan (coll->chan frames (partial merge-with merge) {})
         timer-chan (coll->chan (repeat [0.3 true]))
         stop-playback-chan (chan)
         elapsed-time #(* (elapsed-time-since start) speed)


Use destructuring to get to individual player props

--- src/cljs/asciinema_player/view.cljs
+++ src/cljs/asciinema_player/view.cljs
@@ -144,15 +144,11 @@
         (go (>! events [event-name]))))))

 (defn player [state events]
-  (let [on-key-press (partial process-key-event events)
-        class-name (player-class-name (:theme @state))
-        font-size (:font-size @state)
-        lines (:lines @state)
-        playing? (:playing @state)
-        current-time (:current-time @state)
-        duration (:duration @state)]
+  (let [{:keys [font-size theme lines playing current-time duration]} @state
+        on-key-press (partial process-key-event events)
+        class-name (player-class-name theme)]
     [:div.asciinema-player-wrapper {:tab-index -1 :on-key-press on-key-press}
       [:div.asciinema-player {:class-name class-name :style (player-style)}
         [terminal font-size lines]
-        [control-bar playing? current-time duration events]
+        [control-bar playing current-time duration events]
         #_ [start-overlay]]]))


Start prototyping a new reagent based waypoints implementation

--- src/cljs/comic_reader/ui/image.cljs
+++ src/cljs/comic_reader/ui/image.cljs
@@ -3,7 +3,8 @@
             [reagent.core :as reagent]
             [comic-reader.api :as api]
             [cljsjs.waypoints]
-            [comic-reader.ui.base :as base]))
+            [comic-reader.ui.base :as base])
+  (:import (goog.async Throttle)))

 (defn setup! []
   (re-frame/reg-sub
@@ -29,46 +30,68 @@
    (fn [app-db [_ location image-tag]]
      (assoc-in app-db [:images location] image-tag))))

-(defn make-waypoint [options]
-  (js/Waypoint. (clj->js options)))
+(def ^:private waypoints (atom {}))

-(defn make-img-did-mount [set-waypoints! set-current-comic]
-  (fn [this]
-    (let [node (reagent/dom-node this)
-          wp-down (make-waypoint {:element node
-                                  :group "comic-image"
-                                  :continuous true
-                                  :handler #(when (= % "down")
-                                              (set-current-comic))})
-          wp-up (make-waypoint {:element node
-                                :group "comic-image"
-                                :continuous true
-                                :offset "bottom-in-view"
-                                :handler #(when (= % "up")
-                                            (set-current-comic))})]
-      (set-waypoints! [wp-up wp-down]))))
+(defn waypoint [child-el options]
+  (let [id (gensym "waypoint-id")
+        trigger-point (atom nil)
+        reset-trigger-point! (fn [n]
+                               (reset! trigger-point n))]
+    (reagent/create-class
+     {:display-name "waypoint"
+      :component-will-mount
+      (fn []
+        (.log js/console (str id " will-mount"))
+        (swap! waypoints assoc id (fn []
+                                    (.log js/console (str "Waypoint " id " triggered.")))))
+      :component-did-mount
+      (fn []
+        (.log js/console (str id " did-mount")))
+      :component-will-unmount
+      (fn []
+        (.log js/console (str id " will-unmount"))
+        (swap! waypoints dissoc id))
+      :component-did-update
+      (fn []
+        (.log js/console (str id " did-update")))
+      :reagent-render
+      (fn [child-el]
+        child-el)})))

-(defn replace-waypoints [waypoints new-waypoints]
-  (doseq [wp waypoints]
-    (.destroy wp) )
-  new-waypoints)
+(defn check-waypoints [last-scroll-y]
+  (.log js/console "Last scroll was " last-scroll-y))
+
+(defn waypoint-context [child-el]
+  (let [state (atom {})
+        throttler (Throttle. #(do
+                                (swap! state assoc :ticking false)
+                                (check-waypoints (:last-scroll-y @state))) 200)
+        listener-fn (fn []
+                      (when (not (:ticking @state))
+                        (swap! state assoc
+                               :ticking true
+                               :last-scroll-y (.-scrollY js/window)))
+                      (.fire throttler))]
+    (reagent/create-class
+     {:display-name "waypoint-context"
+      :component-did-mount
+      (fn []
+        (.addEventListener js/window "scroll" listener-fn)
+        (.log js/console "waypoint-context did-mount"))
+      :component-will-unmount
+      (fn []
+        (.removeEventListener js/window "scroll" listener-fn)
+        (.log js/console "waypoint-context did-unmount"))
+      :reagent-render
+      (fn [child-el]
+        child-el)})))

 (defn comic-image [set-current-comic tag]
-  (let [waypoints (atom nil)
-        set-waypoints! #(swap! waypoints replace-waypoints %)]
-    (reagent/create-class
-     {:display-name "comic-image"
-      :component-did-mount
-      (make-img-did-mount
-       set-waypoints!
-       set-current-comic)
-      :component-will-unmount #(set-waypoints! nil)
-      :reagent-render
-      (fn [_ tag]
-        (if (= tag :loading)
-          [base/loading]
-          [:div.row
-           [:div.medium-12.columns tag]]))})))
+  (if (= tag :loading)
+    [base/loading]
+    [:div.row
+     [:div.medium-12.columns
+      [waypoint tag {}]]]))

 (defn comic-image-container [set-current-comic location]
   (let [image (re-frame/subscribe [:image location])]
@@ -104,4 +127,5 @@
                 (+ prev-scroll-top (- curr-scroll-height prev-scroll-height)))))
       :reagent-render
       (fn [set-current-location locations]
-        [:div.comic-list (map #(make-comic-image set-current-location %) locations)])})))
+        [waypoint-context
+         [:div.comic-list (map #(make-comic-image set-current-location %) locations)]])})))


Fix mobile videos (?), fix twitter handle

--- src/cljs/surprise_kittens/core.cljs
+++ src/cljs/surprise_kittens/core.cljs
@@ -33,7 +33,7 @@
                     :height (:height kitten)
                     :loop "loop"
                     :muted "muted"
-                    :src (:webm kitten)}
+                    :data-link (:link kitten)}
       (dom/source #js {:src (:webm kitten)})
       (dom/source #js {:src (:mp4 kitten)}))
     (dom/img #js {:className "clickable rounded shadowed"
@@ -43,7 +43,7 @@
   (str
     (js/encodeURIComponent "Surprise! Kittens! ")
     (js/encodeURIComponent link)
-    (js/encodeURIComponent " via @srprisekittens")))
+    (js/encodeURIComponent " via @sprisekittens")))

 (defn tweet-deep-url [link]
   (str "twitter://post?message=" (tweet-text link)))


Ooops, remove accidental double call to unchanged

--- src/aurora/runtime/core.cljs
+++ src/aurora/runtime/core.cljs
@@ -46,7 +46,7 @@
   (loop [kn cur
          prev nil
          i 0]
-    (if (or (and kn prev (or (prn :change (language/unchanged prev kn)) (language/unchanged prev kn)))
+    (if (or (and kn prev (language/unchanged prev kn))
             (>= i 10))
       kn
       (recur


namespace fix

namespace fix

--- src/babel/espanol/writer.clj
+++ src/babel/espanol/writer.clj
@@ -21,7 +21,7 @@
 (require '[dag-unify.core :as unify])

 ;; for debugging:
-(require '[babel.espanol.morphology.verbs :as verbs])
+(require '[babel.espanol.morphology.verbs :as esverbs])

 (defn expression [& [spec]]
   (let [spec (if spec spec :top)]


Consistent names on single-attr-resolvers

--- src/com/wsscode/pathom/connect.cljc
+++ src/com/wsscode/pathom/connect.cljc
@@ -1351,7 +1351,7 @@

   `f` receives a single argument, which is the input value from `from`."
   [from to f]
-  (let [sym (gensym (attr-alias-name from to))]
+  (let [sym (str (attr-alias-name from to) "-single-attr-transform")]
     (resolver sym
       {::input  #{from}
        ::output [to]}
@@ -1361,7 +1361,7 @@
 (defn single-attr-resolver2
   "Similar single-attr-resolver, but `f` receives two arguments, `env` and the input."
   [from to f]
-  (let [sym (gensym (attr-alias-name from to))]
+  (let [sym (str (attr-alias-name from to) "-single-attr-transform")]
     (resolver sym
       {::input  #{from}
        ::output [to]}


fix typo in comment

fix typo in comment

--- src/clj/com/rpl/specter.cljx
+++ src/clj/com/rpl/specter.cljx
@@ -122,7 +122,7 @@
   The transform-fn in this case is expected to return [ret user-ret]. ret is
    what's used to transform the data structure, while user-ret will be added to the user-ret sequence
    in the final return. replace-in is useful for situations where you need to know the specific values
-   of what was transformd in the data structure."
+   of what was transformed in the data structure."
   [selector transform-fn structure & {:keys [merge-fn] :or {merge-fn concat}}]
   (compiled-replace-in (i/comp-paths* selector) transform-fn structure :merge-fn merge-fn))


Also update-not-delete on slots

Also update-not-delete on slots

--- src/clj/herder/web/slots.clj
+++ src/clj/herder/web/slots.clj
@@ -34,7 +34,7 @@
                             :start-minutes (-> params :start time->minutes)
                             :end-minutes (-> params :end time->minutes)
                             :convention_id (:id params)}]))
-      (notifications/send-notification [(:id params) :slots])
+      (notifications/send-notification [:slots (:id params)])
       (status (response {:id id}) 201))))

 (defn minutes->time [minutes]
@@ -60,7 +60,7 @@

 (defn delete-slot [{{:keys [id slot_id]} :params}]
   (let [slot (d/delete db/slots (d/where {:id slot_id}))]
-    (notifications/send-notification [id :slots])
+    (notifications/send-notification [:slots id])
     (status (response {}) (if (> slot 0) 200 404))))

 (def uuid-regex #"[\w]{8}(-[\w]{4}){3}-[\w]{12}")


some doc-strings for the pipeline-runners

--- src/clj/lambdacd/runners.clj
+++ src/clj/lambdacd/runners.clj
@@ -3,12 +3,18 @@
             [clojure.core.async :as async]
             [lambdacd.internal.pipeline-state :as pipeline-state]))

-(defn start-new-run-after-first-step-finished [{pipeline-def :pipeline-def context :context}]
+(defn start-new-run-after-first-step-finished
+  "Runner that makes sure there is always one pipeline-run with the first step active. useful if the first step is waiting for
+  a trigger such as a VCS commit and you don't want to wait for the whole pipeline to complete before starting the next run.
+  Do not use this if your first step finishes immediately as this will lead to lots of active pipelines"
+  [{pipeline-def :pipeline-def context :context}]
  (let [pipeline-run-fn (fn [] (async/thread (execution/run pipeline-def context)))]
    (pipeline-state/notify-when-no-first-step-is-active context pipeline-run-fn)
    (pipeline-run-fn)))

-(defn start-one-run-after-another [{pipeline-def :pipeline-def context :context}]
+(defn start-one-run-after-another
+  "Runner that always keeps one pipeline-run active. It waits for a run to complete, then starts a new one."
+  [{pipeline-def :pipeline-def context :context}]
  (async/thread
    (while true
      (execution/run pipeline-def context))))


small cleanup

small cleanup

--- src/clj_naive_bayes/core.clj
+++ src/clj_naive_bayes/core.clj
@@ -14,10 +14,10 @@
   "Compute word frequencies in document list restricted to dictionary entries"
   [doc-list]
   (->> doc-list
-       (pmap #(into #{} (split % #" ")))
+       (map #(into #{} (split % #" ")))
        (apply concat)
        frequencies
-       (pmap (fn [[k v]] [k (/ v (count doc-list))]))
+       (map (fn [[k v]] [k (/ v (count doc-list))]))
        (into {})))

@@ -28,7 +28,7 @@
   (let [raw-spam (read-mails spam-dir)
         raw-ham (read-mails non-spam-dir)
         dictionary (->> (concat raw-spam raw-ham)
-                        (pmap #(split % #" "))
+                        (map #(split % #" "))
                         (apply concat)
                         frequencies
                         (remove (fn [[k v]] (< (count k) 2)))
@@ -72,7 +72,7 @@
   [dir model]
   (println (str "Testing " dir " ..."))
   (let [results (->> (read-mails dir)
-                     (pmap #(classify % model))
+                     (map #(classify % model))
                      frequencies)]
     (println (str "Classified as spam: " (or (get results true) 0)))
     (println (str "Classified as nonspam: " (or (get results false) 0)))
@@ -88,9 +88,9 @@

 (comment

-  (->> (train "data/spam-train" "data/nonspam-train")
-       (test-mails "data/spam-test")
-       (test-mails "data/nonspam-test")
-       :done)
+  (time (->> (train "data/spam-train" "data/nonspam-train")
+             (test-mails "data/spam-test")
+             (test-mails "data/nonspam-test")
+             :done))

   )


add Portuguese channel to chat by request

--- src/cljs/netrunner/chat.cljs
+++ src/cljs/netrunner/chat.cljs
@@ -8,7 +8,8 @@
             [netrunner.main :as main]))

 (def app-state
-  (atom {:channels {:general [] :america [] :europe [] :asia-pacific [] :francais [] :español [] :italia [] :sverige []}}))
+  (atom {:channels {:general [] :america [] :europe [] :asia-pacific [] :français []
+                    :español [] :italia [] :português [] :sverige []}}))

 (def chat-channel (chan))
 (def chat-socket (.connect js/io (str js/iourl "/chat")))


Put also groupchats in the chats channel

--- src/cljs/openslack/xmpp.cljs
+++ src/cljs/openslack/xmpp.cljs
@@ -204,6 +204,7 @@
 (defn chats [client]
   (let [c (async/chan 10 (map raw-chat->chat))]
     (.on client "chat" (partial async/put! c))
+    (.on client "groupchat" (partial async/put! c))
     c))

 (defn raw-chat-state->chat-state [rchatstate]


Besser Variante zu 8.4

Besser Variante zu 8.4


Small cosmetics for Force Layout code

Small cosmetics for Force Layout code

Signed-off-by: Daniel Borchmann <25857343a15bf1edafebc2912e82ecf775c585c1@mailbox.tu-dresden.de>

--- src/conexp/layouts/force.clj
+++ src/conexp/layouts/force.clj
@@ -18,18 +18,14 @@

 ;; Helpers

-(defn- square
-  "Squares."
-  [x]
-  (with-doubles [x]
-    (* x x)))
+(defn- ^double square [^double x]
+  (* x x))

 (defn- line-length-squared
   "Returns the square of the length of the line between [x_1, y_1] and [x_2, y_2]."
-  [[x_1, y_1] [x_2, y_2]]
-  (with-doubles [x_1, y_1, x_2, y_2]
-    (+ (square (- x_1 x_2))
-       (square (- y_1 y_2)))))
+  [[x_1, y_1], [x_2, y_2]]
+  (+ (square (- x_1 x_2))
+     (square (- y_1 y_2))))

 (defn- distance
   "Returns distance of two points."
@@ -37,25 +33,13 @@
   (with-doubles [x_1 y_1 x_2 y_2]
     (Math/sqrt (+ (square (- x_1 x_2)) (square (- y_1 y_2))))))

-(defmacro sum
+(defmacro- sum
   "Sums up all values of bindings obtained with expr. See doseq."
   [bindings expr]
   `(let [sum# (atom (double 0))]
      (doseq ~bindings
        (swap! sum# + (double ~expr)))
      (double @sum#)))
-
-(alter-meta! #'sum assoc :private true)
-
-(defn- unit-vector
-  "Returns unit vector between first and second point. Returns
-  [0.0 0.0] when given zero vector."
-  [[x_1 y_1] [x_2 y_2]]
-  (with-doubles [x_1 y_1 x_2 y_2]
-    (let [length (distance [x_1 y_1] [x_2 y_2])]
-      (if (zero? length)
-        [0.0 0.0]
-        [(/ (- x_2 x_1) length), (/ (- y_2 y_1) length)]))))

 ;; Repulsive Energy
@@ -103,7 +87,8 @@
   (let [node-positions (positions layout),
         node-connections (connections layout)]
     (sum [[x y] node-connections]
-         (line-length-squared (node-positions x) (node-positions y)))))
+         (line-length-squared (node-positions x)
+                              (node-positions y)))))

 ;; Gravitative Energy


Rename warn! -> throw-ambiguous

Rename warn! -> throw-ambiguous

--- src/grafter_2/rdf4j/sparql/path.clj
+++ src/grafter_2/rdf4j/sparql/path.clj
@@ -191,7 +191,7 @@
      (symbol path-ns (subs name c))
      (symbol path-ns (subs name 0 1))]))

-(defn- warn! [& bindings]
+(defn- throw-ambiguous [& bindings]
   (throw
    (ex-info (str "Ambiguous syntax, bindings in scope: " bindings)
             {:type ::ambiguous-syntax :bindings bindings})))
@@ -202,7 +202,7 @@
     (let [syms  (cons [sym] ((apply juxt split-fns) sym))
           bound (filter (comp binding? first) syms)
           c     (count bound)]
-      (cond (> c 1) (apply warn! (map first bound))
+      (cond (> c 1) (apply throw-ambiguous (map first bound))
             (= c 1) (apply-fix-fns (first bound))
             :else   (apply-fix-fns (last syms))))))


only give the hint to push on the committed projects

--- src/leiningen/leinsync/commands.clj
+++ src/leiningen/leinsync/commands.clj
@@ -26,14 +26,25 @@
         (t/log-test-hints))))

 (defn commit-all! [_ projects _]
-  (let [projects-str (str/join "," projects)
-        commit-msg (->> projects-str
+  (let [commit-msg (->> (str/join "," projects)
                         (str "\nPlease enter the commit message for the projects: ")
                         (u/ask-user))
-        projects-desc (pr/read-all-target-project-clj projects)]
-    (-> #(u/run-command-on (pr/->target-project-path %) git/commit-project! % commit-msg ((keyword %) projects-desc))
-        (map projects)
-        (git/log-git-status "\n*To push        : lein sync" projects-str "--push"))))
+        status (map #(u/run-command-on (pr/->target-project-path %)
+                                       git/commit-project!
+                                       %
+                                       commit-msg
+                                       ((keyword %)
+                                         (pr/read-all-target-project-clj projects)))
+                    projects)
+        committed-project (seq (map :project (filter #(= :committed (:status %)) status)))
+        not-committed-project (seq (map :project (filter #(not= :committed (:status %)) status)))]
+    (git/log-git-status status
+                        (if committed-project
+                          (str "\n*To push        : lein sync " (str/join "," committed-project) " --push")
+                          "")
+                        (if not-committed-project
+                          (str "\n*Could not commit on the projects: " (str/join "," not-committed-project))
+                          ""))))

 (defn status-all [_ projects _]
   (let [projects-desc (pr/read-all-target-project-clj projects)]


add project.clj to template files

add project.clj to template files

--- src/leiningen/new/lein_quick_om.clj
+++ src/leiningen/new/lein_quick_om.clj
@@ -11,4 +11,4 @@
               :sanitized (name-to-path name)}]
     (main/info "Generating fresh 'lein new' lein-quick-om project.")
     (->files data
-             ["src/{{sanitized}}/foo.clj" (render "foo.clj" data)])))
+             ["src/{{sanitized}}/project.clj" (render "project.clj" data)])))


CLJS-1317: Incremental compilation issues for :nodejs target

The issue was that the AOTed cljs.core is compiled with :target :default. This
triggered recompilation under :target :nodejs. Since core is recompiled all other
namespaces will be recompiled due to :recompile-dependents true.

Don't recompile because of differing build options if the namespace is cljs.core
and AOTed core exists.

--- src/main/clojure/cljs/compiler.cljc
+++ src/main/clojure/cljs/compiler.cljc
@@ -1142,23 +1142,25 @@
      "Return true if the src file requires compilation."
      ([src dest] (requires-compilation? src dest nil))
      ([^File src ^File dest opts]
-      (ensure
-        (or (not (.exists dest))
-            (> (.lastModified src) (.lastModified dest))
-            (let [version' (util/compiled-by-version dest)
-                  version (util/clojurescript-version)]
-              (and version (not= version version')))
-            (and opts (not= (build-affecting-options opts)
-                            (build-affecting-options (util/build-options dest))))
-            (and opts (:source-map opts)
-                 (if (= (:optimizations opts) :none)
-                   (not (.exists (io/file (str (.getPath dest) ".map"))))
-                   (not (get-in @env/*compiler* [::compiled-cljs (.getAbsolutePath dest)]))))
-          (let [{ns :ns} (ana/parse-ns src)
-                {:keys [recompile visited]}
-                (and *dependents* @*dependents*)]
-            (and (contains? recompile ns)
-                 (not (contains? visited ns)))))))))
+      (let [{:keys [ns]} (ana/parse-ns src)]
+        (ensure
+          (or (not (.exists dest))
+              (> (.lastModified src) (.lastModified dest))
+              (let [version' (util/compiled-by-version dest)
+                    version (util/clojurescript-version)]
+                (and version (not= version version')))
+              (and opts
+                   (not (and (io/resource "cljs/core.aot.js") (= 'cljs.core ns)))
+                   (not= (build-affecting-options opts)
+                         (build-affecting-options (util/build-options dest))))
+              (and opts (:source-map opts)
+                (if (= (:optimizations opts) :none)
+                  (not (.exists (io/file (str (.getPath dest) ".map"))))
+                  (not (get-in @env/*compiler* [::compiled-cljs (.getAbsolutePath dest)]))))
+              (let [{:keys [recompile visited]}
+                    (and *dependents* @*dependents*)]
+                (and (contains? recompile ns)
+                     (not (contains? visited ns))))))))))

 #?(:clj
    (defn compile-file


(TK-96) Break proxy tests into more `deftest`s

Debugging can be really hard when there are too many `testing` blocks
inside a single `deftest`.  This commit just breaks the proxy
tests into more `deftest`s.

--- test/clj/puppetlabs/trapperkeeper/services/webserver/jetty9_service_proxy_test.clj
+++ test/clj/puppetlabs/trapperkeeper/services/webserver/jetty9_service_proxy_test.clj
@@ -82,376 +82,430 @@
            (add-proxy-route proxy-webserver# ~proxy-config "/hello-proxy")))
        ~@body)))

-;; TODO: break this into more deftests
-(deftest test-proxy-servlet
-  (let [common-ssl-config       {:ssl-cert    "./dev-resources/config/jetty/ssl/certs/localhost.pem"
-                                 :ssl-key     "./dev-resources/config/jetty/ssl/private_keys/localhost.pem"
-                                 :ssl-ca-cert "./dev-resources/config/jetty/ssl/certs/ca.pem"}
-        rewrite-uri-callback-fn (fn [target-uri req]
-                                  (URI.
-                                    (.getScheme target-uri)
-                                    nil
-                                    (.getHost target-uri)
-                                    (.getPort target-uri)
-                                    "/hello/earth"
-                                    nil nil))
-        callback-fn             (fn [proxy-req req]
-                                  (.header proxy-req "x-fancy-proxy-header" "!!!"))
-        failure-callback-fn     (fn [req resp proxy-resp failure]
-                                  (.setStatus resp 500)
-                                  (.print (.getWriter resp) (str "Proxying failed: " (.getMessage failure))))]
-    (testing "basic proxy support"
-      (with-target-and-proxy-servers
-        {:target       {:host "0.0.0.0"
-                        :port 9000}
-         :proxy        {:host "0.0.0.0"
-                        :port 10000}
-         :proxy-config {:host "localhost"
-                        :port 9000
-                        :path "/hello"}
-         :ring-handler proxy-ring-handler}
-        (let [response (http-get "http://localhost:9000/hello/world")]
-          (is (= (:status response) 200))
-          (is (= (:body response) "Hello, World!")))
-        (let [response (http-get "http://localhost:10000/hello-proxy/world")]
-          (is (= (:status response) 200))
-          (is (= (:body response) "Hello, World!")))))
-
-    (testing "basic proxy support with add-proxy-route-to"
-      (with-target-and-proxy-servers
-        {:target       {:host "0.0.0.0"
-                        :port 9000}
-         :proxy        {:foo            {:host "0.0.0.0"
-                                         :port 10000}
-                        :bar            {:host           "0.0.0.0"
-                                         :port           8085
-                                         :default-server true}}
-         :proxy-config {:host "localhost"
-                        :port 9000
-                        :path "/hello"}
-         :proxy-opts   {:server-id :foo}
-         :ring-handler proxy-ring-handler}
-        (let [response (http-get "http://localhost:9000/hello/world")]
-          (is (= (:status response) 200))
-          (is (= (:body response) "Hello, World!")))
-        (let [response (http-get "http://localhost:10000/hello-proxy/world")]
-          (is (= (:status response) 200))
-          (is (= (:body response) "Hello, World!")))))
-
-    (testing "proxy does not explode on a large cookie when properly configured"
-      (with-target-and-proxy-servers
-        {:target       {:host "0.0.0.0"
-                        :port 9000
-                        :request-header-max-size 16192}
-         :proxy        {:host "0.0.0.0"
-                        :port 10000
-                        :request-header-max-size 16192}
-         :proxy-config {:host "localhost"
-                        :port 9000
-                        :path "/hello"}
-         :proxy-opts   {:request-buffer-size 16192}
-         :ring-handler proxy-ring-handler}
-        (let [response (http-get "http://localhost:9000/hello/world")]
-          (is (= (:status response) 200))
-          (is (= (:body response) "Hello, World!")))
-        (let [response (http-get "http://localhost:10000/hello-proxy/world"
-                                 {:headers {"Cookie" absurdly-large-cookie}
-                                  :as      :text})]
-          (is (= (:status response) 200))
-          (is (= (:body response) (str "Hello, World!" absurdly-large-cookie))))))
-
-    (testing "basic proxy support with explicit :orig scheme"
-      (with-target-and-proxy-servers
-        {:target       {:host "0.0.0.0"
-                        :port 9000}
-         :proxy        {:host "0.0.0.0"
-                        :port 10000}
-         :proxy-config {:host "localhost"
-                        :port 9000
-                        :path "/hello"}
-         :proxy-opts   {:scheme :orig}
-         :ring-handler proxy-ring-handler}
-        (let [response (http-get "http://localhost:9000/hello/world")]
-          (is (= (:status response) 200))
-          (is (= (:body response) "Hello, World!")))
-        (let [response (http-get "http://localhost:10000/hello-proxy/world")]
-          (is (= (:status response) 200))
-          (is (= (:body response) "Hello, World!")))))
-
-    (testing "basic proxy support with explicit \"orig\" scheme as string"
-      (with-target-and-proxy-servers
-        {:target       {:host "0.0.0.0"
-                        :port 9000}
-         :proxy        {:host "0.0.0.0"
-                        :port 10000}
-         :proxy-config {:host "localhost"
-                        :port 9000
-                        :path "/hello"}
-         :proxy-opts   {:scheme "orig"}
-         :ring-handler proxy-ring-handler}
-        (let [response (http-get "http://localhost:9000/hello/world")]
-          (is (= (:status response) 200))
-          (is (= (:body response) "Hello, World!")))
-        (let [response (http-get "http://localhost:10000/hello-proxy/world")]
-          (is (= (:status response) 200))
-          (is (= (:body response) "Hello, World!")))))
-
-    (testing "basic https proxy support (pass-through https config)"
-      (with-target-and-proxy-servers
-        {:target       (merge common-ssl-config
-                              {:ssl-host "0.0.0.0"
-                               :ssl-port 9001})
-         :proxy        (merge common-ssl-config
-                              {:ssl-host "0.0.0.0"
-                               :ssl-port 10001})
-         :proxy-config {:host "localhost"
-                        :port 9001
-                        :path "/hello"}
-         :ring-handler proxy-ring-handler}
-        (let [response (http-get "https://localhost:9001/hello/world" default-options-for-https-client)]
-          (is (= (:status response) 200))
-          (is (= (:body response) "Hello, World!")))
-        (let [response (http-get "https://localhost:10001/hello-proxy/world" default-options-for-https-client)]
-          (is (= (:status response) 200))
-          (is (= (:body response) "Hello, World!")))))
-
-    (testing "basic https proxy support (pass-through https config) with explicit :orig scheme"
-      (with-target-and-proxy-servers
-        {:target       (merge common-ssl-config
-                              {:ssl-host    "0.0.0.0"
-                               :ssl-port    9001})
-         :proxy        (merge common-ssl-config
-                              {:ssl-host    "0.0.0.0"
-                               :ssl-port    10001})
-         :proxy-config {:host "localhost"
-                        :port 9001
-                        :path "/hello"}
-         :proxy-opts   {:scheme :orig}
-         :ring-handler proxy-ring-handler}
-        (let [response (http-get "https://localhost:9001/hello/world" default-options-for-https-client)]
-          (is (= (:status response) 200))
-          (is (= (:body response) "Hello, World!")))
-        (let [response (http-get "https://localhost:10001/hello-proxy/world" default-options-for-https-client)]
-          (is (= (:status response) 200))
-          (is (= (:body response) "Hello, World!")))))
-
-    (testing "basic https proxy support (pass-through https config via explicit :use-server-config)"
-      (with-target-and-proxy-servers
-        {:target       (merge common-ssl-config
-                              {:ssl-host    "0.0.0.0"
-                               :ssl-port    9001})
-         :proxy        (merge common-ssl-config
-                              {:ssl-host    "0.0.0.0"
-                               :ssl-port    10001})
-         :proxy-config {:host "localhost"
-                        :port 9001
-                        :path "/hello"}
-         :proxy-opts   {:ssl-config :use-server-config}
-         :ring-handler proxy-ring-handler}
-        (let [response (http-get "https://localhost:9001/hello/world" default-options-for-https-client)]
-          (is (= (:status response) 200))
-          (is (= (:body response) "Hello, World!")))
-        (let [response (http-get "https://localhost:10001/hello-proxy/world" default-options-for-https-client)]
-          (is (= (:status response) 200))
-          (is (= (:body response) "Hello, World!")))))
-
-    (testing "http->https proxy support with explicit ssl config for proxy"
-      (with-target-and-proxy-servers
-        {:target       (merge common-ssl-config
-                              {:ssl-host    "0.0.0.0"
-                               :ssl-port    9000})
-         :proxy        {:host "0.0.0.0"
-                        :port 10000}
-         :proxy-config {:host "localhost"
-                        :port 9000
-                        :path "/hello"}
-         :proxy-opts   {:scheme     :https
-                        :ssl-config common-ssl-config}
-         :ring-handler proxy-ring-handler}
-        (let [response (http-get "https://localhost:9000/hello/world" default-options-for-https-client)]
-          (is (= (:status response) 200))
-          (is (= (:body response) "Hello, World!")))
-        (let [response (http-get "http://localhost:10000/hello-proxy/world")]
-          (is (= (:status response) 200))
-          (is (= (:body response) "Hello, World!")))))
-
-    (testing "http->https proxy support with scheme as string value"
-      (with-target-and-proxy-servers
-        {:target       (merge common-ssl-config
-                              {:ssl-host    "0.0.0.0"
-                               :ssl-port    9000})
-         :proxy        {:host "0.0.0.0"
-                        :port 10000}
-         :proxy-config {:host "localhost"
-                        :port 9000
-                        :path "/hello"}
-         :proxy-opts   {:scheme     "https"
-                        :ssl-config common-ssl-config}
-         :ring-handler proxy-ring-handler}
-        (let [response (http-get "https://localhost:9000/hello/world" default-options-for-https-client)]
-          (is (= (:status response) 200))
-          (is (= (:body response) "Hello, World!")))
-        (let [response (http-get "http://localhost:10000/hello-proxy/world")]
-          (is (= (:status response) 200))
-          (is (= (:body response) "Hello, World!")))))
-
-    (testing "https->http proxy support"
-      (with-target-and-proxy-servers
-        {:target       {:host "0.0.0.0"
-                        :port 9001}
-         :proxy        (merge common-ssl-config
-                              {:ssl-host    "0.0.0.0"
-                               :ssl-port    10001})
-         :proxy-config {:host "localhost"
-                        :port 9001
-                        :path "/hello"}
-         :proxy-opts   {:scheme :http}
-         :ring-handler proxy-ring-handler}
-        (let [response (http-get "http://localhost:9001/hello/world")]
-          (is (= (:status response) 200))
-          (is (= (:body response) "Hello, World!")))
-        (let [response (http-get "https://localhost:10001/hello-proxy/world" default-options-for-https-client)]
-          (is (= (:status response) 200))
-          (is (= (:body response) "Hello, World!")))))
-
-    (testing "https->http proxy support with scheme as string"
-      (with-target-and-proxy-servers
-        {:target       {:host "0.0.0.0"
-                        :port 9001}
-         :proxy        (merge common-ssl-config
-                              {:ssl-host    "0.0.0.0"
-                               :ssl-port    10001})
-         :proxy-config {:host "localhost"
-                        :port 9001
-                        :path "/hello"}
-         :proxy-opts   {:scheme "http"}
-         :ring-handler proxy-ring-handler}
-        (let [response (http-get "http://localhost:9001/hello/world")]
-          (is (= (:status response) 200))
-          (is (= (:body response) "Hello, World!")))
-        (let [response (http-get "https://localhost:10001/hello-proxy/world" default-options-for-https-client)]
-          (is (= (:status response) 200))
-          (is (= (:body response) "Hello, World!")))))
-
-    (testing "basic http proxy support with callback function"
-      (with-target-and-proxy-servers
-        {:target       {:host "0.0.0.0"
-                        :port 9000}
-         :proxy        {:host "0.0.0.0"
-                        :port 10000}
-         :proxy-config {:host "localhost"
-                        :port 9000
-                        :path "/hello"}
-         :proxy-opts   {:callback-fn  callback-fn}
-         :ring-handler proxy-ring-handler}
-        (let [response (http-get "http://localhost:9000/hello/world")]
-          (is (= (:status response) 200))
-          (is (= (:body response) "Hello, World!")))
-        (let [response (http-get "http://localhost:10000/hello-proxy/world")]
-          (is (= (:status response) 200))
-          (is (= (:body response) "Hello, World!!!!")))))
-
-    (testing "basic https proxy support (pass-through https config) with callback function"
-      (with-target-and-proxy-servers
-        {:target       (merge common-ssl-config
-                              {:ssl-host "0.0.0.0"
-                               :ssl-port 9001})
-         :proxy        (merge common-ssl-config
-                              {:ssl-host "0.0.0.0"
-                               :ssl-port 10001})
-         :proxy-config {:host "localhost"
-                        :port 9001
-                        :path "/hello"}
-         :proxy-opts   {:callback-fn  callback-fn}
-         :ring-handler proxy-ring-handler}
-        (let [response (http-get "https://localhost:9001/hello/world" default-options-for-https-client)]
-          (is (= (:status response) 200))
-          (is (= (:body response) "Hello, World!")))
-        (let [response (http-get "https://localhost:10001/hello-proxy/world" default-options-for-https-client)]
-          (is (= (:status response) 200))
-          (is (= (:body response) "Hello, World!!!!")))))
-
-    (testing "http->https proxy support with explicit ssl config and callback function for proxy"
-      (with-target-and-proxy-servers
-        {:target       (merge common-ssl-config
-                              {:ssl-host    "0.0.0.0"
-                               :ssl-port    9000})
-         :proxy        {:host "0.0.0.0"
-                        :port 10000}
-         :proxy-config {:host "localhost"
-                        :port 9000
-                        :path "/hello"}
-         :proxy-opts   {:scheme       :https
-                        :ssl-config   common-ssl-config
-                        :callback-fn  callback-fn}
-         :ring-handler proxy-ring-handler}
-        (let [response (http-get "https://localhost:9000/hello/world" default-options-for-https-client)]
-          (is (= (:status response) 200))
-          (is (= (:body response) "Hello, World!")))
-        (let [response (http-get "http://localhost:10000/hello-proxy/world")]
-          (is (= (:status response) 200))
-          (is (= (:body response) "Hello, World!!!!")))))
-
-    (testing "basic http proxy support with rewrite uri callback function"
-      (with-target-and-proxy-servers
-        {:target       {:host "0.0.0.0"
-                        :port 9000}
-         :proxy        {:host "0.0.0.0"
-                        :port 10000}
-         :proxy-config {:host "localhost"
-                        :port 9000
-                        :path "/hello"}
-         :proxy-opts   {:rewrite-uri-callback-fn rewrite-uri-callback-fn}
-         :ring-handler proxy-ring-handler}
-        (let [response (http-get "http://localhost:9000/hello/world")]
-          (is (= (:status response) 200))
-          (is (= (:body response) "Hello, World!")))
-        (let [response (http-get "http://localhost:10000/hello-proxy/world")]
-          (is (= (:status response) 200))
-          (is (= (:body response) "Hello, Earth!")))))
-
-    (testing "basic https proxy support (pass-through https config) with rewrite uri callback function"
-      (with-target-and-proxy-servers
-        {:target       (merge common-ssl-config
-                              {:ssl-host "0.0.0.0"
-                               :ssl-port 9001})
-         :proxy        (merge common-ssl-config
-                              {:ssl-host "0.0.0.0"
-                               :ssl-port 10001})
-         :proxy-config {:host "localhost"
-                        :port 9001
-                        :path "/hello"}
-         :proxy-opts   {:rewrite-uri-callback-fn rewrite-uri-callback-fn}
-         :ring-handler proxy-ring-handler}
-        (let [response (http-get "https://localhost:9001/hello/world" default-options-for-https-client)]
-          (is (= (:status response) 200))
-          (is (= (:body response) "Hello, World!")))
-        (let [response (http-get "https://localhost:10001/hello-proxy/world" default-options-for-https-client)]
-          (is (= (:status response) 200))
-          (is (= (:body response) "Hello, Earth!")))))
-
-    (testing "http->https proxy support with explicit ssl config and rewrite uri callback function for proxy"
-      (with-target-and-proxy-servers
-        {:target       (merge common-ssl-config
-                              {:ssl-host    "0.0.0.0"
-                               :ssl-port    9000})
-         :proxy        {:host "0.0.0.0"
-                        :port 10000}
-         :proxy-config {:host "localhost"
-                        :port 9000
-                        :path "/hello"}
-         :proxy-opts   {:scheme                   :https
-                        :ssl-config               common-ssl-config
-                        :rewrite-uri-callback-fn  rewrite-uri-callback-fn}
-         :ring-handler proxy-ring-handler}
-        (let [response (http-get "https://localhost:9000/hello/world" default-options-for-https-client)]
-          (is (= (:status response) 200))
-          (is (= (:body response) "Hello, World!")))
-        (let [response (http-get "http://localhost:10000/hello-proxy/world")]
-          (is (= (:status response) 200))
-          (is (= (:body response) "Hello, Earth!")))))
-
-    (testing "basic proxy support with query parameters"
+(def common-ssl-config
+  {:ssl-cert    "./dev-resources/config/jetty/ssl/certs/localhost.pem"
+   :ssl-key     "./dev-resources/config/jetty/ssl/private_keys/localhost.pem"
+   :ssl-ca-cert "./dev-resources/config/jetty/ssl/certs/ca.pem"})
+
+(defn rewrite-uri-callback-fn
+  [target-uri req]
+  (URI.
+    (.getScheme target-uri)
+    nil
+    (.getHost target-uri)
+    (.getPort target-uri)
+    "/hello/earth"
+    nil nil))
+
+(defn callback-fn
+  [proxy-req req]
+  (.header proxy-req "x-fancy-proxy-header" "!!!"))
+
+(defn failure-callback-fn
+  [req resp proxy-resp failure]
+  (.setStatus resp 500)
+  (.print (.getWriter resp) (str "Proxying failed: " (.getMessage failure))))
+
+(deftest test-basic-proxy-support
+  (testing "basic proxy support"
+    (with-target-and-proxy-servers
+      {:target       {:host "0.0.0.0"
+                      :port 9000}
+       :proxy        {:host "0.0.0.0"
+                      :port 10000}
+       :proxy-config {:host "localhost"
+                      :port 9000
+                      :path "/hello"}
+       :ring-handler proxy-ring-handler}
+      (let [response (http-get "http://localhost:9000/hello/world")]
+        (is (= (:status response) 200))
+        (is (= (:body response) "Hello, World!")))
+      (let [response (http-get "http://localhost:10000/hello-proxy/world")]
+        (is (= (:status response) 200))
+        (is (= (:body response) "Hello, World!")))))
+
+  (testing "basic proxy support with add-proxy-route-to"
+    (with-target-and-proxy-servers
+      {:target       {:host "0.0.0.0"
+                      :port 9000}
+       :proxy        {:foo {:host "0.0.0.0"
+                            :port 10000}
+                      :bar {:host           "0.0.0.0"
+                            :port           8085
+                            :default-server true}}
+       :proxy-config {:host "localhost"
+                      :port 9000
+                      :path "/hello"}
+       :proxy-opts   {:server-id :foo}
+       :ring-handler proxy-ring-handler}
+      (let [response (http-get "http://localhost:9000/hello/world")]
+        (is (= (:status response) 200))
+        (is (= (:body response) "Hello, World!")))
+      (let [response (http-get "http://localhost:10000/hello-proxy/world")]
+        (is (= (:status response) 200))
+        (is (= (:body response) "Hello, World!"))))))
+
+(deftest proxy-large-cookie
+  (testing "proxy does not explode on a large cookie when properly configured"
+    (with-target-and-proxy-servers
+      {:target       {:host                    "0.0.0.0"
+                      :port                    9000
+                      :request-header-max-size 16192}
+       :proxy        {:host                    "0.0.0.0"
+                      :port                    10000
+                      :request-header-max-size 16192}
+       :proxy-config {:host "localhost"
+                      :port 9000
+                      :path "/hello"}
+       :proxy-opts   {:request-buffer-size 16192}
+       :ring-handler proxy-ring-handler}
+      (let [response (http-get "http://localhost:9000/hello/world")]
+        (is (= (:status response) 200))
+        (is (= (:body response) "Hello, World!")))
+      (let [response (http-get "http://localhost:10000/hello-proxy/world"
+                               {:headers {"Cookie" absurdly-large-cookie}
+                                :as      :text})]
+        (is (= (:status response) 200))
+        (is (= (:body response) (str "Hello, World!" absurdly-large-cookie)))))))
+
+(deftest proxy-with-orig-scheme
+  (testing "basic proxy support with explicit :orig scheme"
+    (with-target-and-proxy-servers
+      {:target       {:host "0.0.0.0"
+                      :port 9000}
+       :proxy        {:host "0.0.0.0"
+                      :port 10000}
+       :proxy-config {:host "localhost"
+                      :port 9000
+                      :path "/hello"}
+       :proxy-opts   {:scheme :orig}
+       :ring-handler proxy-ring-handler}
+      (let [response (http-get "http://localhost:9000/hello/world")]
+        (is (= (:status response) 200))
+        (is (= (:body response) "Hello, World!")))
+      (let [response (http-get "http://localhost:10000/hello-proxy/world")]
+        (is (= (:status response) 200))
+        (is (= (:body response) "Hello, World!")))))
+
+  (testing "basic proxy support with explicit \"orig\" scheme as string"
+    (with-target-and-proxy-servers
+      {:target       {:host "0.0.0.0"
+                      :port 9000}
+       :proxy        {:host "0.0.0.0"
+                      :port 10000}
+       :proxy-config {:host "localhost"
+                      :port 9000
+                      :path "/hello"}
+       :proxy-opts   {:scheme "orig"}
+       :ring-handler proxy-ring-handler}
+      (let [response (http-get "http://localhost:9000/hello/world")]
+        (is (= (:status response) 200))
+        (is (= (:body response) "Hello, World!")))
+      (let [response (http-get "http://localhost:10000/hello-proxy/world")]
+        (is (= (:status response) 200))
+        (is (= (:body response) "Hello, World!"))))))
+
+(deftest basic-https-proxy
+  (testing "basic https proxy support (pass-through https config)"
+    (with-target-and-proxy-servers
+      {:target       (merge common-ssl-config
+                            {:ssl-host "0.0.0.0"
+                             :ssl-port 9001})
+       :proxy        (merge common-ssl-config
+                            {:ssl-host "0.0.0.0"
+                             :ssl-port 10001})
+       :proxy-config {:host "localhost"
+                      :port 9001
+                      :path "/hello"}
+       :ring-handler proxy-ring-handler}
+      (let [response (http-get "https://localhost:9001/hello/world" default-options-for-https-client)]
+        (is (= (:status response) 200))
+        (is (= (:body response) "Hello, World!")))
+      (let [response (http-get "https://localhost:10001/hello-proxy/world" default-options-for-https-client)]
+        (is (= (:status response) 200))
+        (is (= (:body response) "Hello, World!")))))
+
+  (testing "basic https proxy support (pass-through https config) with explicit :orig scheme"
+    (with-target-and-proxy-servers
+      {:target       (merge common-ssl-config
+                            {:ssl-host "0.0.0.0"
+                             :ssl-port 9001})
+       :proxy        (merge common-ssl-config
+                            {:ssl-host "0.0.0.0"
+                             :ssl-port 10001})
+       :proxy-config {:host "localhost"
+                      :port 9001
+                      :path "/hello"}
+       :proxy-opts   {:scheme :orig}
+       :ring-handler proxy-ring-handler}
+      (let [response (http-get "https://localhost:9001/hello/world" default-options-for-https-client)]
+        (is (= (:status response) 200))
+        (is (= (:body response) "Hello, World!")))
+      (let [response (http-get "https://localhost:10001/hello-proxy/world" default-options-for-https-client)]
+        (is (= (:status response) 200))
+        (is (= (:body response) "Hello, World!")))))
+
+  (testing "basic https proxy support (pass-through https config via explicit :use-server-config)"
+    (with-target-and-proxy-servers
+      {:target       (merge common-ssl-config
+                            {:ssl-host "0.0.0.0"
+                             :ssl-port 9001})
+       :proxy        (merge common-ssl-config
+                            {:ssl-host "0.0.0.0"
+                             :ssl-port 10001})
+       :proxy-config {:host "localhost"
+                      :port 9001
+                      :path "/hello"}
+       :proxy-opts   {:ssl-config :use-server-config}
+       :ring-handler proxy-ring-handler}
+      (let [response (http-get "https://localhost:9001/hello/world" default-options-for-https-client)]
+        (is (= (:status response) 200))
+        (is (= (:body response) "Hello, World!")))
+      (let [response (http-get "https://localhost:10001/hello-proxy/world" default-options-for-https-client)]
+        (is (= (:status response) 200))
+        (is (= (:body response) "Hello, World!"))))))
+
+(deftest http-https-proxy-support
+  (testing "http->https proxy support with explicit ssl config for proxy"
+    (with-target-and-proxy-servers
+      {:target       (merge common-ssl-config
+                            {:ssl-host "0.0.0.0"
+                             :ssl-port 9000})
+       :proxy        {:host "0.0.0.0"
+                      :port 10000}
+       :proxy-config {:host "localhost"
+                      :port 9000
+                      :path "/hello"}
+       :proxy-opts   {:scheme     :https
+                      :ssl-config common-ssl-config}
+       :ring-handler proxy-ring-handler}
+      (let [response (http-get "https://localhost:9000/hello/world" default-options-for-https-client)]
+        (is (= (:status response) 200))
+        (is (= (:body response) "Hello, World!")))
+      (let [response (http-get "http://localhost:10000/hello-proxy/world")]
+        (is (= (:status response) 200))
+        (is (= (:body response) "Hello, World!")))))
+
+  (testing "http->https proxy support with scheme as string value"
+    (with-target-and-proxy-servers
+      {:target       (merge common-ssl-config
+                            {:ssl-host "0.0.0.0"
+                             :ssl-port 9000})
+       :proxy        {:host "0.0.0.0"
+                      :port 10000}
+       :proxy-config {:host "localhost"
+                      :port 9000
+                      :path "/hello"}
+       :proxy-opts   {:scheme     "https"
+                      :ssl-config common-ssl-config}
+       :ring-handler proxy-ring-handler}
+      (let [response (http-get "https://localhost:9000/hello/world" default-options-for-https-client)]
+        (is (= (:status response) 200))
+        (is (= (:body response) "Hello, World!")))
+      (let [response (http-get "http://localhost:10000/hello-proxy/world")]
+        (is (= (:status response) 200))
+        (is (= (:body response) "Hello, World!"))))))
+
+(deftest https-http-proxy-support
+
+  (testing "https->http proxy support"
+    (with-target-and-proxy-servers
+      {:target       {:host "0.0.0.0"
+                      :port 9001}
+       :proxy        (merge common-ssl-config
+                            {:ssl-host "0.0.0.0"
+                             :ssl-port 10001})
+       :proxy-config {:host "localhost"
+                      :port 9001
+                      :path "/hello"}
+       :proxy-opts   {:scheme :http}
+       :ring-handler proxy-ring-handler}
+      (let [response (http-get "http://localhost:9001/hello/world")]
+        (is (= (:status response) 200))
+        (is (= (:body response) "Hello, World!")))
+      (let [response (http-get "https://localhost:10001/hello-proxy/world" default-options-for-https-client)]
+        (is (= (:status response) 200))
+        (is (= (:body response) "Hello, World!")))))
+
+  (testing "https->http proxy support with scheme as string"
+    (with-target-and-proxy-servers
+      {:target       {:host "0.0.0.0"
+                      :port 9001}
+       :proxy        (merge common-ssl-config
+                            {:ssl-host "0.0.0.0"
+                             :ssl-port 10001})
+       :proxy-config {:host "localhost"
+                      :port 9001
+                      :path "/hello"}
+       :proxy-opts   {:scheme "http"}
+       :ring-handler proxy-ring-handler}
+      (let [response (http-get "http://localhost:9001/hello/world")]
+        (is (= (:status response) 200))
+        (is (= (:body response) "Hello, World!")))
+      (let [response (http-get "https://localhost:10001/hello-proxy/world" default-options-for-https-client)]
+        (is (= (:status response) 200))
+        (is (= (:body response) "Hello, World!"))))))
+
+(deftest proxy-support-with-callback
+  (testing "basic http proxy support with callback function"
+    (with-target-and-proxy-servers
+      {:target       {:host "0.0.0.0"
+                      :port 9000}
+       :proxy        {:host "0.0.0.0"
+                      :port 10000}
+       :proxy-config {:host "localhost"
+                      :port 9000
+                      :path "/hello"}
+       :proxy-opts   {:callback-fn callback-fn}
+       :ring-handler proxy-ring-handler}
+      (let [response (http-get "http://localhost:9000/hello/world")]
+        (is (= (:status response) 200))
+        (is (= (:body response) "Hello, World!")))
+      (let [response (http-get "http://localhost:10000/hello-proxy/world")]
+        (is (= (:status response) 200))
+        (is (= (:body response) "Hello, World!!!!")))))
+
+  (testing "basic https proxy support (pass-through https config) with callback function"
+    (with-target-and-proxy-servers
+      {:target       (merge common-ssl-config
+                            {:ssl-host "0.0.0.0"
+                             :ssl-port 9001})
+       :proxy        (merge common-ssl-config
+                            {:ssl-host "0.0.0.0"
+                             :ssl-port 10001})
+       :proxy-config {:host "localhost"
+                      :port 9001
+                      :path "/hello"}
+       :proxy-opts   {:callback-fn callback-fn}
+       :ring-handler proxy-ring-handler}
+      (let [response (http-get "https://localhost:9001/hello/world" default-options-for-https-client)]
+        (is (= (:status response) 200))
+        (is (= (:body response) "Hello, World!")))
+      (let [response (http-get "https://localhost:10001/hello-proxy/world" default-options-for-https-client)]
+        (is (= (:status response) 200))
+        (is (= (:body response) "Hello, World!!!!")))))
+
+  (testing "http->https proxy support with explicit ssl config and callback function for proxy"
+    (with-target-and-proxy-servers
+      {:target       (merge common-ssl-config
+                            {:ssl-host "0.0.0.0"
+                             :ssl-port 9000})
+       :proxy        {:host "0.0.0.0"
+                      :port 10000}
+       :proxy-config {:host "localhost"
+                      :port 9000
+                      :path "/hello"}
+       :proxy-opts   {:scheme      :https
+                      :ssl-config  common-ssl-config
+                      :callback-fn callback-fn}
+       :ring-handler proxy-ring-handler}
+      (let [response (http-get "https://localhost:9000/hello/world" default-options-for-https-client)]
+        (is (= (:status response) 200))
+        (is (= (:body response) "Hello, World!")))
+      (let [response (http-get "http://localhost:10000/hello-proxy/world")]
+        (is (= (:status response) 200))
+        (is (= (:body response) "Hello, World!!!!"))))))
+
+(deftest proxy-with-rewrite-uri-callback
+  (testing "basic http proxy support with rewrite uri callback function"
+    (with-target-and-proxy-servers
+      {:target       {:host "0.0.0.0"
+                      :port 9000}
+       :proxy        {:host "0.0.0.0"
+                      :port 10000}
+       :proxy-config {:host "localhost"
+                      :port 9000
+                      :path "/hello"}
+       :proxy-opts   {:rewrite-uri-callback-fn rewrite-uri-callback-fn}
+       :ring-handler proxy-ring-handler}
+      (let [response (http-get "http://localhost:9000/hello/world")]
+        (is (= (:status response) 200))
+        (is (= (:body response) "Hello, World!")))
+      (let [response (http-get "http://localhost:10000/hello-proxy/world")]
+        (is (= (:status response) 200))
+        (is (= (:body response) "Hello, Earth!")))))
+
+  (testing "basic https proxy support (pass-through https config) with rewrite uri callback function"
+    (with-target-and-proxy-servers
+      {:target       (merge common-ssl-config
+                            {:ssl-host "0.0.0.0"
+                             :ssl-port 9001})
+       :proxy        (merge common-ssl-config
+                            {:ssl-host "0.0.0.0"
+                             :ssl-port 10001})
+       :proxy-config {:host "localhost"
+                      :port 9001
+                      :path "/hello"}
+       :proxy-opts   {:rewrite-uri-callback-fn rewrite-uri-callback-fn}
+       :ring-handler proxy-ring-handler}
+      (let [response (http-get "https://localhost:9001/hello/world" default-options-for-https-client)]
+        (is (= (:status response) 200))
+        (is (= (:body response) "Hello, World!")))
+      (let [response (http-get "https://localhost:10001/hello-proxy/world" default-options-for-https-client)]
+        (is (= (:status response) 200))
+        (is (= (:body response) "Hello, Earth!")))))
+
+  (testing "http->https proxy support with explicit ssl config and rewrite uri callback function for proxy"
+    (with-target-and-proxy-servers
+      {:target       (merge common-ssl-config
+                            {:ssl-host "0.0.0.0"
+                             :ssl-port 9000})
+       :proxy        {:host "0.0.0.0"
+                      :port 10000}
+       :proxy-config {:host "localhost"
+                      :port 9000
+                      :path "/hello"}
+       :proxy-opts   {:scheme                  :https
+                      :ssl-config              common-ssl-config
+                      :rewrite-uri-callback-fn rewrite-uri-callback-fn}
+       :ring-handler proxy-ring-handler}
+      (let [response (http-get "https://localhost:9000/hello/world" default-options-for-https-client)]
+        (is (= (:status response) 200))
+        (is (= (:body response) "Hello, World!")))
+      (let [response (http-get "http://localhost:10000/hello-proxy/world")]
+        (is (= (:status response) 200))
+        (is (= (:body response) "Hello, Earth!"))))))
+
+(deftest proxy-with-query-params
+  (testing "basic proxy support with query parameters"
+    (with-target-and-proxy-servers
+      {:target       {:host "0.0.0.0"
+                      :port 9000}
+       :proxy        {:host "0.0.0.0"
+                      :port 10000}
+       :proxy-config {:host "localhost"
+                      :port 9000
+                      :path "/hello"}
+       :ring-handler app-wrapped}
+      (let [response (http-get "http://localhost:9000/hello?foo=bar")]
+        (is (= (:status response) 200))
+        (is (= (:body response) (str {"foo" "bar"}))))
+      (let [response (http-get "http://localhost:10000/hello-proxy?foo=bar")]
+        (is (= (:status response) 200))
+        (is (= (:body response) (str {"foo" "bar"}))))))
+
+  (testing "basic proxy support with url encodable query parameters"
+    (with-target-and-proxy-servers
+      {:target       {:host "0.0.0.0"
+                      :port 9000}
+       :proxy        {:host "0.0.0.0"
+                      :port 10000}
+       :proxy-config {:host "localhost"
+                      :port 9000
+                      :path "/hello"}
+       :ring-handler app-wrapped}
+      (let [response (http-get "http://localhost:9000/hello?hello%5B%5D=hello%20world")]
+        (is (= (:status response) 200))
+        (is (= (:body response) (str {"hello[]" "hello world"}))))
+      (let [response (http-get "http://localhost:10000/hello-proxy?hello%5B%5D=hello%20world")]
+        (is (= (:status response) 200))
+        (is (= (:body response) (str {"hello[]" "hello world"}))))))
+
+  (testing "basic proxy support with multiple query parameters"
+    (let [params {"foo"   "bar"
+                  "baz"   "lux"
+                  "hello" "world"}
+          query "?foo=bar&baz=lux&hello=world"]
       (with-target-and-proxy-servers
         {:target       {:host "0.0.0.0"
                         :port 9000}
@@ -461,169 +515,133 @@
                         :port 9000
                         :path "/hello"}
          :ring-handler app-wrapped}
-        (let [response (http-get "http://localhost:9000/hello?foo=bar")]
+        (let [response (http-get (str "http://localhost:9000/hello" query))]
           (is (= (:status response) 200))
-          (is (= (:body response) (str {"foo" "bar"}))))
-        (let [response (http-get "http://localhost:10000/hello-proxy?foo=bar")]
+          (is (= (read-string (:body response)) params)))
+        (let [response (http-get (str "http://localhost:10000/hello-proxy" query))]
           (is (= (:status response) 200))
-          (is (= (:body response) (str {"foo" "bar"}))))))
-
-    (testing "basic proxy support with url encodable query parameters"
-      (with-target-and-proxy-servers
-        {:target       {:host "0.0.0.0"
-                        :port 9000}
-         :proxy        {:host "0.0.0.0"
-                        :port 10000}
-         :proxy-config {:host "localhost"
-                        :port 9000
-                        :path "/hello"}
-         :ring-handler app-wrapped}
-        (let [response (http-get "http://localhost:9000/hello?hello%5B%5D=hello%20world")]
-          (is (= (:status response) 200))
-          (is (= (:body response) (str {"hello[]" "hello world"}))))
-        (let [response (http-get "http://localhost:10000/hello-proxy?hello%5B%5D=hello%20world")]
-          (is (= (:status response) 200))
-          (is (= (:body response) (str {"hello[]" "hello world"}))))))
-
-    (testing "basic proxy support with multiple query parameters"
-      (let [params {"foo"   "bar"
-                    "baz"   "lux"
-                    "hello" "world"}
-            query "?foo=bar&baz=lux&hello=world"]
-        (with-target-and-proxy-servers
-          {:target       {:host "0.0.0.0"
-                          :port 9000}
-           :proxy        {:host "0.0.0.0"
-                          :port 10000}
-           :proxy-config {:host "localhost"
-                          :port 9000
-                          :path "/hello"}
-           :ring-handler app-wrapped}
-          (let [response (http-get (str "http://localhost:9000/hello" query))]
-            (is (= (:status response) 200))
-            (is (= (read-string (:body response)) params)))
-          (let [response (http-get (str "http://localhost:10000/hello-proxy" query))]
-            (is (= (:status response) 200))
-            (is (= (read-string (:body response)) params))))))
-
-    (testing "redirect test with proxy"
-      (with-target-and-proxy-servers
-        {:target       {:host "0.0.0.0"
-                        :port 9000}
-         :proxy        {:host "0.0.0.0"
-                        :port 10000}
-         :proxy-config {:host "localhost"
-                        :port 9000
-                        :path "/hello"}
-         :proxy-opts   {:follow-redirects true}
-         :ring-handler redirect-test-handler}
-        (let [response (http-get (str "http://localhost:9000/hello/"))]
-          (is (= (:status response) 200))
-          (is (= (:body response) "Hello, World!")))
-        (let [response (http-get (str "http://localhost:9000/hello/world"))]
-          (is (= (:status response) 200))
-          (is (= (:body response) "Hello, World!")))
-        (let [response (http-get (str "http://localhost:10000/hello-proxy"))]
-          (is (= (:status response) 200))
-          (is (= (:body response) "Hello, World!")))
-        (let [response (http-get (str "http://localhost:10000/hello-proxy/world"))]
-          (is (= (:status response) 200))
-          (is (= (:body response) "Hello, World!")))))
-
-    (testing "proxy redirect fails if :follow-redirects not configured properly"
-      (with-target-and-proxy-servers
-        {:target       {:host "0.0.0.0"
-                        :port 9000}
-         :proxy        {:host "0.0.0.0"
-                        :port 10000}
-         :proxy-config {:host "localhost"
-                        :port 9000
-                        :path "/hello"}
-         :ring-handler redirect-test-handler}
-        (let [response (http-get (str "http://localhost:10000/hello-proxy"))]
-          (is (= (:status response) 404)))))
-
-    (testing "proxy-redirect to non-target host fails"
-      (with-target-and-proxy-servers
-        {:target       {:host "0.0.0.0"
-                        :port 9000}
-         :proxy        {:host "0.0.0.0"
-                        :port 10000}
-         :proxy-config {:host "localhost"
-                        :port 9000
-                        :path "/hello"}
-         :proxy-opts   {:follow-redirects true}
-         :ring-handler redirect-wrong-host}
-        (let [response (http-get (str "http://localhost:10000/hello-proxy"))]
-          (is (= (:status response) 502)))))
-
-    (testing "proxy redirect to correct host in fully qualified url works"
-      (with-target-and-proxy-servers
-        {:target {:host "0.0.0.0"
-                  :port 9000}
-         :proxy  {:host "0.0.0.0"
-                  :port 10000}
-         :proxy-config {:host "localhost"
-                        :port 9000
-                        :path "/hello"}
-         :proxy-opts   {:follow-redirects true}
-         :ring-handler redirect-same-host}
-        (let [response (http-get (str "http://localhost:9000/hello/"))]
-          (is (= (:status response) 200))
-          (is (= (:body response) "Hello, World!")))
-        (let [response (http-get (str "http://localhost:9000/hello/world"))]
-          (is (= (:status response) 200))
-          (is (= (:body response) "Hello, World!")))
-        (let [response (http-get (str "http://localhost:10000/hello-proxy"))]
-          (is (= (:status response) 200))
-          (is (= (:body response) "Hello, World!")))
-        (let [response (http-get (str "http://localhost:10000/hello-proxy/world"))]
-          (is (= (:status response) 200))
-          (is (= (:body response) "Hello, World!")))))
-
-    (testing "proxy-redirect to non-proxied path on correct host succeeds"
-      (with-target-and-proxy-servers
-        {:target       {:host "0.0.0.0"
-                        :port 9000}
-         :proxy        {:host "0.0.0.0"
-                        :port 10000}
-         :proxy-config {:host "localhost"
-                        :port 9000
-                        :path "/hello"}
-         :proxy-opts   {:follow-redirects true}
-         :ring-handler redirect-different-proxy-path}
-        (let [response (http-get (str "http://localhost:9000/hello/"))]
-          (is (= (:status response) 200))
-          (is (= (:body response) "Hello, World!")))
-        (let [response (http-get (str "http://localhost:10000/hello-proxy"))]
-          (is (= (:status response) 200))
-          (is (= (:body response) "Hello, World!")))))
-
-    (testing "proxying failure - default handler"
-      (with-target-and-proxy-servers
-        {:target       {:host "0.0.0.0"
-                        :port 9000}
-         :proxy        {:host "0.0.0.0"
-                        :port 10000}
-         :proxy-config {:host "localhost"
-                        :port 123456789 ; illegal port number
-                        :path "/hello"}
-         :ring-handler proxy-ring-handler}
-        (let [response (http-get "http://localhost:10000/hello-proxy/world")]
-          (is (= (:status response) 502))
-          (is (= (:body response) "")))))
-
-    (testing "proxying failure - custom handler"
-      (with-target-and-proxy-servers
-        {:target       {:host "0.0.0.0"
-                        :port 9000}
-         :proxy        {:host "0.0.0.0"
-                        :port 10000}
-         :proxy-config {:host "localhost"
-                        :port 123456789 ; illegal port number
-                        :path "/hello"}
-         :proxy-opts   {:failure-callback-fn failure-callback-fn}
-         :ring-handler proxy-ring-handler}
-        (let [response (http-get "http://localhost:10000/hello-proxy/world")]
-          (is (= (:status response) 500))
-          (is (= (:body response) "Proxying failed: port out of range:123456789")))))))
+          (is (= (read-string (:body response)) params)))))))
+
+(deftest proxy-with-redirect
+  (testing "redirect test with proxy"
+    (with-target-and-proxy-servers
+      {:target       {:host "0.0.0.0"
+                      :port 9000}
+       :proxy        {:host "0.0.0.0"
+                      :port 10000}
+       :proxy-config {:host "localhost"
+                      :port 9000
+                      :path "/hello"}
+       :proxy-opts   {:follow-redirects true}
+       :ring-handler redirect-test-handler}
+      (let [response (http-get (str "http://localhost:9000/hello/"))]
+        (is (= (:status response) 200))
+        (is (= (:body response) "Hello, World!")))
+      (let [response (http-get (str "http://localhost:9000/hello/world"))]
+        (is (= (:status response) 200))
+        (is (= (:body response) "Hello, World!")))
+      (let [response (http-get (str "http://localhost:10000/hello-proxy"))]
+        (is (= (:status response) 200))
+        (is (= (:body response) "Hello, World!")))
+      (let [response (http-get (str "http://localhost:10000/hello-proxy/world"))]
+        (is (= (:status response) 200))
+        (is (= (:body response) "Hello, World!")))))
+
+  (testing "proxy redirect fails if :follow-redirects not configured properly"
+    (with-target-and-proxy-servers
+      {:target       {:host "0.0.0.0"
+                      :port 9000}
+       :proxy        {:host "0.0.0.0"
+                      :port 10000}
+       :proxy-config {:host "localhost"
+                      :port 9000
+                      :path "/hello"}
+       :ring-handler redirect-test-handler}
+      (let [response (http-get (str "http://localhost:10000/hello-proxy"))]
+        (is (= (:status response) 404)))))
+
+  (testing "proxy-redirect to non-target host fails"
+    (with-target-and-proxy-servers
+      {:target       {:host "0.0.0.0"
+                      :port 9000}
+       :proxy        {:host "0.0.0.0"
+                      :port 10000}
+       :proxy-config {:host "localhost"
+                      :port 9000
+                      :path "/hello"}
+       :proxy-opts   {:follow-redirects true}
+       :ring-handler redirect-wrong-host}
+      (let [response (http-get (str "http://localhost:10000/hello-proxy"))]
+        (is (= (:status response) 502)))))
+
+  (testing "proxy redirect to correct host in fully qualified url works"
+    (with-target-and-proxy-servers
+      {:target       {:host "0.0.0.0"
+                      :port 9000}
+       :proxy        {:host "0.0.0.0"
+                      :port 10000}
+       :proxy-config {:host "localhost"
+                      :port 9000
+                      :path "/hello"}
+       :proxy-opts   {:follow-redirects true}
+       :ring-handler redirect-same-host}
+      (let [response (http-get (str "http://localhost:9000/hello/"))]
+        (is (= (:status response) 200))
+        (is (= (:body response) "Hello, World!")))
+      (let [response (http-get (str "http://localhost:9000/hello/world"))]
+        (is (= (:status response) 200))
+        (is (= (:body response) "Hello, World!")))
+      (let [response (http-get (str "http://localhost:10000/hello-proxy"))]
+        (is (= (:status response) 200))
+        (is (= (:body response) "Hello, World!")))
+      (let [response (http-get (str "http://localhost:10000/hello-proxy/world"))]
+        (is (= (:status response) 200))
+        (is (= (:body response) "Hello, World!")))))
+
+  (testing "proxy-redirect to non-proxied path on correct host succeeds"
+    (with-target-and-proxy-servers
+      {:target       {:host "0.0.0.0"
+                      :port 9000}
+       :proxy        {:host "0.0.0.0"
+                      :port 10000}
+       :proxy-config {:host "localhost"
+                      :port 9000
+                      :path "/hello"}
+       :proxy-opts   {:follow-redirects true}
+       :ring-handler redirect-different-proxy-path}
+      (let [response (http-get (str "http://localhost:9000/hello/"))]
+        (is (= (:status response) 200))
+        (is (= (:body response) "Hello, World!")))
+      (let [response (http-get (str "http://localhost:10000/hello-proxy"))]
+        (is (= (:status response) 200))
+        (is (= (:body response) "Hello, World!"))))))
+
+(deftest proxy-failure
+  (testing "proxying failure - default handler"
+    (with-target-and-proxy-servers
+      {:target       {:host "0.0.0.0"
+                      :port 9000}
+       :proxy        {:host "0.0.0.0"
+                      :port 10000}
+       :proxy-config {:host "localhost"
+                      :port 123456789                       ; illegal port number
+                      :path "/hello"}
+       :ring-handler proxy-ring-handler}
+      (let [response (http-get "http://localhost:10000/hello-proxy/world")]
+        (is (= (:status response) 502))
+        (is (= (:body response) "")))))
+
+  (testing "proxying failure - custom handler"
+    (with-target-and-proxy-servers
+      {:target       {:host "0.0.0.0"
+                      :port 9000}
+       :proxy        {:host "0.0.0.0"
+                      :port 10000}
+       :proxy-config {:host "localhost"
+                      :port 123456789                       ; illegal port number
+                      :path "/hello"}
+       :proxy-opts   {:failure-callback-fn failure-callback-fn}
+       :ring-handler proxy-ring-handler}
+      (let [response (http-get "http://localhost:10000/hello-proxy/world")]
+        (is (= (:status response) 500))
+        (is (= (:body response) "Proxying failed: port out of range:123456789"))))))


[scamp] correct paper section reference in implementation tracking list

--- modules/scamp/src/scamp/core.clj
+++ modules/scamp/src/scamp/core.clj
@@ -10,9 +10,8 @@
     * DONE: subscription (§2.2.1, Algorithm 1)
     * DONE: subscription (§2.2.1, Algorithm 2)
     * DONE: unsubscription (§2.2.2)
-    * DONE: heartbeats (§2.2.3) (This is the first async feature,
-                                 because it depends on the concept of
-                                 \"a long time\".)
+    * DONE: recovery from isolation (§2.2.3)
+            ^- (This is the first async feature, because it depends on the concept of \"a long time\".)
     * subscription indirection (§3.1)
     * lease mechanism (§3.2)
   "


[scamp] throw on receipt of unknown message type for now, instead of logging error

--- modules/scamp/src/scamp/core.clj
+++ modules/scamp/src/scamp/core.clj
@@ -277,14 +277,13 @@
 (defmethod receive-msg :default
   [& args]
   (let [[_message-type {:keys [logging]} & _rest] args]
-    (if logging
+    (when logging
       ;; TODO: If an unknown message type is received, gracefully shut
       ;; down to allow restart with an upgrade?
       (timbre/log* logging :error
                    :receive-msg-unknown-message-type
-                   :args args)
-      (prn "Error: unknown message type received by 'receive-msg."
-           :args args))))
+                   :args args))
+    (throw (ex-info "Error: unknown message type received by 'receive-msg." {:args args}))))

 (s/defmethod receive-msg :new-subscription :- CommUpdateSchema
   #_"Add 'subscription to :upstream.


support %ID% template string in worker childopts

--- src/clj/backtype/storm/daemon/supervisor.clj
+++ src/clj/backtype/storm/daemon/supervisor.clj
@@ -366,7 +366,7 @@
     (let [stormroot (supervisor-stormdist-root conf storm-id)
           stormjar (supervisor-stormjar-path stormroot)
           classpath (add-to-classpath (current-classpath) [stormjar])
-          childopts (conf WORKER-CHILDOPTS)
+          childopts (.replaceAll (conf WORKER-CHILDOPTS) "%ID%" (str port))
           logfilename (str "worker-" port ".log")
           command (str "java -server " childopts
                        " -Djava.library.path=" (conf JAVA-LIBRARY-PATH)


Use buttons from ReactBootstrap

Use buttons from ReactBootstrap

--- src/cljs/cglossa/search_inputs/cwb/core.cljs
+++ src/cljs/cglossa/search_inputs/cwb/core.cljs
@@ -106,15 +106,16 @@
 ;;;;;;;;;;;;;

 (defn- search-button [a m margin-left]
-  [:button.btn.btn-success {:style    {:marginLeft margin-left}
-                            :on-click #(search! a m)} "Search"])
+  [button {:bs-style "success"
+           :style    {:marginLeft margin-left}
+           :on-click #(search! a m)} "Search"])

 (defn- add-language-button []
-  [:button.btn {:style {:marginLeft 20} :on-click #()} "Add language"])
+  [button {:style {:marginLeft 20} :on-click #()} "Add language"])

 (defn- add-phrase-button [view]
-  [:button.btn.btn-default {:style    {:margin-top (if (= view extended) -15 0)}
-                            :on-click #()} "Or..."])
+  [button {:style    {:margin-top (if (= view extended) -15 0)}
+           :on-click #()} "Or..."])

 (defn- language-select [languages selected-language]
   [:select {:value selected-language}


Make room for metrics.

Make room for metrics.

--- src/cljs/onyx_dashboard/components/jobs.cljs
+++ src/cljs/onyx_dashboard/components/jobs.cljs
@@ -124,4 +124,9 @@
                 {:header (om/build section-header-collapsible {:text "Flow Conditions"} {})
                  :collapsible? true
                  :bs-style "primary"}
-                (om/build clojure-block {:input pretty-flow-conditions}))))))
+                (om/build clojure-block {:input pretty-flow-conditions})))
+
+            (p/panel
+              {:header (om/build section-header-collapsible {:text "Metrics"} {})
+               :collapsible? true
+               :bs-style "primary"}))))


refactor async-future* to extract state atom setup

--- src/cljx/jamesmacaulay/async_tools/core.cljx
+++ src/cljx/jamesmacaulay/async_tools/core.cljx
@@ -27,6 +27,17 @@
   [x]
   (if (readport? x) x (constant x)))

+(defn- async-future-state-atom
+  [f]
+  (let [state-atom (atom {:boxed-value nil
+                          :handlers []})]
+    (f (fn [value]
+         (let [state (swap! state-atom assoc :boxed-value (channels/box value))]
+           (doseq [handler (:handlers state)]
+             ((impl/commit handler) value))
+           (swap! state-atom assoc :handlers nil))))
+    state-atom))
+
 (defrecord AsyncFuture [state-atom]
   impl/ReadPort
   (take! [_ handler]
@@ -39,15 +50,7 @@

 (defn async-future*
   [f]
-  (let [state-atom (atom {:boxed-value nil
-                          :handlers []})
-        resolve-fn (fn [value]
-                     (let [state (swap! state-atom assoc :boxed-value (channels/box value))]
-                       (doseq [handler (:handlers state)]
-                         ((impl/commit handler) value))
-                       (swap! state-atom assoc :handlers nil)))]
-    (f resolve-fn)
-    (AsyncFuture. state-atom)))
+  (AsyncFuture. (async-future-state-atom f)))

 (defn async-future<
   [ch]


Refactor names and map access

Refactor names and map access

--- src/day8/re_frame/trace.cljs
+++ src/day8/re_frame/trace.cljs
@@ -144,12 +144,11 @@
     (fn [trace]
       (< (:query query) (:duration trace)))))

-(defn render-traces [showing-traces trace-details]
+(defn render-traces [showing-traces trace-detail-expansions]
   (doall
     (for [{:keys [op-type id operation tags duration] :as trace} showing-traces]
       (let [padding   {:padding "0px 5px 0px 5px"}
             row-style (merge padding {:border-top (case op-type :event "1px solid lightgrey" nil)})
-            keyword-id (keyword (str id))
             #_#__ (js/console.log (devtools/header-api-call tags))]
         (list [:tr {:key   id
                     :style {:color (case op-type
@@ -160,9 +159,12 @@
                                      :re-frame.router/fsm-trigger "#fd701e"
                                      nil)}}
                [:td {:style (merge row-style {:cursor "pointer"})
-                     :on-click #(swap! trace-details assoc keyword-id (not (keyword-id @trace-details)))}
-                (if (or (keyword-id @trace-details)
-                        (:showing @trace-details))
+                     :on-click (fn [e]
+                                 (when (:showing @trace-detail-expansions)
+                                   (swap! trace-detail-expansions assoc :showing false))
+                                 (swap! trace-detail-expansions update-in [:overrides id] not))}
+                (if (or (get-in @trace-detail-expansions [:overrides id])
+                        (:showing @trace-detail-expansions))
                   "▼"
                   "▶")]
                [:td {:style row-style} (str op-type)]
@@ -177,17 +179,19 @@
                                           :white-space "nowrap"})}

                 (.toFixed duration 1) " ms"]]
-              (when (or (keyword-id @trace-details)
-                        (:showing @trace-details))
+              (when (or (get-in @trace-detail-expansions [:overrides id])
+                        (:showing @trace-detail-expansions))
                 [:tr {:key (str id "-details")}
                  [:td {:col-span 3} (with-out-str (pprint/pprint (dissoc tags :query-v :event :duration)))]]))))))

+
+
 (defn render-trace-panel []
-  (let [filter-input     (r/atom "")
-        filter-items     (r/atom [])
-        filter-type      (r/atom :contains)
-        input-error      (r/atom false)
-        trace-details    (r/atom {:showing false})]
+  (let [filter-input               (r/atom "")
+        filter-items               (r/atom [])
+        filter-type                (r/atom :contains)
+        input-error                (r/atom false)
+        trace-detail-expansions    (r/atom {:showing false :overrides {}})]
     (fn []
       (let [showing-traces       (if (= @filter-items [])
                                    @traces
@@ -234,8 +238,11 @@
             [:thead>tr
              [:th [:button.text-button
                    {:style {:cursor "pointer"}
-                    :on-click #(reset! trace-details {:showing (not (:showing @trace-details))})}
-                   (if (:showing @trace-details) "-" "+")]]
+                    :on-click (fn [e]
+                                (when (:showing @trace-detail-expansions)
+                                  (swap! trace-detail-expansions assoc :overrides {}))
+                                (swap! trace-detail-expansions update :showing not))}
+                   (if (:showing @trace-detail-expansions) "-" "+")]]
              [:th "operations"]
              [:th
                (when (pos? (count @filter-items))
@@ -246,7 +253,7 @@
                (when (pos? (count @traces))
                  [:span "(" [:button.text-button {:on-click #(do (trace/reset-tracing!) (reset! traces []))} "clear"] ")"])]
              [:th "meta"]]
-            [:tbody (render-traces showing-traces trace-details)]]]]))))
+            [:tbody (render-traces showing-traces trace-detail-expansions)]]]]))))

 (defn resizer-style [draggable-area]
   {:position "absolute" :z-index 2 :opacity 0


Tn-Seq revealed need to adjust barcodes per illumina sample - not just all barcodes

--- src/aerobio/htseq/common.clj
+++ src/aerobio/htseq/common.clj
@@ -273,8 +273,13 @@
                      (reduce (fn[BC v] (conj BC (last v))) #{})
                      sort vec))))
       ((fn[m]
-         (assoc m :barcodes-map
-                (reduce (fn[M bc] (assoc M bc bc)) {} (m :barcodes)))))
+         (assoc m :barcode-maps
+                (->> (m :exp-illumina-xref)
+                     (map #(vector (first %)
+                                   (->> % second (map last)
+                                        (map (fn[bc] (vector bc bc)))
+                                        (into {}))))
+                     (into {})))))
       ((fn[m]
          (assoc m :bcmaps
                 (apply merge
@@ -282,10 +287,11 @@
                             (fs/directory-files (m :stats) ".clj"))))))
       ((fn[m]
          (assoc m :ed1codes
-                (let [bcmaps (m :bcmaps)]
+                (let [bcmaps (m :bcmaps)
+                      barcode-maps (m :barcode-maps)]
                   (into {} (map #(vector % (barcodes-edist-1-seqs
                                             (bcM bcmaps %)
-                                            (m :barcodes)))
+                                            (keys (barcode-maps %))))
                                 (keys bcmaps)))))))
       ((fn[m]
          (assoc m :red1codes
@@ -378,17 +384,28 @@
                ibcs))))

-(defn get-sq-bc [sq barcodes-map other-barcodes]
-  (let [bc (str/substring sq 0 7)]
-    (or (barcodes-map bc) (other-barcodes bc))))
+(defn get-sq-bc [sq bclen barcodes-map other-barcodes]
+  (when sq
+    (let [bc (str/substring sq 0 bclen)]
+      (or (barcodes-map bc) (other-barcodes bc)))))

 (defn pass-qcscore [qc qc-ctpt sqc%]
   (> (fil/percent-pass-qscore qc qc-ctpt) (double sqc%)))

+(def SDBG (atom #{}))
+;;;#{"GGATGG" "CTTAAC" "TAATTA" "ATGGAT" "AATTGC" "TGCTTA"}
 (defn write-chunk-to-files [ot-fd-map recs]
-  (let [file-groups (->> recs (group-by (fn[[bc fqrec]] (ot-fd-map bc)))
-                         (mapv (fn[[fd rec]] [fd (mapv second rec)])))]
+  (let [file-groups (->> recs (group-by
+                               (fn[[bc fqrec]]
+                                 (let [fd (ot-fd-map bc)]
+                                   (if fd fd
+                                       (when (not (@SDBG bc))
+                                         (swap! SDBG #(conj % bc))
+                                         (prn :BAD-BC?! bc))))))
+                         (mapv (fn[[fd rec]] [fd (mapv second rec)])))
+
+        file-groups (filter (fn[[fd recs]] fd) file-groups)]
     (dorun
      (mapv (fn[fut] (deref fut))
            (mapv (fn[[fd recs]]
@@ -397,6 +414,7 @@

 (defn split-barcodes
   [in-fq sqxform-fn ot-fq-map barcodes-map other-barcodes qc-ctpt sqc%]
+
   (letio [bclen (->> ot-fq-map keys first count long)
           inf (io/open-streaming-gzip in-fq :in)
           lines (io/read-lines inf)
@@ -420,7 +438,9 @@
                                  V v)))
                       (fn[V fqrec]
                         (let [[id sq aux qc] (sqxform-fn fqrec)
-                              bc (get-sq-bc sq barcodes-map other-barcodes)]
+                              bc (get-sq-bc sq bclen
+                                            barcodes-map
+                                            other-barcodes)]
                           (if bc
                             (if (pass-qcscore qc qc-ctpt sqc%)
                               (let [len (count sq)
@@ -444,7 +464,7 @@
   (let [base (get-exp-info eid :base)
         exp-illumina-xref (get-exp-info eid :exp-illumina-xref)
         illumina-sample-xref (get-exp-info eid :illumina-sample-xref)
-        barcodes-map (get-exp-info eid :barcodes-map)
+        barcode-maps (get-exp-info eid :barcode-maps)
         red1codes (get-exp-info eid :red1codes)
         [qc-ctpt _] (fil/qcscore-min-entropy baseqc% 0.9 10)
         bc-file-specs (get-bc-file-specs
@@ -464,7 +484,7 @@
         (split-barcodes (sample-ifq-xref samp)
                         sqxform-fn
                         (bc-file-specs ibc)
-                        barcodes-map
+                        (barcode-maps ibc)
                         (red1codes sid)
                         qc-ctpt sqc%)))
     :success))
@@ -505,10 +525,12 @@
 (comment
   (def eid "160930_161002_AHK72HBGXY_AHK7YKBGXY")
   (def neid "161108_161109_AH2WWGBGX2_AH2WLJBGX2")
+  (def teid "160804_NS500751_0017_AHF2KLBGXY")

   (set-exp "160307_NS500751_0013_AHL7L3BGXX")
   (set-exp "160930_161002_AHK72HBGXY_AHK7YKBGXY")
   (set-exp "161108_161109_AH2WWGBGX2_AH2WLJBGX2")
+  (set-exp teid)

   (get-exp "160307_NS500751_0013_AHL7L3BGXX")
   ((get-exp "160307_NS500751_0013_AHL7L3BGXX") :base)


Español, not Italiano

Español, not Italiano

--- src/babel/espanol/writer.clj
+++ src/babel/espanol/writer.clj
@@ -141,7 +141,7 @@
                                                         (log/error message)
                                                         (throw (Exception. message))))

-                                                    ;; The verb is "funzionare" (which takes a non-human
+                                                    ;; The verb is "funcionar" (which takes a non-human
                                                     ;; subject), but we're trying to generate with
                                                     ;; {:agr {:person :1st or :2nd}}, for which the only lexemes
                                                     ;; are human.
@@ -155,7 +155,7 @@
                                                     (log/info (str "ignoring exception(funcionar-is-only-nonhuman): " e))

-                                                    ;; The verb is "funzionare" (which takes a non-human
+                                                    ;; The verb is "funcionar" (which takes a non-human
                                                     ;; subject), but we're trying to generate a non-pronoun complement;
                                                     ;; there are no such single words in the lexicon that are both
                                                     ;; non-human and non-pronoun. There are *human* non-pronouns in the lexicon,


Remove wip/debugging stuff

Remove wip/debugging stuff

--- src/braid/bots/server/db.clj
+++ src/braid/bots/server/db.clj
@@ -244,22 +244,3 @@
             (get-in (d/entity db-after [:thread/id thread-id]) [:thread/group :group/id]))
          (format "Bot %s tried to watch thread not in its group %s" bot-id thread-id)))}
    [:db/add [:bot/id bot-id] :bot/watched [:thread/id thread-id]]])
-
-(comment
-  {:notify-all-messages? nil, :webhook-url "https://bots.braid.chat/giphybot/bloom/message", :group-id #uuid "572e4ed2-a786-45bd-9859-430b7a68cc70", :name "giphybot", :user-id #uuid "575c5960-5ae5-48c8-88be-96caab2d1cf3", :token "PevlOatUfuY32MWc3X7EjuPKMF7J1uFT83uzywer", :id #uuid "575c5960-f810-44a3-af53-410a1102f8fd", :event-webhook-url nil, :avatar "https://s3.amazonaws.com/chat.leanpixel.com/uploads/5730f31a-8b10-451d-a1b0-3c515045481c/ptero.gif"}
-
-  (let [user-id (d/tempid :entities)
-        bot-id (d/tempid :entities)]
-    @(d/transact
-      db/conn
-      [{:db/id user-id
-        :user/id (d/squuid)
-        :user/is-bot? true}
-       {:db/id bot-id
-        :bot/id #uuid "575c5960-f810-44a3-af53-410a1102f8fd",
-        :bot/token "PevlOatUfuY32MWc3X7EjuPKMF7J1uFT83uzywer",
-        :bot/name "giphybot",
-        :bot/avatar "https://s3.amazonaws.com/chat.leanpixel.com/uploads/5730f31a-8b10-451d-a1b0-3c515045481c/ptero.gif",
-        :bot/webhook-url "https://bots.braid.chat/giphybot/bloom/message",
-        :bot/group [:group/id #uuid "5cb8ad79-0851-4968-acb5-ffe3f4ec5809"]
-        :bot/user user-id}])))


change pr/add to deal with emtpy sequences and single IStatements properly

--- src/rdf-repository/grafter/rdf/repository.clj
+++ src/rdf-repository/grafter/rdf/repository.clj
@@ -50,17 +50,26 @@
   (pr/add
     ([this triples]
        {:pre [(or (nil? triples)
-                  (sequential? triples))]}
-       (if (seq triples)
-         (let [^Iterable stmts (map IStatement->sesame-statement triples)]
-           (.add this stmts (resource-array)))
+                (sequential? triples)
+                (instance? IStatement triples))]}
+       (if (not (instance? IStatement triples))
+         (when (seq triples)
+               ( let [^Iterable stmts (map IStatement->sesame-statement triples)]
+               (.add this stmts (resource-array)))
+             )
          (pr/add-statement this triples)))

+
     ([this graph triples]
-       (if (seq triples)
-         (let [^Iterable stmts (map IStatement->sesame-statement triples)]
-           (.add this stmts (resource-array (URIImpl. graph))))
-         (pr/add-statement this graph triples)))
+       {:pre [(or (nil? triples)
+                (sequential? triples)
+                (instance? IStatement triples))]}
+       (if (not (instance? IStatement triples))
+         (when (seq triples)
+             ( let [^Iterable stmts (map IStatement->sesame-statement triples)]
+                   (.add this stmts (resource-array (URIImpl. graph))))
+             )
+         (pr/add-statement this triples)))

     ([this graph format triple-stream]
        (.add this triple-stream nil format (resource-array (URIImpl. graph))))


Fix to use (.setAutoCommit false) instead of .begin as autoCommitFalse implies begin.

--- src/rdf-repository/grafter/rdf/repository.clj
+++ src/rdf-repository/grafter/rdf/repository.clj
@@ -197,7 +197,7 @@
 (extend-protocol pr/ITransactable
   Repository
   (begin [repo]
-    (-> repo .getConnection .begin))
+    (-> repo .getConnection (.setAutoCommit false)))

   (commit [repo]
     (-> repo .getConnection .commit))
@@ -207,7 +207,7 @@

   RepositoryConnection
   (begin [repo]
-    (-> repo .begin))
+    (-> repo (.setAutoCommit false)))

   (commit [repo]
     (-> repo .commit))
@@ -320,7 +320,6 @@
   (if (instance? RepositoryConnection repo)
     repo
     (let [c (.getConnection repo)]
-      (.setAutoCommit c false)
       c)))

 (defn prepare-query


Update format of fav posts output

Update format of fav posts output

--- src/ecregister/favorites.clj
+++ src/ecregister/favorites.clj
@@ -14,8 +14,8 @@
                post-date)))

 (defn print-post [p]
-  (prn (format "%s, автор <ls user=\"%s\"/> (%s голосов)"
-               (:link p) (:title p) (:author p) (:fav-count p))))
+  (println (format "%s, автор <ls user=\"%s\"/>"
+               (:link p) (:title p) (:author p))))

 (defn print-favorites [since-date]
   (let [all-posts (posts/fetch-aw-posts #(is-more-recent since-date %))]