Unify :topic for message subscription.

Unify :topic for message subscription.

Propagate subscriptions to other peers incrementally.

--- src/clj/geschichte/sync.clj
+++ src/clj/geschichte/sync.clj
@@ -21,7 +21,7 @@
   [name store]
   (let [log (atom {})
         in (debug/chan log [name :in])
-        out (async/pub in (fn [{:keys [user meta]}] [user (:id meta)]))]
+        out (async/pub in :topic)]
     (atom {:volatile {:server nil
                       :log log
                       :chans [in out]
@@ -37,7 +37,7 @@
   (let [{:keys [new-conns] :as server} (start-server! ip port)
         log (atom {})
         in (debug/chan log [ip :in])
-        out (async/pub in (fn [{:keys [user meta]}] [user (:id meta)]))
+        out (async/pub in :topic)
         peer (atom {:volatile (merge server
                                      {:store store
                                       :log log
@@ -46,7 +46,7 @@
                     :ip ip
                     :port port})]
     (go-loop [[in out] (<! new-conns)]
-             (wire peer [out (async/pub in :type)])
+             (wire peer [out (async/pub in :topic)])
              (recur (<! new-conns)))
     peer))

@@ -63,10 +63,10 @@
   ([peer author repo schema]
      (load-stage! peer author repo schema (chan) (chan)))
   ([peer author repo schema [in out]]
-     (go (<! (wire peer [in (async/pub out :type)]))
+     (go (<! (wire peer [in (async/pub out :topic)]))
          {:author author
           :schema schema
-          :meta (<! (-get-in (:store (:volatile peer)) [author repo]))
+          :meta (<! (-get-in (:store (:volatile @peer)) [author repo]))
           :chans [in out]
           :transactions []})))

@@ -79,22 +79,42 @@
 (defn- new-commits! [store meta-sub old-meta]
   (->> (map #(go [(not (<!(-exists? store [%]))) %])
             (new-commits meta-sub old-meta))
-       (async/merge)
+       async/merge
        (filter< first)
        (map< second)
        (async/into #{})))

 ;; TODO multiple subscriptions, subscription propagation; incremental subscription?
-(defn subscribe [peer sub-ch bus-out out]
-  (go-loop [{:keys [metas] :as s} (<! sub-ch)]
-           (when s
-             (doseq [user (keys metas)
-                     repo (get metas user)]
-               (async/sub bus-out [user repo] out))
-             (swap! peer update-in [:meta-sub] (partial merge-with set/union) metas)
-             (>! out {:type :meta-subed :metas metas})
-             (recur (<! sub-ch)))))
+(defn subscribe [peer sub-ch out]
+  (let [[bus-in bus-out] (-> @peer :volatile :chans)]
+    (async/sub bus-out :meta-pub out)
+    (go-loop [{:keys [metas] :as s} (<! sub-ch)]
+             (let [cpch (chan)]
+               (when s
+                 (doseq [user (keys metas)
+                         repo (get metas user)]
+                   (async/sub bus-out :meta-pub cpch)
+                   (go-loop [{{r :id} :meta u :user :as m} (<! cpch)]
+                            (when (and (= u user)
+                                       (= r repo))
+                              (>! out m))
+                            (when m (recur (<! cpch)))))
+
+
+                 ;; incrementally propagate subscription to other peers
+                 (let [new-subs (->> (:meta-sub @peer)
+                                     (merge-with set/difference metas)
+                                     (filter (fn [[k v]] (not (empty? v))))
+                                     (into {}))]
+                   (when-not (empty? new-subs)
+                     (>! bus-in {:topic :meta-sub :metas new-subs})))
+
+                 (swap! peer update-in [:meta-sub] (partial merge-with set/union) metas)
+
+                 (>! out {:topic :meta-subed :metas metas})
+
+                 (recur (<! sub-ch)))))))

@@ -104,14 +124,14 @@
              (let [repo (:id meta)
                    nc (<! (new-commits! store meta (<! (-get-in store [user repo]))))]
                (when-not (empty? nc)
-                 (>! out {:type :fetch
+                 (>! out {:topic :fetch
                           :user user :repo repo
                           :ids nc})
                  (doseq [[repo-id val] (:values (<! fetched-ch))]
                    (<! (-assoc-in store [repo-id] val))))

-               (>! out {:type :meta-pubed :user user :repo repo})
-               ;; TODO find cleaner way to atomically update
+               (>! out {:topic :meta-pubed})
+               ;; TODO find cleaner way to atomically update; get new commits of updated-meta
                (let [old-meta (<! (-get-in store [user repo]))
                      up-meta (<! (-update-in store [user repo] #(if % (update % meta) meta)))]
                  (when (not= old-meta up-meta)
@@ -132,12 +152,12 @@
                (client-connect! ip4 port c-in c-out)

                                         ; handshake
-               (>! c-out {:type :meta-sub :metas subs})
+               (>! c-out {:topic :meta-sub :metas subs})
                (put! subed-ch (<! c-in))
-               (subscribe peer subed-ch bus-out c-out)
-
-               (<! (wire peer [c-out (async/pub c-in :type)]))
-               (>! out {:type :connected
+               (subscribe peer subed-ch c-out)
+
+               (<! (wire peer [c-out (async/pub c-in :topic)]))
+               (>! out {:topic :connected
                         :ip4 ip4 :port port})
                (recur (<! conn-ch))))))

@@ -148,11 +168,11 @@
              (let [store (:store (:volatile @peer))
                    fetched (->> ids
                                 (map #(-get-in store [%]))
-                                (async/merge)
+                                async/merge
                                 (async/into [])
                                 <!
                                 (zipmap ids))]
-               (>! out {:type :fetched
+               (>! out {:topic :fetched
                         :user user :repo repo
                         :values fetched})
                (recur (<! fetch-ch))))))
@@ -168,7 +188,7 @@
             fetch-ch (debug/chan log [ip :fetch])
             fetched-ch (debug/chan log [ip :fetched])]
         (async/sub p :meta-sub sub-ch)
-        (subscribe peer sub-ch bus-out out)
+        (subscribe peer sub-ch out)

         (async/sub p :meta-pub pub-ch)
         (async/sub p :fetched fetched-ch)
@@ -199,62 +219,64 @@
       (reset! peer @(client-peer "CLIENT" (new-store)))
       (reset! stage-log {}))
 #_(clojure.pprint/pprint @(:log (:volatile @peer)))
-#_(clojure.pprint/pprint @(:log (:volatile @peer-a)))
+#_(clojure.pprint/pprint @(:log (:volatile @peer-b)))
 #_(clojure.pprint/pprint @stage-log)
 #_(let [in (debug/chan stage-log [:stage :in])
       out (debug/chan stage-log [:stage :out])
       b-in (debug/chan stage-log [:peer-b :in])
       b-out (debug/chan stage-log [:peer-b :out])]
-    (go-loop [m (<! b-in)]
-                (println "PEERB-IN" m)
-                (recur (<! b-in)))
-  (go (<! (wire peer [in (async/pub out :type)]))
-      (<! (wire peer-b [b-in (async/pub b-out :type)]))
-      (>! b-out {:type :meta-sub :metas {"john" #{1}}})
-      (<! (timeout 1000))
-      (>! b-out {:type :connect :ip4 "127.0.0.1" :port 9090})
-
-      (>! out {:type :meta-sub :metas {"john" #{1}}})
-;      (<! in)
-      (<! (timeout 1000))
-      (>! out {:type :connect
+  (go-loop [m (<! b-in)]
+           (println "PEERB-IN" m)
+           (recur (<! b-in)))
+  (go (<! (wire peer [in (async/pub out :topic)]))
+      (<! (wire peer-b [b-in (async/pub b-out :topic)]))
+      (>! b-out {:topic :connect :ip4 "127.0.0.1" :port 9090})
+      (<! (timeout 100))
+      #_(>! b-out {:topic :meta-sub :metas {"john" #{1}}})
+      (<! (timeout 100))
+      (>! out {:topic :meta-sub :metas {"john" #{1}}})
+                                        ;      (<! in)
+      (<! (timeout 100))
+      (>! out {:topic :connect
                :ip4 "127.0.0.1"
                :port 9090})
-      #_(>! out {:type :connect
-               :ip4 "127.0.0.1"
-               :port 9091})
-      (<! (timeout 1000))
-      (>! out {:type :meta-pub
-               :user "john" :meta {:id 1
-                                   :causal-order {1 #{}
-                                                  2 #{1}}
-                                   :last-update (java.util.Date. 0)
-                                   :schema {:type ::geschichte
-                                            :version 1}}})
-      (<! (timeout 1000))
-;     (<! in)
-      (>! out {:type :fetched :values {1 2
-                                       2 42}})
-      (<! (timeout 1000))
-;     (println "1" (:type (<! in)))
-;     (println "2" (:type (<! in)))
-      (>! out {:type :meta-pub
-               :user "john" :meta {:id 1
-                                   :causal-order {1 #{}
-                                                  2 #{1}
-                                                  3 #{2}}
-                                   :last-update (java.util.Date. 0)
-                                   :schema {:type ::geschichte
-                                            :version 1}}})
-      (<! (timeout 1000))
-      (>! out {:type :fetched :values {3 43}})
-;     (println "4" (:type (<! in)))
-;     (println "5" (:type (<! in)))
-      (<! (timeout 5000)))
+      #_(>! out {:topic :connect
+                 :ip4 "127.0.0.1"
+                 :port 9091})
+      (<! (timeout 100))
+      (>! out {:topic :meta-pub
+               :user "john"
+               :meta {:id 1
+                      :causal-order {1 #{}
+                                     2 #{1}}
+                      :last-update (java.util.Date. 0)
+                      :schema {:topic ::geschichte
+                               :version 1}}})
+      (<! (timeout 100))
+                                        ;     (<! in)
+      (>! out {:topic :fetched :values {1 2
+                                        2 42}})
+      (<! (timeout 100))
+                                        ;     (println "1" (:topic (<! in)))
+                                        ;     (println "2" (:topic (<! in)))
+      (>! out {:topic :meta-pub
+               :user "john"
+               :meta {:id 1
+                      :causal-order {1 #{}
+                                     2 #{1}
+                                     3 #{2}}
+                      :last-update (java.util.Date. 0)
+                      :schema {:topic ::geschichte
+                               :version 1}}})
+      (<! (timeout 100))
+      (>! out {:topic :fetched :values {3 43}})
+                                        ;     (println "4" (:topic (<! in)))
+                                        ;     (println "5" (:topic (<! in)))
+      (<! (timeout 500)))

   (go-loop [i (<! in)]
-           #_(println "RECEIVED:" i)
+           (println "RECEIVED:" i)
            (recur (<! in))))

@@ -262,10 +284,10 @@
 (defn wire-stage [peer {:keys [chans] :as stage}]
   (go (if chans stage
           (let [log (atom {})
-                in (debug/chan log ["STAGE" :in])
+                in (debug/chan log ["STAGE" :in] 10)
                 out (debug/chan log ["STAGE" :out])]
-            (<! (wire peer [in (async/pub out :type)]))
-            (assoc stage :chans [(async/pub in :type) out])))))
+            (<! (wire peer [in (async/pub out :topic)]))
+            (assoc stage :chans [(async/pub in :topic) out])))))

 ;; push perspective
@@ -278,13 +300,13 @@
         (async/sub p :fetch fch)
         (async/sub p :meta-pubed pch)
         (case type
-          :meta-pub  (>! out {:type :meta-pub :user author :meta meta})
+          :meta-pub  (>! out {:topic :meta-pub :meta meta :user author})
           :meta-sub (do
-                      (>! out {:type :meta-sub :metas {author #{repo}}})
-                      (>! out {:type :meta-pub :user author :meta meta})))
+                      (>! out {:topic :meta-sub :metas {author #{repo}}})
+                      (>! out {:topic :meta-pub :meta meta :user author})))

         (go (let [to-fetch (select-keys new-values (:ids (<! fch)))]
-              (>! out {:type :fetched
+              (>! out {:topic :fetched
                        :user author :repo repo
                        :values to-fetch})))

@@ -297,10 +319,12 @@
         (dissoc stage :type :new-values))))

+;; TODO check why peer-a does not store on first run
 (comment
   (def peer (client-peer "CLIENT" (new-store)))
   (require '[clojure.core.incubator :refer [dissoc-in]])
   (dissoc-in @peer [:volatile :log])
+  @(get-in @peer [:volatile :store :state])
   (clojure.pprint/pprint (get-in @peer [:volatile :log]))

   (go (let [printfn (partial println "STAGE:")
@@ -309,23 +333,24 @@
                                        "Testing."
                                        false
                                        {:some 42})
-            stage (<! (wire-stage peer-b stage))
+            stage (<! (wire-stage peer stage))
             [in out]  (:chans stage)
             connedch (chan)
             _ (async/sub in :connected connedch)
             _ (go-loop [conned (<! connedch)]
                        (println "CONNECTED-TO:" conned)
                        (recur (<! connedch)))
-;           _ (>! out {:type :meta-sub
-;                      :metas {"me@mail.com" #{(:id (:meta stage))}}})
-;           _ (<! (timeout 1000))
-            _ (>! out {:type :connect
+            _ (<! (timeout 100))
+            _ (>! out {:topic :meta-sub
+                       :metas {"me@mail.com" #{(:id (:meta stage))}}})
+            _ (<! (timeout 100))
+            _ (>! out {:topic :connect
                        :ip4 "127.0.0.1"
                        :port 9090})
             _ (<! (timeout 1000))
-;            new-stage (<! (sync! stage))
+             new-stage (<! (sync! stage))
             ]
-        #_(-> new-stage
+        (-> new-stage
             (s/transact {:helo :world} '(fn more [old params] old))
             repo/commit
             sync!


Removed unused namespace clojure.pprint

Removed unused namespace clojure.pprint

--- src/clj_mrazik/schedule.clj
+++ src/clj_mrazik/schedule.clj
@@ -12,7 +12,6 @@

 (ns clj-mrazik.schedule)

-(require '[clojure.pprint :as pprint])
 (require '[clj-calendar.calendar :as calendar])
 (require '[sunrise.core :as sunrise])


Only match string surface forms

Only match string surface forms

--- src/cljs/db_quiz/logic.cljs
+++ src/cljs/db_quiz/logic.cljs
@@ -129,7 +129,7 @@
           match-fn (fn [surface-form] (> (jaro-winkler normalized-guess
                                                        (normalize-answer surface-form))
                                          actual-threshold))]
-      (not (nil? (some match-fn (cons label surface-forms)))))
+      (not (nil? (some match-fn (cons label (filter string? surface-forms))))))
     false))

 (defn clear-answer


Remove user from Peer

Remove user from Peer

--- src/clojure_fabric/peer.clj
+++ src/clojure_fabric/peer.clj
@@ -11,15 +11,14 @@
 ;; It should be noted that Peer event streams function at the Peer level and not at the chain
 ;; and chaincode levels.

-(ns clojure-fabric.peer
-  (:require [clojure-fabric.user :as user]))
+(ns clojure-fabric.peer)

 (defonce ^:dynamic *peer* nil)

 ;; an endorser, committer and/or submitter
 ;; endorser is a committer
 ;; %roles ex : #{:endorser :submitter :committer}, #{}, etc
-(defrecord Peer [name url user certificate])
+(defrecord Peer [name url certificate])

 (defn make-peer [m]
   (map->Peer m))
@@ -119,18 +118,13 @@
 ;; Immutable in this implementation

 ;;get_roles
-(defn get-roles
-  "Get the user’s roles the Peer participates in. It’s an array of possible values in “client”,
-  and “auditor”. The member service defines two more roles reserved for peer membership:
-  “peer” and “validator”, which are not exposed to the applications.
-  Returns (str[]):
-        The roles for this user"
-  ([]
-   (if *peer*
-     (get-roles *peer*)
-     (user/get-roles user/*user*)))
-  ([peer]
-   (-> peer :user :roles)))
+;; "Get the user’s roles the Peer participates in. It’s an array of possible values in “client”,
+;; and “auditor”. The member service defines two more roles reserved for peer membership:
+;; “peer” and “validator”, which are not exposed to the applications.
+;; Returns (str[]):
+;;       The roles for this user"
+;;
+;; User's method

 ;; set_roles


NPE wasn't handled and caused stop to fail. fixed now

--- src/clueweb_disqus/core.clj
+++ src/clueweb_disqus/core.clj
@@ -69,7 +69,8 @@

 (defn get-stop-for-start-epoch
   [credentials since-epoch]
-  (or (-> credentials (get (str since-epoch)) :stop Long/parseLong)
+  (or (try (-> credentials (get (str since-epoch)) :stop Long/parseLong)
+           (catch Exception e nil))
       (let [orig-epochs (keys credentials)
             correct-key (str
                          (first
@@ -167,10 +168,10 @@
                       (-> page-response last (get "createdAt")))
              c/to-long
              (/ 1000)))
-     (catch Exception e (do (println (.getMessage e))
-                            (pprint (last page-response))
-                            (flush)
-                            true)))))              ; stop anyway
+      (catch Exception e (do (println (.getMessage e))
+                             (pprint (last page-response))
+                             (flush)
+                             true)))))              ; stop anyway

 (defn process-disqus-date
   [a-date]


Bind *data-readers* when looking for macro defs

This closes clojure-emacs/clj-refactor.el#320

--- src/refactor_nrepl/find/find_macros.clj
+++ src/refactor_nrepl/find/find_macros.clj
@@ -50,7 +50,8 @@
   [f]
   (util/with-additional-ex-data [:file (.getAbsolutePath f)]
     (with-open [file-rdr (FileReader. f)]
-      (binding [*ns* (or (core/path->namespace :no-error f) *ns*)]
+      (binding [*ns* (or (core/path->namespace :no-error f) *ns*)
+                reader/*data-readers* *data-readers*]
         (let [rdr (LineNumberingPushbackReader. file-rdr)
               opts {:read-cond :allow :features #{:clj} :eof :eof}]
           (loop [macros [], form (reader/read opts rdr)]


notes

notes

--- src/maths/movingaverage.clj
+++ src/maths/movingaverage.clj
@@ -64,6 +64,10 @@
         (recur (rest values) period (conj acc (/ (reduce + first) period)))
         acc))))

+; To get the Exponent,
+; take the number 2 and divide it by Days+1.
+; For example the Exponent for a 200 day moving average would be:
+; 2÷201 = 0.01

 ; implementation of an exponentially weighted moving-average function
 ; https://gist.github.com/MerelyAPseudonym/5273905


Cleanup

Cleanup

--- src/midje/util/checkers.clj
+++ src/midje/util/checkers.clj
@@ -561,22 +561,18 @@
               (match? actual expected looseness)

               :else
-              (tag-as-chatty-falsehood
-               {
-                :notes [(cl-format nil
-                                   "Expected ~R element~:P. There ~[were~;was~:;were~]~:* ~R."
-                                   (count expected)
-                                   (count actual))]}))))))
+              (noted-falsehood
+               (cl-format nil "Expected ~R element~:P. There ~[were~;was~:;were~]~:* ~R."
+                          (count expected)
+                          (count actual))))))))

 (defn- has-xfix [x-name pattern-fn take-fn]
   (fn [actual expected looseness]
     (cond (set? actual)
-          (tag-as-chatty-falsehood {
-                                    :notes [(str "Sets don't have " x-name "es.")]})
+          (noted-falsehood (format "Sets don't have %ses." x-name))

           (map? actual)
-          (tag-as-chatty-falsehood {
-                                    :notes [(str "Maps don't have " x-name "es.")]})
+          (noted-falsehood (format "Maps don't have %ses." x-name))

           :else
           (let [ [actual expected looseness] (standardized-arguments actual expected looseness)]
@@ -587,13 +583,10 @@
                   (match?(take-fn (count expected) actual) expected looseness)

                   :else
-                  (tag-as-chatty-falsehood
-                   {
-                    :notes [(str (cl-format nil
-                                            "A collection with ~R element~:P cannot match a "
-                                            (count actual))
-                                 x-name
-                                 (cl-format nil " of size ~R." (count expected)))]}))))))
+                  (noted-falsehood
+                   (cl-format nil
+                              "A collection with ~R element~:P cannot match a ~A of size ~R."
+                              (count actual) x-name (count expected))))))))

 (def has-prefix
      (container-checker-maker 'has-prefix


Clean up console logging

Clean up console logging

--- src/clj/retroboard/api/environment.clj
+++ src/clj/retroboard/api/environment.clj
@@ -16,7 +16,7 @@

 (defmulti cmd-handler (fn [data _ _] (:cmd data)))
 (defmethod cmd-handler :register [data eid-atom out-ch]
-  (println "Registering to env " (:action data))
+  (println "Registering to env" (:action data))
   (let [eid (:action data)]
     (if (env/exists? eid)
       (do
@@ -27,14 +27,14 @@
       (put! out-ch {:cmd :error :error :no-such-environment}))))

 (defmethod cmd-handler :unregister [data eid-atom out-ch]
-  (println "Unregistering")
+  (println "Unregistering from env" @eid-atom)
   (when (and @eid-atom (env/exists? @eid-atom))
     (env/unsubscribe @eid-atom out-ch)
     (env/on-leave @eid-atom)
     (reset! eid-atom nil)))

 (defmethod cmd-handler :actions [data eid-atom out-ch]
-  (println "Received " data " for " @eid-atom)
+  (println "Received" data "for" @eid-atom)
   (when (and @eid-atom (env/exists? @eid-atom))
     (env/append-actions @eid-atom (:actions data))))


Move temple down a cell to not interfere with log/ui-hint messages

--- src/cljc/robinson/dungeons/temple.cljc
+++ src/cljc/robinson/dungeons/temple.cljc
@@ -564,7 +564,7 @@
                                (map (fn [column]
                                       (let [width (rr/uniform-int min-width (dec max-width))
                                             height (rr/uniform-int min-height (dec max-height))
-                                            x (rr/uniform-int (* column max-width) (+ (* column max-width) (dec max-width) (- width)))
+                                            x (inc (rr/uniform-int (* column max-width) (+ (* column max-width) (dec max-width) (- width))) )
                                             y (rr/uniform-int (* row max-height) (+ (* row max-height) (dec max-height) (- height)))]
                                       [x y (+ x width) (+ y height)]))
                                     (range columns)))


update app-state with random values for demo

--- src/cljs/deliverit_dashboard/core.cljs
+++ src/cljs/deliverit_dashboard/core.cljs
@@ -1,7 +1,18 @@
 (ns deliverit-dashboard.core
   (:require [dashboard-clj.core :as d]
             [dashboard-clj.layouts.grid-layout :as grid]
-            [dashboard-clj.widgets.simple-text :as s]))
+            [dashboard-clj.widgets.simple-text :as s]
+            [re-frame.core :as rf]))
+
+
+
+;; update app-state with random values
+
+(.setInterval js/window
+              #(rf/dispatch [:update-data-source
+                             (rand-nth [:kochi-weather :bangalore-weather])
+                             {:value (rand-int 100)}]) 500)
+


clog! helper accepts multiple arguments

clog! helper accepts multiple arguments

--- src/cljs/funnel_front/lib/helpers.cljs
+++ src/cljs/funnel_front/lib/helpers.cljs
@@ -1,10 +1,11 @@
 (ns funnel-front.lib.helpers)

 ;; https://groups.google.com/forum/#!topic/clojure/ghHqHuXE0pY
-(defn clog! [to-print]
-  (.log js/console (pr-str to-print)))
+(defn clog! [& items-to-print]
+  (.log js/console (apply pr-str items-to-print)))

 (defn event-source [route callback]
   (let [source (js/EventSource. route)]
     (set! (.-onmessage source) callback)
-    source))
+    source
+    ))


repl port

repl port

--- src/clojure/zensols/actioncli/repl.clj
+++ src/clojure/zensols/actioncli/repl.clj
@@ -4,7 +4,7 @@
   (:require [clojure.tools.nrepl.server :as replserv])
   (:require [clojure.tools.nrepl.cmdline :as replcmd]))

-(def ^:private default-port)
+(def ^:private default-port 12345)

 (defn run-server
   "Run REPL server."


Updated test for atom original_format change.

--- src/cmr/system_int_test/data2/atom.clj
+++ src/cmr/system_int_test/data2/atom.clj
@@ -200,8 +200,7 @@
      :dataset-id entry-title
      :short-name short-name
      :version-id version-id
-     ;; TODO original-format will be changed to ECHO10 later once the metadata-db format is updated to ECHO10
-     :original-format "application/echo10+xml"
+     :original-format "ECHO10"
      :collection-data-type collection-data-type
      :data-center (:provider-id (cu/parse-concept-id concept-id))
      :archive-center archive-center
@@ -239,8 +238,7 @@
      :updated (str update-time)
      :coordinate-system coordinate-system
      :size (str size)
-     ;; TODO original-format will be changed to ECHO10 later once the metadata-db format is updated to ECHO10
-     :original-format "application/echo10+xml"
+     :original-format "ECHO10"
      :data-center (:provider-id (cu/parse-concept-id concept-id))
      :links (related-urls->links related-urls)
      :start beginning-date-time


[#2127] Don't return value on execute transformation (& undo-tx)

Transformation engine is executed in another thread, that only needs to
take care of talking to the DB

--- backend/src/akvo/lumen/lib/transformation/engine.clj
+++ backend/src/akvo/lumen/lib/transformation/engine.clj
@@ -1,6 +1,5 @@
 (ns akvo.lumen.lib.transformation.engine
-  (:require [akvo.lumen.lib :as lib]
-            [akvo.lumen.util :as util]
+  (:require [akvo.lumen.util :as util]
             [akvo.lumen.db.transformation :as db.transformation]
             [akvo.lumen.db.dataset-version :as db.dataset-version]
             [clojure.set :as set]
@@ -166,8 +165,7 @@
                                                                                columns))))
                                     :columns (w/keywordize-keys columns)}]
           (db.dataset-version/new-dataset-version tenant-conn next-dataset-version)
-          (db.transformation/touch-dataset tenant-conn {:id dataset-id})
-          (lib/created next-dataset-version))))))
+          (db.transformation/touch-dataset tenant-conn {:id dataset-id}))))))

 (defn- apply-undo [{:keys [tenant-conn] :as deps} dataset-id job-execution-id current-dataset-version]
   (let [imported-table-name (:imported-table-name current-dataset-version)
@@ -202,8 +200,7 @@
             (db.dataset-version/new-dataset-version tenant-conn
                                  next-dataset-version)
             (db.transformation/touch-dataset tenant-conn {:id dataset-id})
-            (db.transformation/drop-table tenant-conn {:table-name previous-table-name})
-            (lib/created next-dataset-version)))
+            (db.transformation/drop-table tenant-conn {:table-name previous-table-name})))
         (let [transformation (assoc (first transformations) :dataset-id dataset-id)
               {:keys [success? message columns execution-log] :as transformation-result}
               (try-apply-operation deps table-name columns transformation)]
@@ -218,10 +215,8 @@

 (defn execute-undo [{:keys [tenant-conn] :as deps} dataset-id job-execution-id]
   (let [current-dataset-version (db.transformation/latest-dataset-version-by-dataset-id tenant-conn
-                                                                      {:dataset-id dataset-id})
-        current-version (:version current-dataset-version)]
-    (if (= current-version 1)
-      (lib/created (assoc current-dataset-version :dataset-id dataset-id))
+                                                                      {:dataset-id dataset-id})]
+    (when (not= (:version current-dataset-version) 1)
       (apply-undo deps
                   dataset-id
                   job-execution-id


Simplify id-generating code

Simplify id-generating code

--- src/datascript_dom/core.clj
+++ src/datascript_dom/core.clj
@@ -53,15 +53,12 @@
     [:text-node {:text node}]))

 (defn- node-to-transaction [node parent prev]
-  (->
-   (merge
-    {:tag (first node)}
-    (html/attributes node)
-    (when-let [id (:id node)] {:dom-id id})
-    (when parent {:parent parent})
-    (when prev {:prev-sibling prev}))
-   (dissoc :id ::id)
-   (assoc :db/id (-> node html/attributes ::id))))
+  (merge
+   {:tag (first node)}
+   (html/attributes node)
+   (when-let [id (:id node)] {:dom-id id})
+   (when parent {:parent parent})
+   (when prev {:prev-sibling prev})))

 (defn- has-children? [node]
   (and (vector? node) (> (count node) 2)))
@@ -73,9 +70,9 @@
   (let [walk (fn walk [zipper id]
                (when-not (zip/end? zipper)
                  (let [zipper (zip/replace zipper
-                                           (assoc-in (as-node (zip/node zipper)) [1 ::id] id))
-                       parent (some-> zipper zip/up zip/node html/attributes ::id)
-                       prev (some-> zipper zip/left zip/node html/attributes ::id)]
+                                           (assoc-in (as-node (zip/node zipper)) [1 :db/id] id))
+                       parent (some-> zipper zip/up zip/node html/attributes :db/id)
+                       prev (some-> zipper zip/left zip/node html/attributes :db/id)]
                    (cons (node-to-transaction (zip/node zipper) parent prev)
                          (lazy-seq (walk (zip/next zipper) (dec id)))))))]
     (walk (zip/zipper has-children? html/children set-children dom) -1)))


make event handler-pool and event-debug* atom private

--- src/overtone/libs/event.clj
+++ src/overtone/libs/event.clj
@@ -5,8 +5,8 @@
   (:require [overtone.config.log :as log]
             [overtone.libs.handlers :as handlers]))

-(defonce handler-pool (handlers/mk-handler-pool "Overtone Event Handlers"))
-(defonce event-debug* (atom false))
+(defonce ^:private handler-pool (handlers/mk-handler-pool "Overtone Event Handlers"))
+(defonce ^:private event-debug* (atom false))

 (defn- log-event
   "Log event on separate thread to ensure logging doesn't interfere with


bodge rig to use bus 49 so it doesn't clash with server mixer buses. Need to make this more sophisticated.

--- src/overtone/studio/rig.clj
+++ src/overtone/studio/rig.clj
@@ -27,8 +27,7 @@
 (defonce mixer-id*     (ref nil))
 (defonce fx-group*     (ref nil))
 (defonce record-group* (ref nil))
-(defonce MIXER-BUS 10)
-
+(defonce MIXER-BUS 49)

 (def RIG-BOOT-DEPS [:server-ready :studio-setup-completed])

@@ -50,7 +49,7 @@
 ; A mixer synth for volume, pan, and limiting
 ; TODO: Add basic EQ
 (defonce __MIXER-SYNTH__
-  (defsynth mixer [in-bus 10 out-bus 0
+  (defsynth mixer [in-bus 49 out-bus 0
                    volume 0.5 pan 0.0
                    threshold 0.7
                    slope-below 1 slope-above 0.1
@@ -138,6 +137,7 @@
         f (with-server-sync #(group :after g))
         m (group :tail (root-group))
         r (group :tail (root-group))]
+
     (dosync
       (ref-set inst-group* g)
       (ref-set fx-group* f)
@@ -192,7 +192,8 @@
              [vol-ugen out-ugen])
      (set (floatify (conj constants MIXER-BUS 1 0)))]))

-(defmacro inst [sname & args]
+(defmacro inst
+  [sname & args]
   `(let [[sname# params# ugens# constants#] (pre-synth ~sname ~@args)
          [params# ugens# constants#] (inst-prefix params# ugens# constants#)
          sdef# (synthdef sname# params# ugens# constants#)
@@ -236,7 +237,7 @@
   (and (associative? o)
        (= ::instrument (:type o))))

-(defmacro definst [i-name & inst-form]
+(defmacro definst
   "Define an instrument and return a player function. The instrument definition
   will be loaded immediately. Instruments differ from basic synths in that they
   will automatically add pan2 and out ugens when necessary to create a stereo
@@ -249,6 +250,7 @@
   You may also kill an all of an instrument's running synths:

   (kill inst-name)"
+  [i-name & inst-form]
   (let [[i-name params ugen-form] (synth-form i-name inst-form)
         i-name (with-meta i-name (merge (meta i-name) {:type ::instrument}))]
     `(def ~i-name (inst ~i-name ~params ~ugen-form))))


Introduce third shutdown reason to reflect use cases

--- src/puppetlabs/trapperkeeper/core.clj
+++ src/puppetlabs/trapperkeeper/core.clj
@@ -173,26 +173,28 @@
   "Walk the graph and register all shutdown functions. The functions
   will be called when the JVM shuts down, or by calling `shutdown!`."
   [graph]
-  (let [shutdown-fns        (atom ())
-        wrapped-graph       (walk-leaves-and-path
-                              (partial wrap-with-shutdown-registration shutdown-fns)
-                              graph)
-        shutdown-reason     (promise)
-        do-shutdown-fn      #(do
-                               (doseq [f @shutdown-fns] (f))
-                               (deliver shutdown-reason {:type :jvm-signal}))
-        shutdown-service    (service :shutdown-service
-                                     {:depends  []
-                                      :provides [do-shutdown wait-for-shutdown shutdown-on-error]}
-                                     {:do-shutdown        do-shutdown-fn
-                                      :wait-for-shutdown  #(deref shutdown-reason)
-                                      :shutdown-on-error  (fn [f]
-                                                            (try
-                                                              (f)
-                                                              (catch Throwable t
-                                                                (deliver shutdown-reason {:type  :service-error
-                                                                                :error t}))))})]
-    (add-shutdown-hook! do-shutdown-fn)
+  (let [shutdown-fns          (atom ())
+        wrapped-graph         (walk-leaves-and-path
+                                (partial wrap-with-shutdown-registration shutdown-fns)
+                                graph)
+        shutdown-reason       (promise)
+        perform-shutdown-fn   #(doseq [f @shutdown-fns] (f))
+        shutdown-service      (service :shutdown-service
+                                       {:depends  []
+                                        :provides [do-shutdown wait-for-shutdown shutdown-on-error]}
+                                       {:do-shutdown        #(do
+                                                               (perform-shutdown-fn)
+                                                               (deliver shutdown-reason {:type :requested}))
+                                        :wait-for-shutdown  #(deref shutdown-reason)
+                                        :shutdown-on-error  (fn [f]
+                                                              (try
+                                                                (f)
+                                                                (catch Throwable t
+                                                                  (deliver shutdown-reason {:type  :service-error
+                                                                                :error t}))))})]
+    (add-shutdown-hook! #(do
+                           (perform-shutdown-fn)
+                           (deliver shutdown-reason {:type :jvm-shutdown-hook})))
     (merge (shutdown-service) wrapped-graph)))

 (defn shutdown!
@@ -308,6 +310,8 @@
   [^TrapperKeeperApp app]
   (let [wait-for-shutdown (get-service-fn app :shutdown-service :wait-for-shutdown)
         shutdown-reason   (wait-for-shutdown)]
-    (when (= :service-error (:type shutdown-reason))
+    (when (or (= :service-error (:type shutdown-reason))
+              (= :requested (:type shutdown-reason)))
       (shutdown! app)
-      (throw (:error shutdown-reason)))))
+      (when (:error shutdown-reason)
+        (throw (:error shutdown-reason))))))


Don't parse code if it's options.

Don't parse code if it's options.

--- src/rsvp_backend/handlers/invitee.clj
+++ src/rsvp_backend/handlers/invitee.clj
@@ -8,14 +8,13 @@

 (defn new-invitee
   [request]
-  (let [query (:query (:params request))
-        request-method (:request-method request)
-        keywordized-req-body (clj-walk/keywordize-keys (:body request))
-        code (Long/parseLong (:code keywordized-req-body))
-        updated-req-body (assoc keywordized-req-body :code code)
-        resp (db/create-invitee updated-req-body)]
-    (if (= request-method :options)
-      (res/response {:status "OPTIONS_SUCCESS"})
+  (if (=  (:request-method request) :options)
+    (res/response {:status "OPTIONS_SUCCESS"})
+    (let [query (:query (:params request))
+          keywordized-req-body (clj-walk/keywordize-keys (:body request))
+          code (Long/parseLong (:code keywordized-req-body))
+          updated-req-body (assoc keywordized-req-body :code code)
+          resp (db/create-invitee updated-req-body)]
       (if (= resp "AWS_ERROR")
         (res/status (res/response {:status "AWS_ERROR"}) 500)
         (res/response {:status "SUCCESS" :data {:code code}})))))


Pass resolution along with the path, since we can't reconstruct a PK without resolution

--- src/io/cyanite/engine.clj
+++ src/io/cyanite/engine.clj
@@ -71,7 +71,7 @@

 (defn snapshot-resolution
   [path now resolution]
-  (mapv #(assoc % :path path) (snapshot! resolution now)))
+  (mapv #(assoc % :path path :resolution (:resolution resolution)) (snapshot! resolution now)))

 (defn snapshot-path
   [now [path resolutions]]


build properties. fixes #4

build properties. fixes #4

--- src/lolitemsets/core.cljs
+++ src/lolitemsets/core.cljs
@@ -93,6 +93,41 @@
              :value (key @app)
              :on-change #(swap! app assoc key (int (-> % .-target .-value)))}]]])

+(defn build-stats []
+  (let [{:keys [recommended champ champ-level]} @app]
+    [:div.panel.panel-primary
+     [:div.panel-heading "Build statistics"]
+     [:table.table
+      [:tr [:th "Stat"] [:th "Value"]]
+      [:tr [:td "Attack damage per second"] [:td (int (algo/build-dps champ champ-level recommended))]]
+      [:tr [:td "Attack damage"] [:td (int (algo/attack-damage champ champ-level recommended))]]
+      [:tr [:td "Critical strike chance"] [:td (int (* 100 (algo/critical-strike champ champ-level recommended))) "%"]]
+      [:tr [:td "Attack speed"] [:td (algo/attack-speed champ champ-level recommended)]]
+      [:tr [:td "Life steal per second"] [:td (int (algo/build-lsps champ champ-level recommended))]]
+      [:tr [:td "Life steal"] [:td (int (* 100 (algo/life-steal recommended))) "%"]]
+      [:tr [:td "Ability power"] [:td (algo/ability-power recommended)]]
+      [:tr [:td "Effcetive health (AD)"] [:td (int (algo/build-hp-ad champ champ-level recommended))]]
+      [:tr [:td "Effcetive health (AP)"] [:td (int (algo/build-hp-ap champ champ-level recommended))]]
+      [:tr [:td "HP"] [:td (int (algo/health champ champ-level recommended))]]
+      [:tr [:td "Armor"] [:td (int (algo/armor champ champ-level recommended))]]
+      [:tr [:td "Magic resist"] [:td (int (algo/magic-resist champ champ-level recommended))]]
+      ]]))
+
+(defn item-block [id block items]
+  (let [ids (set (map #(int (:id %)) (:items block)))
+       check #(contains? ids (:id %))
+       items (filter check items)]
+   [:div.panel.panel-default {:key id}
+    [:div.panel-heading
+     [:input.form-control
+      {:type "text"
+       :on-change #(swap! app assoc-in [:itemset :blocks id :type] (-> % .-target .-value))
+       :value (:type block)}]]
+      [:div.panel-body
+     (for [item items]
+       [:span {:key (:id item)}
+        (item-image item)])]]))
+
 (defn item-set []
   (let [state @app
         itemset (:itemset state)
@@ -106,19 +141,7 @@
          :value (:title itemset)}]]
       [:div.panel-body
        (for [[id block] blocks]
-         (let [ids (set (map #(int (:id %)) (:items block)))
-               check #(contains? ids (:id %))
-               items (filter check items)]
-           [:div.panel.panel-default {:key id}
-            [:div.panel-heading
-             [:input.form-control
-              {:type "text"
-               :on-change #(swap! app assoc-in [:itemset :blocks id :type] (-> % .-target .-value))
-               :value (:type block)}]]
-              [:div.panel-body
-             (for [item items]
-               [:span {:key (:id item)}
-                (item-image item)])]]))]]))
+         [item-block id block items])]]))

 (defn needlessly-large-button []
   (let [blob (js/Blob. #js[(.stringify js/JSON (clj->js (:itemset @app)))]
@@ -150,7 +173,9 @@
       [needlessly-large-button]] ; download
     [:br][:br] ; ugly
     [item-set]]
-   [:div.container.col-sm-6 [item-recommendation]]])
+   [:div.container.col-sm-6
+    [build-stats]
+    [item-recommendation]]])

 (reagent/render-component [app-component]
                           (. js/document (getElementById "app")))


escape the "&" in the uri which is used as feed id

--- src/statuses/views/atom.clj
+++ src/statuses/views/atom.clj
@@ -46,7 +46,7 @@
   [items base-uri feed-uri]
   (into [:feed {:xmlns "http://www.w3.org/2005/Atom"}
          [:title "innoQ Status updates"]
-         [:id feed-uri]
+         [:id (escape-html feed-uri)]
          [:updated (as-rfc3339 (:time (first items)))]
          [:link {:rel "self"
                  :type "application/atom+xml"


Removed duplicate link in top bar

Removed duplicate link in top bar

--- src/statuses/views/main.clj
+++ src/statuses/views/main.clj
@@ -40,8 +40,7 @@
 (defn nav-links [request]
   (let [github-issue-uri "https://github.com/innoq/statuses/issues"
         info-uri         "/statuses/info"]
-    (list (nav-link (updates-uri request)       "Everything"      "th-list")
-          (nav-link (mention-uri request)       "Mentions"        "user")
+    (list (nav-link (mention-uri request)       "Mentions"        "user")
           (nav-link (updates-uri request :atom) "Feed (all)"      "fire")
           (nav-link (mention-uri request :atom) "Feed (mentions)" "fire")
           (nav-link info-uri                    "Info"            "info-sign")


#10 add next|previous page url

#10 add next|previous page url

--- src/kalar_plugins/templates/hiccup.clj
+++ src/kalar_plugins/templates/hiccup.clj
@@ -34,9 +34,6 @@
            (kfile/touch f#)
            (spit  f#  (let [] ~@body)))))))

-
-
-
 (defn load-markdown [^String file]
   (let [input    (new StringReader (slurp file))
         output   (new StringWriter)
@@ -51,24 +48,36 @@

 (def num-ptn #":num")

+(defn get-post-url [num]
+  (let [ptn (:post-url-pattern (config/read-config))]
+    (string/replace ptn num-ptn (str num))))
+
 (defmacro def-posts [body]
   `(def hiccup#
      (reify HiccupPlugin
        (hiccup-compile [this]
          (let [files# (.listFiles (io/file ~(:posts-dir (config/read-config))))
-               rng# (range (count files#))
-               index-file-map# (zipmap rng# files#)]
+               total# (count files#)
+               get-next-post# (fn [num#] (if (= num# total#) nil (get-post-url (+ num# 1))))
+               get-previous-post# (fn [num#] (if (= num# 1) nil (get-post-url (- num# 1))))
+               num-file-map# (map (fn [file# num#] {:num num#
+                                                    :file file#
+                                                    :post-url (get-post-url num#)
+                                                    :next-page (get-next-post# num#)
+                                                    :previous-page (get-previous-post# num#)})
+                                  files#
+                                  (range 1 (+ 1 total#)))]
            (dorun
-             (for [tuple# index-file-map#]
-               (let [~'page_ (merge (load-markdown (.getAbsolutePath (val tuple#))) {:index (key tuple#)})
-                     output# (io/file (kfile/find-dest) (string/replace (:post-url-pattern (config/read-config))
-                                                                        num-ptn (str (key tuple#))))]
+             (for [post# num-file-map#]
+               (let [~'page_ (merge (load-markdown (.getAbsolutePath (:file post#))) (dissoc post#
+                                                                                :num
+                                                                                :file
+                                                                                :post-url))
+                     output# (io/file (kfile/find-dest) (string/replace (:post-url post#) #"^/" ""))]
                  (kfile/touch output#)
                  (spit output# ~body)))))))))

-(defn get-post-url [num]
-  (let [ptn (:post-url-pattern (config/read-config))]
-    (string/replace ptn num-ptn (str num))))
+

 (defmacro def-excerpts [head-url tail-url-ptn num-perpage body]
   `(def hiccup#


corrected require in core.clj for missing defstate

--- src/lcmap/aardvark/core.clj
+++ src/lcmap/aardvark/core.clj
@@ -10,7 +10,7 @@
   See also:
   * `dev/lcmap/aardvark/dev.clj` for REPL-driven development.
   * `dev/resources/lcmap-landsat.edn` for configuration."
-  (:require [mount.core :as mount]
+  (:require [mount.core :refer [defstate] :as mount]
             [clojure.edn :as edn]
             [clojure.tools.logging :as log]
             [lcmap.aardvark.config :as config])


better alias for pc.datomic

better alias for pc.datomic

--- src/pc/datomic/schema.clj
+++ src/pc/datomic/schema.clj
@@ -1,5 +1,5 @@
 (ns pc.datomic.schema
-  (:require [pc.datomic :as c-d]
+  (:require [pc.datomic :as pcd]
             [datomic.api :refer [db q] :as d]))

 (defn attribute [ident type & {:as opts}]
@@ -39,7 +39,7 @@
    ])

 (defn ensure-schema
-  ([] (ensure-schema (c-d/conn)))
+  ([] (ensure-schema (pcd/conn)))
   ([conn]
      @(d/transact conn schema)))


Add description on main page

Add description on main page

--- src/pict_source/index.clj
+++ src/pict_source/index.clj
@@ -5,6 +5,13 @@

 (defn page [dictionaries]
   [:div {:class "content"}
+   [:div {:class "row"}
+    [:div {:class "twelve column"}
+     [:p
+      "The programmers open dictionary from programmers for culture of using your own spoken language."
+      " I highly encourage you to "
+      [:a {:href "https://github.com/shvetsovdm/pict-source"} "contribute to dictionaries and to the project"]
+      "."]]]
    (for [dict-row (partition-all 3 dictionaries)]
      [:div {:class "row"}
       (for [dict dict-row]


fix reflection warning

fix reflection warning

--- src/preflex/resilient.clj
+++ src/preflex/resilient.clj
@@ -372,7 +372,7 @@
                                                      ts (now-millis-finder)]
                                                  (if (:open-elapsed? state)
                                                    ;; half-open window may have elapsed, so test and shift to next one
-                                                   (if (>= (- ^long ts (.-last-retry-ts state)) half-open-millis)
+                                                   (if (>= (- ^long ts (.-last-retry-ts state)) ^long half-open-millis)
                                                      (h-shift ts)  ; shift to the next half-open window and return true
                                                      (let [rc (.-retry-counter state)]
                                                        (if (< rc ^long retry-times)


beginning to consolidate functions

beginning to consolidate functions

--- src/midje/util/checkers.clj
+++ src/midje/util/checkers.clj
@@ -511,8 +511,10 @@
 ;  (println 'map-match actual expected looseness)
   (let [comparison (compare-results midje-classification actual expected looseness)
         mismatch-description (fn [comparison expected]
-                               (remove nil? [ (best-actual-match midje-classification comparison)
-                                              (best-expected-match midje-classification comparison expected) ]))]
+                               (cons (best-actual-match midje-classification comparison)
+                                     (when (some inexact-checker?)
+                                       (best-expected-match midje-classification
+                                                            comparison expected))))]
     (or (total-match? comparison)
         (apply noted-falsehood (mismatch-description comparison expected)))))


implement :on-change, use reagent/cursor

refactor/rename a little

--- src/re_com/typeahead.cljs
+++ src/re_com/typeahead.cljs
@@ -51,40 +51,43 @@
     out))

 (def ^:private typeahead-state-initial
-  {:text ""
+  {:input-text ""
    :waiting? false
    :suggestions []})

 (defn- wrap [index count]
   (mod (+ count index) count))

-(defn- suggestion-select-prev
+(defn- select-prev
   [{:as state :keys [suggestions]}]
-  (update state :suggestion-selected-index #(-> % (or 0) dec (wrap (count suggestions)))))
-
-(defn- suggestion-select-next
+  (update state :selected-index #(-> % (or 0) dec (wrap (count suggestions)))))
+
+(defn- select-next
   [{:as state :keys [suggestions]}]
-  (update state :suggestion-selected-index #(-> % (or -1) inc (wrap (count suggestions)))))
-
-(defn- suggestion-select-set
+  (update state :selected-index #(-> % (or -1) inc (wrap (count suggestions)))))
+
+(defn- select-set
   [state i]
-  (assoc state :suggestion-selected-index i))
-
-(defn- suggestion-select-choose
-  [{:as state :keys [suggestions suggestion-selected-index]}]
-  (-> state
-      (assoc :model (nth suggestions suggestion-selected-index))
-      (dissoc :suggestions)))
-
-(defn- suggestion-select-reset
+  (assoc state :selected-index i))
+
+(defn- select-choose
+  [{:as state :keys [suggestions selected-index on-change]}]
+  (let [[search suggestion :as selected] (nth suggestions selected-index)]
+    (when on-change
+      (on-change suggestion))
+    (-> state
+        (assoc :model suggestion :input-text "")
+        (dissoc :suggestions))))
+
+(defn- select-reset
   [state]
-  (dissoc state :suggestion-selected-index))
+  (dissoc state :selected-index))

 (defn- reset-typeahead
   [state]
   (-> state
-      (assoc :waiting? false :suggestions [])
-      suggestion-select-reset))
+      (assoc :waiting? false :suggestions [] :input-text "")
+      select-reset))

 (defn- search-data-source
   "Call the user-supplied `data-source` fn and put the result on `c-sugg`.
@@ -106,16 +109,17 @@
   [state-atom c-sugg]
   (go-loop []
     (let [[search suggestions] (<! c-sugg)]
-      (when (= search (:model @state-atom))
+      (when (= search (:input-text @state-atom))
         (swap! state-atom #(-> %
                                (assoc :suggestions suggestions :waiting? false)
-                               suggestion-select-reset))))
+                               select-reset))))
     (recur)))

 (defn- make-typeahead-state
-  []
+  [on-change]
   (let [c-input (chan)]
     (assoc typeahead-state-initial
+           :on-change on-change
            :c-keypress (chan)
            :c-input c-input
            :c-search (debounce c-input 250) ;; FIXME hard-coded
@@ -136,9 +140,9 @@
   (when-let [key (keys-by-code (.-which event))]
     (.preventDefault event)
     (case key
-      :up    (swap! state-atom suggestion-select-prev)
-      :down  (swap! state-atom suggestion-select-next)
-      :enter (swap! state-atom suggestion-select-choose)
+      :up    (swap! state-atom select-prev)
+      :down  (swap! state-atom select-next)
+      :enter (swap! state-atom select-choose)
       true)))

 (defn- on-key-down
@@ -146,27 +150,32 @@
   (when-let [key (keys-by-code (.-which event))]
     (.preventDefault event)
     (case key
-      :tab   (swap! state-atom suggestion-select-next)
+      :tab   (swap! state-atom select-next)
       true)))

 (defn- typeahead
   "Returns markup for a typeahead text input"
-  [& {:keys [model data-source] :as args}]
+  [& {:keys [data-source on-change] :as args}]
   {:pre [(validate-args-macro typeahead-args-desc args "typeahead")]}
-  (let [{:as state :keys [ c-search c-sugg c-input c-keypress ]} (make-typeahead-state)
-        state-atom (reagent/atom state)]
+  (let [{:as state :keys [ c-search c-sugg c-input c-keypress ]} (make-typeahead-state on-change)
+        state-atom (reagent/atom state)
+        input-text-model (reagent/cursor state-atom [:input-text])]
     (handle-search-results state-atom c-sugg)
     (handle-search state-atom c-sugg data-source c-search)
     (fn
-      [& {:keys [model placeholder width height status-icon? status status-tooltip disabled? class style]
+      [& {:keys [render-suggestion on-change model
+                 placeholder width height status-icon?
+                 status status-tooltip disabled? rigid?
+                 class style]
           :as   args}]
       {:pre [(validate-args-macro typeahead-args-desc args "typeahead")]}
-      (let [{:keys [suggestions waiting? model suggestion-selected-index]} @state-atom
+      (let [{:keys [suggestions waiting? model selected-index]} @state-atom
             width (or width "250px")]
         [v-box
          :width width
          :children
          [[input-text
+           :model          input-text-model
            :class          class
            :style          style
            :disabled?      disabled?
@@ -176,10 +185,9 @@
            :width          width
            :height         height
            :placeholder    placeholder
-           :on-change #(do (swap! state-atom assoc :model %)
+           :on-change #(do (swap! state-atom assoc :input-text %)
                            (put! c-input %))
            :change-on-blur? false
-           :model (or model "")
            :attr {:on-key-up   #(on-key-up state-atom %)
                   :on-key-down #(on-key-down state-atom %)}]
           (if (or (not-empty suggestions) waiting?)
@@ -188,11 +196,13 @@
              :children [(when waiting?
                           [box :align :center :child [throbber :size :small :class "rc-typeahead-throbber"]])
                         (for [[ i s ] (map vector (range) suggestions)
-                              :let [selected? (= suggestion-selected-index i)]]
+                              :let [selected? (= selected-index i)]]
+                          ^{:key i}
                           [box
-                           :child s
+                           :child (if render-suggestion
+                                    (render-suggestion s)
+                                    s)
                            :class (str "rc-typeahead-suggestions-item"
                                        (when selected? " active"))
-                           :attr {:on-mouse-over #(swap! state-atom suggestion-select-set i)
-                                  :on-mouse-down #(do (.preventDefault %) (swap! state-atom suggestion-select-choose))
-                                  }])]])]]))))
+                           :attr {:on-mouse-over #(swap! state-atom select-set i)
+                                  :on-mouse-down #(do (.preventDefault %) (swap! state-atom select-choose))}])]])]]))))


Add documentation to the wrapper stuff

Add documentation to the wrapper stuff

--- src/useful/experimental.clj
+++ src/useful/experimental.clj
@@ -156,7 +156,31 @@
          (extend ~name
            ~@(apply concat proto-fns))))))

-(defmacro defn-wrapping [name wrappers-var doc args & body]
+(defmacro defn-wrapping
+  "Define a function as with defn, which checks the contents of wrappers-var
+  whenever it is called. If that var is empty, the underlying defn is called
+  without modification. Otherwise, it is treated as a list of wrapper functions,
+  which are wrapped around the underlying implementation before it is called.
+
+  The wrappers are applied left-to-right, which means that the rightmost
+  wrapper is outermost, and the leftmost wrapper is applied just before the base
+  function.
+
+  The wrappers are not called \"directly\" on the arguments, but are
+  instead called like Ring wrappers, to create a single function composed of
+  all of them; the resulting function is called with the actual arguments to
+  the defn-wrapping function.
+
+  For example, if the wrapped function is -, and the wrappers are
+  [(fn [f] (fn [x] (* 2 (f x)))), (fn [f] (fn [x] (f (+ 10 x))))],
+  then the eventual function will behave like (fn [x] (* 2 (- (+ 10 x)))).
+
+  Swapping the order of the wrappers would yield a function behaving like
+  (fn [x] (* 2 (+ 10 (- x)))).
+
+  Note the order of the wrapping: when called with 10 as an argument, the former
+  will return -40, and the latter 0."
+  [name wrappers-var doc args & body]
   `(let [impl# (fn ~args ~@body)]
      (defn ~name ~doc [& args#]
        (let [wrappers# (seq @~wrappers-var)]
@@ -171,9 +195,17 @@
                             wrappers#)
                     args#)))))))

-(defmacro with-wrappers [wrappers-var wrap-fns & body]
+(defmacro with-wrappers
+  "Dynamically bind some additional wrappers to the specified wrapper-var
+  (see defn-wrapping). Each wrapper function will be conj-ed onto the current
+  set of wrappers."
+  [wrappers-var wrap-fns & body]
   `(with-bindings {~wrappers-var (into @~wrappers-var ~wrap-fns)}
      ~@body))

-(defmacro with-wrapper [wrappers-var wrap-fn & body]
+(defmacro with-wrapper
+  "Dynamically bind an additional wrapper to the specified wrapper-var
+  (see defn-wrapping). The wrapper function will be conj-ed onto the current
+  set of wrappers."
+  [wrappers-var wrap-fn & body]
   `(with-wrappers ~wrappers-var [~wrap-fn] ~@body))


Tests for the new function

Tests for the new function

--- test/clj_fileutils/fileutils_test.clj
+++ test/clj_fileutils/fileutils_test.clj
@@ -234,3 +234,34 @@
             (is (not (some #{"test2.txt"} test-files)))
             (is (not (some #{"test3.txt"} test-files)))
             (is (not (some #{"foobarbaz"} test-files))))))
+
+(deftest test-file-list
+    "Check the function clj-fileutils.fileutils/file-list"
+    (testing "Check the function clj-fileutils.fileutils/file-list"
+        (let [test-files (file-list "test")
+              filenames (map #(.getName %) test-files)]
+            (is (some #{"test1.txt"} filenames))
+            (is (some #{"test2.txt"} filenames))
+            (is (some #{"test3.txt"} filenames))
+            (is (not (some #{"foobarbaz"} filenames))))))
+
+(deftest test-file-list-2
+    "Check the function clj-fileutils.fileutils/filename-list"
+    (testing "Check the function clj-fileutils.fileutils/filename-list"
+        (let [test-files (file-list "test" ".txt")
+              filenames (map #(.getName %) test-files)]
+            (is (some #{"test1.txt"} filenames))
+            (is (some #{"test2.txt"} filenames))
+            (is (some #{"test3.txt"} filenames))
+            (is (not (some #{"foobarbaz"} filenames))))))
+
+(deftest test-file-list-3
+    "Check the function clj-fileutils.fileutils/filename-list"
+    (testing "Check the function clj-fileutils.fileutils/filename-list"
+        (let [test-files (file-list "test" ".baz")
+              filenames (map #(.getName %) test-files)]
+            (is (not (some #{"test1.txt"} filenames)))
+            (is (not (some #{"test2.txt"} filenames)))
+            (is (not (some #{"test3.txt"} filenames)))
+            (is (not (some #{"foobarbaz"} filenames))))))
+


Better error message for org name length

--- src/oc/storage/api/orgs.clj
+++ src/oc/storage/api/orgs.clj
@@ -212,10 +212,10 @@

 ;; ----- Validations -----

-(def -org-name-error (str "Org name length. Allowed length is " org-name-min-length " to " org-name-max-length " characters"))
+(def -org-name-error (str "Error in org name length: allowed length is " org-name-min-length " to " org-name-max-length " characters"))

 (defn- org-name-error [org-name]
-  (format "%s, \"%s\" is %d" -org-name-error org-name (count org-name)))
+  (format "%s, proposed value \"%s\" is %d" -org-name-error org-name (count org-name)))

 (defn- valid-org-name? [org-name]
   (<= org-name-min-length (count org-name) org-name-max-length))


Make Eastwood happy.

Make Eastwood happy.

--- src/oc/storage/representations/org.clj
+++ src/oc/storage/representations/org.clj
@@ -36,8 +36,9 @@
 (defn- activity-link [org]
   (hateoas/link-map "activity" hateoas/GET (str (url org) "/activity") {:accept mt/activity-collection-media-type}))

-(defn- calendar-link [org]
-  (hateoas/link-map "calendar" hateoas/GET (str (url org) "/activity/calendar") {:accept mt/activity-calendar-media-type}))
+;; Not currently used
+; (defn- calendar-link [org]
+;   (hateoas/link-map "calendar" hateoas/GET (str (url org) "/activity/calendar") {:accept mt/activity-calendar-media-type}))

 (defn- org-links [org access-level]
   (let [links [(self-link org)]


load_all.clj: added test.www

load_all.clj: added test.www

--- src/org/altlaw/load_all.clj
+++ src/org/altlaw/load_all.clj
@@ -8,6 +8,7 @@
    org.altlaw.test.internal.privacy.impl
    org.altlaw.test.internal.privacy.client
    org.altlaw.test.run
+   org.altlaw.test.www

    org.altlaw.util.context
    org.altlaw.util.date


ignore nil

ignore nil

--- kafka-clj/src/kafka_clj/consumer.clj
+++ kafka-clj/src/kafka_clj/consumer.clj
@@ -442,8 +442,10 @@
 	                                            (calculate-locked-offsets topic group-conn broker-offsets1 conf)))
                timer-ctx (.time m-consume-cycle)
                q (consume-brokers! producers group-conn broker-offsets2 msg-ch conf)]
-	       (let [[v errors] q]
-			    (if (> (count (filter #(> (:error-code %) 1) errors)) 0) ;exclude out of range errors
+	       (let [[v errors] q
+               errors2 (filter #(> (:error-code %) 1) errors) ;exclude out of range errors
+               ]
+			    (if (and (not (nil? errors2)) (> (count errors2) 0))
 			      (do
 			         (error "Error close and reconnect: " errors)


More level tweaks; all should be passable

--- src/the_narrator_is_dyxleic/levels.cljs
+++ src/the_narrator_is_dyxleic/levels.cljs
@@ -4,15 +4,15 @@
   {
     :start "bitrab"
     :target "rabbit"
-    :text-before "A rabbid cabbage blocks the path. You pull a"
-    :text-after " out of your hat and hurl it at the beast."
+    :text-before "Jack strolls through the forest. Suddenly, Jack notices that a rabbid cabbage blocks the path. Jack pulls a"
+    :text-after " out of his hat and hurls it at the beast. Cabbage gone, the path forward is clear."
     :operations ["rotate"]}
   {
     :start "snoop"
     :target "spoon"
-    :text-before "A laser unicorn stands in your way. You deflect its beam with a"
-    :text-after ". Run while it's stunned!"
-    :operations ["reverse" "rotate"]}
+    :text-before "Just a few steps down the path, a laser unicorn jumps out of a shrubberry bush and stands in Jack's way. Jack deflect its beam with a"
+    :text-after ". Better run while it's stunned!"
+    :operations ["rotate" "reverse"]}
   {
     :start "tep"
     :target "steps"
@@ -23,16 +23,16 @@
     :text-after " away. Hungry Harry violently hits the wall of the pit. The wall crumbles, revealing a cave."
     :operations ["reverse" "rotate" "push-s"]}
   {
-    :start "yrH"
+    :start "Hry"
     :target "Harry"
     :text-before "Wild crocodile in the cave! In a brief moment of panic, Jack throws "
-    :text-after " at the crocodile. The crocodile and Harry seem both hungry so Jack decides to leave the two alone."
+    :text-after " at the crocodile. The crocodile and Harry both seem hungry so Jack decides to leave the two alone."
     :operations ["rotate" "duplicate-last" "rr -> a"]}
   {
     :start "cellut"
     :target "carrot"
     :text-before (str
-                   "Jack gets out of the cave but is stopped by a snowman guard: 'Intruders shall pay!'"
+                   "The cave exit leads to a wintery realm. Jack looks briefly around but is stopped by a snowman guard: 'Intruders shall pay!'"
                    "Jack grabs the snowman's")
     :text-after (str
                   " nose and coal eyes and feeds them to a passing rabbit. The faceless snowman is furious and "
@@ -51,14 +51,14 @@
     :target "tchro"
     :text-before (str
                    "The key fits and Jack's out of the cell - into a hallway. A few steps down the hallway, "
-                   "a bat is attacking a weasel! Fortunately, Jack brought along a")
+                   "a wild bat is attacking a wild weasel! Fortunately, Jack brought along a")
     :text-after (str
-                  " and swings it at the bat, scaring it away. The weasel thanks Jack and asks him for a ride out."
+                  " and swings it at the bat, scaring it away. The wild weasel thanks Jack and asks him for a ride out."
                   "Jack agrees and the wesel climbs into Jack's pocket. A door stands at the end of the hallway.")
     :operations ["reverse" "rotate"]}
   {
-    :start "asd"
-    :target "wel"
+    :start "wel"
+    :target "weasel"
     :text-before "Jack opens the door, only to reveal a sleeping Basilisk. Jack sees the "
     :text-after (str
                   " jump out of his pocket and speed towards the serpent-like creature. The Basilisk twists and turns,"


Implemented a function for changing location.hash (address bar).

--- app/src/clj_web_example/ui/route.cljs
+++ app/src/clj_web_example/ui/route.cljs
@@ -29,3 +29,10 @@
   []
   (set! js/window.onhashchange update-route!)
   (update-route! nil))
+
+;
+; For modifying the location.hash
+;
+(defn modify-location-hash!
+  [hash]
+  (set! js/location.hash hash))


Added grouping of edits, working on application.

--- src/api_test/xml.clj
+++ src/api_test/xml.clj
@@ -94,23 +94,52 @@
 (defn test-set-values
   "given a lazy sequence of cucumber table values of :tag path and :content reset the :content of the matching paths in the message"
   [values message]
-  (loop [zipper (zip/xml-zip (parse message)) line values]
+  (loop [zipper (zip/xml-zip (parse message)) line (reduce-by :tag #(conj %1 (:content %2)) [] values)]
     (if (= () line)
       (xml/indent-str (zip/root zipper))
       (do
-        (let [paths (str/split (:tag (first line)) #">")
+        (println "line=" line)
+        (let [paths (str/split (key (first line)) #">")
               matches (map #(zx/tag= (keyword %)) paths)
-              edit { :tag (keyword (last paths)) :content (:content (first line)) }
+              ;edit { :tag (keyword (last paths)) :content (:content (first line)) }
+              edits (val (first line))
               new-loc (apply zx/xml-> zipper matches)]
-          (println (class new-loc) " : " new-loc)
-          (let [loc (if (not= nil new-loc)
-                      (zip/root (zip/replace new-loc edit))
+          (println "first= " (first new-loc))
+          (println "second=" (second new-loc))
+          (let [loc (if (not= () new-loc)
+                      (do
+                        ;(println "new-loc="  new-loc)
+                        ;(zip/root (zip/replace (first new-loc) {:tag (keyword (last paths)) :content (val (first line))})))
+                        (zip/root (map #(zip/replace %1 {:tag (keyword (last paths)) :content (val %2)}) new-loc edits)))
                       (zip/root zipper))]
             (recur (zip/xml-zip loc) (rest line))))))))

 (pr (test-set-values  (lazy-seq '({:tag "a" :content "arglebargle" }
                               {:tag "b>c>d" :content "foo" }
                               {:tag "b>c>d" :content "bar" })) test-request))
+
+
+
+(def myvals (lazy-seq '({:tag "a" :content "arglebargle" }
+                              {:tag "b>c>d" :content "foo" }
+                              {:tag "b>c>d" :content "bar" })))
+
+(defn reduce-by [key-fn f init coll]
+  (reduce (fn [summaries x]
+            (let [k (key-fn x)]
+              (assoc summaries k (f (summaries k init ) x))))
+          {} coll))
+
+(def rdcd (reduce-by :tag #(conj %1 (:content %2)) [] myvals))
+
+(pr rdcd)
+(pr  (second rdcd))
+
+(for [line rdcd]
+  (do
+    (pr (key line))
+    (pr (val line))))
+

 (defn set-values
   "given a lazy sequence of cucumber table values of :tag path and :content reset the :content of the matching paths in the message"


fixes broken spec

fixes broken spec

--- src/speclj/components.clj
+++ src/speclj/components.clj
@@ -5,12 +5,12 @@

 (extend-protocol SpecComponent
   ;cljs-ignore->
-;  java.lang.Object ; This prohibits multimethod defs... Let it pass
-;  (install [this description] (throw (java.lang.Exception. (str "Oops!  It looks like you tried to add a " (type this) ":" this " to a spec.  That's not allowed."))))
+  java.lang.Object
+  (install [this description] (comment "This prohibits multimethod defs, and other stuff.  Don't be so stingy! Let it pass."))
   nil
   (install [this description] (throw (java.lang.Exception. (str "Oops!  It looks like you tried to add 'nil' to a spec.  That's not allowed."))))
-;  clojure.lang.Var
-;  (install [this description] (comment "Vars are cool.  Let them pass."))
+  clojure.lang.Var
+  (install [this description] (comment "Vars are cool.  Let them pass."))
   clojure.lang.Seqable
   (install [this description] (doseq [component (seq this)] (install component description)))
   ;<-cljs-ignore


Fix debugging limitation

Fix debugging limitation

Change-Id: Iea6143f6ab826864c4a6f40eace1ef75b5bc0c06

--- src/qcast/infoq/scraper.clj
+++ src/qcast/infoq/scraper.clj
@@ -157,7 +157,6 @@
   (let [publish #(hooksapp/publish % hooks-alertid hooks-apikey)
         tasks (juxt cache/put publish)]
     (->> updates
-         (take 3)
          (map tasks)
          doall)))


Add extensions option

Add extensions option

--- src/io/perun.clj
+++ src/io/perun.clj
@@ -520,9 +520,10 @@
 (deftask highlight
   "Syntax highlighting for code blocks using Pygments.

-   Requires Pygments CSS styles to be present, see https://github.com/richleland/pygments-css."
-  [_ filterer FILTER code "predicate to use for selecting entries (default: `identity`)"
-   _ class    CLASS  str  "CSS class to wrap code blocks with (default: `highlight`)"]
+   Pygments CSS styles must be provided, see https://github.com/richleland/pygments-css."
+  [_ filterer   FILTER     code  "predicate to use for selecting entries (default: `identity`)"
+   e extensions EXTENSIONS [str] "extensions of files to process"
+   c class      CLASS      str   "CSS class to wrap code blocks with (default: `highlight`)"]
   (let [pod     (create-pod highlight-deps)
         options (merge +highlight-defaults+ *opts*)]
     (content-task


Add do alias for tap function.

Add do alias for tap function.

--- src/beicon/core.cljs
+++ src/beicon/core.cljs
@@ -2,7 +2,7 @@
   (:require [beicon.extern.rxjs])
   (:refer-clojure :exclude [true? map filter reduce merge repeat mapcat
                             repeatedly zip dedupe drop take take-while
-                            concat empty delay range throw]))
+                            concat empty delay range throw do]))

 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; Predicates
@@ -537,6 +537,10 @@
   ([f g e ob]
    {:pre [(observable? ob) (fn? f) (fn? g) (fn? g)]}
    (.do ob f g e)))
+
+(def do
+  "An idiomatic alias for `tap`."
+  tap)

 (defn log
   "Print all values passed through the given


Don't collect parens that are the result of template misparses

--- src/atom_finder/questions/superfluous_parens.clj
+++ src/atom_finder/questions/superfluous_parens.clj
@@ -28,14 +28,20 @@
     (tree=by (juxt class expr-operator) parenless-mom reparsed-parenless-mom)
   ))

+(defn macro-def-node?
+  "Was this AST node parsed from inside the defintion of a macro?"
+  [node]
+  (->> node filename (= "anonymously-parsed-code.c")))
+
 (defn find-parens
   [root]
   (let [paren-types
         [(Atom. :parens paren-node? (default-finder paren-node?))
          (Atom. :superfluous-parens superfluous-parens?
                 (default-finder (fn [node]
-                                  (when (and (not (= "anonymously-parsed-code.c" (filename node)))
-                                            (paren-node? node))
+                                  (when (and (-> node macro-def-node? not)
+                                             (-> node parent misparsed-template? not)
+                                             (-> node paren-node?))
                                    (superfluous-parens? node)))))
          (Atom. :operator-precedence operator-precedence-child? (default-finder operator-precedence-child?))]]
   (find-atoms paren-types root)))
@@ -104,6 +110,20 @@
    )
   )

+(defn --test-parse-file-for-superfluous-parens []
+  "Just a place for sandbox code to live"
+  (->> "sql/item_geofunc.cc"
+     (str "~/opt/src/atom-finder/mysql-server/")
+     expand-home
+     parse-file
+     ((default-finder #(when (paren-node? %) (superfluous-parens? %))))
+     (take 4)
+     last
+     parent
+     misparsed-template?
+     prn
+     ))
+
 (defn main-superfluous-parens
   []
   (let [edn-file "tmp/all-parens_2018-10-29_03_operator-precedence-child.edn"


Initial tunes revamp.

Initial tunes revamp.

--- src/clojure/playasophy/wonderdome/mode/tunes.clj
+++ src/clojure/playasophy/wonderdome/mode/tunes.clj
@@ -1,29 +1,90 @@
 (ns playasophy.wonderdome.mode.tunes
   (:require
-    [playasophy.wonderdome.geometry.sphere :as sphere]
+    [playasophy.wonderdome.geometry.sphere :as sphere :refer [pi tau]]
     [playasophy.wonderdome.mode.core :as mode]
-    [playasophy.wonderdome.util.color :as color]))
+    [playasophy.wonderdome.util.color :as color]
+    [playasophy.wonderdome.util.control :as ctl]))
+
+
+;; General idea:
+;; - Divide up the circle into `n` slices, each assigned to a part of the
+;; frequency spectrum.
+;; - Assign a rainbow spectrum to each of the slices.
+;; - As time passes, rotate the angular offset of slices in physical space.
+;; - As time passes, rotate the offset into the rainbow for each slice.
+;; - Maintain a rolling average of the power in a particular frequency. Power
+;; decay is controlled by `falloff` parameter.
+;; - Adjust the gain per segment based on recently observed history to try to
+;; keep values normalized.
+;;
+;; For a given slice, pixels along the slice will be colored based on the
+;; rainbow offset. The current power in the slice determines how far the color
+;; should extend away from the polar axis. More energy = further coloring.
+;;
+;; To color a particular pixel, figure out which two slices it falls between,
+;; average the color and intensity. Should be a quick lookup ideally.
+;;
+;; As a stretch goal, if beats are detected, color the first few pixels of the
+;; strips (up to a max) a totally different color which fades back to zero.
+
+
+(defn- azimuth->bands
+  "Given an azimuthal angle (around the pole), determine the two bands the
+  angle falls between. Returns a vector containing the index of the first and
+  second bands and the proportion between the two."
+  [n angle]
+  {:pre [(pos? n)]}
+  (let [band-width (/ tau n)
+        angle' (if (neg? angle)
+                 (+ angle tau)
+                 angle)
+        angle-div (/ angle' band-width)
+        low-band (int (Math/floor angle-div))
+        high-band (int (Math/ceil angle-div))]
+    [low-band
+     (if (<= n high-band) 0 high-band)
+     (- angle-div low-band)]))
+

 (defrecord TunesMode
-  [gain falloff]
+  [bands          ; Average energy per band
+   gain           ; Gain per band (static for now)
+   falloff        ; How quickly energy levels decay (frac/ms)
+   smoothing      ; Proportion to smooth input samples by (fraction of old average to keep)
+   rotation       ; How much to rotate each band spatially
+   rotation-rate  ; How fast the rotation changes over time
+   color-shift    ; How much to shift the colors
+   shift-rate     ; How fast the color shifts over time
+   ]

   mode/Mode

   (update
     [this event]
-    (case (:type event)
-      ; TODO: add controls for adjusting gain and falloff
+    (case [(:type event) (:input event)]
+      [:time/tick nil]
+      (let [elapsed (or (:elapsed event) 0.0)]
+        (assoc this
+               :bands (mapv (fn [p] (* p (- 1.0 (* falloff elapsed)))) bands)
+               :rotation (sphere/wrap-angle (+ rotation (* elapsed (/ rotation-rate 1000))))
+               :color-shift (ctl/wrap [0.0 1.0] (+ color-shift (* elapsed (/ shift-rate 1000))))))

-      :audio/beat
+      [:audio/beat nil]
+      ; TODO: something
+      this
+
+      [:audio/freq nil]
       (assoc this
-             :beat/at (System/currentTimeMillis)
-             :beat/power (:power event))
+             :bands (mapv
+                      (fn [avg band-gain energy]
+                        (+ (* smoothing (or avg 0.0))
+                           (* (- 1 smoothing)
+                              (or band-gain 0.0)
+                              (or energy 0.0))))
+                      bands gain (:spectrum event)))

-      :audio/freq
-      (assoc this
-             :freq/spectrum (:spectrum event)
-             :freq/at (System/currentTimeMillis))
+      ; TODO: add controls for adjusting gain, falloff, rotation-rate, shift-rate

       ; default
       this))
@@ -31,17 +92,30 @@

   (render
     [this pixel]
-    (let [[r p a] (:sphere pixel)
-          now (System/currentTimeMillis)
-          beat-elapsed (- now (or (:beat/at this) 0))
-          saturation (Math/exp (/ beat-elapsed -100.0))]
+    (let [[_ polar azimuth] (:sphere pixel)
+          [i1 i2 p] (azimuth->bands (count bands) (+ azimuth rotation))
+          hue-index (/ (+ i1 p) (count bands))
+          e1 (ctl/bound [0.0 1.0] (- 1 (Math/exp (- (nth bands i1)))))
+          e2 (ctl/bound [0.0 1.0] (- 1 (Math/exp (- (nth bands i2)))))]
       (color/hsv
-        a ;(/ a sphere/tau)
-        1
-        1))))
+        (color/rainbow (+ hue-index color-shift))
+        1 ; TODO: something fun with saturation
+        ; TODO: calculate value based on polar angle
+        (+ (* (- 1 p) e1) (* p e2))
+        ))))

 (defn init
-  "Creates a new rainbow color-cycling mode."
-  []
-  (TunesMode. 0.0 0.0))
+  "Creates a new sound-reactive mode with `n` frequency bands."
+  [n & {:as opts}]
+  (map->TunesMode
+    (merge
+      {:gain (vec (take n (repeat 1.0)))
+       :falloff 0.1
+       :smoothing 0.2
+       :rotation-rate 0.1
+       :shift-rate 0.1}
+      opts
+      {:bands (vec (take n (repeat 0.0)))
+       :rotation 0.0
+       :color-shift 0.0})))


need 8181 port open for DNS (spartan)

need 8181 port open for DNS (spartan)

--- src/terraboot/cluster.clj
+++ src/terraboot/cluster.clj
@@ -374,6 +374,7 @@
                    :elb [{:name "internal-lb"
                           :listeners [(elb-listener {:port 80 :protocol "HTTP"})
                                       (elb-listener {:port 2181 :protocol "TCP"})
+                                      (elb-listener {:port 8181 :protocol "TCP"})
                                       (elb-listener {:port 53 :protocol "TCP"})]
                           :health_check {:healthy_threshold 2
                                          :unhealthy_threshold 3


Move size into utility functions.

Move size into utility functions.

--- src/blobble/core.clj
+++ src/blobble/core.clj
@@ -58,12 +58,6 @@
   (when content
     (*hash-fn* content)))

-
-(defn size
-  "Determine the number of bytes stored in a blob."
-  [blob]
-  (when-let [content (:content blob)]
-    (.capacity content)))

 (defn validate!
@@ -188,6 +182,15 @@
       limit  (take limit))))

+(defn size
+  "Determine the number of bytes stored in a blob."
+  [blob]
+  (or
+    (when-let [content (:content blob)]
+      (.capacity content))
+    (:stat/size blob)))
+
+
 (defn scan-size
   "Scans the blobs in a store to determine the total stored content size."
   [store]


Trigger notification :task-complete -> :task-lifecycle-stopped in onyx core

--- src/onyx_peers/functions/functions.clj
+++ src/onyx_peers/functions/functions.clj
@@ -13,7 +13,7 @@
                         trigger
                         {:keys [window-id upper-bound lower-bound context]}
                         state]
-  (when (= :task-complete context)
+  (when (= :task-lifecycle-stopped context)
     (let [compressed (nippy/zookeeper-compress [(java.util.Date.) lower-bound upper-bound state])
           n-bytes (count compressed)]
       (info "task complete:" (.getId ledger-handle) n-bytes "bytes" [lower-bound upper-bound (map :id state)])


do not block start with jetty

do not block start with jetty

--- src/org/zalando/friboo/system/http.clj
+++ src/org/zalando/friboo/system/http.clj
@@ -32,7 +32,8 @@
                             (wrap-params))]

             ; use httpkit as ring implementation
-            (assoc this :httpd (jetty/run-jetty handler configuration)))))))
+            (assoc this :httpd (jetty/run-jetty handler (merge configuration
+                                                               {:join? false}))))))))

   (stop [this]
     (if-not httpd
@@ -42,7 +43,7 @@

       (do
         (log/info "stopping HTTP daemon")
-        (httpd :timeout 100)
+        (.stop httpd)
         (assoc this :httpd nil)))))

 (defn new-http


Zoom camera in

Zoom camera in

--- dungeon-crawler/desktop/src-common/dungeon_crawler/utils.clj
+++ dungeon-crawler/desktop/src-common/dungeon_crawler/utils.clj
@@ -2,7 +2,7 @@
   (:require [play-clj.core :refer :all]
             [play-clj.g2d :refer :all]))

-(def ^:const vertical-tiles 30)
+(def ^:const vertical-tiles 4)
 (def ^:const pixels-per-tile 64)
 (def ^:const duration 0.2)
 (def ^:const damping 0.5)


fix nested-maps transform

fix nested-maps transform

--- src/status_im/data_store/messages.cljs
+++ src/status_im/data_store/messages.cljs
@@ -18,7 +18,7 @@
   (->> (keywordize-keys (apply hash-map (split s #"[;=]")))
        (map (fn [[k v]]
               [k (if (= k :params)
-                   (read-string v)
+                   (keywordize-keys (read-string v))
                    v)]))
        (into {})))


Update docstring

Update docstring

--- src/cljam/io/wig.clj
+++ src/cljam/io/wig.clj
@@ -45,7 +45,7 @@
 (def ^:const wig-fields [:track :chr :start :end :value])

 (defn- header-or-comment?
-  "Checks if given string is neither a header nor a comment line."
+  "Returns true if given string is a blank, header, or comment line."
   [^String s]
   (or (empty? s)
       (.startsWith s "browser")


full demo

full demo

--- src/clojure/core.clj
+++ src/clojure/core.clj
@@ -389,6 +389,22 @@
   )))

 (comment
+
+  (def all-wavs (filter #(.endsWith (.getName %) ".wav") (file-seq (io/file "/Users/josephwilk/Workspace/music/samples"))))
+
+  (doseq [w (take 1000 all-wavs)]
+
+    (try
+      (let [wav (.getPath w) ;; "test/fixtures/test.wav" ;;(.getPath wav)
+            _ (println wav)
+            b-stats (block-stats wav 512)
+            g-stats (global-stats b-stats)
+            ]
+        (println {:file wav :stats g-stats})
+        )
+
+      (catch Exception e true)
+      ))
   (dotimes [i 1]
     (let [block-stats (block-stats "test/fixtures/test.wav")]
 ;;      (doseq [frame block-stats] (println frame))


Tweak for --create command (start with empty map, do not parse empty string)

--- src/nml/core.clj
+++ src/nml/core.clj
@@ -249,7 +249,7 @@
     ;; read -> parse -> lookup or modify -> output

     (let [fmt (let [f (:format options)] (if f (formats f) fmt-namelist))
-          m   (nml-map (if (:create options) "" (read-file in)) :s provenance)]
+          m   (if (:create options) {} (nml-map (read-file in) :s provenance))]
       (cond gets  (nml-out out (nml-gets m gets (:no-prefix options)))
             sets  (nml-out out (fmt (nml-sets m sets)))
             :else (nml-out out (fmt m))))))


replace the smart quotes

replace the smart quotes

--- src/pc/views/blog/clojure_is_a_product_design_tool.clj
+++ src/pc/views/blog/clojure_is_a_product_design_tool.clj
@@ -50,7 +50,7 @@
    :body
    (list
     [:article
-     [:p "As a product designer I’m obsessed with solving problems, and lately I’ve been designing with a niche programming language."]
+     [:p "As a product designer I'm obsessed with solving problems, and lately I've been designing with a niche programming language."]
      [:p [:a {:href "http://clojure.org/"} "Clojure"]
       " carries a stark notoriety among developers, despite being a tremendous feat of design. "
       [:a {:href "http://blog.venanti.us/why-clojure/"} "David Jarvis"]
@@ -118,7 +118,7 @@
       [:span example-cljs]]
      [:p "My favorite part about ClojureScript, is that it shares its syntax with Clojure itself.
          I improve my understanding of Clojure as a side effect of my normal workflow.
-         I can’t think of a better way to learn.
+         I can't think of a better way to learn.
          That's great design, by any standard."]]

     [:article
@@ -169,8 +169,8 @@
      [:p "My optimizations are individually subtle but they save me hours every week.
          I spend that time on more important things, like polish.
          And therein lies the point; Clojure makes me more efficient and extends my reach as a designer."]
-     [:p "Don’t let fear prevent growth.
-         You don’t have to learn Clojure—even though it’d be nice knowing I'm not alone—you just need to learn something.
+     [:p "Don't let fear prevent growth.
+         You don't have to learn Clojure—even though it'd be nice knowing I'm not alone—you just need to learn something.
          There's something you can learn right now that will help you a build better products.
          Find it and make something."]]


Add frames/to-relative-time

Add frames/to-relative-time

--- src/asciinema/player/frames.cljs
+++ src/asciinema/player/frames.cljs
@@ -98,3 +98,11 @@
   (reductions (fn [[prev-time _] [curr-time data]]
                 [(+ prev-time curr-time) data])
               frames))
+
+(defn to-relative-time
+  ([frames] (to-relative-time frames 0))
+  ([frames base-time]
+   (lazy-seq
+    (when (seq frames)
+      (let [[t v] (first frames)]
+        (cons [(- t base-time) v] (to-relative-time (rest frames) t)))))))


Use a better name for test data

Use a better name for test data

Signed-off-by: Gregory Haskins <640d9fe47775e6723f0355b7315e38f7d98d3539@gmail.com>

--- test/chaintool/build/test_interface.clj
+++ test/chaintool/build/test_interface.clj
@@ -136,7 +136,7 @@

 (def example-bad-default-enum
   "
-  enum ConflictingEnum {
+  enum BadDefaultEnum {
          ZERO = 1;
          ONE  = 2;
          TWO  = 3;


eval buffer

eval buffer

--- src/fugue/space.cljs
+++ src/fugue/space.cljs
@@ -32,22 +32,25 @@
       (update :boxes boxes/insert :below (:active state) (:next-id state))))

 (defn box [state on-shortcut name]
-  (let [file (get-in state [:files name])]
-    (cond
-      (vector? file) file
-      (string? file)
+  (let [init-text (get-in state [:files name])
+        buffer (r/atom init-text)]
+    (fn []
+      (let [buffer-val @buffer]
+        (cond
+          (vector? buffer-val) buffer-val
+          (string? buffer-val)
 ;      [:p file]
-      [editor/editor file #(print "on-change") #(print "on-selection-change") on-shortcut {"keyMap" "vim"}]
-      :else [:p (str file)])))
+          [editor/editor init-text (partial reset! buffer) #(print "on-selection-change") #(on-shortcut @buffer) {"keyMap" "vim"}]
+          :else [:p (str buffer-val)])))))

 (defn mapped-boxes [state on-shortcut]
-  (boxes/map-values (:boxes state) (partial box state on-shortcut)))
+  (boxes/map-values (:boxes state) (partial vector box state on-shortcut)))

 (defn app []
   (let [eval-state (cljs.js/empty-state)
         state (r/atom init-state)]
-    (defn eval! []
-      (let [[source settings] ((juxt current-buffer-text eval-settings) @state)
+    (defn eval! [source]
+      (let [settings (eval-settings @state)
             cb (partial swap! state on-eval)]
         (cljs.js/eval-str eval-state source nil settings cb)))
     (fn []


fixed doc strings

fixed doc strings

--- src/pho/core.clj
+++ src/pho/core.clj
@@ -19,7 +19,9 @@

 ;;from: http://stackoverflow.com/q/16748447
 ;; we don't need a uuid for this
-(defn gen-string[chunk-size, key-length]
+(defn gen-string
+  "generates a random string of chunk-size and key-length"
+  [chunk-size, key-length]
  (apply str
   (flatten
    (interpose "-"
@@ -34,11 +36,14 @@
 (defn just-files [file-s]
   (filter #(.isFile %) file-s))

-(defn local-list [some-dir]
+(defn local-list
+  "Lists just the files in your current directory"
+  [some-dir]
   (get-names (just-files (file-seq (clojure.java.io/file some-dir)))))

-;; Removes the ./ if it appears in the key name
-(defn clean-if-dot [some-file-name]
+(defn clean-if-dot
+  "Removes the annoying ./ from the filename"
+  [some-file-name]
   (if (.startsWith some-file-name "./")
     (subs some-file-name 2)
     some-file-name))
@@ -53,28 +58,35 @@
                   (.listDistributions (build-cf-client creds) (ListDistributionsRequest.))))]
         (println "Distro: " (.getId distro))))

-(defn get-invalidation-files []
+(defn get-invalidation-files
+  "Gets a vector of files in the current dir and formats them for the invalidation listing"
+  []
   (vec (map #(str "/" %) (map #(clean-if-dot %) (local-list ".")))))

-(defn build-index-path []
+(defn build-index-path
+  "Sets up a Path for holding the invalidation listing. This is misnamed"
+  []
   (let [index-path (Paths.)
         file-list (get-invalidation-files)]
     (.setItems index-path (java.util.ArrayList. file-list))
     (.setQuantity index-path (Integer. (count file-list)))
     index-path))

-(defn invalidate-index [creds which-distro]
+(defn invalidate-index
+  "Invalidates all the files we just pushed that are in S3."
+  [creds which-distro]
   (let [cf-client (build-cf-client creds)
         index-path (build-index-path)]
-   (print "Invalidating index.html with ID: "
+   (print "Invalidating files with ID: "
      (.getId
        (.getInvalidation
          (.createInvalidation cf-client
            (CreateInvalidationRequest. which-distro
              (InvalidationBatch. index-path (gen-string 12 13)))))))))

-;; Returns a list of the filenames in the bucket
-(defn pull-fnames-by-bucket [creds bucket-name]
+(defn pull-fnames-by-bucket
+  "Returns a list of the filenames in the bucket"
+  [creds bucket-name]
    (map (fn [i] (:key i))
         (:objects (s3/list-objects creds bucket-name))))


revert to master version of built_in.clj

--- boot/core/src/boot/task/built_in.clj
+++ boot/core/src/boot/task/built_in.clj
@@ -549,13 +549,9 @@
   "Perform AOT compilation of Clojure namespaces."

   [a all          bool   "Compile all namespaces."
-   n namespace NS #{sym} "The set of namespaces to compile."
-   d compile-path-sfx PATH str "*compile-path* suffix"]
+   n namespace NS #{sym} "The set of namespaces to compile."]

   (let [tgt         (core/tmp-dir!)
-        sfx (if compile-path-sfx (clojure.string/replace compile-path-sfx #"^/" "") nil)
-        sfx (if (empty? sfx) nil sfx) ;; handle pathological case -d "/"
-        compile-path (if sfx (str (.getPath tgt) "/" sfx) (.getPath tgt))
         pod-env     (update-in (core/get-env) [:directories] conj (.getPath tgt))
         compile-pod (future (pod/make-pod pod-env))]
     (core/with-pre-wrap [fs]
@@ -563,9 +559,7 @@
       (let [all-nses (->> fs core/fileset-namespaces)
             nses     (->> all-nses (set/intersection (if all all-nses namespace)) sort)]
         (pod/with-eval-in @compile-pod
-          ~(io/make-parents (io/file tgt (if sfx (str sfx "/dummy") "")))
-          (boot.pod/add-classpath ~compile-path)
-          (binding [*compile-path* ~compile-path] ;; ~(.getPath tgt)]
+          (binding [*compile-path* ~(.getPath tgt)]
             (doseq [[idx ns] (map-indexed vector '~nses)]
               (boot.util/info "Compiling %s/%s %s...\n" (inc idx) (count '~nses) ns)
               (compile ns)))))


remove debug output from fsworker

remove debug output from fsworker

--- src/brainbot/nozzle/fsworker.clj
+++ src/brainbot/nozzle/fsworker.clj
@@ -76,9 +76,6 @@
   (let [rmq-settings (misc/rmq-settings-from-config iniconfig)
         filesystems (vfs/make-filesystems-from-iniconfig iniconfig section)]

-    (println "config" iniconfig)
-    (println "rmq-settings" rmq-settings)
-    (println "fs:" filesystems)
     (when (empty? filesystems)
       (misc/die (str "no filesystems defined in section " section)))


Discard old test.

Discard old test.

--- test/behaviors/t_canary.clj
+++ test/behaviors/t_canary.clj
@@ -41,16 +41,3 @@
    (provided
      (all-procedures) => [...procedure...] ))

-
-
-(unfinished first-subfunction another-subfunction)
-
-(defn function-under-test []
-  (+ (first-subfunction 1 2 '(a blue cow))
-     (another-subfunction inc)))
-
-(fact (function-under-test) => 11
-        (provided
-          (first-subfunction odd? even? anything) => 1
-	  (another-subfunction (exactly inc)) => 10))
-


friendlier formatting for "_content: foo"

--- cljs/sledge/core.cljs
+++ cljs/sledge/core.cljs
@@ -418,7 +418,9 @@
 (defmulti format-search-term (fn [op & terms] op))

 (defmethod format-search-term :like [_ field value]
-  (str field ": " value))
+  (if (= field "_content")
+    value
+    (str field ": " value)))

 (defmethod format-search-term := [_ field value]
   (str field ": " value))


Add a test for lifting letfns with the same name

This test makes sure that lifted letfn forms do not result in name
conflicts under Oxcart.

--- test/oxcart/passes/lambda_lift_test.clj
+++ test/oxcart/passes/lambda_lift_test.clj
@@ -47,7 +47,25 @@
                (ll/lift-lambdas {})
                (eclj/emit-clojure {})
                (eval)))))
+
+  ;; Side by side letfn case
+  ;; -----------------------
+  (let [case '(let [x 1]
+                (letfn [(bar [z] (+ x z))]
+                  (bar x))
+                (letfn [(bar [z] (* (wat z) 3))
+                        (wat [z] (* 3 z))]
+                        ((juxt bar wat) x)))]

+    (is (= (eval case)
+           (oxcart/eval case)
+           (-> (let [forms (atom {})]
+                 (oxcart/eval case {:forms forms})
+                 @forms)
+               (ll/lift-lambdas {})
+               (eclj/emit-clojure {})
+               (eval)))))
+
   ;; Closure of closures case
   ;; ------------------------
   (let [case '(let [x 1]


fix timer shutdown code to check for interruptedexceptions nested as a cause of a runtime exception

--- src/clj/backtype/storm/timer.clj
+++ src/clj/backtype/storm/timer.clj
@@ -34,12 +34,12 @@
                                   (afn))
                                 (Time/sleep 1000)
                                 ))
-                            (catch InterruptedException e
-                              )
                             (catch Throwable t
-                              (kill-fn t)
-                              (reset! active false)
-                              (throw t)
+                              ;; because the interrupted exception can be wrapped in a runtimeexception
+                              (when-not (exception-cause? InterruptedException t)
+                                (kill-fn t)
+                                (reset! active false)
+                                (throw t))
                               )))
                         (.release notifier)))]
     (.setDaemon timer-thread true)


Make links protocol relative.

Make links protocol relative.

--- src/clj/leipzig_live/handler.clj
+++ src/clj/leipzig_live/handler.clj
@@ -23,13 +23,13 @@
      [:meta {:name "viewport"
              :content "width=device-width, initial-scale=1"}]
      (include-css
-       "https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.8.0/codemirror.min.css"
+       "//cdnjs.cloudflare.com/ajax/libs/codemirror/5.8.0/codemirror.min.css"
        (if (env :dev) "css/site.css" "css/site.min.css"))]
     [:body
      mount-target
      (include-js
-       "https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.8.0/codemirror.min.js"
-       "https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.8.0/mode/clojure/clojure.min.js"
+       "//cdnjs.cloudflare.com/ajax/libs/codemirror/5.8.0/codemirror.min.js"
+       "//cdnjs.cloudflare.com/ajax/libs/codemirror/5.8.0/mode/clojure/clojure.min.js"
        "js/app.js")]]))


Always send timing info for google analytics.

--- src/clj/quil_site/views/page.clj
+++ src/clj/quil_site/views/page.clj
@@ -19,7 +19,7 @@
   (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();
   })(window,document,'ga');

-  ga('create', 'UA-51485241-2', 'auto');
+  ga('create', 'UA-51485241-2', {'siteSpeedSampleRate': 100});
   ga('send', 'pageview');
   window.onerror = function(message) {
     ga('send', 'exception', {


ENH: chapter 6, exercise 4: use update-in

--- src/clj_prj03/ch6_additional.clj
+++ src/clj_prj03/ch6_additional.clj
@@ -70,3 +70,9 @@
 (assoc-in users [1 :age] 44)
 (assoc-in users [1 :password] "nhoJ")
 (assoc-in users [2] {:name "Jack" :age 19})
+
+;; Exercise 4: use the update-in function
+(def users [{:name "James" :age 26}  {:name "John" :age 43}])
+(update-in users [0 :age] inc)
+(update-in users [1 :name] clojure.string/upper-case)
+


Thomsky: allow parameterized queries

Thomsky: allow parameterized queries

Dave Dixon's `bind` only put @conn as the query's parameter. This is
rather limiting. Add the possibility to provide arbitrary parameters. In
order to make the code (and my mind) clearer, remove the `state`
argument from `bind`. I didn't see its necessity for now and it clashed
with the query parameters.

--- src/cljs/theatralia/thomsky.cljs
+++ src/cljs/theatralia/thomsky.cljs
@@ -3,7 +3,6 @@
             datascript.core
             [cljs-uuid-utils.core :as uuid]
             [re-frame.core :as rf]
-            [re-frame.utils :as rf-utils]
             [re-frame.handlers :as handlers]
             [re-frame.middleware :as middleware]
             [plumbing.core :refer [safe-get]]
@@ -30,18 +29,21 @@
 (defn bind
   "Returns a ratom containing the result of query Q on the value of the database
   behind CONN. Pass STATE if you want to use an existing ratom."
-  ([conn q]
-   (bind conn q (reagent/atom nil)))
-  ([conn q state]
-   (let [k (uuid/make-random-uuid)]
-     (reset! state (d/q q @conn))
-     (d/listen! conn k (fn [tx-report]
-                         (let [novelty (d/q q (:tx-data tx-report))]
-                           ;; Only update if query results actually changed.
-                           (when (not-empty novelty)
-                             (reset! state (d/q q (:db-after tx-report)))))))
-     (set! (.-__key state) k)
-     state)))
+  [q conn & q-args]
+  (let [k (uuid/make-random-uuid)
+        state (reagent/atom nil)
+        res (apply d/q q @conn q-args)]
+    (reset! state res)
+    (d/listen!
+      conn
+      k
+      (fn [tx-report]
+        (let [novelty (apply d/q q (:tx-data tx-report) q-args)]
+          ;; Only update if query results actually changed.
+          (when (not-empty novelty)
+            (reset! state (apply d/q q (:db-after tx-report) q-args))))))
+    (set! (.-__key state) k)
+    state))

 (defn unbind
   "Stops updates on ratom STATE from changes in CONN."