Add clickable class and start on vertex/edge logic

--- src/constraint/core.cljs
+++ src/constraint/core.cljs
@@ -36,9 +36,10 @@
     (string/join " " (map str ["M" "L" "L"] coords))))

-(defn line [from to color]
+(defn line [from to color id]
   [:svg:path
-   {:id "clickthis"
+   {:class "clickable"
+    :id id
     :d (make-line-dirs from to)
     :stroke color
     :stroke-width "10px"
@@ -53,8 +54,8 @@
                            [:svg:defs
                             triangle-marker
                             circle-marker]
-                           (line [100, 20] [200, 40] "#6666ff")
-                           (line [200, 40] [100, 80] "red")]))
+                           (line [100, 20] [200, 40] "#6666ff" "one")
+                           (line [200, 40] [100, 80] "red" "two")]))

 (defn e->tid [e]
   (-> e
@@ -66,9 +67,17 @@
   (.log js/console (e->tid e))
   (js/alert "123"))

+(def vertex-loc [[40 40]
+                 [100 40]
+                 [100 100]
+                 [40 100]])

+(def edges-vec [[0 1 "red"]
+                [1 2 "blue"]
+                [2 3 "red"]
+                [3 1 "red"]])

-(map #(dommy.core/listen! % :click click-handler) (dommy.core/sel :#clickthis))
+(map #(dommy.core/listen! % :click click-handler) (dommy.core/sel :.clickable))

 ; (dommy.core/append (dommy.core/parent (dommy.core/sel1 :circle))
 ;                    (crate/html


Refactor calculating inflow.

Refactor calculating inflow.

--- src/constraint/core.cljs
+++ src/constraint/core.cljs
@@ -55,8 +55,7 @@
                    :blue 2})

 (defn svg-vertex [edges id [weight [x y]]]
-  (let [entering (filter #(= id (second (second %))) edges)
-        summed (apply + (map #(color->value ((second %) 2)) entering))]
+  (let [vert-inflow (inflow edges id)]
     (list
       [:svg:circle
        {:cx x :cy y
@@ -69,7 +68,7 @@
        {:x x :y (+ 5 y)
         :fill "black"
         :text-anchor "middle"}
-       (str id " (" summed "/" weight ")") ]))
+       (str id " (" vert-inflow "/" weight ")") ]))
   )

 (defn event->targetid [e]
@@ -120,18 +119,21 @@
                   (crate/html [:div#forsvg
                                 (make-svg [1000 1000] world-state)])))

-(defn ok-to-flip? [{:keys [vertices edges]} [left right color]]
-  (let [this-value (color->value color)
-        entering-right (filter #(= right (second (second %))) edges)
-        sum-into-right (apply + (map #(color->value ((second %) 2)) entering-right))
-        right-value (first (vertices right))]
-    (if (< (- sum-into-right this-value) right-value)
-      false
-      true)))
+(defn inflow [edges vertex]
+  (let [in-going (for [[_ [_ to color]] edges
+                       :when (= to vertex)]
+                   (color->value color))]
+    (apply + in-going)))

-(defn flip-edge [world-state [left right color :as edge]]
+(defn ok-to-flip? [{:keys [vertices edges]} [_ to color]]
+  (let [edge-value (color->value color)
+        to-inflow (inflow edges to)
+        to-vertex-value (first (vertices to))]
+    (>= (- to-inflow edge-value) to-vertex-value)))
+
+(defn flip-edge [world-state [from to color :as edge]]
   (if (ok-to-flip? world-state edge)
-    [right left color]
+    [to from color]
     edge))


Support maps as inputs to layers (#174)

Support maps as inputs to layers (#174)

* support maps to layer types

* Think it is ready to merge back.

--- src/cortex/nn/layers.clj
+++ src/cortex/nn/layers.clj
@@ -99,22 +99,40 @@

 (defn input
+  ([arg]
+   (let [arg (if (map? arg) arg {:width arg})
+         {:keys [width height channels]
+          :or {height   1
+               channels 1}
+          :as args} arg]
+     (assert width)
+     [(merge
+       {:type :input
+        :output-size     (* width height channels)
+        :output-width    width
+        :output-height   height
+        :output-channels channels}
+       args)]))
   ([width height channels & args]
    [(merge-args
      {:type :input
-      :output-size (* width height channels)
-      :output-width width
-      :output-height height
+      :output-size     (* width height channels)
+      :output-width    width
+      :output-height   height
       :output-channels channels}
-     args)])
-  ([output-size]
-   (input output-size 1 1)))
+     args)]))

 ;; Linear layer

 (defn linear
-  [num-output & args]
-  [(merge-args {:type :linear :output-size num-output} args)])
+  ([arg]
+   (let [args (if (map? arg)
+                arg
+                {:output-size arg})]
+     (assert (:output-size args))
+     [(assoc args :type :linear)]))
+  ([output-size & args]
+   (linear (merge-args {:output-size output-size} args))))

 (defn linear-weight-parameter-shape
@@ -245,24 +263,38 @@

 (defn dropout
   "Bernoulli dropout where random (flat distribution) activations are zeroed out.
-Probability is the probability that an activation will survive so a probability of
-1 means no dropout while a probability of will zero out the activation vector."
-  [probability & args]
-  [(merge-args
-    {:type :dropout :distribution :bernoulli :probability probability}
-    args)])
+  Probability is the probability that an activation will survive so a probability of
+  1 means no dropout while a probability of will zero out the activation vector."
+  ([arg]
+   (let [args (if (map? arg)
+                arg
+                {:probability arg})]
+     (assert (:probability args))
+     [(assoc args :type :dropout :distribution :bernoulli)]))
+  ([probability & args]
+   [(merge-args
+     {:type :dropout :distribution :bernoulli :probability probability}
+     args)]))

 (defn multiplicative-dropout
   "Gaussian dropout where the activation vector is multiplied by a gaussian
-vector centered around (1,variance).  Note that this means the variance
-argument has an opposite effect of traditional dropout's probability in that
-a variance of 1 is actually quite a lot of variance and a variance of 0 means
-no change to the input."
-  [variance & args]
-  [(merge-args
-    {:type :dropout :distribution :gaussian :variance variance}
-    args)])
+  vector centered around (1,variance).  Note that this means the variance
+  argument has an opposite effect of traditional dropout's probability in that
+  a variance of 1 is actually quite a lot of variance and a variance of 0 means
+  no change to the input."
+  ([arg]
+   (let [args (if (map? arg)
+                arg
+                {:variance arg})]
+     (assert (:variance args))
+     [(assoc args
+             :type :dropout
+             :ditribution :gaussian)]))
+  ([variance & args]
+   [(merge-args
+     {:type :dropout :distribution :gaussian :variance variance}
+     args)]))

 (defmethod graph/get-node-metadata :dropout
@@ -331,14 +363,18 @@

 (defn convolutional
   "Create a convolutional layer.  The dimension operation used for height/width
-calculations must be "
-  [kernel-dim pad stride num-kernels & args]
-  ;;We have to force the dimension operation to be floor for convolutional operations
-  ;;due to cudnn compatibility constraints
-  [(assoc
-    (apply convolutional-type-layer :convolutional kernel-dim kernel-dim
-           pad pad stride stride num-kernels :floor args)
-    :dimension-op :floor)])
+  calculations must be "
+  ([{:keys [kernel-dim pad stride num-kernels floor] :as args}]
+   (assert (and kernel-dim pad stride num-kernels))
+   [(assoc
+     (apply convolutional-type-layer :convolutional kernel-dim kernel-dim
+            pad pad stride stride num-kernels :floor (flatten (seq args)))
+     :dimension-op :floor)])
+  ([kernel-dim pad stride num-kernels & args]
+   ;;We have to force the dimension operation to be floor for convolutional operations
+   ;;due to cudnn compatibility constraints
+   (convolutional (merge-args {:kernel-dim kernel-dim :pad pad :stride stride
+                               :num-kernels num-kernels} args))))

 (defn- convolutional-weight-parameter-shape
@@ -424,14 +460,15 @@

 (defn max-pooling
-  "Max pooling with one of three possible pooling operations (:pool-op):
+    "Max pooling with one of three possible pooling operations (:pool-op):
 :max - default, take the max excluding padding.
 :avg - Take the average including padding.
 :avg-exc-pad - Take the average excluding padding."
-  [kernel-dim pad stride & args]
-  (let [retval (-> (apply convolutional-type-layer :max-pooling
+  ([{:keys [kernel-dim pad stride ceil] :as args}]
+   (assert (and kernel-dim pad stride))
+   (let [retval (-> (apply convolutional-type-layer :max-pooling
                           kernel-dim kernel-dim pad pad
-                          stride stride 0 :ceil args)
+                          stride stride 0 :ceil (flatten (seq args)))
                    (#(if (contains? % :pool-op)
                        %
                        (assoc % :pool-op :max))))]
@@ -440,6 +477,8 @@
                       {:possible-operation-set #{:max :avg :avg-exc-pad}
                        :pool-op (get retval :pool-op)})))
     [retval]))
+  ([kernel-dim pad stride & args]
+   (max-pooling (merge-args {:kernel-dim kernel-dim :pad pad :stride stride} args))))

 (defmethod graph/build-node :max-pooling


A user has only one name therefore a list does not make sense and is … (#103)

* A user has only one name therefore a list does not make sense and is not allowed by cloud formation

* Allow username to be a ref

--- src/crucible/aws/iam.clj
+++ src/crucible/aws/iam.clj
@@ -96,7 +96,7 @@

 (s/def ::managed-policy-arns (s/* string?))

-(s/def ::username (s/* string?))
+(s/def ::username (spec-or-ref string?))

 (s/def ::user (s/keys :opt [::groups
                             ::login-profile


Finally we can use references directly

Finally we can use references directly

Since https://codereview.chromium.org/1096283003

--- src/devtools/format.cljs
+++ src/devtools/format.cljs
@@ -30,7 +30,6 @@
 (def string-style "color:#C41A16")
 (def symbol-style "color:#000000")
 (def fn-style "color:#090")
-(def fn-label "λ")
 (def bool-style "color:#099")

 ; IRC #clojurescript @ freenode.net on 2015-01-27:
@@ -112,7 +111,7 @@
     (number? value) (number-template value)
     (keyword? value) (template span keyword-style (str value))
     (symbol? value) (template span symbol-style (str value))
-    (fn? value) (template span fn-style (reference (surrogate value fn-label)))))
+    (fn? value) (template span fn-style (reference value))))

 (defn abbreviated? [template]
   (some #(= more-marker %) template))
@@ -134,8 +133,7 @@
 ; we want to wrap stringified obj in a reference for further inspection
 (defn detect-else-case-and-patch-it [group obj]
   (if (and (= (count group) 3) (= (aget group 0) "#<") (= (str obj) (aget group 1)) (= (aget group 2) ">"))
-    (let [label (aget group 1)]
-      (aset group 1 (reference (surrogate obj label true (reference obj "inspect js object"))))))) ; TODO change to direct reference after devtools guys fix the bug
+    (aset group 1 (reference obj))))

 (defn alt-printer-impl [obj writer opts]
   (if-let [tmpl (atomic-template obj)]
@@ -163,8 +161,8 @@

 (defn standard-body-template
   ([lines margin?] (let [ol-style (if margin? standard-ol-style standard-ol-no-margin-style)
-        li-style (if margin? standard-li-style standard-li-no-margin-style)]
-    (template ol ol-style (map #(template li li-style %) lines))))
+                         li-style (if margin? standard-li-style standard-li-no-margin-style)]
+                     (template ol ol-style (map #(template li li-style %) lines))))
   ([lines] (standard-body-template lines true)))

 (defn body-line-template [index value]
@@ -200,7 +198,7 @@
       (if (seqable? target)
         (let [starting-index (or (aget value "startingIndex") 0)]
           (build-body target starting-index))
-        (template ol standard-ol-style (template li standard-li-style (reference target (str target))))))))
+        (template ol standard-ol-style (template li standard-li-style (reference target)))))))

 ;;;;;;;;; PROTOCOL SUPPORT


Only use compojure 'site' for dynamic route; it's got cookies and stuff

--- src/foreclojure/core.clj
+++ src/foreclojure/core.clj
@@ -48,6 +48,7 @@
          identity))
       session/wrap-stateful-session
       wrap-uri-binding
+      handler/site
       wrap-strip-trailing-slash))

 (let [canonical-host (or config/dynamic-host "www.4clojure.com")]
@@ -74,7 +75,6 @@

 (def app (-> (split-hosts host-handlers)
              wrap-404
-             handler/site
              wrap-gzip))

 (defn register-heartbeat []


Pyramid should touch the ground

Pyramid should touch the ground

--- src/fractalz/pyramid.clj
+++ src/fractalz/pyramid.clj
@@ -50,7 +50,7 @@
 (defn get-coords
   "Gets the coordinates to place the block at, ensuring the rows of the triangle are centralized"
   [col row depth x y z size]
-  (let [top (+ size y -1)]
+  (let [top (+ size y -2)]
     [(-> col (+ x) (- (/ row 2)))
      (- top row)
      (-> depth (+ z) (- (/ row 2)))]))


Support more than one form

Support more than one form

--- test/cljs/go_test.clj
+++ test/cljs/go_test.clj
@@ -64,7 +64,7 @@
   (println"*/"))

 (defn test-setup [setup]
-  (let [ast (-> [setup] cljs->ast)]
+  (let [ast (-> setup cljs->ast)]
     (test-comment setup ast)
     (printf "\t%s\n" (ast->go ast))))

@@ -195,7 +195,7 @@
     (testify "Do"
              [3 '(do 1 2 3)])
     (test-setup-toplevel
-     '(def x 2))
+     '[(def x 2)])
     (testify "Def"
              [2 'x])
     (testify "New"


code cleanup

code cleanup

--- src/selmer/test_parser.clj
+++ src/selmer/test_parser.clj
@@ -1,49 +1,68 @@
 (ns selmer.test-parser)

-(declare parse expr-tag)
+(def ^Character tag-open \{)
+(def ^Character tag-close \})
+(def ^Character filter-open \{)
+(def ^Character filter-close \})
+(def ^Character tag-second \%)

-(defn render [template args]
+(declare parse expr-tag tag-content)
+
+(defn render [template args]
   (let [buf (StringBuilder.)]
-    (doseq [element template]
+    (doseq [element template]
       (.append buf (if (string? element) element (element args))))
     (.toString buf)))

 (defn read-char [rdr]
   (let [ch (.read rdr)]
-    (if-not (neg? ch) (char ch))))
+    (if-not (== -1 ch) (char ch))))

-(defn peek-stream [rdr size]
-  (.mark rdr size)
-  (let [result (loop [items []]
-                 (let [ch (read-char rdr)]
-                   (if (and ch (< (count items) size))
-                     (recur (conj items ch))
-                     items)))]
-    (.reset rdr)
-    result))
+(defn for-hanlder [[id _ items] rdr]
+  (let [content (tag-content :endfor rdr)
+        id (map keyword (.split id "\\."))
+        items (keyword items)]
+    (fn [args]
+      (let [buf (StringBuilder.)]
+        (doseq [value (get args items)]
+          (.append buf (render content (assoc-in args id value))))
+        (.toString buf)))))

-(defn value-tag [{:keys [tag-value]}]
+(def expr-tags
+  {:for {:handler for-hanlder}
+   :block {:handler
+           (fn [args rdr]
+             (let [content (tag-content :endblock rdr)]
+               (fn [args] (render content args))))}})
+
+(defn expr-tag [{:keys [tag-name args] :as tag} rdr]
+  (if-let [handler (get-in expr-tags [tag-name :handler])]
+    (handler args rdr)
+    (throw (Exception. (str "unrecognized tag: " tag-name)))))
+
+(defn filter-tag [{:keys [tag-value]}]
   (let [value (map keyword (.split tag-value "\\."))]
     (fn [args] (get-in args value))))

-#_((value-tag {:tag-value "foo.bar.baz"}) {:foo {:bar {:baz "ok"}}})
+#_((filter-tag {:tag-value "foo.bar.baz"}) {:foo {:bar {:baz "ok"}}})
 ;ok
-#_((value-tag {:tag-value "foo"}) {:foo "ok"})
+#_((filter-tag {:tag-value "foo"}) {:foo "ok"})
 ;ok

 (defn read-tag-info [rdr]
   (let [buf (StringBuilder.)
-        tag-type (if (= \{(read-char rdr)) :value :expr)]
+        tag-type (if (= filter-open (read-char rdr)) :filter :expr)]
     (loop [ch1 (read-char rdr)
-           ch2 (read-char rdr)]
-      (when-not (and (or  (= \% ch1) (= \} ch1)) (= \} ch2))
+           ch2 (read-char rdr)]
+      (when-not (and (or (= filter-close ch1) (= tag-second ch1))
+                     (= tag-close ch2))
         (.append buf ch1)
         (recur ch2 (read-char rdr))))
     (let [content (->>  (.split (.toString buf ) " ") (remove empty?) (map (memfn trim)))]
       (merge {:tag-type tag-type}
-             (if (= :value tag-type)
+             (if (= :filter tag-type)
                {:tag-value (first content)}
-               {:tag-name (first content)
+               {:tag-name (keyword (first content))
                 :args (rest content)})))))

 #_(read-tag-info (java.io.StringReader. "% for i in nums %}"))
@@ -52,17 +71,17 @@
 #_(read-tag-info (java.io.StringReader. "{ nums }}"))
 ;{:tag-value "nums", :tag-type :value}

-(defn tag-content [close-tag rdr]
+(defn tag-content [end-tag rdr]
   (let [content (transient [])
         buf (StringBuilder.)]
     (loop [ch (read-char rdr)]
-      (if (= \{ ch)
-        (let [{:keys [tag-name tag-type] :as tag} (read-tag-info rdr)]
-          (when (not= close-tag tag-name)
+      (if (= tag-open ch)
+        (let [{:keys [tag-name tag-type] :as tag} (read-tag-info rdr)]
+          (when (not= end-tag tag-name)
             (conj! content (.toString buf))
             (.setLength buf 0)
-            (conj! content (if (= :value tag-type)
-                             (value-tag tag)
+            (conj! content (if (= :filter tag-type)
+                             (filter-tag tag)
                              (expr-tag tag rdr)))
             (recur (read-char rdr))))
         (do
@@ -76,49 +95,35 @@
 #_(render (tag-content "endfor" (java.io.StringReader. "foo {{name.first}} bar {% endfor %}")) {:name {:first "Bob"}})
 ;"foo Bob bar "

-(defn for-hanlder [[id _ items] rdr]
-  (let [content (tag-content "endfor" rdr)
-        id (map keyword (.split id "\\."))
-        items (keyword items)]
-    (fn [args]
-      (->> (for [value (get args items)]
-             (render content (assoc-in args id value)))
-           (apply str)))))
-
-(def expr-tags
-  {:for {:handler for-hanlder}
-   :block {:handler
-           (fn [args rdr]
-             (let [content (tag-content "endblock" rdr)]
-               (fn [args] (render content args))))}})
-
-(defn expr-tag [{:keys [tag-name args]} rdr]
-  ((get-in expr-tags [(keyword tag-name) :handler]) args rdr))
-
 (defn handle-tag [rdr]
-  (let [tag (read-tag-info rdr)]
-    (if (= :value (:tag-type tag))
-      (value-tag tag)
+  (let [tag (read-tag-info rdr)]
+    (if (= :filter (:tag-type tag))
+      (filter-tag tag)
       (expr-tag tag rdr))))

-(defn parse [file & state]
+(defn parse [file]
   (with-open [rdr (clojure.java.io/reader file)]
       (let [template (transient [])
-            sb (StringBuilder.)]
-        (loop [state state
-               ch (.read rdr)]
-          (when (pos? ch)
-            (let [ch (char ch)]
-              (if (= \{ ch)
-                (do
-                  (conj! template (.toString sb))
-                  (.setLength sb 0)
-                  (conj! template (handle-tag rdr))
-                  (recur state (.read rdr)))
-                (do
-                  (.append sb ch)
-                  (recur state (.read rdr)))))))
-        (conj! template (.toString sb))
+            buf      (StringBuilder.)]
+        (loop [ch (read-char rdr)]
+          (when ch
+            (if (= tag-open ch)
+              (do
+                ;we hit a tag so we append the buffer content to the template
+                ; and empty the buffer, then we proceed to parse the tag
+                (conj! template (.toString buf))
+                (.setLength buf 0)
+                (conj! template (handle-tag rdr))
+                (recur (read-char rdr)))
+              (do
+                ;default case, here we simply append the character and
+                ;go to read the next one
+                (.append buf ch)
+                (recur (read-char rdr))))))
+        ;add the leftover content of the buffer and return the template
+        (conj! template (.toString buf))
         (persistent! template))))

-#_(render (parse "home.html") {:name "Bob" :users [[{:name "test" }] [{:name "test1" }]]})
+#_(spit "out.html" (render (parse "home.html") {:name "Bob" :users [[{:name "test" }] [{:name "test1" }]]}))
+#_(println (render (parse "home.html") {:name "Bob" :users [[{:name "test" }] [{:name "test1" }]]}))
+


Fixing default temp path

Fixing default temp path

--- src/clj/fortress/ring/server.clj
+++ src/clj/fortress/ring/server.clj
@@ -17,7 +17,6 @@
                       :port 3000
                       :ssl? false
                       :zero-copy? true
-                      :temp-path (System/getProperty ":ava.io.tmpdir")
                       :error-fn (fn [_ _])
                       :thread-prefix "fortress-http"})

@@ -128,6 +127,7 @@
   ([handler]
    (run-fortress handler {}))
   ([handler {:keys [debug-requests temp-path]
+             :or {temp-path (System/getProperty "java.io.tmpdir")}
              :as options}]
    (start-deleting temp-path)
    (let [options (merge default-options options)]


Made Aesop's not able to target itself

Made Aesop's not able to target itself

--- src/clj/game/cards-resources.clj
+++ src/clj/game/cards-resources.clj
@@ -24,7 +24,7 @@
    "Aesops Pawnshop"
    {:flags {:runner-phase-12 (req (>= 2 (count (all-installed state :runner))))}
     :abilities [{:msg (msg "trash " (:title target) " and gain 3 [Credits]")
-                 :choices {:req #(and (= (:side %) "Runner") (:installed %))}
+                 :choices {:req #(and (= (:side %) "Runner") (:installed %) (not= (:title %) "Aesop's Pawnshop"))}
                  :effect (effect (gain :credit 3) (trash target {:unpreventable true}))}]}

    "Always Be Running"


Some more atomic helpers

Some more atomic helpers

--- src/clj/momentum/core/atomic.clj
+++ src/clj/momentum/core/atomic.clj
@@ -29,6 +29,13 @@
   [atom & args]
   `(swap! ~atom (fn [val#] (assoc val# ~@args))))

+(defn atomic-queue
+  ([] (atom clojure.lang.PersistentQueue/EMPTY)))
+
+(defn atomic-stack
+  ([]     (atom (list)))
+  ([coll] (atom coll)))
+
 (defn atomic-pop!
   "Atomically pop an element off of a stack. The stack should be
   represented as an atom that references a seq."
@@ -47,3 +54,11 @@
     (let [new-head (cons val seq)]
       (if (compare-and-set! atom seq new-head)
         new-head (recur @atom)))))
+
+(defn atomic-conj!
+  "Atomically add an element onto a collection using conj."
+  [atom val]
+  (loop [coll @atom]
+    (let [new-coll (conj coll val)]
+      (if (compare-and-set! atom coll new-coll)
+        new-coll (recur @atom)))))


Improve summary code and printout

Improve summary code and printout

The patch introduces a converted from Java to Clojure summaries and tries to improve the readability
of intermediate summaries.

--- boot/core/src/boot/task_helpers.clj
+++ boot/core/src/boot/task_helpers.clj
@@ -14,8 +14,7 @@
     [boot.util               :as util]
     [boot.tmpdir             :as tmpd])
   (:import java.lang.InterruptedException
-           [java.util HashMap
-                      Collections
+           [java.util Map HashMap Collections
                       concurrent.ConcurrentHashMap
                       concurrent.CountDownLatch]))

@@ -152,6 +151,13 @@

 ;; test helpers ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

+(defn command-str
+  "Given a seq of command segments, the input to the runboot task,
+  return its string representation. Useful for Java interop, for example
+  it can be key in a HashMap."
+  [command-seq]
+  (string/join " " command-seq))
+
 (defn initial-sync-map
   "Generates the (mutable) sync map necessary for the test task.
   This map will be modified during parallel testing so make sure the
@@ -164,7 +170,7 @@
       (.put "start-latch" start-latch)
       (.put "done-latch" done-latch)
       (.put "test-number" (count test-commands))
-      ;; (.put "test-command") ;; set in runboot-comp as it is on a per-test basis
+      ;; (.put "test-command") ;; AR - set in per-task-sync-map cause on a per-test basis
       (.put "test-summaries" (ConcurrentHashMap.)))))

 (defn per-task-sync-map
@@ -173,7 +179,7 @@
   are thread safe."
   [sync-map command-seq]
   (Collections/unmodifiableMap
-   (let [command-str (string/join " " command-seq)]
+   (let [command-str (command-str command-seq)]
      (doto (.clone sync-map)
        (.put "test-command-str" command-str)
        #(-> (get % "test-summaries")
@@ -192,27 +198,52 @@
     (.countDown (get data "start-latch"))))

 (defn- print-summary!
+  "Print out (info) the summary. Note that it has to be in Clojure form
+  already, see clojurize-summary."
   [summary]
   ;; (util/dbug "%s" (into {} summary))
-  (util/info "Ran %s tests containing %s assertions.\n"
-             (get summary "test" 0)
-             (+ (get summary "pass" 0) (get summary "fail" 0) (get summary "error" 0)))
-  (util/info "%s failures, %s errors.\n"
-             (get summary "fail" 0)
-             (get summary "error" 0)))
+  (util/info "Ran %s tests, %s assertions, %s failures, %s errors.\n"
+             (get summary :test 0)
+             (+ (get summary :pass 0) (get summary :fail 0) (get summary :error 0))
+             (get summary :fail 0)
+             (get summary :error 0)))
+
+(defn- clojurize-summaries
+  "Transform Java to Clojure summaries, for instance converting keys to
+  keywords. Returns a map of summaries indexed by command string (the
+  boot in boot command executed, see command-str)."
+  [^Map java-summaries]
+  (assert (every? (partial instance? Map) (vals java-summaries)))
+  (zipmap (keys java-summaries)
+          (map (comp walk/keywordize-keys (partial into {})) (vals java-summaries))))
+
+(comment
+  (def m (doto (HashMap.)
+      (.put "a" {"test" 2 "pass" 1 "error" 1})
+      (.put "b" {})
+      (.put "c" {"test" 1 "fail" 1})))
+  (print-summary! (second (vals (clojurize-summaries m))))
+  (print-summary! (merge-summaries (vals (clojurize-summaries m)))))
+
+(defn- merge-summaries
+  "Merge summaries. Note that it has to be in Clojure form
+  already, see clojurize-summary."
+  [summaries]
+  (assert (every? map? summaries))
+  (apply merge-with + summaries))

 (core/deftask test-report
   [d data OBJECT ^:! code "The data for this task"]
   (fn [next-handler]
     (fn [fileset]
-      (let [summaries (get data "test-summaries")]
+      (let [summaries (clojurize-summaries (get data "test-summaries"))]
         ;; Individual report
         (doseq [[command-str summary] summaries]
-          (util/info "\nReporting \"boot %s\"\n" command-str)
+          (util/info "\n* boot %s\n" command-str)
           (print-summary! summary))
         ;; Summary
         (util/info "\nSummary\n")
-        (print-summary! (apply merge-with + (map (partial into {}) (vals summaries))))))))
+        (print-summary! (merge-summaries (vals summaries)))))))

 (defn done!
   "Signal that this pod is shutting down"
@@ -221,7 +252,7 @@
     (.countDown done-latch)
     (util/dbug "Remaining running tests %s\n" (.getCount done-latch))))

-(defn set-summary!
+(defn set-summary-data!
   "Set the summary in the (share) data for this pod"
   [data]
   (let [summaries (get data "test-summaries")
@@ -231,10 +262,8 @@

 (core/deftask inc-test-counter
   []
-  (fn [next-handler]
-    (fn [fileset]
-      (test/inc-report-counter :test)
-      (next-handler fileset))))
+  (core/with-pass-thru [_]
+    (test/inc-report-counter :test)))

 (core/deftask with-report-counters
   []
@@ -245,10 +274,8 @@

 (core/deftask set-summary
   []
-  (fn [next-handler]
-    (fn [fileset]
-      (set-summary! pod/data)
-      (next-handler fileset))))
+  (core/with-pass-thru [_]
+    (set-summary-data! pod/data)))

 (defn test-task
   "Create a boot test task by wrapping other tasks, either the result of


Fix sticky not positioning correctly on page load

--- src/cljs/clojuredocs/sticky.cljs
+++ src/cljs/clojuredocs/sticky.cljs
@@ -57,4 +57,5 @@
                   :top (str px-offset "px")))
               (dom/remove-class! $el :sticky)))]
     (dom/listen! js/window :scroll f)
-    (dom/listen! js/window :resize f)))
+    (dom/listen! js/window :resize f)
+    (f nil)))


om-if seems like it's working

om-if seems like it's working

--- src/cljs/om_lette/templater.cljs
+++ src/cljs/om_lette/templater.cljs
@@ -27,10 +27,11 @@
     h
     nil))

-(defn has-om-if? [h] (-> h like-html-vec? second :om-lette :om-if))
-(defn has-om-repeat? [h] (-> h like-html-vec? second :om-lette :om-repeat))
-(defn is-om-text? [h] (and (vector? h) (= (first h) :om-text)))
-(defn is-om-code? [h] (and (vector? h) (= (first h) :om-code)))
+(defn has-om-lette? [h kw] (if-let [v (-> h like-html-vec? second :om-lette kw)] [h v] nil))
+(defn has-om-if? [h] (has-om-lette? h :om-if))
+(defn has-om-repeat? [h] (has-om-lette? h :om-repeat))
+(defn is-om-text? [h] (and (vector? h) (= (first h) :om-text) (second h)))
+(defn is-om-code? [h] (and (vector? h) (= (first h) :om-code) (second h)))

 (defn strip-attrs [tag & xattrs]
   (let [[name attrs & rest] tag] (vec (concat [name (apply dissoc attrs xattrs)] rest))))
@@ -68,12 +69,12 @@
   [p]
   (->> p
        split-dbl-brackets
-       (map (fn [x] (condp #(= % (count %2)) x
-                      0 nil
-                      1 [:om-text (first x)]
-                      2 [:om-text (-> x drop-delim first)]
-                      3 [:om-code (second x)])))
-       (filter #(-> % second not-empty))))
+       (mapv (fn [x] (condp #(= % (count %2)) x
+                       0 nil
+                       1 [:om-text (first x)]
+                       2 [:om-text (-> x drop-delim first)]
+                       3 [:om-code (second x)])))
+       (filterv #(-> % second not-empty))))

 (defn grab-om-attrs
   [a ks]
@@ -84,6 +85,10 @@
                   (assoc :om-lette (select-keys a ks)))
               a))]
     r))
+
+(defn eval-om-if-expr
+  [x state]
+  (get state (apply str (mapcat second x))))

 (defn html->template
   [h]
@@ -105,20 +110,30 @@
               (get-html-template %))
         names))

+(defn processors
+  [state]
+  [[is-om-text? identity]
+   [is-om-code? #(get state % "")]
+   [has-om-if? (fn [[h ifx]]
+                 (if (eval-om-if-expr ifx state)
+                   h
+                   nil))]])
+
 (defn template->hiccup
   [tmplt state]
-  (walk/prewalk (fn [x]
-                  (cond (is-om-text? x) (second x)
-                        (is-om-code? x) (get state (second x) "")
-                        (has-om-if? x) (if (get state (second x))
-                                         x
-                                         nil)
-                        :else x))
+  (walk/prewalk (fn [h]
+                  (reduce (fn [current [pred proc-fn]]
+                            (if-let [r (pred current)]
+                              (proc-fn r)
+                              current))
+                          h
+                          (processors state)))
                 tmplt))

 (defn cached-template->hiccup
   [tname state]
-  (template->hiccup (get @template-cache tname) state))
+  (let [r (template->hiccup (get @template-cache tname) state)]
+    r))

 #_ (-> "<div>{{a}}</div" html->template (template->hiccup {"a" 33}))


improve clojure-api file org

improve clojure-api file org


Re-add GA to bare layout.

Re-add GA to bare layout.

--- src/stuttaford/web/layout/html.clj
+++ src/stuttaford/web/layout/html.clj
@@ -45,16 +45,18 @@
     "I'm on " [:a {:href twitter} "Twitter"]
     " and " [:a {:href github} "GitHub"] "."]])

-(defnk foot [google-analytics-id domain year [:author name]]
+(defnk foot [domain year [:author name]]
   [:div.footer
-   [:p "© " name " " year ". All rights reserved. Some lefts, too."]
-   [:script {:type "text/javascript"}
-    "(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
+   [:p "© " name " " year ". All rights reserved. Some lefts, too."]])
+
+(defnk google-analytics [google-analytics-id]
+  [:script {:type "text/javascript"}
+   "(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
     (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
     m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
     })(window,document,'script','//www.google-analytics.com/analytics.js','google_analytics');
     google_analytics('create', '" google-analytics-id "', '" domain "');
-    google_analytics('send', 'pageview');"]])
+    google_analytics('send', 'pageview');"])

 (defnk html-layout [base-url [:page layout content] :as config]
   (let [layout (keyword layout)]
@@ -67,4 +69,5 @@
        (when-let [page-layout (layout templates)]
          (page-layout config))
        (when-not (= :bare layout)
-         (foot config))]])))
+         (foot config))
+       (google-analytics config)]])))


REST API module: read-request-body, send-response, refactoring

--- src/emender_service/rest_api.clj
+++ src/emender_service/rest_api.clj
@@ -15,26 +15,45 @@
 (require '[ring.util.response     :as http-response])
 (require '[clojure.data.json      :as json])

+(require '[emender-service.file-utils :as file-utils])
+
+(defn read-request-body
+    [request]
+    (file-utils/slurp- (:body request)))
+
+(defn body->job-name
+    [body]
+    (let [data (json/read-str body)]
+        (get data "name")))
+
+(defn send-response
+    [response]
+    (-> (http-response/response (json/write-str response))
+        (http-response/content-type "application/json")))
+
 (defn info-handler
     [request hostname]
     (let [response {:toasterNotifications [(str "info|Api response|Emender Service api v1 on
" hostname)]
                     :configuration (:configuration request)}]
-        (-> (http-response/response (json/write-str response))
-            (http-response/content-type "application/json"))))
+        (send-response response)))

 (defn unknown-call-handler
     [uri method]
-    (let [response {:error "Unknown API call"
+    (let [response {:status :error
+                    :error "Unknown API call"
                     :uri uri
                     :method method}]
-        (-> (http-response/response (json/write-str response))
-            (http-response/content-type "application/json"))))
+        (send-response response)))

-(defn job-start-handler
+(defn job-started-handler
     [request]
-    (println "job started"))
+    (let [job-name (-> (read-request-body request) body->job-name)]
+        (println "job started" job-name)
+        (send-response {:status :ok})))

 (defn job-finished-handler
     [request]
-    (println "job finished"))
+    (let [job-name (-> (read-request-body request) body->job-name)]
+        (println "job finished" job-name)
+        (send-response {:status :ok})))


Fix indentation

Fix indentation

--- src/afrey/boot_asset_fingerprint.clj
+++ src/afrey/boot_asset_fingerprint.clj
@@ -9,12 +9,13 @@
   (or (-> path io/file .getParent) ""))

 (defn fingerprint-file [[path hash]]
-  (let [regex #"(.*)\.([^.]*?)$"
+  (let [regex       #"(.*)\.([^.]*?)$"
         replacement (clojure.string/replace path regex (str "$1-" hash ".$2"))]
     [path replacement]))

 (defn- add-fingerprint-to-filenames [fileset sources]
-  (reduce (fn [fs [source dest]] (core/mv fs source dest)) fileset sources))
+  (reduce (fn [fs [source dest]] (core/mv fs source dest))
+    fileset sources))

 (def default-source-extensions [".html"])


Trying to fix issue with require missing in electron ver 5+

Relates to #20

--- electron_src/electron/core.cljs
+++ electron_src/electron/core.cljs
@@ -10,7 +10,8 @@
 (defn init-browser []
   (reset! main-window (browser-window.
                         (clj->js {:width 800
-                                  :height 600})))
+                                  :height 600
+                                  :webPreferences {:nodeIntegration true}})))
   ; Path is relative to the compiled js file (main.js in our case)
   (.loadURL ^js/electron.BrowserWindow @main-window (str "file://" js/__dirname "/public/index.html"))
   (.on ^js/electron.BrowserWindow @main-window "closed" #(reset! main-window nil)))


WIP: getting basic info from asana

WIP: getting basic info from asana

--- src/chat/server/extensions/asana.clj
+++ src/chat/server/extensions/asana.clj
@@ -22,6 +22,8 @@
 (def client-id (env :asana-client-id))
 (def client-secret (env :asana-client-secret))

+
+;; Authentication flow
 (def token-url "https://app.asana.com/-/oauth_token")
 (def authorization-url "https://app.asana.com/-/oauth_authorize")
 (def api-url "https://app.asana.com/api/1.0")
@@ -58,6 +60,23 @@
                                                   :refresh-token refresh_token})))
             (timbre/warnf "Bad response when exchanging token %s" (:body resp))))))))

+(defn refresh-token
+  [ext]
+  (let [refresh-token (:refresh-token ext)]
+    (let [resp @(http/post token-url
+                           {:form-params {"grant_type" "refresh_token"
+                                          "client_id" client-id
+                                          "client_secret" client-secret
+                                          "redirect_uri" redirect-uri
+                                          "refresh_token" refresh-token}})]
+      (if (= 200 (:status resp))
+        (let [{:strs [access_token refresh_token]} (json/read-str (:body resp))]
+          (db/with-conn
+            (db/save-extension-token! (ext :id) {:access-token access_token
+                                                 :refresh-token refresh_token})))
+        (timbre/warnf "Bad response when exchanging token %s" (:body resp))))))
+
+;; Webhooks
 (defn register-webhook
   [extension-id]
   (let [ext (db/with-conn (db/extension-by-id extension-id))
@@ -74,3 +93,22 @@
     {:status 200 :headers {"X-Hook-Secret" secret}}
     (do (println "webhook" event-req)
         {:status 200})))
+
+;; Fetching information
+(defn fetch-asana-info
+  [extension-id path]
+  (let [ext (db/with-conn (db/extension-by-id extension-id))]
+    (let [resp @(http/get (str api-url path)
+                  {:oauth-token (ext :token)})]
+      (if (= 200 (:status resp))
+        (-> resp :body json/read-str)
+        (timbre/warnf "token expired %s" (:body resp))))))
+
+(defn available-workspaces
+  [extension-id]
+  (-> (fetch-asana-info extension-id "/users/me")
+      (get-in ["data" "workspaces"])))
+
+(defn workspace-projects
+  [extension-id workspace-id]
+  (fetch-asana-info extension-id (str "/workspaces/" workspace-id "/projects")))


Fix bug

Fix bug

--- src/checkin_halake/models/events.clj
+++ src/checkin_halake/models/events.clj
@@ -15,6 +15,6 @@
 ;; (register-event "Swift開発講座" "/images/evnets/inside_halake.png" (java.util.Date ) "taro@email.com" "hoge" "Taro" "090")

 (defn query-events []
-  (map (mc/find-maps db "events")))
+  (mc/find-maps db "events"))

 ;; (query-events)


Quick'n'dirty fix for first playoff game of series still in progress

--- src/nhl_score_api/fetchers/mlbam/game_scores.clj
+++ src/nhl_score_api/fetchers/mlbam/game_scores.clj
@@ -174,12 +174,15 @@
       (let [win-count (read-string (nth series-tied-match 1))]
         {away-team win-count
          home-team win-count})
-      (let [team-leads-match (re-find #"(\w+) (?:leads|wins) (\d)-(\d)" series-summary-description)
-            leading-team (nth team-leads-match 1)
-            leading-team-win-count (read-string (nth team-leads-match 2))
-            trailing-team-win-count (read-string (nth team-leads-match 3))]
-        {away-team (if (= away-team leading-team) leading-team-win-count trailing-team-win-count)
-         home-team (if (= home-team leading-team) leading-team-win-count trailing-team-win-count)}))))
+      (let [team-leads-match (re-find #"(\w+) (?:leads|wins) (\d)-(\d)" series-summary-description)]
+        (if team-leads-match
+          (let [leading-team (nth team-leads-match 1)
+                leading-team-win-count (read-string (nth team-leads-match 2))
+                trailing-team-win-count (read-string (nth team-leads-match 3))]
+            {away-team (if (= away-team leading-team) leading-team-win-count trailing-team-win-count)
+             home-team (if (= home-team leading-team) leading-team-win-count trailing-team-win-count)})
+          {away-team 0
+           home-team 0})))))

 (defn- get-winning-team [game-details]
   (let [away-team (:away (:teams game-details))


Adding a middleware to log each request/response the server does

--- src/clj/baconator/server/handler.clj
+++ src/clj/baconator/server/handler.clj
@@ -78,9 +78,16 @@
   (route/resources "/")
   (route/not-found "Not Found"))

+(defn wrap-logging [handler]
+  (fn [req]
+    (let [resp (handler req)]
+      (info  (:remote-addr req) "==" (:request-method req) (:uri req) "=>" (:status resp))
+      resp)))
+
 (def application
   (->
    (handler/site app-routes)
+   (wrap-logging)
    reload/wrap-reload))

 (defn -main [& args]


Add player display

Add player display

--- src/cljs/love_letter_cljs/views.cljs
+++ src/cljs/love_letter_cljs/views.cljs
@@ -199,28 +199,12 @@
            [:div.col-md-4.col-sm-4.col-xs-4
             [card-display]]]]])))

-(defn- card-spread [cards]
-  (map-indexed
-   (fn [i c]
-     ^{:key (str i (:face c))}
-     [:div.discarded-card
-      {:style {:position "absolute"
-               :left (str (* 30 i) "px")
-               :width "65px"
-               :height "85px"
-               :border-radius "5px"
-               :border-color "black"
-               :border-style "solid"
-               :background-size "contain"
-               :background-image (str "url(images/cardart/" (name (:face c)) ".png)")
-               :border-width "2px"}}]) cards))
-
 (defn discard-pile [cards]
   [:div
    [:div {:style {:position "relative"
                   :height "120px"
                   :width  "425px"
-                  :background-color "darkgray"}}
+                  :background-color "black"}}
     (map-indexed (fn [i c]
                    ^{:key (str i (:face c))}
                    [:div.discarded-card
@@ -234,6 +218,8 @@
                              :background-size "contain"
                              :background-image (str "url(images/cardart/" (name (:face c)) ".png)")
                              :border-width "2px"}}]) cards)]])
+
+

 (defn player-one-area [player-info phase active-player?]
   (let [player-info (subscribe [:player-info 1])
@@ -306,8 +292,41 @@
              {:on-click #(dispatch [:set-guard-guess guess])}
              (s/capitalize (name guess))]) card-faces)]))))

-(defn button [label on-click]
-  [:button {:on-click on-click} label])
+(def face->symbol
+  {:guard "G"
+   :priest "Pst"
+   :baron "B"
+   :handmaid "H"
+   :prince "Prnc"
+   :king   "K"
+   :countess "C"
+   :princess "P"})
+
+(defn in?
+  [coll element]
+  (some #(= element %) coll))
+
+(defn hand->symbols [hand]
+  (s/join
+   (reduce
+    (fn [string card]
+      (if (in? (:visible card) 1)
+        (concat string (face->symbol (:face card)))
+        string)) "" hand)))
+
+(defn player-display [current-player players]
+  [:ul {:style {:list-style "none"
+                :font-size "1em"}}
+   (map-indexed
+    (fn [i p]
+      (let [{:keys [id hand alive? protected?]} p]
+        ^{:key (str "player" i "display")}
+        [:li {:style {:text-decoration (if alive? "" "line-through")
+                      :color (if (= current-player id) "steelblue" "white")}}
+         (str (when protected? (js/String.fromCharCode 9730))
+              " Player " id " "
+              (hand->symbols hand))])) players)])
+

 (defn game-screen []
   (let [deck              (subscribe [:deck])
@@ -333,6 +352,10 @@
        [:div#discard-pile {:style {:position "absolute" :left "35%" :bottom "60%"}}
         [discard-pile @discarded-cards]]

+       [:div#player-display {:style {:position "absolute" :left "80%" :top "20%"}}
+        [player-display @current-player-id @players]
+        ]
+
        [:div#player-controls
         [:div (menu-box-style "0%")
          (if (= 1 @current-player-id)
@@ -371,10 +394,10 @@
         (reverse (sort-by :value scores)))]]))

 (defn win-screen []
-  (let [score (subscribe [:score-game])]
+  (let [scores (subscribe [:score-game])]
     (fn []
       [:div.flex-item {:margin-bottom 200}
-       [:div (parse-winner @score)]
+       [:div (parse-winner @scores)]
        [:button
         {:style {:position "absolute" :left "45%" :bottom "30%"}
          :on-click #(do (dispatch [:new-game]) (dispatch [:set-active-screen :game-screen]))} "New Game"]


fix class on element

fix class on element

--- src/cljs/phonecat_re_frame/core.cljs
+++ src/cljs/phonecat_re_frame/core.cljs
@@ -53,7 +53,7 @@
   (let [phones (re-frame/subscribe [:phones])
         search-input (re-frame/subscribe [:search-input])]
     (fn []
-      [:ul {:class= "phones"}
+      [:ul {:class "phones"}
        (for [phone (filter (partial matches-query? @search-input) @phones)]
          ^{:key phone} [phone-component (:name phone) (:snippet phone)])])))


Remove libs from *loaded-libs* before reloading

* More efficient than :reload-all
* May prevent some load-order errors

--- src/main/clojure/lazytest/reload.clj
+++ src/main/clojure/lazytest/reload.clj
@@ -1,9 +1,17 @@
-(ns lazytest.reload)
+(ns lazytest.reload
+  (:require clojure.set))
+
+(defn remove-from-loaded-libs
+  "Removes symbols from the set in the private Ref clojure.core/*loaded-libs*"
+  [& syms]
+  (dosync
+   (alter @#'clojure.core/*loaded-libs*
+	  clojure.set/difference (set syms))))

 (defn reload
-  "Removes all namespaces named by symbols, then reloads those
-  namespaces and all their dependencies."
+  "Removes all namespaces named by symbols, then reloads them."
   [& symbols]
   {:pre (every? symbol? symbols)}
   (doseq [sym symbols] (remove-ns sym))
-  (apply require :reload-all symbols))
+  (apply remove-from-loaded-libs symbols)
+  (apply require symbols))


fix param-match-type?

fix param-match-type?

--- src/app/find.clj
+++ src/app/find.clj
@@ -20,9 +20,8 @@

 (defn param-match-type? [pair]
   (let [[param expected-type] pair
-        paramType (.getType param)
-        paramSolvedType (solveType paramType)]
-    (type-exact-match? paramSolvedType expected-type)))
+        paramType (.getType param)]
+    (type-exact-match? paramType expected-type)))

 (defn method-match-exactly-parameters? [param-expected-types method]
   (let [params (.getParameters method)


Catch unserializable exception errors and re-wrap them (#893)

* Catch unserializable exception errors and re-wrap them

The clojure.lang.ExceptionInfo: Unfreezable type exception thrown by
nippy when this happens is itself serialzable, so we just catch that and serialize
it instead of the original exception.

* Warn on unserializable exceptions

--- src/onyx/log/zookeeper.clj
+++ src/onyx/log/zookeeper.clj
@@ -582,7 +582,10 @@

 (defmethod extensions/write-chunk [ZooKeeper :exception]
   [{:keys [conn opts prefix monitoring] :as log} kw chunk id]
-  (let [bytes (zookeeper-compress chunk)]
+  (let [bytes (try (zookeeper-compress chunk)
+                   (catch clojure.lang.ExceptionInfo unserializable
+                     (warn unserializable)
+                     (zookeeper-compress unserializable)))]
     (measure-latency
      #(clean-up-broken-connections
        (fn []


Move getting the allocations outside the loop.

--- src/onyx/peer/function.clj
+++ src/onyx/peer/function.clj
@@ -39,6 +39,7 @@
              (into-transient coll (first vs)))
       (persistent! coll))))

+;; needs a performance boost
 (defn build-segments-to-send [leaves]
   (->> leaves
        (map (fn [{:keys [routes ack-vals hash-group message] :as leaf}]
@@ -66,6 +67,7 @@
                 (count active-peers)))
       (rand-nth active-peers))))

+;; Needs a performance boost
 (defmethod p-ext/write-batch :default
   [{:keys [onyx.core/results onyx.core/messenger onyx.core/job-id] :as event}]
   (let [leaves (fast-concat (map :leaves results))
@@ -73,9 +75,10 @@
     (when-not (empty? leaves)
       (let [replica @(:onyx.core/replica event)
             segments (build-segments-to-send leaves)
-            groups (group-by (juxt :route :hash-group) segments)]
+            groups (group-by (juxt :route :hash-group) segments)
+            allocations (get (:allocations replica) job-id)]
         (doseq [[[route hash-group] segs] groups]
-          (let [peers (get-in replica [:allocations job-id (get egress-tasks route)])
+          (let [peers (get allocations (get egress-tasks route))
                 active-peers (filter #(= (get-in replica [:peer-state %]) :active) peers)
                 target (pick-peer active-peers hash-group)]
             (when target


Re-throw exception in leaf function tasks when task fn throws an exception.

--- src/onyx/peer/function.clj
+++ src/onyx/peer/function.clj
@@ -2,9 +2,21 @@
   (:require [taoensso.timbre :refer [fatal info debug] :as timbre]
             [onyx.protocol.task-state :refer :all]
             [onyx.messaging.protocols.messenger :as m]
+            [onyx.static.util :refer [kw->fn exception?] :as u]
             [onyx.plugin.protocols.output :as o]
             [onyx.plugin.protocols.plugin :as p]))

+(defn throw-exceptions!
+  "Temporary work-around for the fact that flow conditions are not possible
+   when using the function plugin as an output task. Long term goal should be
+   to determine how to use flow conditions in a clean way with leaf tasks."
+  [results]
+  (run! (fn [{:keys [leaves]}]
+            (run! (fn [segment]
+                    (when (exception? segment)
+                       (throw segment)))
+                  leaves))
+          (:tree results)))

 (defrecord NullWriter [event prepared]
   p/Plugin
@@ -26,8 +38,8 @@
   (prepare-batch [this event _]
     true)

-  (write-batch
-    [this _ _ _]
+  (write-batch [this {:keys [onyx.core/results]} _ _]
+    (throw-exceptions! results)
     true))

 (defn function [event]


added missing function to callable-map proxy.

--- src/overtone/core/util.clj
+++ src/overtone/core/util.clj
@@ -92,15 +92,16 @@

 (defn callable-map [m fun]
     (proxy [clojure.lang.Associative clojure.lang.IFn] []
-      (count [] (count m))
-      (seq   [] (seq m))
-      (cons  [[k v]] (callable-map (assoc m k v)))
-      (empty [] {})
-      (equiv [o] (= o m))
+      (count       [] (count m))
+      (seq         [] (seq m))
+      (cons        [[k v]] (callable-map (assoc m k v) fun))
+      (empty       [] {})
+      (equiv       [o] (= o m))
       (containsKey [k] (contains? m k))
       (entryAt     [k] (map-entry k (get m k)))
-      (assoc       [k v] (callable-map (assoc m k v)))
+      (assoc       [k v] (callable-map (assoc m k v) fun))
       (valAt
-        ([k] (get m k))
-        ([k d] (get m k d)))
-      (invoke [& args] (apply fun args))))
+                  ([k] (get m k))
+                  ([k d] (get m k d)))
+      (invoke      [& args] (apply fun args))
+      (applyTo    ([args] (apply fun args)))))


Tentative fix for Issue 363: 	backspace doesn't work in editor

--- src/paredit/text_utils.clj
+++ src/paredit/text_utils.clj
@@ -19,7 +19,7 @@

 (defn insert
   "insert what at offset. offset shifted by what's length, selection length unchanged"
-  ([{:keys [^String text offset length modifs] :as where :or {:modifs []}} ^String what]
+  ([{:keys [^String text offset length modifs] :as where :or {modifs []}} ^String what]
     (let [new-offset (+ offset (.length what))]
       (assoc where
         :text (str (.substring text 0 offset) what (.substring text offset))
@@ -30,7 +30,7 @@
   "removes n chars at offset off. offset not shifted, selection length unchanged"
   ; TODO FIXME : decrease length if now that things are removed, length would make the selection overflow the text
   ; and also adjust :offset if off is before it
-  [{:keys [^String text offset length modifs] :as where :or {:modifs []}} off n]
+  [{:keys [^String text offset length modifs] :as where :or {modifs []}} off n]
   (assoc where
     :text (str (.substring text 0 off) (.substring text (+ off n)))
     :offset offset


thru rm_case_prod_devices

thru rm_case_prod_devices

--- src/pg_demo/table_defs.clj
+++ src/pg_demo/table_defs.clj
@@ -1684,6 +1684,277 @@
               PRIMARY KEY (ENTERPRISE_ID,CASE_ID,REVISION,DLP_REVISION_NUMBER)
           ); " }

+    { "rm_case_pregnancy"
+          "CREATE TABLE rm_case_pregnancy (
+              ENTERPRISE_ID numeric NOT NULL,
+              CASE_ID numeric NOT NULL,
+              DATE_OF_LMP timestamp,
+              WEEKS numeric,
+              DUE_DATE timestamp,
+              EXP_TRIMESTER numeric,
+              GESTATION_EXP_PERIOD numeric,
+              PARENT numeric(1) NOT NULL,
+              DELETED timestamp,
+              BREASTFEEDING numeric(1),
+              PROSPECTIVE numeric(1),
+              NUMBER_OF_FETUS numeric(2),
+              DATE_OF_LMP_RES numeric,
+              DATE_OF_LMP_PARTIAL varchar(20),
+              GRAVIDA numeric,
+              PARA numeric,
+              DLP_REVISION_NUMBER numeric NOT NULL,
+              REVISION_DELETE_FLAG numeric,
+              DELETED_FLAG numeric(1) NOT NULL,
+              EFFECTIVE_START_DATE timestamp NOT NULL,
+              EFFECTIVE_END_DATE timestamp NOT NULL,
+              PRIMARY KEY (ENTERPRISE_ID,CASE_ID,PARENT,DLP_REVISION_NUMBER)
+          ); " }
+
+    { "rm_case_product"
+          "CREATE TABLE rm_case_product (
+              ENTERPRISE_ID numeric NOT NULL,
+              CASE_ID numeric NOT NULL,
+              SEQ_NUM numeric NOT NULL,
+              PRODUCT_ID numeric,
+              DRUG_TYPE numeric,
+              PAT_EXPOSURE numeric,
+              MANUFACTURER_ID numeric,
+              PROTOCOL_FOLLOWED numeric,
+              FIRST_SUS_PROD numeric,
+              SELECTED_VIEW numeric,
+              SORT_ID numeric,
+              VIEWS_AVAILABLE numeric,
+              COUNTRY_ID numeric,
+              QC_SAFETY_DATE timestamp,
+              QC_SENT_DATE timestamp,
+              QC_RESULT_DATE timestamp,
+              QC_CROSS_REFERENCE varchar(16),
+              WHO_DRUG_CODE varchar(45),
+              CO_DRUG_CODE varchar(20),
+              PRODUCT_NAME varchar(70),
+              GENERIC_NAME text,
+              GENERIC_NAME_J text,
+              UD_TEXT_1 varchar(100),
+              UD_TEXT_2 varchar(100),
+              UD_TEXT_3 varchar(100),
+              UD_TEXT_4 varchar(100),
+              UD_TEXT_5 varchar(100),
+              UD_TEXT_6 varchar(100),
+              UD_TEXT_7 varchar(100),
+              UD_TEXT_8 varchar(100),
+              UD_TEXT_9 varchar(100),
+              UD_TEXT_10 varchar(100),
+              UD_TEXT_11 varchar(100),
+              UD_TEXT_12 varchar(100),
+              UD_DATE_1 timestamp,
+              UD_DATE_2 timestamp,
+              UD_DATE_3 timestamp,
+              UD_DATE_4 timestamp,
+              UD_DATE_5 timestamp,
+              UD_DATE_6 timestamp,
+              UD_DATE_7 timestamp,
+              UD_DATE_8 timestamp,
+              UD_DATE_9 timestamp,
+              UD_DATE_10 timestamp,
+              UD_DATE_11 timestamp,
+              UD_DATE_12 timestamp,
+              UD_NUMBER_1 numeric(30,10),
+              UD_NUMBER_2 numeric(30,10),
+              UD_NUMBER_3 numeric(30,10),
+              UD_NUMBER_4 numeric(30,10),
+              UD_NUMBER_5 numeric(30,10),
+              UD_NUMBER_6 numeric(30,10),
+              UD_NUMBER_7 numeric(30,10),
+              UD_NUMBER_8 numeric(30,10),
+              UD_NUMBER_9 numeric(30,10),
+              UD_NUMBER_10 numeric(30,10),
+              UD_NUMBER_11 numeric(30,10),
+              UD_NUMBER_12 numeric(30,10),
+              INCLUDE_FREQUENCY numeric,
+              SDRUG_NOT_ADMIN numeric,
+              PROD_REPTD varchar(255),
+              PROD_CODED varchar(255),
+              PROD_SYN_ID numeric,
+              PROD_CODE_STATUS numeric(3),
+              DELETED timestamp,
+              STUDY_PRODUCT_NUM numeric(2),
+              QC_QUANTITY varchar(10),
+              QC_RETURN_DATE timestamp,
+              QC_COMPLAINT_CAT_DATE timestamp,
+              QC_ANALYSIS_CAT_DATE timestamp,
+              QC_ANALYSIS_SUMMARY_DATE timestamp,
+              PRIMARY_EVENT numeric,
+              MEDICINAL_PROD_ID varchar(10),
+              FAMILY_ID numeric,
+              EXISTING_RPT_SEQ_MOD_FLG numeric,
+              DRUG_CODE_J varchar(20),
+              DRUG_CODE_TYPE_J numeric,
+              PRODUCT_NAME_J varchar(70),
+              PROD_CODED_J varchar(255),
+              PROD_REPTD_J varchar(255),
+              QC_CROSS_REFERENCE_J varchar(16),
+              UD_TEXT_1_J varchar(100),
+              UD_TEXT_2_J varchar(100),
+              UD_TEXT_3_J varchar(100),
+              UD_TEXT_4_J varchar(100),
+              UD_TEXT_5_J varchar(100),
+              UD_TEXT_6_J varchar(100),
+              UD_TEXT_7_J varchar(100),
+              UD_TEXT_8_J varchar(100),
+              UD_TEXT_9_J varchar(100),
+              UD_TEXT_10_J varchar(100),
+              UD_TEXT_11_J varchar(100),
+              UD_TEXT_12_J varchar(100),
+              DLP_REVISION_NUMBER numeric NOT NULL,
+              LAST_UPDATE_TIME timestamp,
+              REVISION_DELETE_FLAG numeric,
+              DELETED_FLAG numeric(1) NOT NULL,
+              EFFECTIVE_START_DATE timestamp NOT NULL,
+              EFFECTIVE_END_DATE timestamp NOT NULL,
+              NOTES text,
+              NOTES_J text,
+              QC_ANALYSIS_CAT_TEXT text,
+              QC_ANALYSIS_CAT_TEXT_J text,
+              QC_ANAL_SUMMARY_TEXT text,
+              QC_ANAL_SUMMARY_TEXT_J text,
+              QC_RESULT text,
+              QC_RESULT_J text,
+              QC_COMMENT text,
+              QC_COMMENT_J text,
+              QC_COMPLAINT_CAT_TEXT text,
+              QC_COMPLAINT_CAT_TEXT_J text,
+              VAERS_BLOCK_ID numeric,
+              PROD_LIC_ID numeric,
+              PRIMARY KEY (ENTERPRISE_ID,CASE_ID,SEQ_NUM,DLP_REVISION_NUMBER)
+          ); " }
+
+    { "rm_case_prod_devices"
+          "CREATE TABLE rm_case_prod_devices (
+              ENTERPRISE_ID numeric NOT NULL,
+              CASE_ID numeric NOT NULL,
+              SEQ_NUM numeric NOT NULL,
+              MODEL_NO varchar(20),
+              LOT_NO varchar(35),
+              SERIAL_NO varchar(20),
+              DATE_IMPLANT timestamp,
+              DATE_IMPANT_RES numeric,
+              DATE_EXPLANT timestamp,
+              DATE_EXPLANT_RES numeric,
+              DEVICE_AGE varchar(10),
+              EXP_DATE timestamp,
+              EXP_DATE_RES numeric,
+              SORT_ID numeric,
+              EXPLANT_DATE_PARTIAL varchar(20),
+              IMPLANT_DATE_PARTIAL varchar(20),
+              EXP_DATE_PARTIAL varchar(20),
+              DELETED timestamp,
+              MALFUNCTION_DATE timestamp,
+              LOT_ID numeric,
+              LOT_JUST varchar(1000),
+              LOT_STATUS numeric(1),
+              MFR_EVALUATION numeric,
+              MFR_EVAL_REASON_ID numeric,
+              MFG_DATE timestamp,
+              REMEDIAL_ACTION numeric,
+              REMEDIAL_OTHER varchar(20),
+              DEV_USAGE numeric,
+              DEV_OPER numeric,
+              DEV_OPER_OTHER_TEXT varchar(20),
+              CATALOG varchar(20),
+              CATALOG_OTHER varchar(30),
+              EVALUATION numeric,
+              RETURN_DATE timestamp,
+              SUBCOMPONENT_ID numeric,
+              SUBCOMPONENT_LOT varchar(35),
+              DEVICE_TYPE numeric,
+              TRAINED_USER numeric,
+              IMPROPER_USE numeric,
+              MALFUNCTION numeric,
+              MALFUNCTION_TYPE numeric,
+              REPROCESSED_REUSE numeric,
+              REPROCESSOR_NAME_ADDRESS varchar(200),
+              UD_TEXT_1 varchar(100),
+              UD_TEXT_2 varchar(100),
+              UD_TEXT_3 varchar(100),
+              UD_TEXT_4 varchar(100),
+              UD_TEXT_5 varchar(100),
+              UD_TEXT_6 varchar(100),
+              UD_TEXT_7 varchar(100),
+              UD_TEXT_8 varchar(100),
+              UD_TEXT_9 varchar(100),
+              UD_TEXT_10 varchar(100),
+              UD_TEXT_11 varchar(100),
+              UD_TEXT_12 varchar(100),
+              UD_DATE_1 timestamp,
+              UD_DATE_2 timestamp,
+              UD_DATE_3 timestamp,
+              UD_DATE_4 timestamp,
+              UD_DATE_5 timestamp,
+              UD_DATE_6 timestamp,
+              UD_DATE_7 timestamp,
+              UD_DATE_8 timestamp,
+              UD_DATE_9 timestamp,
+              UD_DATE_10 timestamp,
+              UD_DATE_11 timestamp,
+              UD_DATE_12 timestamp,
+              UD_NUMBER_1 numeric(30,10),
+              UD_NUMBER_2 numeric(30,10),
+              UD_NUMBER_3 numeric(30,10),
+              UD_NUMBER_4 numeric(30,10),
+              UD_NUMBER_5 numeric(30,10),
+              UD_NUMBER_6 numeric(30,10),
+              UD_NUMBER_7 numeric(30,10),
+              UD_NUMBER_8 numeric(30,10),
+              UD_NUMBER_9 numeric(30,10),
+              UD_NUMBER_10 numeric(30,10),
+              UD_NUMBER_11 numeric(30,10),
+              UD_NUMBER_12 numeric(30,10),
+              FOLLOWUP_TYPE numeric,
+              METH_CD1 varchar(4),
+              METH_CD2 varchar(4),
+              METH_CD3 varchar(4),
+              METH_CD4 varchar(4),
+              RES_CD1 varchar(4),
+              RES_CD2 varchar(4),
+              RES_CD3 varchar(4),
+              RES_CD4 varchar(4),
+              CONC_CD1 varchar(4),
+              CONC_CD2 varchar(4),
+              CONC_CD3 varchar(4),
+              CONC_CD4 varchar(4),
+              USC varchar(20),
+              MANU_NARRATIVE numeric(1),
+              MANU_CORRECTED numeric(1),
+              ADVERSE_EVENT numeric,
+              PRODUCT_PROBLEM numeric,
+              REPORT_TYPE numeric,
+              MFG_DATE_PARTIAL varchar(20),
+              MFG_DATE_RES numeric,
+              UD_TEXT_1_J varchar(100),
+              UD_TEXT_2_J varchar(100),
+              UD_TEXT_3_J varchar(100),
+              UD_TEXT_4_J varchar(100),
+              UD_TEXT_5_J varchar(100),
+              UD_TEXT_6_J varchar(100),
+              UD_TEXT_7_J varchar(100),
+              UD_TEXT_8_J varchar(100),
+              UD_TEXT_9_J varchar(100),
+              UD_TEXT_10_J varchar(100),
+              UD_TEXT_11_J varchar(100),
+              UD_TEXT_12_J varchar(100),
+              LOT_JUST_J varchar(1000),
+              DLP_REVISION_NUMBER numeric NOT NULL,
+              IMPLANT_DURATION varchar(20),
+              REVISION_DELETE_FLAG numeric,
+              DELETED_FLAG numeric(1) NOT NULL,
+              EFFECTIVE_START_DATE timestamp NOT NULL,
+              EFFECTIVE_END_DATE timestamp NOT NULL,
+              PRELIMINARY_COMMENTS text,
+              NARRATIVE_TEXT text,
+              PRELIMINARY_COMMENTS_J text,
+              PRIMARY KEY (ENTERPRISE_ID,CASE_ID,SEQ_NUM,DLP_REVISION_NUMBER)
+          ); " }
+
   ] ))

 (def dummy


bug fixed: readonly ratom status not enforced after the first reset! call

--- src/reagent_mvsa/core.cljs
+++ src/reagent_mvsa/core.cljs
@@ -11,7 +11,7 @@
       (-reset!
         [this new-value]
         (if (::force-reset? (meta new-value))
-          (original-reset-fn this new-value)
+          (original-reset-fn this (with-meta new-value nil))
           (assert nil (str "readonly atom cannot be reset to " (pr-str new-value))))))))

 (defn -force-reset!


move to dev local

move to dev local

--- tutorial/migration.clj
+++ tutorial/migration.clj
@@ -9,13 +9,10 @@
 (require '[datomic.client.api :as d]
          '[datomic.samples.repl :as repl]
          '[datomic.samples.schema :as schema])
-(import '(java.util UUID))

-(def client-cfg (read-string (slurp "config.edn")))
-(def client (d/client client-cfg))
-(def db-name (str "scratch-" (UUID/randomUUID)))
-(d/create-database client {:db-name db-name})
-(def conn (d/connect client {:db-name db-name}))
+(def client (d/client {:server-type :dev-local :system "day-of-datomic-cloud"}))
+(d/create-database client {:db-name "migration"})
+(def conn (d/connect client {:db-name "migration"}))

 (def schema-map (-> (repl/resource "day-of-datomic-cloud/schema.edn")
                     slurp read-string))
@@ -32,6 +29,4 @@

 ;; and we have the social-news attributes, because provenance
 ;; depended on them
-(schema/has-attribute? db :story/title)
-
-(d/delete-database client {:db-name db-name})
+(schema/has-attribute? db :story/title)


implement when-valid with if, not error-let -- easier  to understand than (error-let [_ ...]) to the uninitiated.

--- src/midje/error_handling/monadic.clj
+++ src/midje/error_handling/monadic.clj
@@ -57,5 +57,7 @@
 (defmethod validate :default [form] (rest form))

 (defmacro when-valid [validatable-form-or-forms & body-to-execute-if-valid]
-  `(error-let [_# (validate ~validatable-form-or-forms)]
-     ~@body-to-execute-if-valid))+  `(let [result# (validate ~validatable-form-or-forms)]
+     (if (user-error-form? result#)
+       result#
+       (do ~@body-to-execute-if-valid))))


Return ES search errors

Return ES search errors

--- src/org/spootnik/cyanite/es_path.clj
+++ src/org/spootnik/cyanite/es_path.clj
@@ -114,13 +114,13 @@
          (throw (too-many-paths-ex :path-search paths-count))
          (map #(:_source %) (scroll res))))
      (catch [:status 400] {:keys [body]}
-       (warn (:throwable &throw-context)
-             (str "Elasticsearch returns error 400 for the query: " es-query))
-       [])
+       (let [err (str "Elasticsearch returns error 400 for the query: " es-query)]
+         (warn (:throwable &throw-context) err)
+         {:error err}))
      (catch Object _
-       (error (:throwable &throw-context)
-              ("Unexpected error for the Elasticsearch query: " es-query))
-       []))))
+       (let [err (str "Unexpected error for the Elasticsearch query: " es-query)]
+         (error (:throwable &throw-context) err)
+         {:error err})))))

 (defn add-path
   "write a path into elasticsearch if it doesn't exist"


Cleaned up demo a bit

Cleaned up demo a bit

Cleaned up demo a bit

--- src/webapp/framework/client/components/main.cljs
+++ src/webapp/framework/client/components/main.cljs
@@ -2,27 +2,11 @@
   (:require
    [webapp.framework.client.coreclient   :as c ])
   (:use-macros
-    [webapp.framework.client.coreclient  :only [ns-coils sql log neo4j neo4j-1 sql-1 log
-                                                watch-data  -->ui  <--data <--ui
-                                                watch-ui
-                                               remote  defn-ui-component
+    [webapp.framework.client.coreclient  :only [ns-coils defn-ui-component def-coils-app
                                                 container  map-many  inline  text
-                                                div   img pre
-                                                component h2 input
-                                                write-ui read-ui container
-                                                inline text admin
-                                                ==data
-                                                ==ui  -->ui  watch-ui <--ui
-                                                <--data -->data
-                                                remote
-                                                input
-                                                component <--
-                                                h1 h2 h3 h4 h5 h6
-                                                span  data-view-v2
-                                                watch-data map-many inline text
-                                                container <--pos <--id
-                                                session-user-id select select-debug
-                                                def-coils-app
+                                                div img pre component h2 input
+                                                write-ui read-ui container input component <--
+                                                h1 h2 h3 h4 h5 h6 span  data-view-v2 select
                                                 ]]))

@@ -37,11 +21,9 @@
                               (h2 nil "Coils")
                                 (select id, item from todo_items where item like '%'
                                           {}
-                                        (div {:style {:paddingBottom "20px"}}
-                                            (div {} (str (<-- :id)))
-                                             (div {} (str (<-- :item)))
-                                             )
-                                        )
+                                        (container
+                                            (inline  "10%" (str (<-- :id)))
+                                            (inline  "90%" (str (<-- :item)))))
                                 "Build database webapps with Clojure"))


Fix a bug which resulted in `:dispatch ()`.  Improve code comments.

--- src/re_frame_async_flow_fx/core.cljs
+++ src/re_frame_async_flow_fx/core.cljs
@@ -24,22 +24,22 @@

 (defn massage-rules
   "Massage the supplied rules as follows:
-    - replace `:when` keyword value with a function  implements the predicate
-    - ensure that `:dispatch` is always a list and turn  `:done` into the right event
-    - ensure that :events is a set
-    - add a unique id"
-  [id rules]
-  (let [halt-event  [id :halt]
-        when->fn {:seen? all-events-seen?
-                  :seen-both? all-events-seen?
+    - replace `:when` keyword value with a function implementing the predicate
+    - ensure that `:dispatch` is always a list (even of one item) and transform `:halt` into an event.
+    - turn :events into a set
+    - add a unique :id, if one not already present"
+  [flow-id rules]
+  (let [halt-event  [flow-id :halt]
+        when->fn {:seen?            all-events-seen?
+                  :seen-both?       all-events-seen?
                   :all-events-seen? all-events-seen?
                   :any-events-seen? any-events-seen?}]
     (->> rules
-         (map-indexed (fn [index {:keys [when events dispatch]}]
-                        (let [w  (when->fn when)
-                              _  (assert (some? w) (str "aync-flow: found illegal value for :when: " when))]
-                          {:id        index
-                           :when      w
+         (map-indexed (fn [index {:keys [id when events dispatch]}]
+                        (let [when-as-fn  (when->fn when)
+                              _  (assert (some? when-as-fn) (str "aync-flow: found bad value for :when: " when))]
+                          {:id        (or id index)
+                           :when      when-as-fn
                            :events    (if (coll? events) (set events) #{events})
                            :dispatch  (cond
                                         (vector? dispatch)  (list dispatch)
@@ -48,7 +48,10 @@
                                         :else  (js/console.error "aync-flow: dispatch value not valid: " dispatch))}))))))

+;; -- Create Event Handler
+
 (defn make-flow-event-handler
+  "given a flow definitiion, returns an event handler which implements this definition"
   [{:keys [id db-path rules first-dispatch]}]
   (let [id  (or id default-id)

@@ -56,6 +59,7 @@
         ;; Two pieces of state are maintained:
         ;;  - the set of seen events
         ;;  - the set of started tasks
+        _           (assert (or (nil? db-path) (vector? db-path)) "aync-flow: db-path must be a vector")
         local-store (atom {})
         set-state   (if db-path
                       (fn [db seen started]
@@ -69,48 +73,52 @@

         rules  (massage-rules id rules)]       ;; all of the events refered to in the rules

-    ;; return an event handler which will manage the flow
-    ;; This event handler will receive 3 kinds of events
+    ;; Return an event handler which will manage the flow.
+    ;; This event handler will receive 3 kinds of events:
     ;;   (dispatch [:id :setup])
-    ;;   (dispatch [:id :done])
-    ;;   (dispatch [:id [:a :forwarded :event :vector])
+    ;;   (dispatch [:id :halt])
+    ;;   (dispatch [:id [:forwarded :event :vector]])
+    ;;
+    ;; This event handler returns a map of effects.
     ;;
     (fn async-flow-event-hander
       [{:keys [db]} event-v]
+
         (condp = event-v
-
-              ;; Setup the flow coordinator:
-              ;;   1. Initialise the state  (seen-events and started-tasks)
-              ;;   2. dispatch the first event, to kick start
-              ;;   3. arrange for the events to get forwarded to this handler
+              ;; Setup this flow coordinator:
+              ;;   1. Establish initial state - :seen-events and :started-tasks are made empty sets
+              ;;   2. dispatch the first event, to kick start flow
+              ;;   3. arrange for the events to be forwarded to this handler
               :setup {:db (set-state db #{} #{})
                       :dispatch first-dispatch
                       :event-forwarder {:register    id
                                         :events      (apply set/union (map :events rules))
                                         :dispatch-to [id]}}

-              ;; Teardown the flow coordinator:
+              ;; Teardown this flow coordinator:
               ;;   1. remove this event handler
               ;;   2. remove any state stored in app-db
-              ;;   3. stop the events forwarder
+              ;;   3. deregister the events forwarder
               :halt {:db (dissoc db db-path)
                      :event-forwarder {:unregister id}
                      :deregister-event-handler id}

+              ;; Here we are managig the flow.
               ;; A new event has been forwarded to this handler. What does it mean?
-              ;;  1. does this new event mean we need to dispatch another
-              ;;  2. save that this event has happened
+              ;;  1. does this new event mean we need to dispatch another?
+              ;;  2. remember this event has happened
               (let [[_ [forwarded-event-id & args]] event-v
                     {:keys [seen-events started-tasks]} (get-state db)
                     new-seen-events    (conj seen-events forwarded-event-id)
                     ready-tasks        (newly-startable-tasks rules new-seen-events started-tasks)
                     ready-task-ids     (->> ready-tasks (map :id) set)
                     new-started-tasks  (set/union started-tasks ready-task-ids)]
-                {:db       (set-state db new-seen-events new-started-tasks)
-                 :dispatch (concat (map :dispatch ready-tasks))})))))
+                (merge
+                    {:db       (set-state db new-seen-events new-started-tasks)}
+                    (when (seq ready-tasks) {:dispatch (concat (map :dispatch ready-tasks))})))))))

-;; -- Register handler with re-frame
+;; -- Register effects handler with re-frame

 (re-frame.core/def-fx
   :aync-flow