Refactor rules for handle zoom and better performance.

--- src/uxbox/ui/workspace/rules.cljs
+++ src/uxbox/ui/workspace/rules.cljs
@@ -15,9 +15,7 @@
             [uxbox.ui.workspace.base :as wb]
             [uxbox.ui.mixins :as mx]))

-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; Constants & Helpers
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; --- Constants & Helpers

 (def ^:const zoom 1)
 (def ^:const step-padding 20)
@@ -34,77 +32,128 @@
   (concat (range (- (/ wb/viewport-width 1)) 0 step-size)
           (range 0 (/ wb/viewport-width 1) step-size)))

-(def ^:const +rule-padding+ 20)
+(def ^:const rule-padding 20)

-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; Horizontal Rule
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
-(defn vertical-tick-render
-  [own value]
-  (let [big-ticks-mod (big-ticks-mod 1)
-        mid-ticks-mod (mid-ticks-mod 1)
+(defn- make-vertical-tick
+  [zoom acc value]
+  (let [big-ticks-mod (big-ticks-mod zoom)
+        mid-ticks-mod (mid-ticks-mod zoom)
         big-step? (< (mod value big-ticks-mod) step-size)
         mid-step? (< (mod value mid-ticks-mod) step-size)
-        pos (+ value +rule-padding+
+        pos (+ value
+               rule-padding
                wb/canvas-start-x
                wb/canvas-scroll-padding)
         pos (* pos zoom)]
     (cond
-      big-step?
-      (html
-       [:g {:key value}
-        [:line {:x1 pos
-                :x2 pos
-                :y1 5
-                :y2 step-padding
-                :stroke "#9da2a6"}]
-        [:text {:x (+ pos 2)
-                :y 13
-                :fill "#9da2a6"
-                :style {:font-size "12px"}}
-         value]])
+      (< (mod value big-ticks-mod) step-size)
+      (conj acc (str/format "M %s %s L %s %s" pos 5 pos step-padding))

-      mid-step?
-      (html
-       [:line {:key pos
-               :x1 pos
-               :x2 pos
-               :y1 10
-               :y2 step-padding
-               :stroke "#9da2a6"}])
+      (< (mod value mid-ticks-mod) step-size)
+      (conj acc (str/format "M %s %s L %s %s" pos 10 pos step-padding))

       :else
+      (conj acc (str/format "M %s %s L %s %s" pos 15 pos step-padding)))))
+
+(defn- make-horizontal-tick
+  [zoom acc value]
+  (let [big-ticks-mod (big-ticks-mod zoom)
+        mid-ticks-mod (mid-ticks-mod zoom)
+        pos (+ value
+               wb/canvas-start-x
+               wb/canvas-scroll-padding)
+        pos (* pos zoom)]
+    (cond
+      (< (mod value big-ticks-mod) step-size)
+      (conj acc (str/format "M %s %s L %s %s" 5 pos step-padding pos))
+
+      (< (mod value mid-ticks-mod) step-size)
+      (conj acc (str/format "M %s %s L %s %s" 10 pos step-padding pos))
+
+      :else
+      (conj acc (str/format "M %s %s L %s %s" 15 pos step-padding pos)))))
+
+;; --- Horizontal Text Label
+
+(defn- horizontal-text-label
+  [zoom value]
+  (let [big-ticks-mod (big-ticks-mod zoom)
+        pos (+ value
+               rule-padding
+               wb/canvas-start-x
+               wb/canvas-scroll-padding)
+        pos (* pos zoom)]
+    (when (< (mod value big-ticks-mod) step-size)
       (html
-       [:line {:key pos
-               :x1 pos
-               :x2 pos
-               :y1 15
-               :y2 step-padding
-               :stroke "#9da2a6"}]))))
+       [:text {:x (+ pos 2)
+               :y 13
+               :key (str pos)
+               :fill "#9da2a6"
+               :style {:font-size "12px"}}
+        value]))))

-(def ^:const vertical-tick
+;; --- Horizontal Text Label
+
+(defn- vertical-text-label
+  [zoom value]
+  (let [big-ticks-mod (big-ticks-mod zoom)
+        pos (+ value
+               wb/canvas-start-x
+               wb/canvas-scroll-padding)
+        pos (* pos zoom)]
+    (when (< (mod value big-ticks-mod) step-size)
+      (html
+       [:text {:y (- pos 3)
+               :x 5
+               :key (str pos)
+               :fill "#9da2a6"
+               :transform (str/format "rotate(90 0 %s)" pos)
+               :style {:font-size "12px"}}
+        value]))))
+
+;; --- Horizontal Rule Ticks (Component)
+
+(defn- horizontal-rule-ticks-render
+  [own zoom]
+  (let [zoom (or zoom 1)
+        path (reduce (partial make-vertical-tick zoom) [] +ticks+)
+        labels (->> (map (partial horizontal-text-label zoom) +ticks+)
+                    (filterv identity))]
+    (println (count labels))
+    (html
+     [:g
+      [:path {:d (str/join " " path) :stroke "#9da2a6"}]
+      labels])))
+
+(def ^:const ^:private horizontal-rule-ticks
   (mx/component
-   {:render vertical-tick-render
-    :name "vertical-tick-render"
+   {:render horizontal-rule-ticks-render
+    :name "horizontal-rule-ticks"
     :mixins [mx/static]}))

-(defn vertical-ticks-render
-  [own]
-  (html
-   [:g
-    (for [value +ticks+]
-      (-> (vertical-tick value)
-          (rum/with-key value)))]))
+;; --- Vertical Rule Ticks (Component)

-(def ^:const vertical-ticks
+(defn- vertical-rule-ticks-render
+  [own zoom]
+  (let [zoom (or zoom 1)
+        path (reduce (partial make-horizontal-tick zoom) [] +ticks+)
+        labels (->> (map (partial vertical-text-label zoom) +ticks+)
+                    (filterv identity))]
+    (html
+     [:g
+      [:path {:d (str/join " " path) :stroke "#9da2a6"}]
+      labels])))
+
+(def ^:const ^:private vertical-rule-ticks
   (mx/component
-   {:render vertical-ticks-render
-    :name "vertical-ticks-render"
+   {:render vertical-rule-ticks-render
+    :name "vertical-rule-ticks"
     :mixins [mx/static]}))

+;; --- Horizontal Rule (Component)
+
 (defn horizontal-rule-render
-  [own sidebar?]
+  [own zoom]
   (let [scroll (rum/react wb/scroll-a)
         scroll-x (:x scroll)
         translate-x (- (- wb/canvas-scroll-padding) (:x scroll))]
@@ -113,7 +162,7 @@
       {:width wb/viewport-width
        :height 20}
       [:g {:transform (str "translate(" translate-x ", 0)")}
-       (vertical-ticks)]])))
+       (horizontal-rule-ticks zoom)]])))

 (def horizontal-rule
   (mx/component
@@ -121,77 +170,10 @@
     :name "horizontal-rule"
     :mixins [mx/static rum/reactive]}))

-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; Horizontal Rule
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
-(defn horizontal-tick-render
-  [own value]
-  (let [big-ticks-mod (big-ticks-mod 1)
-        mid-ticks-mod (mid-ticks-mod 1)
-        big-step? (< (mod value big-ticks-mod) step-size)
-        mid-step? (< (mod value mid-ticks-mod) step-size)
-        pos (+ value
-               wb/canvas-start-x
-               wb/canvas-scroll-padding)
-        pos (* pos zoom)]
-  (cond
-    big-step?
-    (html
-     [:g {:key pos}
-      [:line {:y1 pos
-              :y2 pos
-              :x1 5
-              :x2 step-padding
-              :stroke "#9da2a6"}]
-      [:text {:y pos
-              :x 5
-              :transform (str/format "rotate(90 0 %s)" pos)
-              :fill "#9da2a6"
-              :style {:font-size "12px"}}
-       value]])
-
-    mid-step?
-    (html
-     [:line {:key pos
-             :y1 pos
-             :y2 pos
-             :x1 10
-             :x2 step-padding
-             :stroke "#9da2a6"}])
-
-    :else
-    (html
-     [:line {:key pos
-             :y1 pos
-             :y2 pos
-             :x1 15
-             :x2 step-padding
-             :stroke "#9da2a6"}]))))
-
-(def ^:const horizontal-tick
-  (mx/component
-   {:render horizontal-tick-render
-    :name "horizontal-tick-render"
-    :mixins [mx/static]}))
-
-(defn- horizontal-ticks-render
-  [own]
-  (html
-   [:g
-    (for [value +ticks+]
-      (-> (horizontal-tick value)
-          (rum/with-key value)))]))
-
-(def ^:const horizontal-ticks
-  (mx/component
-   {:render horizontal-ticks-render
-    :name "horizontal-ticks-render"
-    :mixins [mx/static]}))
+;; --- Vertical Rule (Component)

 (defn vertical-rule-render
-  [own sidebar?]
+  [own zoom]
   (let [scroll (rum/react wb/scroll-a)
         scroll-y (:y scroll)
         translate-y (- (- wb/canvas-scroll-padding) (:y scroll))]
@@ -201,7 +183,7 @@
        :height wb/viewport-height}

       [:g {:transform (str  "translate(0, " translate-y ")")}
-       (horizontal-ticks)]
+       (vertical-rule-ticks zoom)]
       [:rect {:x 0
               :y 0
               :height 20


Test commit - resolving magit/EMACSCLIENT issue

--- src/vdquil/chapter5/figure5-7.clj
+++ src/vdquil/chapter5/figure5-7.clj
@@ -2,7 +2,7 @@
 ;; Sample ranking that highlights lines
 ;; Converted from Processing to Clojure as an exercise by Dave Liepmann

-;; TODO use salary as a tiebreaker for rankings (p127)
+;; TODO use salary as a tiebreaker for rankings (page 127)

 (ns vdquil.chapter5.figure5-7
   (:use quil.core)


(maint) Add test for invalid PQL queries on entity endpoints

PQL queries on query entity endpoints (like query/v4/inventory) should
return a 400 HTTP status and produce an error message about a failed
JSON parse attempt.

--- test/puppetlabs/puppetdb/http/inventory_test.clj
+++ test/puppetlabs/puppetdb/http/inventory_test.clj
@@ -223,6 +223,12 @@
         (is (= 500 status))
         (is (= "Value does not match schema: (not (map? nil))" body))))

+    (testing "pql query fails with json parse error message"
+      (let [query "inventory[]{}"
+            {:keys [body status]} (query-response method endpoint query)]
+        (is (= 400 status))
+        (is (re-find #"^Json parse error" body))))
+
     (testing "inventory queries"
       (testing "well-formed queries"
         (doseq [[query result] (queries-and-results timestamp)]


Added more tests for nimbus interop

Added more tests for nimbus interop

Actually Nimbus can use BouncyCastle generated ECDSA keys,
so i've changed generation code to use them and added more
curve and JWS types

--- test/buddy/sign/interop_tests.clj
+++ test/buddy/sign/interop_tests.clj
@@ -40,7 +40,7 @@
            com.nimbusds.jose.crypto.MACVerifier
            com.nimbusds.jose.crypto.DirectEncrypter
            com.nimbusds.jose.crypto.DirectDecrypter
-           (com.nimbusds.jose.crypto ECDSAVerifier)
+           com.nimbusds.jose.crypto.ECDSAVerifier
            (javax.crypto KeyGenerator)
            (java.security SecureRandom KeyPairGenerator)
            (java.security.spec ECGenParameterSpec)))
@@ -119,17 +119,31 @@
     (is (.verify jwt (MACVerifier. key32)))
     (is (= "test" (.. jwt getJWTClaimsSet (getClaim "test1"))))))

-(let [kg (KeyPairGenerator/getInstance "EC")
-      ;; for speed
-      sr (SecureRandom/getInstance "SHA1PRNG")
-      ;; Nimbus can't handle BouncyCastle's ECDSA keys so we use Java EC spec
-      _ (.initialize kg (ECGenParameterSpec. "secp256r1") sr)
-      pair (.generateKeyPair kg)]
-  (def ecdsa-priv-sun (.getPrivate pair))
-  (def ecdsa-pub-sun (.getPublic pair)))
+(defn generate-ecdsa-pair [curvename]
+  (let [kg (KeyPairGenerator/getInstance "EC" "BC")
+        _ (.initialize kg (ECGenParameterSpec. curvename) (SecureRandom/getInstance "SHA1PRNG"))
+        pair (.generateKeyPair kg)
+        public (.getPublic pair)
+        private (.getPrivate pair)]
+    [public private]))

-(deftest interoperability-test-7
-  (let [token (jws/sign (json/generate-string {:test1 "test"}) ecdsa-priv-sun {:alg :es256})
+(deftest interoperability-test-es256
+  (let [[public private] (generate-ecdsa-pair "P-256")
+        token (jws/sign (json/generate-string {:test1 "test"}) private {:alg :es256})
         jwt (SignedJWT/parse token)]
-    (is (.verify jwt (ECDSAVerifier. ecdsa-pub-sun)))
+    (is (.verify jwt (ECDSAVerifier. public)))
     (is (= "test" (.. jwt getJWTClaimsSet (getClaim "test1"))))))
+
+(deftest interoperability-test-es384
+  (let [[public private] (generate-ecdsa-pair "P-384")
+        token (jws/sign (json/generate-string {:test1 "test"}) private {:alg :es384})
+        jwt (SignedJWT/parse token)]
+    (is (.verify jwt (ECDSAVerifier. public)))
+    (is (= "test" (.. jwt getJWTClaimsSet (getClaim "test1"))))))
+
+(deftest interoperability-test-es512
+  (let [[public private] (generate-ecdsa-pair "P-521")
+        token (jws/sign (json/generate-string {:test1 "test"}) private {:alg :es512})
+        jwt (SignedJWT/parse token)]
+    (is (.verify jwt (ECDSAVerifier. public)))
+    (is (= "test" (.. jwt getJWTClaimsSet (getClaim "test1"))))))


Fix test

Fix test

--- test/caesium/crypto/hash_test.clj
+++ test/caesium/crypto/hash_test.clj
@@ -1,7 +1,8 @@
 (ns caesium.crypto.hash-test
   (:require [caesium.crypto.hash :as h]
             [caesium.vectors :as v]
-            [clojure.test :refer [deftest is are]]))
+            [clojure.test :refer [deftest is are]]
+            [caesium.util :refer [array-eq]]))

 (def ^:private hash-vector
   (comp v/hex-resource (partial str "vectors/hash/")))
@@ -23,8 +24,8 @@
 (deftest sha-256-512-test
   "sha256 and 512 work directly"
   (are [f message expected] (array-eq expected (f message))
-    sha256 sha256-message (sha256-vector "digest-0")
-    sha256 empty-string (sha256-vector "digest-empty-string")
+    h/sha256 sha256-message (sha256-vector "digest-0")
+    h/sha256 empty-string (sha256-vector "digest-empty-string")

-    sha512 sha512-message (sha512-vector "digest-0")
-    sha512 empty-string (sha512-vector "digest-empty-string")))
+    h/sha512 sha512-message (sha512-vector "digest-0")
+    h/sha512 empty-string (sha512-vector "digest-empty-string")))


Add tests for writing variants with undeclared keys

--- test/cljam/io/bcf/writer_test.clj
+++ test/cljam/io/bcf/writer_test.clj
@@ -1,8 +1,10 @@
 (ns cljam.io.bcf.writer-test
   (:require [clojure.test :refer :all]
             [clojure.string :as cstr]
-            [cljam.io.bcf.writer :as bcf-writer])
-  (:import [java.nio ByteBuffer]))
+            [cljam.io.bcf.writer :as bcf-writer]
+            [cljam.io.util.bgzf :as bgzf])
+  (:import [java.nio ByteBuffer ByteOrder]
+           [java.io ByteArrayOutputStream File]))

 (deftest about-encode-typed-value
   (let [ba (#'bcf-writer/encode-typed-value :int (vec (repeat 14 1)))]
@@ -210,3 +212,58 @@
      0x80 0x81
      0x02 0x02
      0x02 0x04]))
+
+(defn- bgzf->bb ^ByteBuffer [f]
+  (with-open [is (bgzf/bgzf-input-stream f)
+              baos (ByteArrayOutputStream.)]
+    (while (pos? (.available is))
+      (.write baos (.read is)))
+    (.flush baos)
+    (doto (ByteBuffer/wrap (.toByteArray baos))
+      (.order ByteOrder/LITTLE_ENDIAN))))
+
+(defn- read-variant-blocks! [f]
+  (let [bb (bgzf->bb f)]
+    (doseq [b (map byte [\B \C \F 2 2])]
+      (assert (= b (.get bb))))
+    (.position bb (+ (.getInt bb) (.position bb)))
+    (->> (repeatedly
+          #(when (.hasRemaining bb)
+             (let [shared (byte-array (.getInt bb))
+                   indiv (byte-array (.getInt bb))]
+               (.get bb shared)
+               (.get bb indiv)
+               [(vec shared) (vec indiv)])))
+         (take-while some?)
+         vec)))
+
+(defn- write-variants&read-blocks [meta-info header variants]
+  (let [tmp (File/createTempFile "write-variants" ".bcf")]
+    (with-open [w (bcf-writer/writer tmp meta-info header)]
+      (bcf-writer/write-variants w variants))
+    (let [blocks (read-variant-blocks! tmp)]
+      (.delete tmp)
+      blocks)))
+
+(deftest write-variants
+  (let [meta-info {:fileformat "VCFv4.3"
+                   :contig [{:id "1", :length 100}]}
+        header ["CHROM" "POS" "ID" "REF" "ALT" "QUAL" "FILTER" "INFO"
+                "FORMAT" "SAMPLE"]]
+    (are [?variants ?blocks]
+         (= (map #(map (partial map unchecked-byte) %) ?blocks)
+            (write-variants&read-blocks meta-info header ?variants))
+      [{:chr "1", :pos 10, :ref "A", :alt ["C"],
+        :info {:UNDECLARED-INFO #{"???"}},
+        :FORMAT [:UNDECLARED-FORMAT]}]
+      [[[0x00 0x00 0x00 0x00
+         0x09 0x00 0x00 0x00
+         0x01 0x00 0x00 0x00
+         0x01 0x00 0x80 0x7f
+         0x00 0x00 0x02 0x00
+         0x01 0x00 0x00 0x00
+         0x07
+         0x17 0x41
+         0x17 0x43
+         0x00]
+        []]])))


fixed some links generation

fixed some links generation

--- src-cljs/acha.cljs
+++ src-cljs/acha.cljs
@@ -44,11 +44,16 @@
 (defn map-by [f xs]
   (reduce (fn [acc x] (assoc acc (f x) x)) {} xs))

+(defn trimr [s suffix]
+  (let [pos (- (count s) (count suffix))]
+    (if (and (>= (count s) (count suffix))
+             (= (subs s pos) suffix))
+      (subs s 0 pos)
+      s)))
+
 (defn repo-name [url]
-  (let [[_ m] (re-matches #".*/([^/]+)" url)]
-    (if (and m (re-matches #".*\.git" m))
-      (subs m 0 (- (count m) 4))
-      m)))
+  (let [[_ m] (re-matches #".*/([^/]+)/?" url)]
+    (trimr m ".git")))

 ;; Navigation

@@ -132,11 +137,11 @@

 (defn- sha1-url [url sha1]
   (let [path (condp re-matches url
-               #"(?i)(?:https?://)?(?:www\.)?github.com/([\-_\w0-9\.\/]+/?)\.git" :>> second
-               #"(?i)git\@github\.com\:([\-_\w0-9\.\/]+)\.git" :>> second
+               #"(?i)(?:https?://)?(?:www\.)?github.com/(.+)" :>> second
+               #"(?i)git\@github\.com\:(.+)" :>> second
                nil)]
     (when path
-      (str "https://github.com/" path "/commit/" sha1))))
+      (str "https://github.com/" (trimr path ".git") "/commit/" sha1))))

 (r/defc ach [achent aches]
   (s/html


pretty-print the result of a submission

pretty-print the result of a submission

--- src/cljs/org/broadinstitute/firecloud_ui/page/workspace/method_config_editor.cljs
+++ src/cljs/org/broadinstitute/firecloud_ui/page/workspace/method_config_editor.cljs
@@ -172,7 +172,7 @@
                :status-warning-triangle)
              (icons/font-icon {:style {:fontSize "200%" :color (:success-green style/colors)}}
                             :status-done))
-           (:launch-result @state)]
+           [:pre {} (.stringify js/JSON (.parse js/JSON (:launch-result @state)) nil 2)]]
           [:div {}
            (style/create-form-label "Select Entity Type")
            (style/create-select


Ring middleware: Move test of `wrap-json-body`


Label now fades when input is valid. References #47.

--- src/app/cljs/one/sample/animation.cljs
+++ src/app/cljs/one/sample/animation.cljs
@@ -47,7 +47,7 @@
   "Make the passed input field label invisible. Run when the input
   field loses focus and contains a valid input value."
   [label]
-  (play label {:effect :fade :end 0 :time 200}))
+  (play label {:effect :fade :start 1 :end 0 :time 200}))

 (def move-down [{:effect :fade :end 1 :time 200}
                 {:effect :color :end "#BBC4D7" :time 200}


Open twitter up in a new tab when clicked from the footer.

--- src-cljs/frontend/components/footer.cljs
+++ src-cljs/frontend/components/footer.cljs
@@ -34,4 +34,5 @@
     [:div.col-sm-1
      [:a.fa.fa-twitter
       {:title "Follow CircleCI on Twitter",
-       :href "https://twitter.com/circleci"}]]]])
+       :href "https://twitter.com/circleci"
+       :target "_blank"}]]]])


Make sure header links work on enterprise

--- src-cljs/frontend/components/header.cljs
+++ src-cljs/frontend/components/header.cljs
@@ -134,8 +134,11 @@
                                     :height 25})]
               (if logged-in?
                 [:a.mobile-nav {:href "/dashboard"} "Back to app"]
-                [:a.mobile-nav.signup (open-ext {:href "/signup/"}) "Sign up"])
-              ]
+                [:a.mobile-nav.signup
+                 (open-ext {:href (if (config/enterprise?)
+                                    (auth-url)
+                                    "/signup/")})
+                 "Sign up"])]
              [:div.navbar-container {:class hamburger-state}
               [:ul.nav.navbar-nav
                (when (config/show-marketing-pages?)
@@ -184,7 +187,12 @@
                    [:li (maybe-active nav-point :pricing)
                     [:a.menu-item (open-ext {:href "/pricing/"}) "Pricing"]]))
                [:li (maybe-active nav-point :documentation)
-                [:a.menu-item (open-ext {:href "/docs"}) "Documentation"]]
+                [:a.menu-item {:href "https://circleci.com/docs"}
+                 (if (config/enterprise?)
+                  "CircleCI Documentation"
+                  "Documentation")]]
+               (if (config/enterprise?)
+                 [:li [:a.menu-item {:href "https://enterprise-docs.circleci.com"} "Enterprise Documentation"]])
                [:li [:a.menu-item {:href "https://discuss.circleci.com" :target "_blank"} "Discuss"]]
                (when (config/show-marketing-pages?)
                  (list
@@ -206,9 +214,10 @@
                                                   :on-click #((om/get-shared owner :track-event) {:event-type :login-clicked})
                                                   :title "Log In with Github"}
                    "Log In"]]
-                 [:li
-                  [:a.signup-link.btn.btn-success.navbar-btn.menu-item (open-ext {:href "/signup/"
-                                                                                :on-click #((om/get-shared owner :track-event) {:event-type :signup-clicked})}) "Sign Up"]]])]]]
+                 (when (not (config/enterprise?))
+                   [:li
+                    [:a.signup-link.btn.btn-success.navbar-btn.menu-item (open-ext {:href "/signup/"
+                                                                                :on-click #((om/get-shared owner :track-event) {:event-type :signup-clicked})}) "Sign Up"]])])]]]
            (outer-subheader
              [{:mobile {:path "/mobile"
                         :title "Mobile"}


fix typo

fix typo

--- src/babel/espanol/morphology/verbs.clj
+++ src/babel/espanol/morphology/verbs.clj
@@ -468,9 +468,9 @@
         (= :plur (get-in word [:agr :number]))
         (get-in word [:preterito :3plur]))
    (get-in word [:preterito :3plur])
-   true (regular-preterito word {usted :usted
-                                 vosotros :vosotros
-                                 ustedes :ustedes})))
+   true (regular-preterito word {:usted usted
+                                 :vosotros vosotros
+                                 :ustedes ustedes})))

 (defn regular-preterito [word {usted :usted
                                vosotros :vosotros


type init on clear

type init on clear

--- data/celestial/fixtures/populate.clj
+++ data/celestial/fixtures/populate.clj
@@ -64,7 +64,9 @@
   ([] (re-initlize false))
   ([clear-es]
    (c/initilize-puny)
-   (when clear-es (es/clear))
+   (when clear-es
+     (es/clear)
+     (es/initialize))
    (red/clear-all)))

 (defn populate-all
@@ -88,6 +90,6 @@
   "run populate all"
   [& args]
   (set-user {:username "admin"}
-            (populate-all)
-            (p/delete-user "admin"); will be set up in next launch
-            (println "populate done!")))
+     (populate-all)
+     (p/delete-user "admin"); will be set up in next launch
+     (println "populate done!")))


disables assertion in test-streaming for multi-router scenario (#806)

--- waiter/integration/waiter/streaming_test.clj
+++ waiter/integration/waiter/streaming_test.clj
@@ -61,8 +61,7 @@
         ;; there is no content length on the canary request
         (is (= (inc num-streaming-requests) (get request-size-histogram :count 0))
             (str "request-size-histogram: " request-size-histogram))
-        (is (= 0.0 (get-in request-size-histogram [:value :0.0] 0.0))
-            (str "request-size-histogram: " request-size-histogram))
+        ;; we do not assert the 0th percentile as the value may be corrupted during a multi-router merge
         (is (->> (get-in request-size-histogram [:value :1.0] 0.0) (- body-size) Math/abs (>= epsilon))
             (str "request-size-histogram: " request-size-histogram))
         (is (= (inc num-streaming-requests) (get response-size-histogram :count))


remove test line

remove test line

Signed-off-by: Koleman Nix <9f9effdfeb1aae8da61017791c660428b97c5749@gmail.com>

--- markov-clj/src/markov_clj/markov.clj
+++ markov-clj/src/markov_clj/markov.clj
@@ -74,5 +74,3 @@
                                   (interpose " " ,,)
                                   (apply str ,,)))]
     (repeatedly generation-fn)))
-
-(println "\n" (first (generate (parse-corpus (slurp "resources/koleman_tweets.txt")) 1)))


Update to clojure 1.10.2

Update to clojure 1.10.2

--- project.clj
+++ project.clj
@@ -6,7 +6,7 @@
   :scm {:name "git"
         :url  "https://github.com/otto-de/tesla-jetty"}

-  :dependencies [[org.clojure/clojure "1.8.0"]
+  :dependencies [[org.clojure/clojure "1.10.2"]
                  [ring/ring-jetty-adapter "1.6.3"]
                  [io.prometheus/simpleclient_jetty "0.1.0"]
                  ;Overwrite outdated,transitive dependencies


Test utilities

Test utilities

--- src/flatgui/samples/forms/compound.clj
+++ src/flatgui/samples/forms/compound.clj
@@ -19,9 +19,8 @@
             [flatgui.samples.forms.hellowindow :as hw]
             [flatgui.samples.forms.colorchooserwin :as cc]
             [flatgui.samples.forms.orderticketwin :as ticket]
-            [flatgui.samples.forms.blotterwin :as blotterwin])
-  (:import (java.awt Container)
-           (java.awt.event MouseEvent)))
+            [flatgui.samples.forms.blotterwin :as blotterwin]
+            [flatgui.testsuite]))

 (fg/defevolverfn main-theme-evolver :theme
   (if (get-property [:this :header-panel :dark] :pressed)
@@ -120,20 +119,7 @@
 ;;; both check boxes - as if it was for UI testing
 ;;;

-(def dummy-source (Container.))
-
-(defn simulate-mouse-left [container id target]
-  (flatgui.widgets.componentbase/evolve-container
-    container
-    target
-    (MouseEvent. dummy-source id 0 0 0 0 0 0 1 false MouseEvent/BUTTON1)))
-
-(defn simulate-mouse-click [container target]
-  (-> (simulate-mouse-left container MouseEvent/MOUSE_PRESSED target)
-      (simulate-mouse-left MouseEvent/MOUSE_RELEASED target)
-      (simulate-mouse-left MouseEvent/MOUSE_CLICKED target)))
-
 ;;; raw-compoundpanel container with two simulated mouse clicks passed to it
 (def compoundpanel
-  (-> (simulate-mouse-click raw-compoundpanel [:main :header-panel :hello-world])
-      (simulate-mouse-click [:main :header-panel :color-chooser])))+  (-> (flatgui.testsuite/simulate-mouse-click raw-compoundpanel [:main :header-panel :hello-world])
+      (flatgui.testsuite/simulate-mouse-click [:main :header-panel :color-chooser])))


made example changes

made example changes

--- example/src/example/core.cljs
+++ example/src/example/core.cljs
@@ -1,6 +1,7 @@
 (ns example.core
   (:require
-   [figwheel.client :as fw :include-macros true]
+   #_[figwheel.client :as fw :include-macros true]
+   [example.client :as fw]
    [example.cube]
    [crate.core]))

@@ -10,10 +11,18 @@
 ;; you must call this function to start the listener that reloads
 ;; the compiled javascript

-;; this is commented out because we are invoking it at the bottom of
-;; this file
-;; (fw/watch-and-reload
-;;   :jsload-callback (fn [] (ex2-reload)))
+(declare ex2-restart)
+
+(fw/start
+ {
+  :websocket-url "ws://localhost:3449/figwheel-ws"
+  :on-jsload (fn []
+               (ex2-restart)
+               ;; this is a better way to reload the cube example
+               ;; which will reload even for non-local changes
+               ;; (example.cube/stop-and-start-ex3)
+               )
+  })

 ;; When you are writing reloadable code you have to protect things
 ;; that you don't want defined over and over.
@@ -22,7 +31,7 @@
 ;; You should see the changed statement printed out in the console of
 ;; your web inspector.

-(println "This is a reloaded print statement: modify me.")
+(println "This is a reloaded print statement: modify me now.")

 ;; Example 1:  simple crate based app

@@ -113,17 +122,3 @@

 ;; start the app once
 (defonce start-ex2 (ex2-start))
-
-;; this is a better way to reload the cube example
-;; (defonce start-cube (example.cube/stop-and-start-ex3))
-
-;; IMPORTANT!!!
-;; Here we start the websocket listener
-(fw/watch-and-reload
- :websocket-url "ws://localhost:3449/figwheel-ws"
- :jsload-callback (fn []
-                    (ex2-restart)
-                    ;; this is a better way to reload the cube example
-                    ;; which will reload even for non-local changes
-                    ;; (example.cube/stop-and-start-ex3)
-                    ))


binary matrix success

binary matrix success

--- fmri/src/cljs/fmri/core.cljs
+++ fmri/src/cljs/fmri/core.cljs
@@ -23,25 +23,23 @@
 (defmethod cf/formatter* :fressian [_]
   (reify cf/ChordFormatter
     (freeze [_ obj] (fressian/write obj))
-    (thaw [_ s]
+    (thaw [_ s]
       (println "incoming fressian object:")
       (js/console.log s)
-      (fressian/read s :handlers
+      (fressian/read s :handlers
                      (assoc fressian/cljs-read-handler "array"
                             (fn [reader tag component-count]
                               (println "component-count: " component-count)
                               (let [shape (freader/read-object reader)
-                                    size (apply + shape)]
+                                    size (apply + shape)
+                                    ary (make-array size)]
                                 (println "shape: " shape)
-                                shape)))))))
+                                (doseq [i (range size)]
+                                  (aset ary i (freader/read-double reader)))
+                                {:type :matrix
+                                 :shape shape
+                                 :data ary})))))))

-
-(defn read-array
-  [obj]
-  (println "read-array")
-  (let [shape (freader/read-object obj)]
-    (println "SHAPE: " shape)
-    shape))

 (defn home-page []
   (let [msg (atom "")]
@@ -56,9 +54,8 @@
             (js/console.log error))
           (do
             (println "MSG:")
-            (js/console.log message)
-            (js/console.log (type message))
-            (reset! msg (read-array message))))
+            (println message)
+            (reset! msg message)))
         (reset! conn* conn)))
     (fn []
       [:div [:h2 "Welcome to fmri"]


Add better request method

Add better request method

--- src/leiningen/new/cljskel/web_unit.clj
+++ src/leiningen/new/cljskel/web_unit.clj
@@ -1,11 +1,23 @@
 (ns {{name}}.unit.web
-    (:require [{{name}}.web :refer :all]
-              [cheshire.core :as json]
-              [midje.sweet :refer :all]))
+  (:require [{{name}}.web :refer :all]
+            [cheshire.core :as json]
+            [midje.sweet :refer :all])
+  (:import [java.io ByteArrayInputStream InputStream]))

-(defn request [method resource]
-  (app {:request-method method
-        :uri resource}))
+(defn request
+  "Creates a compojure request map and applies it to our routes.
+   Accepets method, resource and optionally an extended map"
+  [method resource & [{:keys [params body content-type]
+                       :or {:params {}}}]]
+  (let [{:keys [body] :as res}
+        (app (merge {:request-method method
+                     :uri resource
+                     :params params}
+                    (when body {:body (-> body json/generate-string .getBytes ByteArrayInputStream.)})
+                    (when content-type {:content-type content-type})))]
+    (cond-> res
+            (instance? InputStream body)
+            (assoc :body (json/parse-string (slurp body) true)))))

 (fact-group
  :unit


clean target as well

clean target as well

--- src/leiningen/new/figwheel/project.clj
+++ src/leiningen/new/figwheel/project.clj
@@ -17,7 +17,7 @@

   :source-paths ["src"]

-  :clean-targets ^{:protect false} ["resources/public/js/compiled"]
+  :clean-targets ^{:protect false} ["resources/public/js/compiled" "target"]

   :cljsbuild {
     :builds [{:id "dev"


Upgrade re-frame-10x to 0.4.3

Upgrade re-frame-10x to 0.4.3

--- src/leiningen/new/re_frame/project.clj
+++ src/leiningen/new/re_frame/project.clj
@@ -49,7 +49,7 @@
   :profiles
   {:dev
    {:dependencies [[binaryage/devtools "0.9.10"]{{#10x?}}
-                   [day8.re-frame/re-frame-10x "0.4.2"]
+                   [day8.re-frame/re-frame-10x "0.4.3"]
                    [day8.re-frame/tracing "0.5.3"]{{/10x?}}{{#re-frisk?}}
                    [re-frisk "0.5.4.1"]{{/re-frisk?}}]}


CMR-2652: Used are3 for the Ancillary Keyword search tests.

--- system-int-test/test/cmr/system_int_test/search/collection_keyword_search_test.clj
+++ system-int-test/test/cmr/system_int_test/search/collection_keyword_search_test.clj
@@ -528,30 +528,35 @@
                                (assoc exp-conv/example-collection-record
                                       :AncillaryKeywords ["CMR-2652-AKW1" "CMR-2652-AKW2"])
                                {:format :umm-json
-                                :accept-format :json})
-        keyword-str1 "CMR-2652-AKW1"
-        keyword-str2 "CMR-2652-AKW2"
-        keyword-str3 "CMR-2652-AKW3"]
+                                :accept-format :json})]
     (index/wait-until-indexed)
-    (testing "search by existing ancillary keywords parameter match."
-      (let [parameter-refs (search/find-refs :collection {:keyword keyword-str1})
-            parameter-matches? (d/refs-match? [c10-umm-json] parameter-refs)]
-        (is parameter-matches?)))
-
-    (testing "search by non-existing ancillary keywords parameter match."
-      (let [parameter-refs (search/find-refs :collection {:keyword keyword-str3})
-            parameter-matches? (d/refs-match? [] parameter-refs)]
-        (is parameter-matches?)))
-
-    (testing "search by existing ancillary keywords json query match."
-      (let [json-refs (search/find-refs-with-json-query :collection {} {:keyword keyword-str2})
-            json-matches? (d/refs-match? [c10-umm-json] json-refs)]
-        (is json-matches?)))
-
-    (testing "search by non-existing ancillary keywords json query match."
-      (let [json-refs (search/find-refs-with-json-query :collection {} {:keyword keyword-str3})
-            json-matches? (d/refs-match? [] json-refs)]
-        (is json-matches?)))))
+    (testing "parameter searches"
+      (are3 [keyword-str items]
+        (let [parameter-refs (search/find-refs :collection {:keyword keyword-str})
+              parameter-matches? (d/refs-match? items parameter-refs)]
+          (is parameter-matches?))
+
+        "testing parameter search by existing ancillary keywords"
+        "CMR-2652-AKW1"
+        [c10-umm-json]
+
+        "testing parmaeter search by non-existing ancillary keywords"
+        "CMR-2652-NO-AKW"
+        []))
+
+    (testing "json query searchs"
+      (are3 [keyword-str items]
+        (let [json-refs (search/find-refs-with-json-query :collection {} {:keyword keyword-str})
+              json-matches? (d/refs-match? items json-refs)]
+          (is json-matches?))
+
+        "testing json query search by existing ancillary keywords"
+        "CMR-2652-AKW2"
+        [c10-umm-json]
+
+        "testing json query search by non-existing ancillary keywords"
+        "CMR-2652-NO-AKW"
+        []))))

 ;; This tests that when searching by relevancy that if the score is the same short name ascending is used for
 ;; sorting the results and then if short name is the same version is used for sorting the results


Prefer aliases over refers + minor docstring changes

A stylistic change to avoid :use in the ns declaration.

--- src/main/clojure/clojure/tools/cli.clj
+++ src/main/clojure/clojure/tools/cli.clj
@@ -1,8 +1,7 @@
 (ns ^{:author "Gareth Jones, Sung Pae"}
   clojure.tools.cli
-  (:use [clojure.string :as s :only [replace]]
-        [clojure.pprint :only [cl-format]])
-  (:refer-clojure :exclude [replace]))
+  (:require [clojure.pprint :as pp]
+            [clojure.string :as s]))

 (defn- tokenize-args
   "Reduce arguments sequence into [opt-type opt ?optarg?] vectors and a vector
@@ -88,11 +87,11 @@
         vs (for [d docs]
              (mapcat (fn [& x] (apply vector x)) max-cols d))]
     (doseq [v vs]
-      (cl-format true "~{ ~vA  ~vA  ~vA ~}" v)
+      (pp/cl-format true "~{ ~vA  ~vA  ~vA ~}" v)
       (prn))))

 (defn- name-for [k]
-  (replace k #"^--no-|^--\[no-\]|^--|^-" ""))
+  (s/replace k #"^--no-|^--\[no-\]|^--|^-" ""))

 (defn- flag-for [^String v]
   (not (.startsWith v "--no-")))
@@ -155,8 +154,8 @@
   [switches flag]
   (-> (for [^String s switches]
         (cond
-         (and flag (flag? s))            [(replace s #"\[no-\]" "no-") (replace s #"\[no-\]" "")]
-         (and flag (.startsWith s "--")) [(replace s #"--" "--no-") s]
+         (and flag (flag? s))            [(s/replace s #"\[no-\]" "no-") (s/replace s #"\[no-\]" "")]
+         (and flag (.startsWith s "--")) [(s/replace s #"--" "--no-") s]
          :default                        [s]))
       flatten))

@@ -365,7 +364,7 @@
   (let [fmt (case (count lens)
               2 "~{  ~vA  ~vA~}"
               3 "~{  ~vA  ~vA  ~vA~}")]
-    (map #(s/trimr (cl-format nil fmt (interleave lens %))) parts)))
+    (map #(s/trimr (pp/cl-format nil fmt (interleave lens %))) parts)))

 (defn ^{:added "0.3.0"} summarize
   "Reduce options specs into a options summary for printing at a terminal."
@@ -463,7 +462,8 @@
                    :default 0
                    :assoc-fn (fn [m k _] (update-in m [k] inc))]

-    :validate     A vector of [validate-fn validate-msg].
+    :validate     A vector of [validate-fn validate-msg]; the validation
+                  message is optional.

     :validate-fn  A function that receives the parsed option value and returns
                   a falsy value when the value is invalid.
@@ -477,8 +477,7 @@
      :arguments   A vector of unprocessed arguments
      :summary     A string containing a minimal options summary
      :errors      A possible vector of error message strings generated during
-                  parsing; nil when no errors exist
-     }
+                  parsing; nil when no errors exist}

   A few function options may be specified to influence the behavior of
   parse-opts:


FIX: catch process channel exception

FIX: catch process channel exception

--- src/main/clojure/pdok/featured/api.clj
+++ src/main/clojure/pdok/featured/api.clj
@@ -49,19 +49,26 @@
         persistence (config/persistence)
         projectors (config/projectors persistence)
         processor (processor/create persistence projectors)]
-    (with-open [in (io/input-stream (:file request))]
-      (let [features (reader/features-from-stream in :dataset (:dataset request))
-            consumed (consume processor features)
-            n-processed (count consumed)
-            _ (shutdown processor)
-            end-time (tl/local-now)
-            process-time (t/in-seconds (t/interval start-time end-time))
-            run-stats (assoc request :n-processed n-processed :start-time start-time :end-time end-time
-                             :process-time process-time)]
-        (swap! stats update-in [:processed] #(conj % run-stats))
-        (swap! stats assoc-in [:processing] nil)
-        (when (:callback request)
-          (go (>! callback-chan [(:callback request) (-> run-stats (dissoc :callback))]))))))
+    (try (with-open [in (io/input-stream (:file request))]
+           (let [features (reader/features-from-stream in :dataset (:dataset request))
+                 consumed (consume processor features)
+                 n-processed (count consumed)
+                 _ (shutdown processor)
+                 end-time (tl/local-now)
+                 process-time (t/in-seconds (t/interval start-time end-time))
+                 run-stats (assoc request :n-processed n-processed :start-time start-time :end-time end-time
+                                  :process-time process-time)]
+             (swap! stats update-in [:processed] #(conj % run-stats))
+             (swap! stats assoc-in [:processing] nil)
+             (when (:callback request)
+               (go (>! callback-chan [(:callback request) (-> run-stats (dissoc :callback))])))))
+         (catch Exception e
+           (let [error-stats (assoc request :error (str e))]
+             (log/warn error-stats)
+             (swap! stats update-in [:errored] #(conj % error-stats))
+             (swap! stats assoc-in [:processing] nil)
+             (when (:callback request)
+               (go (>! callback-chan [(:callback request) (-> error-stats (dissoc :callback))])))))))
   )

 (defn- process [process-chan http-req]
@@ -84,7 +91,8 @@
   (let [pc (chan)
         cc (chan 10)
         stats (atom {:processing nil
-                     :processed []})]
+                     :processed []
+                     :errored []})]
     (go (while true (process* stats cc (<! pc))))
     (go (while true (apply callbacker (<! cc))))
     (-> (api-routes pc cc stats)


Remove contrib dependencies from r.m.stacktrace.

--- ring-devel/src/ring/middleware/stacktrace.clj
+++ ring-devel/src/ring/middleware/stacktrace.clj
@@ -4,7 +4,6 @@
         hiccup.page-helpers
         clj-stacktrace.core
         clj-stacktrace.repl
-        (clojure.contrib [def :only (defvar-)])
         ring.util.response))

 (defn wrap-stacktrace-log
@@ -81,7 +80,7 @@
     wrap-stacktrace-log
     wrap-stacktrace-web))

-(defvar- css "
+(def ^{:private true} css "
 /*
 Copyright (c) 2008, Yahoo! Inc. All rights reserved.
 Code licensed under the BSD License:


More DRY on stroke SVG.

More DRY on stroke SVG.

--- src/cbfg/core.cljs
+++ src/cbfg/core.cljs
@@ -201,10 +201,9 @@
                              ay (actx-y actx)
                              cy (ch-y ch)]
                          [(if (= :put wait-kind)
-                            ["<line x1='500' y1='" ay "' x2='600' y2='" cy
-                             "' stroke='#faa' stroke-width='1' marker-end='url(#triangle)'/>"]
-                            ["<line x1='600' y1='" cy "' x2='500' y2='" ay
-                             "' stroke='#faa' stroke-width='1' marker-end='url(#triangle)'/>"])
+                            ["<line x1='500' y1='" ay "' x2='600' y2='" cy]
+                            ["<line x1='600' y1='" cy "' x2='500' y2='" ay])
+                          "' stroke='#faa' stroke-width='1' marker-end='url(#triangle)'/>"
                           (when ch-name
                             ["<text class='ch-name' x='540' y='" (* 0.5 (+ ay cy))
                              "'>" ch-name "</text>"])]))
@@ -218,22 +217,22 @@
                  [(case (:delta delta)
                     :put (when (get chs (:ch delta))
                            ["<g transform='translate(500," ay ")'>"
-                            "<line class='delta' x1='0' y1='0' x2='100' y2='" (- cy ay)
-                            "' stroke='green' stroke-width='1' marker-end='url(#triangle)'/></g>"])
+                            "<line class='delta' x1='0' y1='0' x2='100' y2='"
+                            (- cy ay) "' stroke='green'"])
                     :take (when (get chs (:ch delta))
                             ["<g transform='translate(600," cy ")'>"
-                             "<line class='delta' x1='0' y1='0' x2='-100' y2='" (- ay cy)
-                             "' stroke='" (if (:msg delta) "green" "black")
-                             "' stroke-width='1' marker-end='url(#triangle)'/></g>"])
+                             "<line class='delta' x1='0' y1='0' x2='-100' y2='"
+                             (- ay cy) "' stroke='" (if (:msg delta) "green" "black") "'"])
                     :actx-start (when (> childy line-height)
                                   ["<g transform='translate(30," ay ")'>"
-                                   "<line class='delta' x1='0' y1='0' x2='30' y2='" (- childy ay)
-                                   "' stroke='green' stroke-width='1' marker-end='url(#triangle)'/></g>"])
+                                   "<line class='delta' x1='0' y1='0' x2='30' y2='"
+                                   (- childy ay) "' stroke='green'"])
                     :actx-end (when (> childy line-height)
                                 ["<g transform='translate(60," childy ")'>"
-                                 "<line class='delta' x1='0' y1='0' x2='-30' y2='" (- ay childy)
-                                 "' stroke='black' stroke-width='1' marker-end='url(#triangle)'/></g>"])
+                                 "<line class='delta' x1='0' y1='0' x2='-30' y2='"
+                                 (- ay childy) "' stroke='black'"])
                     nil)
+                  " stroke-width='1' marker-end='url(#triangle)'/></g>"
                   (when (:ch-name delta)
                     ["<text class='ch-name' x='540' y='" (* 0.5 (+ ay cy))
                      "'>" (:ch-name delta) "</text>"])])))


Add events for :track-clicked and :refresh-clicked.

--- samples/twitterbuzz/src/twitterbuzz/core.cljs
+++ samples/twitterbuzz/src/twitterbuzz/core.cljs
@@ -14,12 +14,21 @@

 (def state (atom {:max-id 1
                   :graph {}
-                  :new-tweets-listeners []
-                  :graph-update-listeners []
+                  :listeners {:new-tweets []
+                              :graph-update []
+                              :track-clicked []
+                              :refresh-clicked []}
                   :tweet-count 0}))

-(defn add-listener [k f]
-  (swap! state (fn [old] (assoc old k (conj (k old) f)))))
+(defn add-listener [old-state k f]
+  (let [l (-> old-state :listeners k)]
+    (assoc-in old-state [:listeners k] (conj l f))))
+
+(defn register
+  "Register a function to be called when new data arrives specifying
+  the event to receive updates for. Events can be :new-tweets or :graph-update."
+  [event f]
+  (swap! state add-listener event f))

 (def twitter-uri (goog.Uri. "http://twitter.com/search.json"))

@@ -28,9 +37,12 @@
          payload
          callback))

-(defn send-tweets [fns tweets]
-  (doseq [f fns]
-    (f tweets)))
+(defn send-event
+  ([event]
+     (send-event event nil))
+  ([event message]
+     (doseq [f (-> @state :listeners event)]
+       (f message))))

 (defn matches [p s]
   (seq (js* "~{s}.match(new RegExp(~{p}, 'g'))")))
@@ -80,22 +92,15 @@
         tweets (filter #(> (:id %) old-max)
                        (:results result-map))]
     (do  (swap! state update-state new-max tweets)
-         (send-tweets (:new-tweets-listeners @state) tweets)
-         (send-tweets (:graph-update-listeners @state) (:graph @state)))))
-
-(defn register
-  "Register a function to be called when new data arrives specifying
-  the event to receive updates for. Events can be :new-tweets or :graph-update."
-  [event f]
-  (cond (= event :new-tweets) (add-listener :new-tweets-listeners f)
-        (= event :graph-update) (add-listener :graph-update-listeners f)))
+         (send-event :new-tweets tweets)
+         (send-event :graph-update (:graph @state)))))

 (defn search-tag
   "Get the current tag value from the page."
   []
   (.value (dom/getElement "twitter-search-tag")))

-(defn listener []
+(defn do-timer []
   (retrieve (.strobj {"q" (search-tag)}) my-callback))

 (defn poll
@@ -103,10 +108,27 @@
   you at the 150 request/hour rate limit. We can speed it up for the demo."
   []
   (let [timer (goog.Timer. 24000)]
-    (do (listener)
+    (do (do-timer)
         (. timer (start))
-        (events/listen timer goog.Timer/TICK listener))))
+        (events/listen timer goog.Timer/TICK do-timer))))

+(defn do-track-button-clicked []
+  (send-event :track-clicked))
+
+(defn do-refresh-button-clicked []
+  (send-event :refresh-clicked))
+
+(defn start-app []
+  (events/listen (dom/getElement "twitter-search-button")
+                 "click"
+                 do-track-button-clicked)
+  (events/listen (dom/getElement "refresh-button")
+                 "click"
+                 do-refresh-button-clicked))
+
+;; this should be rolled up into one and the polling should only start
+;; when the track button is clicked.
+(start-app)
 (poll)

 (comment


client store tests

client store tests

--- iwaswhere-web/test/iwaswhere_web/client_store_test.cljc
+++ iwaswhere-web/test/iwaswhere_web/client_store_test.cljc
@@ -1,6 +1,7 @@
 (ns iwaswhere-web.client-store-test
   "Here, we test the handler functions of the server side store component."
   (:require [clojure.test :refer [deftest testing is]]
+            [iwaswhere-web.store-test :as st]
             [iwaswhere-web.client-store :as store]))

 (def empty-query
@@ -34,9 +35,54 @@
    :timestamp      1465059173965
    :md             "Moving to #cljc"})

+(def state-from-backend
+  {:entries [test-entry st/some-test-entry]
+   :linked-entries-list []
+   :hashtags            #{"#drama" "#hashtag" "#blah"}
+   :mentions            #{"@myself" "@me" "@I"}
+   :stats               {:entry-count 4118 :node-count 5636 :edge-count 28726}
+   :duration-ms         19})
+
 (def entry-update
   {:timestamp 1465059173965
    :md        "Moving to #cljc. Edited entry."})
+
+(def entry-geo-update
+  {:mentions   #{}
+   :tags       #{}
+   :timezone   "Europe/Berlin"
+   :new-entry  true
+   :utc-offset -120
+   :longitude  9.9
+   :latitude   53.5
+   :timestamp  1465059173965
+   :md         ""})
+
+(deftest new-state-test
+  (let [current-state @(:state (store/initial-state-fn #()))
+        new-state (:new-state (store/new-state-fn {:current-state current-state
+                                                   :msg-payload   state-from-backend}))]
+    (testing "entries are on new state"
+      (is (= (:entries new-state) (:entries state-from-backend))))
+    (testing "entries map is on new state"
+      (is (= (:entries-map new-state)
+             (into {} (map (fn [entry] [(:timestamp entry) entry]) (:entries state-from-backend))))))
+    (testing "hashtags are on new state"
+      (is (= (:hashtags (:cfg new-state)) (:hashtags state-from-backend))))
+    (testing "mentions are on new state"
+      (is (= (:mentions (:cfg new-state)) (:mentions state-from-backend))))
+    (testing "stats are on new state"
+      (is (= (:stats new-state) (:stats state-from-backend))))
+    (testing "query duration is on new state"
+      (is (= (:duration-ms new-state) (:duration-ms state-from-backend))))))
+
+(deftest set-active-test
+  "Test that active entry is updated properly in store component state"
+  (let [current-state @(:state (store/initial-state-fn #()))
+        new-state (:new-state (store/set-active-fn {:current-state current-state
+                                                    :msg-payload   test-entry}))]
+    (testing "active entry is set"
+      (is (= test-entry (:active new-state))))))

 (deftest update-query-test
   "Test that new query is updated properly in store component state"
@@ -71,15 +117,67 @@
       (is (= :state/get (first emit-msg)))
       (is (= updated-query (second emit-msg))))))

+(deftest new-entry-test
+  "Test that local entry is properly set in state."
+  (with-redefs [store/new-entries-ls (atom {})]
+    (let [current-state @(:state (store/initial-state-fn #()))
+          new-state (:new-state (store/new-entry-fn {:current-state current-state :msg-payload test-entry}))]
+      (testing "pomodoro test entry in new-entries"
+        (is (= test-entry (get-in new-state [:new-entries 1465059173965]))))
+      (testing "new entries atom properly updated - this would be backed by localstorage on client"
+        (is (= (:new-entries new-state) @store/new-entries-ls))))))
+
 (deftest update-local-test
   "Test that local entry is properly attached to state."
-  (let [current-state @(:state (store/initial-state-fn #()))
-        new-state (:new-state (store/update-local-fn {:current-state current-state :msg-payload test-entry}))
-        new-state2 (:new-state (store/update-local-fn {:current-state new-state :msg-payload entry-update}))]
-    (testing "pomodoro test entry in new-entries"
-      (is (= test-entry (get-in new-state [:new-entries 1465059173965]))))
-    (testing "entry update is merged with previous entry, thus allows omitting keys"
-      (is (= (merge test-entry entry-update) (get-in new-state2 [:new-entries 1465059173965]))))))
+  (with-redefs [store/new-entries-ls (atom {})]
+    (let [current-state @(:state (store/initial-state-fn #()))
+          new-state (:new-state (store/update-local-fn {:current-state current-state :msg-payload test-entry}))
+          new-state2 (:new-state (store/update-local-fn {:current-state new-state :msg-payload entry-update}))]
+      (testing "pomodoro test entry in new-entries"
+        (is (= test-entry (get-in new-state [:new-entries 1465059173965]))))
+      (testing "entry update is merged with previous entry, thus allows omitting keys"
+        (is (= (merge test-entry entry-update) (get-in new-state2 [:new-entries 1465059173965]))))
+      (testing "new entries atom properly updated - this would be backed by localstorage on client"
+        (is (= (:new-entries new-state2) @store/new-entries-ls))))))
+
+(deftest geo-enrich-test
+  "Test that local entry is properly attached to state."
+  (with-redefs [store/new-entries-ls (atom {})]
+    (let [current-state @(:state (store/initial-state-fn #()))
+          new-state (:new-state (store/update-local-fn {:current-state current-state :msg-payload test-entry}))
+          new-state2 (:new-state (store/geo-enrich-fn {:current-state new-state :msg-payload entry-geo-update}))]
+      (testing "pomodoro test entry in new-entries"
+        (is (= test-entry (get-in new-state [:new-entries 1465059173965]))))
+      (testing "entry update is merged with previous entry, thus allows omitting keys"
+        (is (= (merge entry-geo-update test-entry) (get-in new-state2 [:new-entries 1465059173965]))))
+      (testing "new entries atom properly updated - this would be backed by localstorage on client"
+        (is (= (:new-entries new-state2) @store/new-entries-ls))))))
+
+(deftest remove-local-test
+  "Test that local entry is properly removed from state after delete message."
+  (with-redefs [store/new-entries-ls (atom {})]
+    (let [current-state @(:state (store/initial-state-fn #()))
+          new-state (:new-state (store/update-local-fn {:current-state current-state :msg-payload test-entry}))
+          new-state2 (:new-state (store/remove-local-fn {:current-state new-state :msg-payload entry-update}))]
+      (testing "pomodoro test entry in new-entries"
+        (is (= test-entry (get-in new-state [:new-entries 1465059173965]))))
+      (testing "entry update is removed from component state"
+        (is (not (get-in new-state2 [:new-entries 1465059173965]))))
+      (testing "new entries atom properly updated - this would be backed by localstorage on client"
+        (is (= (:new-entries new-state2) @store/new-entries-ls))))))
+
+(deftest entry-saved-test
+  "New entry removed after backend confirms save."
+  (with-redefs [store/new-entries-ls (atom {})]
+    (let [current-state @(:state (store/initial-state-fn #()))
+          new-state (:new-state (store/update-local-fn {:current-state current-state :msg-payload test-entry}))
+          new-state2 (:new-state (store/entry-saved-fn {:current-state new-state :msg-payload entry-update}))]
+      (testing "test entry in new-entries"
+        (is (= test-entry (get-in new-state [:new-entries 1465059173965]))))
+      (testing "entry update is removed from component state after receiving save confirmation"
+        (is (not (get-in new-state2 [:new-entries 1465059173965]))))
+      (testing "new entries atom properly updated - this would be backed by localstorage on client"
+        (is (= (:new-entries new-state2) @store/new-entries-ls))))))

 (def pomodoro-inc-msg
   {:timestamp 1465059173965})
@@ -87,13 +185,46 @@
 (deftest pomodoro-inc-test
   "Test the time increment handler for running pomodoros. Expectation is that the :completed-time key
   is incremented on every call."
-  (let [current-state @(:state (store/initial-state-fn #()))
-        new-state (:new-state (store/update-local-fn {:current-state current-state :msg-payload test-entry}))
-        new-state1 (:new-state (store/pomodoro-inc-fn {:current-state new-state :msg-payload pomodoro-inc-msg}))
-        new-state2 (:new-state (store/pomodoro-inc-fn {:current-state new-state1 :msg-payload pomodoro-inc-msg}))]
-    (testing "pomodoro test entry in new-entries"
-      (is (= test-entry (get-in new-state [:new-entries 1465059173965]))))
-    (testing "time incremented"
-      (is (= 1 (get-in new-state1 [:new-entries 1465059173965 :completed-time]))))
-    (testing "time incremented"
-      (is (= 2 (get-in new-state2 [:new-entries 1465059173965 :completed-time]))))))
+  (with-redefs [store/new-entries-ls (atom {})]
+    (let [current-state @(:state (store/initial-state-fn #()))
+          new-state (:new-state (store/update-local-fn {:current-state current-state :msg-payload test-entry}))
+          new-state1 (:new-state (store/pomodoro-inc-fn {:current-state new-state :msg-payload pomodoro-inc-msg}))
+          new-state2 (:new-state (store/pomodoro-inc-fn {:current-state new-state1 :msg-payload pomodoro-inc-msg}))]
+      (testing "pomodoro test entry in new-entries"
+        (is (= test-entry (get-in new-state [:new-entries 1465059173965]))))
+      (testing "time incremented"
+        (is (= 1 (get-in new-state1 [:new-entries 1465059173965 :completed-time]))))
+      (testing "time incremented"
+        (is (= 2 (get-in new-state2 [:new-entries 1465059173965 :completed-time]))))
+      (testing "new entries atom properly updated - this would be backed by localstorage on client"
+        (is (= (:new-entries new-state2) @store/new-entries-ls))))))
+
+(deftest toggle-key-test
+  "toggle key messages flip boolean value"
+  (let [current-state @(:state (store/initial-state-fn #()))
+        new-state (:new-state (store/toggle-key-fn {:current-state current-state
+                                                    :msg-payload   {:path [:cfg :sort-by-upvotes]}}))
+        new-state2 (:new-state (store/toggle-key-fn {:current-state current-state
+                                                     :msg-payload   {:path [:some :crazy :long :path]}}))]
+    (testing "before receiving toggle-key msg, key is false, as per initial state"
+      (is (not (:sort-by-upvotes (:cfg current-state)))))
+    (testing "after receiving toggle-key msg, key is true"
+      (is (:sort-by-upvotes (:cfg new-state))))
+    (testing "previously unknown key is set to true. can be nested"
+      (is (get-in new-state2 [:some :crazy :long :path])))))
+
+(deftest toggle-set-test
+  "toggle key messages flip boolean value"
+  (let [test-ts 1465059139281
+        path [:cfg :show-maps-for]
+        current-state @(:state (store/initial-state-fn #()))
+        new-state (:new-state (store/toggle-set-fn {:current-state current-state
+                                                    :msg-payload   {:timestamp test-ts :path path}}))
+        new-state1 (:new-state (store/toggle-set-fn {:current-state new-state
+                                                     :msg-payload   {:timestamp test-ts :path path}}))]
+    (testing "cfg set is initially empty"
+      (is (empty? (:show-maps-for (:cfg current-state)))))
+    (testing "set contains timestamp after initial toggle"
+      (is (contains? (:show-maps-for (:cfg new-state)) test-ts)))
+    (testing "timestamp removed from set after subsequent toggle"
+      (is (not (contains? (:show-maps-for (:cfg new-state1)) 1465059139281))))))


Reduce history steps

Reduce history steps


adding fancy response

adding fancy response

--- src/clojure/my/company/superapp/main.clj
+++ src/clojure/my/company/superapp/main.clj
@@ -41,7 +41,7 @@
                     ;; calling static method way 1: (This hang the connection so nothing is being return "empty reponse)
                     ;; (.newFixedLengthResponse NanoHTTPD (str msg "\n"))
                     ;; calling static method way 2: (This cause the application to crash
-                    (NanoHTTPD/newFixedLengthResponse "This is a test")
+                    (NanoHTTPD/newFixedLengthResponse (str msg "\n"))
                     )
                   )
                 )]


CMR-814: Escape double quotes as special characters in queries

--- src/cmr/search/data/query_to_elastic.clj
+++ src/cmr/search/data/query_to_elastic.clj
@@ -35,7 +35,7 @@

 (def query_string-reserved-characters-regex
   "Characters reserved for elastic query_string queries. These must be escaped."
-  #"([+\-\[\]!\^:\\/{}\(\)]|&&)")
+  #"([+\-\[\]!\^:\\/{}\(\)\\\"]|&&)")

 (defprotocol ConditionToElastic
   "Defines a function to map from a query to elastic search query"


documenting and testing workaround for specifying environment variables in shell-step until #9 is fixed

--- test/clj/lambdacd/steps/shell_test.clj
+++ test/clj/lambdacd/steps/shell_test.clj
@@ -31,6 +31,8 @@
       (is (= "foo\nbar\n" (:out (bash (some-ctx)"/" "echo foo" "echo bar" "exit 1" "echo baz")))))
     (testing "that the output also contains stderr"
       (is (= "foo\nerror\nbaz\n" (:out (bash (some-ctx)"/" "echo foo" ">&2 echo error" "echo baz")))))
+    (testing "that exports work until we are able to set environment variables"
+      (is (= "foo\n" (:out (bash (some-ctx)"/" "export X=foo" "echo $X")))))
     (testing "that the output channel is updated with every line"
       (let [some-ctx (some-ctx)
             result-channel (:result-channel some-ctx)]


Add tests for member?

Add tests for member?

--- test/little_clojurer/chapter2_test.clj
+++ test/little_clojurer/chapter2_test.clj
@@ -9,3 +9,13 @@
     (is (lat? '()))
     (is (lat? '(:a)))
     (is (lat? '(:a 1)))))
+
+(deftest member?-test
+  (testing
+    (is (not (member? :a '())))
+    (is (not (member? 1 '())))
+    (is (not (member? '() '('()))))
+    (is (member? :a '(:a :a :a)))
+    (is (member? 1 '(:a 1 :a)))
+    (is (member? :a '(1 1 1 :a)))))
+


use some-checker instead of read-string

use some-checker instead of read-string

--- test/midje/emission/plugins/t_util.clj
+++ test/midje/emission/plugins/t_util.clj
@@ -15,8 +15,8 @@
   ;; Note ordering
   (attractively-stringified-value {:b 2 :a 1}) => "{:a 1, :b 2}"
   (attractively-stringified-value #{9 6 2 7 1 3}) => "#{1 2 3 6 7 9}"
-  (read-string (attractively-stringified-value #{[1] [:a]})) => #{[1] [:a]}
-  (read-string (attractively-stringified-value {[1] "1" [:a] "a"})) => {[1] "1" [:a] "a"}
+  (attractively-stringified-value #{[1] [:a]}) => (some-checker "#{[1] [:a]}" "#{[:a] [1]}")
+  (attractively-stringified-value {[1] "1" [:a] "a"}) => (some-checker "{[1] \"1\", [:a] \"a\"}" "{[:a] \"a\", [1] \"1\"}")
   (attractively-stringified-value (R. 1 2 3)) => #"\{:a 3, :m 2, :x 1\}::\S+\.R")


gh-33 -> fix broken test

gh-33 -> fix broken test

--- test/untangled_spec/provided_spec.cljc
+++ test/untangled_spec/provided_spec.cljc
@@ -81,7 +81,7 @@
            (assertions
              (take 2 (th/locate `im/with-reporting expanded))
              => `(im/with-reporting
-                   {:type :provided :string "some string"})))))
+                   {:type :provided :string "PROVIDED: some string"})))))

      (behavior "Can do mocking without output"
        (let [expanded (p/provided* false :skip-output


cyanite: docstring

cyanite: docstring

--- src/io/cyanite.clj
+++ src/io/cyanite.clj
@@ -31,6 +31,11 @@
       (System/exit 1))))

 (defn build-components
+  "Build a list of components from data.
+   Extracts key k from system and yield
+   an updated system with top-level keys.
+   components are created by call f on them
+   options."
   [system k f]
   (if (seq (get system k))
     (merge (dissoc system k)


added render-func for kioo.core

added render-func for kioo.core

--- src/kioo/core.cljs
+++ src/kioo/core.cljs
@@ -178,3 +178,6 @@
       (assoc node
         :attrs (merge (:attrs node) sev)
         :events (merge (:events node) rev)))))
+
+(defn render [component node]
+  (.renderComponent js/React component node))


Added map-with

Added map-with

--- src/parse/core.clj
+++ src/parse/core.clj
@@ -295,18 +295,16 @@

 (defn rpc-unmarshall-args
   [schema-arg-trees msg-arg-trees]
-  (let [fn-unmarshall-arg
-        (fn [schema-tree msg-tree]
-          (let [schema-arg-name (fetch-in schema-tree [:attrs :name])
-                schema-arg-type (fetch-in schema-tree [:attrs :type])
-                schema-arg-parse-fn (grab schema-arg-type type-unmarshal-map)
-                msg-arg-name (fetch-in msg-tree [:attrs :tag])
-                _ (assert (= msg-arg-name schema-arg-name))
-                msg-arg-value-raw (only (grab :content msg-tree))
-                msg-arg-value (schema-arg-parse-fn msg-arg-value-raw)]
-            msg-arg-value))
-        args (mapv fn-unmarshall-arg schema-arg-trees msg-arg-trees )
-        ]
+  (let [args (map-with [schema-tree schema-arg-trees
+                        msg-tree msg-arg-trees]
+               (let [schema-arg-name (fetch-in schema-tree [:attrs :name])
+                     schema-arg-type (fetch-in schema-tree [:attrs :type])
+                     schema-arg-parse-fn (grab schema-arg-type type-unmarshal-map)
+                     msg-arg-name (fetch-in msg-tree [:attrs :tag])
+                     _ (assert (= msg-arg-name schema-arg-name))
+                     msg-arg-value-raw (only (grab :content msg-tree))
+                     msg-arg-value (schema-arg-parse-fn msg-arg-value-raw)]
+                 msg-arg-value))]
     args))

 (s/defn rpc-unmarshall :- s/Any
@@ -325,7 +323,6 @@
                 (only it))
      msg-fn-name (fetch-in msg-call [:attrs :tag])
      _ (assert (= schema-fn-name msg-fn-name))
-
      schema-input-hid (tf/find-hid schema-hid [:rpc :input])
      schema-input-hids (grab :kids (tf/hid->node schema-input-hid))
      schema-arg-trees (mapv tf/hid->tree schema-input-hids)


answer q8

answer q8

--- src/puzzule/q8.clj
+++ src/puzzule/q8.clj
@@ -0,0 +1,14 @@
+(ns puzzule.q8)
+
+(defn walk [move-num current route]
+  (if (some #(= % current) route)
+      0
+      (if (= move-num 0)
+          1
+          (+ (walk (dec move-num) [(inc (first current)) (second current)] (conj route current))
+             (walk (dec move-num) [(dec (first current)) (second current)] (conj route current))
+             (walk (dec move-num) [(first current) (inc (second current))] (conj route current))
+             (walk (dec move-num) [(first current) (dec (second current))] (conj route current))))))
+
+
+(walk 12 [0 0] [])


Removing unnecessary file.

Removing unnecessary file.

--- umm-spec-lib/src/umm_spec_lib/core.clj
+++ umm-spec-lib/src/umm_spec_lib/core.clj
@@ -1,6 +0,0 @@
-(ns umm-spec-lib.core)
-
-(defn foo
-  "I don't do a whole lot."
-  [x]
-  (println x "Hello, World!"))


Fix dev namespace

Fix dev namespace

I accidentally merged this when resolving a conflict.

--- app/dev/dev.clj
+++ app/dev/dev.clj
@@ -12,7 +12,7 @@
    [edge.system :as system]
    [figwheel-sidecar.repl-api]
    [io.aviso.ansi]
-   [reloaded.repl :refer [system init start stop go reset reset-all]]
+   [reloaded.repl :refer [system init start stop reset reset-all]]
    [yada.test :refer [response-for]]))

 (when (System/getProperty "edge.load_krei")


Incremental aggregates seem to work, but interact poorly with persistent tables

--- src/aurora/language.cljs
+++ src/aurora/language.cljs
@@ -156,15 +156,24 @@
          (dotimes [i (alength sinks)]
            (.run (aget sinks i) kn rule->dirty? kind->name->rules facts&vals)))))

-(deftype AggregateFlow [index group-len limit-ix ascending? agg-ixes agg-funs sinks]
+(deftype AggregateFlow [index delta-index group-len limit-ix ascending? agg-ixes agg-funs sinks]
   Object
   (run [this kn rule->dirty? kind->name->rules]
+       ;; TODO this is kind of hacky - we shouldn't be directly messing with input state or storing things in anon fields
+
+       ;; update input
+       (.foreach delta-index
+                 (fn [k v]
+                   (.update index k v)))
+       (.reset delta-index)
+
+       ;; figure out new output
        (let [current-key nil
              current-limit nil
              current-index 1
              inputs #js []
              aggs (make-array (alength agg-ixes))
-             facts&vals #js []
+             new-output (btree/tree 10 (+ group-len 1 (alength aggs)))
              push-input (fn [key]
                           (when (nil? current-key)
                             (set!! current-key key)
@@ -176,8 +185,7 @@
                               (let [output (aget inputs i)]
                                 (dotimes [j (alength aggs)]
                                   (apush output (aget aggs j)))
-                                (apush facts&vals output)
-                                (apush facts&vals 1)))
+                                (.update new-output output 1)))
                             (aclear inputs)
                             (set!! current-key key)
                             (set!! current-limit (aget key limit-ix))
@@ -191,8 +199,24 @@
            (.foreach index push-input)
            (.foreach-reverse index push-input))
          (push-input (btree/greatest-key group-len))
-         (dotimes [i (alength sinks)]
-           (.run (aget sinks i) kn rule->dirty? kind->name->rules facts&vals)))))
+
+         ;; diff against old output
+         (let [old-output (or (.-facts&vals index) (btree/tree 10 (+ group-len 1 (alength aggs))))
+               delta-output (btree/tree 10 (+ group-len 1 (alength aggs)))]
+           (.foreach old-output
+                     (fn [k v]
+                       (.update delta-output k (- v))))
+           (.foreach new-output
+                     (fn [k v]
+                       (.update delta-output k v)))
+
+           ;; save new output
+           (set! (.-facts&vals index) new-output)
+
+           ;; send deltas to sinks
+           (let [facts&vals (.elems delta-output)]
+             (dotimes [i (alength sinks)]
+               (.run (aget sinks i) kn rule->dirty? kind->name->rules facts&vals)))))))

 (deftype Flows [rules rule->flow rule->dirty? kind->name->rules name->lifetime]
   Object
@@ -338,6 +362,7 @@
                               (for [i (range (alength out-vars))]
                                 [(aget out-vars i) i]))
                 index (.get-or-create-index kn "know" agg-index-id in-vars)
+                delta-index (.get-or-create-index kn "know" (str "delta-" agg-index-id) in-vars)
                 group-len (count (conj (set group-by-vars) limit))
                 limit-ix (var->ix limit)
                 ascending? (= ascending|descending "ascending")
@@ -350,8 +375,8 @@
                 sinks (into-array
                        (for [[_ clause-type clause-id name] clauses
                              :when (not= clause-type "when")]
-                         (sink-of rule-id clause-type clause-id name var->ix)))]
-            (swap! rule->flow assoc agg-rule-id (AggregateFlow. index group-len limit-ix ascending? agg-ixes agg-funs sinks))
+                         (sink-of rule-id clause-type clause-id (str "delta-" name) var->ix)))]
+            (swap! rule->flow assoc agg-rule-id (AggregateFlow. index delta-index group-len limit-ix ascending? agg-ixes agg-funs sinks))
             (swap! kind->name->rules update-in ["know" (str "delta-" agg-index-id)] conj agg-rule-id)))))

     (doseq [[rule-id clauses] @rule-id->clauses]


Actually commit the fix for Let

Actually commit the fix for Let

--- src/aurora/language.cljs
+++ src/aurora/language.cljs
@@ -457,7 +457,7 @@
     Let (when (every? (set vars) (:vars pattern))
           (let [let-fun (expr->fun vars (:expr pattern))
                 filter-map-fun (fn [fact]
-                                 (let [new-value (.apply let-fun (.-values fact))
+                                 (let [new-value (.apply let-fun nil (.-values fact))
                                        new-values (aclone (.-values fact))]
                                    (apush new-values new-value)
                                    (Fact. nil new-values)))
@@ -466,7 +466,7 @@
     When (when (every? (set vars) (:vars pattern))
            (let [when-fun (expr->fun vars (:expr pattern))
                  filter-map-fun (fn [fact]
-                                  (when (.apply when-fun (.-values fact))
+                                  (when (.apply when-fun nil (.-values fact))
                                     fact))
                  [plan node] (add-flow plan (->FilterMap nodes filter-map-fun))]
              [plan [node] vars]))))


Handle multiple returns from aggregates

Handle multiple returns from aggregates

--- src/aurora/language.cljs
+++ src/aurora/language.cljs
@@ -130,18 +130,22 @@
                      (when (nil? current-key)
                        (set!! current-key key))
                      (when (btree/prefix-not= key current-key prefix-len)
-                       (let [output-key (aclone current-key)]
-                         (aset output-key prefix-len (aggregate-function inputs))
-                         (apush output-facts&vals output-key)
-                         (apush output-facts&vals 1)
+                       (let [outputs (aggregate-function inputs)]
+                         (dotimes [i (alength outputs)]
+                           (let [output-key (.slice current-key 0 prefix-len)]
+                             (aset output-key prefix-len (aget outputs i))
+                             (apush output-facts&vals output-key)
+                             (apush output-facts&vals 1)))
                          (set!! current-key key)
                          (aclear inputs)))
                      (apush inputs (.slice key prefix-len))))
          (when (> (alength inputs) 0)
-           (let [output-key (aclone current-key)]
-             (aset output-key prefix-len (aggregate-function inputs))
-             (apush output-facts&vals output-key)
-             (apush output-facts&vals 1)
+           (let [outputs (aggregate-function inputs)]
+             (dotimes [i (alength outputs)]
+               (let [output-key (.slice current-key 0 prefix-len)]
+                 (aset output-key prefix-len (aget outputs i))
+                 (apush output-facts&vals output-key)
+                 (apush output-facts&vals 1)))
              (set!! current-key key)
              (aclear inputs)))
          (when (true? (.update-facts kn output-kind output-name output-fields output-facts&vals))
@@ -384,7 +388,7 @@
                 ;; create aggregate flow if needed
                 (when-not (nil? aggregate-key)
                   (let [input-index (.get-or-create-index kn "know" output-name filtered-fields)
-                        aggregate-function (js/eval aggregate-fun)
+                        aggregate-function (aget js/aurora.aggregates aggregate-fun)
                         prefix-len (- (count final-fields) 1)]
                     (swap! name->transient? assoc output-name true)
                     (swap! kind->name->rules update-in ["know" output-name] #(conj (or % #{}) output-name))
@@ -473,6 +477,7 @@
                                                                                #js ["some-interval" "variable" "hi" "yy"]
                                                                                #js ["some-interval" "variable" "in" "zz"]
                                                                                #js ["rem-bar" "variable" "z" "zz"]])
+

 (.add-facts kn "know" "clauses" #js ["rule-id" "when|know|remember|forget" "clause-id" "name"] #js [#js ["count-overlap" "when" "get-more-foos" "foo"]
                                                                                #js ["count-overlap" "when" "some-more-interval" "interval"]
@@ -489,7 +494,7 @@

 (.add-facts kn "know" "clause-aggregate-vars" #js ["aggregate-id" "ix" "var"] #js [#js ["count-zz" 0 "zz"]])

-(.add-facts kn "know" "clause-aggregate-funs" #js ["aggregate-id" "js"] #js [#js ["count-zz" "cljs.core.count"]])
+(.add-facts kn "know" "clause-aggregate-funs" #js ["aggregate-id" "js"] #js [#js ["count-zz" "count"]])

 (def flows (compile kn))


Fix frequencies to load as components to trips

--- env/dev/clj/gtfve/datomic.clj
+++ env/dev/clj/gtfve/datomic.clj
@@ -237,21 +237,22 @@
 ;;;;;;;;;;;;;;;;;

 (def frequencies-header-keys
-  {"trip_id" :delete/trip/id
+  {"trip_id" :trip/id
    "start_time" :trip.frequency/start-time
    "end_time" :trip.frequency/end-time
    "headway_secs" :trip.frequency/headway-seconds
    "exact_times" :trip.frequency/exact-times?})

 (def frequencies-val-transforms
-  {:delete/trip/id (fn [x] nil)
-   :trip.frequency/headway-seconds read-string
+  {:trip.frequency/headway-seconds read-string
    :trip.frequency/exact-times? (comp not zero? read-string)})

 (defn load-frequencies! [path conn]
-  (d/transact conn (csv->map frequencies-header-keys
-                           frequencies-val-transforms
-                           path)))
+  (->> (csv->maps frequencies-header-keys
+                  frequencies-val-transforms
+                  path)
+       (map #(assoc % :db/id [:trip/id (:trip/id %)]))
+       (map #(dissoc % :trip/id))))

 ;; Main ;;
 ;;;;;;;;;;


Simplify CSS with :auto-prefix.

Simplify CSS with :auto-prefix.

--- src-cljs/pepa/style.cljs
+++ src-cljs/pepa/style.cljs
@@ -143,10 +143,9 @@
                :border-bottom (str "1px solid " border-dark)}
      [:input (list
               {:position :absolute
-               :top "50%"
-               :left "50%"
+               :top "50%", :left "50%"
+               :transform "translate(-50%,-50%)"
                :border (str "1px solid " border-dark)}
-              ^:prefix {:transform "translate(-50%,-50%)"}
               (calc-property :width ["100%" - (* 2 search-padding)]))]]))

 (def sidebar-css
@@ -173,15 +172,15 @@
              line-height (/ item-height 1.5)
              icon-size 20
              padding-left 20]
-         [:li (list {:list-style-type :none
-                     :height (px line-height)
-                     :line-height (px line-height)
-                     :padding {:top (px padding)
-                               :bottom (px padding)}
-                     :background {:repeat :no-repeat
-                                  :size (px icon-size)
-                                  :position [[(px padding-left) :center]]}}
-                    ^:prefix {:user-select :none})
+         [:li {:list-style-type :none
+               :height (px line-height)
+               :line-height (px line-height)
+               :padding {:top (px padding)
+                         :bottom (px padding)}
+               :background {:repeat :no-repeat
+                            :size (px icon-size)
+                            :position [[(px padding-left) :center]]}
+               :user-select :none}
           (for [row (map (comp name second) navigation-elements)]
             (let [selector (keyword (str "&." row))]
               [selector
@@ -218,12 +217,10 @@
                         :font-size (px color-size)
                         :line-height (px color-size)
                         :height (px color-size)}
-               [:.tag-name (list {:position :absolute
-                                  :top "50%"
-                                  :overflow :hidden
-                                  :text-overflow :ellipsis}
-                                 (calc-property :width ["100%" - (* 2 color-size)])
-                                 ^:prefix {:transform "translateY(-50%)"})]
+               [:.tag-name {:position :absolute
+                            :top "50%" :transform "translateY(-50%)"
+                            :overflow :hidden
+                            :text-overflow :ellipsis}]
                [:.color {:width (px color-size)
                          :height (px color-size)
                          :float :right}]])]]
@@ -252,15 +249,14 @@
                 :background-color "rgba(255, 255, 255, 0.8)"
                 :margin (px 5)
                 :border-radius (px 4)}
-      [:.left :.right (list
-                       {:float :right
-                        :width (px rotate-height)
-                        :height (px rotate-height)
-                        :line-height (px rotate-height)
-                        :text-align :center
-                        :cursor :pointer
-                        :opacity 0.3}
-                       ^:prefix {:user-select :none})
+      [:.left :.right {:float :right
+                       :width (px rotate-height)
+                       :height (px rotate-height)
+                       :line-height (px rotate-height)
+                       :text-align :center
+                       :cursor :pointer
+                       :opacity 0.3
+                       :user-select :none}
        ;; Give buttons full opacity when hovered
        [:&:hover {:opacity 1}]
        [:&.right {:background-image (image-url "material/page-rotate-right.svg")}]
@@ -316,18 +312,16 @@
                   :text-overflow :ellipsis
                   }]
           [:&input {:width (px header-width)}]]
-         [:button (list
-                   {:position :absolute
-                    :right (px header-padding)
-                    :top (px (/ header-height 2))}
-                   ^:prefix {:transform "translateY(-50%)"})]
+         [:button {:position :absolute
+                   :right (px header-padding)
+                   :top (px (/ header-height 2))
+                   :transform "translateY(-50%)"}]
          [:.tags {:max-height (px (- tags-height 8))
                   :padding-botton (px 8)}]])
       [:ul.pages {:margin 0, :padding 0}
-       [:li.page (list
-                  {:width "100%"
-                   :list-style-type :none}
-                  ^:prefix {:user-select :none})
+       [:li.page {:width "100%"
+                  :list-style-type :none
+                  :user-select :none}

         page-css

@@ -374,22 +368,20 @@
                  :background-color header-color
                  :bottom 0
                  :display :initial}
-        [:button (list
-                  {:position :relative
-                   :left "50%", :top "50%"}
-                  ^:prefix {:transform "translate(-50%,-50%)"})]]]])
+        [:button {:position :relative
+                  :left "50%", :top "50%"
+                  :transform "translate(-50%,-50%)"}]]]])
    ;; The drop-area to create new documents
    [:td.create-document {:min-width (px document-width)
                          :position :relative
                          :display :block}
     [:&.active {:background-color "lightgray"}]
-    [:.note (list
-             {:width "100%"
-              :height "100"
-              :position :absolute
-              :top "50%", :left "50%"
-              :text-align :center}
-             ^:prefix {:transform "translate(-50%, -50%)"})
+    [:.note {:width "100%"
+             :height "100"
+             :position :absolute
+             :top "50%", :left "50%"
+             :transform "translate(-50%, -50%)"
+             :text-align :center}
      [:.arrow {:background {:image (image-url "drop-arrow.svg")
                             :repeat :no-repeat
                             :position :center
@@ -477,10 +469,9 @@
              :white-space :nowrap
              :text-overflow :ellipsis}
     [:form
-     [:button (list
-               {:float :right
-                :margin-top (px (/ header-height 2))}
-               ^:prefix {:transform "translateY(-50%)"})]]]
+     [:button {:float :right
+               :margin-top (px (/ header-height 2))
+               :transform "translateY(-50%)"}]]]
    [:.pane {:float :left
             :height "100%"
             :overflow :auto}
@@ -578,6 +569,7 @@
      [:&.editable (list
                    {:padding-left (px tag-icon-box)
                     :border (str "1px solid " border-dark)
+                    :border-radius (px 3)
                     :height :auto
                     :background {:image (image-url "tag-icon.svg")
                                  :repeat :no-repeat
@@ -585,8 +577,7 @@
                                  :position [[(px 4) (px 4)]]
                                  :color :white}
                     :white-space :initial}
-                   (calc-property :width ["100%" -  (px tag-icon-box)])
-                   ^:prefix {:border-radius (px 3)})
+                   (calc-property :width ["100%" -  (px tag-icon-box)]))
       [:&:before {:content (pr-str "Tags:")
                   :font-size (em 1.2)}]]
      (let [tag-height 16]
@@ -610,15 +601,14 @@
         (ui/css-fade "tag" (u/ms 100))

         (let [color-size 8]
-          [:.color (list
-                    {:display :inline-block
-                     :height (px color-size)
-                     :width (px color-size)
-                     :margin-right (px 2)
-                     ;; Border looks horrible on non-high-DPI screens
-                     ;; :border "1px solid white"
-                     }
-                    ^:prefix {:border-radius "50%"})])])
+          [:.color {:display :inline-block
+                    :height (px color-size)
+                    :width (px color-size)
+                    :margin-right (px 2)
+                    ;; Border looks horrible on non-high-DPI screens
+                    ;; :border "1px solid white"
+                    :border-radius "50%"
+                    }])])
      (let [input-padding 5]
        [:li {:display :inline-block}
         [:input {:background-color :transparent
@@ -632,20 +622,19 @@
 (def button-css
   (let [padding (px 10)]
     [:button :a.button
-     (list
-      {:background "linear-gradient(to bottom, #ffffff 0%,#e4e4e4 100%)"
-       :border (str "1px solid " border-buttons)
-       :color blue-text
-       :text-shadow "1px 1px #ffffff"
-       :height (px 25)
-       :font {:family default-font
-              :size (px 14)
-              :weight 400}
-       :outline :none
-       :padding {:left padding
-                 :right padding}}
-      ^:prefix {:border-radius (px 3)
-                :box-shadow "0px 0px 3px #dddddd"})
+     {:background "linear-gradient(to bottom, #ffffff 0%,#e4e4e4 100%)"
+      :border (str "1px solid " border-buttons)
+      :color blue-text
+      :text-shadow "1px 1px #ffffff"
+      :height (px 25)
+      :font {:family default-font
+             :size (px 14)
+             :weight 400}
+      :outline :none
+      :padding {:left padding
+                :right padding}
+      :border-radius (px 3)
+      :box-shadow "0px 0px 3px #dddddd"}
      [:&:hover {:background "linear-gradient(to bottom, #f5f5f5 0%,#d0d0d0 100%)"}]
      [:&:active {:box-shadow "inset 0 0 3px #000000;"}]
      [:&:disabled :&.disabled {:background "linear-gradient(to bottom, #f5f5f5 0%,#d0d0d0 100%)"
@@ -654,20 +643,20 @@
 (def dropdown-css
   (let [font-size (px 14)
         height 25]
-    [:label.dropdown (list {:background "linear-gradient(to bottom, #ffffff 0%,#e4e4e4 100%)"
-                            :font-size font-size
-                            :position :relative
-                            :height (px height)
-                            :text-shadow "1px 1px #ffffff"
-                            :line-height (px height)
-                            :display :inline-flex
-                            :padding  {:left (px 10)
-                                       :right (px 0)
-                                       :top (px 0)
-                                       :bottom (px 0)}
-                            :border (str "1px solid " border-buttons)
-                            :border-radius (px 4)}
-                           ^:prefix {:box-shadow "0px 0px 3px #dddddd"})
+    [:label.dropdown {:background "linear-gradient(to bottom, #ffffff 0%,#e4e4e4 100%)"
+                      :font-size font-size
+                      :position :relative
+                      :height (px height)
+                      :text-shadow "1px 1px #ffffff"
+                      :line-height (px height)
+                      :display :inline-flex
+                      :padding  {:left (px 10)
+                                 :right (px 0)
+                                 :top (px 0)
+                                 :bottom (px 0)}
+                      :border (str "1px solid " border-buttons)
+                      :border-radius (px 4)
+                      :box-shadow "0px 0px 3px #dddddd"}
      [:span {:padding {:left (px 20)
                        :right (px 20)}
              :font-weight 300}]
@@ -687,11 +676,11 @@
                      :outline :none
                      :font-family default-font
                      :padding {:left (px 30)
-                               :right (px 10)}}
-                    ^:prefix {:appearance :none})
+                               :right (px 10)}
+                     :appearance :none})
       [:&:active {:background-gradient :white}]
-      [:&:disabled (list {:color text-color-disabled}
-                         ^:prefix {:filter "grayscale(100%)"})]
+      [:&:disabled {:color text-color-disabled
+                    :filter "grayscale(100%)"}]
       [:&:hover {:background [(str (image-url "dropdown-arrow.svg") " 10px center no-repeat")
                               "linear-gradient(to bottom, #f5f5f5 0%,#d0d0d0 100%)"] }]]]))

@@ -723,8 +712,7 @@
                :background-color darker-background
                :cursor :pointer}]
      [:ul.files (list
-                 {:padding {:left (px padding)
-                            :right (px padding)}
+                 {:padding {:left (px padding), :right (px padding)}
                   :margin {:top (px header-height)}
                   :overflow-y :auto
                   :list-style-type :none}
@@ -741,7 +729,7 @@
                         :background {:image (image-url (str "material/warning-invalid-file.svg?" (gensym)))
                                      :position :center
                                      :repeat :no-repeat}}]
-            [:.title {:color "red"
+            [:.title {:color :red
                       :padding-left (px 4)}]])
          [:.title {:max-width "70%", :height "100%"
                    :display :inline-block
@@ -752,20 +740,19 @@
          [:a.title {:text-decoration :underline}]
          [:.size {:font-size (pt 8)
                   :padding (px 4)}]
-         [:.progress :.hide (list
-                             {:position :absolute
-                              :display :block
-                              :right 0, :top "50%"}
-                             ^:prefix {:transform "translateY(-50%)"})]
+         [:.progress :.hide {:position :absolute
+                             :display :block
+                             :right 0, :top "50%"
+                             :transform "translateY(-50%)"}]
          (let [progress-height 4]
            [:.progress {:width (px 150)
                         :height (px progress-height)}
             [:.bar {:height "100%"
                     :float :right
                     :background-color "darkgrey"}]])
-         [:.hide (list {:text-decoration :underline
-                        :cursor :pointer}
-                       ^:prefix {:user-select :none})
+         [:.hide {:text-decoration :underline
+                  :cursor :pointer
+                  :user-select :none}
           [:&:hover {:color grey-1}]]])]
      [:form.upload {:width "100%", :height (px upload-button-height)
                     :padding {:left (px padding)
@@ -775,10 +762,19 @@
   [:a {:text-decoration :none
        :color default-text}])

+(def auto-prefix #{:transition
+                   :user-select
+                   :border-radius
+                   :transform
+                   :filter
+                   :appearance
+                   :box-shadow})
+
 (def css-string
   (css
    {:vendors ["webkit" "moz" "ms"]
-    :output-to "resources/public/style.css"}
+    :output-to "resources/public/style.css"
+    :auto-prefix auto-prefix}
    [:html :body :#app {:height "100%"
                        :font-weight "300"
                        :font-family default-font}]


add :args/:ret/:fn accessors for fspecs

add :args/:ret/:fn accessors for fspecs

--- src/clj/clojure/spec.clj
+++ src/clj/clojure/spec.clj
@@ -1415,6 +1415,16 @@
     (reify
      clojure.lang.IFn
      (invoke [this x] (valid? this x))
+
+     clojure.lang.ILookup
+     (valAt [this k] (.valAt this k nil))
+     (valAt [_ k not-found]
+            (case k
+                  :args argspec
+                  :ret retspec
+                  :fn fnspec
+                  not-found))
+
      Spec
      (conform* [_ f] (if (fn? f)
                        (if (identical? f (validate-fn f specs *fspec-iterations*)) f ::invalid)


Added matrix transpose method to trends.

--- src/clj/forma/trends.clj
+++ src/clj/forma/trends.clj
@@ -12,4 +12,25 @@
 them by building a time series vector of vectors. Entering chunks
 should be sorted in descending order."}
   timeseries [chunks]
-  [(apply conj [] chunks)])+  [(apply conj [] chunks)])
+
+(defn transpose
+  "Matrix transpose. Transforms
+
+ [[1 2 3]
+  [4 5 6]
+  [7 8 9]]
+
+into:
+
+ [[1 4 7]
+  [2 5 8]
+  [3 6 9]]
+
+The code works because map applies the given function to the first
+  arguments of all the supplied collections, then the second, etc, all
+  down the line. The apply allows us to apply this to any number of
+  collections. So, we make a vector out of all of the firsts, then the
+  seconds, etc."
+  [a]
+  (vec (apply map vector a)))


fix that port

fix that port

--- src/cljs/ceres/core.cljs
+++ src/cljs/ceres/core.cljs
@@ -76,8 +76,7 @@
                                (if ssl?  "wss://" "ws://")
                                (.getDomain uri)
                                ":"
-                               8082
-                               #_(.getPort uri)
+                               (.getPort uri)
                                "/tweets/ws")))]
             (om/set-state! owner :ws-in (:in connection))
             (om/set-state! owner :ws-out (:out connection))


Fix time formatting for clicking on log

Fix time formatting for clicking on log

--- src/cljs/klang/core.cljs
+++ src/cljs/klang/core.cljs
@@ -51,6 +51,8 @@
  library in single user mode. Ie only one logging system. Will be true for 99%
  of all users."}
   *db* (atom {}))
+
+(declare time-formatter)

 ;; Config for display/tabs of the log viewer
 (defn new-db
@@ -75,8 +77,7 @@
    :showing-tab :all
    ;; Date time formatter
    ;; memfn not working?
-   :time-formatter (fn[time] (.format
-                              (goog.i18n.DateTimeFormat. "HH:mm:ss.SSS") time))
+   :time-formatter time-formatter
    ;; User defined tabs state
    :tabs (sorted-map
           ;; The main tab holding all logs
@@ -188,6 +189,10 @@
                           (g) (repeatedly 3 f) "-"
                           (repeatedly 12 f)))))

+(defn time-formatter
+  [time]
+  (.format (goog.i18n.DateTimeFormat. "HH:mm:ss.SSS") time))
+
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; Declares
 (declare action!)
@@ -254,9 +259,9 @@
                     (:ns lg-ev)
                     (if (empty? (:ns lg-ev)) "" "/")
                     (name (:type lg-ev))
-                    ((.format
-                      (goog.i18n.DateTimeFormat. "HH:mm:ss.SSS"))
-                     (:time lg-ev)))
+                    ;; We can't dered DB here to get the formatter
+                    ;; or reagent will re-render everything always
+                    (time-formatter (:time lg-ev)))
                    ;; console.dir firefox & chrome only?
                    ;;(mapv #(js/console.dir %) (:msg lg-ev))
                    ;; %o calls either .dir() or .dirxml() if it's a DOM node


Fix metadata for generated sketch initialization function.

--- src/cljs/quil/sketch.clj
+++ src/cljs/quil/sketch.clj
@@ -5,7 +5,7 @@
      ~@body))

-(def ^{:private true}
+(def ^{:private true}
 	supported-features
 	#{:no-start})

@@ -19,9 +19,9 @@
                    (reduce #(assoc %1 %2 (contains? user-features %2)) {}
                            supported-features))]
     `(do
-       (defn ^:export ~app-name []
-         (quil.sketch/sketch
+       (defn ~(vary-meta app-name assoc :export true) []
+         (quil.sketch/sketch
           ~app-name ~@(apply concat (seq (merge (dissoc opts :features) features)))))
-
+
        ~(when (not (:no-start features))
           `(quil.sketch/add-sketch-to-init-list {:fn ~app-name :name (str '~app-name)})))))