Coercion performance

Coercion performance

--- perf-test/clj/reitit/coercion_perf_test.clj
+++ perf-test/clj/reitit/coercion_perf_test.clj
@@ -6,11 +6,11 @@
             [spec-tools.core :as st]
             [muuntaja.middleware :as mm]
             [muuntaja.core :as m]
-            [muuntaja.format.jsonista :as jsonista-format]
             [jsonista.core :as j]
             [reitit.ring.coercion :as rrc]
             [reitit.coercion.spec :as spec]
             [reitit.coercion.schema :as schema]
+            [reitit.coercion.malli :as malli]
             [reitit.coercion :as coercion]
             [reitit.ring :as ring]))

@@ -173,15 +173,14 @@

 (defn json-perf-test []
   (title "json")
-  (let [m (m/create (jsonista-format/with-json-format m/default-options))
-        app (ring/ring-handler
+  (let [app (ring/ring-handler
               (ring/router
                 ["/plus" {:post {:handler (fn [request]
                                             (let [body (:body-params request)
                                                   x (:x body)
                                                   y (:y body)]
                                               {:status 200, :body {:result (+ x y)}}))}}]
-                {:data {:middleware [[mm/wrap-format m]]}}))
+                {:data {:middleware [mm/wrap-format]}}))
         request {:request-method :post
                  :uri "/plus"
                  :headers {"content-type" "application/json"}
@@ -196,15 +195,14 @@

 (defn schema-json-perf-test []
   (title "schema-json")
-  (let [m (m/create (jsonista-format/with-json-format m/default-options))
-        app (ring/ring-handler
+  (let [app (ring/ring-handler
               (ring/router
                 ["/plus" {:post {:responses {200 {:body {:result Long}}}
                                  :parameters {:body {:x Long, :y Long}}
                                  :handler (fn [request]
                                             (let [body (-> request :parameters :body)]
                                               {:status 200, :body {:result (+ (:x body) (:y body))}}))}}]
-                {:data {:middleware [[mm/wrap-format m]
+                {:data {:middleware [mm/wrap-format
                                      rrc/coerce-request-middleware
                                      rrc/coerce-response-middleware]
                         :coercion schema/coercion}}))
@@ -234,6 +232,7 @@
                         :coercion schema/coercion}}))
         request {:request-method :post
                  :uri "/plus"
+                 :muuntaja/request {:format "application/json"}
                  :body-params {:x 1, :y 2}}
         call (fn [] (-> request app :body))]
     (assert (= {:result 3} (call)))
@@ -241,6 +240,7 @@
     ;; 0.23µs (no coercion)
     ;; 12.8µs
     ;;  1.9µs (cached coercers)
+    ;;  2.5µs (real json)
     (cc/quick-bench
       (call))))

@@ -258,11 +258,13 @@
                         :coercion spec/coercion}}))
         request {:request-method :post
                  :uri "/plus"
+                 :muuntaja/request {:format "application/json"}
                  :body-params {:x 1, :y 2}}
         call (fn [] (-> request app :body))]
     (assert (= {:result 3} (call)))

     ;;  6.0µs
+    ;; 30.0µs (real json)
     (cc/quick-bench
       (call))))

@@ -287,17 +289,45 @@
                         :coercion spec/coercion}}))
         request {:request-method :post
                  :uri "/plus"
+                 :muuntaja/request {:format "application/json"}
                  :body-params {:x 1, :y 2}}
         call (fn [] (-> request app :body))]
     (assert (= {:result 3} (call)))

     ;;  3.2µs
+    ;; 13.0µs (real json)
+    (cc/quick-bench
+      (call))))
+
+(defn malli-perf-test []
+  (title "malli")
+  (let [app (ring/ring-handler
+              (ring/router
+                ["/plus" {:post {:responses {200 {:body [:map [:result int?]]}}
+                                 :parameters {:body [:map [:x int?] [:y int?]]}
+                                 :handler (fn [request]
+                                            (let [body (-> request :parameters :body)]
+                                              {:status 200, :body {:result (+ (:x body) (:y body))}}))}}]
+                {:data {:middleware [rrc/coerce-request-middleware
+                                     rrc/coerce-response-middleware]
+                        :coercion malli/coercion}}))
+        request {:request-method :post
+                 :uri "/plus"
+                 :muuntaja/request {:format "application/json"}
+                 :body-params {:x 1, :y 2}}
+        call (fn [] (-> request app :body))]
+    (assert (= {:result 3} (call)))
+
+    ;;  1.2µs (real json)
     (cc/quick-bench
       (call))))

 (comment
   (json-perf-test)
   (schema-json-perf-test)
-  (schema-perf-test)
-  (data-spec-perf-test)
-  (spec-perf-test))
+
+  (do
+    (schema-perf-test)
+    (data-spec-perf-test)
+    (spec-perf-test)
+    (malli-perf-test)))


test(paredit): fix broken tests

test(paredit): fix broken tests


add :excludes option, fix bikeshed issues

--- src/leiningen/jslint.clj
+++ src/leiningen/jslint.clj
@@ -46,6 +46,7 @@
 (defn- config [project] (opt project :config {}))
 (defn- config-file [project] (opt project :config-file DEF_CONFIG_FILE))
 (defn- include-files [project] (find-files (vec (opt project :includes nil))))
+(defn- exclude-files [project] (find-files (vec (opt project :excludes nil))))

 ; Internal API: Runner
@@ -54,24 +55,37 @@
   (json/generate-string
    (merge (config project) DEF_CONFIG)))

+(defn- sources-list [project args]
+  (let [includes (include-files project)
+        sources (remove empty? (concat (apply vec args) includes))
+        excludes (apply hash-set (exclude-files project))
+        target (remove (fn [x] (or (empty? x)
+                                   (contains? excludes x))) sources)]
+    (if (empty? target)
+      (do
+        (println "No JS files specified.")
+        (main/abort))
+      target)))
+
 (defn- invoke [project & args]
   (process/exec
    (project :root)
    (cons "jslint" args)))

-(defn- proc [project]
+(defn- proc [project & args]
   (try
     (npm/environmental-consistency project)
     (let [file (config-file project)
           content (generate-config-file project)
-          includes (include-files project)]
+          sources (sources-list project args)]
       (npm/with-json-file file content project
-                          (apply invoke project includes)))
+                          (apply invoke project sources)))
     (catch Throwable t
-      (println (joine (str "Can't execute jslint application: " (.getMessage t))
-                      "Check that JSLint is:"
-                      " - installed correctly: npm install jslint -g"
-                      " - configured correctly: https://github.com/vbauer/lein-jslint.git"))
+      (println
+       (joine (str "Can't execute jslint application: " (.getMessage t))
+              "Something is wrong:"
+              " - installation: npm install jslint -g"
+              " - configuration: https://github.com/vbauer/lein-jslint"))
       (main/abort))))

@@ -83,7 +97,7 @@
   [project & args]
   (if (= args ["help"])
     (println (help/help-for "jslint"))
-    (proc project)))
+    (proc project args)))

 ; External API: Hooks


Playing around and cleaning up old stuff.

--- test/sc_examples.clj
+++ test/sc_examples.clj
@@ -1,5 +1,5 @@
 (ns sc-examples
-  (:use (overtone sc synth time pitch rhythm)
+  (:use overtone
      clojure.contrib.seq-utils
      clj-backtrace.repl))

@@ -12,9 +12,17 @@
 (def TICK (/ (/ 60000 BPM) 4))

 (defsynth sin-chord {:out 0 :pitch 52 :dur 500 :amp 0.2}
-  (out.ar :out (+ (* :amp (sin-osc.ar (midicps :pitch)))
-                  (* :amp (sin-osc.ar (midicps (+ :pitch 4))))
-                  (* :amp (sin-osc.ar (midicps (+ :pitch 7)))))))
+  (let [dur-half (/ (/ :dur 1000.0) 2)
+        env (env-gen.ar (perc dur-half dur-half) :done-free)]
+  (out.ar :out (* env :amp (+ (sin-osc.ar (midicps :pitch))
+                              (sin-osc.ar (midicps (+ :pitch 4)))
+                              (sin-osc.ar (midicps (+ :pitch 7))))))))
+
+(defn chords [t n]
+  (hit t sin-chord :pitch (choose [52 55 57 61 63]) :amp 0.2 :dur 500)
+  (callback (+ (now) 260) #'chords (+ t 125) n))
+
+(chords (now) [52 57 59 64])

 (def hat-buf (load-sample "/home/rosejn/projects/overtone/instruments/samples/kit/open-hat.wav"))

@@ -38,7 +46,7 @@
         (if note
           (hit (+ (* i TICK) t) (inst voices)))))))

-;(play-beat house-drums house-beat 500)
+(play-beat house-drums house-beat 500)

 (defn beats [t cnt]
   (cond
@@ -64,7 +72,7 @@
     (hit (now) "sin" :pitch (+ 20 start (- (rand-int 6) 3)) :dur (* 0.1 (+ 1 (rand-int 2)))))
   (callback (+ 500 (now)) #'sin-man start))

-;(sin-man 40)
+(sin-man 40)

 ;(defn forever [tick pat cur]
 ;  (lazy-seq


add =number? predicate

add =number? predicate

--- stuf/src/sandbox/deriv.clj
+++ stuf/src/sandbox/deriv.clj
@@ -1,4 +1,7 @@
 (ns sandbox.deriv)
+
+(defn =number? [exp num]
+  (and (number? exp) (= exp num)))

 (defn variable? [x] (symbol? x))
 (defn same-variable? [v1 v2]


Fix syntax error in tests

Fix syntax error in tests

I guess this shows how often people run the tests.

--- test/foreclojure/test/users.clj
+++ test/foreclojure/test/users.clj
@@ -2,7 +2,7 @@
   (:use [foreclojure.users])
   (:use [clojure.test])
   (:use [midje.sweet])
-  (:use [somnium.congomongo :only [update!]))
+  (:use [somnium.congomongo :only [update!]]))

 (def users [{:user "user1", :solved [1 2 3 4] :rank 1}
               {:user "user2", :solved [1 2 3] :rank 2}


Replace deprecated core/execute-step function with the current alternative

--- test/lambdacd_git/core_test.clj
+++ test/lambdacd_git/core_test.clj
@@ -6,12 +6,12 @@
             [lambdacd.state.internal.pipeline-state-updater :as pipeline-state-updater]
             [lambdacd.state.core :as state-core]
             [lambdacd-git.test-utils :refer [str-containing some-ctx-with]]
-            [lambdacd.core :as lambdacd-core]
             [lambdacd.presentation.pipeline-state :as presentation-state]
             [clojure.java.io :as io]
             [lambdacd.event-bus :as event-bus]
             [ring.mock.request :as ring-mock]
-            [lambdacd-git.test-utils :as test-utils])
+            [lambdacd-git.test-utils :as test-utils]
+            [lambdacd.execution.core :as execution-core])
   (:import (java.util.concurrent TimeoutException)))

 (defmacro flaky-testing [title & body]
@@ -93,8 +93,8 @@
 (defn execute-pipeline-step [state step]
   (clear-channel (:step-status-channel @state))
   (let [future (future
-                 (let [execute-step-result (lambdacd-core/execute-step {} (:ctx @state)
-                                                                       step)]
+                 (let [execute-step-result (execution-core/execute-step {} (:ctx @state)
+                                                                        step)]
                    (first (vals (:outputs execute-step-result)))))]
     (swap! state #(assoc % :step-future future))
     state))


fix commit weirdness

fix commit weirdness

--- test/metabase/api/user_test.clj
+++ test/metabase/api/user_test.clj
@@ -122,7 +122,7 @@

 ;; ## PUT /api/user/:id/password
 ;; Test that a User can change their password
-(expect-eval-actual-first (sel :one :fields [Session :id] (order :created_at :desc)) ; latest Session in the DB
+(expect-eval-actual-first (sel :one :fields [Session :id] (order :created_at :desc)) ; get the latest Session from the DB
   (let [password {:old "password"
                   :new "new_password"}
         {:keys [email id] :as user} (create-user :password (:old password))


All tests executing.

All tests executing.

It appears that if you nest fact/facts midje will skip over them.

/cc @loganlinn

--- test/poky/kv/jdbc/util_test.clj
+++ test/poky/kv/jdbc/util_test.clj
@@ -52,36 +52,35 @@
                                         (jdbc-delete @@S bucket "key1")
                                         (jdbc-delete @@S bucket "key2")))]
     (facts :integration :jdbc-mget
-      (fact "basic mget"
-        (jdbc-mget @@S bucket [{:key "key1"} {:key "key2"}])
-        => (just
-             (contains {:key "key1"})
-             (contains {:key "key2"})
-             :in-any-order))
+      ;basic mget
+      (jdbc-mget @@S bucket [{:key "key1"} {:key "key2"}])
+      => (just
+           (contains {:key "key1"})
+           (contains {:key "key2"})
+           :in-any-order)

-      (facts "empty results"
-        (jdbc-mget @@S bucket []) => empty?
-        (jdbc-mget @@S bucket [{}]) => empty?
-        (jdbc-mget @@S bucket [{:key "unknown-key"}]) => empty?)
+      ;empty results
+      (jdbc-mget @@S bucket []) => empty?
+      (jdbc-mget @@S bucket [{}]) => empty?
+      (jdbc-mget @@S bucket [{:key "unknown-key"}]) => empty?

-      (facts "modified_at"
-        (let [key1-ts (-> (jdbc-get @@S bucket "key1") :modified_at)
-              key1-ts-invalid (java.sql.Timestamp. (+ (.getTime key1-ts) 36000))
-              key2-ts (-> (jdbc-get @@S bucket "key2") :modified_at)]
-          (fact "valid"
-            (jdbc-mget @@S bucket [{:key "key1" :modified_at key1-ts}]) => (just (contains {:key "key1"})))
-          (fact "invalid"
-            (jdbc-mget @@S bucket [{:key "key1" :modified_at key1-ts-invalid}]) => empty?)
-          (fact "invalid + valid"
-            (jdbc-mget @@S bucket [{:key "key1" :modified_at key1-ts-invalid}
-                                   {:key "key2" :modified_at key2-ts}]) => (just (contains {:key "key2"})))))))
+      ;modified_at
+      (let [key1-ts (-> (jdbc-get @@S bucket "key1") :modified_at)
+            key1-ts-invalid (java.sql.Timestamp. (+ (.getTime key1-ts) 36000))
+            key2-ts (-> (jdbc-get @@S bucket "key2") :modified_at)]
+        ;valid
+        (jdbc-mget @@S bucket [{:key "key1" :modified_at key1-ts}]) => (just (contains {:key "key1"}))
+        ;invalid
+        (jdbc-mget @@S bucket [{:key "key1" :modified_at key1-ts-invalid}]) => empty?
+        ;invalid + valid
+        (jdbc-mget @@S bucket [{:key "key1" :modified_at key1-ts-invalid}
+                               {:key "key2" :modified_at key2-ts}]) => (just (contains {:key "key2"}))))

     (facts :integration :jdbc-mset
-      (fact "single set"
-        (jdbc-mset @@S bucket [{:key "key1" :data "data1"}]) => (just "inserted"))
-      (fact "multi set"
-        (let [key1-ts (util/http-date->Timestamp "Sat, 29 Jun 2013 22:43:43 GMT")]
-         (jdbc-mset @@S bucket [{:key "key1" :data "data1" :modified_at key1-ts}
-                                 {:key "key2" :data "data2"}]) => (just "inserted" "inserted")
-         (jdbc-get @@S bucket "key1") => (contains {:bucket bucket :key "key1" :data "data1" :modified_at key1-ts})
-         (jdbc-get @@S bucket "key2") => (contains {:bucket bucket :key "key2" :data "data2"})))))
+      (jdbc-mset @@S [{:bucket bucket :key "key1" :data "data1"}]) => (contains {:upsert_kv_data "updated"})
+
+      (let [key1-ts (util/http-date->Timestamp "Sat, 29 Jun 2013 22:43:43 GMT")]
+        (jdbc-mset @@S [{:bucket bucket :key "key1" :data "data1" :modified_at key1-ts}
+                        {:bucket bucket :key "key2" :data "data2"}]) => (list {:upsert_kv_data "rejected"} {:upsert_kv_data "updated"})
+        (jdbc-get @@S bucket "key1") => (contains {:bucket bucket :key "key1" :data "data1"})
+        (jdbc-get @@S bucket "key2") => (contains {:bucket bucket :key "key2" :data "data2"})))))


Added products xml search example for tupelo.forest

--- test/tst/tupelo/forest_examples.cljc
+++ test/tst/tupelo/forest_examples.cljc
@@ -522,7 +522,6 @@
                   </data> " )
 (dotest
   (with-forest (new-forest)
-    ; (let-spy-pretty
     (let [enlive-tree          (->> xml-str-prod
                                  java.io.StringReader.
                                  en-html/html-resource
@@ -541,7 +540,6 @@
           tree-2               (hid->hiccup root-hid)

           product-hids         (find-hids root-hid [:** :product])
-          product-trees        (mapv hid->tree product-hids)
           product-trees-hiccup (mapv hid->hiccup product-hids)

           img2-paths           (find-paths-leaf root-hid [:data :products :product :images :image] "img2.jpg")
@@ -553,8 +551,8 @@
           red-prod-paths       (mapv #(drop-last 1 %) red-sect-paths)
           red-prod-hids        (mapv last red-prod-paths)
           red-trees-hiccup     (mapv hid->hiccup red-prod-hids)]
-     (spyx-pretty tree-1)
-     (spyx-pretty tree-2)
+     ;(spyx-pretty tree-1)
+     ;(spyx-pretty tree-2)
      (is= product-trees-hiccup
        [[:product
          [:section "Red Section"]
@@ -570,23 +568,23 @@
          [:section "Green Section"]
          [:images
           [:image "img.jpg"]
-          [:image "img2.jpg"]]]] )
-
-    (is= img2-trees-hiccup
-      [[:product
-        [:section "Red Section"]
-        [:images
-         [:image "img.jpg"]
-         [:image "img2.jpg"]]]
-       [:product
-        [:section "Green Section"]
-        [:images
-         [:image "img.jpg"]
-         [:image "img2.jpg"]]]])
-
-    (is= red-trees-hiccup
-      [[:product
-        [:section "Red Section"]
-        [:images
-         [:image "img.jpg"]
-         [:image "img2.jpg"]]]]))))
+          [:image "img2.jpg"]]]])
+
+      (is= img2-trees-hiccup
+        [[:product
+          [:section "Red Section"]
+          [:images
+           [:image "img.jpg"]
+           [:image "img2.jpg"]]]
+         [:product
+          [:section "Green Section"]
+          [:images
+           [:image "img.jpg"]
+           [:image "img2.jpg"]]]])
+
+      (is= red-trees-hiccup
+        [[:product
+          [:section "Red Section"]
+          [:images
+           [:image "img.jpg"]
+           [:image "img2.jpg"]]]]))))


added reification handling for the cardinality restriction

also added the chunkProcessingAllowed magic prefix to see if it helps

--- kabob-build/src/main/resources/edu/ucdenver/ccp/kabob/build/rules/temp/irefweb/temp/binary.clj
+++ kabob-build/src/main/resources/edu/ucdenver/ccp/kabob/build/rules/temp/irefweb/temp/binary.clj
@@ -84,10 +84,13 @@
                  :ns "kbio" :prefix "R_"}]
           [?/r2 {:ln (:restriction)
                  :ns "kbio" :prefix "R_"}]
+          [?/rcard {:ln (:restriction)
+                 :ns "kbio" :prefix "R_"}]
           [?/protein1_sc {:ln (:sha-1 ?/interaction ?/protein1)
                           :ns "kbio" :prefix "P_"}]
           [?/protein2_sc {:ln (:sha-1 ?/interaction ?/protein2)
                           :ns "kbio" :prefix "P_"}])

-  :options {:magic-prefixes [["franzOption_clauseReorderer" "franz:identity"]]}
+  :options {:magic-prefixes [["franzOption_clauseReorderer" "franz:identity"]
+                             ["franzOption_chunkProcessingAllowed" "franz:yes"]]}
   }


Update verification email copy.

Update verification email copy.

--- src/oc/email/content.clj
+++ src/oc/email/content.clj
@@ -49,7 +49,7 @@
 (def reset-button-text "reset_password")

 (def verify-message "Please verify your email")
-(def verify-instructions "Welcome to Carrot! Carrot helps leaders rise above noisy chat and email to keep teams aligned.")
+(def verify-instructions "Welcome to Carrot! Carrot keeps fast-growing and remote teams on the same page.")
 (def verify-instructions-2 "Please click the link below to verify your account:")
 (def verify-button-text "verify_email")


Change digest copy, add go to digest button.

--- src/oc/email/content.clj
+++ src/oc/email/content.clj
@@ -258,14 +258,19 @@
   (let [board-name (:name board)]
     (assoc board :posts (map #(assoc % :board-name board-name) (:posts board)))))

+(defn- weekly-digest? [digest-data]
+  (or (= "weekly" (:digest-frequency digest-data))
+      (= :weekly (:digest-frequency digest-data))))
+
 (defn- digest-content [digest]
   (let [logo-url (:logo-url digest)
         logo? (not (s/blank? logo-url))
-        weekly? (= "weekly" (:digest-frequency digest))
+        weekly? (weekly-digest? digest)
         org-name (:org-name digest)
-        title (if weekly? (str org-name " Weekly Digest") (str org-name " Daily Digest"))
+        title (if weekly? "Your weekly brief" "Your morning brief")
         boards (map posts-with-board-name (:boards digest))
-        posts (mapcat :posts boards)]
+        posts (mapcat :posts boards)
+        digests-url (s/join "/" [config/web-url (:org-slug digest) "all-posts"])]
     [:td {:class "small-10 large-8 columns"}
       (spacer 40)
       (when logo? (org-logo {:org-name (:org-name digest)
@@ -274,6 +279,8 @@
                              :org-logo-height (:logo-height digest)}))
       (when logo? (spacer 40))
       (h1 title)
+      (spacer 20)
+      (left-button "Go to digest" digests-url)
       (mapcat post posts)
       (spacer 73)]))

@@ -433,7 +440,7 @@
                   :digest (digest-content data))
                 [:td {:class "small-1 large-2 columns"}]]]
             (case type
-              :digest (digest-footer (= "daily" (:digest-frequency data)))
+              :digest (digest-footer (not (weekly-digest? data)))
               (simple-footer))]]]]))

 (defn- head [data]


isolating stages, giving a key to each stage of the pipeline

--- src/ophion/aggregate.clj
+++ src/ophion/aggregate.clj
@@ -303,13 +303,18 @@

 (defn assemble-stages
   [stages queries]
-  (reduce
-   (fn [outs [key query]]
-     (map
-      (fn [out stage]
-        (assoc out key query))
-      outs query))
-   (map (fn [_] {}) stages) queries))
+  (into
+   {}
+   (map
+    vector
+    stages
+    (reduce
+     (fn [outs [key query]]
+       (map
+        (fn [out stage]
+          (assoc out key stage))
+        outs query))
+     (map (fn [_] {}) stages) queries))))

 (defn aggregate
   [spec]
@@ -486,3 +491,46 @@

 ;; [{:$group {:_id {:$multiply [100000 {:$ceil {:$divide ["$end" 100000]}}]} :count {:$sum 1}}} {:$sort {"_id" -1}}]

+[{:start
+  [[{:$bucketAuto
+     {:groupBy "$start",
+      :buckets 100}}]
+   {:$map
+    {:input [1 5 70 85],
+     :as "index",
+     :in
+     {:percentile "$$index",
+      :start {:$arrayElemAt ["$start" "$$index"]}}}}
+   {:$map
+    {:input "$start",
+     :as "index",
+     :in
+     {:percentile "$$index.percentile",
+      :start "$$index.start._id.max"}}}],
+  :end
+  [[{:$group
+     {:_id
+      {:$multiply
+       [1000000
+        {:$ceil
+         {:$divide
+          ["$end" 1000000]}}]},
+      :count {:$sum 1}}}
+    {:$sort {"_id" -1}}]
+   "$end"
+   "$end"],
+  :chromosome
+  [[{:$sortByCount "$chromosome"}
+    {:$limit 11}]
+   "$chromosome"
+   "$chromosome"]}
+ {:start
+  [[{:$bucketAuto
+     {:groupBy "$start",
+      :buckets 100}}]
+   {:$map
+    {:input [1 5 70 85],
+     :as "index",
+     :in
+     {:percentile "$$index",
+      :start {:$arrayElemAt ["$start" "$$index"]}}}} {:$map {:input "$start", :as "index", :in {:percentile "$$index.percentile", :start "$$index.start._id.max"}}}], :end [[{:$group {:_id {:$multiply [1000000 {:$ceil {:$divide ["$end" 1000000]}}]}, :count {:$sum 1}}} {:$sort {"_id" -1}}] "$end" "$end"], :chromosome [[{:$sortByCount "$chromosome"} {:$limit 11}] "$chromosome" "$chromosome"]} {:start [[{:$bucketAuto {:groupBy "$start", :buckets 100}}] {:$map {:input [1 5 70 85], :as "index", :in {:percentile "$$index", :start {:$arrayElemAt ["$start" "$$index"]}}}} {:$map {:input "$start", :as "index", :in {:percentile "$$index.percentile", :start "$$index.start._id.max"}}}], :end [[{:$group {:_id {:$multiply [1000000 {:$ceil {:$divide ["$end" 1000000]}}]}, :count {:$sum 1}}} {:$sort {"_id" -1}}] "$end" "$end"], :chromosome [[{:$sortByCount "$chromosome"} {:$limit 11}] "$chromosome" "$chromosome"]} {:$project {:_id false}}]


Add a layer implementation of stop markers

--- src/cljs/gtfve/components/maps_canvas/google.cljs
+++ src/cljs/gtfve/components/maps_canvas/google.cljs
@@ -45,6 +45,32 @@
     (render [_]
       (html [:noscript (pr-str data)]))))

+(defn stops-layer
+  "Takes data as a list of stops and renders it to gmap in state."
+  [data owner]
+  (reify
+    om/IDisplayName (display-name [_] "Stops Layer")
+    om/IWillMount
+    (will-mount [_]
+      (let [gmap (om/get-state owner :gmap)
+            marker-fn (fn [stop]
+                        (maps/marker [(:stop/latitude stop)
+                                      (:stop/longitude stop)]))
+            markers (mapv marker-fn data)]
+        (om/set-state! owner :markers markers)))
+    om/IDidMount
+    (did-mount [_]
+      (let [{:keys [gmap markers]} (om/get-state owner)]
+        (doseq [marker markers]
+          (.setMap marker gmap))))
+    om/IWillUnmount
+    (will-unmount [_]
+      (let [{:keys [markers]} (om/get-state owner)]
+        (doseq [marker markers]
+          (.setMap marker nil))))
+    om/IRender
+    (render [_]
+      (html [:noscript]))))

 (defn search-stop-marker [data owner]
   (reify


Make Clojure LibGDX code more idiomatic

Make Clojure LibGDX code more idiomatic

--- src/clojure/leiningen/new/libgdx_clojure/core.clj
+++ src/clojure/leiningen/new/libgdx_clojure/core.clj
@@ -5,26 +5,25 @@
            [com.badlogic.gdx.scenes.scene2d Stage]
            [com.badlogic.gdx.scenes.scene2d.ui Label Label$LabelStyle]))

-(declare ^Stage stage)
-
 (def main-screen
-  (proxy [Screen] []
-    (show []
-      (def stage (Stage.))
-      (let [style (Label$LabelStyle. (BitmapFont.) (Color. 1.0 1.0 1.0 1.0))
-            label (Label. "Hello world!" style)]
-        (.addActor stage label)))
-    (render [delta]
-      (.glClearColor (Gdx/gl) 0 0 0 0)
-      (.glClear (Gdx/gl) GL20/GL_COLOR_BUFFER_BIT)
-      (doto stage
-        (.act delta)
-        (.draw)))
-    (dispose[])
-    (hide [])
-    (pause [])
-    (resize [w h])
-    (resume [])))
+  (let [stage (atom nil)]
+    (proxy [Screen] []
+      (show []
+        (reset! stage (Stage.))
+        (let [style (Label$LabelStyle. (BitmapFont.) (Color. 1 1 1 1))
+              label (Label. "Hello world!" style)]
+          (.addActor @stage label)))
+      (render [delta]
+        (.glClearColor (Gdx/gl) 0 0 0 0)
+        (.glClear (Gdx/gl) GL20/GL_COLOR_BUFFER_BIT)
+        (doto @stage
+          (.act delta)
+          (.draw)))
+      (dispose [])
+      (hide [])
+      (pause [])
+      (resize [w h])
+      (resume []))))

 (gen-class
   :name {{namespace}}.Game


Fixed buglet regarding weighting of non-aligned images.

--- src/main/clojure/brainardlab/nben/retina/core.clj
+++ src/main/clojure/brainardlab/nben/retina/core.clj
@@ -78,7 +78,7 @@
              (loop [s dep, w 0.0, sig nil]
                (if s
                  (let [[row col weight] (first s)
-                       spec (nth (nth image (dec row)) (dec col))]
+                       spec (map #(* % weight) (nth (nth image (dec row)) (dec col)))]
                    (recur (next s)
                           (+ w weight)
                           (if sig (map + sig spec) spec)))


Cleanup ID parsing in routes.

Cleanup ID parsing in routes.

--- src/ranked_choice/routes.clj
+++ src/ranked_choice/routes.clj
@@ -38,7 +38,7 @@
            (resource-response "/results.html")))
     (GET "/close" []
          (async/close! (:votes-ch poll))
-         (swap! (:polls poll-mgr) assoc (Integer/parseInt id) nil)
+         (swap! (:polls poll-mgr) assoc id nil)
          (redirect "/poll/monitor"))))

 (defroutes app-routes
@@ -56,9 +56,10 @@
              polls-by-id (->> polls (map-indexed vector) (filter last))]
          (monitor polls-by-id)))
   (context "/poll/:id" [id :as {poll-mgr :poll/poll-mgr}]
-           (if-let [poll (poll/get-poll poll-mgr (Integer/parseInt id))]
-             (poll-routes poll-mgr poll id)
-             (not-found (str "No poll found with id: " id))))
+           (let [poll-id (Integer/parseInt id)]
+             (if-let [poll (poll/get-poll poll-mgr poll-id)]
+               (poll-routes poll-mgr poll poll-id)
+               (not-found (str "No poll found with id: " poll-id)))))
   (resources ""))

 (def app (wrap-params app-routes))


all tests should pass now

all tests should pass now

--- pigpen-cascading/src/test/clojure/pigpen/cascading/functional_test.clj
+++ pigpen-cascading/src/test/clojure/pigpen/cascading/functional_test.clj
@@ -68,12 +68,4 @@
       (let [file (t/file this)]
         (spit file (clojure.string/join "\n" lines))
         file)))
-  #{
-    pigpen.functional.map-test/test-map-indexed
-    pigpen.functional.map-test/test-map-indexed+sort
-    pigpen.functional.map-test/test-sort
-    pigpen.functional.map-test/test-sort-desc
-    pigpen.functional.map-test/test-sort-by
-    pigpen.functional.map-test/test-sort-by-desc
-    pigpen.functional.map-test/test-sort-by-with-duplicates
-    })
+  #{})


adding test structure for all the player methods


Improve demo a little

Improve demo a little

--- test/demo.cljs
+++ test/demo.cljs
@@ -34,14 +34,15 @@
                  (map #(% defs) names))))

 (def builtins ["def" "defn" "ns" "atom" "let" "if" "when"
-               "cond" "merge" "assoc" "swap!" "reset!"])
+               "cond" "merge" "assoc" "swap!" "reset!" "for"
+               "range" "nil\\?" "int" "or" "->" "%"])

 (defn syntaxify [src]
   (let [sep "\\][(){} \\t\\n"
         str-p "\"[^\"]*\""
         keyw-p (str ":[^" sep "]+")
-        res-p (string/join "|" (map #(str % "(?=[" sep "])") builtins))
-        any-p ".|\\n"
+        res-p (string/join "|" (map #(str "\\b" % "(?=[" sep "])") builtins))
+        any-p (str "[^" sep "]+|.|\\n") ;; ".|\\n"
         patt (re-pattern (str "("
                               (string/join ")|(" [str-p keyw-p res-p any-p])
                               ")"))]
@@ -94,19 +95,21 @@
   [:div
    "The atom " [:code "click-count"] " has value: "
    @click-count ". "
-   [:input {:type "button"
-            :value "Click me!"
+   [:input {:type "button" :value "Click me!"
             :on-click #(swap! click-count inc)}]])

-(defn local-state []
+(defn atom-input [{:keys [value]}]
+  [:input {:type "text"
+           :value @value
+           :on-change #(reset! value (-> % .-target .-value))}])
+
+(defn shared-state []
   (let [val (atom "foo")]
     (fn []
       [:div
        [:p "The value is now: " @val]
-       [:p "Change it: "
-        [:input
-         {:type "text" :value @val
-          :on-change #(reset! val (-> % .-target .-value))}]]])))
+       [:p "Change it here: "
+        [atom-input {:value val}]]])))

 (defn timer-component []
   (let [seconds-elapsed (atom 0)]
@@ -162,10 +165,12 @@
   [:div
    [:h2 "Introduction to Cloact"]

-   [:p "Cloact provides a minimalistic interface between ClojureScript
-   and React. It allows you to define React components using nothing
-   but plain ClojureScript functions, that describe your UI using a
-   Hiccup-like syntax."]
+   [:p "Cloact provides a minimalistic interface between "
+    [:a {:href "https://github.com/clojure/clojurescript"} "ClojureScript"]
+    " and " [:a {:href "http://facebook.github.io/react/"} "React"]
+    ". It allows you to define React components using nothing but
+    plain ClojureScript functions, that describe your UI using a
+    Hiccup-like syntax."]

    [:p "A very basic component may look something like this: "]
    [demo-component {:comp simple-component
@@ -178,7 +183,7 @@

    [:p "Data is passed to child components using a plain old Clojure
    maps. For example, here is a component that shows items in a "
-   [:code "seq"] "." ]
+    [:code "seq"] "." ]

    [demo-component {:comp lister-user
                     :defs [:lister :lister-user]}]
@@ -207,10 +212,12 @@
    [:p "Sometimes you may want to maintain state locally in a
    component. That is easy to do with an " [:code "atom"] " as well."]

-   [:p "Here is an example of that:"]
-   [demo-component {:comp local-state
-                    :defs [:ns :local-state]}]
-
+   [:p "Here is an example of that, where we call setTimeout every
+   time the component is rendered to update a simple clock:"]
+
+   [demo-component {:comp timer-component
+                    :defs [:timer-component]}]
+
    [:p "The previous example also uses another feature of Cloact: a component
    function can return another function, that is used to do the actual
    rendering. It is called with the same arguments as any other
@@ -218,10 +225,10 @@
    created components, without resorting to React's lifecycle
    events."]

-   [:p "Here is another example, where we call setTimeout everytime
-   the component is rendered to update a simple clock:"]
-   [demo-component {:comp timer-component
-                    :defs [:timer-component]}]])
+   [:p "By simply passing atoms around you can share state management
+   between components, like this:"]
+   [demo-component {:comp shared-state
+                    :defs [:ns :atom-input :shared-state]}]])

 (defn essential-api []
   [:div
@@ -229,7 +236,7 @@

    [:p "Cloact supports most of React's API, but there is really only
    one entry-point that is necessary for most applications: "
-   [:code "cloact.core/render-component"] "."]
+    [:code "cloact.core/render-component"] "."]

    [:p "It takes too arguments: a component, and a DOM node. For
    example, splashing the very first example all over the page would


Fix #36 (experimental): batch writes shouldn't range over sets

Untested fix, written in a hurry.

Batch requests like `{:mytable {:put [{:id 1 :s #{"a" "b"}}` were
incorrectly ranging over individual s values: "a", "b" rather than
being correctly interpreted as a _single_ :put with a single set
value.

--- src/taoensso/faraday.clj
+++ src/taoensso/faraday.clj
@@ -668,19 +668,23 @@
 (defn- attr-multi-vs
   "[{<attr> <v-or-vs*> ...} ...]* -> [{<attr> <v> ...} ...] (* => optional vec)"
   [attr-multi-vs-map]
-  (let [ensure-coll (fn [x] (if (coll?* x) x [x]))]
+  (let [;; ensure-coll (fn [x] (if (coll?* x) x [x]))
+        ensure-sequential (fn [x] (if (sequential? x) x [x]))]
     (reduce (fn [r attr-multi-vs]
               (let [attrs (keys attr-multi-vs)
-                    vs    (mapv ensure-coll (vals attr-multi-vs))]
+                    vs    (mapv ensure-sequential (vals attr-multi-vs))]
                 (when (> (count (filter next vs)) 1)
                   (-> (Exception. "Can range over only a single attr's values")
                       (throw)))
                 (into r (mapv (comp clj-item->db-item (partial zipmap attrs))
                               (apply utils/cartesian-product vs)))))
-            [] (ensure-coll attr-multi-vs-map))))
-
-(comment (attr-multi-vs {:a "a1" :b ["b1" "b2" "b3"] :c ["c1" "c2"]})
-         (attr-multi-vs {:a "a1" :b ["b1" "b2" "b3"] :c ["c1"]}))
+            [] (ensure-sequential attr-multi-vs-map))))
+
+(comment
+  (attr-multi-vs {:a "a1" :b ["b1" "b2" "b3"] :c ["c1" "c2"]}) ; ex
+  (attr-multi-vs {:a "a1" :b ["b1" "b2" "b3"] :c ["c1"]})       ; Range over b's
+  (attr-multi-vs {:a "a1" :b ["b1" "b2" "b3"] :c #{"c1" "c2"}}) ; ''
+  )

 (defn- batch-request-items
   "{<table> <request> ...} -> {<table> KeysAndAttributes> ...}"


Split single and many into two functions

--- src/test_utils/core.cljc
+++ src/test_utils/core.cljc
@@ -61,7 +61,11 @@
     number
     (str "0" number)))

-(defn rand-uuid
+(defn rand-uuid []
   "Return a random UUID."
-  ([] (java.util.UUID/randomUUID))
-  ([n] (repeatedly n (fn [] (java.util.UUID/randomUUID)))))
+  (java.util.UUID/randomUUID))
+
+(defn rand-uuids
+  "Return many random UUIDs."
+  ([] (rand-uuids 3))
+  ([n] (repeatedly n rand-uuid)))


CMR-2866 Fixed an errant spacing error

CMR-2866 Fixed an errant spacing error

--- search-app/src/cmr/search/services/parameters/parameter_validation.clj
+++ search-app/src/cmr/search/services/parameters/parameter_validation.clj
@@ -514,7 +514,6 @@
   {:collection (concat
                  cpv/common-validations
                  [boosts-validation
-
                   temporal-format-validation
                   updated-since-validation
                   revision-date-validation


upgrade storm version

upgrade storm version

--- examples/leinproj/project.clj
+++ examples/leinproj/project.clj
@@ -5,7 +5,7 @@
   :target-path "_build"
   :min-lein-version "2.0.0"
   :main stormy
-  :dependencies [[storm "0.8.2"]
+  :dependencies [[org.apache.storm/storm-core "0.9.1-incubating"]
                  [org.clojure/clojure "1.5.1"]
                  [org.clojure/data.json "0.2.4"]
                  [org.clojure/tools.cli "0.3.1"]


#28 update gen-paginate-page

#28 update gen-paginate-page

--- src/tamaki/template/page.clj
+++ src/tamaki/template/page.clj
@@ -76,6 +76,27 @@
      (map #(load-postmd (.getAbsolutePath %)) mds)))
   ([]
    (load-recent-posts (:recent-post-num (config/read-config)) (-> (config/read-config) :post-dir))))
+
+(defn- gen-paginate-page [dir]
+  ^{:doc "dir is the directory where posts are put."}
+  (letfn [(create-paginate-files [total paginate-url-pattern]
+            (cons "index.html"
+                  (map #(str/replace paginate-url-pattern #":num" (str %)) (range 2 (+ 1 total)))))]
+    (let [num-per-page (:posts-per-page (config/read-config))
+          excerpts (map #(load-post-excerpt (.getAbsolutePath %)) (-> dir io/file .listFiles reverse))
+          parted-excerpts (partition-all num-per-page excerpts)
+          output-files (create-paginate-files (count parted-excerpts) (:pagination-pattern (config/read-config)))
+          neighbor-links (create-neighbor-link output-files)
+          pages (map (fn [excerpt current-page neighbors] (merge {:posts excerpt} {:current-page current-page}  neighbors))
+                      excerpts
+                      output-files
+                      neighbor-links)
+          template (:pagination-template (config/read-config))]
+      (require (symbol (str/replace template  #"/.*"  "")))
+      (doseq [page pages]
+        (let [dst (str (:dest (config/read-config)) (:current-page chunk))]
+          (tfile/create-empty-file dst)
+          (spit dst ((var-get (resolve template)) page)))))))
 ;

 (defn load-markdown
@@ -165,25 +186,6 @@
           (spit (:dest-file md) ((var-get (resolve (symbol func))) md))
           )))))

-(defn- gen-paginate-page [dir]
-  ^{:doc "dir is the directory where posts are put."}
-  (letfn [(create-paginate [total paginate-url-pattern]
-            (cons "index.html"
-                  (map #(str/replace paginate-url-pattern #":num" (str %)) (range 2 (+ 1 total)))))]
-    (let [paginate (:paginate (config/read-config))
-          ;;
-          mds (map #(load-md-excerpt (.getAbsolutePath %)) (-> dir io/file .listFiles reverse))
-          mdchunks (partition-all paginate mds)
-          paginate (create-paginate (count mdchunks) (:paginate-path (config/read-config)))
-          paginate2 (create-neighbor-url paginate)
-          result (map (fn [md p pn] (merge {:posts md} {:current-page p}  pn)) mdchunks paginate paginate2)
-          func (:paginate-template (config/read-config))]
-      (require (symbol (str/replace func  #"/.*"  "")))
-      (dorun
-        (for [chunk result]
-          (let [dst  ((:dest (config/read-config))  (:current-page chunk))]
-            (tfile/create-empty-file dst)
-            (spit dst ((var-get (resolve func)) chunk))))))))

 (defn load-plugin []
   (gen-paginate-page (:posts-dir (config/read-config)))


Whitelist/blacklist switch

Whitelist/blacklist switch

--- src/zg/html_renderer.clj
+++ src/zg/html_renderer.clj
@@ -56,37 +56,40 @@
             [:div {:class "input-group-btn"}
                 (form/submit-button {:class "btn btn-default"} "Remember me")]]))

+(defn tab-class
+    [active mode]
+    (if (= active mode)
+    {:class "active"}))
+
+(defn users-href
+    [url-prefix mode]
+    (if (= mode :whitelist)
+        (str url-prefix "users-whitelist")
+        (str url-prefix "users-blacklist")))
+
 (defn render-navigation-bar-section
     "Renders whole navigation bar."
-    [word user-name url-prefix zw-mode]
-    [:nav {:class "navbar navbar-inverse navbar-fixed-top" :role "navigation"}
+    [user-name url-prefix title mode]
+    [:nav {:class "navbar navbar-inverse navbar-fixed-top" :role "navigation"} ; use navbar-default instead of navbar-inverse
         [:div {:class "container-fluid"}
             [:div {:class "row"}
-                [:div {:class "col-md-1"}
+                [:div {:class "col-md-7"}
                     [:div {:class "navbar-header"}
-                        [:a {:href url-prefix :class "navbar-brand"} (if zw-mode "zw" "zg")]
-                    ] ; ./navbar-header
-                ] ; col ends
-                [:div {:class "col-md-3"}
-                    (render-search-field word url-prefix)
-                ] ; col ends
-                [:div {:class "col-md-4"}
-                    [:div {:class "navbar-header"}
-                        [:a {:href (str url-prefix "all-words") :class "navbar-brand"} "All words"]
+                        [:a {:href url-prefix :class "navbar-brand"} title]
                     ] ; ./navbar-header
                     [:div {:class "navbar-header"}
-                        [:a {:href (str url-prefix "active-words") :class "navbar-brand"} "Active words"]
-                    ] ; ./navbar-header
-                    [:div {:class "navbar-header"}
-                        [:a {:href (str url-prefix "deleted-words") :class "navbar-brand"} "Deleted words"]
-                    ] ; ./navbar-header
-                ] ; col ends
+                        [:ul {:class "nav navbar-nav"}
+                            [:li (tab-class :whitelist mode) [:a {:href (str url-prefix "whitelist")} "Whitelist"]]
+                            [:li (tab-class :blacklist mode) [:a {:href (str url-prefix "blacklist")} "Blacklist"]]
+                        ]
+                    ]
+                ] ; col-md-7 ends
                 [:div {:class "col-md-3"}
                     (render-name-field user-name url-prefix)
                 ]
-                [:div {:class "col-md-1"}
+                [:div {:class "col-md-2"}
                     [:div {:class "navbar-header"}
-                        [:a {:href (str url-prefix "users") :class "navbar-brand"} "Users"]
+                        [:a {:href (users-href url-prefix mode) :class "navbar-brand"} "Users"]
                     ] ; ./navbar-header
                 ] ; col ends
             ] ; row ends


Improve error message if schema is nil

Improve error message if schema is nil

--- src/territory_bro/db.clj
+++ src/territory_bro/db.clj
@@ -159,7 +159,7 @@

 (defn set-search-path [conn schemas]
   (doseq [schema schemas]
-    (assert (re-matches #"^[a-zA-Z0-9_]+$" schema)
+    (assert (and schema (re-matches #"^[a-zA-Z0-9_]+$" schema))
             {:schema schema}))
   (jdbc/execute! conn [(str "set search_path to " (str/join "," schemas))]))


separate out flash middleware into request and response

--- ring-core/src/ring/middleware/flash.clj
+++ ring-core/src/ring/middleware/flash.clj
@@ -1,5 +1,26 @@
 (ns ring.middleware.flash
   "A session-based flash store that persists to the next request.")
+
+(defn flash-request
+  "Adds :flash key to request from :_flash in session."
+  [request]
+  (let [session (:session request)
+        flash   (:_flash session)
+        session (dissoc session :_flash)]
+    (assoc request :session session, :flash flash)))
+
+(defn flash-response
+  "If response has a :flash key, saves it in :_flash of session for next request."
+  [response {:keys [session flash] :as request}]
+  (let [session (if (contains? response :session)
+                  (response :session)
+                  session)
+        session (if-let [flash (response :flash)]
+                  (assoc (response :session session) :_flash flash)
+                  session)]
+    (if (or flash (response :flash) (contains? response :session))
+      (assoc response :session session)
+      response)))

 (defn wrap-flash
   "If a :flash key is set on the response by the handler, a :flash key with
@@ -7,17 +28,7 @@
   This is useful for small messages that persist across redirects."
   [handler]
   (fn [request]
-    (let [session (:session request)
-          flash   (:_flash session)
-          session (dissoc session :_flash)
-          request (assoc request :session session, :flash flash)]
-      (if-let [response (handler request)]
-        (let [session (if (contains? response :session)
-                        (response :session)
-                        session)
-              session (if-let [flash (response :flash)]
-                        (assoc (response :session session) :_flash flash)
-                        session)]
-          (if (or flash (response :flash) (contains? response :session))
-            (assoc response :session session)
-            response))))))
+    (when-let [resp (-> request
+                        flash-request
+                        handler)]
+      (flash-response resp request))))


Add flag to not start RServe from worker

--- worker/src/clinicico/worker/main.clj
+++ worker/src/clinicico/worker/main.clj
@@ -22,6 +22,7 @@
   (let [[options args banner]
         (cli args
              ["-h" "--help" "Show help" :default false :flag true]
+             ["-r" "--rserve" "Start RServe from application" :default false :flag true]
              ["-n" "--nworkers" "Amount of worker threads to start"
               :default (.availableProcessors (Runtime/getRuntime))
               :parse-fn #(Integer. %)]
@@ -34,6 +35,6 @@
     (when (:help options)
       (println banner)
       (System/exit 0))
-    (pirate/initialize (:file options) (:packages options))
+    (when (:rserve options) (pirate/initialize (:file options) (:packages options)))
     (tasks/initialize method (:nworkers options) run)
     (while true (Thread/sleep 100))))


simplify against-pred

simplify against-pred

--- src/babel/enrich.cljc
+++ src/babel/enrich.cljc
@@ -19,14 +19,12 @@
     (log/debug (str "against-pred with spec: " spec " and pred: " pred))
     (if (= :top pred)
       spec
-      (mapcat (fn [lexeme]
-                (let [result (unify spec
-                                    {:synsem {:sem (strip-refs (get-in lexeme [:synsem :sem] :top))}})]
-                  (if (not (fail? result))
-                    (do
-                      (log/debug (str "matched head lexeme: " (strip-refs lexeme)))
-                      (list result)))))
-              (matching-head-lexemes spec lexicon)))))
+      (filter (fn [result]
+                (not (fail? result)))
+              (map (fn [lexeme]
+                     (unify spec
+                            {:synsem {:sem (strip-refs (get-in lexeme [:synsem :sem] :top))}}))
+                   (matching-head-lexemes spec lexicon))))))

 (defn matching-head-lexemes [spec lexicon]
   (let [pred-of-head (get-in spec [:synsem :sem :pred] :top)]


fix back-button when launching app

fix back-button when launching app

--- src-cljs/frontend/controllers/controls.cljs
+++ src-cljs/frontend/controllers/controls.cljs
@@ -1287,7 +1287,8 @@

 (defmethod post-control-event! :launch-app-clicked
   [target message _ previous-state current-state]
-  (put! (get-in current-state [:comms :nav]) [:navigate! {:path (str "/document/" (:document/id current-state))}]))
+  (put! (get-in current-state [:comms :nav]) [:navigate! {:path (str "/document/" (:document/id current-state))
+                                                          :replace-token? true}]))

 (defmethod control-event :subscriber-updated
   [browser-state message {:keys [client-id fields]} state]


more efficient pen drawings through ws channel

--- src-cljs/frontend/controllers/controls.cljs
+++ src-cljs/frontend/controllers/controls.cljs
@@ -72,7 +72,7 @@
                                                 :document/id (:document/id current-state)
                                                 :layers (when (or (get-in current-state [:drawing :in-progress?])
                                                                   (get-in current-state [:drawing :moving?]))
-                                                          (get-in current-state [:drawing :layers]))
+                                                          (map #(dissoc % :points) (get-in current-state [:drawing :layers])))
                                                 :relation (when (get-in current-state [:drawing :relation :layer])
                                                             (get-in current-state [:drawing :relation]))
                                                 :recording (:recording current-state)}


Remove faulty :on-jsload

Remove faulty :on-jsload

--- env/dev/cljs/train_race/app.cljs
+++ env/dev/cljs/train_race/app.cljs
@@ -6,7 +6,6 @@
 (enable-console-print!)

 (figwheel/watch-and-reload
-  :websocket-url "ws://localhost:3449/figwheel-ws"
-  :on-jsload core/mount-components)
+  :websocket-url "ws://localhost:3449/figwheel-ws")

 (devtools/install!)


CLJS-521: pass along entire repl environment when loading dependencies

--- src/clj/cljs/repl.clj
+++ src/clj/cljs/repl.clj
@@ -24,6 +24,15 @@
   (-load [this ns url] "load code at url into the environment")
   (-tear-down [this] "dispose of the environment"))

+(defn- env->opts
+  "Returns a hash-map containing all of the entries in [repl-env], translating
+:working-dir to :output-dir."
+  [repl-env]
+  ; some bits in cljs.closure use the options value as an ifn :-/
+  (-> (into {} repl-env)
+      (assoc :optimizations (get repl-env :optimizations :none))
+      (assoc :output-dir (get repl-env :working-dir ".repl"))))
+
 (defn load-namespace
   "Load a namespace and all of its dependencies into the evaluation environment.
   The environment is responsible for ensuring that each namespace is loaded once and
@@ -33,8 +42,8 @@
                      (= (first sym) 'quote))
               (second sym)
               sym)
-        opts {:output-dir (get repl-env :working-dir ".repl")}
-        deps (->> (cljsc/add-dependencies opts {:requires [(name sym)] :type :seed})
+        deps (->> (cljsc/add-dependencies (env->opts repl-env)
+                                          {:requires [(name sym)] :type :seed})
                   (remove (comp #{["goog"]} :provides))
                   (remove (comp #{:seed} :type))
                   (map #(select-keys % [:provides :url])))]


add source map branch to `cljs.repl/display-error`

--- src/clj/cljs/repl.clj
+++ src/clj/cljs/repl.clj
@@ -148,13 +148,16 @@
      (load-namespace repl-env ns opts))))

 (defn- display-error
-  ([ret form]
-    (display-error ret form (constantly nil)))
-  ([ret form f]
+  ([ret form opts]
+    (display-error ret form (constantly nil) opts))
+  ([ret form f opts]
     (f)
     (println (:value ret))
     (when-let [st (:stacktrace ret)]
-      (println st)
+      (if (and (true? (:source-map opts))
+               (vector? st))
+        (println st)
+        (println st))
       (flush))))

 (defn evaluate-form
@@ -204,11 +207,12 @@
             (print js))
           (let [ret (-evaluate repl-env filename (:line (meta form)) wrap-js)]
             (case (:status ret)
-              :error (display-error ret form)
+              :error (display-error ret form opts)
               :exception (display-error ret form
                            (if (:repl-verbose opts)
                              #(prn "Error evaluating:" form :as js)
-                             (constantly nil)))
+                             (constantly nil))
+                           opts)
               :success (:value ret)))))
       (catch Throwable ex
         (.printStackTrace ex)


Only use Madras2 related roles from ldap

--- src/clj/mdr2/ldap.clj
+++ src/clj/mdr2/ldap.clj
@@ -25,7 +25,8 @@

 (defn- extract-role [s]
   (->> s
-   (re-matches #"cn=([a-z_.]+),cn=roles,cn=accounts,dc=sbszh,dc=ch")
+   ;; only extract roles related to Madras2
+   (re-matches #"cn=madras2.([a-z_.]+),cn=roles,cn=accounts,dc=sbszh,dc=ch")
    second))

 (defn- add-groups [{memberships :memberOf :as user}]


Re-introduce save-request option in build-response-map

--- src/clj_http/core.clj
+++ src/clj_http/core.clj
@@ -321,24 +321,47 @@
   (clojure.pprint/pprint (bean http-req)))

 (defn- build-response-map
-  [^HttpResponse response req conn-mgr ^HttpClientContext context]
+  [^HttpResponse response req ^HttpUriRequest http-req
+   conn-mgr ^HttpClientContext context]
   (let [^HttpEntity entity (.getEntity response)
         status (.getStatusLine response)
-        protocol-version (.getProtocolVersion status)]
-    {:body (coerce-body-entity entity conn-mgr response)
-     :headers (parse-headers
-               (.headerIterator response)
-               (opt req :use-header-maps-in-response))
-     :length (if (nil? entity) 0 (.getContentLength entity))
-     :chunked? (if (nil? entity) false (.isChunked entity))
-     :repeatable? (if (nil? entity) false (.isRepeatable entity))
-     :streaming? (if (nil? entity) false (.isStreaming entity))
-     :status (.getStatusCode status)
-     :protocol-version  {:name (.getProtocol protocol-version)
-                         :major (.getMajor protocol-version)
-                         :minor (.getMinor protocol-version)}
-     :reason-phrase (.getReasonPhrase status)
-     :trace-redirects (mapv str (.getRedirectLocations context))}))
+        protocol-version (.getProtocolVersion status)
+        body (:body req)
+        response
+        {:body (coerce-body-entity entity conn-mgr response)
+         :headers (parse-headers
+                   (.headerIterator response)
+                   (opt req :use-header-maps-in-response))
+         :length (if (nil? entity) 0 (.getContentLength entity))
+         :chunked? (if (nil? entity) false (.isChunked entity))
+         :repeatable? (if (nil? entity) false (.isRepeatable entity))
+         :streaming? (if (nil? entity) false (.isStreaming entity))
+         :status (.getStatusCode status)
+         :protocol-version  {:name (.getProtocol protocol-version)
+                             :major (.getMajor protocol-version)
+                             :minor (.getMinor protocol-version)}
+         :reason-phrase (.getReasonPhrase status)
+         :trace-redirects (mapv str (.getRedirectLocations context))}]
+    (if (opt req :save-request)
+      (-> response
+          (assoc :request req)
+          (assoc-in [:request :body-type] (type body))
+          (update-in [:request]
+                     #(if (opt req :debug-body)
+                        (assoc % :body-content
+                               (cond
+                                 (isa? (type (:body %)) String)
+                                 (:body %)
+
+                                 (isa? (type (:body %)) HttpEntity)
+                                 (let [baos (ByteArrayOutputStream.)]
+                                   (.writeTo ^HttpEntity (:body %) baos)
+                                   (.toString baos "UTF-8"))
+
+                                 :else nil))
+                        %))
+          (assoc-in [:request :http-req] http-req))
+      response)))

 (defn- get-conn-mgr
   [async? req]
@@ -418,7 +441,7 @@
              client (http-client req conn-mgr http-url proxy-ignore-hosts)]
          (try
            (build-response-map (.execute client http-req context)
-                               req conn-mgr context)
+                               req http-req conn-mgr context)
            (catch Throwable t
              (when-not (conn/reusable? conn-mgr)
                (conn/shutdown-manager conn-mgr))
@@ -437,7 +460,7 @@
                      (completed [this resp]
                        (try
                          (respond (build-response-map
-                                   resp req conn-mgr context))
+                                   resp req http-req conn-mgr context))
                          (catch Throwable t
                            (when-not (conn/reusable? conn-mgr)
                              (conn/shutdown-manager conn-mgr))


Fix unify's update behavior so that nodes are always in the correct DOM order.

--- src/cljs/c2/core.cljs
+++ src/cljs/c2/core.cljs
@@ -201,13 +201,14 @@
       (let [new-node (attach-data (mapping d idx) d)]
         ;;If there's an existing node
         (if-let [old (existing-nodes-by-key (key-fn d idx))]
-          ;;and its data is not equal to the new data, replace it
-          (if (not= d (:datum old))
-            (when-let [updated-node (update d idx (:node old) new-node)]
-
-              (dom/replace (:node old) (html/html updated-node)))
-            ;;otherwise, append the old node (effectively moving it to the correct index in the container)
-            (gdom/appendChild container (:node old)))
+          (do
+            ;;append it (effectively moving it to the correct index in the container)
+            (gdom/appendChild container (:node old))
+
+            ;;If its data is not equal to the new data, replace it
+            (if (not= d (:datum old))
+              (when-let [updated-node (update d idx (:node old) new-node)]
+                (dom/replace (:node old) (html/html updated-node)))))

           (let [new-dom-node (html/html new-node)]
             (dom/append container new-dom-node)


bump heartbeat interval

bump heartbeat interval

--- src/cljs/ji/main.cljs
+++ src/cljs/ji/main.cljs
@@ -25,7 +25,7 @@
     [cljs.core.match.macros :refer [match]]
     [ji.util.macros :refer [go-loop]]))

-(def heartbeat-interval 5000)
+(def heartbeat-interval 7500)
 (def heartbeat-req :ping)
 (def heartbeat-resp :pong)


Comparison of imperative vs functional tree walking/accumulation

--- test/tst/tupelo/xxx.cljc
+++ test/tst/tupelo/xxx.cljc
@@ -22,30 +22,71 @@
 (def data {
   :tag :root
   :content [
-    {:tag :a :content [
+    { :tag :a :content [
       {:tag :a1 :content [] }
-      {:tag :a2 :content [] }
     ] }
-    {:tag :b :content [
+    { :tag :b :content [
       {:tag :b1 :content [] }
       {:tag :b2 :content [] }
+    ] }
+  {:tag :c :content [
+      {:tag :c1 :content [] }
+      {:tag :c2 :content [] }
+      {:tag :c3 :content [] }
     ] }
   ]
 }
 )

-(defn walk* [path-in node]
+(defn walk-1* [result path-in node]
   (newline)
-  (spyx path-in)
-  (spyx (grab :tag node))
-  (doseq [child (grab :content node)]
-    (let [tag-child (grab :tag child)
-          path-new (t/append path-in tag-child)]
-      (walk* path-new child)))
-)
+  (let [tag      (grab :tag node)
+        _        (spyx tag)
+        path-new (t/append path-in tag)
+        _        (spyx path-new)
+        content  (grab :content node)]
+    (if (empty? content)
+      (do
+        (swap! result append path-new)
+        (println "....saved"))
+      (doseq [child content]
+        (walk-1* result path-new child)))))

-(defn walk [node]
-  (walk* [] node))
+(defn walk-1 [node]
+  (let [result    (atom [])
+        path      [] ]
+    (walk-1* result path node)
+    @result ))

-(spyx (walk data))
+(newline)
+(let [result (walk-1 data)]
+  (newline)
+  (println :walk-1)
+  (pretty result))

+(newline)
+(println "-----------------------------------------------------------------------------")
+
+(defn walk-2 [node]
+  (newline)
+  (let [tag     (grab :tag node)
+        _       (spyx tag)
+        content (grab :content node)]
+    (if (empty? content)
+      [[tag]]
+      (spy :mapv
+        (mapv #(prepend tag %)
+          (spy :apply-glue
+            (apply glue
+              (spy :forv
+                (forv [child content]
+                  (spy :walk-2
+                    (walk-2 child)))))))))))
+
+(let [result (walk-2 data)]
+  (newline)
+  (println :walk-2)
+  (pretty result))
+
+
+


Reformatted db_spec_test.clj by zprint

Reformatted db_spec_test.clj by zprint

--- test/zg/db_spec_test.clj
+++ test/zg/db_spec_test.clj
@@ -19,7 +19,7 @@
 ;

 (defn callable?
-    "Test if given function-name is bound to the real function."
-    [function-name]
-    (clojure.test/function? function-name))
+  "Test if given function-name is bound to the real function."
+  [function-name]
+  (clojure.test/function? function-name))


Finallies

Finallies

--- test/icecap/e2e/common.clj
+++ test/icecap/e2e/common.clj
@@ -13,8 +13,9 @@
   "Runs an icecap server as a test fixture."
   [f]
   (with-redefs [icecap-server (core/run)]
-    (f)
-    (.close icecap-server)))
+    (try
+      (f)
+      (finally (.close icecap-server)))))

 (def base-url
   (str "http://localhost:" core/port))


Fix the log pagination when log filters are used

--- src/cljs/onyx_dashboard/components/log.cljs
+++ src/cljs/onyx_dashboard/components/log.cljs
@@ -36,15 +36,6 @@
 (def entries-per-page 20)
 (def num-pages-to-show 10)

-(defn pagination-info [entries start-index]
-  (let [num-pages (Math/ceil (/ (count entries) entries-per-page))]
-    {:displayed-entries (take entries-per-page
-                              (keep entries
-                                    (reverse (range 0
-                                                    (inc start-index)))))
-     :current-page (- num-pages (Math/ceil (* num-pages (/ start-index (count entries)))))
-     :num-pages num-pages}))
-
 (defcomponent log-entry-modal [log-entry owner {:keys [entry-ch]}]
   (render [_]
           (md/modal {:header (dom/h4 "Log Entry " (:message-id log-entry))
@@ -58,6 +49,15 @@
                                  (dom/tr (dom/td (str k))
                                          (dom/td (pr-str v)))))))))

+(defn pagination-info [entries start-index]
+  (let [num-pages (Math/ceil (/ (count entries) entries-per-page))]
+    {:displayed-entries (take entries-per-page
+                              (keep entries
+                                    (reverse (range 0
+                                                    (inc start-index)))))
+     :current-page (- num-pages (Math/ceil (* num-pages (/ start-index (count entries)))))
+     :num-pages num-pages}))
+
 (defcomponent log-entries-pager [{:keys [job-filter entries] :as log} owner]
   (init-state [_]
               {:entry-index nil
@@ -69,17 +69,15 @@
                          (om/set-state! owner :visible-entry entry))
                        (recur)))
   (render-state [_ {:keys [entry-index visible-entry entry-ch]}]
-                (let [filtered-entries (if job-filter
-                                         (into {}
-                                               (filter (comp (partial = job-filter)
-                                                             :job
-                                                             :args
-                                                             val)
-                                                       entries))
-                                         entries)]
+                (let [filtered-entries (vec
+                                         (sort-by :message-id
+                                                  (cond->> (vals entries)
+                                                    job-filter (filter (comp (partial = job-filter)
+                                                                             :job
+                                                                             :args)))))]
                   (if (empty? filtered-entries)
                     (dom/div {} "")
-                    (let [max-id (apply max (keep :message-id (vals filtered-entries)))
+                    (let [max-id (dec (count filtered-entries))
                           current-index (or entry-index max-id)
                           {:keys [num-pages current-page displayed-entries]} (pagination-info filtered-entries current-index)
                           pagination-start (max (- current-page


failed attempt at distprtion. needs firefox to work, and then ff needs float32 arrays, and thats lame, so will move to other effects for now

--- src/cljs/reagent_demo/views/about_page.cljs
+++ src/cljs/reagent_demo/views/about_page.cljs
@@ -6,31 +6,64 @@

 (def ac (new window/AudioContext))

-(defn play-clip [url, position, duration, rate, reverse]
-  (let [xhr (new window/XMLHttpRequest)]
+(defn distortion-curve [amount]
+  (let [k (+ amount 3)
+        pi (.-PI js/Math)
+        n-samples 44100
+        deg (/ pi 180)]
+    (map
+      #(let [x (/ (* 2 %) (- n-samples 1))]
+          (/ (* k x 20 deg)
+          (* (.abs js/Math x) (+ amount pi))))
+      (range 44100))))
+
+(defn play-clip [url position duration rate gain reverse]
+  (let [xhr (new window/XMLHttpRequest)
+        source (.createBufferSource ac)
+        gain-node (.createGain ac)
+        analize-node (.createAnalyser ac)
+        distort-node (.createWaveShaper ac)
+        biquad-node (.createBiquadFilter ac)
+        convolve-node (.createConvolver ac)]
     (.open xhr "get" url true)
     (set! (.-responseType xhr) "arraybuffer")
     (set! (.-onload xhr) (fn []
       (.decodeAudioData ac (.-response xhr)
         (fn [buffer]
-          (let [source (.createBufferSource ac)]
-            (when reverse
-              (js/Array.prototype.reverse.call (.getChannelData buffer 0))
-              (js/Array.prototype.reverse.call (.getChannelData buffer 1)))
-            (set! (.-value (.-playbackRate source)) rate)
-            (set! (.-buffer source) buffer)
-            (.connect source (aget ac "destination"))
-            (.start source (.-currentTime ac) position)
-            (js/setTimeout
-              #(.stop source 0)
-              (* duration 1000)))))))
+          (when reverse
+            (js/Array.prototype.reverse.call (.getChannelData buffer 0))
+            (js/Array.prototype.reverse.call (.getChannelData buffer 1)))
+          ; (.linearRampToValueAtTime (.-gain gain-node) 1 0)
+          ; (.linearRampToValueAtTime (.-gain gain-node) 0 5)
+          ; (set! (.-buffer convolve-node) buffer)
+          (set! (.-value (.-gain gain-node)) gain)
+          (set! (.-value (.-playbackRate source)) rate)
+          (set! (.-buffer source) buffer)
+          (set! (.-type biquad-node) "notch")
+          (set! (.-value (.-frequency biquad-node)) 1000)
+          (set! (.-Q biquad-node) 1)
+          (set! (.-gain biquad-node) 1)
+          (set! (.-curve distort-node) (distortion-curve 400))
+          (set! (.-oversample distort-node) "4x")
+          (.connect source analize-node)
+          (.connect analize-node distort-node)
+          (.connect distort-node biquad-node)
+          (.connect biquad-node gain-node)
+          ; (.connect biquad-node convolve-node)
+          ; (.connect convolve-node gain-node)
+          (.connect gain-node (aget ac "destination"))
+          (.start source (.-currentTime ac) position)
+          (js/setTimeout
+            #(.stop source 0)
+            (* duration 1000))))))
     (.send xhr)))

 (def url "http://static.kevvv.in/sounds/callmemaybe.mp3")
-(play-clip url 2 100 0.5 true)
-(play-clip url 0 100 0.25 false)
+; (play-clip url 0 100 0.4 true)
+; (play-clip url 0 100 0.25 1 false)
+(play-clip url 3 6 1 1 false)

-; (js/setInterval #(play-clip url 7.1 30) 4000)
+; (js/setInterval #(play-clip url 7.1 4 1 1 false) 3000)

 ; (play-clip url 7.1 0.35)
 ; (js/setInterval #(play-clip url 7.1 2 2 false) 2000)


CMR-736: Removed unneeded tests.

CMR-736: Removed unneeded tests.

--- test/cmr/system_int_test/search/collection_keyword_search_test.clj
+++ test/cmr/system_int_test/search/collection_keyword_search_test.clj
@@ -106,9 +106,7 @@
            "NEAR_REAL_TIME" [coll22]
            "near_real_time" [coll22]
            "nrt" [coll22]
-           "near real time" [coll22]
-           "near-real time" [coll22]
-           "near real-time" [coll22]
+           "near-real-time" [coll22]

            ;; summary
            "summary" [coll15]


Update tmp/bower_components/ace-builds/demo/kitchen-sink/docs/clojure.clj

Signed-off-by: Bernard Ojengwa <fccb4cc00c1ba7e51bf5c2b5f77130b9fe8d917e@gmail.com>

--- tmp/bower_components/ace-builds/demo/kitchen-sink/docs/clojure.clj
+++ tmp/bower_components/ace-builds/demo/kitchen-sink/docs/clojure.clj
@@ -1,19 +0,0 @@
-(defn parting
-  "returns a String parting in a given language"
-  ([] (parting "World"))
-  ([name] (parting name "en"))
-  ([name language]
-    ; condp is similar to a case statement in other languages.
-    ; It is described in more detail later.
-    ; It is used here to take different actions based on whether the
-    ; parameter "language" is set to "en", "es" or something else.
-    (condp = language
-      "en" (str "Goodbye, " name)
-      "es" (str "Adios, " name)
-      (throw (IllegalArgumentException.
-        (str "unsupported language " language))))))
-
-(println (parting)) ; -> Goodbye, World
-(println (parting "Mark")) ; -> Goodbye, Mark
-(println (parting "Mark" "es")) ; -> Adios, Mark
-(println (parting "Mark", "xy")) ; -> java.lang.IllegalArgumentException: unsupported language xy


(maint) Fix CA HTTP API prefix

(maint) Fix CA HTTP API prefix

--- src/clj/puppetlabs/services/ca/certificate_authority_core.clj
+++ src/clj/puppetlabs/services/ca/certificate_authority_core.clj
@@ -241,7 +241,7 @@
 (schema/defn ^:always-validate web-routes :- comidi/BidiRoute
   [ca-settings :- ca/CaSettings]
   (comidi/routes
-    (comidi/context ["/" :environment]
+    (comidi/context ["/v1"]
       (ANY ["/certificate_status/" :subject] [subject]
         (certificate-status subject ca-settings))
       (ANY ["/certificate_statuses/" :ignored-but-required] []


helper functions for references

helper functions for references

--- server/src/gratefulplace/db/transform.clj
+++ server/src/gratefulplace/db/transform.clj
@@ -3,18 +3,29 @@

 (declare rules transform-entity)

+(defn one
+  [ref-fn rules]
+  #(transform-entity rules (ref-fn %)))
+
+(defn many
+  [remote-key rules]
+  (fn [ent] (map #(transform-entity rules %)
+                (db/all remote-key [remote-key (:db/id ent)]))))
+
+(defn ref-count
+  [ref-attr]
+  #(ffirst (db/q [:find '(count ?c) :where ['?c ref-attr (:db/id %)]])))
+
 (def rules
   {:topic {:id :db/id
            :title :topic/title
-           :first-post #(transform-entity (:post rules) (:topic/first-post %))
-           :posts (fn [ent] (map #(transform-entity (:post rules) %)
-                                (db/all :post/content [:post/topic (:db/id ent)])))
-           :author #(transform-entity (:user rules) (:content/author %))
-           :post-count #(ffirst (db/q [:find '(count ?c) :where ['?c :post/topic (:db/id %)]]))}
+           :first-post (one :topic/first-post (:post rules))
+           :posts (many :post/topic (:post rules))
+           :author (one :content/author (:user rules))
+           :post-count (ref-count :post/topic)}
    :post {:id :db/id
           :content :post/content
-          :author #(transform-entity (:user rules) (:content/author %))}
-
+          :author (one :content/author (:user rules))}
    :user {:id :db/id
           :username :user/username
           :email :user/email}})


set a threshold height that the rocket should explode at, instead of a step count

--- src-cljs/hello.cljs
+++ src-cljs/hello.cljs
@@ -21,11 +21,13 @@
    :y (- -2.5 (rand))})

 (defn spawn-random-rocket [game-world]
-  (let [rockets (aget game-world :rockets)
-        new-rocket {:pos-x (rand-int (aget game-world :width))
-                    :pos-y (aget game-world :height)
+  (let [width (aget game-world :width)
+        height (aget game-world :height)
+        rockets (aget game-world :rockets)
+        new-rocket {:pos-x (rand-int width)
+                    :pos-y height
                     :dir-vector (random-angle-vector)
-                    :remaining-steps (rand-int (aget game-world :height))}]
+                    :threshold (+ 100 (rand (- height 200)))}]
     (aset game-world
       :rockets (conj rockets new-rocket))))


Add tags in entry scene

Add tags in entry scene

--- src/elfeed_cljsrn/android/scenes/entry.cljs
+++ src/elfeed_cljsrn/android/scenes/entry.cljs
@@ -11,6 +11,16 @@
                     :background-color "#fff9c4"}}
    [rn/text "Network error. Check your wifi or your elfeed server."]])

+(defn tag [label]
+  (let [styles {:wrapper {:background-color (:grey300 colors)
+                          :margin-left 4
+                          :padding-vertical 2
+                          :padding-horizontal 4}
+                :text {:font-size 12
+                       :color (:primary-text colors)}}]
+    [rn/view {:style (:wrapper styles)}
+     [rn/text {:style (:text styles)} label]]))
+
 (defn entry-scene [entry]
   (let [loading? (subscribe [:fetching-entry?])
         remote-error (subscribe [:remote-error :entry])
@@ -21,6 +31,8 @@
                          :padding-horizontal 10
                          :border-bottom-color (:divider palette)
                          :border-bottom-width 1}
+                :feed-info {:flex 1
+                            :flex-direction "row"}
                 :loading-content {:flex 1
                                   :padding-left 10
                                   :justify-content "center"
@@ -35,7 +47,9 @@
          [remote-error-message])
        [rn/view {:style (:header styles)}
         [rn/text (:title @entry-content)]
-        [rn/text (str "» " (:title (:feed @entry-content)))]]
+        [rn/view {:style (:feed-info styles)}
+         [rn/text (str "» " (:title (:feed @entry-content)))]
+         (for [tag-label (:tags @entry-content)] ^{:key tag-label} [tag tag-label])]]
        [rn/view {:style (if @loading? (:loading-content styles) (:content styles))}
         (if @loading?
           [rn/activity-indicator]


Load repl namespace when running on 1.3

Load repl namespace when running on 1.3

--- server/src/main/clojure/vimclojure/core.clj
+++ server/src/main/clojure/vimclojure/core.clj
@@ -24,4 +24,9 @@

 (defn init-server
   []
-  )
+  ; Check for doc macro. 1.2 in c.core, 1.3 in c.repl
+  (when-not (ns-resolve 'clojure.core 'doc)
+    (binding [*ns* *ns*]
+      (in-ns 'user)
+      (refer-clojure)
+      (use 'clojure.repl))))


InviteModal: Only compute invitees on submit


More experiments with the way data is enqueued.

--- src/dsbdp/local_data_processing_pipeline.clj
+++ src/dsbdp/local_data_processing_pipeline.clj
@@ -33,9 +33,11 @@
 ;                  "ArrayBlockingQueue_put-counted-yield"))]
 ;                  "ArrayBlockingQueue_add-counted-yield"))]
 ;                  "ArrayBlockingQueue_add-counted-yield_remove-yield"))]
+;                  "ArrayBlockingQueue_add-counted_remove"))]
+                  "LinkedBlockingQueue_add-counted_remove"))]
 ;                  "OneToOneConcurrentArrayQueue3_add-counted-yield_remove-yield"))]
 ;                  "OneToOneConcurrentArrayQueue3_add-counted_remove-yield"))]
-                  "OneToOneConcurrentArrayQueue3_add-counted_remove"))]
+;                  "OneToOneConcurrentArrayQueue3_add-counted_remove"))]
 ;                  "ArrayBlockingQueue_offer-counted"))]
 ;                  "ArrayBlockingQueue_offer-counted-yield"))]
 ;                  "LinkedTransferQueue_transfer"))]


refactor -work-threads

refactor -work-threads

--- src/byplay/core.clj
+++ src/byplay/core.clj
@@ -195,13 +195,15 @@
 (defn ^:no-doc -work-threads
   "Creates several working threads."
   [dbspec queues threads-num polling-interval-msec on-ack]
-  (doall
-    (for [_ (range threads-num)]
-      (-polling-thread (fn on-poll []
-                         (with-open [conn (jdbc/connection dbspec)]
-                           (-> (work-once (jdbc.proto/connection conn) queues)
-                               on-ack)))
-                       polling-interval-msec))))
+  (letfn [(on-poll []
+            (with-open [conn (jdbc/connection dbspec)]
+              (-> conn
+                  jdbc.proto/connection
+                  (work-once queues)
+                  on-ack)))]
+    (doall
+      (for [_ (range threads-num)]
+        (-polling-thread on-poll polling-interval-msec)))))

 (defn ^:no-doc -println-err
   "As in http://yellerapp.com/posts/2014-12-11-14-race-condition-in-clojure-println.html"


Added geo-clj dependency to the project.

--- app/project.clj
+++ app/project.clj
@@ -20,7 +20,8 @@
                  [clj-time "0.9.0"]
                  [org.clojure/core.async "0.1.346.0-17112a-alpha"]
                  [cljs-http "0.1.31"]
-                 [cljs-pikaday "0.1.1"]]
+                 [cljs-pikaday "0.1.1"]
+                 [geo-clj "0.3.22"]]
   :main ^:skip-aot weather.main
   :target-path "target/%s"
   :profiles {:dev {:resource-paths ["target/dev"]


Added cljs-http dependency to the project.

--- app/project.clj
+++ app/project.clj
@@ -18,7 +18,8 @@
                  [secretary "1.2.3"]
                  [com.novemberain/monger "2.0.1"]
                  [clj-time "0.9.0"]
-                 [org.clojure/core.async "0.1.346.0-17112a-alpha"]]
+                 [org.clojure/core.async "0.1.346.0-17112a-alpha"]
+                 [cljs-http "0.1.31"]]
   :main ^:skip-aot clj-web-example.main
   :target-path "target/%s"
   :profiles {:dev {:resource-paths ["target/dev"]


Require the build.deploy on circle.init.

--- src/circle/init.clj
+++ src/circle/init.clj
@@ -6,6 +6,7 @@
   (:require circle.logging)
   (:require circle.backend.build.run)
   (:require circle.backend.build.config)
+  (:require circle.backend.build.deploy)
   (:require fs))

 (defonce init*


Extract argument completer creation in own function.

--- src/cli4clj/cli.clj
+++ src/cli4clj/cli.clj
@@ -18,7 +18,7 @@
   (:import
     (java.io PushbackReader StringReader)
     (jline.console ConsoleReader)
-    (jline.console.completer ArgumentCompleter StringsCompleter)))
+    (jline.console.completer ArgumentCompleter Completer StringsCompleter)))

 (defn cli-repl-print
   [arg]
@@ -62,30 +62,40 @@
     {}
     cmds))

+(defn create-arg-hint-completers
+  [cmds cmd-aliases]
+  (reduce
+    (fn [v k]
+      (let [fn-args (get-in cmds [k :fn-args])
+            completion-hint (get-in cmds [k :completion-hint])]
+        (if (or (not (nil? fn-args))
+                (not (nil? completion-hint)))
+          (conj v
+                (ArgumentCompleter.
+                  [(StringsCompleter. (conj (vec (map name (cmd-aliases k))) (name k)))
+                   (proxy [Completer] []
+                     (complete [buffer cursor candidates]
+                       (if (not (nil? fn-args))
+                         (.add candidates (str "Arguments: "
+                                               fn-args
+                                               (if (not (nil? completion-hint))
+                                                 "\n"))))
+                       (if (not (nil? completion-hint))
+                         (.add candidates completion-hint))
+                       (.add candidates "")
+                       0))])))))
+    []
+    (keys cmd-aliases)))
+
 (defn create-jline-read-fn
   [cmds prompt-string]
   (let [cmd-aliases (get-cmd-aliases cmds)
         in-rdr (doto (ConsoleReader.)
                  (.addCompleter (StringsCompleter. (map name (keys cmds))))
                  (.setPrompt prompt-string))
-        arg-completers (reduce
-                         (fn [v k]
-                           (let [fn-args (get-in cmds [k :fn-args])
-                                 completion-hint (get-in cmds [k :completion-hint])
-                                 arg-completion-vec [(str "Arguments: " fn-args "\n")]]
-                             (if (or (not (nil? fn-args))
-                                     (not (nil? completion-hint)))
-                               (conj v
-                                     (ArgumentCompleter.
-                                       [(StringsCompleter. (conj (vec (map name (cmd-aliases k))) (name k)))
-                                        (StringsCompleter. (if (not (nil? completion-hint))
-                                                             (conj arg-completion-vec
-                                                               (str "Hint: " completion-hint))
-                                                             arg-completion-vec))])))))
-                         []
-                         (keys cmd-aliases))
-        _ (doseq [arg-compl arg-completers]
-            (.addCompleter in-rdr arg-compl))
+        arg-hint-completers (create-arg-hint-completers cmds cmd-aliases)
+        _ (doseq [compl arg-hint-completers]
+            (.addCompleter in-rdr compl))
         rdr-fn (create-repl-read-fn cmds)]
     (fn [request-prompt request-exit]
       (let [line (.readLine in-rdr)]


fixed refinement

fixed refinement

--- src/crawler/dom.clj
+++ src/crawler/dom.clj
@@ -580,32 +580,36 @@
            only-restrictions (:only refinement)
            avoid-restrictions (:avoid refinement)

-           restricted-to-only (filter
-                               (fn [[path info]]
-                                 (some
-                                  identity
-                                  (map
-                                   (fn [[p ns]]
-                                     (let [ns-set (set ns)]
-                                       (some #{(last
-                                                (nth path p))}
-                                             ns-set)))
-                                   only-restrictions)))
-                               nodes-paths)
-
-           restrict-avoid     (filter
-                               (fn [[path info]]
-                                 (some
-                                  identity
-                                  (map
-                                   (fn [[p ns]]
-                                     (let [ns-set (set ns)]
-                                       (not
-                                        (some #{(last
-                                                 (nth path p))}
-                                              ns-set))))
-                                   avoid-restrictions)))
-                               restricted-to-only)
+           restricted-to-only (if-not (empty? only-restrictions)
+                                (filter
+                                 (fn [[path info]]
+                                   (some
+                                    identity
+                                    (map
+                                     (fn [[p ns]]
+                                       (let [ns-set (set ns)]
+                                         (some #{(last
+                                                  (nth path p))}
+                                               ns-set)))
+                                     only-restrictions)))
+                                 nodes-paths)
+                                nodes-paths)
+
+           restrict-avoid     (if-not (empty? avoid-restrictions)
+                                (filter
+                                 (fn [[path info]]
+                                   (some
+                                    identity
+                                    (map
+                                     (fn [[p ns]]
+                                       (let [ns-set (set ns)]
+                                         (not
+                                          (some #{(last
+                                                   (nth path p))}
+                                                ns-set))))
+                                     avoid-restrictions)))
+                                 restricted-to-only)
+                                restricted-to-only)

            xpaths-nodes-paths (map
                                (fn [[path an-info]]


Workaround CLJS-910

Workaround CLJS-910

--- ClojureScript/planck/script/build.clj
+++ ClojureScript/planck/script/build.clj
@@ -5,6 +5,7 @@
 (api/build (api/inputs "src")
   {:output-dir    "out"
    :output-to     "out/main.js"
-   :optimizations :none})
+   :optimizations :none
+   :static-fns    true})
 (println "Done building")
 (System/exit 0)


fix test

fix test

--- test/chat/test/server/db.clj
+++ test/chat/test/server/db.clj
@@ -471,6 +471,7 @@
       (is (= :weekly (db/user-get-preference (:id u) :email-frequency)))
       (db/user-set-preference! (:id u) :email-frequency :daily)
       (is (= :daily (db/user-get-preference (:id u) :email-frequency)))
+      (db/user-set-preference! (:id u) :email-frequency :weekly)
       (testing "can search by preferences"
         (let [u1 (:id (db/create-user! {:id (db/uuid)
                                         :email "foo@baz.com"


system builder tests

system builder tests

--- test/deferst/system_test.clj
+++ test/deferst/system_test.clj
@@ -9,11 +9,57 @@
 ;; check schemas
 (use-fixtures :once schema.test/validate-schemas)

-(deftest build-nothing
+(deftest empty-system
+  (let [sb (s/system-builder [])
+        sys (s/start-system! sb {:foo 10})]
+
+    (testing "null system contains config"
+      (is (= @(s/system-map sys)
+             {:foo 10})))))
+
+(deftest empty-system-stops
   (let [ff (fn [v] [v (fn [] (prn "destroying" v))])
         sb (s/system-builder [])
+        sys (s/start-system! sb {:foo 10})
+        _ (s/stop-system! sys)]
+
+    (testing "null system is stopped"
+      (is (= (-> sys deref last :config/destroyed deref)
+             true)))))
+
+(deftest single-item-system
+  (let [ff (fn [v] [v (fn [] (prn "destroying" v))])
+        sb (s/system-builder [[:a ff {:a-arg [:foo]}]])
         sys (s/start-system! sb {:foo 10})]

-    (testing ""
+    (testing "single item system has the single object"
       (is (= @(s/system-map sys)
-             {:foo 10})))))
+             {:foo 10
+              :a {:a-arg 10}})))))
+
+(deftest dependent-item-system
+  (let [ff (fn [v] [v (fn [] (prn "destroying" v))])
+        sb (s/system-builder [[:a ff {:a-arg [:foo]}]
+                              [:b ff {:b-arg [:a :a-arg]}]])
+        sys (s/start-system! sb {:foo 10})]
+
+    (testing "single item system has the single object"
+      (is (= @(s/system-map sys)
+             {:foo 10
+              :a {:a-arg 10}
+              :b {:b-arg 10}})))))
+
+(deftest composed-builders
+  (let [ff (fn [v] [v (fn [] (prn "destroying" v))])
+        sb (s/system-builder [[:a ff {:a-arg [:foo]}]
+                              [:b ff {:b-arg [:a :a-arg]}]])
+        sb2 (s/system-builder sb [[:c ff {:c-a [:a :a-arg]
+                                          :c-b [:b :b-arg]}]])
+        sys (s/start-system! sb2 {:foo 10})]
+
+    (testing "single item system has the single object"
+      (is (= @(s/system-map sys)
+             {:foo 10
+              :a {:a-arg 10}
+              :b {:b-arg 10}
+              :c {:c-a 10 :c-b 10}})))))


no test p012

no test p012


don't break the back button

don't break the back button

--- src-cljs/frontend/controllers/controls.cljs
+++ src-cljs/frontend/controllers/controls.cljs
@@ -1317,8 +1317,7 @@

 (defmethod post-control-event! :launch-app-clicked
   [target message _ previous-state current-state]
-  (put! (get-in current-state [:comms :nav]) [:navigate! {:path (str "/document/" (:document/id current-state))
-                                                          :replace-token? true}]))
+  (put! (get-in current-state [:comms :nav]) [:navigate! {:path (str "/document/" (:document/id current-state))}]))

 (defmethod control-event :subscriber-updated
   [browser-state message {:keys [client-id fields]} state]


Show debug messages

Show debug messages

--- src/webapp/server/fns.clj
+++ src/webapp/server/fns.clj
@@ -115,9 +115,11 @@

 (defn check-messages []
   (let [messages-waiting (neo4j "match (n:AskForEndorsement) return n" {} "n")]
+    (println (str "AskForEndorsement: " messages-waiting))
     (dorun (map process-ask-for-endorsement  messages-waiting)))

   (let [messages-waiting (neo4j "match (n:AskForEndorsementContactReceiver) return n" {} "n")]
+    (println (str "AskForEndorsementContactReceiver: " messages-waiting))
     (dorun (map process-ask-for-endorsement-ask-receiver  messages-waiting)))

@@ -234,6 +236,10 @@
           )
         []
         )))
+
+
+
+

 (defn request-endorsement [{:keys [from-full-name
@@ -265,7 +271,9 @@
                                          }
                                         "n"))
         ]
-    web-record)
+    (do
+      (println (str "WebRecord: " web-record))
+      web-record))
   )


indentation

indentation

--- src-cljs/frontend/components/aside.cljs
+++ src-cljs/frontend/components/aside.cljs
@@ -60,13 +60,14 @@
       (let [{:keys [cast!]} (om/get-shared owner)
             client-id (str client-uuid)
             chats (ds/touch-all '[:find ?t :where [?t :chat/body]] @db)
-            dummy-chat {:chat/body [:span "Welcome to Precursor! "
-                                          "Create fast prototypes and share your url to collaborate. "
-                                          "Chat "
-                                          [:a {:on-click #(cast! :aside-user-clicked {:id-str (str/lower-case chat-bot)})
-                                               :role "button"}
-                                           (str "@" (str/lower-case chat-bot))]
-                                          " for help."]
+            dummy-chat {:chat/body [:span
+                                    "Welcome to Precursor! "
+                                    "Create fast prototypes and share your url to collaborate. "
+                                    "Chat "
+                                    [:a {:on-click #(cast! :aside-user-clicked {:id-str (str/lower-case chat-bot)})
+                                         :role "button"}
+                                     (str "@" (str/lower-case chat-bot))]
+                                    " for help."]
                         :chat/color "#00b233"
                         :session/uuid chat-bot
                         :server/timestamp (js/Date. 0)}]


Update oracle.clj.

Update oracle.clj.

--- src/dbms/oracle.clj
+++ src/dbms/oracle.clj
@@ -2,18 +2,18 @@
   (:use (korma db core config))
   (:require (clojure [string :as str])))

+;; (def db-spec
+;;   {:classname "oracle.jdbc.OracleDriver"
+;;    :subprotocol "oracle"
+;;    :subname "thin:@192.168.1.83:1521:testdb"
+;;    :user "xxx"
+;;    :password "xxx"
+;;    :naming {:keys str/lower-case :fields str/upper-case}})
+
 (def db-spec
-  {:classname "oracle.jdbc.OracleDriver"
-   :subprotocol "oracle"
-   :subname "thin:@192.168.1.83:1521:testdb"
-   :user "xxx"
-   :password "xxx"
-   :naming {:keys str/lower-case :fields str/upper-case}})
-
-;; (def db-spec
-;;   (oracle {:keys ["192.168.1.83" 1521 true]
-;;            :as {:user "hr" :password "hr"}
-;;            :naming {:keys str/lower-case :fields str/upper-case}}))
+  (oracle {:subname "@//192.168.1.83:1521/testdb"
+           :user "xxx" :password "xxx"
+           :naming {:keys str/lower-case :fields str/upper-case}}))

 (defdb korma-db db-spec)


Don't need anonymous function

Don't need anonymous function

--- src/exploud/setup.clj
+++ src/exploud/setup.clj
@@ -149,5 +149,5 @@
 (defn -main
   "The entry point for the application."
   [& args]
-  (.addShutdownHook (Runtime/getRuntime) (Thread. #(shutdown-agents)))
+  (.addShutdownHook (Runtime/getRuntime) (Thread. shutdown-agents))
   (start))


checkbox now handles :options

checkbox now handles :options

--- src/ez_form/field.clj
+++ src/ez_form/field.clj
@@ -65,10 +65,33 @@
   (let [id (get-first field :id :name)
         value (:value-added field)
         checked? (:checked field)
+        options (:options field)
         opts (get-opts field [:class :name :value :type] form-options)]
-    [:input (merge {:value value} opts {:id id} (if (or checked?
-                                                        (= value (:value opts)))
-                                                  {:checked true}))]))
+    (if options
+      (map (fn [option]
+             (let [[value label] (if (sequential? option)
+                                   option
+                                   [option option])
+                   id (str (name id) "-" value)]
+               (list [:input (merge {:value value}
+                                    opts
+                                    {:id id}
+                                    (if (and
+                                         (not (nil? value))
+                                         (or checked?
+                                             (= value (:value opts))
+                                             (= "on" (:value opts))
+                                             (= "on" value)))
+                                      {:checked true}))]
+                     [:label {:for id} label])))
+           options)
+      [:input (merge {:value value} opts {:id id} (if (and
+                                                       (not (nil? value))
+                                                       (or checked?
+                                                           (= value (:value opts))
+                                                           (= "on" (:value opts))
+                                                           (= "on" value)))
+                                                    {:checked true}))])))

 (defmethod field :radio [field form-options]
   (let [id (get-first field :id :name)


Update parser.clj

Update parser.clj


Fix checkout-keys path.

Fix checkout-keys path.

Stray char ruins everything

--- src-cljs/frontend/api/path.cljs
+++ src-cljs/frontend/api/path.cljs
@@ -16,7 +16,7 @@
                   "/api/dangerzone/project/%s/%s/checkout-key"
                   vcs-type repo-name)
     "github" (gstring/format
-               "/api1/v1/project/%s/checkout-key"
+               "/api/v1/project/%s/checkout-key"
                repo-name)))

 (defn project-checkout-key  [vcs-type repo-name fingerprint]


try mobile feature artwork without imgs

try mobile feature artwork without imgs

--- src-cljs/frontend/components/landing.cljs
+++ src-cljs/frontend/components/landing.cljs
@@ -198,11 +198,27 @@
      [:div.art-screen
       [:div.art-menu
        [:div.art-heading "Today"]
-       [:div.art-doc [:div.art-doc-frame   [:img.art-doc-img {:src "https://prcrsr.com/document/17592196129062.svg"}]]]
-       [:div.art-doc.selected [:div.art-doc-frame [:img.art-doc-img {:src "https://prcrsr.com/document/17592196129062.svg"}]]]
-       [:div.art-doc   [:div.art-doc-frame [:img.art-doc-img {:src "https://prcrsr.com/document/17592196129062.svg"}]]]
-       [:div.art-doc   [:div.art-doc-frame [:img.art-doc-img {:src "https://prcrsr.com/document/17592196129062.svg"}]]]]
-      [:div.art-canvas [:div.art-doc-frame [:img.art-doc-img {:src "https://prcrsr.com/document/17592196129062.svg"}]]]
+       [:div.art-doc
+        [:div.art-doc-frame
+         ; [:img.art-doc-img {:src "https://prcrsr.com/document/17592196129062.svg"}]
+         ]]
+       [:div.art-doc.selected
+        [:div.art-doc-frame
+         ; [:img.art-doc-img {:src "https://prcrsr.com/document/17592196129062.svg"}]
+         ]]
+       [:div.art-doc
+        [:div.art-doc-frame
+         ; [:img.art-doc-img {:src "https://prcrsr.com/document/17592196129062.svg"}]
+         ]]
+       [:div.art-doc
+        [:div.art-doc-frame
+         ; [:img.art-doc-img {:src "https://prcrsr.com/document/17592196129062.svg"}]
+         ]]]
+      [:div.art-canvas
+       [:div.art-doc-frame
+        [:img.art-doc-img
+         ; {:src "https://prcrsr.com/document/17592196129062.svg"}
+         ]]]
       [:div.art-screen-select]]]
     [:div.art-mobile-foot
      [:div.art-mobile-button]]]])


remove unused prolog copy ideas

remove unused prolog copy ideas

--- src-cljs/frontend/components/landing.cljs
+++ src-cljs/frontend/components/landing.cljs
@@ -69,18 +69,7 @@
               (common/google-login :small)]]
             [:div.our-philosphy-wrap.content
              [:div.our-philosphy
-              ; [:h1 "Sharing prototypes with your team should be easy."]
-              ; [:h1 "Prototyping with your team should be easy."]
-              ; [:h1 "Brainstorming should be easier."]
-              ; [:h1 "Brainstorming should be easier from anywhere."]
-              ; [:h1 "Brainstorming with your team should be easy from anywhere."]
               [:h1 "Collaborating with your team should be easy from anywhere."]
-              ; [:p "Prototype just your ideas without all the nonsense."]
-              ; [:p "Prototype just your ideas without all the nonsense, anytime and on any device."]
-              ; [:p "Prototype your ideas anywhere, with any device, and without all the nonsense."]
-              ; [:p "Prototype your ideas anywhere, with any device, and without the nonsense."]
-              ; [:p "Prototype ideas anywhere, with any device, and without nonsense."]
-              ; [:p "Prototype ideas anywhere without all the nonsense, and on any device."]
               [:p "Prototype ideas anywhere, with anyone, and on any device. No nonsense, it's just what you need, when you need it."]
               [:div.call-to-action
                [:button {:on-click #(cast! :landing-closed)} "Jump in and make a ________."]]]]]


hide learn-more banner to test out customer quote

--- src-cljs/frontend/components/landing.cljs
+++ src-cljs/frontend/components/landing.cljs
@@ -282,17 +282,19 @@
       (let [cast! (om/get-shared owner :cast!)]
         (html
          [:div.the-how
-          [:div.landing-learn-back {:class (when (and (:show-scroll-to-arrow app) (not (contains? active-features "1"))) " show ")}]
-
-          (if (get-in app state/dn-discount-path)
-            [:div.landing-learn-front.dn-override {:class (when-not (contains? active-features "1") " show ")}
-             [:a.dn-discount {:href "/pricing" :style {:width "auto"}}
-              (common/icon :dn-logo)
-              "Hi Designer News, here's 50% off for 3 mo!"]]
-            [:div.landing-learn-front {:class (when-not (contains? active-features "1") " show ")}
-             [:a.landing-learn-link {:role "button" :on-click #(cast! :scroll-to-arrow-clicked)}
-              "Learn more."]])
-
+          ;;
+          ;; May not need this learn more banner with customer quote there now
+          ;;
+          ;; [:div.landing-learn-back {:class (when (and (:show-scroll-to-arrow app) (not (contains? active-features "1"))) " show ")}]
+          ;;
+          ;; (if (get-in app state/dn-discount-path)
+          ;;   [:div.landing-learn-front.dn-override {:class (when-not (contains? active-features "1") " show ")}
+          ;;    [:a.dn-discount {:href "/pricing" :style {:width "auto"}}
+          ;;     (common/icon :dn-logo)
+          ;;     "Hi Designer News, here's 50% off for 3 mo!"]]
+          ;;   [:div.landing-learn-front {:class (when-not (contains? active-features "1") " show ")}
+          ;;    [:a.landing-learn-link {:role "button" :on-click #(cast! :scroll-to-arrow-clicked)}
+          ;;     "Learn more."]])
           [:div.feature.content {:class (when (contains? active-features "1") "art-visible") :ref "1"}
            [:div.feature-story
             [:h2.content-copy