rename `make-async-backend` param

rename `make-async-backend` param

--- src/duratom/core.clj
+++ src/duratom/core.clj
@@ -86,7 +86,7 @@
   )

 ;; override default `print-method` for records in order to hide certain fields,
-;; but also to provide printing that sort of resembles atoms
+;; but also to provide printing which resembles atoms
 (defmethod print-method Duratom [dura ^Writer w]
   (.write w "#")
   (.write w (-> dura class .getName))
@@ -98,11 +98,12 @@

 (defn- ->Duratom ;; shadow the generated constructor-fns
-  [make-async-backend lock init]
+  [make-backend lock init]
   (assert (or (ut/lock? lock)
-              (nil? lock)) "The <lock> provided is neither a valid implementation of `java.util.concurrent.locks.Lock`, nor nil!")
+              (nil? lock))
+          "The <lock> provided is neither a valid implementation of `java.util.concurrent.locks.Lock`, nor nil!")
   (let [raw-atom (atom nil)
-        backend (make-async-backend (agent raw-atom))
+        backend (make-backend (agent raw-atom))
         duratom (Duratom. backend raw-atom lock (ut/releaser))
         storage-init (doto duratom read_in)]
     (if (some? @storage-init) ;; found stuff
@@ -111,8 +112,8 @@
               (some? init) (doto (reset! init)))))) ;; empty storage means we start off with <initial-value>

 (defn- map->Duratom [m]
-  (let [[make-async-backend lock initial-value] ((juxt :make-async-backend :lock :init) m)]
-    (->Duratom make-async-backend lock initial-value)))
+  (let [[make-backend lock initial-value] ((juxt :make-backend :lock :init) m)]
+    (->Duratom make-backend lock initial-value)))

 ;;==================<PUBLIC API>==========================
@@ -124,14 +125,14 @@
   ([file-path lock initial-value]
    (map->Duratom {:lock lock ;; allow for explicit nil
                   :init initial-value
-                  :make-async-backend (partial storage/->FileBackend
-                                               (try
-                                                 (doto (jio/file file-path)
-                                                   (.createNewFile))
-                                                 (catch IOException exception
-                                                   (throw (ex-info "Failed creating the file needed!"
-                                                                   {:file-path file-path}
-                                                                   exception)))))
+                  :make-backend (partial storage/->FileBackend
+                                         (try
+                                           (doto (jio/file file-path)
+                                             (.createNewFile))
+                                           (catch IOException exception
+                                             (throw (ex-info "Failed creating the file needed!"
+                                                             {:file-path file-path}
+                                                             exception)))))
                   })))

@@ -146,13 +147,13 @@
   ([db-config table-name row-id lock initial-value]
    (map->Duratom {:lock lock
                   :init initial-value
-                  :make-async-backend (partial storage/->PGSQLBackend
-                                               db-config
-                                               (if (ut/table-exists? db-config table-name)
-                                                 table-name
-                                                 (do (ut/create-dedicated-table! db-config table-name)
-                                                     table-name))
-                                               row-id)
+                  :make-backend (partial storage/->PGSQLBackend
+                                         db-config
+                                         (if (ut/table-exists? db-config table-name)
+                                           table-name
+                                           (do (ut/create-dedicated-table! db-config table-name)
+                                               table-name))
+                                         row-id)
                   })))

 (defn s3-atom
@@ -163,13 +164,13 @@
   ([creds bucket k lock initial-value]
    (map->Duratom {:lock lock
                   :init initial-value
-                  :make-async-backend (partial storage/->S3Backend
-                                               creds
-                                               (if (ut/does-bucket-exist creds bucket)
-                                                 bucket
-                                                 (do (ut/create-s3-bucket creds bucket)
-                                                     bucket))
-                                               k)
+                  :make-backend (partial storage/->S3Backend
+                                         creds
+                                         (if (ut/does-bucket-exist creds bucket)
+                                           bucket
+                                           (do (ut/create-s3-bucket creds bucket)
+                                               bucket))
+                                         k)
                   })))


Let components override parent properties and evolvers with nil intentionally when needed

--- src/flatgui/base.clj
+++ src/flatgui/base.clj
@@ -201,9 +201,9 @@
   (let [ key-order (distinct (concat (for [[k v] a] k) (for [[k v] b] k)))
          result (apply array-map (mapcat (fn [k] (if (and (map? (a k)) (map? (b k)))
                                              [k (merge-ordered (a k) (b k))]
-                                             (if (nil? (b k))
-                                               [k (a k)]
-                                               [k (b k)]))) key-order))]
+                                             (if (contains? b k) ; b may intentionally override smth with nil
+                                               [k (b k)]
+                                               [k (a k)]))) key-order))]
     (do
       ;(log-debug " Merged result of class: " (.getClass result))
       result)))


Introduce query planner/executor framework.

--- src/fleetdb/core.clj
+++ src/fleetdb/core.clj
@@ -101,39 +101,94 @@
     (fn [record-a record-b]
       (compare (attr record-b) (attr record-a)))))

-(defn- apply-order [records order]
-  (if-let [[attr dir] order]
-    (sort (order-keyfn attr dir) records)
-    records))
-
-(defn- apply-offset [records offset]
-  (if offset (drop offset records) records))
-
-(defn- apply-limit [records limit]
-  (if limit (take limit records) records))
-
-(defn- find-records [records {:keys [where order offset limit]}]
-  (-> (filter (where-pred where) records)
-    (apply-order order)
-    (apply-offset offset)
-    (apply-limit limit)))
-
 (defn- apply-only [records only]
   (if only
     (map #(select-keys % only) records))
     records)

-(defn- q-select [db {:keys [only] :as opts}]
-  (-> (find-records (vals (:rmap db)) opts)
-    (apply-only only)))
+(defn filter-plan [source where]
+  (if-not where
+    source
+    {:action  :filter
+     :options {:where where}
+     :source  source}))
+
+(defn order-plan [source order]
+  (if-not order
+    source
+    {:action  :sort
+     :options {:order order}
+     :source  source}))
+
+(defn record-stream-plan [db where order]
+  (-> {:action :full-scan}
+    (filter-plan where)
+    (order-plan order)))
+
+(defn offset-plan [source offset]
+  (if-not offset
+    source
+    {:action  :offset
+     :options {:offset offset}
+     :source  source}))
+
+(defn limit-plan [source limit]
+  (if-not limit
+    source
+    {:action  :limit
+     :options {:limit limit}
+     :source  source}))
+
+(defn only-plan [source only]
+  (if-not only
+    source
+    {:action  :only
+     :options {:only only}
+     :source  source}))
+
+(defn select-plan [db where order offset limit only]
+  (-> (record-stream-plan db where order)
+    (offset-plan offset)
+    (limit-plan limit)
+    (only-plan only)))
+
+(defn execute-plan [db plan]
+  (let [{:keys [action options source]} plan]
+    (condp = action
+      :full-scan
+        (vals (:rmap db))
+
+      :filter
+        (let [{:keys [where]} options]
+          (filter (where-pred where) (execute-plan db source)))
+
+      :sort
+        (let [{:keys [attr dir]} options]
+          (sort (order-keyfn attr dir) (execute-plan db source)))
+
+      :offset
+        (let [{:keys [offset]} options]
+          (drop offset (execute-plan db source)))
+
+      :limit
+        (let [{:keys [limit]} options]
+          (take limit (execute-plan db source)))
+
+      :only
+        (let [{:keys [only]} options]
+          (map #(select-keys % only) (execute-plan db source))))))
+
+(defn- q-select [db {:keys [where order offset limit only]}]
+  (execute-plan db
+    (select-plan db where order offset limit only)))

 (defn- q-count [db opts]
-  (count (find-records (vals (:rmap db)) opts)))
+  (count (q-select db opts)))

 (defn- q-update [db {:keys [with] :as opts}]
   (assert with)
   (let [{old-rmap :rmap old-imap :imap} db
-        old-records     (find-records (vals old-rmap) opts)
+        old-records     (q-select db opts)
         num-old-records (count old-records)
         [new-rmap new-imap]
           (reduce
@@ -150,7 +205,7 @@

 (defn- q-delete [db opts]
   (let [{old-rmap :rmap old-imap :imap} db
-        old-records (find-records (vals old-rmap) opts)
+        old-records (q-select db opts)
         num-old-records (count old-records)
         [new-rmap new-imap]
           (reduce


sorting out how to do this via public methods

--- src/jsx_fun/core.clj
+++ src/jsx_fun/core.clj
@@ -71,25 +71,27 @@
       (slurp (io/file "resources/ScrollResponder.js"))))

   (let [js      [(SourceFile/fromCode
-                    "ScrollResponder.js"
+                   "ScrollResponder.js"
                    (slurp (io/file "resources/ScrollResponder.js")))]
         options (set-options
                   {:lang-in :es5 :type :commonjs}
                   (CompilerOptions.))
         comp    (doto (cl/make-closure-compiler)
                   (.init '() js options))
-        module  (JSModule. "[singleton]")
-        input   (do
-                  (doseq [x js]
-                     (.add module x))
-                  (first (.getInputs module)))
-        root    (.getAstRoot input comp)]
-    (.setCompiler input comp)
-    (.process
+        ;module  (JSModule. "[singleton]")
+        ;input   (do
+        ;          (doseq [x js]
+        ;             (.add module x))
+        ;          (first (.getInputs module)))
+        ]
+    (.parse comp)
+    #_(.setCompiler input comp)
+    #_(.process
       (ProcessCommonJSModules. comp
         (ES6ModuleLoader. comp "resources/")
         false)
       nil root)
-    (.toSource comp root))
+    (.toSource comp)
+    )

 )


return a vec rather than a lazy seq

return a vec rather than a lazy seq

--- src/k_means/core.clj
+++ src/k_means/core.clj
@@ -42,10 +42,10 @@
         (> 0 max-iterations) g
         (still-moving? t c) ; Keep shifting centroids until equilibrium
           (recur l k c g (dec max-iterations))
-        :else g))))
+        :else (vec g)))))

 (defn -main
   "Main function for k-means"
   [& args]
-  (let [c (profile :info :Arithmetic (k-means-p (vector/make-vector-rand 40000) 10 25)) => "Done"]
+  (let [c (profile :info :Arithmetic (k-means-p (vector/make-vector-rand 40000) 5 100)) => "Done"]
     (spit "k-means.txt" c)) (shutdown-agents))


get started on mean-centroids

get started on mean-centroids

--- src/k_means/core.clj
+++ src/k_means/core.clj
@@ -17,19 +17,19 @@
 (defn mean
   "Retrieve the mean value of a list"
   [l]
-  (float (/ (reduce + l) (count l))))
+  (/ (reduce + l) (count l)))

+;; This is the next method which will be implemented...
 (defn mean-centroids
   "Calculates the mean for a given centroid"
-  [g]
-  g)
-; (defn centroid)
+  ([g] (mean-centroids g []))
+  ([g l]
+    g))

 (defn distance
   "Implements euclidian distance between two vectors"
   ([c1 c2]
-    (->> (map - c1 c2) (map #(* % %)) (reduce +)))) ; This is a better implementation for when this gets parallelised
-
+    (->> (map - c1 c2) (map #(* % %)) (reduce +))))
 (defn min-index
   [c]
   (.indexOf c (apply min c)))
@@ -64,14 +64,6 @@
   [l]
   (map distance l))

-(defn group
-  "Group each vector based on the distance from each centroid"
-  ([l c g]
-    (cond
-      (empty? l) g
-      :else
-        (recur (rest l) c ()))))
-
 (defn k-means
   "Perform the actual k-means"
   ([l k]
@@ -81,11 +73,10 @@
       ; (println g)
       (cond
         (still-moving? t c) ; Keep shifting centroids until equilibrium
-          ; (recur nil k c g)
-          g
+          (recur l k c g)
         :else g))))

 (defn -main
   "Main function for k-means"
   [& args]
-  (let [c (k-means [[1 2] [3 2] [6 3] [1 8] [9 10] [1 4] [56 67] [44 53] [43 54] [43 64] [76 56]] 3)] (println c)))
+  (let [c (k-means [[1 2] [3 2] [6 3] [1 8] [9 10] [1 4] [56 67] [44 53] [43 54] [43 64] [76 56]] 2)] (println c)))


remove inspect

remove inspect

--- src-cljs/frontend/core.cljs
+++ src-cljs/frontend/core.cljs
@@ -108,9 +108,9 @@

 (defn app-state []
   (let [initial-state (state/initial-state)
-        document-id (utils/inspect (or (aget js/window "Precursor" "initial-document-id")
-                                       ;; TODO: remove after be is fully deployed
-                                       (long (last (re-find #"document/(.+)$" (.getPath utils/parsed-uri))))))
+        document-id (or (aget js/window "Precursor" "initial-document-id")
+                        ;; TODO: remove after be is fully deployed
+                        (long (last (re-find #"document/(.+)$" (.getPath utils/parsed-uri)))))
         cust (some-> (aget js/window "Precursor" "cust")
                (reader/read-string))
         initial-entities (some-> (aget js/window "Precursor" "initial-entities")


Encode thread, like decode thread, now distinguishes between IOExceptions and other exceptions. Also, all exceptions preface their message string with "clj-mavlink".

--- src/mavlink/core.clj
+++ src/mavlink/core.clj
@@ -1144,8 +1144,9 @@
                     :signing-tuples (:signing-tuples channel)})
         ; shutdown the encode thread normally
         (shutdown-fn nil)
-        (catch IOException e (shutdown-fn (ex-info "IOException occurred, probably due to shutdown of the link."
+        (catch IOException e (shutdown-fn (ex-info "clj-mavlink IOException occurred, probably due to shutdown of the link."
                                                    {:cause :io-exception
+                                                    :thread "Mavlink Decode"
                                                     :exception e})))
         (catch Exception e (shutdown-fn (ex-info "clj-mavlink decode thread Exception"
                                                  {:cause :decode
@@ -1159,6 +1160,10 @@
                          encode-output-link)
         ; shutdown the decode thread normally
         (shutdown-fn nil)
+        (catch IOException e (shutdown-fn (ex-info "clj-mavlink IOException occurred, probably due to shutdown of the link."
+                                                   {:cause :io-exception
+                                                    :thread "Mavlink Encode"
+                                                    :exception e})))
         (catch Exception e (shutdown-fn (ex-info "clj-mavlink encode thread Exception"
                                                  {:cause :encode
                                                   :exception e})))))


Improve db entry for archiving

Improve db entry for archiving

--- src/mdr2/archive.clj
+++ src/mdr2/archive.clj
@@ -34,6 +34,7 @@
             [clojure.java.io :refer [file]]
             [clojure.tools.logging :as log]
             [environ.core :refer [env]]
+            [clj-time.core :as t]
             [me.raynes.fs :as fs]
             [mdr2.production :as prod]
             [mdr2.production.path :as path]
@@ -55,11 +56,12 @@
   (env :archive-other-spool-dir))

 (def ^:private default-job
-  {:verzeichnis ""
-   :archivar "NN"
-   :abholer "NN"
+  {:archivar "Madras2"
+   :abholer ""
    :aktion "save"
-   :transaktions_status "pending"})
+   :transaktions_status "pending"
+   :container_status "ok"
+   :bemerkung ""})

 (defn- container-id
   "Return the name of a archive spool directory for a given
@@ -97,7 +99,8 @@
   [production sektion]
   (let [new-job
         {:verzeichnis (container-id production sektion)
-         :sektion (case sektion :master "master" :dist-master "cdimage")}
+         :sektion (case sektion :master "master" :dist-master "cdimage")
+         :datum (t/now)}
         job (merge default-job new-job)]
     (jdbc/insert! db :container job)))


Layout cosmetics

Layout cosmetics

--- src/mdr2/handler.clj
+++ src/mdr2/handler.clj
@@ -16,21 +16,29 @@
   "Main routes for the application"
   (GET "/" request (views/home request))
   ;; bulk import of productions
-  (GET "/production/upload" request (friend/authenticated
-                                     (views/production-bulk-import-form request)))
-  (POST "/production/upload-confirm" [file :as r] (friend/authenticated
-                                                   (views/production-bulk-import-confirm r file)))
-  (POST "/production/upload" [productions :as r] (friend/authenticated
-                                                  (views/production-bulk-import r productions)))
+  (GET "/production/upload" request
+       (friend/authenticated (views/production-bulk-import-form request)))
+  (POST "/production/upload-confirm" [file :as r]
+        (friend/authenticated (views/production-bulk-import-confirm r file)))
+  (POST "/production/upload" [productions :as r]
+        (friend/authenticated (views/production-bulk-import r productions)))
   ;; individual productions
-  (GET "/production/:id.xml" [id] (friend/authenticated (views/production-xml id)))
-  (GET "/production/:id/upload" [id :as r] (friend/authenticated (views/file-upload-form r id)))
-  (POST "/production/:id/upload" [id file :as r] (friend/authenticated (views/production-add-xml r id file)))
-  (POST "/production/:id/state" [id state :as r] (friend/authenticated (views/production-set-state r id state)))
-  (GET "/catalog" request (friend/authenticated (views/catalog request)))
-  (POST "/catalog/:id" [id library_signature :as r] (friend/authenticated (views/production-catalog r id library_signature)))
-  (GET "/production/:id" [id :as r] (friend/authenticated (views/production r id)))
-  (GET "/production/:id/delete" [id] (friend/authorize #{:admin} (views/production-delete id)))
+  (GET "/production/:id.xml" [id]
+       (friend/authenticated (views/production-xml id)))
+  (GET "/production/:id/upload" [id :as r]
+       (friend/authenticated (views/file-upload-form r id)))
+  (POST "/production/:id/upload" [id file :as r]
+        (friend/authenticated (views/production-add-xml r id file)))
+  (POST "/production/:id/state" [id state :as r]
+        (friend/authenticated (views/production-set-state r id state)))
+  (GET "/catalog" request
+       (friend/authenticated (views/catalog request)))
+  (POST "/catalog/:id" [id library_signature :as r]
+        (friend/authenticated (views/production-catalog r id library_signature)))
+  (GET "/production/:id" [id :as r]
+       (friend/authenticated (views/production r id)))
+  (GET "/production/:id/delete" [id]
+       (friend/authorize #{:admin} (views/production-delete id)))
   ;; auth
   (GET "/login" [] (views/login-form))
   (GET "/logout" req (friend/logout* (response/redirect "/")))
@@ -41,7 +49,7 @@
 (def app
   "Main handler for the application"
   (-> app-routes
-      (friend/authenticate
+      (friend/authenticate
        {:credential-fn (partial creds/bcrypt-credential-fn db/get-user)
         :workflows [(workflows/interactive-form)]
         :unauthorized-handler views/unauthorized})


:paredit-open-round - added handling of special case of cursor behind a comma

--- src/paredit/core.clj
+++ src/paredit/core.clj
@@ -221,7 +221,10 @@
 	                {"(a b|c d)" "(a b (|) c d)"
 	                 "(|)" "((|))"
 	                 "|" "(|)"
-	                 "a|" "a (|)"}]
+	                 "a|" "a (|)"
+	                 "(a |,b)" "(a (|),b)"
+	                 "(a,| b)" "(a, (|) b)"
+	                 "(a,|b)" "(a, (|) b)"}]
 	    #_[")"         :paredit-close-round
 	                {"(a b |c   )" "(a b c)|"
 	                "; Hello,| world!"
@@ -234,7 +237,8 @@
     ]
   ])

-(def *spaces* #{\newline \tab \space \,})
+(def *real-spaces* #{\newline \tab \space})
+(def *extended-spaces* (conj *real-spaces* \,))
 (def *open-brackets* (conj (set "([{") nil)) ; we add nil to the list to also match beginning of text
 (def *close-brackets* (conj (set ")]}") nil)) ; we add nil to the list to also match end of text

@@ -290,15 +294,15 @@
 (defmethod paredit
   :paredit-open-round
   [cmd {:keys [text offset length] :as t}]
-  (println "t:" t)
+  #_(prn "t:" t)
   (if (in-code? text offset)
-    (let [add-pre-space? (not (contains? (into *spaces* *open-brackets*) (previous-char t)))
-          add-post-space? (not (contains? (into *spaces* *close-brackets*) (next-char t)))
+    (let [add-pre-space? (not (contains? (into *real-spaces* *open-brackets*) (previous-char t)))
+          add-post-space? (not (contains? (into *extended-spaces* *close-brackets*) (next-char t)))
           ins-str (str (if add-pre-space? " " "")
                        "()"
                        (if add-post-space? " " ""))
           offset-shift (if add-post-space? -2 -1)]
-      (prn "ins-str:" ins-str)
+      #_(prn "ins-str:" ins-str)
       (-> t (insert ins-str) (shift-offset offset-shift)))
     (-> t (insert "("))))


Upgrade karma to 5.1.0

Upgrade karma to 5.1.0

--- src/deps.cljs
+++ src/deps.cljs
@@ -1,5 +1,5 @@
 {:npm-dev-deps {"shadow-cljs"           "2.10.17"
-                "karma"                 "4.4.1"
+                "karma"                 "5.1.0"
                 "karma-chrome-launcher" "3.1.0"
                 "karma-cljs-test"       "0.1.0"
                 "karma-junit-reporter"  "2.0.1"}}


Whitespace

Whitespace

--- boot/core/src/boot/git.clj
+++ boot/core/src/boot/git.clj
@@ -8,6 +8,7 @@
 (defn dirty?         [] (not (clean?)))
 (defn last-commit    [] (pod/with-call-worker (boot.jgit/last-commit)))
 (defn branch-current [] (pod/with-call-worker (boot.jgit/branch-current)))
+(defn describe       [] (pod/with-call-worker (boot.jgit/describe)))

 (defn ls-files
   [& {:keys [ref untracked]}]
@@ -23,8 +24,3 @@
   []
   (let [fs (util/guard (ls-files :untracked true))]
     (if-not fs (constantly false) #(not (contains? fs (.getPath %))))))
-
-(defn describe
-  []
-  (pod/with-call-worker
-    (boot.jgit/describe)))


add {:synsem {:subcat '()}} to all specs

--- src/babel/english/demo.cljc
+++ src/babel/english/demo.cljc
@@ -79,6 +79,7 @@
   (let [n (if n (Integer. n)
               10)
         spec (if spec (unify spec
+                             {:synsem {:subcat '()}}
                              {:modified false})
                  {:modified false})]
     (filter #(not (nil? %))


Fetch blocks put into memory store.

Fetch blocks put into memory store.

--- src/blocks/store/memory.clj
+++ src/blocks/store/memory.clj
@@ -34,7 +34,8 @@
     [this block]
     (when-let [id (:id block)]
       (or (get @memory id)
-          (let [block' (block/with-stats block {:stored-at (Date.)})]
+          (let [block' (block/with-stats (block/fetch block)
+                                         {:stored-at (Date.)})]
             (swap! memory assoc id block')
             block'))))


Earlier check for existence for repalce/append/prepend.

--- src/cbfg/world-storage.cljs
+++ src/cbfg/world-storage.cljs
@@ -40,19 +40,19 @@
                        (if (and (= op :add) old-sq)
                          (return s1 res
                                  {:opaque opaque :status :exists :key key})
-                         (let [prev-change (when (or cas-check
-                                                     (= op :append)
-                                                     (= op :prepend))
-                                             (get-in s1 [:changes old-sq]))]
-                           (if (and cas-check (not= old-cas (:cas prev-change)))
-                             (return s1 res
-                                     {:opaque opaque :status :wrong-cas :key key})
-                             (if (and (or (= op :replace)
-                                          (= op :append)
-                                          (= op :prepend))
-                                      (not old-sq))
+                         (if (and (or (= op :replace)
+                                      (= op :append)
+                                      (= op :prepend))
+                                  (not old-sq))
+                           (return s1 res
+                                   {:opaque opaque :status :not-found :key key})
+                           (let [prev-change (when (or cas-check
+                                                       (= op :append)
+                                                       (= op :prepend))
+                                               (get-in s1 [:changes old-sq]))]
+                             (if (and cas-check (not= old-cas (:cas prev-change)))
                                (return s1 res
-                                       {:opaque opaque :status :not-found :key key})
+                                       {:opaque opaque :status :wrong-cas :key key})
                                (let [new-cas (gen-cas)
                                      new-val (case op
                                                :add val


fixing construction

fixing construction

--- src/celestial/workflows.clj
+++ src/celestial/workflows.clj
@@ -81,8 +81,8 @@

 (defn run-action
   "Runs an action"
-  [{:keys [actions run-info] :as spec}]
- (let [remote (rconstruct spec) {:keys [action]} run-info]
+  [actions run-info]
+ (let [remote (rconstruct actions run-info) {:keys [action]} run-info]
    (info (<< "setting up task ~{action}"))
    (.setup remote)
    (info (<< "running up task ~{action}"))


Rename DataSource find fn

Rename DataSource find fn

--- src/cfpb/qu/data/source.clj
+++ src/cfpb/qu/data/source.clj
@@ -4,5 +4,5 @@
   (get-datasets [source]) ;; returns a list of all datasets
   (get-metadata [source dataset]) ;; returns the metadata for a dataset
   (get-concept-data [source dataset concept]) ;; returns the data table for a concept
-  (find [source query])
+  (get-results [source query])
   (load-dataset [source definition options]))


fix multiplayer boards to use the new adjacency cell format


reformat cljs.rhino.repl, prep for changes

--- src/clj/cljs/repl/rhino.clj
+++ src/clj/cljs/repl/rhino.clj
@@ -13,38 +13,47 @@
             [cljs.analyzer :as ana]
             [cljs.repl :as repl]
             [cljs.util :as util])
-  (:import java.io.File
-           cljs.repl.IJavaScriptEnv
-           [org.mozilla.javascript Context ScriptableObject]))
+  (:import cljs.repl.IJavaScriptEnv
+           [java.io File Reader]
+           [org.mozilla.javascript Context ScriptableObject
+                                   RhinoException Undefined]))

 (def current-repl-env (atom nil))

 ;;todo - move to core.cljs, using js
-(def ^String bootjs (str "goog.require = function(rule){"
-                         "Packages.clojure.lang.RT[\"var\"](\"cljs.repl.rhino\",\"goog-require\")"
-                         ".invoke(___repl_env, __repl_opts, rule);}"))
+(def ^String bootjs
+  (str "goog.require = function(rule){"
+       "Packages.clojure.lang.RT[\"var\"](\"cljs.repl.rhino\",\"goog-require\")"
+       ".invoke(___repl_env, __repl_opts, rule);}"))
+
+;; =============================================================================
+;; Protocols

 (defprotocol IEval
   (-eval [this env filename line]))

 (extend-protocol IEval
-
-  java.lang.String
+  String
   (-eval [this {:keys [cx scope]} filename line]
     (.evaluateString cx scope this filename line nil))

-  java.io.Reader
+  Reader
   (-eval [this {:keys [cx scope]} filename line]
     (.setOptimizationLevel ^Context cx -1)
-    (.evaluateReader cx scope this filename line nil))
-  )
+    (.evaluateReader cx scope this filename line nil)))
+
+;; =============================================================================
+;; Stacktrace & eval support

 (defmulti stacktrace class)

 (defmethod stacktrace :default [e]
-  (apply str (interpose "\n" (map #(str "        " (.toString %)) (.getStackTrace e)))))
-
-(defmethod stacktrace org.mozilla.javascript.RhinoException [e]
+  (apply str
+    (interpose "\n"
+      (map #(str "        " (.toString %))
+        (.getStackTrace e)))))
+
+(defmethod stacktrace RhinoException [^RhinoException e]
   (.getScriptStackTrace e))

 (defmulti eval-result class)
@@ -54,7 +63,9 @@

 (defmethod eval-result nil [_] "")

-(defmethod eval-result org.mozilla.javascript.Undefined [_] "")
+(defmethod eval-result Undefined [_] "")
+
+;; =============================================================================

 (defn rhino-eval
   [repl-env filename line js]
@@ -69,16 +80,14 @@

 (defn goog-require [repl-env opts rule]
   (when-not (contains? @(:loaded-libs repl-env) rule)
-    (let [repl-env @current-repl-env
-          path (string/replace (comp/munge rule) \. java.io.File/separatorChar)
+    (let [repl-env   @current-repl-env
+          path       (string/replace (comp/munge rule) \. File/separatorChar)
           cljsc-path (str (util/output-directory opts)
                        File/separator (str path ".js"))
-          cljs-path (str path ".cljs")
-          js-path (str "goog/"
-                    (-eval (str "goog.dependencies_.nameToPath['" rule "']")
-                      repl-env
-                      "<cljs repl>"
-                      1))]
+          cljs-path  (str path ".cljs")
+          js-path    (str "goog/"
+                       (-eval (str "goog.dependencies_.nameToPath['" rule "']")
+                         repl-env "<cljs repl>" 1))]
       (let [compiled (io/file cljsc-path)]
         (if (.exists compiled)
           ;; TODO: only take this path if analysis cache is available
@@ -91,40 +100,38 @@
             (if-let [res (io/resource js-path)]
               (with-open [reader (io/reader res)]
                 (-eval reader repl-env js-path 1))
-              (throw (Exception. (str "Cannot find " cljs-path " or " js-path " in classpath")))))))
+              (throw
+                (Exception.
+                  (str "Cannot find " cljs-path
+                       " or " js-path " in classpath")))))))
       (swap! (:loaded-libs repl-env) conj rule))))

 (defn load-javascript [repl-env ns url]
   (let [missing (remove #(contains? @(:loaded-libs repl-env) %) ns)]
     (when (seq missing)
-      (do (try
-            (with-open [reader (io/reader url)]
-              (-eval reader repl-env (.toString url) 1))
-            ;; TODO: don't show errors for goog/base.js line number 105
-            (catch Throwable ex (println (.getMessage ex))))
-          (swap! (:loaded-libs repl-env) (partial apply conj) missing)))))
+      (do
+        (try
+          (with-open [reader (io/reader url)]
+            (-eval reader repl-env (.toString url) 1))
+          ;; TODO: don't show errors for goog/base.js line number 105
+          (catch Throwable ex (println (.getMessage ex))))
+        (swap! (:loaded-libs repl-env) (partial apply conj) missing)))))

 (defn rhino-setup
   ([repl-env] (rhino-setup repl-env nil))
   ([repl-env opts]
-    (let [env (ana/empty-env)
+    (let [env   (ana/empty-env)
           scope (:scope repl-env)]
-      (ScriptableObject/putProperty scope
-        "__repl_opts"
+      (ScriptableObject/putProperty scope "__repl_opts"
         (Context/javaToJS opts scope))
       (repl/load-file repl-env "cljs/core.cljs" opts)
       (swap! (:loaded-libs repl-env) conj "cljs.core")
-      (repl/evaluate-form repl-env
-        env
-        "<cljs repl>"
+      (repl/evaluate-form repl-env env "<cljs repl>"
         '(ns cljs.user))
       (ScriptableObject/putProperty scope
-        "out"
-        (Context/javaToJS *out* scope))
+        "out" (Context/javaToJS *out* scope))
       (binding [ana/*cljs-ns* 'cljs.core]
-        (repl/evaluate-form repl-env
-          env
-          "<cljs repl>"
+        (repl/evaluate-form repl-env env "<cljs repl>"
           '(set! *print-fn* (fn [x] (.write js/out x))))))))

 (defrecord RhinoEnv [loaded-libs]
@@ -152,8 +159,7 @@
     (assert deps "Can't find goog/deps.js in classpath")
     (swap! current-repl-env (fn [old] new-repl-env))
     (ScriptableObject/putProperty scope
-                                  "___repl_env"
-                                  (Context/javaToJS new-repl-env scope))
+      "___repl_env" (Context/javaToJS new-repl-env scope))
     (with-open [r (io/reader base)]
       (-eval r new-repl-env "goog/base.js" 1))
     (-eval bootjs new-repl-env "bootjs" 1)


fox missing arg and remove withFilenamepolicy and replace with temp-directory

--- src/clj/datasplash/core.clj
+++ src/clj/datasplash/core.clj
@@ -66,7 +66,7 @@
           (let [[_ missing-ns] (or (re-find #"call unbound fn: #'([^/]+)/" message)
                                    (re-find #"Unbound: #'([^/]+)/" message)
                                    (re-find #"Can't dynamically bind non-dynamic var: ([^/]+)/" message)
-                                   (re-find #"Unable to resolve spec: :([^/]+)/"))
+                                   (re-find #"Unable to resolve spec: :([^/]+)/" message))
                 ns-to-add (->> trace-elems
                                (filter #(:clojure %))
                                (map :ns)
@@ -1089,8 +1089,11 @@
 (def text-writer-schema
   {:windowed {:docstr "Make windowed writes"
               :action (fn [transform b] (when b (.withWindowedWrites transform )))}
-   :filename-policy {:docstr "Use withFilenamePolicy (see filename-policy fn)"
-                     :action (fn [transform policy] (when policy (.withFilenamePolicy transform policy)))}
+   :temp-directory {:docstr "Use withFilenamePolicy (see filename-policy fn)"
+                    :action (fn [transform prefix] (when prefix
+                                                     (.withTempDirectory
+                                                      transform
+                                                      (.getCurrentDirectory (FileBasedSink/convertToFileResourceIfPossible prefix)))))}
    :num-shards {:docstr "Selects the desired number of output shards (file fragments). 0 to let the system decide (recommended)."
                 :action (fn [transform shards] (.withNumShards transform shards))}
    :without-sharding {:docstr "Forces a single file output."


fixed bug with flipped order of cols and rows.

--- src/clj/forma/reproject.clj
+++ src/clj/forma/reproject.clj
@@ -94,8 +94,8 @@
   within the bounds of an ASCII grid with the supplied step size."
   [step row col]
   (let [[cols rows] (dimensions-for-step step)]
-    (and (>= row 0) (< rows row)
-         (>= col 0) (< cols col))))
+    (and (>= row 0) (< row rows)
+         (>= col 0) (< col cols))))

 (defn modis-indexer
   "Accepts WGS84 coordinates and returns the corresponding `[mod-h,


added commis-dataset

added commis-dataset

--- src/clj/gitomic/reports.clj
+++ src/clj/gitomic/reports.clj
@@ -59,6 +59,12 @@

 (def rails-code-filter #(or (.startsWith % "app/") (.startsWith % "lib/")))

+(defn commit-size-filter [min-size max-size]
+  (fn [commit]
+    (let [size (-> commit :commit/changes count)]
+      (and (>= size min-size)
+           (<= size max-size)))))
+
 (defn temporal-coupling [db repo-name opts]
   (let [r (:db/id (gd/ent db [:repo/name repo-name]))
         churn (pairs->map (query/churn db r))]
@@ -66,6 +72,28 @@
          pairs->map
          (mapcat (partial pair-details churn))
          i/to-dataset)))
+
+(defn changes-summary [commit file-filter]
+  (let [flatten-change (fn [change]
+                         (merge (select-keys (:commit/author commit) [:person/name :person/email])
+                                (select-keys commit [:commit/sha :commit/time])
+                                (select-keys (:change/file change) [:file/path])
+
+                                (if (:change/added change)
+                                  (assoc (select-keys change [:change/added :change/deleted])
+                                    :change/lines (- (:change/added change)
+                                                     (:change/deleted change)))
+                                  {:change/added 0 :change/deleted 0 :change/lines 0})))]
+    (->> commit
+         :commit/changes
+         (filter #(file-filter (-> % :change/file :file/path)))
+         (map flatten-change))))
+
+(defn commits-dataset [db repo-name {:keys [file-filter commit-filter]
+                                     :or {file-filter identity
+                                          commit-filter identity}}]
+  (i/to-dataset (mapcat #(changes-summary % file-filter)
+                        (filter commit-filter (:repo/commits (gd/ent db [:repo/name repo-name]))))))

 (defn coupling-stats [ds]
   {:churn (stats/basic-stats (i/$ :churn ds))


Round indegree

Round indegree

--- src/cljs/db_quiz/model.cljs
+++ src/cljs/db_quiz/model.cljs
@@ -30,12 +30,14 @@
   "Gets limiting indegrees from an exponential distribution.
   `max-count` is the number of instances in the distribution,
   `angle` is the angle of the tangent of the distribution, where the limiting indegree is computed,
-  `b-param` determines the shape of the exponential distribution."
+  `b-param` determines the shape of the exponential distribution.
+  The result is rounded to 2 decimal places."
   (let [b-param (get-in config [:data :sparql :difficulty-distribution :params :b])]
     (fn [max-count angle]
-      (/ (js/Math.log (- (/ (* max-count b-param)
+      (/ (js/Math.round (* (/ (js/Math.log (- (/ (* max-count b-param)
                             (js/Math.tan (degrees->radians angle)))))
-         b-param))))
+                           b-param) 100))
+         100))))

 ; ----- Public functions -----

@@ -53,7 +55,7 @@
                               ; we need to use Virtuoso-specific query parameter `format`.
                               :format "application/sparql-results+json"
                               :query query
-                              :timeout 60000}}))
+                              :timeout 200000}}))

 (defn wrap-load
   [input-channel output-channel]


Refactor event loop up to application; add login form; add session check and authentication event handling.

Login form is not wired up :)

--- src/cljs/om_sente/core.cljs
+++ src/cljs/om_sente/core.cljs
@@ -13,57 +13,108 @@
   (def ch-chsk    ch-recv)
   (def chsk-send! send-fn))

-(def app-state (atom {:text "Hello world!"}))
-
 (defn send-field [e owner state]
   (when (== (.-keyCode e) 13)
-    (chsk-send! [:test/echo (:text state)])
+    (chsk-send! [:test/echo (clojure.string/reverse (:text state))])
     (om/set-state! owner :text "")))

 (defn field-change [e owner state]
   (let [value (.. e -target -value)]
     (om/set-state! owner :text value)))

-(defn field-view [app owner]
+(defn field-view [app owner opts]
   (reify
     om/IInitState
     (init-state [this]
       {:text ""})
     om/IRenderState
     (render-state [this state]
-      (dom/input #js {:ref "data" :type "text" :value (:text state)
+      (dom/input #js {:ref (:name opts) :type (or (:type opts) "text") :value (:text state)
                       :onChange #(field-change % owner state)
                       :onKeyPress #(send-field % owner state)}))))
+
+(defmulti handle-event (fn [event app owner] (first event)))
+
+(defmethod handle-event :test/reply
+  [[_ msg] app owner]
+  (om/set-state! owner :text msg))
+
+(defmethod handle-event :default
+  [_ app owner]
+  nil)
+
+(defmethod handle-event :session/state
+  [[_ state] app owner]
+  (om/update! app [:session/state] state))
+
+(defmethod handle-event :auth/fail
+  [_ app owner]
+  (om/update! app [:notify/error] "Invalid credentials"))
+
+(defmethod handle-event :auth/success
+  [_ app owner]
+  (om/update! app [:notify/error] nil)
+  (om/update! app [:session/state] :secure))
+
+(defn event-loop [app owner]
+  (go (loop []
+        (let [[op arg] (<! ch-chsk)]
+          (case op
+            :chsk/recv (handle-event arg app owner)
+            nil))
+        (recur))))

 (defn data-view [app owner]
   (reify
     om/IInitState
     (init-state [this]
       {:text "none"})
-    om/IWillMount
-    (will-mount [this]
-      (go (loop []
-            (let [[op arg] (<! ch-chsk)]
-              (case op
-                :chsk/recv
-                (let [[ev-id payload] arg]
-                  (case ev-id
-                    :test/reply (om/set-state! owner :text payload)
-                    nil))
-                nil))
-            (recur))))
     om/IRenderState
     (render-state [this {:keys [text]}]
       (dom/div nil text))))

-(defn app-view [app owner]
+(defn login [e app owner]
+  nil)
+
+(defn login-view [app owner]
   (reify
     om/IRender
     (render [this]
-      (dom/div nil
-               (dom/h1 nil "Test Sente")
-               (om/build field-view app {})
-               (om/build data-view app {})))))
+            (dom/div #js {:style {:align "center" :width "25%"}}
+                     (if-let [error (:notify/error app)]
+                       (dom/div #js {:style "color: red;"}
+                                error))
+                     (dom/h1 nil "Login")
+                     (dom/div #js {:style {:width "100%"}}
+                             (dom/p nil "Username")
+                             (om/build field-view app {:opts {:name "username"}}))
+                     (dom/div #js {:style {:width "100%"}}
+                             (dom/p nil "Password")
+                             (om/build field-view app {:opts {:name "password"
+                                                              :type "password"}}))
+                     (dom/div #js {:style {:width "50%" :align "center"}}
+                             (dom/button #js {:onClick #(login % app owner)}
+                                        "Login"))))))
+
+(defn app-view [app owner]
+  (reify
+    om/IWillMount
+    (will-mount [this]
+                (event-loop app owner)
+                (when (= :unknown (:session/state app))
+                  (js/alert "will-mount send session/status query")
+                  (chsk-send! [:session/status])))
+    om/IRender
+    (render [this]
+            (js/alert "render app")
+            (if (= :secure (:session/state app))
+              (dom/div nil
+                       (dom/h1 nil "Test Sente")
+                       (om/build field-view app {:opts {:name "data"}})
+                       (om/build data-view app {}))
+              (om/build login-view app {})))))
+
+(def app-state (atom {:session/state :unknown}))

 (om/root app-view
          app-state


Changed args to #'eval-push and #'run-push

to avoid multiple recursive calls to the functions when only one or two and two or three arguments are passed, respectively.

--- src/clojush/interpreter.clj
+++ src/clojush/interpreter.clj
@@ -53,8 +53,8 @@
   "Executes the contents of the exec stack, aborting prematurely if execution limits are
    exceeded. The resulting push state will map :termination to :normal if termination was
    normal, or :abnormal otherwise."
-  ([state] (eval-push state false false))
-  ([state print-steps] (eval-push state print-steps false))
+  ([state] (eval-push state false false false))
+  ([state print-steps] (eval-push state print-steps false false))
   ([state print-steps trace] (eval-push state print-steps trace false))
   ([state print-steps trace save-state-sequence]
     ;(when (empty? @global-atom-generators)
@@ -108,9 +108,9 @@
    pushing/popping. The resulting push state will map :termination to :normal if termination was
    normal, or :abnormal otherwise."
   ([code state]
-    (run-push code state false false))
+    (run-push code state false false false))
   ([code state print-steps]
-    (run-push code state print-steps false))
+    (run-push code state print-steps false false))
   ([code state print-steps trace]
     (run-push code state print-steps trace false))
   ([code state print-steps trace save-state-sequence]


Removed some testing code.

Removed some testing code.

--- src/clojush/interpreter.clj
+++ src/clojush/interpreter.clj
@@ -45,10 +45,9 @@
               (and (empty? (:exec s)) (empty? (:environment s)))
               (and (not (zero? time-limit))
                    (> (System/nanoTime) time-limit)))
-        (assoc (assoc s :termination (if (and (empty? (:exec s)) (empty? (:environment s)))
-                                       :normal
-                                       :abnormal))
-               :eval-push-iterations iteration)
+        (assoc s :termination (if (and (empty? (:exec s)) (empty? (:environment s)))
+                                :normal
+                                :abnormal))
         (if (empty? (:exec s))
           (let [s (end-environment s)]
             (when print-steps


Push ns-records into user ns

Push ns-records into user ns

--- modules/reitit-core/src/reitit/trie.cljc
+++ modules/reitit-core/src/reitit/trie.cljc
@@ -300,7 +300,8 @@
            (map-parameters keys)
            (let [sym (gensym "PathParams")
                  ctor (symbol (str "map->" sym))]
-             (eval `(do (defrecord ~sym ~(mapv (comp symbol name) keys)) (~ctor {})))))))))
+             (binding [*ns* (find-ns 'user)]
+               (eval `(do (defrecord ~sym ~(mapv (comp symbol name) keys)) (~ctor {}))))))))))

 (defn insert
   "Returns a trie with routes added to it."


Fix displaying source on client side

Fix displaying source on client side

--- src/subman/views.clj
+++ src/subman/views.clj
@@ -28,6 +28,6 @@
                                :ng-repeat "result in results"}
              [:h3
               "{{result.show}} - {{result.name}} (S{{result.season}}E{{result.episode}})"]
-             [:p.pull-right "Source: {{{0: 'Addicted'}[result.source]}}"]
+             [:p.pull-right "Source: {{{0: 'Addicted', 1: 'Podnapisi'}[result.source]}}"]
              [:p "Language: {{result.lang}}"]
              [:p "Version: {{result.version}}"]]]]]))


Make java.net.URL not show up in .cljs.

Make java.net.URL not show up in .cljs.

--- src/zprint/core.cljc
+++ src/zprint/core.cljc
@@ -24,7 +24,8 @@
             [zprint.focus :refer [range-ssv]]
             [rewrite-clj.parser :as p]
             #_[clojure.spec.alpha :as s])
-  (:import (java.net URL URLConnection)
+  (:import
+           #?@(:clj ((java.net URL URLConnection)))
            (java.util.concurrent Executors)
            (java.io File)
            (java.util Date)))


Revised transfer_rdf_list_links_with_nil rule

To reflect updates to list record structure

--- resources/rules/post_identifier_merge/step_b_ontology_to_ice/step_c/transfer_rdf_list_links_with_nil.clj
+++ resources/rules/post_identifier_merge/step_b_ontology_to_ice/step_c/transfer_rdf_list_links_with_nil.clj
@@ -2,10 +2,19 @@
   :description "This rule transfers links to rdf:nil from list members to bio world. These links are
   predominantly '?x rdf:rest rdf/nil'."
   :head ((?/bio_list_member ?/p rdf/nil))
-  :sparql-string "select ?bio_list_member ?p {
-  ?list_record rdf:type ccp:IAO_EXT_0000317 .
-  ?list_record obo:IAO_0000219 ?list_member .
-  ?list_member ?p rdf:nil .
-  ?list_record obo:IAO_0000219 ?bio_list_member .
-  filter (?list_member != ?bio_list_member)
-  }"}+  :sparql-string "prefix franzOption_clauseReorderer: <franz:identity>
+                  prefix franzOption_chunkProcessingAllowed: <franz:yes>
+                  prefix ccp: <http://ccp.ucdenver.edu/obo/ext/>
+                  prefix obo: <http://purl.obolibrary.org/obo/>
+
+                  select ?bio_list_member ?p {
+                  ?list_record rdf:type ccp:IAO_EXT_0000317 .
+                  ?list_record obo:BFO_0000051 ?id_field_value .
+                  ?id_field_value rdf:type ccp:IAO_EXT_0000346 . # ccp:RDF_list_identifier_field_value
+                  ?id_field_value rdf:type ?id .
+                  ?id rdf:type ccp:IAO_EXT_0000354 .
+                  ?id obo:IAO_0000219 ?list_member .
+                  ?list_member ?p rdf:nil .
+                  ?id obo:IAO_0000219 ?bio_list_member .
+                  filter (?list_member != ?bio_list_member && contains(str(?bio_list_member),'http://ccp.ucdenver.edu/obo/ext/'))
+                  }"}


Add lein-nvd plugin

Add lein-nvd plugin

--- .lein/profiles.clj
+++ .lein/profiles.clj
@@ -11,7 +11,8 @@
     [lein-expectations "0.0.8"]
     [lein-autoexpect "1.9.0"]
     [com.jakemccrary/lein-test-refresh "0.14.0"]
-    [lein-ancient "0.6.10"]]
+    [lein-ancient "0.6.10"]
+    [lein-nvd "0.2.3"]]
   :repl-options {
     :timeout 300000}
   :aliases {


Change a comment

Change a comment

--- test/com/nomistech/clojure_the_language/c_200_clojure_basics/s_600_clojure_spec/ss_examples_from_clojure_org.clj
+++ test/com/nomistech/clojure_the_language/c_200_clojure_basics/s_600_clojure_spec/ss_examples_from_clojure_org.clj
@@ -3,10 +3,9 @@
             [midje.sweet :refer :all])
   (:import java.util.Date))

+;;;; Reference: This is mostly stuff from https://clojure.org/guides/spec
+
 ;;;; ___________________________________________________________________________
-;;;; Stuff from https://clojure.org/guides/spec
-
-;;;; _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
 ;;;; Basics

 (fact "Intro to `conform`: spec X value -> value"


Use namespaced keywords on raise unauthorized exception.

--- src/buddy/auth.clj
+++ src/buddy/auth.clj
@@ -34,5 +34,5 @@
   authorization primitive."
   ([] (throw-unauthorized {}))
   ([errordata]
-   (throw+ {:type ::unauthorized
-            :payload errordata})))
+   (throw+ {::type ::unauthorized
+            ::payload errordata})))


remove obsolete test

remove obsolete test

--- test/clj/app_test.clj
+++ test/clj/app_test.clj
@@ -99,16 +99,6 @@

 (deftest get-custom-1
-  (let [facts (lp/with-db *ldb*
-                (ll/run* [q]
-                  (ll/fresh [e a v]
-                    (fl/fact e a v (ll/lvar))
-                    (ll/== e 1)
-                    (ll/== q a))))]
-    (println facts)
-    (is (set facts) #{:user/name :user/birthday :user/gender})))
-
-(deftest get-custom-2
   (let [facts (->> (lp/with-db *ldb*
                      (ll/run* [q]
                        (ll/fresh [e a v]


Add some examples do the foldm docstring

--- src/cats/core.cljc
+++ src/cats/core.cljc
@@ -502,7 +502,32 @@
 (defn foldm
   "Given an optional monadic context, a function that takes two non-monadic
   arguments and returns a value inside the given monadic context, an initial
-  value, and a collection of values, perform a left-associative fold."
+  value, and a collection of values, perform a left-associative fold.
+
+      (require '[cats.context :as ctx]
+               '[cats.core :as m]
+               '[cats.monad.maybe :as maybe])
+
+      (defn m-div [x y]
+        (if (zero? y)
+          (maybe/nothing)
+          (maybe/just (/ x y))))
+
+      (m/foldm m-div 1 [1 2 3])
+      (m/foldm maybe/maybe-monad m-div 1 [1 2 3])
+      ;; => #<Just 1/6>
+
+      (m/foldm maybe/maybe-monad m-div 1 [1 0 3])
+      ;; => #<Nothing>
+
+      (foldm m-div 1 [])
+      ;; => Exception
+
+      (m/foldm maybe/maybe-monad m-div 1 [])
+      (ctx/with-context maybe/maybe-monad
+        (foldm m-div 1 []))
+      ;; => #<Just 1>
+  "
   ([f z xs]
    (if (empty? xs)
      (return (get-current-context) z)


grammar

grammar

--- src/cats/core.cljc
+++ src/cats/core.cljc
@@ -185,8 +185,8 @@
      let. This allows much easy composition of monadic
      computations.

-     Let see one example for understand how it works, this is
-     a code using bind for compose few number of operations:
+     Let's see an example to understand how it works.
+     This code uses bind to compose a few operations:

          (bind (just 1)
                (fn [a]
@@ -195,8 +195,8 @@
                            (return (* b 2))))))
          ;=> #<Just [4]>

-     Now see how this code can be more clear if you
-     are using mlet macro for do it:
+     Now see how this code can be made clearer
+     by using the mlet macro:

          (mlet [a (just 1)
                 b (just (inc a))]


Use mapv and no more merge.

Use mapv and no more merge.

--- src/cbfg/core.cljs
+++ src/cbfg/core.cljs
@@ -132,7 +132,7 @@
 ;; ------------------------------------------------

 (defn assign-position [positions id]
-  (swap! positions #(merge {id (count %)} %)))
+  (swap! positions #(update-in % [id] (fn [v] (if v v (count %))))))

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

@@ -153,20 +153,20 @@
        [])
      "
"
      "
"
-     (map (fn [ch-ch-info]
-            (let [ch-info (second ch-ch-info)
-                  ch-id (:id ch-info)]
-              (assign-position positions ch-id)
-              ["
" ch-id ": " (:msgs ch-info) "
"]))
-          (get actx-ch-ch-infos actx))
+     (mapv (fn [ch-ch-info]
+             (let [ch-info (second ch-ch-info)
+                   ch-id (:id ch-info)]
+               (assign-position positions ch-id)
+               ["
" ch-id ": " (:msgs ch-info) "
"]))
+           (get actx-ch-ch-infos actx))
      "
"
      "
"
      (if (not-empty children)
-       ["
" (map (fn [child-actx-bool]
-                      ["
" (vis-html-actx vis (first child-actx-bool)
-                                             positions actx-ch-ch-infos)
-                       "
"])
-                    children)
+       ["
" (mapv (fn [child-actx-bool]
+                       ["
" (vis-html-actx vis (first child-actx-bool)
+                                              positions actx-ch-ch-infos)
+                        "
"])
+                     children)
         "
"]
        [])
      "
"]))
@@ -180,30 +180,30 @@
    " orient='auto'>"
    " <path d='M 0 0 L 10 5 L 0 10 z'/>"
    "</defs>"
-   (map (fn [actx-actx-info]
-          (let [[actx actx-info] actx-actx-info
-                actx-id (last actx)
-                actx-position (+ 0.5 (get positions actx-id))
-                wait-chs (:wait-chs actx-info)
-                chs (:chs vis)
-                line-height 21
-                stroke-width 1]
-            (map (fn [kv]
-                   (let [[ch wait-kind] kv
-                         ch-info (get chs ch)
-                         ch-id (:id ch-info)
-                         ch-position (+ 0.5 (get positions ch-id))]
-                     (if (= :put wait-kind)
-                       ["<line x1='500' y1='" (* actx-position line-height)
-                        "' x2='600' y2='" (* ch-position line-height)
-                        "' stroke='green' stroke-width='" stroke-width
-                        "' marker-end='url(#triangle)'/>"]
-                       ["<line x1='600' y1='" (* ch-position line-height)
-                        "' x2='500' y2='" (* actx-position line-height)
-                        "' stroke='red' stroke-width='" stroke-width
-                        "' marker-end='url(#triangle)'/>"])))
-                 wait-chs)))
-        (:actxs vis))])
+   (mapv (fn [actx-actx-info]
+           (let [[actx actx-info] actx-actx-info
+                 actx-id (last actx)
+                 actx-position (+ 0.5 (get positions actx-id))
+                 wait-chs (:wait-chs actx-info)
+                 chs (:chs vis)
+                 line-height 21
+                 stroke-width 1]
+             (mapv (fn [kv]
+                     (let [[ch wait-kind] kv
+                           ch-info (get chs ch)
+                           ch-id (:id ch-info)
+                           ch-position (+ 0.5 (get positions ch-id))]
+                       (if (= :put wait-kind)
+                         ["<line x1='500' y1='" (* actx-position line-height)
+                          "' x2='600' y2='" (* ch-position line-height)
+                          "' stroke='green' stroke-width='" stroke-width
+                          "' marker-end='url(#triangle)'/>"]
+                         ["<line x1='600' y1='" (* ch-position line-height)
+                          "' x2='500' y2='" (* actx-position line-height)
+                          "' stroke='red' stroke-width='" stroke-width
+                          "' marker-end='url(#triangle)'/>"])))
+                   wait-chs)))
+         (:actxs vis))])

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


The vis-add-ch helps with first-taker-actx.

--- src/cbfg/core.cljs
+++ src/cbfg/core.cljs
@@ -40,11 +40,16 @@

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

-(defn vis-add-ch [vis ch]
-  (update-in vis [:chs ch]
-             (fn [v] (if (nil? v)
-                       {:id ((:gen-id vis)) :msgs {} :first-taker-actx nil}
-                       v))))
+(defn vis-add-ch [vis ch first-taker-actx]
+  (-> vis
+      (update-in [:chs ch]
+                 #(if (nil? %)
+                    {:id ((:gen-id vis))
+                     :msgs {}
+                     :first-taker-actx first-taker-actx}
+                    %))
+      (update-in [:chs ch :first-taker-actx]
+                 #(if % % first-taker-actx))))

 (def vis-event-handlers
   {"ago"
@@ -69,10 +74,7 @@
            (let [[ch] args]
              (swap! vis #(-> %
                              (assoc-in [:actxs actx :wait-chs ch] :take)
-                             (vis-add-ch ch)
-                             (update-in [:chs ch :first-taker-actx]
-                                        (fn [fta]
-                                          (if fta fta actx)))))))
+                             (vis-add-ch ch actx)))))
     :end (fn [vis actx args]
            (let [[ch msg] args]
              (swap! vis #(-> %
@@ -85,7 +87,7 @@
            (let [[ch msg] args]
              (swap! vis #(-> %
                              (assoc-in [:actxs actx :wait-chs ch] :put)
-                             (vis-add-ch ch)
+                             (vis-add-ch ch nil)
                              (assoc-in [:chs ch :msgs msg] true)))))
     :end (fn [vis actx args]
            (let [[ch msg result] args]
@@ -96,22 +98,15 @@
    "aalts"
    {:beg (fn [vis actx args]
            (let [[ch-bindings] args
-                 ; The actions will be [[ch :take] [ch :put] ...].
-                 actions (map #(if (seq? %) [(first %) :put] [% :take])
-                              ch-bindings)]
-             (doseq [action actions]
-               (swap! vis #(vis-add-ch % (first action)))
-               (swap! vis #(if (= (second action) :take)
-                             (update-in % [:chs (first action) :first-taker-actx]
-                                        (fn [fta]
-                                          (if fta fta actx)))
-                             %)))
-             (swap! vis #(update-in % [:actxs actx :wait-chs]
-                                    (fn [wait-chs] ; Update wait-chs with actions.
-                                      (reduce (fn [acc v]
-                                                (assoc acc (first v) (second v)))
-                                              wait-chs
-                                              actions))))))
+                 ; The ch-actions will be [[ch :take] [ch :put] ...].
+                 ch-actions (map #(if (seq? %) [(first %) :put] [% :take])
+                                 ch-bindings)]
+             (doseq [ch-action ch-actions]
+               (swap! vis #(-> %
+                               (vis-add-ch (first ch-action)
+                                           (if (= (second ch-action) :take) actx nil))
+                               (assoc-in [:actxs actx :wait-chs (first ch-action)]
+                                         (second ch-action)))))))
     :end (fn [vis actx args]
            (let [[ch-bindings result] args
                  chs (map #(if (seq? %) (first %) %) ch-bindings)


fix link to interactive layers post (has to use target="_self")

--- src-cljs/frontend/components/landing.cljs
+++ src-cljs/frontend/components/landing.cljs
@@ -289,7 +289,7 @@
              [:span.content-copy
               "Easily link your wireframes together in minutes to create working demos of your idea.
               You'll save time by pinpointing areas for improvement before you go into development."]]
-            [:a.feature-link {:href "/blog/interactive-layers" :role "button" :title "Read the tutorial."}
+            [:a.feature-link {:href "/blog/interactive-layers" :target "_self" :role "button" :title "Read the tutorial."}
              [:span.content-copy
               "Read the tutorial."]]]
            [:div.feature-media.reverse artwork-interact]]


Capitalization

Capitalization

--- src-cljs/frontend/components/landing.cljs
+++ src-cljs/frontend/components/landing.cljs
@@ -135,7 +135,7 @@
                 :position 3}
    :sincerely {:name "Sincerely"
                :logo ""
-               :quote "We never merge until we get that green checkmark. A pull request without CircleCi is like skydiving without a parachute."
+               :quote "We never merge until we get that green checkmark. A pull request without CircleCI is like skydiving without a parachute."
                :cite "Justin Watt"
                :cite-title "Director of Engineering"
                :cite-avatar "/img/outer/home/justin-watt.png"


reverse the order

reverse the order

--- src-cljs/frontend/components/overlay.cljs
+++ src-cljs/frontend/components/overlay.cljs
@@ -226,7 +226,7 @@
                     :data-placeholder-nil "Type their email"
                     :data-placeholder-forgot "Don't forget to submit"}]]
           [:div.access-list
-           (for [access-entity (sort-by :db/id (concat permissions access-grants access-requests))]
+           (for [access-entity (sort-by (comp - :db/id) (concat permissions access-grants access-requests))]
              (render-access-entity access-entity cast!))]])))))

 (defn public-sharing [app owner]


Update privacy.cljs

Update privacy.cljs

--- src-cljs/frontend/components/privacy.cljs
+++ src-cljs/frontend/components/privacy.cljs
@@ -71,13 +71,13 @@
              "http://www.google.co.uk/intl/en/analytics/privacyoverview.html"}
             "Google Analytics' privacy policy"]
            " discusses how they use this information."]
-         [:li
+          [:li
            [:a {:href "http://hipchat.com/"} "Hipchat"]
            " provides our live support channel, where we discuss support issues with customers. This is a public channel, and we do not ask customers for any private details via Hipchat, and none should ever be volunteered. Hipchat is also used for internal Circle communication. "
            [:a
             {:href "https://www.hipchat.com/privacy"}
             "Hipchat's privacy policy"]
-           " discusses what information they collect, and how they protect our data and yours."]]]
+           " discusses what information they collect, and how they protect our data and yours."]]
          [:h2 "Changelog"]
          [:ul.privacy-changelog
           [:li


Add code and xml filetypes for clojure

Add code and xml filetypes for clojure

--- clojure/cljsearch/src/cljsearch/filetypes.clj
+++ clojure/cljsearch/src/cljsearch/filetypes.clj
@@ -12,9 +12,15 @@
   (:import (java.io File))
   (:require [clojure.java.io :as io])
   (:use [clojure.set :only (union)]
-        [clojure.string :only (split upper-case)]
+        [clojure.string :only (split lower-case)]
         [clojure.xml :only (parse)]
         [cljsearch.fileutil :only (expand-path get-ext)]))
+
+(def ARCHIVE "archive")
+(def BINARY "binary")
+(def CODE "code")
+(def TEXT "text")
+(def XML "xml")

 (defn get-filetypemap []
   (let [ftcontents (slurp (io/resource "filetypes.xml"))
@@ -24,41 +30,70 @@
         extension-nodes (map first (map :content (map first (map :content filetypes))))
         extension-sets (map #(set %) (map #(split % #"\s+") extension-nodes))
         filetypemap (zipmap typenames extension-sets)
-        textmap (hash-map "text"
-                  (union (get filetypemap "text")
-                         (get filetypemap "code")
-                         (get filetypemap "xml")))
+        textmap (hash-map "all-text"
+                  (union (get filetypemap TEXT)
+                         (get filetypemap CODE)
+                         (get filetypemap XML)))
         searchablemap (hash-map "searchable"
-                        (union (get filetypemap "archive")
-                               (get filetypemap "binary")
-                               (get filetypemap "text")))
+                        (union (get filetypemap ARCHIVE)
+                               (get filetypemap BINARY)
+                               (get filetypemap TEXT)))
         ]
   (merge filetypemap textmap searchablemap)))

 (def FILETYPEMAP (get-filetypemap))

-(defn binary-file? [f]
-  (contains? (get FILETYPEMAP "binary") (get-ext f)))
+(defn archive-ext? [ext]
+  (contains? (get FILETYPEMAP ARCHIVE) ext))

 (defn archive-file? [f]
-  (contains? (get FILETYPEMAP "archive") (get-ext f)))
+  (archive-ext? (get-ext f)))
+
+(defn binary-ext? [ext]
+  (contains? (get FILETYPEMAP BINARY) ext))
+
+(defn binary-file? [f]
+  (contains? (get FILETYPEMAP BINARY) (get-ext f)))
+
+(defn code-ext? [ext]
+  (contains? (get FILETYPEMAP CODE) ext))
+
+(defn code-file? [f]
+  (contains? (get FILETYPEMAP CODE) (get-ext f)))

 (defn searchable-file? [f]
   (contains? (get FILETYPEMAP "searchable") (get-ext f)))

+(defn text-ext? [ext]
+  (contains? (get FILETYPEMAP TEXT) ext))
+
 (defn text-file? [f]
-  (contains? (get FILETYPEMAP "text") (get-ext f)))
+  (contains? (get FILETYPEMAP TEXT) (get-ext f)))
+
+(defn xml-ext? [ext]
+  (contains? (get FILETYPEMAP XML) ext))
+
+(defn xml-file? [f]
+  (contains? (get FILETYPEMAP XML) (get-ext f)))

 (defn get-filetype [f]
-  (cond
-    (text-file? f) :text
-    (binary-file? f) :binary
-    (archive-file? f) :archive
-    :else :unknown))
+  (let [ext (get-ext f)]
+    (cond
+      (text-ext? ext) :text
+      (binary-ext? ext) :binary
+      (archive-ext? ext) :archive
+      (code-ext? ext) :code
+      (xml-ext? ext) :xml
+      :else :unknown)))
+
+(defn unknown-file? [f]
+  (= :unknown (get-filetype f)))

 (defn from-name [name]
   (cond
-    (= "TEXT" (upper-case name)) :text
-    (= "BINARY" (upper-case name)) :binary
-    (= "ARCHIVE" (upper-case name)) :archive
+    (= TEXT (lower-case name)) :text
+    (= BINARY (lower-case name)) :binary
+    (= ARCHIVE (lower-case name)) :archive
+    (= CODE (lower-case name)) :code
+    (= XML (lower-case name)) :xml
     :else :unknown))


Always present cue variables in the same order.

Was previously using sets to gather the variables too early, so they
were ending up in the web interface in a random order. Now they are
presented in the order they exist within the cue variable list, as they
are on the Push.

--- src/afterglow/web/routes/show_control.clj
+++ src/afterglow/web/routes/show_control.clj
@@ -246,10 +246,11 @@
   [page-id current-effects]
   (let [last-info (get @clients page-id)
         show (:show last-info)
-        current-vars (set (cue-var-values show current-effects))
-        changes (for [change (filter identity (clojure.set/difference current-vars (:cue-vars last-info)))]
-                  {:cue-var-change change})]
-    (swap! clients update-in [page-id] assoc :cue-vars current-vars)
+        current-vars (cue-var-values show current-effects)
+        changes (filter identity (for [candidate current-vars]
+                                   (when-not ((:cue-vars last-info) candidate)
+                                     {:cue-var-change candidate})))]
+    (swap! clients update-in [page-id] assoc :cue-vars (set current-vars))
     changes))

 (def effect-time-formatter


Fix issues with DJ Link sync

Fix issues with DJ Link sync

But need to complete refactoring to single socket solution before it
actually is usable with the web interface.

Also fixed web interface to log errors since they are really hard to see
in XMLHttpRequest responses.

--- src/afterglow/web/routes/show_control.clj
+++ src/afterglow/web/routes/show_control.clj
@@ -309,7 +309,7 @@
                 :selected (= :manual (:type (show/sync-status)))}]
               (build-sync-list known-midi :midi #(str (:name %) " (MIDI, sync BPM only).")
                                (:source (show/sync-status)))
-              (build-sync-list known-dj :midi #(str (:name %) " (DJ Link Pro, sync BPM and beats).")
+              (build-sync-list known-dj :dj-link #(str % " (DJ Link Pro, sync BPM and beats).")
                                (:source (show/sync-status)))))))

 (defn sync-menu-changes
@@ -474,7 +474,7 @@
                     (recur (rest choices)))))))

           (.startsWith value "dj-link-")
-          (let [id (Long/valueOf (get (clojure.string/split value #"-") 3))]
+          (let [id (Long/valueOf (get (clojure.string/split value #"-") 2))]
             (loop [choices (:known (:dj-link-sync page-info))]
               (if-not (seq choices)
                 {:error (str "Unrecognized DJ Link sync source id: " id)}
@@ -534,45 +534,48 @@
   "Route which reports a user interaction with the show web
   interface."
   [id kind req]
-  (when-let [page-id (Integer/valueOf id)]
-    (if-let [page-info (get @clients page-id)]
-      ;; Found the page tracking information, process the event.
-      (response
-       (cond (.startsWith kind "cue-")
-             (handle-cue-click-event page-info kind)
-
-             (.startsWith kind "cues-")
-             (handle-cue-move-event page-info kind)
-
-             (= kind "link-select")
-             (handle-link-controller-event page-info (get-in req [:params :value]))
-
-             (= kind "choose-sync")
-             (handle-sync-choice-event page-info (get-in req [:params :value]))
-
-             (when-let [[delta metro] (metronome-delta-for-event page-info kind)]
-               (rhythm/metro-adjust metro delta))
-             {:adjusted kind}
-
-             (when-let [[delta metro] (metronome-bpm-delta-for-event page-info kind)]
-               (rhythm/metro-bpm metro (+ (rhythm/metro-bpm metro) delta)))
-             {:adjusted kind}
-
-             (= kind "bpm-slider")
-             (rhythm/metro-bpm (:metronome (:show page-info))
-                               (Float/valueOf (get-in req [:params :value])))
-
-             (= kind "phrase-reset")
-             (do (rhythm/metro-phrase-start (:metronome (:show page-info)) 1)
-                 {:adjusted kind})
-
-             (= kind "tap-tempo")
-             (interpret-tempo-tap page-info)
-
-             ;; We do no recognize this kind of request
-             :else
-             (do
-               (warn "Unrecognized UI event posted:" kind)
-               {:error (str "Unrecognized UI event kind: " kind)})))
-      ;; Found no page tracking information, advise the page to reload itself.
-      (response {:reload "Page ID not found"}))))
+  (try (when-let [page-id (Integer/valueOf id)]
+         (if-let [page-info (get @clients page-id)]
+           ;; Found the page tracking information, process the event.
+           (response
+            (cond (.startsWith kind "cue-")
+                  (handle-cue-click-event page-info kind)
+
+                  (.startsWith kind "cues-")
+                  (handle-cue-move-event page-info kind)
+
+                  (= kind "link-select")
+                  (handle-link-controller-event page-info (get-in req [:params :value]))
+
+                  (= kind "choose-sync")
+                  (handle-sync-choice-event page-info (get-in req [:params :value]))
+
+                  (when-let [[delta metro] (metronome-delta-for-event page-info kind)]
+                    (rhythm/metro-adjust metro delta))
+                  {:adjusted kind}
+
+                  (when-let [[delta metro] (metronome-bpm-delta-for-event page-info kind)]
+                    (rhythm/metro-bpm metro (+ (rhythm/metro-bpm metro) delta)))
+                  {:adjusted kind}
+
+                  (= kind "bpm-slider")
+                  (rhythm/metro-bpm (:metronome (:show page-info))
+                                    (Float/valueOf (get-in req [:params :value])))
+
+                  (= kind "phrase-reset")
+                  (do (rhythm/metro-phrase-start (:metronome (:show page-info)) 1)
+                      {:adjusted kind})
+
+                  (= kind "tap-tempo")
+                  (interpret-tempo-tap page-info)
+
+                  ;; We do no recognize this kind of request
+                  :else
+                  (do
+                    (warn "Unrecognized UI event posted:" kind)
+                    {:error (str "Unrecognized UI event kind: " kind)})))
+           ;; Found no page tracking information, advise the page to reload itself.
+           (response {:reload "Page ID not found"})))
+       (catch Throwable t
+           (warn t "Problem processing web UI event))")
+           (response {:error (str "Unable to process event:" (.getMessage t))}))))


Add support for raw-icon to drawarea.

Add support for raw-icon to drawarea.

--- src/uxbox/main/ui/workspace/drawarea.cljs
+++ src/uxbox/main/ui/workspace/drawarea.cljs
@@ -110,6 +110,7 @@
   (when-let [shape (:drawing @wb/workspace-ref)]
     (case (:type shape)
       :icon (on-init-draw-icon shape)
+      :icon-raw (on-init-draw-icon shape)
       :path (if (:free shape)
               (on-init-draw-free-path shape)
               (on-init-draw-path shape))


Dummy test

Dummy test

--- test/clj_jenkins_api/jenkins_api_test.clj
+++ test/clj_jenkins_api/jenkins_api_test.clj
@@ -24,3 +24,8 @@
     (clojure.test/function? function-name))

+(deftest dummy-test
+    "At least one test result is needed by CI."
+    (testing "Dummy test"
+        (is (= 1 1))))
+


AW + FM | 341 | translation testing automatically includes added languages

--- test/objective8/unit/translation_test.clj
+++ test/objective8/unit/translation_test.clj
@@ -1,7 +1,8 @@
 (ns objective8.unit.translation-test
   (:require [midje.sweet :refer :all]
             [objective8.front-end.translation :as tr]
-            [clojure.algo.generic.functor :as algs]))
+            [clojure.algo.generic.functor :as algs]
+            [clojure.java.io :as io]))

 (def translations-directory "translations")

@@ -11,17 +12,19 @@
 (defn map-of-maps->map-of-sets [lang-map]
   (algs/fmap map->key-set lang-map))

-(tabular
-  (fact "All translation files contain the same entries"
-        (let [languages (tr/load-translations (tr/find-translation-resources translations-directory))
-              en-map (:en languages)
-              lang-map (?language languages)
-              valueless-en-map (map-of-maps->map-of-sets en-map)
-              valueless-lang-map (map-of-maps->map-of-sets lang-map)
-              difference (clojure.data/diff valueless-en-map valueless-lang-map)
-              ]
-          (first difference) => nil
-          ))
-  ?language
-  :es)
+(defn check-diff [map-primary map-secondary]
+  (first (clojure.data/diff map-primary map-secondary)))

+(defn test-languages [en-map other-languages-map]
+  (algs/fmap (partial check-diff en-map) other-languages-map))
+
+(facts "translations"
+      (let [languages (tr/load-translations (tr/find-translation-resources translations-directory))
+            en-map (:en languages)
+            other-languages (dissoc languages :en)
+            lang-seq (keys other-languages)
+            valueless-en-map (map-of-maps->map-of-sets en-map)
+            valueless-other-lang-map (algs/fmap map-of-maps->map-of-sets other-languages)
+            differences (test-languages valueless-en-map valueless-other-lang-map)]
+        differences => (has every? nil?)))
+


[CS] Correctly refernce squishy data-readers

--- dev-src/dev/core.clj
+++ dev-src/dev/core.clj
@@ -10,7 +10,7 @@
             [vip.data-processor.validation.zip :as zip]
             [vip.data-processor.db.postgres :as psql]
             [vip.data-processor.s3 :refer [zip-filename]]
-            [democracyworks.squishy.data-readers]))
+            [squishy.data-readers]))

 (def pipeline
   (concat [psql/start-run


Only run time zone tests in CLJ

Only run time zone tests in CLJ

--- test/hundred_pushups/datetime_test.cljc
+++ test/hundred_pushups/datetime_test.cljc
@@ -19,11 +19,15 @@
   (is (= "19700101T000000Z" (inst->str (inst 0))))
   (is (= "19700112T134640Z" (inst->str (inst 1000000000)))))

-(deftest local-date-test
-  (testing "returns date based on timezone"
-    (is (= 2016
-           (first (local-date #inst "2016-01-02T01:01:01Z"))))
-    (is (= [2016 01 01]
-           (local-date #inst "2016-01-02T01:01:01Z" "America/Denver")))
-    (is (= [2016 01 02]
-           (local-date #inst "2016-01-02T12:01:01Z" "America/Denver")))))
+;; FIXME - you can't set time zones in CLJS
+;; https://github.com/andrewmcveigh/cljs-time/issues/14
+;; so I'm not sure how to test this without breaking CI
+#?(:clj
+   (deftest local-date-test
+     (testing "returns date based on timezone"
+       (is (= 2016
+              (first (local-date #inst "2016-01-02T01:01:01Z"))))
+       (is (= [2016 01 01]
+              (local-date #inst "2016-01-02T01:01:01Z" "America/Denver")))
+       (is (= [2016 01 02]
+              (local-date #inst "2016-01-02T12:01:01Z" "America/Denver"))))))


Increment template version

Increment template version

--- template/project.clj
+++ template/project.clj
@@ -1,4 +1,4 @@
-(defproject play-clj/lein-template "0.3.11"
+(defproject play-clj/lein-template "0.3.11.1"
   :description "A template for making play-clj projects"
   :url "https://github.com/oakes/play-clj"
   :license {:name "Public Domain"


acrive el api moved

acrive el api moved

--- src/etaoin/api.clj
+++ src/etaoin/api.clj
@@ -95,6 +95,26 @@
     [:session (:session @driver)]
     nil
     _))
+
+;;
+;; actice element
+;;
+
+(defmulti get-active-element dispatch-driver)
+
+(defmethod get-active-element :firefox
+  [driver]
+  (with-resp driver :get
+    [:session (:session @driver) :element :active]
+    nil resp
+    (-> resp :value first second)))
+
+(defmethods get-active-element [:chrome :phantom :safari]
+  [driver]
+  (with-resp driver :post
+    [:session (:session @driver) :element :active]
+    nil resp
+    (-> resp :value :ELEMENT)))

 ;;
 ;; windows
@@ -758,26 +778,6 @@
   (with-resp driver :post
     [:session (:session @driver) :accept_alert]
     nil _))
-
-;;
-;; actice element
-;;
-
-(defmulti get-active-element dispatch-driver)
-
-(defmethod get-active-element :firefox
-  [driver]
-  (with-resp driver :get
-    [:session (:session @driver) :element :active]
-    nil resp
-    (-> resp :value first second)))
-
-(defmethods get-active-element [:chrome :phantom :safari]
-  [driver]
-  (with-resp driver :post
-    [:session (:session @driver) :element :active]
-    nil resp
-    (-> resp :value :ELEMENT)))

 ;;
 ;; predicates


properties of logical equivalence

properties of logical equivalence

--- src/latte/prop.clj
+++ src/latte/prop.clj
@@ -263,7 +263,7 @@

 (defthm iff-refl
-  "Reflexivity of equivalence."
+  "Reflexivity of logical equivalence."
   [[A :type]]
   (<=> A A))

@@ -277,3 +277,91 @@
        (have <c> (<=> A A) :by ((<b>) <a> <a>))
        (qed <c>))

+(defthm iff-intro
+  "Introduction rule for logical equivalence."
+  [[A :type] [B :type]]
+  (==> (==> A B)
+       (==> B A)
+       (<=> A B)))
+
+
+(proof iff-intro
+       :script
+       (assume [H1 (==> A B)
+                H2 (==> B A)]
+         (have <a> (==> (==> A B)
+                        (==> B A)
+                        (<=> A B)) :by (and-intro (==> A B) (==> B A)))
+         (have <b> (<=> A B) :by ((<a>) H1 H2))
+         (qed <b>)))
+
+(defthm iff-elim-if
+  "Elimination rule for logical equivalence.
+   This one only keeps the if part of the equivalence."
+  [[A :type] [B :type]]
+  (==> (<=> A B)
+       (==> A B)))
+
+(proof iff-elim-if
+       :script
+       (assume [H (<=> A B)]
+         (have <a> (==> (<=> A B)
+                        (==> A B)) :by (and-elim-left (==> A B) (==> B A)))
+         (have <b> (==> A B) :by ((<a>) H))
+         (qed <b>)))
+
+(defthm iff-elim-only-if
+  "Elimination rule for logical equivalence.
+   This one only keeps the only-if part of the equivalence."
+  [[A :type] [B :type]]
+  (==> (<=> A B)
+       (==> B A)))
+
+(proof iff-elim-only-if
+       :script
+       (assume [H (<=> A B)]
+         (have <a> (==> (<=> A B)
+                        (==> B A)) :by (and-elim-right (==> A B) (==> B A)))
+         (have <b> (==> B A) :by ((<a>) H))
+         (qed <b>)))
+
+
+(defthm iff-sym
+  "Symmetry of logical equivalence."
+  [[A :type] [B :type]]
+  (==> (<=> A B)
+       (<=> B A)))
+
+
+(proof iff-sym
+        :script
+        (assume [H (<=> A B)]
+          (have <a> (==> B A) :by ((iff-elim-only-if A B) H))
+          (have <b> (==> A B) :by ((iff-elim-if A B) H))
+          (have <c> (==> (==> B A)
+                         (==> A B)
+                         (<=> B A)) :by (iff-intro B A))
+          (have <d> (<=> B A) :by ((<c>) <a> <b>))
+          (qed <d>)))
+
+(defthm iff-trans
+  "Transitivity of logical equivalence."
+  [[A :type] [B :type] [C :type]]
+  (==> (<=> A B)
+       (<=> B C)
+       (<=> A C)))
+
+
+(proof iff-trans
+       :script
+       (assume [H1 (<=> A B)
+                H2 (<=> B C)]
+         (have <a> (==> A B) :by ((iff-elim-if A B) H1))
+         (have <b> (==> B C) :by ((iff-elim-if B C) H2))
+         (have <c> (==> A C) :by ((impl-trans A B C) <a> <b>))
+         (have <d> (==> C B) :by ((iff-elim-only-if B C) H2))
+         (have <e> (==> B A) :by ((iff-elim-only-if A B) H1))
+         (have <f> (==> C A) :by ((impl-trans C B A) <d> <e>))
+         (have <g> (<=> A C) :by ((iff-intro A C) <c> <f>))
+         (qed <g>)))
+


We send the flash as HTML.

We send the flash as HTML.

--- src-cljs/frontend/components/header.cljs
+++ src-cljs/frontend/components/header.cljs
@@ -119,7 +119,7 @@
          [:div
           [:div
            (when flash
-             [:div#flash flash])]
+             [:div#flash {:dangerouslySetInnerHTML {:__html flash}}])]
           ;; TODO: Temporary hack until new header ships
           [:div.navbar.navbar-default.navbar-static-top {:class (case nav-point
                                                                   :language-landing