[#1949]Auth id in "/datasets/:id*" with middleware

--- backend/src/akvo/lumen/endpoint/dataset.clj
+++ backend/src/akvo/lumen/endpoint/dataset.clj
@@ -32,31 +32,39 @@
                               body :body}]
                           (dataset/create (p/connection tenant-manager tenant) (merge import-config upload-config)
                                           error-tracker jwt-claims (w/stringify-keys body)))}}]
-   ["/:id" [["" {:get {:parameters {:path-params {:id string?}}
-                       :handler (fn [{tenant :tenant
-                                      {:keys [id]} :path-params}]
-                                  (dataset/fetch (p/connection tenant-manager tenant) id))}
-                 :put {:parameters {:body map?
-                                    :path-params {:id string?}}
-                       :handler (fn [{tenant :tenant
-                                      body :body
-                                      {:keys [id]} :path-params}]
-                                  (dataset/update-meta (p/connection tenant-manager tenant) id body))}
-                 :delete {:parameters {:path-params {:id string?}}
-                          :handler (fn [{tenant :tenant
-                                         {:keys [id]} :path-params}]
-                                     (dataset/delete (p/connection tenant-manager tenant) id))}}]
-            ["/meta" {:get {:parameters {:path-params {:id string?}}
-                            :handler (fn [{tenant :tenant
-                                           {:keys [id]} :path-params}]
-                                       (dataset/fetch-metadata (p/connection tenant-manager tenant) id))}}]
-            ["/update" {:post {:parameters {:path-params {:id string?}}
-                               :handler (fn [{tenant :tenant
-                                              jwt-claims :jwt-claims
-                                              body :body
-                                              {:keys [id]} :path-params}]
-                                          (dataset/update (p/connection tenant-manager tenant) (merge import-config upload-config)
-                                                          error-tracker id (w/stringify-keys body)))}}]]]])
+   ["/:id"
+    {:middleware [(fn [handler]
+                    (fn [{{:keys [id]} :path-params
+                          auth-service :auth-service
+                          :as req}]
+                      (if (p/allow? auth-service (l.auth/ids ::dataset.s/id id))
+                        (handler req)
+                        (lib/not-authorized {:id id}))))]}
+    [["" {:get {:parameters {:path-params {:id string?}}
+                :handler (fn [{tenant :tenant
+                               {:keys [id]} :path-params}]
+                           (dataset/fetch (p/connection tenant-manager tenant) id))}
+          :put {:parameters {:body map?
+                             :path-params {:id string?}}
+                :handler (fn [{tenant :tenant
+                               body :body
+                               {:keys [id]} :path-params}]
+                           (dataset/update-meta (p/connection tenant-manager tenant) id body))}
+          :delete {:parameters {:path-params {:id string?}}
+                   :handler (fn [{tenant :tenant
+                                  {:keys [id]} :path-params}]
+                              (dataset/delete (p/connection tenant-manager tenant) id))}}]
+     ["/meta" {:get {:parameters {:path-params {:id string?}}
+                     :handler (fn [{tenant :tenant
+                                    {:keys [id]} :path-params}]
+                                (dataset/fetch-metadata (p/connection tenant-manager tenant) id))}}]
+     ["/update" {:post {:parameters {:path-params {:id string?}}
+                        :handler (fn [{tenant :tenant
+                                       jwt-claims :jwt-claims
+                                       body :body
+                                       {:keys [id]} :path-params}]
+                                   (dataset/update (p/connection tenant-manager tenant) (merge import-config upload-config)
+                                                   error-tracker id (w/stringify-keys body)))}}]]]])

 (defmethod ig/init-key :akvo.lumen.endpoint.dataset/dataset  [_ opts]


[#1143] guard against empty lat/long responses

--- backend/src/akvo/lumen/import/flow.clj
+++ backend/src/akvo/lumen/import/flow.clj
@@ -135,8 +135,10 @@

 (defmethod render-response "GEO"
   [_ response]
-  (import/->Geopoint
-   (format "POINT (%s %s)" (get response "long") (get response "lat"))))
+  (let [{:strs [long lat]} response]
+    (when (and long lat)
+      (import/->Geopoint
+       (format "POINT (%s %s)" long lat)))))

 (defmethod render-response "CASCADE"
   [_ response]


rm comments

rm comments

--- src/dalap/escape/html.clj
+++ src/dalap/escape/html.clj
@@ -1,10 +1,5 @@
 (ns dalap.escape.html
-
-;; Third Party ;;;;;
-
   (:require [clojure.string :as string])
-
-;; Local Library ;;;

   (:use dalap.escape)
   (:import [dalap.escape PreEscaped]))


Schema for non-negative numbers

Schema for non-negative numbers

--- src/db_quiz_prep/core.clj
+++ src/db_quiz_prep/core.clj
@@ -10,6 +10,8 @@
 ; ----- Schemata -----

 (def ^:private positive-number (s/both s/Int (s/pred pos? 'pos?)))
+
+(def ^:private non-negative-number (s/both s/Int (s/pred (complement neg?) 'non-negative?)))

 (def ^:private degree (s/both positive-number (s/pred (partial >= 180) 'degree?)))

@@ -25,7 +27,7 @@
           :target-graph sc/URI}
    :split-angles {:easy degree
                   :normal degree}
-   (s/optional-key :start-from) positive-number})
+   (s/optional-key :start-from) non-negative-number})

 ; ----- Private functions -----


Make 'hint' test to use only p3d renderer as some hints require 3D.

--- test/cljx/snippets/rendering.cljx
+++ test/cljx/snippets/rendering.cljx
@@ -5,7 +5,7 @@
   #+cljs
   (:use-macros [quil.snippet :only [defsnippet]]))

-(defsnippet hint {}
+(defsnippet hint {:renderer :p3d}
   (let [hints [:enable-native-fonts
                :disable-native-fonts
                :enable-depth-test


Fix bad test (replica was wrong)

Fix bad test (replica was wrong)

--- test/onyx/task_lifecycle_test.clj
+++ test/onyx/task_lifecycle_test.clj
@@ -4,7 +4,7 @@
             [onyx.peer.task-lifecycle :as task-lifecycle]))

 (deftest initialise-log-test
-  (let [event {:onyx.core/job-id :job-1
+  (let [event {:onyx.core/job-id :job0
                :onyx.core/id :peer-id-1
                :onyx.core/task-id :task-id-1
                :onyx.core/replica (atom {:task-slot-ids {:job-1 {:task-id-1 {:peer-id-1 :slot-0}}}})


figwheel.repl: greatly improve node support, don't require web socket connection

--- figwheel-repl/src/figwheel/repl.cljc
+++ figwheel-repl/src/figwheel/repl.cljc
@@ -34,7 +34,6 @@
 #?(:cljs (do

 ;; TODO dev only
-(enable-console-print!)

 ;; --------------------------------------------------
 ;; Logging
@@ -287,16 +286,39 @@
        :response response-body}
     uuid (assoc :uuid uuid)))

+;; this is a fire and forget POST
+(def http-post
+  (condp = host-env
+    :node
+    (let [http (js/require "http")]
+      (fn [url post-data]
+        (let [data (volatile! "")
+              uri (guri/parse (str url))]
+          (-> (.request http
+               #js {:host (.getDomain uri)
+                    :port (.getPort uri)
+                    :path (str (.getPath uri) (when-let [q (.getQuery uri)]
+                                                (str "?" q)))
+                    :method "POST"
+                    :headers #js {"Content-Length" (js/Buffer.byteLength post-data)}}
+               (fn [x]))
+              (.on "error" #(js/console.error %))
+              (doto
+                  (.write post-data)
+                  (.end))))))
+    (fn [url response]
+      (xhrio/send url
+                  (fn [e] (debug "Response Posted"))
+                  "POST"
+                  response))))
+
 (defn respond-to [{:keys [websocket http-url] :as old-msg} response-body]
   (let [response (response-for old-msg response-body)]
     (cond
       websocket
       (.send websocket (pr-str response))
       http-url
-      (xhrio/send http-url
-                  (fn [e] (debug "Response Posted"))
-                  "POST"
-                  (pr-str response)))))
+      (http-post http-url (pr-str response)))))

 (defn respond-to-connection [response-body]
   (respond-to (:connection @state) response-body))
@@ -341,6 +363,9 @@
                :ua-product ua-product
                :value result-value})))
         (catch js/Error e
+          ;; logging errors to console helpful
+          (when (and (exists? js/console) (exists? js/console.error))
+            (js/console.error "REPL eval error" e))
           {:status :exception
            :value (pr-str e)
            :ua-product ua-product
@@ -389,17 +414,21 @@
                  :args (mapv #(if (string? %) % (gjson/serialize %)) args)}))
   (setup-printing!))

+(defn get-websocket-class []
+  (or
+   (gobj/get goog.global "WebSocket")
+   (gobj/get goog.global "FIGWHEEL_WEBSOCKET_CLASS")
+   (and (= host-env :node)
+        (try (js/require "ws")
+             (catch js/Error e
+               nil)))
+   (and (= host-env :worker)
+        (gobj/get js/self "WebSocket"))))
+
 (defn ensure-websocket [thunk]
   (if (gobj/get goog.global "WebSocket")
     (thunk)
-    (if-let [websocket-class
-             (or (gobj/get goog.global "FIGWHEEL_WEBSOCKET_CLASS")
-                 (and (= host-env :node)
-                      (try (js/require "ws")
-                           (catch js/Error e
-                             nil)))
-                 (and (= host-env :worker)
-                      (gobj/get js/self "WebSocket")))]
+    (if-let [websocket-class (get-websocket-class)]
       (do
         (gobj/set goog.global "WebSocket" websocket-class)
         (thunk)
@@ -415,7 +444,6 @@
   (ensure-websocket
    #(let [websocket (goog.net.WebSocket.)
           url (str (make-url websocket-url'))]
-      (patch-goog-base)
       (try
         (doto websocket
           (.addEventListener goog.net.WebSocket.EventType.MESSAGE
@@ -431,25 +459,41 @@
           (.addEventListener goog.net.WebSocket.EventType.OPENED
                              (fn [e]
                                (swap! state assoc :connection {:websocket websocket})
-                               (hook-repl-printing-output! {:websocket websocket})
-                               (js/console.log "OPENED")
-                               (js/console.log e)))
+                               (hook-repl-printing-output! {:websocket websocket})))
           (.open url))))))

 ;; -----------------------------------------------------------
 ;; HTTP simple and long polling
 ;; -----------------------------------------------------------

-(defn http-get [url]
-  (Promise.
-   (fn [succ err]
-     (xhrio/send
-      url
-      (fn [e]
-        (let [xhr (gobj/get e "target")]
-          (if (.isSuccess xhr)
-            (succ (.getResponseJson xhr))
-            (err xhr))))))))
+(def http-get
+  (condp = host-env
+    :node
+    (let [http (js/require "http")]
+      (fn [url]
+        (Promise.
+         (fn [succ err]
+           (let [data (volatile! "")]
+             (-> (.get http (str url)
+                       (fn [response]
+                         (.on response "data"
+                              (fn [chunk] (vswap! data str chunk)))
+                         (.on response "end" #(succ
+                                               (try (js/JSON.parse @data)
+                                                    (catch js/Error e
+                                                      (js/console.error e)
+                                                      (err e)))))))
+                 (.on "error" err)))))))
+    (fn [url]
+      (Promise.
+       (fn [succ err]
+         (xhrio/send
+          url
+          (fn [e]
+            (let [xhr (gobj/get e "target")]
+              (if (.isSuccess xhr)
+                (succ (.getResponseJson xhr))
+                (err xhr))))))))))

 (declare http-connect http-connect*)

@@ -505,8 +549,24 @@
 (defn http-connect [& [connect-url']]
   (http-connect* 0 connect-url'))

+(defn switch-to-http? [url]
+  (if (or (gstring/startsWith url "http")
+          (get-websocket-class))
+    url
+    (do
+      (glog/warning
+       logger
+       (str
+        "No WebSocket implementation found falling back to http long polling"
+        (when (= host-env :node)
+          ":\n Please make sure \"ws\" is installed :: do -> 'npm install ws'")))
+      (-> (guri/parse url)
+          (.setScheme "http")
+          str))))
+
 (defn connect [& [connect-url']]
-  (let [url (string/trim (or connect-url' connect-url))]
+  (patch-goog-base)
+  (let [url (switch-to-http? (string/trim (or connect-url' connect-url)))]
     (cond
       (gstring/startsWith url "ws")   (ws-connect url)
       (gstring/startsWith url "http") (http-connect url))))
@@ -863,10 +923,6 @@
     (when (empty? (connections-available repl-env))
       (Thread/sleep 500)
       (recur))))
-
-
-
-

 (defn send-for-eval [{:keys [focus-session-name ;; just here for consideration
                              broadcast] :as repl-env} connections js]
@@ -1099,10 +1155,7 @@
         (remove-listener listener))))
   cljs.repl/IReplEnvOptions
   (-repl-options [this]
-    (let [main-fn (resolve 'figwheel.main/default-main)
-          ;compile-fn (resolve 'figwheel.main/default-compile)
-          ]
-
+    (let [main-fn (resolve 'figwheel.main/default-main)]
       (cond->
           {;:browser-repl true
            :preloads '[[figwheel.repl.preload]]
@@ -1123,9 +1176,7 @@
                                              (dynload %2)))
               :arg "string"
               :doc "Ring Handler for default REPL server EX. \"example.server/handler\" "}}}}
-        main-fn    (assoc :cljs.cli/main    @main-fn)
-        ;compile-fn (assoc :cljs.cli/compile @compile-fn)
-        )))
+        main-fn    (assoc :cljs.cli/main @main-fn))))
   cljs.repl/IParseStacktrace
   (-parse-stacktrace [this st err opts]
     (cljs.stacktrace/parse-stacktrace this st err opts)))
@@ -1194,7 +1245,6 @@
 (defmacro focus [session-name]
   (focus* session-name))

-
 ;; TODOS
 ;; - try https setup
 ;; - make work on node and other platforms


removing import

removing import

--- test/sparkling/sql/types_test.clj
+++ test/sparkling/sql/types_test.clj
@@ -8,7 +8,6 @@
   (:import [java.text SimpleDateFormat]
            [org.apache.spark.sql.catalyst.expressions GenericRowWithSchema]
            [scala.collection JavaConverters]
-           [org.apache.spark.sql DataFrame ]
            [org.apache.spark.sql.types StructType StructField ]
            [java.sql Date Timestamp]))


Fix bug

Fix bug

--- src/expound/problems.cljc
+++ src/expound/problems.cljc
@@ -301,3 +301,8 @@
                :expound/problems problems'))))

 (def type ptype)
+
+;; Must keep this function here because
+;; spell-spec uses it
+;; https://github.com/bhauman/spell-spec/blob/48ea2ca544f02b04a73dc42a91aa4876dcc5fc95/src/spell_spec/expound.cljc#L20
+(def value-in paths/value-in)


Recover from nil emails, even though they shouldn't happen

--- src/foreclojure/users.clj
+++ src/foreclojure/users.clj
@@ -74,7 +74,9 @@
 (let [canonical-email (comp string/trim string/lower-case)
       md5 #(DigestUtils/md5Hex %)]
   (defn gravatar-img [{:keys [email size class] :or {size 24}}]
-    (let [hash (md5 (canonical-email email))
+    (let [hash (if email
+                 (md5 (canonical-email email))
+                 "0000000000000000")
           url (str (name *http-scheme*) "://www.gravatar.com/avatar/"
                    hash "?s=" size "&d=identicon")]
       [:img (conj {:src url, :alt "gravatar icon"


Test mulbymat graph

Test mulbymat graph

Multiply scalar*matrix and matrix*matrix

--- test/tensorflow_clj/core_test.clj
+++ test/tensorflow_clj/core_test.clj
@@ -67,3 +67,11 @@
     (with-graph-file "misc/addconst.pb"
       (let [[v] (run-graph {:Placeholder [[1 2] [3 4]]} :mul)]
         (is (= v [[3.0 6.0] [9.0 12.0]]))))))
+
+(deftest mulbymat-graph
+  (testing "Multiplying variable by constant matrix"
+    (with-graph-file "misc/mulbymat.pb"
+      (let [[v] (run-graph {:Placeholder 5} :mul)]
+        (is (= v [[5. 10.] [15. 20.]])))
+      (let [[v] (run-graph {:Placeholder [[1. -1.] [2. -2.]]} :mul)]
+        (is (= v [[1. -2.] [6. -8.]]))))))


use guava LRU cache

use guava LRU cache

--- src/hambo/trident/cql.clj
+++ src/hambo/trident/cql.clj
@@ -8,7 +8,8 @@
             TransactionalMap
             OpaqueMap
             CachedMap
-            SnapshottableMap]))
+            SnapshottableMap]
+           [calculon.storm.trident.state LRUCachedMap]))

 (defn mk-map-state [state-type backing-map]
   (case state-type
@@ -35,5 +36,5 @@
         conn (cc/connect (s/split (get hambo-config conf/HAMBO-HOSTS) #",") {:keyspace keyspace})
         instrumented-map (backing-hof conn table)
         _ (.registerMetrics instrumented-map conf metrics prefix-name (int bucket-size))
-        cached-map (CachedMap. instrumented-map cache-size)]
+        cached-map (LRUCachedMap. instrumented-map cache-size)]
     (mk-map-state state-type cached-map)))


smart naming scheme for common stuff on home

--- frontend/components/landing-b.cljs
+++ frontend/components/landing-b.cljs
@@ -24,24 +24,24 @@
             controls-ch (om/get-shared owner [:comms :controls])]
         (html [:div.home.page
                [:section.home-prolog
-                [:a.prolog-action {:role "button"}
+                [:a.home-action {:role "button"}
                  "Sign Up Free"]
-                [:div.prolog-cover]
+                [:div.home-cover]
                 [:div.prolog-navigation
                  [:nav
                   [:a.promo "What is Continuous Integration?"]
                   [:a.login "Log In"]]]
-                [:div.prolog-logos
+                [:div.home-avatars
                  [:div.avatars
                   [:div.avatar-github
                    (common/ico :github)]
                   [:div.avatar-circle
                    (common/ico :logo)]]]
-                [:div.prolog-slogans
+                [:div.home-slogans
                  [:h1.slogan.proverb {:title "Your org needs a hero."
                                       :alt   "Let's just authorize first."}
                   "Your org needs a hero."]
-                 [:h3.slogan.context {:title "You have a product to focus on, let Circle handle your "
+                 [:h3.slogan.context {:title "You have a product to focus on, let Circle handle your"
                                       :alt   "Signing up using your GitHub login lets us start really fast."}
                   "You have a product to focus on, let Circle handle your"]
                  [:h3.slogan.context {:title "Continuous Integration & Deployment."
@@ -113,29 +113,29 @@
                  [:div.drawing]
                  (om/build drawings/drawing-build app)]]
                [:section.home-prolog
-                [:a.prolog-action {:role "button"}
+                [:a.home-action {:role "button"}
                  "Sign Up Free"]
-                [:div.prolog-cover]
+                [:div.home-cover]
                 [:div.prolog-navigation
                  [:nav
                   [:a.promo "What is Continuous Integration?"]
                   [:a.login "Log In"]]]
-                [:div.prolog-logos
+                [:div.home-avatars
                  [:div.avatars
                   [:div.avatar-github
                    (common/ico :github)]
                   [:div.avatar-circle
                    (common/ico :logo)]]]
-                [:div.prolog-slogans
+                [:div.home-slogans
                  [:h1.slogan.proverb {:title "Ready to start testing?"
                                       :alt   "Let's just authorize first."}
-                  "Your org needs a hero."]
-                 [:h3.slogan.context {:title "You have a product to focus on, let Circle handle your "
+                  "Ready to start testing?"]
+                 [:h3.slogan.context {:title "Next you'll just need to sign in using your GitHub account."
                                       :alt   "Signing up using your GitHub login lets us start really fast."}
-                  "You have a product to focus on, let Circle handle your"]
-                 [:h3.slogan.context {:title "Continuous Integration & Deployment."
+                  "Next you'll just need to sign in using your GitHub account."]
+                 [:h3.slogan.context {:title "Not convinced just yet? Try taking the full tour."
                                       :alt   "Currently, we must request permissions in bulk."}
-                  "Continuous Integration & Deployment."]]
+                  "Not convinced just yet? Try taking the full tour."]]
                 [:div.prolog-learn
                  [:a
                   "Learn more"


tighten up header cta

tighten up header cta

--- frontend/controllers/controls.cljs
+++ frontend/controllers/controls.cljs
@@ -935,7 +935,7 @@

-(defmethod control-event :home-technology-tab-selected
+(defmethod control-event :home-technology-tab-selected
   [target message {:keys [tab]} state]
   (assoc-in state state/selected-home-technology-tab-path tab))

@@ -1010,4 +1010,4 @@
     (.play (goog.fx.dom.Scroll. main
                          #js [(.-scrollLeft main) (.-scrollTop main)]
                          #js [(.-scrollLeft main) vh]
-                         200))))
+                         250))))


Forcing ':aggressive' mode with ':get'.

Forcing ':aggressive' mode with ':get'.

--- src/leiningen/ancient.clj
+++ src/leiningen/ancient.clj
@@ -111,7 +111,8 @@
   [project [_ package & args]]
   (if-not package
     (println "':get' expects a package to retrieve version information for.")
-    (let [settings (parse-cli args)
+    (let [settings (-> (parse-cli args)
+                     (assoc :aggressive true))
           {:keys [artifact-id group-id]} (dependency-map [package ""])
           artifact-str (str group-id "/" artifact-id)]
       (binding [*verbose* (:verbose settings)


move exceptional form-handling higher

move exceptional form-handling higher

--- src/babel/english/morphology.cljc
+++ src/babel/english/morphology.cljc
@@ -53,7 +53,7 @@

    (= word :top)
    ".."
-
+
    (and (map? word)
         (nil? (:a word))
         (nil? (:b word))
@@ -61,7 +61,13 @@
         (nil? (:english word)))
    ".."

-    (= (get-in word '(:infl)) :infinitive)
+   (and (= true (get-in word [:exception] false))
+        ;; for exceptions, lexical compilation sets [:exception] to true
+        ;; and the :english is the inflected irregular form which does not need further conjugation/inflection.
+        (string? (get-in word [:english])))
+   (get-in word [:english])
+
+   (= (get-in word '(:infl)) :infinitive)
     (if (string? (get-in word '(:english)))
       (str "to " (get-in word '(:english)))
       (exception (str "don't know how to find infinitive for word: " word)))
@@ -396,8 +402,7 @@
            (str stem-minus-one "ied")  ;; "try"->"tried"

            true
-           (str stem "ed"))) ;; "play"->"played"
-
+           (str stem "ed"))) ;; "play"->"played"
    (and
     (= :present (get-in word '(:infl)))
     (string? (get-in word '(:english))))
@@ -413,14 +418,10 @@
          stem (replace root #"^to " "")
          last-stem-char-is-e (re-find #"e$" stem)
          penultimate-stem-char-is-vowel (re-find #"[aeiou].$" stem)
-         last-stem-char-is-vowel (re-find #"[aeiou]$" stem)
-         exception? (get-in word [:exception] false)]
+         last-stem-char-is-vowel (re-find #"[aeiou]$" stem)]
      (log/debug "+else")
      (log/debug (str "(english):word: " word))
      (cond
-
-       exception? stem
-
       (and (= person :1st) (= number :sing)
            (string? (get-in word '(:present :1sing))))
       (get-in word '(:present :1sing))


use dummy reaction hack to fix tag view re-use

need to call :threads-for-tag when the tag page changes, but did-mount
only gets invoked once and other react lifecycle methods don't come into
play for ratoms; hacking around this by using a dummy reaction to call
dispatch!

--- src/braid/ui/views/pages/tag.cljs
+++ src/braid/ui/views/pages/tag.cljs
@@ -36,50 +36,47 @@
                                 (comp (partial apply max)
                                       (partial map :created-at)
                                       :messages))
-                              reverse))]
-    (r/create-class
-      {:component-did-mount
-       (fn []
-         ; TODO: need to do this when page-id changes, not just on mount!
-         (dispatch! :threads-for-tag {:tag-id @page-id}))
-       :reagent-render
-       (fn []
-         (let [status (cond
-                        @loading? :loading
-                        (not (contains? @page :thread-ids)) :searching
-                        (seq (@page :thread-ids)) :done-results
-                        :else :done-empty)]
-           [:div.page.channel
-            [:div.title
-             [tag-pill-view (@tag :id)]
-             [subscribe-button-view (@tag :id)]]
+                              reverse))
+        dummy (reaction (do (dispatch! :threads-for-tag {:tag-id @page-id})
+                            nil))]
+    (fn []
+      (let [status (cond
+                     @loading? :loading
+                     (not (contains? @page :thread-ids)) :searching
+                     (seq (@page :thread-ids)) :done-results
+                     :else :done-empty)
+            _ @dummy]
+        [:div.page.channel
+         [:div.title
+          [tag-pill-view (@tag :id)]
+          [subscribe-button-view (@tag :id)]]

-            [:div.content
-             [:div.description
-              [:p "One day, a tag description will be here."]
+         [:div.content
+          [:div.description
+           [:p "One day, a tag description will be here."]

-              [:div
-               (case status
-                 :searching "Searching..."
-                 :loading "Loading more..."
-                 :done-results (str "Done! Displaying " (count @sorted-threads)
-                                    " out of " (+ (count @sorted-threads) @pagination-remaining))
-                 :done-empty "No Results")]]]
+           [:div
+            (case status
+              :searching "Searching..."
+              :loading "Loading more..."
+              :done-results (str "Done! Displaying " (count @sorted-threads)
+                                 " out of " (+ (count @sorted-threads) @pagination-remaining))
+              :done-empty "No Results")]]]

-            [threads-view
-             {:new-thread-args {:tag-ids [(@tag :id)]}
-              :threads @sorted-threads
-              :threads-opts {:on-scroll ; page in more results as the user scrolls
-                             (fn [e]
-                               (let [div (.. e -target)]
-                                 (when (and (= status :done-results)
-                                         (> @pagination-remaining 0)
-                                         (> 100 (- (.-scrollWidth div)
-                                                   (+ (.-scrollLeft div) (.-offsetWidth div)))))
-                                   (start-loading!)
-                                   (dispatch! :threads-for-tag
-                                              {:tag-id @page-id
-                                               :offset (count @sorted-threads)
-                                               :on-complete
-                                               (fn []
-                                                 (stop-loading!))}))))}}]]))})))
+         [threads-view
+          {:new-thread-args {:tag-ids [(@tag :id)]}
+           :threads @sorted-threads
+           :threads-opts {:on-scroll ; page in more results as the user scrolls
+                          (fn [e]
+                            (let [div (.. e -target)]
+                              (when (and (= status :done-results)
+                                      (> @pagination-remaining 0)
+                                      (> 100 (- (.-scrollWidth div)
+                                                (+ (.-scrollLeft div) (.-offsetWidth div)))))
+                                (start-loading!)
+                                (dispatch! :threads-for-tag
+                                           {:tag-id @page-id
+                                            :offset (count @sorted-threads)
+                                            :on-complete
+                                            (fn []
+                                              (stop-loading!))}))))}}]]))))


Remove some errant code in core.clj

Remove some errant code in core.clj

--- src/lcmap/aardvark/core.clj
+++ src/lcmap/aardvark/core.clj
@@ -62,9 +62,6 @@
                   :search    {:index-url "http://elasticsearch:9200/tile-specs"
                               :max-result-size 10000}})

-(config/init default-cfg)
-(config/init (util/read-edn "lcmap.aardvark.edn"))
-
 (defn env-name->env-value
   "Replaces all string values with the matching environment variable."
   [nested-map]


simplify by using destructuring of language-model argument to (defn do-defaults)

--- src/babel/generate.cljc
+++ src/babel/generate.cljc
@@ -199,12 +199,16 @@
         (lazy-cat lexical phrasal)
         (lazy-cat phrasal lexical)))))

-(defn do-defaults [tree language-model]
-  (log/trace (str "calling do-defaults on tree:" ((:morph language-model) tree)))
-  (if-let [default-fn (:default-fn language-model)]
+(defn do-defaults [tree {default-fn :default-fn
+                         morph :morph}]
+  (if (not (fn? morph))
+    (throw (Exception. (str "(do-defaults) was unexpectedly called without a 'morph' function."))))
+
+  (log/trace (str "calling do-defaults on tree:" (morph tree)))
+  (if default-fn
     (let [result
           (default-fn tree)]
-      (log/trace (str "result of calling do-defaults on tree:" ((:morph language-model) result)))
+      (log/trace (str "result of calling do-defaults on tree:" (morph result)))
       result)
     ;;
     (do


Fix email on copyright notice on core.keys ns.

--- src/buddy/core/keys.clj
+++ src/buddy/core/keys.clj
@@ -1,4 +1,4 @@
-;; Copyright 2013-2015 Andrey Antukh <niwi@niwi.be>
+;; Copyright 2013-2015 Andrey Antukh <niwi@niwi.nz>
 ;;
 ;; Licensed under the Apache License, Version 2.0 (the "License")
 ;; you may not use this file except in compliance with the License.


fix docstring typo

fix docstring typo

--- src/buddy/core/keys.clj
+++ src/buddy/core/keys.clj
@@ -96,7 +96,7 @@
    (read-pem->privkey path passphrase)))

 (defn public-key
-  "Public key constrcutor from file path."
+  "Public key constructor from file path."
   [path]
   (read-pem->pubkey path))


Initial support for syncing complete stages where jobs are aggregated

--- src/buildviz/gosync.clj
+++ src/buildviz/gosync.clj
@@ -38,6 +38,10 @@
    ["-f" "--from DATE" "DATE from which on builds are loaded (by default tries to pick up where the last run finished)"
     :id :load-builds-from
     :parse-fn #(tf/parse date-formatter %)]
+   ["-s" "--aggregate PIPELINE" "PIPELINE for which a complete stage will be synced as a job"
+    :id :aggregate-jobs-for-pipelines
+    :default '()
+    :assoc-fn (fn [previous key val] (assoc previous key (conj (get previous key) val)))]
    ["-h" "--help"]])

 ;; util
@@ -80,8 +84,24 @@
   (let [build (get-json "/jobStatus.json?pipelineName=&stageName=&jobId=%s" jobId)]
     (parse-build-info build)))

+(defn accumulate-builds [builds]
+  (let [outcomes (map :outcome builds)
+        start-times (map :start builds)
+        end-times (map :end builds)]
+    {:start (apply min start-times)
+     :end (apply max end-times)
+     :outcome (if (every? #(= "pass" %) outcomes)
+                "pass"
+                "fail")}))
+
+(defn build-for-job [job-instance]
+  (if-let [jobs-for-accumulation (:jobs-for-accumulation job-instance)]
+    (let [builds (map build-for jobs-for-accumulation)]
+      (accumulate-builds builds))
+    (build-for job-instance)))
+
 (defn job-data-for-instance [jobInstance]
-  (assoc jobInstance :build (build-for jobInstance)))
+  (assoc jobInstance :build (build-for-job jobInstance)))

 ;; /api/stages/%pipeline/%stage/history
@@ -89,13 +109,31 @@
 (defn job-instances-for-stage-instance [{pipeline-run :pipeline_counter
                                          stage-run :counter
                                          jobs :jobs}]
-  (map (fn [{id :id name :name result :result scheduled-date :scheduled_date}]
+  (map (fn [{id :id name :name scheduled-date :scheduled_date}]
          {:jobId id
           :jobName name
           :stageRun stage-run
           :pipelineRun pipeline-run
           :scheduledDateTime (tc/from-long scheduled-date)})
        jobs))
+
+(defn job-instance-for-accumulated-stage-instance [{pipeline-run :pipeline_counter
+                                                    stage-run :counter
+                                                    jobs :jobs}]
+  (let [job-instances (map (fn [{id :id name :name}]
+                             {:jobId id :jobName name})
+                           jobs)]
+    {:jobId 0
+     :jobName "accumulated"
+     :stageRun stage-run
+     :pipelineRun pipeline-run
+     :scheduledDateTime (tc/from-long (apply min (map :scheduled_date jobs)))
+     :jobs-for-accumulation job-instances}))
+
+(defn fetch-job-instances-for-stage-instance [accumulate-stages-for-pipelines stage-name stage-instance]
+  (if (contains? accumulate-stages-for-pipelines stage-name)
+    (list (job-instance-for-accumulated-stage-instance stage-instance))
+    (job-instances-for-stage-instance stage-instance)))

 (defn get-stage-instances [pipeline stage-name offset]
   (let [stage-history (get-json "/api/stages/%s/%s/history/%s" pipeline stage-name offset)
@@ -109,11 +147,11 @@
 (defn fetch-all-stage-history [pipeline stage]
   (get-stage-instances pipeline stage 0))

-(defn job-instances-for-stage [load-builds-from {stage-name :stage pipeline :pipeline}]
+(defn job-instances-for-stage [load-builds-from accumulate-stages-for-pipelines {stage-name :stage pipeline :pipeline}]
   (let [safe-build-start-date (t/minus load-builds-from (t/millis 1))]
     (->> stage-name
          (fetch-all-stage-history pipeline)
-         (mapcat job-instances-for-stage-instance)
+         (mapcat (partial fetch-job-instances-for-stage-instance accumulate-stages-for-pipelines pipeline))
          (take-while #(t/after? (:scheduledDateTime %) safe-build-start-date))
          (map #(assoc % :stageName stage-name :pipelineName pipeline)))))

@@ -277,6 +315,7 @@
   (println "Go" go-url "-> buildviz" buildviz-url)

   (let [load-builds-from (get-start-date (:load-builds-from (:options args)))
+        accumulate-stages-for-pipelines (set (:aggregate-jobs-for-pipelines (:options args)))
         selected-pipeline-group-names (set (drop 1 (:arguments args)))
         pipeline-groups (get-pipeline-groups)
         selected-pipeline-groups (if (seq selected-pipeline-group-names)
@@ -284,12 +323,14 @@
                                    pipeline-groups)]
     (println "Looking at pipeline groups" (map :name selected-pipeline-groups))
     (println "Syncing all builds starting from" (tf/unparse (:date-time tf/formatters) load-builds-from))
+    (when (some? accumulate-stages-for-pipelines)
+      (println "Aggregating jobs for stages of" accumulate-stages-for-pipelines))

     (println "Finding all builds for syncing...")

     (let [builds-to-be-synced (->> selected-pipeline-groups
                                  (mapcat stages-for-pipeline-group)
-                                 (mapcat (partial job-instances-for-stage load-builds-from))
+                                 (mapcat (partial job-instances-for-stage load-builds-from accumulate-stages-for-pipelines))
                                  (sort-by :scheduledDateTime))]
     (println (format "Found %s builds to be synced, starting" (count builds-to-be-synced)))


exclude remove

exclude remove

--- src/clj/flambo/conf.clj
+++ src/clj/flambo/conf.clj
@@ -1,6 +1,6 @@
 (ns flambo.conf
   (:import [org.apache.spark SparkConf])
-  (:refer-clojure :exclude (set get contains)))
+  (:refer-clojure :exclude (set get contains remove)))

 ;; SparkConf functions


Improve translation

Improve translation

--- src/cljc/mdr2/i18n.cljc
+++ src/cljc/mdr2/i18n.cljc
@@ -125,14 +125,14 @@
                     :source_publisher "Verlag"
                     :description "Beschreibung"
                     :state "Status"
-                    :product_number "Produktnummer"
+                    :product_number "Produkt Nummer"
                     :library_number "DS Nummer"
                     :library_signature "Signatur"
                     :library_record_id "Record Id"
                     :total_time "Total Time"
                     :narrator "Sprecher"
                     :source_date "Source Date"
-                    :produced_date "Produktionsdatum"
+                    :produced_date "Datum der Produktion"
                     :language "Sprache"
                     :spelling "Rechtschreibung"
                     :date "Datum"


Fix metadata for `lightness`.

Fix metadata for `lightness`.

--- src/cljc/quil/core.cljc
+++ src/cljc/quil/core.cljc
@@ -2159,8 +2159,8 @@
    (defn
      ^{:requires-bindings true
        :processing-name "lightness()"
-       :category nil
-       :subcategory nil
+       :category "Color"
+       :subcategory "Creating & Reading"
        :added "3.0.0"}
      lightness
      "Extracts the HSL lightness value from a color or pixel array."


Added number? #34

Added number? #34

--- src/cljs/cljs/core.cljs
+++ src/cljs/cljs/core.cljs
@@ -143,6 +143,9 @@
 (defn symbol? [x]
   (and (goog/isString x)
        (= (.charAt x 0) \uFDD1)))
+
+(defn number? [n]
+  (goog/isNumber n))

 (defn fn? [f]
   (goog/isFunction f))


* src/cljs/cljs/core.cljs: use satisfies? in nth and reduce. reducible? -> reduceable?

--- src/cljs/cljs/core.cljs
+++ src/cljs/cljs/core.cljs
@@ -635,11 +635,11 @@
   also works for strings, arrays, regex Matchers and Lists, and,
   in O(n) time, for sequences."
   ([coll n]
-     (if (indexed? coll)
+     (if (satisfies? IIndexed coll)
        (-nth coll (.floor js/Math n))
        (linear-traversal-nth coll (.floor js/Math n))))
   ([coll n not-found]
-     (if (indexed? coll)
+     (if (satisfies? IIndexed coll)
        (-nth coll (.floor js/Math n) not-found)
        (linear-traversal-nth coll (.floor js/Math n) not-found))))

@@ -750,7 +750,7 @@
   "Returns true if coll implements nth in constant time"
   [x] (satisfies? IIndexed x))

-(defn ^boolean reducible?
+(defn ^boolean reduceable?
   "Returns true if coll satisfies IReduce"
   [x] (satisfies? IReduce x))

@@ -973,11 +973,11 @@
   applying f to that result and the 2nd item, etc. If coll contains no
   items, returns val and f is not called."
   ([f coll]
-     (if (reducible? coll)
+     (if (satisfies? IReduce coll)
        (-reduce coll f)
        (seq-reduce f coll)))
   ([f val coll]
-     (if (reducible? coll)
+     (if (satisfies? IReduce coll)
        (-reduce coll f val)
        (seq-reduce f val coll))))


Oops, left off a paren. Refs #22

Oops, left off a paren. Refs #22

--- src/cljs/cljs/core.cljs
+++ src/cljs/cljs/core.cljs
@@ -798,7 +798,7 @@
   IIndexed
   (-nth
     ([array n]
-       if (< n (-count array)) (aget array n))
+       (if (< n (-count array)) (aget array n)))
     ([array n not_found]
        (if (< n (-count array)) (aget array n)
            not_found)))


Distinguish between text/plain and text/html output.

--- src/clouseau/server.clj
+++ src/clouseau/server.clj
@@ -467,9 +467,14 @@
           products-with-descriptions    (get-products-with-descriptions products/products package-descriptions)
           products-per-description      (get-products-per-description package-descriptions products-with-descriptions)
           user-name                     (get-user-name new-user-name old-user-name)]
-          (cond (not ccs-description)                (generate-error-response package user-name "Can not read from the database file 'ccs_descriptions.db'!")
-                (package-error package-descriptions) (generate-error-response package user-name (generate-error-message-package-db-error package-descriptions))
-                :else                                (generate-normal-response products/products package package-descriptions ccs-description products-per-description products-without-descriptions new-description user-name))))
+          (condp = output-format
+              "html" (cond (not ccs-description)                (generate-error-response package user-name "Can not read from the database file 'ccs_descriptions.db'!")
+                           (package-error package-descriptions) (generate-error-response package user-name (generate-error-message-package-db-error package-descriptions))
+                           :else                                (generate-normal-response products/products package package-descriptions ccs-description products-per-description products-without-descriptions new-description user-name))
+              "txt"  (cond (not ccs-description)                (generate-txt-error-response package user-name "Can not read from the database file 'ccs_descriptions.db'!")
+                           (package-error package-descriptions) (generate-txt-error-response package user-name (generate-error-message-package-db-error package-descriptions))
+                           :else                                (generate-txt-normal-response products/products package package-descriptions ccs-description products-per-description products-without-descriptions new-description user-name))
+)))

 (defn perform-normal-processing
     [request]


Last point for moves. Wrong realization of 'summary' table. Need reformat.

--- src/ombs/handler/handle.clj
+++ src/ombs/handler/handle.clj
@@ -25,13 +25,13 @@
     (redirect "/"))
   )

-(defn pay [{ename :event-name date :date price :price }]
+(defn pay [{ename :event-name date :date debt :debt :as params}]
   "Add participation of current user and selected event(given as param from post)"
   (let [uname (sess/get :username)
         uid (db/get-uid uname)
         eid (db/get-eid ename date)]
     (if (isvalid/stake? eid uid)
-      (db/debit-payment eid uid price)
+      (str "u:"uid " e:"eid " gonna pay " (db/get-debit uid eid))
       "validation fails."
       )


Remove debugging statement.

Remove debugging statement.

--- src/onyx/peer/transform.clj
+++ src/onyx/peer/transform.clj
@@ -84,8 +84,7 @@
   [event] (write-batch-shim event))

 (defmethod p-ext/close-pipeline-resources :default
-  [event]
-  (info "[Transformer] Closing pipeline injections"))
+  [event] {})

 (with-post-hook! #'read-batch-shim
   (fn [{:keys [batch consumers]}]


Reduce chance of race condition in :done handling

--- src/onyx/plugin/datomic.clj
+++ src/onyx/plugin/datomic.clj
@@ -328,6 +328,7 @@
         (swap! pending-messages assoc (:id m) m))
       (when (and (all-done? (vals @pending-messages))
                  (all-done? batch)
+                 (zero? (count (.buf read-ch)))
                  (or (not (empty? @pending-messages))
                      (not (empty? batch))))
         (when-not (:checkpoint/key (:onyx.core/task-map event))


handle exceptions generated in on-latest-event hander-fns similar to how other event-hander fns are handled.

--- src/overtone/libs/event.clj
+++ src/overtone/libs/event.clj
@@ -123,8 +123,14 @@
   event is all that matters."
   [event-type handler key]
   (log-event "Registering lossy event handler:: " event-type " with key:" key)
-  (let [worker (lossy-worker (fn [val]
-                               (handler val)))
+  (let [worker (lossy-worker (fn [event-map]
+                               (try
+                                 (handler event-map)
+                                 (catch Exception e
+                                   (log/error "Handler Exception - with event-map: "
+                                              event-map
+                                              "\n"
+                                              (with-out-str (.printStackTrace e)))))))
         [old _] (swap-returning-prev! lossy-workers* assoc key worker)]
     (when-let [old-worker (get old key)]
       (.put (:queue old-worker) :die))


added fix-file-names

added fix-file-names

--- src/publisher/date_copy.clj
+++ src/publisher/date_copy.clj
@@ -6,6 +6,7 @@
            [java.util Calendar Date]
            [java.net URLEncoder URLDecoder]))

+(def files-directory "files")

 (defn files-in-directory [directory-path]
   (reduce (fn [files file] (if (.isDirectory file)
@@ -23,13 +24,27 @@
   (let [dates (reduce (fn [dates file]
                         (assoc dates (relative-path file)  (core/last-modified-date file)))
                       {}
-                      (files-in-directory "files"))]
+                      (files-in-directory files-directory))]
     (spit "dates.clj" dates)))
+
+(defn fix-directory-names []
+  (doseq [file (.listFiles (File. files-directory))]
+    (let [new-file (File. (core/fix-file-name (.getPath file)))]
+      (.renameTo file new-file))))
+
+(defn fix-file-names []
+  (fix-directory-names)
+  (doseq [file (files-in-directory files-directory)]
+    (let [new-name (core/fix-file-name (.getPath file))
+          {:keys [year month day]} (core/last-modified-date file)]
+      (.renameTo file (File. new-name))
+      (.setLastModified (File. new-name) (.getTime (Date. (- year 1900) (- month 1) day)))
+      #_(println "fixed"  new-name))))

 (defn set-dates []
   (let [dates (read-string (slurp "dates.clj"))]
     (doseq [path (keys dates)]
       (let [{:keys [year month day]} (get dates path)]
-        (.setLastModified (File. (str "files/" path)) (.getTime (Date. (- year 1900) (- month 1) day)))))))
+        (.setLastModified (File. (str files-directory "/" path)) (.getTime (Date. (- year 1900) (- month 1) day)))))))


continue with beat after figwheel reload

--- src/metronome/core.cljs
+++ src/metronome/core.cljs
@@ -8,37 +8,36 @@
   (do
     (enable-console-print!)))

-(defonce app-state (atom {:bpm  {:bpm nil}}))
+(defonce app-state (atom {:bpm {}}))

 (defn clock [bpm owner]
   (letfn [(start-interval [millis]
-            (om/set-state! owner :interval millis)
-            (om/set-state! owner :next-beat nil))]
+            (om/update! bpm :interval millis)
+            (om/update! bpm :next-beat nil))]
     (reify
       om/IInitState
-      (init-state [_] {:interval nil})
-
+      (init-state [_] {:mounted false})
       om/IDidMount
       (did-mount [_]
+                 (om/set-state! owner :mounted true)
                  (.requestAnimationFrame
                    js/window
                    (fn cb [t]
-                     (let [interval (om/get-state owner :interval)]
+                     (let [{:keys [interval next-beat]} @bpm]
                        (when interval
-                         (let [next-beat (om/get-state owner :next-beat)
-                               do-beat   (or (nil? next-beat) (> t next-beat))]
+                         (let [do-beat   (or (nil? next-beat) (> t next-beat))]
                            (when do-beat
                              (put! (om/get-state owner :sound-channel) true)
-                             (om/set-state! owner :next-beat (+ t interval))))))
-                     (.requestAnimationFrame js/window cb)))
-                 (let [interval-millis (:get bpm)
-                       click-channel   (om/get-state owner :click-channel)]
-                   (when-not (nil? interval-millis) (start-interval interval-millis))
+                             (om/update! bpm :next-beat (+ t interval))))))
+                     (when (om/get-state owner :mounted)
+                       (.requestAnimationFrame js/window cb))))
+                 (let [click-channel (om/get-state owner :click-channel)]
                    (go (loop []
                          (let [new-interval-millis (<! click-channel)]
                            (start-interval new-interval-millis)
                            (recur))))))
-
+      om/IWillUnmount
+      (will-unmount [_] (om/set-state! owner :mounted false))
       om/IRender
       (render [_] (dom/span nil)))))


Whitespace

Whitespace

--- src/onyx/http_query.clj
+++ src/onyx/http_query.clj
@@ -214,9 +214,6 @@
             (let [job-id (get-param request "job-id" :uuid)
                   task-id (get-param request "task-id" :keyword)]
               (jq/task-information log job-id task-id)))))}})
-
-
-

 (def serializers
   {"application/edn" pr-str


Fix: job would complete with non-empty read-ch

--- src/onyx/plugin/sql.clj
+++ src/onyx/plugin/sql.clj
@@ -104,6 +104,7 @@
         (swap! pending-messages assoc (:id m) m))
       (when (and (= 1 (count @pending-messages))
                  (= (count batch) 1)
+                 (zero? (count (.buf read-ch)))
                  (= (:message (first batch)) :done))
         (reset! drained? true))
       {:onyx.core/batch batch}))
@@ -249,4 +250,4 @@

 (def upsert-rows-calls
   {:lifecycle/before-task-start inject-upsert-rows
-   :lifecycle/after-task-stop close-update-rows})+   :lifecycle/after-task-stop close-update-rows})


about us update in progress

about us update in progress

--- src/prais2/content.cljc
+++ src/prais2/content.cljc
@@ -7,6 +7,17 @@
 ;;;
 (defn get-mugshots []
   ["christina" "david" "tim" "emily B" "mike" "emily J" "joanne"])
+
+(defn get-mugshots-meta []
+  [:rows
+   [:row {:id "christina" :name "Christina" :org "UCL"}]
+   [:row {:id "david" :name "David" :org "Camb"}
+    {:id "mike" :name "Mike" :org "Camb"}]
+   [:row {:id "tim" :name "Tim" :org "KCL"}
+    {:id "emily B" :name "Emily Blackshaw" :org "KCL"}]
+   [:row {:id "emily J" :name "Emily Jesper" :org "SAS"}
+    {:id "joanne" :name "Joanne Thomas" :org "SAS"}]]
+  )

 ;;;
 ;; table structure
@@ -980,8 +991,8 @@
                :body     [:div
                           [:.image-para
                            [:p [:img.pull-left.w150 (core/isrc "assets/ucl-logo-black.png")]
-                            [:a (core/href "http://ucl.ac.uk/coru") "University College London"] ": "
-                            [:a (core/href "http://www.ucl.ac.uk/operational-research/the_team/#christina") "Dr Christina Pagel"]
+                            [:a (core/href "http://ucl.ac.uk/coru" :target "_blank") "University College London"] ": "
+                            [:a (core/href "http://www.ucl.ac.uk/operational-research/the_team/#christina" :target "_blank") "Dr Christina Pagel"]
                             " is a Reader in Operational Research (a branch of applied mathematics) at University College London, applying
                             maths to problems in the NHS. She works very closely with doctors and other clinical staff, mainly at Great
                             Ormond Street Hospital, to help them use routinely collected data to improve NHS services. Her work currently
@@ -993,21 +1004,23 @@
         about Science, the University of Cambridge, King’s College London and the Children’s Heart Federation to develop
         these online resources to help people interpret the audit body’s published results. In particular, she wrote a
         lot of the content, helped enormously by feedback from the team and the user workshops. Thanks to "
-                            [:a (core/href " http://www.ucl.ac.uk/operational-research/the_team/#andrew") " Dr Andrew Wilshere"] " for designing our logo. "]]
+                            [:a (core/href " http://www.ucl.ac.uk/operational-research/the_team/#andrew" :target "_blank") " Dr Andrew Wilshere"] " for designing our logo. "]]

                           [:.image-para
                            [:p [:img.pull-left.w150 (core/isrc "assets/camlogo-old.png")]
-                            [:a (core/href "http://understandinguncertainty.org") "Professor David Spiegelhalter"]
+                            [:a (core/href "http://understandinguncertainty.org" :target "_blank") "Professor David Spiegelhalter"]
                             " is a statistician from Cambridge University.   He has worked for many years with doctors from Great Ormond
                             Street Hospital on monitoring outcomes following surgery for congenital heart disease, and led the statistical
                             team at the Bristol Royal Infirmary Inquiry.  He is particularly interested in transparent communication, and
                             was part of the team that drew up the new national patient information leaflets for breast cancer screening.
                             For this project, David helped write the content, especially the language around the statistical formula and
-                            predicted range.  "
-                            [:a (core/href "http://understandinguncertainty.org") "Mike Pearson"] " has created many mathematics teaching interactives
-                            for " [:a (core/href "http://nrich.maths.org") "NRICH"] ", " [:a (core/href "http://plus.maths.org") "PLUS"] ", and
-                            " [:a (core/href "https://understandinguncertainty.org") "Understanding Uncertainty"] ". He developed this website and its
-                            data visualisations, working closely with the animation team, "
+                            predicted range.  "]
+                           [:p
+                            [:a (core/href "http://nrich.maths.org/2714" :target "_blank") "Mike Pearson"] " has created many visualisations and interactives
+                            for " [:a (core/href "http://understandinguncertainty.org/" :target "_blank") "Understanding Uncertainty"] ", "
+                            [:a (core/href "http://nrich.maths.org" :target "_blank") "NRICH"] ", " [:a (core/href "http://plus.maths.org" :target "_blank") "PLUS"] ", and
+                            " [:a (core/href "http://wild.maths.org") "Wild.maths.org"] ". He developed this website and its
+                            data visualisations, attending the focus groups and working closely with Sense about Science and the video animation team, "
                             [:a (core/href "https://qudos.com" :target "_blank") "Qudos"] "."]]

                           [:.image-para


streams/scale: docstring example

streams/scale: docstring example

--- src/riemann/streams.clj
+++ src/riemann/streams.clj
@@ -1212,7 +1212,10 @@

 (defn scale
   "Passes on a changed version of each event by multiplying each
-   metric with the input scale factor"
+   metric with the given scale factor.
+
+  ; Convert bytes to kilobytes
+  (scale 1/1024 index)"
   [factor & children]
   (let [scale-event (fn [{:keys [metric] :as event}]
                       (assoc event :metric


Fix percentiles documentation for correct name

The current percentiles documentation suggest that the service name is changed like so:

    resource name

becomes

    resource name .95

In reality it becomes:

    resource name 0.95

This change updates the docs to reflect reality.

--- src/riemann/streams.clj
+++ src/riemann/streams.clj
@@ -860,7 +860,7 @@
   event.  If point is 1, takes the highest metric event. 0.5 is the median
   event, and so forth. Forwards each of these events to children. The service
   name has the point appended to it; e.g. 'response time' becomes 'response
-  time .95'."
+  time 0.95'."
   [interval points & children]
   (part-time-fast interval
                 (fn setup [] (atom []))


template: version 0.25.0

template: version 0.25.0

--- template/project.clj
+++ template/project.clj
@@ -1,4 +1,4 @@
-(defproject swagger1st/lein-template "0.25.0-SNAPSHOT"
+(defproject swagger1st/lein-template "0.25.0"
   :description "Leiningen template for creating a swagger1st app."
   :url "https://github.com/zalando/swagger1st"


Fix runner seeing "Take Clicks" when corp is at "Mandatory Draw".

--- src/cljs/netrunner/gameboard.cljs
+++ src/cljs/netrunner/gameboard.cljs
@@ -873,7 +873,7 @@
                                [:button {:on-click #(handle-end-turn cursor owner)} "End Turn"])
                          (when end-turn
                            [:button {:on-click #(send-command "start-turn")} "Start Turn"]))
-                       (when (and (= (keyword active-player side))
+                       (when (and (= (keyword active-player) side)
                                   (or runner-phase-12 corp-phase-12))
                            [:button {:on-click #(send-command "end-phase-12")}
                             (if (= side :corp) "Mandatory Draw" "Take Clicks")])


fixed issue in gamelobby

fixed issue in gamelobby

--- src/cljs/netrunner/gamelobby.cljs
+++ src/cljs/netrunner/gamelobby.cljs
@@ -50,6 +50,7 @@
 (defn join-game [gameid owner]
   (authenticated
    (fn [user]
+     (om/set-state! owner :editing false)
      (send {:action "join" :gameid gameid}))))

 (defn leave-game [cursor owner]


Run paren mode on paste

Run paren mode on paste

--- src/clojure/nightcode/editors.clj
+++ src/clojure/nightcode/editors.clj
@@ -408,6 +408,12 @@
                      (get-indent-state text-area (.isShiftDown e))
                      :else
                      (get-parinfer-state text-area false))
+                   (refresh-content! text-area)
+                   (mwm/update-edit-history! edit-history))
+
+              (and (or (.isControlDown e) (.isMetaDown e))
+                (= (.getKeyCode e) KeyEvent/VK_V))
+              (->> (get-parinfer-state text-area true)
                    (refresh-content! text-area)
                    (mwm/update-edit-history! edit-history))))
           (keyTyped [this e] nil)
@@ -612,10 +618,6 @@
       ; initialize parinfer
       (init-parinfer! text-area extension edit-history true)
       (update-buttons! editor-pane text-area)
-      ; update buttons every time a key is typed
-      (s/listen text-area
-                :key-released
-                (fn [e] (update-buttons! editor-pane text-area)))
       ; return a map describing the editor
       {:view editor-pane
        :text-area text-area


Deal with no cookies properly

Deal with no cookies properly

--- src/mars_ogler/routes.clj
+++ src/mars_ogler/routes.clj
@@ -12,9 +12,15 @@
                          params]))

 (defn parse-cookie-params
-  [{cams "cams", per-page "per-page", sorting "sorting", thumbs "thumbs"}]
-  {:cams (str/split (:value cams) #" "), :per-page (:value per-page)
-   :sorting (:value sorting), :thumbs (:value thumbs)})
+  [cookie-params]
+  (let [kw->sk {:cams "cams", :per-page "per-page", :sorting "sorting"
+                :thumbs "thumbs"}]
+    (into {} (->> (for [[kw sk] kw->sk]
+                    (if-let [v (get-in cookie-params [sk :value])]
+                      (if (= kw :cams)
+                        [kw (str/split v #" ")]
+                        [kw v])))
+               (keep identity)))))

 (defn parse-params
   [{:keys [cams page per-page sorting thumbs query-string]


Use `subject` instead of `bus` on workers ns.

--- frontend/src/uxbox/util/workers.cljs
+++ frontend/src/uxbox/util/workers.cljs
@@ -41,7 +41,7 @@
   "Return a initialized webworker instance."
   [path]
   (let [wrk (js/Worker. path)
-        bus (rx/bus)]
+        bus (rx/subject)]
     (.addEventListener wrk "message"
                        (fn [event]
                          (let [data (.-data event)


fix serialisation

fix serialisation

--- dada-core/src/main/clojure/org/dada/core/JoinModel.clj
+++ dada-core/src/main/clojure/org/dada/core/JoinModel.clj
@@ -11,6 +11,7 @@
    :extends org.dada.core.AbstractModel
    :implements [org.dada.core.ModelView java.io.Serializable]
    :constructors {[String org.dada.core.Metadata org.dada.core.Model java.util.Map clojure.lang.IFn] [String org.dada.core.Metadata]}
+   :methods [[writeReplace [] Object]]
    :init init
    :state state
    :post-init post-init)
@@ -313,5 +314,5 @@
 ;; compound key join ?

 (defn #^{:private true} -writeReplace [#^org.dada.core.JoinModel this]
-  (let [[[_mutable name metadata]] (.state this)]
+  (let [[_mutable name metadata] (.state this)]
       (RemoteModel. name metadata)))


Don't enforce specific 'display' property on backend. Resolves #2205

--- src/metabase/api/card.clj
+++ src/metabase/api/card.clj
@@ -15,11 +15,6 @@
   "Option must be one of `all`, `mine`, or `fav`."
   [symb value :nillable]
   (checkp-contains? #{:all :mine :fav :database :table} symb (keyword value)))
-
-(defannotation CardDisplayType
-  "Option must be a valid `display_type`."
-  [symb value :nillable]
-  (checkp-contains? card/display-types symb (keyword value)))

 (defendpoint GET "/"
   "Get all the `Cards`. With param `f` (default is `all`), restrict cards as follows:
@@ -60,7 +55,7 @@
   [:as {{:keys [dataset_query description display name public_perms visualization_settings]} :body}]
   {name         [Required NonEmptyString]
    public_perms [Required PublicPerms]
-   display      [Required CardDisplayType]}
+   display      [Required NonEmptyString]}
   (->> (ins Card
             :creator_id             *current-user-id*
             :dataset_query          dataset_query
@@ -86,7 +81,7 @@
   [id :as {{:keys [dataset_query description display name public_perms visualization_settings]} :body}]
   {name         NonEmptyString
    public_perms PublicPerms
-   display      CardDisplayType}
+   display      NonEmptyString}
   (write-check Card id)
   (upd-non-nil-keys Card id
                     :dataset_query dataset_query


IO and scheduler helper functions have been added to component ns

--- core/src/cljc/hellhound/component.cljc
+++ core/src/cljc/hellhound/component.cljc
@@ -50,7 +50,8 @@
   (:require
    [hellhound.streams :as streams]
    [hellhound.components.protocols :as impl]
-   [hellhound.components.impl.persistent-map :as component-impl]))
+   [hellhound.components.impl.persistent-map :as component-impl]
+   [hellhound.logger :as logger]))

 ;; Public Functions ----------------------------------------
@@ -113,7 +114,6 @@
       :hellhound.component/stop-fn    hellhound.components.defaults/stop-fn
       :hellhound.component/depends-on []
       :hellhound.component/fn         ~(list* `fn body)}))
-

 (defn make-transformer
   [component-name f]
@@ -126,7 +126,7 @@
      (streams/consume
       (fn [v]
         (let [processed-v (f component v)]
-          (when processed-v
+          (if processed-v
             (streams/>> (output component) processed-v))))
       (input component)))})

@@ -173,6 +173,7 @@
           (hellhound.component/input component#))))}))

+;; IO helpers ----------------------------------------------
 (defn io
   "Returns a vector containing the IO streams of the given `component`.

@@ -204,3 +205,23 @@
            streams/<<!
            streams/>>!
            f))
+
+
+(defn ->output
+  [component v]
+  (let [[_ out] (io component)]
+    (streams/>> out v)))
+
+
+(defn ->output!
+  [component v]
+  (let [[_ out] (io component)]
+    (streams/>>! out v)))
+
+
+;; IO & Execution helpers ----------------------------------
+(defn scheduled-output
+  [component delay f]
+  (let [[_ out] (io component)]
+    (async/schedule-fixedrate-interval delay
+                                       #(>> out (f)))))


Use 30 days instead of 10 as last activity filter.

--- src/oc/storage/config.clj
+++ src/oc/storage/config.clj
@@ -106,4 +106,4 @@
     :table-prefix dynamodb-table-prefix
   })

-(defonce inbox-days-limit (or (env :inbox-days-limit) 10))+(defonce inbox-days-limit (or (env :inbox-days-limit) 30))


Correct local reference missed in refactoring

--- src/papadom/template.cljs
+++ src/papadom/template.cljs
@@ -117,7 +117,7 @@
                       (wrap-control ctrl t-prop)
                       (attr ctrl "checked" "")))
           "SELECT" (let [option ($ "option" ctrl)]
-                     (doseq [e extra]
+                     (doseq [e (rest option)]
                        (jq/remove ($ e)))
                      (html option "{{label}}")
                      (attr option "value" "{{value}}")


Prevent empty conditions from forming query

return empty collection from mget for edge cases of conds such as [{}]

--- src/poky/kv/jdbc/util.clj
+++ src/poky/kv/jdbc/util.clj
@@ -129,7 +129,7 @@
   Entries with keys that doesn't map to a truthy value are excluded (ie sanitization).
   TODO: Add ability to specify comparison operator"
   [m cols]
-  (let [xs (for [[k v] m :let [col (cols k)] :when col] [(str col "=?") v])]
+  (if-let [xs (seq (for [[k v] m :let [col (cols k)] :when col] [(str col "=?") v]))]
     (cons (string/join " AND " (map first xs))
           (mapcat rest xs))))

@@ -140,7 +140,7 @@
   form the query partial.
   Retuns a tuple of [query-partial query-partial-params]"
   [products cols]
-  (let [xs (map #(product-query-and-vals % cols) products)]
+  (if-let [xs (seq (filter identity (map #(product-query-and-vals % cols) products)))]
     [(string/join " OR " (map #(str "(" (first %) ")") xs))
      (mapcat rest xs)]))


SC Book, 3.4

SC Book, 3.4

--- docs/sc-book/sc-three.clj
+++ docs/sc-book/sc-three.clj
@@ -21,13 +21,13 @@
              (linen:kr gate 0.01 0.7 0.3 2))]
     (offset-out out (pan2 z pan amp))))

+(defn release
+  ([x releaseTime] (ctl x :gate (- releaseTime)))
+  ([x] (release x 0.0)))
+
 (defn wait-release
   ([x releaseTime] (if @x (release @x releaseTime) (recur x releaseTime)))
   ([x] (wait-release x 0.0)))
-
-(defn release
-  ([x releaseTime] (ctl x :gate (- releaseTime)))
-  ([x] (release x 0.0)))

 (defn generator [& thunks]
   (let [r (agent thunks)]
@@ -171,3 +171,47 @@
 (go)
 (go)
 (go)
+
+;; Page 89
+///////////////////////////////////////////////////////////////
+// Figure 3.4 Using patterns within a task
+(comment
+(// random notes from lydian b7 scale
+p = Pxrand([64, 66, 68, 70, 71, 73, 74, 76], inf).asStream;
+// ordered sequence of durations
+q = Pseq([1, 2, 0.5], inf).asStream;
+t = Task({
+        loop({
+                x.release(2);
+                x = Synth(\default, [freq: p.value.midicps]);
+                q.value.wait;
+        });
+});
+t.start;
+)
+t.stop; x.release(2);
+)
+
+(do
+  (def p (cycle [64 66 68 70 71 73 74 76]))
+  (def q (cycle [1000 2000 500]))
+
+  (def cont (atom true))
+  (def x (atom nil))
+
+  (defn task [p q]
+    (when @x (release @x 2))
+    (when @cont
+      (reset! x (s :freq (midi->hz (first p))))
+      (apply-at
+       (+ (now) (first q))
+       #'task (rest p) (rest q) [])))
+
+  (defn start-task []
+    (task p q))
+
+  (defn stop-task []
+    (reset! cont false))
+)
+(start-task)
+(stop-task)


Add better timeout helpers

Add better timeout helpers

--- src/promesa/exec/csp.cljc
+++ src/promesa/exec/csp.cljc
@@ -112,6 +112,34 @@
      (pt/-take! port h)
      (deref (p/finally d (fn [_ _] (p/cancel! t)))))))

+(defn alts
+  ([ports] (alts ports {}))
+  ([ports {:keys [priority]}]
+   (let [ret     (p/deferred)
+         lock    (channel/promise->handler ret)
+         ports   (if priority ports (shuffle ports))
+         handler (fn [port]
+                   (reify
+                     pt/ILock
+                     (-lock! [_] (pt/-lock! lock))
+                     (-unlock! [_] (pt/-unlock! lock))
+
+                     pt/IHandler
+                     (-active? [_] (pt/-active? lock))
+                     (-blockable? [_] (pt/-blockable? lock))
+                     (-commit! [_]
+                       (when-let [f (pt/-commit! lock)]
+                         (fn [val]
+                           (f [val port]))))))]
+     (loop [ports (seq ports)]
+       (when-let [port (first ports)]
+         (if (vector? port)
+           (let [[port val] port]
+             (pt/-put! port val (handler port)))
+           (pt/-take! port (handler port)))
+         (recur (rest ports))))
+     ret)))
+
 (defn alts!
   "Completes at most one of several operations on channel. Receives a
   vector of operations and optional keyword options.
@@ -125,30 +153,8 @@
   operation is ready to a vector [val channel] where val is return
   value of the operation and channel identifies the channel where the
   the operation is succeeded."
-  [ports & {:keys [priority]}]
-  (let [ret     (p/deferred)
-        lock    (channel/promise->handler ret)
-        ports   (if priority ports (shuffle ports))
-        handler (fn [port]
-                  (reify
-                    pt/ILock
-                    (-lock! [_] (pt/-lock! lock))
-                    (-unlock! [_] (pt/-unlock! lock))
-
-                    pt/IHandler
-                    (-active? [_] (pt/-active? lock))
-                    (-blockable? [_] (pt/-blockable? lock))
-                    (-commit! [_]
-                      (when-let [f (pt/-commit! lock)]
-                        (fn [val]
-                          (f [val port]))))))]
-    (loop [ports (seq ports)]
-      (when-let [[op port val] (first ports)]
-        (case op
-          (:> :put)  (pt/-put! port val (handler port))
-          (:< :take) (pt/-take! port (handler port)))
-        (recur (rest ports))))
-    ret))
+  [ports & {:as opts}]
+  (deref (alts ports opts)))

 (defn close!
   "Close the channel."
@@ -161,7 +167,12 @@
   [port]
   (pt/-closed? port))

-(defn timeout
+(defn sleep
+  "Turn the current thread to sleep."
+  [ms]
+  (Thread/sleep (int ms)))
+
+(defn timeout-chan
   "Returns a channel that will be closed in the specified timeout. The
   default scheduler will be used. You can provide your own as optional
   first argument."
@@ -173,6 +184,13 @@
    (let [ch (chan)]
      (px/schedule! scheduler ms #(pt/-close! ch))
      ch)))
+
+(defn timeout
+  "Returns a promise that will be resolved in the specified timeout. The
+  default scheduler will be used. You can provide your own as optional
+  first argument."
+  [ms]
+  (go (Thread/sleep (int ms))))

 (defn slidding-buffer
   "Create a slidding buffer instance."


Make the registered websocket URI configurable. Port may differ when connecting through a proxy.

--- src/pubsure_ws/source.clj
+++ src/pubsure_ws/source.clj
@@ -147,8 +147,8 @@
   :port - The port number where the server will bind to. Default is
   8090.

-  :hostname - The hostname to use in the ws:// URI as registered in
-  the directory service. Default is system hostname.
+  :uri - The websocket URI to be registered in the directory service.
+  Default is `ws://system-hostname:port`.

   :cache-size - The number of last published messages kept for each
   topic. This cache can be received through WAMP RPC. Default is 0.
@@ -179,13 +179,12 @@
   Default is `(constantly true)`.

   Returns the source state record, used for `stop-source`."
-  [directory-writer & {:keys [port hostname cache-size summary-fn wrap-fn]
+  [directory-writer & {:keys [port uri cache-size summary-fn wrap-fn]
                        :or {port 8090
-                            cache-size 0
-                            hostname (. (InetAddress/getLocalHost) getHostName)}
+                            cache-size 0}
                        :as config}]
   (info "Starting websocket source with directory writer" directory-writer "and config" config)
-  (let [uri (URI. (str "ws://" hostname ":" port))
+  (let [uri (or uri (URI. (str "ws://" (. (InetAddress/getLocalHost) getHostName) ":" port)))
         stop-fn (atom nil)
         config (assoc config :cache-size cache-size)
         source (WebsocketSource. directory-writer stop-fn (atom true) (ref #{}) (atom {}) uri


Tag alias expressions with alias names.

Tag alias expressions with alias names.

--- src/smallex/parser/smlx.clj
+++ src/smallex/parser/smlx.clj
@@ -45,11 +45,16 @@
   (if (some #(contains? % (:value name-item)) (vals grammar))
     (throw (ex-info "Definition already exists." name-item))
     (let [[rem-seq expr] (end-paren parse-expr item-seq)
-          ;; Tag priority on rules (the lower, the more prioritised)
-          expr-with-meta (if (= (:type definition-type) :def)
-                           (vary-meta expr assoc
-                                      :priority (count (:rules grammar)))
-                           expr)
+          ;; Tag priority on rules (the lower, the more prioritised), along with
+          ;; name of alias expansions.
+          expr-with-meta (cond-> expr
+                                 (= (:type definition-type) :def)
+                                 (vary-meta assoc
+                                            :priority (count (:rules grammar)))
+                                 (= (:type definition-type) :alias)
+                                 (vary-meta assoc
+                                            :alias-expansion true
+                                            :alias-name (:value name-item)))
           updated-grammar (assoc-in grammar [(grammar-key definition-type)
                                              (:value name-item)] expr-with-meta)]
       [rem-seq updated-grammar])))


Delete .#core.cljs

Delete .#core.cljs


CMR-1950: Added :ignore-conflicts false to update-index

--- index-set-app/src/cmr/index_set/data/elasticsearch.clj
+++ index-set-app/src/cmr/index_set/data/elasticsearch.clj
@@ -62,7 +62,8 @@
       (if (esi/exists? conn index-name)
         ;; The index exists. Update the mappings.
         (doseq [[type-name type-mapping] mapping]
-          (let [response (esi/update-mapping conn index-name (name type-name) :mapping mapping)]
+          (let [response (esi/update-mapping
+                           conn index-name (name type-name) :mapping mapping :ignore_conflicts false)]
             (when-not (= {:acknowledged true} response)
               (errors/internal-error! (str "Unexpected response when updating elastic mappings: "
                                            (pr-str response))))))


Use new lib to construct joined collections of strings

--- src/discuss/components/items.cljs
+++ src/discuss/components/items.cljs
@@ -1,13 +1,12 @@
 (ns discuss.components.items
   (:require [om.next :as om :refer-macros [defui]]
-            [clojure.string :as string]
             [sablono.core :as html :refer-macros [html]]
             [discuss.communication.lib :as comlib]
-            [discuss.translations :refer [translate] :rename {translate t}]
             [discuss.utils.common :as lib]
             [discuss.utils.logging :as log]
             [discuss.utils.views :as vlib]
-            [cljs.spec.alpha :as s]))
+            [cljs.spec.alpha :as s]
+            [discuss.texts.lib :as textlib]))

 (defn- dispatch-click-fn
   "Dispatch which function should be applied if there is a click on an item."
@@ -35,7 +34,7 @@
                              :onClick (partial dispatch-click-fn url)
                              :value url}]
                     " "
-                    (vlib/safe-html (string/join (str " <i>" (t :common :and) "</i> ") htmls))]]))))
+                    (vlib/safe-html (textlib/join-with-and htmls))]]))))
 (def item (om/factory Item {:keyfn :url}))

 (defui Items


[#2476] Dont call authz service

[#2476] Dont call authz service

akvo authz service is not currently deployed

--- backend/src/akvo/lumen/lib/auth.clj
+++ backend/src/akvo/lumen/lib/auth.clj
@@ -194,16 +194,11 @@
         (let [tenant-conn    (p/connection tenant-manager tenant)
               dss            (db.dataset/all-datasets tenant-conn)
               rasters        (mapv :id (db.raster/all-rasters tenant-conn))
-              auth-uuid-tree (if (match-by-jwt-family-name? request)
-                               (load-auth-data dss rasters tenant-conn authz-service-client request collector tenant)
-                               (do
-                                 (future
-                                   (load-auth-data dss rasters tenant-conn authz-service-client request collector tenant))
-                                 {:rasters             rasters
-                                  :auth-datasets       (mapv :id dss)
-                                  :auth-visualisations (mapv :id (db.visualisation/all-visualisations-ids tenant-conn))
-                                  :auth-dashboards     (mapv :id (db.dashboard/all-dashboards-ids tenant-conn))
-                                  :auth-collections    (mapv :id (db.collection/all-collections-ids tenant-conn))}))]
+              auth-uuid-tree {:rasters             rasters
+                              :auth-datasets       (mapv :id dss)
+                              :auth-visualisations (mapv :id (db.visualisation/all-visualisations-ids tenant-conn))
+                              :auth-dashboards     (mapv :id (db.dashboard/all-dashboards-ids tenant-conn))
+                              :auth-collections    (mapv :id (db.collection/all-collections-ids tenant-conn))}]
           (handler (assoc request
                           :auth-service (new-auth-service auth-uuid-tree))))))))


Doc spelling fixes

Doc spelling fixes

--- src/semantic_csv/core.clj
+++ src/semantic_csv/core.clj
@@ -63,11 +63,11 @@
 ;; ## mappify

 (defn mappify
-  "Comsumes the first item as a header, and returns a seq of the remaining items as a maps with the header
+  "Consumes the first item as a header, and returns a seq of the remaining items as a maps with the header
   values as keys. Note that an optional `opts` map can be passed as a first arg, with the following option:

-  * `:keyify` - specify whether header/column names should be turned into keywords (deafults to true)
-  * `:header` - specify the header to use for map keys, preventing first row of data from bein gconsumed as header
+  * `:keyify` - specify whether header/column names should be turned into keywords (defaults to true)
+  * `:header` - specify the header to use for map keys, preventing first row of data from being consumed as header
   * `:structs` - bool; use structs instead of hash-maps or array-maps, for performance boost"
   ([rows]
    (mappify {} rows))
@@ -150,7 +150,7 @@
   Additionally, an `opts` map can be used to specify:

   * `:except-first` - Ignore the first row in `rows`; Useful for preserving header rows.
-  * `:exception-handler` - If cast-fn raises an excpetion, this function will be called with args
+  * `:exception-handler` - If cast-fn raises an exception, this function will be called with args
     `colname, value`. The result of the exception handler will be used as the parse value.
   * `:only` - Only the column(s) specified will be casted."
   ([cast-fns rows]
@@ -320,7 +320,7 @@
     (int v)))

 (defn ->long
-  "Translating to long from string or other numeric. If string represents a non integeral value,
+  "Translating to long from string or other numeric. If string represents a non integer value,
   it will be rounded down to the nearest long."
   [v]
   (if (string? v)


Docs for headerless casting.

Docs for headerless casting.

--- src/semantic_csv/core.clj
+++ src/semantic_csv/core.clj
@@ -168,6 +168,10 @@
 ;;
 ;; Note from the implementation here that each row need only be associative.
 ;; So map or vector rows are fine, but lists or lazy sequences would not be.
+;; In particular, if you’ve imported data without a header with the `:header`
+;; option set to `false` then the columns can be keyed by their zero-based
+;; index, for instance `(cast-with {0 #(Integer/parseInt %) 1 #(Double/parseDouble %)} rows)`
+;; will parse the first column as integers and the second as doubles.

 ;; <br/>


Replace environ by cprop in core

Replace environ by cprop in core

--- src/madouc/core.clj
+++ src/madouc/core.clj
@@ -3,11 +3,12 @@
             [immutant.web :as server]
             [ring.middleware.reload :refer [wrap-reload]]
             [ring.middleware.stacktrace :refer [wrap-stacktrace]]
-            [madouc.handlers :as app]
-            [environ.core :refer [env]]
             [taoensso.timbre :as timbre]
             [selmer.parser :refer [set-resource-path!]]
-            [mount.core :as mount :refer [defstate]])
+            [mount.core :as mount :refer [defstate]]
+            [cprop.core :refer [load-config]]
+            [madouc.handlers :as app]
+            [madouc.config :refer [env]])
   (:gen-class))

@@ -46,5 +47,6 @@
 (defn -main
   [& args]
   (.addShutdownHook (Runtime/getRuntime) (Thread. #(mount/stop)))
+
   (set-resource-path! (clojure.java.io/resource "templates"))
   (mount/start))


Add idempotence test for producer component

--- clstreams/test/clstreams/kstreams/component_test.clj
+++ clstreams/test/clstreams/kstreams/component_test.clj
@@ -14,6 +14,9 @@
                                                  (.serializer value-serde))))

 (defmacro cycle-component
+  "Run a component through its lifecycle (initialize, start, stop) and
+  run test assertions after each step."
+
   [[initial-bform component-expr]
    initial-test-exprs
    [started-bform]
@@ -33,12 +36,32 @@
              ~stopped-bform stopped#]
          ~@stopped-test-exprs))))

+(defn check-idempotence
+  "Check that the provided component has idempotent start and stop
+  operations."

-(deftest test-producer-component
+  [component]
+
+  (cycle-component
+
+   [initial component]
+   ()
+
+   [started]
+   ((let [started-again (component/start started)]
+      (is (= started started-again) "component's start is idempotent")))
+
+   [stopped]
+   ((let [stopped-again (component/stop stopped)]
+      (is (= stopped stopped-again) "component's stop is idempotent")))))
+
+
+(deftest test-cycle-producer-component
   (with-redefs [sut/kafka-producer kafka-mock-producer]
     (let [tp-name "ze-topic"
           cnf {"ze.config.option" "ze config value"}]
       (cycle-component
+
        [{:keys [config topic-name producer]} (sut/new-producer tp-name cnf)]
        ((is (= config cnf))
         (is (= topic-name tp-name))
@@ -49,3 +72,9 @@

        [{:keys [producer]}]
        ((is (nil? producer)))))))
+
+(deftest test-idempotent-producer-component
+  (with-redefs [sut/kafka-producer kafka-mock-producer]
+    (let [tp-name "ze-topic"
+          cnf {"ze.config.option" "ze config value"}]
+      (check-idempotence (sut/new-producer tp-name cnf)))))


Fix comment about bitrate for stereo productions

to match the actual implementation

--- src/mdr2/encode.clj
+++ src/mdr2/encode.clj
@@ -122,7 +122,7 @@
     (->> bitrates
          ;; only use bitrate 32 for periodicals
          (filter #(or (= (:production_type production) "periodical") (> % 32)))
-         ;; for stereo productions use only bitrates larger than 96
+         ;; for stereo productions use only bitrates larger or equal than 96
          (filter #(or (dtb/mono? dtb) (>= % 96)))
          (filter #(<= % max-bitrate))
          (apply max 0))))


Add glyphicon and button-group helpers

Add glyphicon and button-group helpers

--- src/mdr2/layout.clj
+++ src/mdr2/layout.clj
@@ -1,6 +1,15 @@
 (ns mdr2.layout
   "Define the basic page structure and layout"
   (:require [hiccup.page :refer [html5 include-css]]))
+
+(defn glyphicon [class]
+  [:span {:class (str "glyphicon glyphicon-" class)}])
+
+(defn button-group [buttons]
+  [:div.btn-group
+   (for [{href :href glyphicon-class :glyphicon} buttons]
+     [:a.btn.btn-default {:href href}
+      (glyphicon glyphicon-class)])])

 (defn loginbar
   "Display a login link or information about the currently logged in user if user is non-nil"
@@ -8,9 +17,9 @@
   [:ul.nav.navbar-nav.navbar-right
    (if user
      (list
-      [:li [:a "Logged in as " [:b (:username user)]]]
-      [:li [:a {:href "/logout"} "Logout"]])
-     [:li [:a {:href "/login"} "Login"]])])
+      [:li [:a [:b (:username user)]]]
+      [:li [:a {:href "/logout"} (glyphicon "log-out")]])
+     [:li [:a {:href "/login"} (glyphicon "log-in")]])])

 (defn navbar
   "Display the navbar"


Delta and sample-tiles are working.

Delta and sample-tiles are working.

--- src/mosaic/tile.clj
+++ src/mosaic/tile.clj
@@ -2,7 +2,8 @@
   (import java.io.File)
   (import javax.imageio.ImageIO)
   (import java.awt.image.BufferedImage)
-  (import com.mortennobel.imagescaling.ResampleOp))
+  (import com.mortennobel.imagescaling.ResampleOp)
+  (import java.lang.Math))

 (defn test-image []
   (ImageIO/read
@@ -40,3 +41,21 @@
   "Save tiles (list of BufferedImages) to directory d."
   (map #(save-image %1 %2) tiles (tile-names d)))

+(defn get-samples [^BufferedImage b]
+  "Get a flat list of all samples in an image."
+  (let [d (.getData b)]
+    (for [x (range (.getWidth d))
+	  y (range (.getHeight d))
+	  z (range (.getNumBands d))]
+      (.getSample d x y z))))
+
+(defn delta [^BufferedImage a ^BufferedImage b]
+  "Calculates the difference between images a and b."
+  (reduce + (map #(Math/abs %)
+		 (map - (get-samples a) (get-samples b)))))
+
+(defn sample-tiles [n tiles]
+  "Resample tiles to size n by n.
+   Output format: {:tile :sample}"
+  (for [t tiles] {:tile t :sample (rescale n n t)}))
+


Made date & time formatting consistent in the RSS template.

--- src/lambda_blog/templates/rss.clj
+++ src/lambda_blog/templates/rss.clj
@@ -1,7 +1,7 @@
 (ns lambda-blog.templates.rss
   (:refer-clojure :exclude [name])
   (:require [clj-time.core :refer [now]]
-            [lambda-blog.utils :refer [pathcat]]
+            [lambda-blog.utils :refer [format-time pathcat]]
             [s-html.tags :refer [deftags link xml] :as tags]))

 (deftags [^:private author
@@ -17,6 +17,8 @@
 (def ^:private _author author) ;; FIXME Loose the _.
 (def ^:private _summary summary)

+(def ^:private format-t (partial format-time :date-time))
+
 (defn rss-feed
   "Creates an XML RSS page conforming to the http://www.w3.org/2005/Atom specification."
   [{:keys [entries path title url]}]
@@ -26,14 +28,14 @@
          (link {:rel :self
                 :href (pathcat url path)})
          (link {:href url})
-         (updated (now))
+         (updated (format-t (now)))
          (id url)
          (map (fn [{:keys [author path summary tags timestamp title]}]
                 (entry (tags/title title)
                        (id path)
                        (_author (name author))
-                       (updated timestamp)
-                       (published timestamp)
+                       (updated (format-t timestamp))
+                       (published (format-t timestamp))
                        (link {:href (pathcat url path)})
                        (map #(category {:scheme (pathcat url (:path %))
                                         :term (:id %)


Log when configuration from environment is disabled

--- src/yetibot/core/config.clj
+++ src/yetibot/core/config.clj
@@ -41,9 +41,10 @@
   []
   (merge
     (merge-possible-prefixes (uc/load-edn! config-path))
-    (when-not config-from-env-disabled?
+    (if-not config-from-env-disabled?
       (let [env-vars (prefixed-env-vars)]
-        (merge-possible-prefixes (explode env-vars))))))
+        (merge-possible-prefixes (explode env-vars)))
+      (info "Configuration from environment is disabled"))))

 (defonce ^:private config (atom (config-from-env-or-file)))


crawl.clj: different input/output dirs

crawl.clj: different input/output dirs

* Don't generate input requests
* Always use web/requests for input
* Output to unique timestampped directory

--- src/org/altlaw/jobs/web/crawl.clj
+++ src/org/altlaw/jobs/web/crawl.clj
@@ -2,6 +2,7 @@
   (:require [org.altlaw.extract.scrape.handler :as handler]
             [org.altlaw.util.log :as log]
             [org.altlaw.util.hadoop :as h]
+            [org.altlaw.util.date :as date]
             [org.altlaw.util.crawler :as crawler]
             [org.altlaw.util.context :as context]
             [org.altlaw.db.download-log :as dl]
@@ -36,22 +37,18 @@
 (defn reducer-close [this]
   (dl/save-download-log))

+
 (defn tool-run [this args]
   (let [job (h/default-jobconf this)
-        outpath (Path. (h/job-path :web :crawl))
-        inpath (Path. (h/job-path :web :requests))
+        inpath (Path. (h/job-path :web :request))
+        outpath (Path. (h/job-path :web :crawl) (str "c-" (date/filename-timestamp)))
         hdfs (FileSystem/get job)]
-    (.delete hdfs inpath true)
-    (with-open [hdfs-stream (.create hdfs (Path. inpath "part-00000") true)]
-      (binding [*out* (duck/writer (.getWrappedStream hdfs-stream))]
-        (doseq [r (handler/all-requests)]
-          (prn r))))
+    (.delete hdfs outpath true)
     (FileInputFormat/setInputPaths job (str inpath))
     (FileOutputFormat/setOutputPath job outpath)
     (FileOutputFormat/setOutputCompressorClass job GzipCodec)
     (.setInputFormat job TextInputFormat)
     (.setOutputFormat job TextOutputFormat)
-    (.delete hdfs outpath true)
     (.setMapperClass job org.altlaw.jobs.web.crawl_mapper)
     (.setReducerClass job org.altlaw.jobs.web.crawl_reducer)
     (.setNumReduceTasks job 1)


hazelcast to 3.10.2

hazelcast to 3.10.2

--- build.boot
+++ build.boot
@@ -4,8 +4,8 @@
   :source-paths #{"src"}
   :dependencies '[[org.clojure/clojure "1.9.0"]
                   [org.clojure/tools.logging "0.3.1"]
-                  [com.hazelcast/hazelcast "3.9.3"]
-                  [com.hazelcast/hazelcast-client "3.9.3"]
+                  [com.hazelcast/hazelcast "3.10.2"]
+                  [com.hazelcast/hazelcast-client "3.10.2"]
                   [org.hface/hface-client "0.1.5"]
                   [cheshire "5.6.3"]
                   [com.cognitect/transit-clj "0.8.275"]


Fix pom properties

Fix pom properties

--- build.boot
+++ build.boot
@@ -20,8 +20,8 @@

 (task-options!
   pom {:version     +version+
-       :url         "https://github.com/deraen/boot-less"
-       :scm         {:url "https://github.com/deraen/boot-less"}
+       :url         "https://github.com/deraen/less4clj"
+       :scm         {:url "https://github.com/deraen/less4clj"}
        :license     {"Eclipse Public License" "http://www.eclipse.org/legal/epl-v10.html"}})

 (defn with-files
@@ -60,7 +60,8 @@
     (fn [x] (re-find #"less4clj" (tmp-path x)))
     (comp
      (pom
-      :project 'deraen/less4clj)
+      :project 'deraen/less4clj
+      :description "Clojure wrapper for Less4j.")
      (jar)
      (install)))


Bump to 0.1.0-alpha1

Bump to 0.1.0-alpha1

--- build.boot
+++ build.boot
@@ -18,7 +18,7 @@

 (task-options!
   pom {:project "om-mantras"
-       :version "0.1.0-alpha1-SNAPSHOT"})
+       :version "0.1.0-alpha1"})

 (require '[adzerk.boot-cljs :refer [cljs]]
          '[adzerk.boot-reload :refer [reload]]


Dependency update

Dependency update

--- build.boot
+++ build.boot
@@ -52,14 +52,14 @@
    [com.cemerick/piggieback "0.2.1" :scope "test"]

    ;; Server deps
-   [aero "1.0.0"]
-   [bidi "2.0.12"]
+   [aero "1.0.1"]
+   [bidi "2.0.14"]
    [com.stuartsierra/component "0.3.1"]
    [hiccup "1.0.5"]
    [org.clojure/tools.namespace "0.2.11"]
    [prismatic/schema "1.0.4"]
    [selmer "1.0.4"]
-   [yada "1.1.37" :exclusions [aleph manifold ring-swagger prismatic/schema]]
+   [yada "1.1.45" :exclusions [aleph manifold ring-swagger prismatic/schema]]

    [aleph "0.4.2-alpha8"]
    [manifold "0.1.6-alpha1"]


Remove (target) intermediaries

Remove (target) intermediaries

These are only really useful for debugging, so should only be added when
needed.

--- build.boot
+++ build.boot
@@ -40,13 +40,13 @@

 (deftask test [] ;; the tests rely on having the jar kicking about!
   (testing)
-  (comp (target) (boot-test/test)))
+  (comp (boot-test/test)))

 (deftask autotest []
   (comp (watch) (test)))

 (deftask make-jar []
-  (comp (target) (pom) (jar)))
+  (comp (pom) (jar)))

 (deftask travis []
   (testing)


Floor, stairs

Floor, stairs

--- src/try_lwjgl/display.clj
+++ src/try_lwjgl/display.clj
@@ -130,23 +130,10 @@

 (defn draw-rectangle []
   (drawing-object
-   ;; x, y, z
-   (GL11/glTranslatef 2.5 0.0 0.0)
-
-   ;; glRotatef
-   ;;   arg0: angle
-   ;;   arg1: x axis (left to right)
-   ;;   arg2: y axis (down to up)
-   ;;   arg3: z axis (front to back)
-   (GL11/glRotatef @logic/angle 1.0 0.0 0.0)
-
-   (GL11/glColor3f 0.5 0.5 1.0)
-
-   (do-shape GL11/GL_QUADS
-             (GL11/glVertex3f -1.0  1.0 0.0)
-             (GL11/glVertex3f  1.0  1.0 0.0)
-             (GL11/glVertex3f  1.0 -1.0 0.0)
-             (GL11/glVertex3f -1.0 -1.0 0.0))))
+   (GL11/glColor3f 1 1 1)
+   (GL11/glTranslatef 0 -10 0)
+   (GL11/glRotatef 90 1 0 0)
+   (draw-textured-panel)))

 (def AXIS-WIDTH 0.05)

@@ -252,14 +239,10 @@
    (Mouse/isButtonDown 1) (Mouse/setGrabbed false)
    (Mouse/isButtonDown 2) (println "Mouse button 2 down")))

-(defn draw-models []
-  (GL20/glUseProgram @program)
-  (draw-axes)
-  (draw-container-cube)
-  (draw-rectangle)
-  (GL20/glUseProgram 0))
-
 (defn draw-textured-panel []
+  (.bind Color/white)
+  (.bind @texture)
+
   (do-shape GL11/GL_QUADS
             (GL11/glTexCoord2f 1 0)
             (GL11/glVertex3f 1 0 0)
@@ -270,46 +253,69 @@
             (GL11/glTexCoord2f 1 1)
             (GL11/glVertex3f 1 1 0)))

-(defn draw-textured-model []
-  ;; face
-  (draw-textured-panel)
+(defn draw-block [draw-panel]
+    ;; face
+  (draw-panel)

   ;; back
   (drawing-object
    (GL11/glTranslatef 0 0 -1)
-   (draw-textured-panel))
+   (draw-panel))

   ;; ;; left
   (drawing-object
    (GL11/glRotatef 90 0 1 0)
-   (draw-textured-panel))
-
-  ;; ;; right
+   (draw-panel))
+
+  ;; right
   (drawing-object
    (GL11/glTranslatef 1 0 0)
    (GL11/glRotatef 90 0 1 0)
-   (draw-textured-panel))
+   (draw-panel))

   ;; back
   (drawing-object
    (GL11/glRotatef -90 1 0 0)
-   (draw-textured-panel))
+   (draw-panel))

   ;; ;; top
   (drawing-object
    (GL11/glTranslatef 0 1 0)
    (GL11/glRotatef -90 1 0 0)
-   (draw-textured-panel)))
+   (draw-panel)))
+
+(defn draw-textured-block []
+  (draw-block draw-textured-panel))
+
+(defn draw-stairs []
+  (doseq [side [0 1 2 3]]
+    (doseq [up [0 1 2]]
+      (drawing-object
+       (GL11/glTranslatef side up (* -1.0 up))
+       (draw-textured-block)))))
+
+(defn draw-floor []
+  (doseq [x (range -10 10)
+          z (range -10 10)]
+    (drawing-object
+     (GL11/glTranslatef x -10 z)
+     (GL11/glRotatef 90 1 0 0)
+     (draw-textured-panel))))
+
+(defn draw-models []
+  (GL20/glUseProgram @program)
+  (draw-axes)
+  (draw-container-cube)
+  (GL20/glUseProgram 0)
+
+  (draw-stairs)
+
+  (draw-floor))

 (defn draw []
   (GL11/glClear (bit-or GL11/GL_COLOR_BUFFER_BIT GL11/GL_DEPTH_BUFFER_BIT))
-
   (GL11/glLoadIdentity)
   (.applyTranslations @camera)
-
-  (.bind Color/white)
-  (.bind @texture)
-  (draw-textured-model)

   (draw-models)


elevio Use frontend.analytics/track with kebabcase

--- src-cljs/frontend/core.cljs
+++ src-cljs/frontend/core.cljs
@@ -307,13 +307,15 @@
           goog.events.EventType.CLICK
           (fn [e]
             (let [target (.-target e)
-                  module-name (or (-> target
-                                      (goog.dom/getAncestorByTagNameAndClass "div")
-                                      (.getAttribute "data-elevio-tooltip"))
-                                  "widget")
-                  message (str "elevio " module-name " clicked")]
+                  module-name (-> (or (-> target
+                                          (goog.dom/getAncestorByTagNameAndClass "div")
+                                          (.getAttribute "data-elevio-tooltip"))
+                                      "widget")
+                                  (string/lower-case)
+                                  (string/replace #"\s+" "-"))
+                  message (str "elevio-" module-name "-clicked")]
              ;; This triggers when the elevio widget is clicked
-             (analytics/track-message {} message state))))))
+             (analytics/track message))))))
      5000)))

 (defn ^:export setup! []


Began to remove get-teas ajax call, replacing with re-frame vers.

--- src-cljs/tea_time/core.cljs
+++ src-cljs/tea_time/core.cljs
@@ -96,7 +96,7 @@
   :initialize-db
   (fn [_ _]
     {:teas-list []
-     :new-tea "BLAH"}))
+     :new-tea ""}))

 (defn new-tea-entered
   [app-state [_ new-tea-input]]
@@ -119,10 +119,10 @@

 (defonce app-db (reagent/atom {}))

-(defn get-teas
-  "Gets the list of all teas from the website"
-  []
-  (ajax/GET "/api/teas" :handler (fn [response] (reset! app-db (assoc-in @app-db [:teas-list] response)))))
+;(defn get-teas
+  ;"Gets the list of all teas from the website"
+  ;[]
+  ;(ajax/GET "/api/teas" :handler (fn [response] (reset! app-db (assoc-in @app-db [:teas-list] response)))))

  ;;(reset! app-db (assoc-in app-db [:teas-list] response))
 (defn delete-tea
@@ -130,21 +130,21 @@
   [name]
   (ajax/GET (str "/api/teas/" name "/delete")
             :error-handler (fn [response] (println "DELETE-TEA ERROR" response))
-            :handler (fn [response] (println name " deleted") (get-teas) (reset! edit-tea-snap nil))))
+            :handler (fn [response] (println name " deleted") (re-frame/dispatch [:load-teas])(reset! edit-tea-snap nil))))

 (defn update-tea
   "Sends an update request to the API, which updates the tea in the db"
   [id newname]
   (ajax/GET (str "/api/teas/" id "/update/" newname)
             :error-handler (fn [response] (println "UPDATE-TEA ERROR" response))
-            :handler (fn [response] (println newname " updated") (get-teas) (reset! edit-tea nil))))
+            :handler (fn [response] (println newname " updated") (reset! edit-tea nil))))

 (defn post-to-teas-db
   "Sends an Ajax Request to the API route to post the tea from the form to the database"
   [tea-name]
   ;; (println "post-to-teas-db hit, params: " tea-name)
   (ajax/POST "/api/newtea" {:params {:new-tea tea-name} :format :json}
-             :handler (fn [] (println "New Tea Posted") (get-teas))
+             :handler (fn [] (println "New Tea Posted"))
              :error-handler (fn [err] (println "New Tea Failed To Post" err))))


CMR-1294: Added values to format call

CMR-1294: Added values to format call

--- metadata-db-app/src/migrations/012_add_granule_index_with_revision_date.clj
+++ metadata-db-app/src/migrations/012_add_granule_index_with_revision_date.clj
@@ -8,7 +8,7 @@
   []
   (println "migrations.012-add-granule-index-with-revision-date up...")
   (doseq [t (h/get-granule-tablenames)]
-    (h/sql (format "create index %s_crddr on %s (concept_id, revision_id, deleted, delete_time, revision_date)"))
+    (h/sql (format "create index %s_crddr on %s (concept_id, revision_id, deleted, delete_time, revision_date)" t t))
     (h/sql (format "drop index %s_crdi" t))))

 (defn down
@@ -16,5 +16,5 @@
   []
   (println "migrations.012-add-granule-index-with-revision-date down...")
   (doseq [t (h/get-granule-tablenames)]
-    (h/sql (format "create index %s_crdi on %s (concept_id, revision_id, deleted, delete_time)"))
+    (h/sql (format "create index %s_crdi on %s (concept_id, revision_id, deleted, delete_time)" t t))
     (h/sql (format "drop index %s_crddr" t))))