theorems with implicit type parameters, working

--- src/latte/core.clj
+++ src/latte/core.clj
@@ -97,8 +97,6 @@
       (throw (ex-info "Cannot define term: syntax error."
                       {:explain (s/explain-str ::definition args)}))
       (let [{def-name :name doc :doc params :params body :body} conf-form]
-        (when (defenv/registered-definition? def-name)
-          (log/warn "Redefinition as term: " def-name))
         ;; handling of implicit parameter types
         (if-let [res (u/fetch-implicit-type-parameters params)]
           (let [{implicit-types :implicit-types new-params :new-params} res
@@ -107,11 +105,13 @@
                    (definition ~explicit-def-name ~(str "This is an explicit variant of [[" def-name "]].") ~new-params ~body)
                    ~(gen-type-parameters-defimplicit def-name "Definition" doc explicit-def-name implicit-types params new-params body)
                    (alter-meta! (var ~def-name) update-in [:arglists] (fn [_#] (list (quote ~params))))
-                   [:defined :term (quote ~def-name)]))
+                   [:defined :term (quote ~def-name) :explicit (quote ~explicit-def-name)]))
           ;; no implicit parmeter types from here...
           (let [[status definition] (handle-term-definition def-name params body)]
             (when (= status :ko)
               (throw (ex-info "Cannot define term." {:name def-name, :error definition})))
+            (when (defenv/registered-definition? def-name)
+              (log/warn "Redefinition as term: " def-name))
             ;;{
             ;;  - Second, after some checks, we register the definition in the currently active namespace (i.e. `*ns*`).
             ;;}
@@ -151,7 +151,7 @@
                                lt-clauses
                                (conj lt-clauses lt-clause))])) [implicit-types []] targs)]
     (when-not (empty? remaining-implicit-types)
-      (throw (ex-info "Unsolved implicit type parameters" {:definition def-name
+      (throw (ex-info "Unsolved implicit type parameters" {:statement def-name
                                                            :implicit-type-params implicit-types
                                                            :unsolved remaining-implicit-types})))
     `(defimplicit ~def-name
@@ -370,12 +370,22 @@
   namespace (i.e. it is a Clojure `def`)."
   [& args]
   (let [{thm-name :name doc :doc params :params body :body}
-        (conform-statement :theorem args)
-        [status result] (handle-statement :theorem thm-name params body)]
-    (if (= status :ko)
-      (throw (ex-info "Cannot declare theorem." result))
-      (let [metadata (statement-metadata :theorem doc params body)]
-        (define-statement! :theorem thm-name result metadata)))))
+        (conform-statement :theorem args)]
+            ;; handling of implicit parameter types
+    (if-let [res (u/fetch-implicit-type-parameters params)]
+      (let [{implicit-types :implicit-types new-params :new-params} res
+            explicit-thm-name (symbol (str thm-name "-thm"))]
+        `(do
+           (defthm ~explicit-thm-name ~(str "This is an explicit variant of [[" thm-name "]].") ~new-params ~body)
+           ~(gen-type-parameters-defimplicit thm-name "Theorem" doc explicit-thm-name implicit-types params new-params body)
+           (alter-meta! (var ~thm-name) update-in [:arglists] (fn [_#] (list (quote ~params))))
+           [:declared :theorem (quote ~explicit-thm-name) :implicit (quote ~thm-name)]))
+      ;; no implicit type parameters
+      (let [[status result] (handle-statement :theorem thm-name params body)]
+        (if (= status :ko)
+          (throw (ex-info "Cannot declare theorem." result))
+          (let [metadata (statement-metadata :theorem doc params body)]
+            (define-statement! :theorem thm-name result metadata)))))))

 ;;{
 ;; ### Lemmas


Channels don't need to be cursored

Channels don't need to be cursored

--- informing/src/app/core.cljs
+++ informing/src/app/core.cljs
@@ -57,13 +57,27 @@

 ;; -----------------------------------------------------------------------------
+;; Channels
+
+(defn get-channel [k]
+  (get-in @omni-state [:cha k]))
+
+(defn swap-channel! [k cha]
+  (swap! omni-state assoc-in [:cha k] cha))
+
+(defonce setup-channels!
+  (do
+    (swap-channel! :dom-viewport-resize (poly/channel-for-viewport-resize!))
+    (swap-channel! :env-mouse-move (poly/channel-for-mouse-move! js/window))
+    true))
+
+
+;; -----------------------------------------------------------------------------
 ;; Cursor Creators (Omni's little helpers)

 (def cc (partial r/cursor omni-state))

 (defonce cc-app (partial r/cursor (cc :app)))
-
-(defonce cc-cha (partial r/cursor (cc :cha)))

 (defonce cc-dom (partial r/cursor (cc :dom)))

@@ -80,18 +94,6 @@

 (defonce rc-app-version
   (cc-app [:version]))
-
-(defonce rc-cha-dom-viewport-resize
-  (cc-cha [:dom-viewport-resize]))
-
-(defonce rc-cha-env-mouse-down
-  (cc-cha [:env-mouse-down]))
-
-(defonce rc-cha-env-mouse-move
-  (cc-cha [:env-mouse-move]))
-
-(defonce rc-cha-env-mouse-up
-  (cc-cha [:env-mouse-up]))

 (defonce rc-dom-document-h
   (cc-dom [:document-height]))
@@ -145,18 +147,6 @@

 ;; -----------------------------------------------------------------------------
-;; Channels
-
-(defonce setup-channels!
-  (do
-    (reset! rc-cha-dom-viewport-resize
-            (poly/channel-for-viewport-resize!))
-    (reset! rc-cha-env-mouse-move
-            (poly/channel-for-mouse-move! js/window))
-    true))
-
-
-;; -----------------------------------------------------------------------------
 ;; Event Handlers (On and on and on, over and over again...)

 (defn on-dom-viewport-resize [{:keys [width height]}]
@@ -182,13 +172,13 @@
   (poly/listen-for-viewport-resize! on-dom-viewport-resize))

 (defonce listen-for-dom-viewport-resize!
-  (poly/listen-take! @rc-cha-dom-viewport-resize on-dom-viewport-resize))
+  (poly/listen-take! (get-channel :dom-viewport-resize) on-dom-viewport-resize))

 (defonce listen-for-dom-window-load!
   (poly/listen! js/window "load" on-dom-window-load))

 (defonce listen-for-env-mouse-move!
-  (poly/listen-take! @rc-cha-env-mouse-move on-env-mouse-move))
+  (poly/listen-take! (get-channel :env-mouse-move) on-env-mouse-move))

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


Improve logging for uncaught exceptions without stacktraces

--- library/src/doo/runner.cljs
+++ library/src/doo/runner.cljs
@@ -59,11 +59,10 @@
       (catch :default e
         (println "\nERROR: Exception outside tests:")
         (println e)
-        (println "\nERROR: Stacktrace:")
-        (println
-         (if (.hasOwnProperty e "stack")
-           (.-stack e)
-           "No stacktrace available."))
+        (if (.hasOwnProperty e "stack")
+          (do (println "\nERROR: Stacktrace:")
+              (println (.-stack e)))
+          (println "\nNo stacktrace available."))
         (exit! false)))))

 (defn set-entry-point!


fixing test

fixing test

--- test/celestial/features/kvm.clj
+++ test/celestial/features/kvm.clj
@@ -22,7 +22,7 @@
           (just {
             :user "celestial" :name "red1.local" :hostname "red1"
             :image {:flavor :debian :template "ubuntu-16.04"}
-            :cpu 2 :ram 1024
+            :cpu 4 :ram 1024
            })))))

 (with-admin


Add tests to illustrate the usability with the Clojure REPL.

--- test/cli4clj/test/cli_tests.clj
+++ test/cli4clj/test/cli_tests.clj
@@ -169,3 +169,30 @@
                                    :b {:fn (fn [summand1 summand2] (+ summand1 summand2))}}})))]
     (test/is (= (cli-tests/expected-string ["2" (str "5" cli/*cli4clj-line-sep*)]) out))))

+
+
+(test/deftest clojure-repl-stdout-no-op-test
+  (let [in-cmds [""]
+        out (cli-tests/test-cli-stdout clojure.main/repl in-cmds)]
+    (test/is (= (cli-tests/expected-string ["user=> user=>"]) out))))
+
+(test/deftest clojure-repl-stderr-no-op-test
+  (let [in-cmds [""]
+        out (cli-tests/test-cli-stderr clojure.main/repl in-cmds)]
+    (test/is (= (cli-tests/expected-string [""]) out))))
+
+(test/deftest clojure-repl-stdout-inc-test
+  (let [in-cmds ["(inc 1)"]
+        out (cli-tests/test-cli-stdout clojure.main/repl in-cmds)]
+    (test/is (= (cli-tests/expected-string ["user=> 2" "user=>"]) out))))
+
+(test/deftest clojure-repl-stdout-let-inc-println-test
+  (let [in-cmds ["(def x 21)" "(inc x)" "(println x)"]
+        out (cli-tests/test-cli-stdout clojure.main/repl in-cmds)]
+    (test/is (= (cli-tests/expected-string ["user=> #'user/x" "user=> 22" "user=> 21" "nil" "user=>"]) out))))
+
+(test/deftest clojure-repl-stderr-div-zero-test
+  (let [in-cmds ["(/ 1 0)"]
+        out (cli-tests/test-cli-stderr clojure.main/repl in-cmds)]
+    (test/is (.startsWith out "ArithmeticException Divide by zero"))))
+


Change the fixture to do a full pave-and-re-bootstrap before and after ever set of tests.

--- test/doctopus/test_database.clj
+++ test/doctopus/test_database.clj
@@ -24,9 +24,13 @@
   (let [sql-string (format "TRUNCATE %s CASCADE" table-name)]
     (do-sql-with-logging! sql-string :test)))

+(defn obliterate!
+  []
+  (do-sql-with-logging! "DROP SCHEMA public CASCADE" :test)
+  (do-sql-with-logging! "CREATE  SCHEMA public" :test))

 (defn database-fixture
   [f]
   (bootstrap :test)
   (f)
-  (doseq [n (keys table-name->schema)] (truncate! n)))
+  (obliterate!))


Clean up core-test step execution and waiting, using simple futures instead of core-async magic

--- test/lambdacd_git/core_test.clj
+++ test/lambdacd_git/core_test.clj
@@ -12,7 +12,8 @@
             [clojure.java.io :as io]
             [lambdacd.event-bus :as event-bus]
             [ring.mock.request :as ring-mock]
-            [lambdacd-git.test-utils :as test-utils]))
+            [lambdacd-git.test-utils :as test-utils])
+  (:import (java.util.concurrent TimeoutException)))

 (defn- status-updates-channel [ctx]
   (let [step-result-updates-ch (event-bus/only-payload
@@ -81,23 +82,18 @@
   state)

 (defn execute-pipeline-step [state step]
-  (let [wait-for-result-channel (async/go
-                                  (let [execute-step-result (lambdacd-core/execute-step {} (:ctx @state)
-                                                              step)]
-                                    (first (vals (:outputs execute-step-result)))))]
-    (swap! state #(assoc % :result-channel wait-for-result-channel))
+  (let [future (future
+                 (let [execute-step-result (lambdacd-core/execute-step {} (:ctx @state)
+                                                                       step)]
+                   (first (vals (:outputs execute-step-result)))))]
+    (swap! state #(assoc % :step-future future))
     state))

 (defn start-wait-for-git-step [state & {:keys [ref ms-between-polls] :or {ms-between-polls 100
                                                                           ref              "refs/heads/master"}}]
-  (let [complete-step-result-channel (async/go
-                                       (let [execute-step-result (lambdacd-core/execute-step {} (:ctx @state)
-                                                                                (fn [_ ctx]
-                                                                                (wait-for-git ctx (get-in @state [:git :remote]) :ref ref :ms-between-polls ms-between-polls)))]
-                                         (first (vals (:outputs execute-step-result)))))]
-    (swap! state #(assoc % :result-channel complete-step-result-channel))
-    (wait-for-step-waiting state)
-    state))
+  (execute-pipeline-step state (fn [_ ctx]
+                                 (wait-for-git ctx (get-in @state [:git :remote]) :ref ref :ms-between-polls ms-between-polls))))
+

 (defn start-clone-step [state ref cwd]
   (execute-pipeline-step state (fn [_ ctx]
@@ -117,9 +113,15 @@
   (reset! (:is-killed @state) true)
   state)

+(defn- throwing-timeout-dref [ref timeout]
+  (let [result (deref ref timeout :timeout)]
+    (if (= :timeout result)
+      (throw (TimeoutException. "timeout"))
+      result)))
+
 (defn get-step-result [state & {:keys [timeout] :or {timeout wait-for-step-finished}}]
   (try
-    (let [result (read-channel-or-time-out (:result-channel @state) :timeout timeout)]
+    (let [result (throwing-timeout-dref (:step-future @state) timeout)]
       (swap! state #(assoc % :step-result result))
       state)
     (catch Exception e


Refactor tests.

Refactor tests.

--- test/om_event_bus/impl_test.clj
+++ test/om_event_bus/impl_test.clj
@@ -41,7 +41,6 @@
       (route-event bus "event")
       (is (timeout? (take! ch))))))

-
 (deftest sending-downstream
   (let [os (async/chan 1024)
         bus (event-bus (downstream-router))
@@ -73,8 +72,6 @@
       (is (= (sort ["[parent] event"])
              (sort (take-all! os)))))))

-
-
 (deftest event-handler
   (let [parent (event-bus (upstream-router))
         os (async/chan 1024)
@@ -84,44 +81,44 @@
       (route-event parent "event")
       (is (= ["[child] event"] (take-all! os))))))

-(defn hub
-  [os name event-bus-down event-bus-up]
-  (let [event-bus-down' (add-fork event-bus-down (fn [event]
-                                                    (async/put! os (str name " received '" event "' from a child"))))
-        event-bus-up' (add-fork event-bus-up (fn [event]
-                                                (async/put! os (str name " received '" event "' from a parent"))))]
-    [event-bus-down' event-bus-up']))
+(deftest tree-structure
+  (letfn [(hub
+            [os name event-bus-down event-bus-up]
+            (let [event-bus-down' (add-fork event-bus-down (fn [event]
+                                                             (async/put! os (str name " received '" event "' from a child"))))
+                  event-bus-up' (add-fork event-bus-up (fn [event]
+                                                         (async/put! os (str name " received '" event "' from a parent"))))]
+              [event-bus-down' event-bus-up']))

-(defn set-up
-  []
-  (let [os (async/chan 1024)
-        event-bus-down (event-bus (downstream-router))
-        event-bus-up (event-bus (upstream-router))
-        buses (hub os "parent" event-bus-down event-bus-up)]
-    {:os os
-     :broadcast event-bus-up
-     :parent-up (second buses)
-     :child-a-down (first (apply hub os "child A" buses))
-     :child-b-down (first (apply hub os "child B" buses))}))
-;
-(deftest tree-structure
-  (testing "broadcasting to all"
-    (let [{:keys [os broadcast]} (set-up)]
-      (route-event broadcast "event")
-      (is (= (sort ["parent received 'event' from a parent"
-                    "child A received 'event' from a parent"
-                    "child B received 'event' from a parent"])
-             (sort (take-all! os))))))
-  (testing "sending down from child"
-    (let [{:keys [os child-a-down]} (set-up)]
-      (route-event child-a-down "event")
-      (is (= (sort ["parent received 'event' from a child"])
-             (sort (take-all! os))))))
+          (set-up
+            []
+            (let [os (async/chan 1024)
+                  event-bus-down (event-bus (downstream-router))
+                  event-bus-up (event-bus (upstream-router))
+                  buses (hub os "parent" event-bus-down event-bus-up)]
+              {:os           os
+               :broadcast    event-bus-up
+               :parent-up    (second buses)
+               :child-a-down (first (apply hub os "child A" buses))
+               :child-b-down (first (apply hub os "child B" buses))}))]

-  (testing "sending up from parent"
-    (let [{:keys [os parent-up]} (set-up)]
-      (route-event parent-up "event")
+    (testing "broadcasting to all"
+     (let [{:keys [os broadcast]} (set-up)]
+       (route-event broadcast "event")
+       (is (= (sort ["parent received 'event' from a parent"
+                     "child A received 'event' from a parent"
+                     "child B received 'event' from a parent"])
+              (sort (take-all! os))))))
+    (testing "sending down from child"
+      (let [{:keys [os child-a-down]} (set-up)]
+        (route-event child-a-down "event")
+        (is (= (sort ["parent received 'event' from a child"])
+               (sort (take-all! os))))))

-      (is (= (sort ["child A received 'event' from a parent"
-                    "child B received 'event' from a parent"])
-             (sort (take-all! os)))))))
+    (testing "sending up from parent"
+      (let [{:keys [os parent-up]} (set-up)]
+        (route-event parent-up "event")
+
+        (is (= (sort ["child A received 'event' from a parent"
+                      "child B received 'event' from a parent"])
+               (sort (take-all! os))))))))


Add test for novelty function call.

Add test for novelty function call.

--- test/postal/core_tests.cljs
+++ test/postal/core_tests.cljs
@@ -60,11 +60,33 @@
       (s/push! busin {:type :socket/open})
       (m/mlet [frame (to-promise busout)
                :let [frame (pc/frame-decode frame)]]
+        (t/is (= (:cmd frame) :query))
+        (t/is (= (:data frame) nil))
         (s/push! busin {:type :socket/message
                         :payload (pc/frame-encode
                                   {:cmd :response
                                    :id (:id frame)
                                    :data "foobar"})}))
+      )))
+
+(t/deftest novelty-frame-success-test
+  (t/async done
+    (let [[busin busout sock client] (make-client)]
+      (m/mlet [frame (send-handshake sock)
+               result (pc/novelty client :users {:id 1})]
+        (t/is (= (:data result) {:ok true}))
+        (done))
+
+      (s/push! busin {:type :socket/open})
+      (m/mlet [frame (to-promise busout)
+               :let [frame (pc/frame-decode frame)]]
+        (t/is (= (:cmd frame) :novelty))
+        (t/is (= (:data frame) {:id 1}))
+        (s/push! busin {:type :socket/message
+                        :payload (pc/frame-encode
+                                  {:cmd :response
+                                   :id (:id frame)
+                                   :data {:ok true}})}))
       )))

 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


simple dyn robots.txt

simple dyn robots.txt

--- src/nossal/web.clj
+++ src/nossal/web.clj
@@ -4,6 +4,7 @@
             [compojure.route :as route]
             [clojure.java.io :as io]
             [ring.adapter.jetty :as jetty]
+            [ring.util.response :as r]
             [environ.core :refer [env]]
             [hiccup.core :as h]
             [hiccup.page :as page]))
@@ -60,10 +61,15 @@
          ]
         "console.log('Oi!')"))

+(defn robots []
+  (-> (r/response (clojure.string/join "\n" ["User-agent: *" "" "Disallow: /js/" "Disallow: /a/"]))
+      (r/header "Content-Type" "text; charset=utf-8"))))
+
 (defroutes app
   (GET "/" []
        (index))
   (route/resources "/")
+  (GET "/robots.txt" [] (robots))
   (ANY "*" []
        (route/not-found (slurp (io/resource "404.html")))))


Remove "click" to start moving paddle (trackpad friendly).

--- src/pong/main.cljs
+++ src/pong/main.cljs
@@ -99,7 +99,7 @@
     (.fillText ctx "Press the spacebar to start." MID_W 300)
     (aset ctx "font" "italic 12px Helvetica")
     (aset ctx "fillStyle" "slategray")
-    (.fillText ctx "Click/drag the mouse near a paddle to move that paddle." MID_W 370)
+    (.fillText ctx "Position the mouse near a paddle to move that paddle." MID_W 370)
     (.fillText ctx "[ Spacebar ] to pause ." MID_W 410)
     (.fillText ctx "[ Escape ] to quit." MID_W 430)
     (.restore ctx)))
@@ -312,29 +312,17 @@

 (defn- paddle-move!
   [state e]
-  (when (and (= (:mode @state) :playing)
-             (not (nil? (:mouse-status @state))))
+  (when (= (:mode @state) :playing)
     (let [t (.-target e)
           w (- (.-innerWidth js/window) 40)
           h (- (int (/ (* w 9) 16)) 40)
           sh (/ h SCALE-H)
           new-y (int (/ (- (.-clientY e) (.-offsetTop t)) sh))
-          paddle (:mouse-status @state)
+          x (.-clientX e)
+          ww (/ (.-innerWidth js/window) 2)
+          paddle (if (>= x ww) :paddle-2 :paddle-1)
           object (get @state paddle)]
       (swap! state assoc paddle (position! object new-y)))))
-
-(defn- paddle-grab!
-  [state e]
-  (aset (.-style (by-id "canvas")) "cursor" "ns-resize")
-  (let [x (.-clientX e)
-        ww (/ (.-innerWidth js/window) 2)
-        status (if (>= x ww) :paddle-2 :paddle-1)]
-    (swap! state assoc :mouse-status status)))
-
-(defn- paddle-release!
-  [state e]
-  (aset (.-style (by-id "canvas")) "cursor" "default")
-  (swap! state assoc :mouse-status nil))

 (def key-stroke-stream
   (comp (map #(or (get KEYBOARD %) :unknown))
@@ -350,8 +338,6 @@
     (listen! js/window "resize" #(resize! state ctx))
     (listen! js/document "keydown" #(put! events (.-keyCode %)))
     (listen! canvas "mousemove" #(paddle-move! state %))
-    (listen! canvas "mousedown" #(paddle-grab! state %))
-    (listen! canvas "mouseup" #(paddle-release! state %))
     (resize! state ctx)
     (animate-loop! state ctx)))


Call the acker.

Call the acker.

--- src/onyx/peer/task_lifecycle.clj
+++ src/onyx/peer/task_lifecycle.clj
@@ -70,6 +70,7 @@
 (defn munge-apply-fn [{:keys [onyx.core/decompressed] :as event}]
   (if (seq decompressed)
     (let [result (merge event (p-ext/apply-fn event))]
+      (ack-messages result)
       result)
     (merge event {:onyx.core/results []})))


Perf test - sleep until we have a full batch

--- src/onyx/plugin/bench_plugin.clj
+++ src/onyx/plugin/bench_plugin.clj
@@ -30,8 +30,11 @@
     (function/write-batch event))

   (read-batch [_ event]
-    (let [pending (count @pending-messages)
-          max-segments (min (- max-pending pending) batch-size)
+    (let [_ (while (< (- max-pending
+                         (count @pending-messages))
+                      batch-size)
+              (Thread/sleep 100))
+          max-segments batch-size
           segments (->> (flush-swap! retry
                                      #(take max-segments %)
                                      #(subvec % (min max-segments (count %))))


Fix bug not reporting time correctly for videos over one hour

--- src/qcast/util.clj
+++ src/qcast/util.clj
@@ -45,6 +45,8 @@
   ([n] (* n (hours 24))))

 (defn interval->sec [s]
-  (let [units (map parse-int (split s #":"))]
-    (+ (* (first units) 60)
-       (second units))))
+  (->> (split s #":")
+       (map parse-int)
+       reverse
+       (map * (iterate (partial * 60) 1))
+       (reduce +)))


make all trig ugens :kr by default

make all trig ugens :kr by default

--- src/overtone/sc/ugen/trig.clj
+++ src/overtone/sc/ugen/trig.clj
@@ -14,12 +14,14 @@
        :args [{:name "trig" :doc "trigger. Trigger can be any signal. A trigger happens when the signal changes from non-positive to positive."}
               {:name "array", :array true :doc "list of probabilities"}
               {:name "normalize", :default 0 :doc "normalise flag - 0 off, 1 on"}]
+       :default-rate :kr
        :doc "When triggered, returns a random index value based on array as a list of probabilities. By default the list of probabilities should sum to 1.0, when the normalize flag is set to 1, the values get normalized by the ugen (less efficient)"}

       {:name "Trig1"
        :args [{:name "trig", :default 0.0 :doc "trigger. Trigger can be any signal. A trigger happens when the signal changes from non-positive to positive."}
               {:name "dur", :default 0.1 :doc "duration of the trigger output."}]
        :signal-range :unipolar
+       :default-rate :kr
        :doc "outputs one for dur seconds whenever the input goes from negative to positive"}

       {:name "Trig", :extends "Trig1"
@@ -29,6 +31,7 @@
        :args [{:name "trig", :default 0.0 :doc "input trigger signal."}
               {:name "dur", :default 0.1 :doc "delay time in seconds."}]
        :signal-range :unipolar
+       :default-rate :kr
        :check [same-rate-as-first-input]
        :doc "delays an input trigger by dur, ignoring other triggers in the meantime"}

@@ -36,6 +39,7 @@
        :args [{:name "in", :default 0.0 :doc "input trigger signal"}
               {:name "id", :default 0 :doc "an integer that will be passed with the trigger message. This is useful if you have more than one SendTrig in a SynthDef"}
               {:name "value", :default 0.0 :doc "a UGen or float that will be polled at the time of trigger, and its value passed with the trigger message"}]
+       :default-rate :kr
        :num-outs 0
        :check [same-rate-as-first-input]
        :doc "on receiving a trigger sends a :trigger event with id and value. This command is the mechanism that synths can use to trigger events in clients.
@@ -57,6 +61,7 @@
               {:name "cmd-name", :default "/reply" :doc "a string or symbol, as a message name."}
               {:name "values", :default 0.0 :mode :append-sequence :doc "array of ugens, or valid ugen inputs"}
               {:name "reply-id", :default -1 :doc "integer id (similar to send-trig)"}]
+       :default-rate :kr
        :doc "send an array of values from the server to all notified clients

 cmdName
@@ -70,6 +75,7 @@
       {:name "Latch"
        :args [{:name "in", :default 0.0 :doc "input signal."}
               {:name "trig", :default 0.0 :doc "trigger. Trigger can be any signal. A trigger happens when the signal changes from non-positive to positive."}]
+       :default-rate :kr
        :doc "holds the input signal value when triggered"}

       {:name "Gate", :extends "Latch"
@@ -79,6 +85,7 @@
        :args [{:name "trig", :default 0.0 :doc "trigger. Trigger can be any signal. A trigger happens when the signal changes from non-positive to positive."}
               {:name "reset", :default 0.0 :doc "resets the counter to zero when triggered."}]
        :check [same-rate-as-first-input]
+       :default-rate :kr
        :doc "each input trigger increments a counter value that is output."}

       {:name "SetResetFF", :extends "PulseCount"
@@ -104,31 +111,37 @@
               {:name "step", :default 1 :doc "step value each trigger. May be negative."}
               {:name "resetval" :default 1 :doc "value to which the counter is reset when it receives a reset trigger."}] ; TODO MAYBE? allow :default :min
        :check [same-rate-as-first-input]
+       :default-rate :kr
        :doc "triggers increment a counter which is output as a signal. The counter loops around from max to min by step increments"}

       {:name "PulseDivider"
        :args [{:name "trig", :default 0.0 :doc "trigger. Trigger can be any signal. A trigger happens when the signal changes from non-positive to positive."}
               {:name "div", :default 2.0 :doc "number of pulses to divide by."}
               {:name "start-val", :default 0.0 :doc "starting value for the trigger count. This lets you start somewhere in the middle of a count, or if startCount is negative it adds that many counts to the first time the output is triggers."}]
+       :default-rate :kr
        :doc "outputs a trigger every div input triggers"}

       {:name "ToggleFF"
        :args [{:name "trig", :default 0.0 :doc "trigger input"}]
+       :default-rate :kr
        :doc "flip-flops between zero and one each trigger"}

       {:name "ZeroCrossing"
        :args [{:name "in", :default 0.0 :doc "input signal"}]
+       :default-rate :kr
        :check [same-rate-as-first-input]
        :doc "Outputs a frequency based upon the distance between interceptions of the X axis. The X intercepts are determined via linear interpolation so this gives better than just integer wavelength resolution. This is a very crude pitch follower, but can be useful in some situations."}

       {:name "Timer"
        :args [{:name "trig", :default 0.0 :doc "trigger input"}]
        :check [same-rate-as-first-input]
+       :default-rate :kr
        :doc "outputs time since last trigger"}

       {:name "Sweep"
        :args [{:name "trig", :default 0.0 :doc "trigger input"}
               {:name "rate", :default 1.0 :doc "rate in seconds"}]
+       :default-rate :kr
        :doc "outputs a linear increasing signal by rate/second on trigger"}

       {:name "Phasor"
@@ -137,11 +150,13 @@
               {:name "start", :default 0.0 :doc "Starting point of the ramp"}
               {:name "end", :default 1.0 :doc "End point of the ramp"}
               {:name "resetPos", :default 0.0  :doc "The value to jump to upon receiving a trigger"}]
+       :default-rate :kr
        :doc "Phasor is a linear ramp between start and end values. When its trigger input crosses from non-positive to positive, Phasor's output will jump to its reset position. Upon reaching the end of its ramp Phasor will wrap back to its start. N.B. Since end is defined as the wrap point, its value is never actually output."}

       {:name "PeakFollower"
        :args [{:name "in", :default 0.0 :doc "input signal."}
               {:name "decay", :default 0.999 :doc "decay factor."}]
+       :default-rate :kr
        :doc "outputs the peak signal amplitude, falling with decay over time until reaching signal level"}

       {:name "Pitch"
@@ -165,6 +180,7 @@
        :args [{:name "in", :default 0.0 :doc "input signal"}
               {:name "lo", :default 0.0 :doc "low threshold"}
               {:name "hi", :default 1.0 :doc "high threshold"}]
+       :default-rate :kr
        :doc "Tests if a signal is between lo and hi"}

       {:name "Fold", :extends "InRange"
@@ -174,6 +190,7 @@
        :args [{:name "in", :default 0.0 :doc "The signal to be clipped"}
               {:name "lo", :default 0.0, :doc "Low threshold of clipping. Must be less then hi"}
               {:name "hi", :default 1.0, :doc "High threshold of clipping. Must be greater then lo"}]
+       :default-rate :kr
        :doc "Clip a signal outside given thresholds. This differs from the BinaryOpUGen clip2 in that it allows one to set both low and high thresholds."}

       {:name "Wrap", :extends "InRange"
@@ -191,6 +208,7 @@
               {:name "top"}
               {:name "right"}
               {:name "bottom"}]
+       :default-rate :kr
        :doc "outputs one if the 2d coordinate of x,y input values falls inside a rectangle, else zero"}

       {:name "Trapezoid"
@@ -198,11 +216,13 @@
               {:name "a", :default 0.2}
               {:name "b", :default 0.4}
               {:name "c", :default 0.6}
-              {:name "d", :default 0.8}]}
+              {:name "d", :default 0.8}]
+       :default-rate :kr}

       {:name "MostChange"
        :args [{:name "a", :default 0.0 :doc "first input"}
               {:name "b", :default 0.0 :doc "second input"}]
+       :default-rate :kr
        :doc "output whichever signal changed the most"}

       {:name "LeastChange", :extends "MostChange"
@@ -211,4 +231,5 @@
       {:name "LastValue"
        :args [{:name "in", :default 0.0 :doc "input signal"}
               {:name "diff", :default 0.01 :doc "difference threshold"}]
+       :default-rate :kr
        :doc "output the last value before the input changed by a threshold of diff"}])


simplify by using remove instead of filter.

--- clojure/word-count/word-count.clj
+++ clojure/word-count/word-count.clj
@@ -5,7 +5,7 @@
   (split (lower-case str) #"\W"))

 (defn- filter-words [str]
-  (filter (comp not blank?) (tokenize str)))
+  (remove blank? (tokenize str)))

 (defn word-count [str]
   (frequencies (filter-words str)))


lein-release plugin: preparing 0.4.13 release

--- re_view/project.clj
+++ re_view/project.clj
@@ -1,4 +1,4 @@
-(defproject re-view "0.4.13-SNAPSHOT"
+(defproject re-view "0.4.13"
   :description "ClojureScript React Library"
   :url "https://www.github.com/braintripping/re-view/tree/master/re_view"
   :license {:name "Eclipse Public License"


(maint) Use introspection of the metrics-registry

Here we rewrite get-cthun-metrics in terms of an inspection of
metrics.core/default-registry.  This means we can add new metrics
without needing to update the function in future.

--- src/puppetlabs/cthun/metrics.clj
+++ src/puppetlabs/cthun/metrics.clj
@@ -2,9 +2,10 @@
   (:require [clojure.tools.logging :as log]
             [clojure.java.jmx :as jmx]
             [clj-time.core :as time]
+            [metrics.core]
             [metrics.counters :as counters]
             [metrics.meters :as meters]
-            [metrics.timers :refer [timer]]
+            [metrics.timers :as timers]
             [cheshire.core :as cheshire]))

 (def total-messages-in (counters/counter ["puppetlabs.cthun" "global" "total-messages-in"]))
@@ -12,17 +13,23 @@
 (def active-connections (counters/counter ["puppetlabs.cthun" "global" "active-connections"]))
 (def rate-messages-in (meters/meter ["puppetlabs.cthun" "global" "rate-messages-in"]))
 (def rate-messages-out (meters/meter ["puppetlabs.cthun" "global" "rate-messages-out"]))
-(def time-in-on-connect (timer ["puppetlabs.cthun" "handlers" "time-in-on-connect"]))
-(def time-in-on-text (timer ["puppetlabs.cthun" "handlers" "time-in-on-text"]))
-(def time-in-on-close (timer ["puppetlabs.cthun" "handlers" "time-in-on-close"]))
-(def time-in-message-queueing (timer ["puppetlabs.cthun" "global" "time-in-message-queueing"]))
+(def time-in-on-connect (timers/timer ["puppetlabs.cthun" "handlers" "time-in-on-connect"]))
+(def time-in-on-text (timers/timer ["puppetlabs.cthun" "handlers" "time-in-on-text"]))
+(def time-in-on-close (timers/timer ["puppetlabs.cthun" "handlers" "time-in-on-close"]))
+(def time-in-message-queueing (timers/timer ["puppetlabs.cthun" "global" "time-in-message-queueing"]))

 (defn- get-cthun-metrics
   "Returns cthun specific metrics as a map"
   []
-  {:total-messages-in (counters/value total-messages-in)
-   :total-messages-out (counters/value total-messages-out)
-   :active-connections (counters/value active-connections)})
+  (reduce into {}
+          [(map (fn [[k v]] {k (meters/rates v)}) (.getMeters metrics.core/default-registry))
+           (map (fn [[k v]] {k (counters/value v)}) (.getCounters metrics.core/default-registry))
+           (map (fn [[k v]] {k {:rates (timers/rates v)
+                                :mean (timers/mean v)
+                                :std-dev (timers/std-dev v)
+                                :percentiles (timers/percentiles v)
+                                :largest (timers/largest v)
+                                :smallest (timers/smallest v)} }) (.getTimers metrics.core/default-registry))]))

 (defn- get-memory-metrics
   "Returns memory related metrics as a map"


Change empty strings to NULL when updating records

--- src/tesq/query.clj
+++ src/tesq/query.clj
@@ -88,21 +88,35 @@
   (str "SELECT * FROM " table " WHERE id=" id))

+(defn nil-string
+  "If s is empty return nil, otherwise s."
+  [s]
+  (if (empty? s) nil s))
+
+
+(defn mapvals
+  "Map f over vals in map, preserve keys."
+  [f m]
+  (into {} (for [[k v] m] [k (f v)])))
+
+
 (defn update-record
   "Params is map of key/val field/value pairs, all strings.
   Must contain 'table' and 'id' keys."
   [params]
   (let [table (:table params)
 		id (:id params)
-		fields (dissoc params :table :id)]
+		fields (mapvals nil-string (dissoc params :table :id))]
 	(str "UPDATE " table " SET "
 		 (trim-comma
 		  (reduce str
 				  (for [[k v] fields]
 					(str
 					 (backtick (name k)) "="
-					 (if (numeric-string? v) v (squote v)) ","
-					 )
-					)))
+					 (cond
+					  (empty? v) "NULL"
+					  (numeric-string? v) v
+					  :else (squote v))
+					 ","))))
 		 " WHERE id=" id ";")))


Be sleepier

Be sleepier

--- integration-tests/src/test/clojure/immutant/integs/msg/destination_in_multiple_apps.clj
+++ integration-tests/src/test/clojure/immutant/integs/msg/destination_in_multiple_apps.clj
@@ -46,22 +46,22 @@

 (deftest both-queue-apps-should-be-up
   (is (= :success (get-as-data "/q1")))
-  (is (= :ham (deref (msg/request "queue.echo" :ham) 5000 nil)))
+  (is (= :ham (deref (msg/request "queue.echo" :ham) 15000 nil)))
   (is (= :success (get-as-data "/q1")))

   (is (= :success (get-as-data "/q2")))
-  (is (= :ham (deref (msg/request "queue.echo" :ham) 5000 nil)))
+  (is (= :ham (deref (msg/request "queue.echo" :ham) 15000 nil)))
   (is (= :success (get-as-data "/q2"))))

 (deftest both-topic-apps-should-be-up
   (is (= :success (get-as-data "/t1")))
   (msg/publish "topic.echo" :ham)
-  (is (= :ham (msg/receive "queue.result" :timeout 5000)))
+  (is (= :ham (msg/receive "queue.result" :timeout 15000)))
   (is (= :success (get-as-data "/t1")))

   (is (= :success (get-as-data "/t2")))
   (msg/publish "topic.echo" :ham)
-  (is (= :ham (msg/receive "queue.result" :timeout 5000)))
+  (is (= :ham (msg/receive "queue.result" :timeout 15000)))
   (is (= :success (get-as-data "/t2"))))


Enable treating warnings as errors and list acceptable warnings

--- src/status_im/utils/build.clj
+++ src/status_im/utils/build.clj
@@ -1,10 +1,21 @@
 (ns status-im.utils.build
   (:require [cljs.analyzer :as analyzer]))

+;; Some warnings are unavoidable due to dependencies. For example, reagent 0.6.0
+;; has a warning in its util.cljs namespace. Adjust this as is necessary and
+;; unavoidable warnings arise.
+(def acceptable-warning?
+  #{
+    "Protocol IFn implements method -invoke with variadic signature (&)" ;; reagent 0.6.0 reagent/impl/util.cljs:61
+    })
+
+(defn nil-acceptable-warning [s]
+  (when-not (acceptable-warning? s)
+    s))
+
 (defn warning-handler [warning-type env extra]
   (when (warning-type analyzer/*cljs-warnings*)
-    (when-let [s (analyzer/error-message warning-type extra)]
+    (when-let [s (nil-acceptable-warning (analyzer/error-message warning-type extra))]
       (binding [*out* *err*]
         (println (analyzer/message env (str "\u001B[31mWARNING\u001B[0m: " s))))
-      ;; TODO Do not enable yet as our current reagent version generates warnings
-      #_(System/exit 1))))+      (System/exit 1))))


Button to delete param keys.

Button to delete param keys.

--- sonic-jam/src/sonic_jam/core.cljs
+++ sonic-jam/src/sonic_jam/core.cljs
@@ -109,7 +109,10 @@
                 closer #js {:onClick #(om/update-state! owner (fn [s] (merge s {:state :init})))
                             :style #js {:color (:link theme)}}
                 canceller #js {:onClick #(om/update-state! owner (fn [s] (merge s {:state :open})))
-                               :style #js {:color (:link theme)}}]
+                               :style #js {:color (:link theme)}}
+                delete #(do
+                          (om/transact! cursor (fn [c] (dissoc c %)))
+                          (go (>! set-state-ch id)))]
             (condp = (:state state)
               :init (dom/span #js {:onClick #(om/update-state! owner (fn [s] (merge s {:state :open})))
                                    :style #js {:color (:link theme)}} "{..}")
@@ -121,7 +124,8 @@
                                                 (dom/td nil nil)
                                                 (dom/td nil nil))]
                                        (map (fn [k v] (dom/tr nil
-                                                              (dom/td nil nil)
+                                                              (dom/td #js {:onClick #(delete k)
+                                                                           :style #js {:color (:link theme)}} "X")
                                                               (dom/td nil (str k ":"))
                                                               (dom/td #js {:onClick #(om/update-state! owner
                                                                                (fn [s] (merge s {:state :editing
@@ -152,6 +156,8 @@
                                                    (dom/td nil nil)
                                                    (dom/td nil nil))]
                                           (map (fn [k v] (dom/tr nil
+                                                                 (dom/td #js {:onClick #(delete k)
+                                                                              :style #js {:color (:link theme)}} "X")
                                                                  (dom/td nil (str k ":"))
                                                                  (if (= k (:field state))
                                                                    (dom/td nil
@@ -187,7 +193,8 @@
                                                  (dom/td nil nil)
                                                  (dom/td nil nil))]
                                         (map (fn [k v] (dom/tr nil
-                                                               (dom/td nil nil)
+                                                               (dom/td #js {:onClick #(delete k)
+                                                                            :style #js {:color (:link theme)}} "X")
                                                                (dom/td nil (str k ":"))
                                                                (dom/td #js {:onClick #(om/update-state! owner
                                                                                (fn [s] (merge s {:state :editing
@@ -219,7 +226,8 @@
                                                  (dom/td nil nil)
                                                  (dom/td nil nil))]
                                         (map (fn [k v] (dom/tr nil
-                                                               (dom/td nil nil)
+                                                               (dom/td #js {:onClick #(delete k)
+                                                                            :style #js {:color (:link theme)}} "X")
                                                                (dom/td nil (str k ":"))
                                                                (dom/td #js {:onClick #(om/update-state! owner
                                                                                (fn [s] (merge s {:state :editing


Do not reduce track beat width below 1.

Do not reduce track beat width below 1.

--- sonic-jam/src/sonic_jam/core.cljs
+++ sonic-jam/src/sonic_jam/core.cljs
@@ -623,10 +623,8 @@
                               halved-tracks (map (fn [t]
                                                    (let [beats (get t "beats")]
                                                      (assoc t "beats"
-                                                            (take (int (/ (count beats) 2)) beats))))
+                                                            (take (max (int (/ (count beats) 2)) 1) beats))))
                                                  tracks)]
-                          (print tracks)
-                          (print halved-tracks)
                           (om/transact! cursor (fn [c] (assoc cursor "tracks" (clj->js halved-tracks))))
                           (go (>! set-state-ch id)))]
         (condp = (:state state)
@@ -688,7 +686,6 @@
                                            :style #js {:background (:link-bar theme)
                                                        :color (:link theme)}}
                                       (if (:grid-expanded state) " - " " + "))
-
                               (dom/td #js {:style #js {:padding "0 0 0 10px"}}
                                       (if-not (:grid-expanded state)
                                         (dom/div nil " ")


renamed method

renamed method

--- cljx/plongeur-clj/src/kierros/core.clj
+++ cljx/plongeur-clj/src/kierros/core.clj
@@ -40,8 +40,8 @@
         sink-chans       (main source-chans)
         _                (weld-cycle! sink-chans sink-proxy-chans)
         close-all!       (fn []
-                           (warn (u/deco "cycle stopping"))
+                           (warn (u/frame "cycle stopping"))
                            (doseq [ch (vals sink-proxy-chans)] (close! ch)))]
-    (info (u/deco "cycle running"))
+    (info (u/frame "cycle running"))
     {:CYCLE sink-chans
      :SHUTDOWN close-all!}))


Allow only create groups from valid selection.

--- src/uxbox/data/workspace.cljs
+++ src/uxbox/data/workspace.cljs
@@ -352,8 +352,12 @@
                         (assoc $ :group group)
                         (assoc-in state [:shapes-by-id id] $)))
                     state
-                    shapes))]
-    (reify rs/UpdateEvent
+                    shapes))
+          (valid-selection? [shapes]
+            (let [groups (into #{} (map :group shapes))]
+              (= 1 (count groups))))]
+    (reify
+      rs/UpdateEvent
       (-apply-update [_ state]
         (let [shapes-by-id (get state :shapes-by-id)
               sid (random-uuid)
@@ -365,11 +369,13 @@
                     :items (into [] selected)
                     :id sid
                     :page pid}]
-          (as-> state $
-            (update-shapes-on-index $ selected' sid)
-            (update-shapes-on-page $ pid selected sid)
-            (update $ :shapes-by-id assoc sid group)
-            (update $ :workspace assoc :selected #{})))))))
+          (if (valid-selection? selected')
+            (as-> state $
+              (update-shapes-on-index $ selected' sid)
+              (update-shapes-on-page $ pid selected sid)
+              (update $ :shapes-by-id assoc sid group)
+              (update $ :workspace assoc :selected #{}))
+            state))))))

 (defn delete-selected
   "Deselect all and remove all selected shapes."


Accept collection parameters from post data instead of url.

--- src/uxbox/frontend/images.clj
+++ src/uxbox/frontend/images.clj
@@ -22,6 +22,7 @@
 (s/def ::file ::us/uploaded-file)
 (s/def ::width ::us/integer-string)
 (s/def ::height ::us/integer-string)
+(s/def ::collection (s/nilable ::us/uuid-string))
 (s/def ::mimetype string?)

 (def +thumbnail-options+ {:src :path
@@ -83,11 +84,13 @@
 ;; --- Create image

 (s/def ::create-image
-  (s/keys :req-un [::file ::width ::height ::mimetype] :opt-un [::us/id]))
+  (s/keys :req-un [::file ::width ::height ::mimetype]
+          :opt-un [::us/id ::collection]))

 (defn create-image
-  [{user :identity params :route-params  data :data}]
-  (let [{:keys [file id width height mimetype] :as data} (us/conform ::create-image data)
+  [{user :identity data :data}]
+  (let [{:keys [file id width height
+                mimetype collection]} (us/conform ::create-image data)
         id (or id (uuid/random))
         filename (paths/base-name file)
         storage media/images-storage]
@@ -98,7 +101,7 @@
                            :width width
                            :height height
                            :mimetype mimetype
-                           :collection (uuid/from-string (:id params))
+                           :collection collection
                            :name filename
                            :path (str path)}))


remove unused requires

remove unused requires

--- src/vignette/storage/core.clj
+++ src/vignette/storage/core.clj
@@ -1,8 +1,6 @@
 (ns vignette.storage.core
   (:require [vignette.media-types :as mt]
-            [vignette.storage.protocols :refer :all]
-            [vignette.util.query-options :as q]
-            [vignette.storage.static-assets :as sa]))
+            [vignette.storage.protocols :refer :all]))

 (defn get*
   [store object-map get-path]


document email bug

document email bug

--- src/wombats/handlers/auth.clj
+++ src/wombats/handlers/auth.clj
@@ -89,6 +89,8 @@
          (let [access-token @(get-access-token {:client_id client-id
                                                 :client_secret client-secret
                                                 :code code})
+               ;; TODO BUG If the user does not have their email setup on GH this
+               ;; step will fail
                user (when access-token
                       (parse-user-response @(get-github-user access-token)))
                create-or-update-user (dao/get-fn :create-or-update-user context)


+default: verbs are not reflexive.

+default: verbs are not reflexive.

--- src/babel/francais/lexicon.cljc
+++ src/babel/francais/lexicon.cljc
@@ -964,6 +964,12 @@
                                }}}
                {:synsem {:sem {:obj :unspec}}})

+      ;; default: reflexive=false.
+      (if-then {:synsem {:cat :verb
+                         :aux false
+                         :sem {:reflexive false}}}
+               {:synsem {:sem {:reflexive false}}})
+
       ;; TODO: use lexiconfn/if-then here, like espanol/lexicon does.
       ;; default: essere=false
       (map-function-on-map-vals


working on language-model-independent indices

--- src/babel/italiano/grammar.cljc
+++ src/babel/italiano/grammar.cljc
@@ -20,6 +20,18 @@
    [clojure.core.cache :as cache]
    [clojure.repl :refer (doc)]
    [dag_unify.core :refer (fail? get-in remove-matching-keys strip-refs unify)]))
+
+(def index-lexicon-on-paths
+  [[:italiano :italiano]
+   [:synsem :aux]
+   [:synsem :cat]
+   [:synsem :sem :pred]])
+
+(defn index-by-paths [lexicon]
+  (map (fn [path]
+         {:path path
+          :lexemes (map-subset-by-path lexicon path)})
+       index-lexicon-on-paths))

 (defn fo-ps [expr]
   (parse/fo-ps expr fo))


implemented Sports Hopper

implemented Sports Hopper

--- src/clj/game/cards-hardware.clj
+++ src/clj/game/cards-hardware.clj
@@ -509,6 +509,12 @@
    {:in-play [:memory 1]
     :recurring 2
     :events {:successful-trace {:req (req run) :effect (effect (damage :brain 1 {:card card}))}}}
+
+   "Sports Hopper"
+   {:in-play [:link 1]
+    :abilities [{:label "Draw 3 cards"
+                 :msg "draw 3 cards"
+                 :effect (effect (trash card {:cause :ability-cost}) (draw 3))}]}

    "Spy Camera"
    {:abilities [{:cost [:click 1]


Display the filter in the comic-list component

--- src/cljs/comic_reader/main.cljs
+++ src/cljs/comic_reader/main.cljs
@@ -45,13 +45,17 @@

 (defn comic-list []
   (let [site (rf/subscribe [:site])
-        comic-list (rf/subscribe [:comic-list])]
+        comic-list (rf/subscribe [:comic-list])
+        comic-list-filter (rf/subscribe [:comic-list-filter])]
     (fn []
       (let [site       @site
-            comic-list @comic-list]
+            comic-list @comic-list
+            cl-filter @comic-list-filter]
         [:div
          [:h1 "Comics from " (titlize site
                                       :to-spaces #"-")]
+         (when cl-filter
+           [:h3 "Filtered by " cl-filter])
          (when (and site comic-list)
            [:ul (map (id-btn-for-callback
                       (fn [item]


Add initialization for the buffer-size in app-db

--- src/cljs/comic_reader/main.cljs
+++ src/cljs/comic_reader/main.cljs
@@ -28,6 +28,11 @@
   (reader/setup!)
   (site-list/setup!)
   (comic-list/setup!)
+
+  (re-frame/reg-event-db
+   :init-db
+   (fn [db _]
+     (assoc db :buffer-size 5)))

   (re-frame/reg-sub
    :page-key
@@ -88,6 +93,7 @@
 (defn ^:export main []
   (enable-console-print!)
   (setup!)
+  (re-frame/dispatch [:init-db])
   (re-frame/dispatch [:view-sites])
   (reagent/render-component [main-panel-container]
                             (.getElementById js/document "app")))


Routing to specific items

Routing to specific items

Main page show Top story

--- src/cljs/hacker_agent/core.cljs
+++ src/cljs/hacker_agent/core.cljs
@@ -131,40 +131,48 @@
 (defmethod item nil [_]
   [:p "Cannot render item"])

-(defn hacker []
+(defn hacker [id]
   [:div
-   [:h2 "Home Page"]
-   [:div
-    [:h3 "Top Story"]
-    [render (global-state :top-story)]
-    ]
+   [:h2 "Hacker News"]
+   [render id]
    ])

 ;; -------------------------
 ;; Views

-(defmulti page identity)
+(defmulti page :current-page)

 (defmethod page :default [_]
   [:div "Invalid/Unknown route"])

-(defmethod page :hacker [_]
-  [hacker])
+(defmethod page :main [state]
+  [hacker (global-state :top-story)])

-(defn main-page []
-  [:div [page :hacker]])
+(defmethod page :item [state]
+  [hacker (:current-item state)])
+
+(defn main-page [state]
+  [page @state])

 ;; -------------------------
 ;; Routes
 (secretary/set-config! :prefix "#")

 (secretary/defroute "/" []
-  (swap! app-state assoc :current-page :hacker))
+  (reset! app-state {:current-page :main
+                     :current-item (global-state :top-story)})
+)
+
+(secretary/defroute "/items/:id" [id]
+  (swap! app-state assoc
+         :current-page :item
+         :current-item id)
+)

 ;; -------------------------
 ;; Initialize app
 (defn init! []
-  (reagent/render-component [main-page] (.getElementById js/document "app")))
+  (reagent/render-component [main-page app-state] (.getElementById js/document "app")))

 ;; -------------------------
 ;; History


Made cursor fn only for associative cursors and added read-only support to lens-cursor.

--- src/clojure/freactive/core.cljc
+++ src/clojure/freactive/core.cljc
@@ -550,44 +550,50 @@
                 false
                 nil))))

-(defn lens-cursor [parent getter setter]
-  #?(:cljs
-     (let [binding-info (get-binding-fns parent)
-           id (new-reactive-id)]
-       (Cursor.
-        id
-        parent
-        nil
-        (fn [this] (getter ((.-raw-deref binding-info) parent)))
-        (fn [this f & args]
-          (swap! parent
-                 (fn [x] (setter x (apply f (getter x) args)))))
-        (fn [this]
-          ((.-add-watch binding-info) parent id
-           (fn [k r o n] (.updateCursor this (getter n) *change-ks*))))
-        (fn [this] ((.-remove-watch binding-info) parent id))
-        nil
-        nil
-        nil
-        #js {}
-        0
-        (getter @parent)
-        nil
-        true
-        nil))))
+(defn lens-cursor
+  "Creates a lens cursor. If the 1-arity version is used or setter is nil, the
+cursor is read-only."
+  ([parent getter]
+   (lens-cursors parent getter nil))
+  ([parent getter setter]
+   #? (:cljs
+       (let [binding-info (get-binding-fns parent)
+             id (new-reactive-id)]
+         (Cursor.
+          id
+          parent
+          nil
+          (fn [this] (getter ((.-raw-deref binding-info) parent)))
+          (if setter
+            (fn [this f & args]
+              (swap! parent
+                     (fn [x] (setter x (apply f (getter x) args)))))
+            (fn [] (throw (ex-info "Cursor is read-only"))))
+          (fn [this]
+            ((.-add-watch binding-info) parent id
+             (fn [k r o n] (.updateCursor this (getter n) *change-ks*))))
+          (fn [this] ((.-remove-watch binding-info) parent id))
+          nil
+          nil
+          nil
+          #js {}
+          0
+          (getter @parent)
+          nil
+          true
+          nil)))))

 (defn root-cursor [atom-like]
   (lens-cursor atom-like identity (fn [old new] new)))

 (defn cursor
-  ([] (atom nil))
-  ([parent] (root-cursor parent))
-  ([parent korks]
-   (if (sequential? korks)
-     (descendant-cursor parent korks)
-     (child-cursor parent korks)))
-  ([parent getter setter]
-   (lens-cursor parent getter setter)))
+  "Creates an associative cursor from the given parent to the provided
+key or key-sequence (korks). Lens cursors should be created explicitly
+using the lens-cursor function."
+  [parent korks]
+  (if (sequential? korks)
+    (descendant-cursor parent korks)
+    (child-cursor parent korks)))

 ;; Reactive Expression Implementation

@@ -899,6 +905,8 @@
   (assert (>= before-idx 0))
   (-target-insert this elem before-idx))

+(defn target-count [this] (-target-count this))
+
 (defn target-peek [this idx]
   (when (and (>= 0 idx) (<= (- (target-count this) 1)))
     (-target-peek this idx)))
@@ -906,8 +914,6 @@
 (defn target-take [this idx]
   (assert (>= idx 0))
   (-target-take this idx))
-
-(defn target-count [this] (-target-count this))

 (defn target-move [this idx before-idx]
   (assert (>= idx 0))


Avoid passing around a parameter in the view.

--- src/clojure/staircase/views.clj
+++ src/clojure/staircase/views.clj
@@ -154,12 +154,12 @@
      [:div.panel.panel-default.first-step {:ng-class "(tool.action ? 'with-action ' : '') + getHeightClass(tool)"}
       [:div.panel-heading
        [:i.fa.fa-arrows-alt.pull-right {:ng-click "expandTool(tool)"}]
-       [:i.fa.fa-undo.pull-right {:ng-show "tool.resettable" :ng-click "resetTool(tool)"}]
+       [:i.fa.fa-undo.pull-right {:ng-show "tool.resettable" :ng-click "reset()"}]
        "{{tool.heading}}"]
       [:div.panel-body
        [:native-tool {:tool "tool"}]]
       [:div.panel-footer {:ng-if "tool.action"}
-       [:button.btn.btn-default.pull-right "{{tool.action}}"]
+       [:button.btn.btn-default.pull-right {:ng-click "act()"} "{{tool.action}}"]
        [:div.clearfix]]
       ]]


Add a warning when no .class files are found in fileset

--- src/radicalzephyr/boot_junit.clj
+++ src/radicalzephyr/boot_junit.clj
@@ -32,11 +32,6 @@
                     (str/split #"/")
                     drop-last)))

-(defn- all-class-names [user-files]
-  (->> user-files
-       (core/by-ext [".java"])
-       (map path->class-name)))
-
 (core/deftask junit
   "Run the jUnit test runner."
   [c class-names  CLASSNAME #{str} "The set of Java class names to run tests from."
@@ -46,7 +41,11 @@
     (core/cleanup (worker-pods :shutdown))
     (core/with-pre-wrap fileset
       (let [worker-pod (worker-pods :refresh)
-            all-class-names (all-class-names (core/input-files fileset))]
+            java-files (core/by-ext [".java"] (core/input-files fileset))
+            class-files (core/by-ext [".class"] (core/output-files fileset))
+            all-class-names (map path->class-name java-files)]
+        (when-not (seq class-files)
+          (util/warn "No .class files found in `output-files`, did you forget to run `javac`?\n"))
         (if-let [result (pod/with-eval-in worker-pod
                           (run-tests-in-classes '~all-class-names
                                                 :classes ~class-names


Add version command

Add version command

--- src/leiningen/pallet_release.clj
+++ src/leiningen/pallet_release.clj
@@ -1,9 +1,18 @@
 (ns leiningen.pallet-release
   "Pallet release commands to support the PalletOps release workflow."
   (:require
+   [clojure.java.io :refer [input-stream resource]]
    [leiningen.pallet-release.core :refer [fail]]
    [leiningen.pallet-release.release :as release]
    [leiningen.pallet-release.travis :as travis]))
+
+(def prop-file
+  "META-INF/maven/lein-pallet-release/lein-pallet-release/pom.properties")
+
+(defn version []
+  (let [props (doto (java.util.Properties.)
+                (.load (input-stream (resource prop-file))))]
+    (println "lein-pallet-release" (get props "version"))))

 (defn pallet-release
   "Pallet release commands to support the PalletOps release workflow."
@@ -18,4 +27,5 @@
     "finish" (release/finish project args)
     "push" (travis/push project args)
     "publish" (release/publish project args)
+    "version" (version)
     (fail "Known cmds are init, auth, start, finish, and publish.")))


add missing use

add missing use

git-svn-id: 03a8048b5ee8463be5048a3801110fb50f378627@8017 d0ab736e-dc22-4aeb-8dc9-08def0aa14fd

--- acqEngine/src/org/micromanager/acq_engine.clj
+++ acqEngine/src/org/micromanager/acq_engine.clj
@@ -24,7 +24,7 @@
            get-msp MultiStagePosition-to-map ChannelSpec-to-map
            get-pixel-type get-current-time-str rekey
            data-object-to-map str-vector double-vector
-           get-property-value]]
+           get-property-value edt]]
         [org.micromanager.sequence-generator :only [generate-acq-sequence
                                                     make-property-sequences]])
   (:require [clojure.set])


fix a misplaced paren

fix a misplaced paren

git-svn-id: 03a8048b5ee8463be5048a3801110fb50f378627@6222 d0ab736e-dc22-4aeb-8dc9-08def0aa14fd

--- acqEngine/src/org/micromanager/acq_engine.clj
+++ acqEngine/src/org/micromanager/acq_engine.clj
@@ -263,8 +263,8 @@
        (or (:slice event) 0)
        (if (:relative-z event)
          (or (get-z-position (:position event) z-drive)
-             (@state :reference-z-position)))
-         0)))
+             (@state :reference-z-position))
+         0))))

 (defn make-event-fns [event out-queue]
   (list


fix REPL timing issue added in 2.8.95

fix REPL timing issue added in 2.8.95

really need to rework this REPL init logic. dealing with
multiple runtimes and client sessions shouldn't be this
messy.

fixes #686

--- src/main/shadow/cljs/devtools/server/worker/impl.clj
+++ src/main/shadow/cljs/devtools/server/worker/impl.clj
@@ -171,6 +171,8 @@
                                                           :event event})
               (async/offer! log-chan {:type :build-log :event event})))

+          repl-init-ns
+          (get-in build-config [:devtools :repl-init-ns] 'cljs.user)

           {:keys [npm extra-config-files] :as build-state}
           (-> (server-util/new-build build-config :dev (:cli-opts worker-state {}))
@@ -181,6 +183,8 @@
                       ;; temp hack for repl/setup since it needs access to repl-init-ns but configure wasn't called yet
                       :shadow.build/config build-config
                       })
+              ;; FIXME: work around issues where this is used by clients before a runtime connects
+              (assoc :repl-state {:current-ns repl-init-ns})
               (build/configure :dev build-config (:cli-opts worker-state {})))

           extra-config-files
@@ -415,15 +419,15 @@
   worker-state)

 (defn ensure-repl-init [{:keys [build-state] :as worker-state}]
-  (let [{:keys [repl-state]} build-state]
-    (if repl-state
-      worker-state
-      ;; ensure that all REPL related things have been compiled
-      ;; so the runtime can properly load them
-      ;; delaying this until a runtime actually connects
-      (let [build-state (repl/prepare build-state)]
-        (assoc worker-state :build-state build-state)
-        ))))
+  ;; FIXME: repl-state should be coupled to the client "session" not the runtime
+  (if (seq (get-in build-state [:repl-state :repl-sources]))
+    worker-state
+    ;; ensure that all REPL related things have been compiled
+    ;; so the runtime can properly load them
+    ;; delaying this until a runtime actually connects
+    (let [build-state (repl/prepare build-state)]
+      (assoc worker-state :build-state build-state)
+      )))

 (defmethod do-proc-control :runtime-connect
   [worker-state {:keys [runtime-id runtime-out runtime-info]}]


fix race condition in REPL code

fix race condition in REPL code

could end up trying to load files before they were written

--- src/main/shadow/cljs/devtools/server/worker/impl.clj
+++ src/main/shadow/cljs/devtools/server/worker/impl.clj
@@ -12,6 +12,7 @@
             [shadow.build :as build]
             [shadow.build.api :as build-api]
             [shadow.build.api :as cljs]
+            [shadow.build.async :as basync]
             [shadow.build.compiler :as build-comp]
             [shadow.cljs.devtools.server.util :as server-util]
             [shadow.cljs.devtools.server.system-bus :as sys-bus]
@@ -612,7 +613,10 @@
               (count (get-in build-state [:repl-state :repl-actions]))

               {:keys [repl-state] :as build-state}
-              (repl/process-input build-state input-text)
+              (-> build-state
+                  (repl/process-input input-text)
+                  ;; ensure everything async is finished before sending stuff to clients
+                  (basync/wait-for-pending-tasks!))

               new-actions
               (->> (subvec (:repl-actions repl-state) start-idx)


fix a few issues

fix a few issues

--- src/main/shadow/cljs/devtools/targets/npm_module.clj
+++ src/main/shadow/cljs/devtools/targets/npm_module.clj
@@ -30,6 +30,9 @@
              (into #{}))]

     (str "var CLJS_ENV = require(\"./cljs_env\");\n"
+         ;; the only actually global var goog sometimes uses that is not on goog.global
+         ;; actually only: goog/promise/thenable.js goog/proto2/util.js?
+         "var COMPILED = false;\n"
          (->> requires
               (remove #{'goog})
               (map (fn [sym]
@@ -57,33 +60,30 @@
          "\n")))

 (defn src-suffix [state {:keys [provides] :as src}]
+  ;; export the shortest name always, some goog files have multiple provides
   (let [export
         (->> provides
              (map str)
              (sort)
-             (reverse)
              (map cljs-comp/munge)
              (first))]
-
     (str "\nmodule.exports = " export ";\n")))

 (defn cljs-env
   [state {:keys [runtime] :or {runtime :node} :as config}]
-  (let [global
-        (case runtime
-          :node
-          "global"
-          :browser
-          "window")]
-
-    (str "var CLJS_ENV = {};\n"
-         "var goog = CLJS_ENV.goog = {};\n"
-         @(get-in state [:sources "goog/base.js" :input])
-         "goog.global = process.browser ? window : global;\n"
-         "goog.provide = function(name) { return goog.exportPath_(name, undefined, CLJS_ENV); };\n"
-         "goog.require = function(name) { return true; };\n"
-         "module.exports = CLJS_ENV;\n"
-         )))
+  (str "var CLJS_ENV = {};\n"
+       "var CLJS_GLOBAL = process.browser ? window : global;\n"
+       ;; closure accesses these defines via goog.global.CLOSURE_DEFINES
+       "CLJS_GLOBAL.CLOSURE_DEFINES = " (output/closure-defines-json state) ";\n"
+       "CLJS_GLOBAL.CLOSURE_NO_DEPS = true;\n"
+       "var goog = CLJS_ENV.goog = {};\n"
+       @(get-in state [:sources "goog/base.js" :input])
+       ;; override goog.global = this;
+       "goog.global = CLJS_GLOBAL;\n"
+       "goog.provide = function(name) { return goog.exportPath_(name, undefined, CLJS_ENV); };\n"
+       "goog.require = function(name) { return true; };\n"
+       "module.exports = CLJS_ENV;\n"
+       ))

 (defn flush
   [state mode
@@ -165,10 +165,11 @@
                  (vals)
                  (remove :from-jar)
                  (map :provides)
-                 (reduce set/union #{'cljs.core})))
+                 (reduce set/union #{})))

+        ;; FIXME: not sure it should always compiled console helper?
         entries
-        (conj entries 'shadow.cljs.devtools.client.console)]
+        (conj entries 'cljs.core 'shadow.cljs.devtools.client.console)]

     (-> state
         (assoc :source-map-comment false)


all routes active; tests to be fixed

all routes active; tests to be fixed

--- test/NoteHub/test/handler.clj
+++ test/NoteHub/test/handler.clj
@@ -1,23 +1,14 @@
 (ns notehub.test.handler
   (:use clojure.test
+        [notehub.api :only [build-key get-date url]]
+        notehub.storage
         ring.mock.request
+        notehub.test.api
         notehub.handler))

-(defn substring? [a b] (not (= nil (re-matches (re-pattern (str "(?s).*" a ".*")) b))))
 (def date [2012 6 3])
 (def test-title "some-title")
 (def test-note "# This is a test note.\nHello _world_. Motörhead, тест.")
-
-
-#_(
-
-   (ns NoteHub.test.views.pages
-  (:use [NoteHub.views.pages]
-        [NoteHub.api :only [build-key get-signature get-date url]]
-        [noir.util.test]
-        [NoteHub.storage]
-        [clojure.test]))
-

 (defn create-testnote-fixture [f]
   (add-note (build-key date test-title) test-note "testPID")
@@ -35,10 +26,10 @@

 (deftest export-test
   (testing "Markdown export"
-    (is (has-body (send-request (url 2012 6 3 "some-title" "export")) test-note))))
+    (is (= (:body (send-request (url 2012 6 3 "some-title" "export"))) test-note))))

 (deftest note-creation
-  (let [session-key (create-session)
+  (let [session-key "somemd5hash"
         date (get-date)
         title "this-is-a-test-note"
         [year month day] date]
@@ -47,7 +38,7 @@
                   [:post "/post-note"]
                   {:session session-key
                    :note test-note
-                   :signature (get-signature session-key test-note)})]
+                   :signature (sign session-key test-note)})]
         (is (has-status resp 302))
         (is (note-exists? (build-key date title)))
         (is (substring? "Hello _world_"
@@ -57,7 +48,7 @@
               (not (note-exists? (build-key date title)))))))))

 (deftest note-creation-utf
-  (let [session-key (create-session)
+  (let [session-key "somemd5hash"
         date (get-date)
         title "радуга"
         note "# Радуга\nкаждый охотник желает знать, где сидят фазаны."
@@ -68,7 +59,7 @@
               [:post "/post-note"]
               {:session session-key
                :note note
-               :signature (get-signature session-key note)}) 302))
+               :signature (sign session-key note)}) 302))
       (is (note-exists? (build-key date title)))
       (is (substring? "знать" ((send-request (url year month day title)) :body)))
       (is (do
@@ -76,11 +67,11 @@
             (not (note-exists? (build-key date title))))))))

 (deftest note-update
-  (let [session-key (create-session)
+  (let [session-key "somemd5hash"
         date (get-date)
         title "this-is-a-test-note"
         [year month day] date
-        hash (get-signature session-key test-note)]
+        hash (sign session-key test-note)]
     (testing "Note update"
       (is (has-status
             (send-request
@@ -128,9 +119,6 @@
       (is (has-status (send-request "/") 200) "accessing landing page"))))

-   )
-
-
 (deftest test-app
   (testing "main route"
     (let [response (app (request :get "/"))]


First simple handler

First simple handler

--- frontend/src/crunsher/communication/main.cljs
+++ frontend/src/crunsher/communication/main.cljs
@@ -21,7 +21,7 @@
   "React on response after sending a new statement. Reset atom and call newly received url."
   [response]
   (let [res (process-response response)]
-    (println res)))
+    (lib/update-pokemon! (:pokemon res))))

 ;;;; Requests


Added some regex for parsing years active

--- src/metallumapi/scrape/bands.clj
+++ src/metallumapi/scrape/bands.clj
@@ -60,12 +60,12 @@
                                 (map html/text
                                      (html/select content *band-stats*))))]
     (assoc stats
-           :lyrical-themes (-> (:lyrical-themes stats)
-                               str/trim
-                               split-comma)
-           :years-active (-> (:years-active stats)
-                             strip-whitespace
-                             split-comma))))
+           :years-active (map (fn [year]
+                                (let [[_ range _ _ _ name]  (re-matches #"((\d{4})(-[\d\w]+)?)\s*(\(as\s*([\w\s]+)\))?" year)]
+                                  {:range range
+                                   :prev-band-name name
+                                   :link}))
+                              (split-comma (:years-active stats))))))

 (defn band-discography []
   (letfn [(disco [d]


Fix #321 by recreating the tools.namespace records before using them

--- src/midje/data/project_state.clj
+++ src/midje/data/project_state.clj
@@ -37,7 +37,6 @@
         (println (color/fail (filenames (:invalid-clojure-file  grouped-by-status))))
         (emit/fail-silently))
       (map :namespace-symbol (:contains-namespace grouped-by-status)))))
-

 (defn namespaces []
   (valid-namespace-symbols (mapcat tude/classify-dir-entries (ecosystem/leiningen-paths))))
@@ -113,7 +112,7 @@
               [new-roots unkilled-descendents] (seq/bifurcate actual-dependent-set surviving-namespaces)]
           (recur (concat roots-to-handle-later new-roots)
                  unkilled-descendents))))))
-
+
 (defn react-to-tracker! [state-tracker options]
   (let [namespaces (load-key state-tracker)]
     (when (not (empty? namespaces))
@@ -136,10 +135,16 @@
         (update-in [deps-key :dependents]
                    map/update-each-value remove-unloaded))))

+(defn with-fresh-copy-of-dependency-map
+  "Records must be recreated if the protocols that they implement are reloaded."
+  [state]
+  (update state deps-key clojure.tools.namespace.dependency/map->MapDependencyGraph))
+
 (defn mkfn:scan-and-react [options scanner]
   (fn []
     (swap! state-tracker-atom
-           #(let [new-tracker (apply scanner % (:files options))]
+           #(let [state (with-fresh-copy-of-dependency-map %)
+                  new-tracker (apply scanner state (:files options))]
               (react-to-tracker! new-tracker options)
               (prepare-for-next-scan new-tracker)))))


Test names are in the plural

Test names are in the plural

--- test/grimoire/api/fs_test.clj
+++ test/grimoire/api/fs_test.clj
@@ -67,7 +67,7 @@
     (is (= ["0.1.0" "0.1.0-SNAPSHOT" "1.0.0" "1.0.1" "1.1.0"]
            (sort (mapv t/thing->name versions))))))

-(deftest list-platform-test
+(deftest list-platforms-test
   (let [p (-> (t/->Group "org.foo")
               (t/->Artifact "a")
               (t/->Version "1.1.0"))


Add a missing test description

Add a missing test description

--- test/magician/string_test.clj
+++ test/magician/string_test.clj
@@ -3,6 +3,7 @@
             [magician.string :refer :all]))

 (deftest palindrome?-test
+  "determines if it is a palindrome"
   (is (palindrome? ""))
   (is (palindrome? "a"))
   (is (palindrome? "deed"))


Test adjacent

Test adjacent

--- test/obb_rules/board_test.clj
+++ test/obb_rules/board_test.clj
@@ -38,4 +38,18 @@
             (is (= true (has-element? new-board [1 1])))
             (is (= 1 (board-elements-count new-board)))))))))

+(deftest adjacent
+  (testing "adjacent"
+    (is (adjacent? [2 2] [1 1]))
+    (is (adjacent? [2 2] [1 2]))
+    (is (adjacent? [2 2] [1 3]))
+    (is (adjacent? [2 2] [2 1]))
+    (is (adjacent? [2 2] [2 2]))
+    (is (adjacent? [2 2] [2 3]))
+    (is (adjacent? [2 2] [3 1]))
+    (is (adjacent? [2 2] [3 2]))
+    (is (adjacent? [2 2] [3 3])))
+  (testing "not adjacent"
+    (is (not (adjacent? [2 2] [4 4])))))
+
 (run-tests)


reformat coordinates test

reformat coordinates test

--- test/tile_game/board_test.clj
+++ test/tile_game/board_test.clj
@@ -26,10 +26,10 @@

 (deftest coordinates
   (are [tile coord]
-       (= (tile->coords a-board tile) coord)
-       1 [0 0] 2 [1 0] 3 [2 0]
-       4 [0 1] 0 [1 1] 5 [2 1]
-       6 [0 2] 7 [1 2] 8 [2 2]))
+      (= (tile->coords a-board tile) coord)
+    1 [0 0] 2 [1 0] 3 [2 0]
+    4 [0 1] 0 [1 1] 5 [2 1]
+    6 [0 2] 7 [1 2] 8 [2 2]))

 (deftest slide-a-direction
   (are [arg result] (= (slide a-board arg) result)


Pass through on identity.

Pass through on identity.

--- src/onyx/peer/task_lifecycle.clj
+++ src/onyx/peer/task_lifecycle.clj
@@ -385,7 +385,9 @@
   (let [matched (filter #(= (:lifecycle/task %) task-name) lifecycles)]
     (reduce
      (fn [f lifecycle]
-       (comp (fn [x] ((operation/kw->fn (get lifecycle kw :clojure.core/identity)) x lifecycle)) f))
+       (if-let [g (get lifecycle kw)]
+         (comp (fn [x] ((operation/kw->fn g) x lifecycle)) f)
+         f))
      identity
      matched)))


Mark internal functions as being private

--- src/radicalzephyr/boot_junit.clj
+++ src/radicalzephyr/boot_junit.clj
@@ -12,12 +12,12 @@
                                  ConfigurationBuilder
                                  FilterBuilder)))

-(defn failure->map [failure]
+(defn- failure->map [failure]
   {:description (.. failure (getDescription) (toString))
    ;;:exception (.getException failure)
    :message (.getMessage failure)})

-(defn result->map [result]
+(defn- result->map [result]
   {:successful? (.wasSuccessful result)
    :run-time (.getRunTime result)
    :run     (.getRunCount result)
@@ -25,7 +25,7 @@
    :failed  (.getFailureCount result)
    :failures (map failure->map (.getFailures result))})

-(defn build-package-config [^String package]
+(defn- build-package-config [^String package]
   (.. (ConfigurationBuilder.)
       (setUrls (ClasspathHelper/forPackage package (into-array ClassLoader [])))
       (setScanners (into-array Scanner [(TypeAnnotationsScanner.)
@@ -33,20 +33,20 @@
       (filterInputsBy (.. (FilterBuilder.)
                           (includePackage (into-array String [package]))))))

-(defn find-tests-in-package [package]
+(defn- find-tests-in-package [package]
   (let [^Configuration config (build-package-config package)
         reflections (Reflections. config)
         test-methods (.getMethodsAnnotatedWith reflections
                                                org.junit.Test)]
     (map (memfn getDeclaringClass) test-methods)))

-(defn find-all-tests [packages]
+(defn- find-all-tests [packages]
   (->> packages
        (map str)
        (mapcat find-tests-in-package)
        set))

-(def run-listener
+(def ^:private run-listener
   (proxy [RunListener]
       []
     (testRunStarted [description]


Add missing whitespace

Add missing whitespace

--- src/asciinema/model/asciicast.clj
+++ src/asciinema/model/asciicast.clj
@@ -1,6 +1,6 @@
 (ns asciinema.model.asciicast
-  (:require[pandect.algo.sha1 :as sha1]
-           [clojure.string :as str]))
+  (:require [pandect.algo.sha1 :as sha1]
+            [clojure.string :as str]))

 (defn json-store-path [{:keys [id file stdout_frames]}]
   (cond


[#44] Start porting clojure.core namespace

--- priv/clojure/core.clj
+++ priv/clojure/core.clj
@@ -1,13 +1,16 @@
 (ns clojure.core)
-
-(def
-  seq (fn* [items] (clj_core/seq.e items)))

 (def
   ^{:arglists '([& items])
     :doc "Creates a new list containing the items."
     :added "1.0"}
-  list (fn* [& items] (clojerl.List/new.e (seq items))))
+  list (fn* [& items] (clojerl.List/new.e items)))
+
+(def
+  ^{:arglists '([& items])
+    :doc "Creates a new list containing the items."
+    :added "1.0"}
+  list* (fn* [items] (clojerl.List/new.e items)))

 (def
   ^{:arglists '([x seq])
@@ -17,6 +20,301 @@
     :static true}
   cons (fn* [x s] (clj_core/cons.e x s)))

+(def
+  ^{:macro true
+    :added "1.0"}
+  let (fn* let [_&form _&env & decl] (cons 'let* decl)))
+
+(def
+ ^{:macro true
+   :added "1.0"}
+ loop (fn* loop [_&form _&env & decl] (cons 'loop* decl)))
+
+(def
+ ^{:macro true
+   :added "1.0"}
+ fn (fn* fn [&form _&env & decl]
+        (let [x (cons 'fn* (clojerl.List/new.e decl))]
+          (clj_core/with_meta.e x (clj_core/meta.e &form)))))
+
+
+(def
+ ^{:arglists '([coll])
+   :doc "Returns the first item in the collection. Calls seq on its
+    argument. If coll is nil, returns nil."
+   :added "1.0"
+   :static true}
+ first (fn ^:static first [coll] (clj_core/first.e coll)))
+
+(def
+ ^{:arglists '([coll])
+   :tag cojerl.ISeq
+   :doc "Returns a seq of the items after the first. Calls seq on its
+  argument.  If there are no more items, returns nil."
+   :added "1.0"
+   :static true}
+ next (fn ^:static next [x] (clj_core/next.e x)))
+
+(def
+ ^{:arglists '([coll])
+   :tag clojerl.ISeq
+   :doc "Returns a possibly empty seq of the items after the first. Calls seq on its
+  argument."
+   :added "1.0"
+   :static true}
+ rest (fn ^:static rest [x] (clj_core/rest.e x)))
+
+(def
+ ^{:arglists '([coll x] [coll x & xs])
+   :doc "conj[oin]. Returns a new collection with the xs
+    'added'. (conj nil item) returns (item).  The 'addition' may
+    happen at different 'places' depending on the concrete type."
+   :added "1.0"
+   :static true}
+ conj (fn ^:static conj
+        ([] [])
+        ([coll] coll)
+        ([coll x] (clj_core/conj.e coll x))
+        ([coll x & xs]
+         (if xs
+           (recur (conj coll x) (first xs) (next xs))
+           (conj coll x)))))
+
+(def
+ ^{:doc "Same as (first (next x))"
+   :arglists '([x])
+   :added "1.0"
+   :static true}
+ second (fn ^:static second [x] (first (next x))))
+
+(def
+ ^{:doc "Same as (first (first x))"
+   :arglists '([x])
+   :added "1.0"
+   :static true}
+ ffirst (fn ^:static ffirst [x] (first (first x))))
+
+(def
+ ^{:doc "Same as (next (first x))"
+   :arglists '([x])
+   :added "1.0"
+   :static true}
+ nfirst (fn ^:static nfirst [x] (next (first x))))
+
+(def
+ ^{:doc "Same as (first (next x))"
+   :arglists '([x])
+   :added "1.0"
+   :static true}
+ fnext (fn ^:static fnext [x] (first (next x))))
+
+(def
+ ^{:doc "Same as (next (next x))"
+   :arglists '([x])
+   :added "1.0"
+   :static true}
+ nnext (fn ^:static nnext [x] (next (next x))))
+
+(def
+ ^{:arglists '([coll])
+   :doc "Returns a seq on the collection. If the collection is
+    empty, returns nil.  (seq nil) returns nil. seq also works on
+    Strings, native Java arrays (of reference types) and any objects
+    that implement Iterable. Note that seqs cache values, thus seq
+    should not be used on any Iterable whose iterator repeatedly
+    returns the same mutable object."
+   :tag clojure.lang.ISeq
+   :added "1.0"
+   :static true}
+ seq (fn ^:static seq [coll] (clj_core/seq.e coll)))
+
+(def
+ ^{:arglists '([p x])
+   :doc "Evaluates x and tests if it extends the protocol
+    p. Returns true or false"
+   :added "1.0"}
+ extends? (fn extends? [p x]
+            (clj_core/extends?.e p (clj_core/type.e x))))
+
+(def
+ ^{:arglists '([t x])
+   :doc "Evaluates x and tests if it is of type t.
+    Returns true or false"
+   :added "1.0"}
+ instance? (fn instance? [t x] (erlang/==.e t (clj_core/type.e x))))
+
+(def
+ ^{:arglists '([x])
+   :doc "Return true if x implements ISeq"
+   :added "1.0"
+   :static true}
+ seq? (fn ^:static seq? [x] (extends? :clojerl.ISeq x)))
+
+(def
+ ^{:arglists '([x])
+   :doc "Return true if x implements IMeta"
+   :added "1.0"
+   :static true}
+ meta? (fn ^:static meta? [x] (extends? :clojerl.IMeta x)))
+
+
+#_(def
+ ^{:arglists '([x])
+   :doc "Return true if x is a Character"
+   :added "1.0"
+   :static true}
+ char? (fn ^:static char? [x] (extends? Character x)))
+
+(def
+ ^{:arglists '([x])
+   :doc "Return true if x is a String"
+   :added "1.0"
+   :static true}
+ string? (fn ^:static string? [x] (instance? :clojerl.String x)))
+
+(def
+ ^{:arglists '([x])
+   :doc "Return true if x implements IMap"
+   :added "1.0"
+   :static true}
+ map? (fn ^:static map? [x] (extends? :clojerl.IMap x)))
+
+(def
+ ^{:arglists '([x])
+   :doc "Return true if x is a Vector"
+   :added "1.0"
+   :static true}
+ vector? (fn ^:static vector? [x] (instance? :clojerl.Vector x)))
+
+(def
+ ^{:arglists '([x])
+   :doc "Return true if x is a Symbol"
+   :added "1.0"
+   :static true}
+ symbol? (fn ^:static symbol? [x] (instance? :clojerl.Symbol x)))
+
+(def
+ ^{:arglists '([map key val] [map key val & kvs])
+   :doc "assoc[iate]. When applied to a map, returns a new map of the
+    same (hashed/sorted) type, that contains the mapping of key(s) to
+    val(s). When applied to a vector, returns a new vector that
+    contains val at index. Note - index must be <= (count vector)."
+   :added "1.0"
+   :static true}
+ assoc
+ (fn ^:static assoc
+   ([map key val] (clj_core/assoc.e map key val))
+   ([map key val & kvs]
+    (let [ret (assoc map key val)]
+      (if kvs
+        (if (next kvs)
+          (recur ret (first kvs) (second kvs) (nnext kvs))
+          (throw "assoc expects even number of arguments after map/vector, found odd number"))
+        ret)))))
+
+;;;;;;;;;;;;;;;;; metadata ;;;;;;;;;;;;;;;;;;;;;;;;;;;
+(def
+ ^{:arglists '([obj])
+   :doc "Returns the metadata of obj, returns nil if there is no metadata."
+   :added "1.0"
+   :static true}
+ meta (fn ^:static meta [x]
+        (if (meta? x)
+          (clj_core/meta.e x))))
+
+(def
+ ^{:arglists '([^clojure.lang.IObj obj m])
+   :doc "Returns an object of the same type and value as obj, with
+    map m as its metadata."
+   :added "1.0"
+   :static true}
+ with-meta (fn ^:static with-meta [x m]
+             (clj_core/with_meta.e x m)))
+
+#_(def ^{:private true :dynamic true}
+  assert-valid-fdecl (fn [fdecl]))
+
+#_(def
+ ^{:private true}
+ sigs
+ (fn [fdecl]
+   (assert-valid-fdecl fdecl)
+   (let [asig
+         (fn [fdecl]
+           (let [arglist (first fdecl)
+                 ;elide implicit macro args
+                 arglist (if (clj_utils/equals.e '&form (first arglist))
+                           (clj_core/subvec.e arglist 2 (clj_core/count.e arglist))
+                           arglist)
+                 body (next fdecl)]
+             (if (map? (first body))
+               (if (next body)
+                 (with-meta arglist (conj (if (meta arglist) (meta arglist) {}) (first body)))
+                 arglist)
+               arglist)))]
+     (if (seq? (first fdecl))
+       (loop [ret [] fdecls fdecl]
+         (if fdecls
+           (recur (conj ret (asig (first fdecls))) (next fdecls))
+           (seq ret)))
+       (list (asig fdecl))))))
+
+(def
+ ^{:arglists '([coll])
+   :doc "Return the last item in coll, in linear time"
+   :added "1.0"
+   :static true}
+ last (fn ^:static last [s]
+        (if (next s)
+          (recur (next s))
+          (first s))))
+
+(def
+ ^{:arglists '([coll])
+   :doc "Return a seq of all but the last item in coll, in linear time"
+   :added "1.0"
+   :static true}
+ butlast (fn ^:static butlast [s]
+           (loop [ret [] s s]
+             (if (next s)
+               (recur (conj ret (first s)) (next s))
+               (seq ret)))))
+
+(def ^:macro defn
+  (fn* [form env name & fdecl]
+       (if (symbol? name)
+         nil
+         (throw "First argument to defn must be a symbol"))
+       (let [m     (if (string? (first fdecl))
+                     {:doc (first fdecl)}
+                     {})
+             fdecl (if (string? (first fdecl))
+                     (next fdecl)
+                     fdecl)
+             m     (if (map? (first fdecl))
+                     (conj m (first fdecl))
+                     m)
+             fdecl (if (map? (first fdecl))
+                     (next fdecl)
+                     fdecl)
+             fdecl (if (vector? (first fdecl))
+                     (list fdecl)
+                     fdecl)
+             m     (if (map? (last fdecl))
+                     (conj m (last fdecl))
+                     m)
+             fdecl (if (map? (last fdecl))
+                      (butlast fdecl)
+                      fdecl)
+             ;; m     (merge {:arglists (list 'quote (sigs fdecl))} m)
+             m     (conj (if (meta name) (meta name) {}) m)]
+         (list 'def (with-meta name m)
+               ;;todo - restore propagation of fn name
+               ;;must figure out how to convey primitive hints to self calls first
+               (cons 'clojure.core/fn (list* (seq fdecl)))))))
+
+;;;;;
+
 (def str
   (fn* [x] (clj_core/str.e x)))

@@ -24,95 +322,146 @@
   (fn* [x]
        (io/format.e "~s~n" (seq [(str x)]))))

+(def apply
+    (fn*
+     ([f args] (clj_core/invoke.e f (seq args)))
+     ([f x args] (clj_core/invoke.e f (cons x (seq args))))
+     ([f x y args] (clj_core/invoke.e f (cons x (cons y (seq args)))))
+     ([f x y z args] (clj_core/invoke.e f (cons x (cons y (cons z (seq args))))))
+     ([f a b c d args] (clj_core/invoke.e f (cons a (cons b (cons c (cons d (seq args)))))))))
+
 (def =
   (fn* [a b] (erlang/==.2 a b)))

 (def not
   (fn* [a] (erlang/not.1 a)))

+(def assert ^:macro
+  (fn* [v] (if (not v) (throw :assert))))
+
 (def <
   (fn* [a b] (erlang/<.e a b)))

-(def assert ^:macro
-  (fn* [v] (if (not v) (throw :assert))))
-
-(def apply
-  (fn*
-   ([f args] (clj_core/invoke.e f (seq args)))
-   ([f x args] (clj_core/invoke.e f (cons x (seq args))))
-   ([f x y args] (clj_core/invoke.e f (cons x (cons y (seq args)))))
-   ([f x y z args] (clj_core/invoke.e f (cons x (cons y (cons z (seq args))))))
-   ([f a b c d args] (clj_core/invoke.e f (cons a (cons b (cons c (cons d (seq args)))))))))
-
-(def first
-  (fn* [xs] (clj_core/first.e xs)))
-
-(def rest
-  (fn* [xs] (clj_core/rest.e xs)))
-
-(def next
-  (fn* [xs] (clj_core/next.e xs)))
-
-(def reverse
-  (fn* [s] (lists/reverse.e (seq s))))
-
-(def concat
-  (fn*
-   ([] (list))
-   ([x] (apply list x))
-   ([x y]
-    (if (seq x)
-      (cons (first (seq x)) (concat (rest (seq x)) y))
-      y))
-   ([x y & zs]
-    (if (seq zs)
-      (apply concat (concat x y) (first zs) (next zs))
-      (concat x y)))))
-
-(def with-meta
-  (fn* [x meta] (clj_core/with_meta.e x meta)))
-
-(def meta
-  (fn* [x] (clj_core/meta.e x)))
-
-(def vector
-  (fn* [& xs] (clj_core/vector.e (seq xs))))
-
-(def hash-map
-  (fn* [& xs] (clj_core/hash_map.e (seq xs))))
-
-(def hash-set
-  (fn* [& xs] (clj_core/hash_set.e (seq xs))))
-
-(def ^:macro defn
-  (fn* [_form _env name args & body]
-       `(def ~name (fn* ~args ~@body))))
-
-(defn reduce
-  ([f coll]
-   (reduce f (first coll) (rest coll)))
-  ([f val coll]
-   (if (seq coll)
-     (reduce f (f val (first coll)) (rest coll))
-     val)))
-
-(defn +
-  ([] 0)
-  ([x] x)
-  ([x y] (erlang/+.e x y))
-  ([x y & more]
-   (reduce + (+ x y) more)))
-
-(defn -
-  ([] 0)
-  ([x] x)
-  ([x y] (erlang/-.e x y))
-  ([x y & more]
-   (reduce - (- x y) more)))
-
-(defn comp [& fs]
-  (let* [fs (reverse fs)]
-    (fn* [& xs]
-      (reduce #(%2 %1)
-              (apply (first fs) xs)
-              (rest fs)))))
+#_(
+
+
+  (def reverse
+    (fn* [s] (lists/reverse.e (seq s))))
+
+  (def concat
+    (fn*
+     ([] (list))
+     ([x] (apply list x))
+     ([x y]
+      (if (seq x)
+        (cons (first (seq x)) (concat (rest (seq x)) y))
+        y))
+     ([x y & zs]
+      (if (seq zs)
+        (apply concat (concat x y) (first zs) (next zs))
+        (concat x y)))))
+
+  (def vector
+    (fn* [& xs] (clj_core/vector.e (seq xs))))
+
+  (def hash-map
+    (fn* [& xs] (clj_core/hash_map.e (seq xs))))
+
+  (def hash-set
+    (fn* [& xs] (clj_core/hash_set.e (seq xs))))
+
+  (def merge
+    (fn* [& xs] (clj_core/merge.e xs)))
+
+  (def
+    ^{:doc "Like defn, but the resulting function name is declared as a
+  macro and will be used as a macro by the compiler when it is
+  called."
+      :arglists '([name doc-string? attr-map? [params*] body]
+                  [name doc-string? attr-map? ([params*] body)+ attr-map?])
+      :added "1.0"}
+    defmacro (fn [&form &env name & args]
+               (let [m    (merge {:macro true} (meta name))
+                     name (with-meta name m)]
+                 (apply list 'defn name args))))
+
+  (defn reduce
+    ([f coll]
+     (reduce f (first coll) (rest coll)))
+    ([f val coll]
+     (if (seq coll)
+       (reduce f (f val (first coll)) (rest coll))
+       val)))
+
+  (defn +
+    ([] 0)
+    ([x] x)
+    ([x y] (erlang/+.e x y))
+    ([x y & more]
+     (reduce + (+ x y) more)))
+
+  (defn -
+    ([] 0)
+    ([x] x)
+    ([x y] (erlang/-.e x y))
+    ([x y & more]
+     (reduce - (- x y) more)))
+
+  (defn comp [& fs]
+    (let* [fs (reverse fs)]
+          (fn* [& xs]
+               (reduce #(%2 %1)
+                       (apply (first fs) xs)
+                       (rest fs)))))
+
+  (defn require
+    "Loads libs, skipping any that are already loaded. Each argument is
+  either a libspec that identifies a lib, a prefix list that identifies
+  multiple libs whose names share a common prefix, or a flag that modifies
+  how all the identified libs are loaded. Use :require in the ns macro
+  in preference to calling this directly.
+  Libs
+  A 'lib' is a named set of resources in classpath whose contents define a
+  library of Clojure code. Lib names are symbols and each lib is associated
+  with a Clojure namespace and a Java package that share its name. A lib's
+  name also locates its root directory within classpath using Java's
+  package name to classpath-relative path mapping. All resources in a lib
+  should be contained in the directory structure under its root directory.
+  All definitions a lib makes should be in its associated namespace.
+  'require loads a lib by loading its root resource. The root resource path
+  is derived from the lib name in the following manner:
+  Consider a lib named by the symbol 'x.y.z; it has the root directory
+  <classpath>/x/y/, and its root resource is <classpath>/x/y/z.clj. The root
+  resource should contain code to create the lib's namespace (usually by using
+  the ns macro) and load any additional lib resources.
+  Libspecs
+  A libspec is a lib name or a vector containing a lib name followed by
+  options expressed as sequential keywords and arguments.
+  Recognized options:
+  :as takes a symbol as its argument and makes that symbol an alias to the
+    lib's namespace in the current namespace.
+  :refer takes a list of symbols to refer from the namespace or the :all
+    keyword to bring in all public vars.
+  Prefix Lists
+  It's common for Clojure code to depend on several libs whose names have
+  the same prefix. When specifying libs, prefix lists can be used to reduce
+  repetition. A prefix list contains the shared prefix followed by libspecs
+  with the shared prefix removed from the lib names. After removing the
+  prefix, the names that remain must not contain any periods.
+  Flags
+  A flag is a keyword.
+  Recognized flags: :reload, :reload-all, :verbose
+  :reload forces loading of all the identified libs even if they are
+    already loaded
+  :reload-all implies :reload and also forces loading of all libs that the
+    identified libs directly or indirectly load via require or use
+  :verbose triggers printing information about each load, alias, and refer
+  Example:
+  The following would load the libraries clojure.zip and clojure.set
+  abbreviated as 's'.
+  (require '(clojure zip [set :as s]))"
+    {:added "1.0"}
+
+    [& _args]
+    #_(apply load-libs :require args))
+  )


working comment body and possible working auto comment

--- src/gh_waiting_room/service.clj
+++ src/gh_waiting_room/service.clj
@@ -68,35 +68,62 @@
            ""
            (str (re-find #"^.{0,100}(?=\s|$)" body)
                 (if (> (count body) 100) " ..." "")))
-   :user (or (get-in issue [:user :login])
+   :user (or (get-in issue [:repository :owner :login])
              (throw (ex-info "No user found for issue" {:issue issue})))
+   :repo-name (get-in issue [:repository :name])
    :created (or (re-find #"\d{4}-\d\d-\d\d"(:created_at issue))
                 (throw (ex-info "Failed to parse date from an issue" {:issue issue})))})

+(defn- viewable-issues []
+  (->> (:issues @db)
+       (filter issue-filter)
+       (map ->issue)
+       reverse
+       (map-indexed (fn [num elem]
+                      (assoc elem :position (inc num))))))
 (defn home-page
   [request]
   (when-not (seq (:issues @db)) (fetch-gh-issues))
   (ring-resp/response
    (render-resource "public/index.mustache"
                     {:github-user (gh-user)
-                     :issues (->> (:issues @db)
-                                  (filter issue-filter)
-                                  (map ->issue)
-                                  reverse
-                                  (map-indexed (fn [num elem]
-                                                 (assoc elem :position (inc num)))))})))
+                     :issues (viewable-issues)})))
+
+(defn get! [m k]
+  (or (get m k) (throw (ex-info "No value found for key in map" {:map m :key k}))))
+
+(defn get-in! [m ks]
+  (or (get-in m ks) (throw (ex-info "No value found for nested keys in map" {:map m :keys ks}))))
+
+; TODO: can this come from url-for?
+(defn- full-url-for [path]
+  (str (or (System/getenv "APP_DOMAIN") "http://localhost:8080") path))
+
+(defn- comment-body [issue]
+  (str
+   (if (= (:type issue) "pull request")
+     "Thanks for your pull request!"
+     "Thanks for reporting your issue!")
+   (format " You're [number %s in my list of open issues](%s). Use that link to check how soon your issue will be answered. Thanks for your patience."
+           (:position issue)
+           (full-url-for (str "/#" (:name issue))))))
+
+(defn- update-issues-and-create-comment [full-name issue-num]
+  (fetch-gh-issues)
+  (let [issue (or
+               (some #(and (= (:name %) (format "%s#%s" full-name issue-num)) %) (viewable-issues))
+               (throw (ex-info "No issue found for webhook" {:full-name full-name :issue-num issue-num})))
+        body (comment-body issue)]
+    (create-comment (:user issue) (:repo-name issue) issue-num body (gh-auth))))

 (defn webhook-page
   [request]
-  (prn request)
   (let [params (-> request :json-params)
-        _ (prn "Params:" params)
-        action (get params "action")]
+        action (get! params "action")]
     (when (some #{action} ["created" "reopened"])
-      (let [body "There's nothing to see here. Move along."
-            issue-num (get-in params ["issue" "number"])
-            _ (prn "ISSUE:" issue-num)]
-        (create-comment "cldwalker" "gh-waiting-room" issue-num body (gh-auth))) ))
+      (let [full-name (get-in! params ["repository" "full_name"])
+            issue-num (get-in! params ["issue" "number"])]
+        (update-issues-and-create-comment full-name issue-num))))
   {:status 200})

 (defon-response html-content-type


Don't show count if it is 0

Don't show count if it is 0

--- src/govuk/blinken/dashboard.clj
+++ src/govuk/blinken/dashboard.clj
@@ -42,8 +42,9 @@
   (let [critical-count (-> service :alerts :critical count)]
     [:a {:href (str "/" (:id service))
          :class (str "service-overview " (if (> critical-count 0) "critical" "ok"))}
-      [:h2 (:name service)]
-      [:div {:class "count"} critical-count]]))
+     [:h2 (:name service)]
+     (if (> critical-count 0)
+       [:div {:class "count"} critical-count])]))

 (defn services-overview [services]
   (for [service services] (service-overview service)))