Use run instead of deref

Use run instead of deref

--- src/reagent/ratom.cljs
+++ src/reagent/ratom.cljs
@@ -212,15 +212,13 @@
     (set! ra.norun? true)
     (doseq [w ra.watching]
       (when (and (reaction? w)
-                 (not (identical? (.-dirty? w) clean)))
-        (-deref w)))
+                 (not (== (.-dirty? w) clean)))
+        (ra-check-clean w)
+        (when-not (== (.-dirty? w) clean)
+          (run w))))
     (set! ra.norun? false)
     (when (== ra.dirty? maybe-dirty)
       (set! ra.dirty? clean))))
-
-(defn- ra-run-check [ra]
-  (binding [*ratom-context* (js-obj)]
-    (ra-check-clean ra)))

 (defn- ra-handle-change [ra sender oldval newval]
   (when ra.active?
@@ -232,9 +230,7 @@
                              is-dirty)))
       (if (and ra.auto-run (not ra.norun?))
         (do
-          ;; FIXME: is this correct?
-          (when (== ra.dirty? maybe-dirty)
-            (ra-run-check ra))
+          (ra-check-clean ra)
           (when-not (== ra.dirty? clean)
             ((or ra.auto-run run) ra)))
         (when (== old-dirty clean)


day 1

day 1

--- src/adventofcode/core.clj
+++ src/adventofcode/core.clj
@@ -8,3 +8,15 @@
                   (re-seq #"\)")
                   count)]
     (- up down)))
+
+(defn day1-position [s]
+  (loop [str s
+         up 0
+         down 0
+         pos 0]
+    (let [[c & rest] str]
+      (if (= -1 (- up down))
+        pos
+        (if (= \( c)
+          (recur rest (inc up) down (inc pos))
+          (recur rest up (inc down) (inc pos)))))))


Use right state machine.

Use right state machine.

--- src/rewindable/ago.clj
+++ src/rewindable/ago.clj
@@ -21,7 +21,7 @@
     `(let [c# (cljs.core.async/chan 1)]
        (cljs.core.async.impl.dispatch/run
         (fn []
-          (let [f# ~x
+          (let [f# ~sm
                 state# (-> (f#)
                            (ioc/aset-all! cljs.core.async.impl.ioc-helpers/USER-START-IDX c#))]
             (cljs.core.async.impl.ioc-helpers/run-state-machine-wrapped state#))))


Remove cruft files

Remove cruft files

--- src/tenor/entities.clj
+++ src/tenor/entities.clj
@@ -1,21 +0,0 @@
-(ns tenor.entities
-  (:use [tenor.constructs]))
-
-(defprotocol Entity
-  (repr [this])
-  (generated [this]))
-
-(defrecord Note [pitch-letter octave]
-  Entity
-  (repr [this] (make-note (str pitch-letter octave))))
-
-(defrecord Beat [note-count note-value]
-  Entity
-  (generated [this] (segment-beat note-count note-value)))
-
-(defrecord Measure [note-count note-value]
-  Entity
-  (generated [this] (map-measure
-                      (segment-measure (time-signature note-count))
-                      (generate-random-scale))))
-


run-finding function complete!

run-finding function complete!

--- statspop/src/statspop/detection.cljs
+++ statspop/src/statspop/detection.cljs
@@ -34,6 +34,7 @@
   (mapv :index matches)))

 (defn find-runs
+  "given a vector of numeric indices and int minsize, returns non-overlapping vectors of runs of sequential numbers where those runs are at least minsize"
   [indices minsize]
   (loop [all-regions []
          active-region []
@@ -57,20 +58,40 @@
                   (recur (conj all-regions active-region) (conj [] cur-idx) (first remaining) (rest remaining))
                     (recur all-regions (conj [] cur-idx) (first remaining) (rest remaining))))))

-(def test-lines "123 abc
-  foo bar baa
-  1234 a
-  1245 ab
-  1 ab
-  12345
-  ab
-  12345
-  12
-  1 2
-  1 a 1 2")
+(defn get-lines-matching-indexes
+  "given vector of lines and vector of indices, return subvector of lines at indices"
+  [lines indices]
+  (mapv (partial get lines) indices))

-(def l (lines test-lines))
+(defn get-lines-from-nested-indices
+  [lines nested-indices]
+  (mapv (partial get-lines-matching-indexes lines) nested-indices))

-(def il (make-index-maps l))
+(defn gather-runs
+  "FINALLY!  this is the entry point to all that mess.

-(def im (get-indexes-of-matches il 0.5))
+  takes multiline text string. splits it into lines. and then searches for lines with at least minproportion of digits in at least minruns runs.
+  produces vector of runs (where each run is a vector of lines)
+
+  text = string
+  minproportion = float between 0 and 1
+  minruns = integer > 0
+  returns: vector of vectors, where each vector is a run of consecutive strings with at least minproportion of digits."
+  [text minproportion minruns]
+  (let [lns (lines text)
+        index-maps (make-index-maps lns)
+        indices (get-indexes-of-matches index-maps minproportion)
+        runs (find-runs indices minruns)]
+    (get-lines-from-nested-indices lns runs)))
+
+;; (def test-lines "123 abc
+;;   foo bar baa
+;;   1234 a
+;;   1245 ab
+;;   1 ab
+;;   12345
+;;   ab
+;;   12345
+;;   12
+;;   1 2
+;;   1 a 1 2")


make normal sente work with issues

make normal sente work with issues

--- src-cljs/frontend/core.cljs
+++ src-cljs/frontend/core.cljs
@@ -145,7 +145,6 @@
                      :ab-choices ab-choices
                      :tal tal
                      :use-talaria? use-talaria?
-                     :sente (when use-talaria? tal)
                      :comms {:controls      controls-ch
                              :api           api-ch
                              :errors        errors-ch
@@ -154,6 +153,8 @@
                              :api-mult      (async/mult api-ch)
                              :errors-mult   (async/mult errors-ch)
                              :nav-mult      (async/mult navigation-ch)})
+            (merge (when use-talaria?
+                     {:sente tal}))
             (browser-settings/restore-browser-settings cust)))))

 (defn controls-handler
@@ -217,8 +218,9 @@
              ;; Can't log in without a page refresh, have to re-evaluate this if
              ;; that ever changes.
              :cust                  (:cust @state)
-             :sente                 (:tal @state); (:sente @state)
-             :tal                   (:tal @state)
+             :sente                 (if (:use-talaria? @state)
+                                      (:tal @state)
+                                      (:sente @state))
              :admin?                (:admin? @state)
              :ab-choices            (:ab-choices @state)
              }


Fix broadcast of new users

Fix broadcast of new users

--- src/braid/server/events.clj
+++ src/braid/server/events.clj
@@ -11,7 +11,7 @@
   (db/run-txns! (group/user-join-group-txn user-id group-id))
   (sync-helpers/broadcast-group-change
     group-id
-    [:braid.client/new-user (user/user-by-id user-id)]))
+    [:braid.client/new-user [(user/user-by-id user-id) group-id]]))

 (defn register-user!
   [email group-id]


fix config parsing for exportable key list

--- src/bract/core/config.clj
+++ src/bract/core/config.clj
@@ -25,7 +25,8 @@
   ;; config keys
   cfg-inducer-names ["bract.core.inducers"    vector?      "Vector of fully qualified inducer fn names"
                      {:parser kputil/any->edn}]
-  cfg-exports       ["bract.core.exports"     vector?      "Vector of config keys to export as system properties"]
+  cfg-exports       ["bract.core.exports"     vector?      "Vector of config keys to export as system properties"
+                     {:parser kputil/any->edn}]
   cfg-launcher      ["bract.core.launcher"    fn?          "Fully qualified launcher fn name"
                      {:parser kputil/str->var->deref}])


holy crap fixed stupid delete bug

holy crap fixed stupid delete bug

--- server/src/gratefulplace/controllers/watches.clj
+++ server/src/gratefulplace/controllers/watches.clj
@@ -27,9 +27,9 @@
   :allowed-methods [:delete]
   :available-media-types ["application/json"]
   :authorized? (fn [_]
-                 (let [watch-id (:id params)
+                 (let [watch-id (str->int (:id params))
                        auth-id (:id auth)
-                       watch {:watch/user {:db/id auth-id}}]
+                       watch (db/ent watch-id)]
                    (if (and watch
                             (= (:db/id (:watch/user watch)) auth-id))
                          {:record {:id watch-id}})))


Support :environment-variables on the script level

--- src/cider_ci/ex/trial.clj
+++ src/cider_ci/ex/trial.clj
@@ -15,16 +15,17 @@
     [cider-ci.ex.scripts.processor]
     [cider-ci.ex.trial.helper :refer :all]
     [cider-ci.utils.daemon :as daemon]
-    [drtom.logbug.debug :as debug]
-    [drtom.logbug.thrown :as thrown]
     [cider-ci.utils.http :refer [build-server-url]]
-    [drtom.logbug.catcher :as catcher]
+    [cider-ci.utils.map :refer [deep-merge]]
     [clj-commons-exec :as commons-exec]
     [clj-logging-config.log4j :as logging-config]
     [clj-time.core :as time]
     [clojure.pprint :as pprint]
     [clojure.stacktrace :as stacktrace]
     [clojure.tools.logging :as logging]
+    [drtom.logbug.catcher :as catcher]
+    [drtom.logbug.debug :as debug]
+    [drtom.logbug.thrown :as thrown]
     [robert.hooke :as hooke]
     ))

@@ -39,16 +40,16 @@

 (defn- prepare-script [k script-params trial-params]
   (atom (conj {}
-              script-params
+              (deep-merge (select-keys trial-params
+                                       [:environment-variables
+                                        :job_id
+                                        :trial_id
+                                        :working_dir])
+                          script-params)
               (when-not (:name script-params)
                 {:name (name k)})
               {:state "pending"
-               :key (name k)}
-              (select-keys trial-params
-                           [:environment-variables
-                            :job_id
-                            :trial_id
-                            :working_dir]))))
+               :key (name k)})))

 (defn- prepare-and-insert-scripts [trial]
   (let [params-atom (get-params-atom trial)


export 3 months

export 3 months

--- src/clj/ceres/curator.clj
+++ src/clj/ceres/curator.clj
@@ -299,7 +299,7 @@

   (def g
     (let [vertices (loop [nodes []
-                          loc (:tree rand-tree)]
+                          loc (:tree some-tree)]
                      (if (zip/end? loc)
                        nodes
                        (recur
@@ -386,6 +386,24 @@
                         (reduce +))]
     (aprint (/ (float (/ delay-sum (count (remove #(= % 0) (:delays dpa-sum))))) 60)))

+
+  (let [tweets (mc/find-maps @db "tweets" {:created_at {$gt (t/date-time 2014 9 29)
+                                                        $lt (t/date-time 2014 9 30)}})]
+
+    (->> tweets
+         first
+         :user
+         keys
+         aprint))
+
+  (sh "mongoexport"
+        "--port" "27017"
+        "--host" (or (System/getenv "DB_PORT_27017_TCP_ADDR") "127.0.0.1")
+        "--db" "athena"
+        "--collection" "tweets"
+        "--query" (str "{"  "created_at : {$gte : new Date(" (c/to-long (t/date-time 2014 7 1)) "), $lt : new Date(" (c/to-long (t/date-time 2014 10 1)) ")}}")
+        "--out" "/home/konny/tmp/tweets.json")
+
   )

 ;; --- TODO ---


Eliminates incorrect merging of metadata when redefining vars

--- src/clj/cljs/analyzer.clj
+++ src/clj/cljs/analyzer.clj
@@ -330,12 +330,9 @@
           (warning env
             (str "WARNING: " (symbol (str ns-name) (str sym))
                  " no longer fn, references are stale"))))
-      (swap! namespaces update-in [ns-name :defs sym]
-             (fn [m]
-               (let [m (assoc (or m {}) :name name)]
-                 (merge m
-                   (when tag {:tag tag})
-                   (when sym-meta sym-meta)
+      (swap! namespaces assoc-in [ns-name :defs sym]
+                 (merge {:name name}
+                   sym-meta
                    (when dynamic {:dynamic true})
                    (when-let [line (:line env)]
                      {:file *cljs-file* :line line})
@@ -353,7 +350,7 @@
                       :protocol-inline (:protocol-inline init-expr)
                       :variadic (:variadic init-expr)
                       :max-fixed-arity (:max-fixed-arity init-expr)
-                      :method-params (map :params (:methods init-expr))})))))
+                      :method-params (map :params (:methods init-expr))})))
       (merge {:env env :op :def :form form
               :name name :doc doc :init init-expr}
              (when tag {:tag tag})


* src/clj/cljs/compiler.clj: preserve :tag on dot forms

--- src/clj/cljs/compiler.clj
+++ src/clj/cljs/compiler.clj
@@ -1210,13 +1210,15 @@
            ::access {:env env :op :dot :form form
                      :target targetexpr
                      :field field
-                     :children [targetexpr]}
+                     :children [targetexpr]
+                     :tag (-> form meta :tag)}
            ::call   (let [argexprs (map #(analyze enve %) args)]
                       {:env env :op :dot :form form
                        :target targetexpr
                        :method method
                        :args argexprs
-                       :children (into [targetexpr] argexprs)})))))
+                       :children (into [targetexpr] argexprs)
+                       :tag (-> form meta :tag)})))))

 (defmethod parse 'js*
   [op env [_ jsform & args :as form] _]


in parse-ns, don't include line information in the case of the destination file not existing. In compile-file we now reset the namespace for the file so that the user will get errors about names that have changed under incremental recompilation.

--- src/clj/cljs/compiler.clj
+++ src/clj/cljs/compiler.clj
@@ -874,14 +874,16 @@
                   (if (= (:op ast) :ns)
                     (let [ns-name (:name ast)
                           deps    (merge (:uses ast) (:requires ast))]
-                      {:ns (or ns-name 'cljs.user)
-                       :provides [ns-name]
-                       :requires (if (= ns-name 'cljs.core)
-                                   (set (vals deps))
-                                   (conj (set (vals deps)) 'cljs.core))
-                       :file dest
-                       :source-file src
-                       :lines (-> dest io/reader line-seq count)})
+                      (merge
+                        {:ns (or ns-name 'cljs.user)
+                         :provides [ns-name]
+                         :requires (if (= ns-name 'cljs.core)
+                                     (set (vals deps))
+                                     (conj (set (vals deps)) 'cljs.core))
+                         :file dest
+                         :source-file src}
+                        (when (.exists ^java.io.File dest)
+                          {:lines (-> (io/reader dest) line-seq count)})))
                     (recur (rest forms))))))))]
     (reset! ana/namespaces namespaces')
     ret))
@@ -909,14 +911,17 @@
           dest-file (io/file dest)]
       (if (.exists src-file)
         (try
-          (if (or (requires-compilation? src-file dest-file) (:source-map opts))
-            (do (mkdirs dest-file)
-              (compile-file* src-file dest-file opts))
-            (let [ns-info (parse-ns src-file dest-file opts)]
-              (when-not (contains? @ana/namespaces (:ns ns-info))
-                (with-core-cljs
-                  (ana/analyze-file src-file)))
-              ns-info))
+          (let [{ns :ns :as ns-info} (parse-ns src-file dest-file opts)]
+            (if (or (requires-compilation? src-file dest-file) (:source-map opts))
+              (do (mkdirs dest-file)
+                (when (contains? @ana/namespaces ns)
+                  (swap! ana/namespaces dissoc ns))
+                (compile-file* src-file dest-file opts))
+              (do
+                (when-not (contains? @ana/namespaces ns)
+                  (with-core-cljs
+                    (ana/analyze-file src-file)))
+                ns-info)))
           (catch Exception e
             (throw (ex-info (str "failed compiling file:" src) {:file src} e))))
         (throw (java.io.FileNotFoundException. (str "The file " src " does not exist.")))))))


fix NullPointerExceptions in clj config when compiling cljs

--- src/clj/tictag/config.clj
+++ src/clj/tictag/config.clj
@@ -12,9 +12,9 @@
                    :host     (env :pg-host "127.0.0.1")
                    :user     (env :pg-user)
                    :password (env :pg-password)}
-   :crypto-key    (codecs/hex->bytes (or (:tictag-crypto-key env) "deadbeef"))
-   :jwt           {:private-key (keys/str->private-key (env :ec-priv-key))
-                   :public-key  (keys/str->public-key (env :ec-pub-key))}
+   :crypto-key    (some-> env :tictag-crypto-key codecs/hex->bytes)
+   :jwt           {:private-key (some-> env :ec-priv-key keys/str->private-key)
+                   :public-key  (some-> env :ec-pub-key keys/str->public-key)}
    :slack         {:verification-token (env :slack-verification-token)}
    :tagtime       {:seed (or (some-> env :tagtime-seed Integer.) 666)
                    :gap  (or (some-> env :tagtime-gap Integer.) (* 60 45))}


need to make a pass through world and the rest of the framework

--- src/clojure/yaw/world.clj
+++ src/clojure/yaw/world.clj
@@ -114,13 +114,11 @@
 (defn create-item!
   "Create an item in the `world` with the
   specified id, position, mesh"
-  [world id & {:keys [x y z scale mesh]
-               :or   {x 0
-                      y 0
-                      z 2
+  [world id & {:keys [position scale mesh]
+               :or   {position [0 0 2]
                       scale    1
                       mesh     (create-mesh! world)}}]         ;;error here
-  (.createItemObject world id x y z scale mesh))
+  (.createItemObject world id (position 0) (position 1) (position 2) scale mesh))

 (defn remove-item!
   "Remove the specified `item` from the `world`"


Fix more docs.

Fix more docs.

--- src/clojurecraft/data.clj
+++ src/clojurecraft/data.clj
@@ -66,6 +66,9 @@
 ; player -> (ref Entity)
 ;   A ref to the Entity representing the bot's player in the world.
 ;
+;   This is exactly the same thing as (@(world entities) player-id), it's just here
+;   for convenience.
+;
 ; world -> World
 ;   The world the bot is connected to.
 ;
@@ -75,8 +78,8 @@
 ;   Worlds themselves should never need to be updated after creation -- instead the
 ;   various refs inside them are updated.
 ;
-; packet-counts-in  -> integer
-; packet-counts-out -> integer
+; packet-counts-in  -> {:packet-type integer}
+; packet-counts-out -> {:packet-type integer}
 (defrecord Bot [connection outqueue player world
                 packet-counts-in packet-counts-out])


Fix item/update-item by retaining the automotic properties of :type, :slug and :collection.

--- src/fcms/resources/item.clj
+++ src/fcms/resources/item.clj
@@ -86,10 +86,11 @@
         (= item-slug provided-slug) true
         :else (if (nil? (get-item coll-slug provided-slug)) true :slug-conflict))))

-(defn- update [coll-slug item-slug props]
+(defn- update [coll-slug item-slug updated-props]
   (collection/with-collection coll-slug
     (if-let [item (item-doc (:id collection) item-slug)]
-      (item-from-db coll-slug (common/update-with-db item props))
+      (let [retained-props (select-keys (:data item) [:type :collection :slug])]
+        (item-from-db coll-slug (common/update-with-db item (merge retained-props updated-props))))
       :bad-item)))

 (defn update-item


Fixed broken tests.

Fixed broken tests.

NOTE a breaking change is that we've changed the behaviour of query so
the maps it returns are keyed by keywords not strings.

--- test/grafter/rdf/repository_test.clj
+++ test/grafter/rdf/repository_test.clj
@@ -89,7 +89,7 @@
     (are [type f?]
         (is (f? (let [o (-> (query test-db (str "PREFIX : <http://example/> SELECT ?o WHERE {" type " :hasValue ?o . }"))
                             first
-                            (get "o"))]
+                            (get :o))]
                   o)))

       :integer integer?


fix bug with compute-corr crashing memory on export for large convs without setting tids param; picks default tid examplars

--- src/polismath/math/corr.clj
+++ src/polismath/math/corr.clj
@@ -146,10 +146,26 @@
           (update :center (partial into []))))
     clusters))

+
+(defn default-tids
+  ;; Gonna need to get all of this under group clusters vs subgroups
+  [{:as conv :keys [repness consensus group-clusters rating-mat pca]}]
+  (let [{:keys [extremity]} pca
+        {:keys [agree disagree]} consensus]
+    (set
+      (concat
+        (map :tid (concat agree disagree))
+        (mapcat
+          (fn [[gid gid-repness]]
+            (map :tid gid-repness))
+          repness)))))
+
+
 (defn compute-corr
   ([conv tids]
-   (let [matrix (:rating-mat conv)
-         subset-matrix (if tids (nm/colname-subset matrix tids) matrix)
+   (log/info tids)
+   (let [matrix (log/spy (:rating-mat conv))
+         subset-matrix (if tids (log/spy (nm/colname-subset matrix tids)) (log/spy matrix))
          cleaned-matrix (cleaned-nmat subset-matrix)
          transposed-matrix (transpose-nmat cleaned-matrix)
          corr-mat (prof/profile :info :corr-mat (correlation-matrix cleaned-matrix))
@@ -161,7 +177,7 @@
                                          matrix/rows))]
      corr-mat'))
   ([conv]
-   (compute-corr conv nil)))
+   (compute-corr conv (default-tids conv))))

 (defn spit-json


Listen by default only on localhost

--- src/gorilla_repl/core.clj
+++ src/gorilla_repl/core.clj
@@ -111,7 +111,7 @@
     ;; first startup nREPL
     (nrepl/start-and-connect nrepl-requested-port)
     ;; and then the webserver
-    (server/run-server app-routes {:port webapp-port :join? false})
+    (server/run-server app-routes {:port webapp-port :join? false :ip "127.0.0.1"})
     (println (str "Running at http://localhost:" webapp-port "/worksheet.html ."))
     (println "Ctrl+C to exit.")))


Make sure that when error is thrown in streaming mode, seq is terminated.

--- src/http/async/client.clj
+++ src/http/async/client.clj
@@ -70,7 +70,10 @@
                           {:part (fn [_ baos]
                                    (.put que baos)
                                    [s-seq :continue])
-                           :completed (fn [_] (.put que ::done))})))))
+                           :completed (fn [_] (.put que ::done))
+                           :error (fn [_ t]
+                                    (.put que ::done)
+                                    t)})))))

 (defn failed?
   "Checks if request failed."


extract local theta

extract local theta

--- examples/src/famous_examples/core.cljs
+++ examples/src/famous_examples/core.cljs
@@ -1,5 +1,5 @@
 (ns ^:figwheel-always famous-examples.core
-    (:require [com.famous.Famous]))
+  (:require [com.famous.Famous]))

 (enable-console-print!)

@@ -7,27 +7,29 @@
 ;; translated from https://github.com/Famous/global-seed/blob/master/src/main.js

 (defonce ImageSurface (.. js/famous -surfaces -ImageSurface))
-(defonce Modifier     (.. js/famous -core -Modifier))
-(defonce Transform    (.. js/famous -core -Transform))
+(defonce Modifier (.. js/famous -core -Modifier))
+(defonce Transform (.. js/famous -core -Transform))

 (defonce logo
-  (ImageSurface.
-    (clj->js {"size" [200,200]
-              "content" "https://pbs.twimg.com/profile_images/559761425766158336/Uq5W8iWA.jpeg"
-              "classes" ["double-sided"]})))
+         (ImageSurface.
+           (clj->js {"size"    [200, 200]
+                     "content" "https://pbs.twimg.com/profile_images/559761425766158336/Uq5W8iWA.jpeg"
+                     "classes" ["double-sided"]})))

-(defonce initialTime (.. js/Date now))
+(defonce initialTime (.. js/Date now))

 (defonce center-spin-modifier
-  (Modifier.
-   (clj->js {"origin" [0.5 0.5]
-             "align" [0.5 0.5]
-             "transform" (fn[] (.. Transform (rotateY  (* .002 (- (.now js/Date) initialTime))) ))})))
+         (Modifier.
+           (clj->js {"origin"    [0.5 0.5]
+                     "align"     [0.5 0.5]
+                     "transform" (fn []
+                                     (let [theta (* .002 (- (.now js/Date) initialTime))]
+                                          (.. Transform (rotateY theta))))})))

-(let [Engine         (.. js/famous -core -Engine)
-      mainContext    (.. Engine createContext)]
-  (.. mainContext (add center-spin-modifier) (add logo)))
+(let [Engine (.. js/famous -core -Engine)
+      mainContext (.. Engine createContext)]
+     (.. mainContext (add center-spin-modifier) (add logo)))


Add numerical histogram and empirical distribution

--- src/clj/clojurewerkz/statistiker/descriptive.clj
+++ src/clj/clojurewerkz/statistiker/descriptive.clj
@@ -1,5 +1,7 @@
 (ns clojurewerkz.statistiker.descriptive
-  (:import [org.apache.commons.math3.stat.descriptive.rank Percentile])
+  (:import [org.apache.commons.math3.stat.descriptive.rank Percentile]
+           [org.apache.commons.math3.random EmpiricalDistribution]
+           [java.util TreeMap])
   (:require [clojurewerkz.statistiker.fast-math :refer :all]))

 (def percentiles
@@ -25,3 +27,81 @@
         first-quartile (.evaluate p (double 25))
         third-quartile (.evaluate p (double 75))]
     (- third-quartile first-quartile)))
+
+(defn median
+  [values]
+  (let [p (Percentile.)
+        _ (.setData p (double-array values))]
+    (.evaluate p (double 50))))
+
+(defn percentiles
+  [values percentiles]
+  (let [p              (Percentile.)
+        _              (.setData p (double-array values))]
+    (mapv #(.evaluate p (double %)) percentiles)))
+
+(defn percentile
+  [values percentile]
+  (let [p              (Percentile.)
+        _              (.setData p (double-array values))]
+    (.evaluate p (double percentile))))
+
+(defprotocol Histogram
+  (add [_ value])
+  (get-counts [_]))
+
+(defn- get-diff
+  [[i1 i2]]
+  (- i2 i1))
+
+(defn- merge-closest
+  [m]
+  (let [[[q1 q2] _] (->> m
+                         keys
+                         sort
+                         (partition 2 1)
+                         (sort-by get-diff))
+        k1          (get m q1)
+        k2          (get m q2)]
+    (-> m
+        (dissoc q1)
+        (dissoc q2)
+        (assoc
+            (/ (+ (* q1 k1) (* q2 k2))
+               (+ k1 k2))
+          (+ k1 k2)))))
+
+(defn make-numerical-histogram
+  [max-bins]
+  (let [bins (atom {})]
+    (reify Histogram
+      (add [_ value]
+        (swap! bins
+               (fn [bins]
+                 (if-let [prev (get bins value)]
+                   (assoc bins value (inc prev))
+                   (loop [bins (assoc bins value 1)]
+                     (if (<= (count bins) max-bins)
+                       bins
+                       (recur (merge-closest bins))))))))
+      (get-counts [_] (into {}
+                            (mapv (fn [[k v]] [(double k) (double v)]) @bins))))))
+
+(defn numerical-histogram
+  [max-bins vals]
+  (let [hist (make-numerical-histogram 5)]
+    (doseq [i vals]
+      (add hist i))
+    (get-counts hist)))
+
+(defn empirical-distribution
+  [bins data]
+  (let [emp-d (EmpiricalDistribution. (int bins))]
+    (.load emp-d (double-array (mapv double data)))
+     (zipmap
+     (.getUpperBounds emp-d)
+     (map #(.getN %) (.getBinStats emp-d)))))
+
+(defn to-sorted-map
+  [m]
+  (TreeMap. m))


Add more examples from section 6.8

Add more examples from section 6.8

- States and its unified model

--- src/clojure/clojure_walkthrough/cjia/ch06_xx.clj
+++ src/clojure/clojure_walkthrough/cjia/ch06_xx.clj
@@ -119,3 +119,43 @@
 (pmap db-query mysql-hosts) ;; (10 9 13)

 ;; 6.8: State and its unified access model (TBC)
+;; creating
+(def a-ref (ref 0))
+(def an-agent (agent 0))
+(def an-atom (atom 0))
+
+;; reading
+(deref a-ref)    ; or @a-ref
+(deref an-agent) ; or @an-agent
+(deref an-atom)  ; or @an-atom
+
+;; Mutation (for refs)
+;(ref-set new-value)
+;(alter ref function & args)
+;(commut ref function & args)
+
+;; Mutation (for agents)
+;(send agent function & args)
+;(send-off agent function & args)
+
+;; Mutattion (for atoms)
+;(reset! atom new-value)
+;(swap! atom function & args)
+;(compare-and-set! atom old-value new-value)
+
+;; 6.8.5: watching for mutation with `add-watch` and `remove-watch`
+(def adi (atom 0))
+
+(defn on-change [the-key the-ref old-value new-value]
+  (println "Hey, seeing change from " old-value " to " new-value))
+
+; Use of add-watch function
+(add-watch adi :adi-watcher on-change)
+
+(deref adi) ;
+
+(swap! adi inc) ; 1
+(swap! adi inc) ; 2
+
+; we can remove them using `remove-watch`
+(remove-watch adi :adi-watcher)


CMR-543: Updated error message to include 'unset' in acceptable values.

--- src/cmr/search/services/parameter_validation.clj
+++ src/cmr/search/services/parameter_validation.clj
@@ -342,7 +342,7 @@
       (fn [[key value]]
         (if (or (= "true" value) (= "false" value) (= "unset" value))
           []
-          [(format "Parameter %s must take value of true of false, but was %s" key value)]))
+          [(format "Parameter %s must take value of true, false, or unset, but was %s" key value)]))
       bool-params)))

 (def parameter-validations


Rendering of destinations in HTML - Main destination content now rendered - converted xml tags into human-readable section titles - added utility functions to convert the depth in the content xml to the appropriate <hx> level; CSS doesn't disambiguate fantastically but presumably editing that is out-of-scope - generated main content html by converting content xml to a zipper, generating html (in hiccup format) based on the location (body copy only from leaf nodes, titling only from parent nodes)

--- src/lonelyplanet/view.clj
+++ src/lonelyplanet/view.clj
@@ -1,5 +1,8 @@
 (ns lonelyplanet.view
-  (:require [net.cgrand.enlive-html :refer :all]))
+  (:require [net.cgrand.enlive-html :refer :all]
+            [clojure.zip :as z]
+            [clojure.string :as s]
+            [aprint.core :refer [aprint]]))

 (def blank "static/example copy.html")

@@ -9,11 +12,30 @@
   [step taxonomy]
   (when step (html [:li [:a {:href (str step ".html")} (-> (Integer. ^String step) taxonomy :placename)]])))

+(defn make-title
+  "Convert lowercase strings with underscores instead of spaces to capitalised strings"
+  [string]
+  (-> string (s/replace "_" " ") s/capitalize))
+
+(defn depth
+  "Determine depth in content hierarchy. 1 is the highest level."
+  [loc]
+  (count (z/path loc)))
+
+(defn level-header
+  "Generate a header keyword (in Hiccup format) based on a supplied hierarchy, with 1 returning a :h1, etc."
+  [depth]
+  (keyword (str "h" depth)))
+
 (defn gen-content
   "Convert destination data (supplied as a lazy xml parser) into the main HTML content for the destination page."
   [destination]
-  (html [:h1 "Test only"] [:p "Testing, just testing."])
-  )
+  (let [destination (-> destination z/xml-zip z/down)
+        fragment-locs (take-while (complement z/end?) (iterate z/next destination))]
+    (html (map (fn [loc]
+                 (list (when (z/down loc) [(level-header (depth loc)) (-> loc z/node :tag name make-title)])
+                       (when (not (z/down loc)) [:p (-> loc z/node)])))
+               fragment-locs))))

 (deftemplate destination blank [destination taxonomy]
              [:div#header :h1] (content (get-in destination [:meta :placename]))


CEO-426 Check header-keys for duplicates and throw error.

--- src/clj/collect_earth_online/generators/external_file.clj
+++ src/clj/collect_earth_online/generators/external_file.clj
@@ -78,7 +78,11 @@
                              (update r geom-key tc/str->pg "geometry")
                              (update r :visible_id tc/val->int)))
                          (str/split body-text #"\r\n|\n|\r"))]
-    [header-keys body]))
+    (if (apply distinct? header-keys)
+      [header-keys body]
+      (pu/init-throw (str "The provided "
+                           design-type
+                           " SHP file must not contain duplicate column titles.")))))

 (defmethod get-file-data :csv [_ design-type ext-file folder-name]
   (let [rows       (str/split (slurp (str folder-name ext-file)) #"\r\n|\n|\r")
@@ -110,7 +114,11 @@
                            (rest rows))]
       (if (and (some #(= % :lon) header-keys)
                (some #(= % :lat) header-keys))
-        [(pu/remove-vector-items header-keys [:lon :lat]) body]
+        (if (apply distinct? header-keys)
+          [(pu/remove-vector-items header-keys [:lon :lat]) body]
+          (pu/init-throw (str "The provided "
+                               design-type
+                               " CSV file must not contain duplicate column titles.")))
         (pu/init-throw  (str "The provided "
                              design-type
                              " CSV file must contain a LAT and LON column."))))))


make development the default environment

--- src-cljs/frontend/env.cljs
+++ src-cljs/frontend/env.cljs
@@ -6,7 +6,7 @@
   (or env-var (let [render-context (aget js/window "renderContext")]
                 (if render-context
                   (-> render-context (aget "env") keyword)
-                  :production))))
+                  :development))))

 (defn production? []
   (= (env) :production))


add type arg for alerts widget

add type arg for alerts widget

--- src-cljs/imago/alerts.cljs
+++ src-cljs/imago/alerts.cljs
@@ -1,14 +1,16 @@
 (ns imago.alerts
   (:require-macros
-   [cljs.core.async.macros :refer [go go-loop]])
+   [cljs.core.async.macros :refer [go]])
   (:require
    [thi.ng.cljs.log :refer [debug info warn]]
    [thi.ng.cljs.dom :as dom]
    [cljs.core.async :as async :refer [<! timeout]]))

 (defn alert
-  [msg parent]
-  (let [alert (dom/create-dom! [:div.alert.alert-danger msg] nil)]
+  [type msg parent]
+  (let [alert (dom/create-dom!
+               [:div {:class (str "alert alert-" (name type))} msg]
+               nil)]
     (dom/insert! alert parent)
     (go
       (<! (timeout 3000))


Aeron: improve connection handling, info logging

--- src/onyx/messaging/aeron/publication_manager.clj
+++ src/onyx/messaging/aeron/publication_manager.clj
@@ -34,8 +34,8 @@
       (fatal "Writing to closed publication." e)
       (stop publication-manager))
     (catch Throwable t
-      ;; TODO, handle this outcome better. Should reset connection?
-      (fatal "Aeron write from buffer error: " t))))
+      (fatal "Aeron write from buffer error: " t)
+      (stop publication-manager))))

 (defrecord PublicationManager [channel stream-id send-idle-strategy connection publication pending-ch write-fut cleanup-fn]
   PPublicationManager
@@ -48,6 +48,7 @@
     (>!! pending-ch (->Message buf start end)))

   (stop [this]
+    (info (format "Stopped publication manager at: %s, stream-id: %s" channel stream-id))
     (cleanup-fn)
     (future-cancel (:write-fut this))
     (close! pending-ch)
@@ -65,6 +66,7 @@
                             (taoensso.timbre/warn "Aeron messaging publication error:" x)))
           conn (Aeron/connect (.errorHandler (Aeron$Context.) error-handler))
           pub (.addPublication conn channel stream-id)]
+      (info (format "Connected via publication on: %s, stream-id: %s" channel stream-id))
       (assoc this :publication pub :connection conn))))

 (defn new-publication-manager [channel stream-id send-idle-strategy write-buffer-size cleanup-fn]


Added caching component.

Added caching component.

--- dev-resources/src/cmr/opendap/dev.clj
+++ dev-resources/src/cmr/opendap/dev.clj
@@ -6,6 +6,7 @@
     [clojure.tools.namespace.repl :as repl]
     [clojusc.dev.system.core :as system-api]
     [clojusc.twig :as logger]
+    [cmr.opendap.components.caching :as caching]
     [cmr.opendap.components.config :as config]
     [cmr.opendap.components.core]
     [com.stuartsierra.component :as component]


Rework site-dev to allow running network tests

--- dev-src/clj/comic_reader/site_dev.clj
+++ dev-src/clj/comic_reader/site_dev.clj
@@ -3,13 +3,29 @@
             [clojure.test :refer [run-tests]]
             [clojure.tools.namespace.repl :refer [refresh]]))

-(defn run-site-tests* []
+(defn- after-run-site-tests [network?]
   (require 'comic-reader.sites-test)
-  (run-tests (find-ns 'comic-reader.sites-test)))
+  (let [test-ns (find-ns 'comic-reader.sites-test)]
+    (reset! (deref (ns-resolve test-ns 'run-network-tests?)) network?)
+    (run-tests test-ns)))

-(defn touch-file [file]
+(defn- *run-site-tests-without-network []
+  (after-run-site-tests false))
+
+(defn- *run-site-tests-with-network []
+  (after-run-site-tests true))
+
+(defn- touch-file [file]
   (.setLastModified (as-file file) (System/currentTimeMillis)))

+(defn- *run-site-tests [after-sym]
+  (touch-file (resource "comic_reader/sites_test.clj"))
+  (refresh :after after-sym))
+
 (defn run-site-tests []
-  (touch-file (resource "comic_reader/sites_test.clj"))
-  (refresh :after 'comic-reader.site-dev/run-site-tests*))
+  (*run-site-tests
+   'comic-reader.site-dev/*run-site-tests-without-network))
+
+(defn run-site-tests-with-network []
+  (*run-site-tests
+   'comic-reader.site-dev/*run-site-tests-with-network))


chatty-checkers are no longer special

chatty-checkers are no longer special

--- src/midje/unprocessed.clj
+++ src/midje/unprocessed.clj
@@ -42,26 +42,23 @@
            :expected (:expected-result-text-for-failures call)})

   (check-result-positive [report-fn actual call]
-    (cond (extended-= actual (:expected-result call))
-      (report-fn {:type :pass})
+    (cond  (extended-= actual (:expected-result call))
+           (report-fn {:type :pass})

-      (chatty-checker? (:expected-result call))
-      (report-fn (merge (fail :mock-expected-result-functional-failure actual call)
-                   (let [chatty-result ((:expected-result call) actual)]
-                     (if (map? chatty-result)
-                       chatty-result
-                       {:notes ["Midje program error. Please report."
-                                (str "A chatty checker returned "
-                                  (pr-str chatty-result)
-                                  " instead of a map.")]}))))
-
-      (fn? (:expected-result call))
-      (report-fn (fail :mock-expected-result-functional-failure actual call))
-
-      :else
-      (report-fn (assoc (fail :mock-expected-result-failure actual call)
-                       :expected (:expected-result call)))))
-
+           (fn? (:expected-result call))
+           (report-fn (merge (fail :mock-expected-result-functional-failure
+                                   actual call)
+                             ;; TODO: It is very lame that the
+                             ;; result-function has to be called again to
+                             ;; retrieve information that extended-=
+                             ;; knows and threw away.
+                              (or ( (:expected-result call) actual)
+                                  {})))
+
+           :else
+           (report-fn (assoc (fail :mock-expected-result-failure actual call)
+                        :expected (:expected-result call)))))
+
   (check-result-negated [report-fn actual call]
     (cond (not (extended-= actual (:expected-result call)))
       (report-fn {:type :pass})
@@ -113,4 +110,4 @@
                                     (captured-throwable ex)))]
       (report-incorrect-call-counts local-fakes)
       (check-result code-under-test-result unprocessed-check)
-      :irrelevant-return-value)))+      :irrelevant-return-value)))


PDOK-1599: analyse tests

PDOK-1599: analyse tests

--- src/test/clojure/pdok/featured/extracts_test.clj
+++ src/test/clojure/pdok/featured/extracts_test.clj
@@ -22,6 +22,8 @@
   (let [[error features-for-extract] (features-for-extract "test" "dummy" "gml2extract" (two-features) "src/test/resources/templates")]
     (is (= 2 )(count features-for-extract))))

+(def ^{:private true} extract-type-citygml "citygml")
+
 (deftest test-rendered-feature-gml
   (let [_ (println (str "feature one " (one-feature)))
         [error features-for-extract] (features-for-extract "test" "dummy" "gml2extract" (one-feature) "src/test/resources/templates")
@@ -32,7 +34,6 @@
     (is (boolean (re-find #"<geo><gml:Polygon" result-feature)))
     (is (boolean (re-find #"<naam>PDOK</naam>" result-feature)))))

-(def ^{:private true} extract-type-citygml "citygml")

 (defn write-xml-to-database [dataset feature-type path template-dir]
   "Helper function to write features to an extract-schema."


Simplify cue creation examples.

Simplify cue creation examples.

Now that cues can rely on the ability to save variables, they can be
created far more simply, and still be incredibly useful. Show how.

--- src/afterglow/examples.clj
+++ src/afterglow/examples.clj
@@ -424,11 +424,10 @@
         cycles-param (params/bind-keyword-param (:cycles var-map) Number 1)]
     (params/build-param-formula Number #(/ %1 %2) beats-param cycles-param)))

-(defn make-sawtooth-cue
+(defn make-sawtooth-dimmer-cue
   "Create a cue which applies a sawtooth oscillator to the dimmers of
-  the specified group of fixtures, with cue parameters to adjust the
-  beat ratio, starting with default values established by show
-  parameters."
+  the specified group of fixtures, with cue variables to adjust the
+  oscillator parameters."
   [group x y color]
   (let [[effect-key fixtures end-keys effect-name] (build-group-cue-elements group "dimmers" "saw")]
     (ct/set-cue! (:cue-grid *show*) x y
@@ -441,18 +440,16 @@
                                           fixtures
                                           :effect-name effect-name))
                            :color color
-                           :variables [{:key "beats" :min 1 :max 32 :type :integer :start :starting-beats :name "Beats"}
-                                       {:key "down" :type :boolean :start :sawtooth-down? :name "Down?"}
-                                       {:key "cycles" :min 1 :max 10 :type :integer :start :starting-cycles
-                                        :name "Cycles"}
-                                       {:key "phase" :min 0 :max 1 :start :starting-phase :name "Phase"}]
+                           :variables [{:key "beats" :min 1 :max 32 :type :integer :start 2 :name "Beats"}
+                                       {:key "down" :type :boolean :start true :name "Down?"}
+                                       {:key "cycles" :min 1 :max 10 :type :integer :start 1 :name "Cycles"}
+                                       {:key "phase" :min 0 :max 1 :start 0 :name "Phase"}]
                            :end-keys end-keys))))

-(defn make-triangle-cue
+(defn make-triangle-dimmer-cue
   "Create a cue which applies a triangle oscillator to the dimmers of
-  the specified set of fixtures, with cue parameters to adjust the
-  beat ratio, starting with default values established by show
-  parameters."
+  the specified set of fixtures, with cue variables to adjust the
+  oscillator parameters."
   [group x y color]
   (let [[effect-key fixtures end-keys effect-name] (build-group-cue-elements group "dimmers" "triangle")]
     (ct/set-cue! (:cue-grid *show*) x y
@@ -464,16 +461,15 @@
                                         fixtures
                                         :effect-name effect-name))
                          :color color
-                         :variables [{:key "beats" :min 1 :max 32 :type :integer :start :starting-beats :name "Beats"}
-                                     {:key "cycles" :min 1 :max 10 :type :integer :start :starting-cycles
-                                      :name "Cycles"}
-                                     {:key "phase" :min 0 :max 1 :start :starting-phase :name "Phase"}]
+                         :variables [{:key "beats" :min 1 :max 32 :type :integer :start 2 :name "Beats"}
+                                     {:key "cycles" :min 1 :max 10 :type :integer :start 1 :name "Cycles"}
+                                     {:key "phase" :min 0 :max 1 :start 0 :name "Phase"}]
                          :end-keys end-keys))))

-(defn make-sine-cue
+(defn make-sine-dimmer-cue
   "Create a cue which applies a sine oscillator to the dimmers of the
-  specified set of fixtures, with cue parameters to adjust the beat
-  ratio, starting with default values established by show parameters."
+  specified set of fixtures, with cue variables to adjust the
+  oscillator parameters."
   [group x y color]
   (let [[effect-key fixtures end-keys effect-name] (build-group-cue-elements group "dimmers" "sine")]
     (ct/set-cue! (:cue-grid *show*) x y
@@ -486,17 +482,15 @@
                                           fixtures
                                           :effect-name effect-name))
                            :color color
-                           :variables [{:key "beats" :min 1 :max 32 :type :integer :start :starting-beats :name "Beats"}
-                                       {:key "cycles" :min 1 :max 10 :type :integer :start :starting-cycles
-                                        :name "Cycles"}
-                                       {:key "phase" :min 0 :max 1 :start :starting-phase :name "Phase"}]
-                         :end-keys end-keys))))
-
-(defn make-square-cue
+                           :variables [{:key "beats" :min 1 :max 32 :type :integer :start 2 :name "Beats"}
+                                       {:key "cycles" :min 1 :max 10 :type :integer :start 1 :name "Cycles"}
+                                       {:key "phase" :min 0 :max 1 :start 0 :name "Phase"}]
+                           :end-keys end-keys))))
+
+(defn make-square-dimmer-cue
   "Create a cue which applies a square oscillator to the dimmers of
-  the specified set of fixtures, with cue parameters to adjust the
-  beat ratio and pulse width, starting with default values established
-  by show parameters."
+  the specified set of fixtures, with cue variables to adjust the
+  oscillator parameters."
   [group x y color]
   (let [[effect-key fixtures end-keys effect-name] (build-group-cue-elements group "dimmers" "square")]
     (ct/set-cue! (:cue-grid *show*) x y
@@ -509,11 +503,10 @@
                                         fixtures
                                         :effect-name effect-name))
                          :color color
-                         :variables [{:key "beats" :min 1 :max 32 :type :integer :start :starting-beats :name "Beats"}
-                                     {:key "width" :min 0 :max 1 :start :starting-width :name "Width"}
-                                     {:key "cycles" :min 1 :max 10 :type :integer :start :starting-cycles
-                                      :name "Cycles"}
-                                     {:key "phase" :min 0 :max 1 :start :starting-phase :name "Phase"}]
+                         :variables [{:key "beats" :min 1 :max 32 :type :integer :start 2 :name "Beats"}
+                                     {:key "width" :min 0 :max 1 :start 0.5 :name "Width"}
+                                     {:key "cycles" :min 1 :max 10 :type :integer :start 1 :name "Cycles"}
+                                     {:key "phase" :min 0 :max 1 :start 0 :name "Phase"}]
                          :end-keys end-keys))))

 (defn x-phase
@@ -555,7 +548,7 @@
   (atom nil))

 (defn- build-focus-oscillator
-  "Creates a cue which oscillates a fixture's focus between a minimum
+  "Returns a cue which oscillates a fixture's focus between a minimum
   and minimum value using a sine oscillator with cue variables to
   adjust the range and the oscillator's parameters."
   [effect-key effect-name fixtures]
@@ -673,55 +666,21 @@
                            :variables [{:key "chance" :min 0.0 :max 0.4 :start 0.05 :velocity true}
                                        {:key "fade-time" :name "Fade" :min 1 :max 2000 :start 50 :type :integer}]))

-
-    ;; Set up default starting values for oscillators driving dimmer cues
-    (when-not (= (type (show/get-variable :starting-beats)) Long)
-      ;; If the default beat ratio numerator has not yet been set, establish it as 2
-      (show/set-variable! :starting-beats 2))
-    (when-not (= (type (show/get-variable :starting-cycles)) Long)
-      ;; If the default beat ratio denominator has not yet been set, establish it as 1
-      (show/set-variable! :starting-cycles 1))
-    (when-not (= (type (show/get-variable :starting-phase)) Double)
-      ;; If the default pulse phase has not yet been set, establish it as 0.0
-      (show/set-variable! :starting-phase 0.0))
-    (when-not (= (type (show/get-variable :sawtooth-down?)) Boolean)
-      ;; If the default sawtooth direction has not yet been set, establish it as down
-      (show/set-variable! :sawtooth-down? true))
-    (when-not (= (type (show/get-variable :starting-width)) Double)
-      ;; If the default pulse width has not yet been set, establish it as 0.5
-      (show/set-variable! :starting-width 0.5))
-
     ;; Dimmer oscillator cues: Sawtooth
-    (make-sawtooth-cue nil 0 3 :yellow)
-    (doall (map-indexed (fn [i group] (make-sawtooth-cue group (inc i) 3 :orange)) light-groups))
-
-    (ct/set-cue! (:cue-grid *show*) 7 3
-                 (cues/cue :sawtooth-down? (fn [_] (var-fx/variable-effect @var-binder :sawtooth-down? false))
-                           :color :red :short-name "Saw Up"))
+    (make-sawtooth-dimmer-cue nil 0 3 :yellow)
+    (doall (map-indexed (fn [i group] (make-sawtooth-dimmer-cue group (inc i) 3 :orange)) light-groups))

     ;; Dimmer oscillator cues: Triangle
-    (make-triangle-cue nil 0 4 :orange)
-    (doall (map-indexed (fn [i group] (make-triangle-cue group (inc i) 4 :red)) light-groups))
+    (make-triangle-dimmer-cue nil 0 4 :orange)
+    (doall (map-indexed (fn [i group] (make-triangle-dimmer-cue group (inc i) 4 :red)) light-groups))

     ;; Dimmer oscillator cues: Sine
-    (make-sine-cue nil 0 5 :cyan)
-    (doall (map-indexed (fn [i group] (make-sine-cue group (inc i) 5 :blue)) light-groups))
-
-    (ct/set-cue! (:cue-grid *show*) 7 5
-                 (cues/cue :beat-ratio
-                           (fn [_] (fx/blank "Starting Ratio"))
-                           :variables [{:key :starting-beats :min 1 :max 32 :type :integer :name "Beats"}
-                                       {:key :starting-cycles :min 1 :max 10 :type :integer :name "Cycles"}]))
+    (make-sine-dimmer-cue nil 0 5 :cyan)
+    (doall (map-indexed (fn [i group] (make-sine-dimmer-cue group (inc i) 5 :blue)) light-groups))

     ;; Dimmer oscillator cues: Square
-    (make-square-cue nil 0 6 :cyan)
-    (doall (map-indexed (fn [i group] (make-square-cue group (inc i) 6 :green)) light-groups))
-
-    (ct/set-cue! (:cue-grid *show*) 7 6
-                 (cues/cue :beat-ratio
-                           (fn [_] (fx/blank "Starting Shape"))
-                           :variables [{:key :starting-width :min 0 :max 1 :name "Width"}
-                                     {:key :starting-phase :min 0 :max 1 :name "Phase"}]))
+    (make-square-dimmer-cue nil 0 6 :cyan)
+    (doall (map-indexed (fn [i group] (make-square-dimmer-cue group (inc i) 6 :green)) light-groups))

     ;; Strobe cues
     (make-strobe-cue-2 "All" (show/all-fixtures) 0 7)


And 2017 day 4 part 2 done!

And 2017 day 4 part 2 done!

--- 2017/day4/src/day4/core.clj
+++ 2017/day4/src/day4/core.clj
@@ -12,6 +12,12 @@
   (let [splitPassphrase (seq (splitWhitespace passphrase))]
     (= splitPassphrase (distinct splitPassphrase))))

+(defn anagramPassphrase?
+  "Checks if the passphrase has no unique/anagram words."
+  [passphrase]
+  (let [sortedPassphrase (map sort (seq (splitWhitespace passphrase)))]
+    (= sortedPassphrase (distinct sortedPassphrase))))
+
 (defn trueToNum
   "Translates true to 1 and false to 0."
   [maybeTrue]
@@ -19,11 +25,11 @@

 (defn validPassphrases
   "Returns how many passphrases of sequence are valid."
-  [sequence]
+  [sequence checkfn]
   (->> sequence
        (clojure.string/split-lines)
        (map clojure.string/trim)
-       (map passphrase?)
+       (map checkfn)
        (map trueToNum)
        (reduce +)))

@@ -32,4 +38,5 @@
   [& args]
   (let [filename (if args (first args) "input")]
     (let [contents (clojure.string/trim (slurp filename))]
-      (println (validPassphrases contents)))))
+      (println (validPassphrases contents passphrase?))
+      (println (validPassphrases contents anagramPassphrase?)))))


Refactored get-item-texts ns to more clearly separate each step of processing.

--- project/scrape-summitpost-data/src/scrape_summitpost_data/get_item_texts.clj
+++ project/scrape-summitpost-data/src/scrape_summitpost_data/get_item_texts.clj
@@ -9,40 +9,35 @@

 (def base-url "http://www.summitpost.org")

-(defn- get-pager-links
+(defn- get-pager-urls
   "Given a link to a paginated search results page from summitpost, GET the
-  page and return a sequence of links to all search results pages."
+  page and return a sequence of fully qualified urls to all search results
+  pages."
   [link]
-  (let [page (slurp (str base-url link))]
-    (or (extract-all-pager-links page) [link])))
+  (let [page (slurp (str base-url link))
+        pager-links (or (extract-all-pager-links page) [link])]
+    (map (partial str base-url) pager-links)))

-(defn- get-search-pages
-  "Given a link to a search results page from summitpost, GET every search
-  results page in the pagination (or just the page if no pagination) and
-  return them as a lazy sequence."
-  [link]
-  (->> (get-pager-links link)
-       (map (partial str base-url))
-       (map slurp)))
-
-(defn- get-urls
-  "Given a link to a search results page from summitpost, return a sequence of
-  fully qualified urls to all of the search result items. This function
-  performs multiple GET requests."
-  [link]
-  (->> link
-       (get-search-pages)
+(defn- get-result-urls
+  "Given a sequence of search results pages from summitpost (as strings),
+  return a sequence of fully qualified urls to all of the search result
+  items."
+  [search-pages]
+  (->> search-pages
        (map extract-result-links)
        (apply concat)
        (map (partial str base-url))))

 (defn get-item-texts
   "Given a link to a search results page from summitpost (i.e. relative to the
-  summitpost domain), GET all search result items (iterating through pagination
-  if present) and return a sequence of [item-url, item-name, item-text]
-  triples."
+  summitpost domain), GET all search result items (iterating through
+  pagination if present) and return a sequence of [item-url, item-name,
+  item-text] triples."
   [search-link]
-  (->> (get-urls search-link)
+  (let [pager-urls (get-pager-urls link)
+        search-pages (map slurp pager-urls)
+        result-urls (get-result-urls search-pages)]
+  (->> result-urls
        (map #(vector
                %
                (extract-item-name base-url %)


refactor code

refactor code

--- src/clj/salava/badge/pdf.clj
+++ src/clj/salava/badge/pdf.clj
@@ -38,13 +38,11 @@
     (replace-nils badges)))

 (defn process-pdf-page [stylesheet template badge]
-  (let [p (slurp (io/piped-input-stream (fn [out] (pdf/pdf (into [stylesheet] (template badge)) out))))]
-    (if (blank? p)
-      (io/piped-input-stream (fn [out] (pdf/pdf [{} [:paragraph "Error while processing, Page can't be displayed"]] out)))
-      (io/piped-input-stream (fn [out] (pdf/pdf (into [stylesheet] (template badge)) out))))))
+  (if-let [p (blank? (slurp (io/piped-input-stream (fn [out] (pdf/pdf (into [stylesheet] (template badge)) out)))))]
+    (io/piped-input-stream (fn [out] (pdf/pdf [{} [:paragraph "Error while processing, Page can't be displayed"]] out)))
+    (io/piped-input-stream (fn [out] (pdf/pdf (into [stylesheet] (template badge)) out)))))

-
-(defn process-markdown [content markdown]
+(defn process-markdown [markdown]
   (if (== 1 (count markdown))
     markdown
       (if-let [p (blank? (slurp (io/piped-input-stream (fn [out] (pdf/pdf [{} (markdown->clj-pdf {:spacer {:extra-starting-value 1 :allow-extra-line-breaks? true :single-value 2} :wrap {:global-wrapper :paragraph}} markdown)] out)))))]
@@ -71,7 +69,7 @@
                     :chunk {:size 11
                             :style :bold}}

-        pdf-settings  (if (empty? font-path) {:stylesheet stylesheet  :bottom-margin 0 :footer {:page-numbers false :align :right}} {:font font :stylesheet stylesheet  :bottom-margin 0 :footer {:page-numbers false :align :right}})
+        pdf-settings  (if (empty? font-path) {:stylesheet stylesheet  :bottom-margin 0 :footer {:page-numbers true :align :right}} {:font font :stylesheet stylesheet  :bottom-margin 0 :footer {:page-numbers false :align :right}})
         badge-template (pdf/template
                          (let [template #(cons [:paragraph]  [ (if (and (not (= "-" (:image_file %)))(ends-with? (:image_file %) "png"))
                                                                  [:image {:width 100 :height 100 :align :center} (str data-dir "/" (:image_file %))]
@@ -109,7 +107,7 @@
                                                                 [:paragraph
                                                                  [:chunk.chunk (str (t :badge/Criteria ul)": ")] [:anchor {:target (:criteria_url %) :style{:family :times-roman :color [66 100 162]}} (:criteria_url %)]]
                                                                 [:spacer 0]
-                                                                (process-markdown "Criteria" (:criteria_content %))]
+                                                                (process-markdown (:criteria_content %))]

                                                                (when-not (empty? $endorsements)
                                                                  [:paragraph.generic
@@ -121,7 +119,7 @@
                                                                                (:issuer_name e) "\n"
                                                                                [:anchor {:target (:issuer_url e) :style{:family :times-roman :color [66 100 162]}} (or (:issuer_url e) "-")] "\n"
                                                                                [:chunk (if (number? (:issued_on e)) (date-from-unix-time (long (* 1000 (:issued_on e)))) (:issued_on e))] "\n"
-                                                                                (process-markdown "Endorsements" (:content e))]))])
+                                                                                (process-markdown (:content e))]))])

                                                                [:line {:dotted true}]
                                                                [:spacer 0]
@@ -156,7 +154,7 @@
                                                                              (:issuer_name e) "\n"
                                                                              [:anchor {:target (:issuer_url e) :style{:family :times-roman :color [66 100 162]}} (:issuer_url e)] "\n"
                                                                              [:chunk.link (if (number? (:issued_on e)) (date-from-unix-time (long (* 1000 (:issued_on e)))) (:issued_on e))] "\n"
-                                                                             (process-markdown "Issuer endorsements" (:content e))]))]))
+                                                                             (process-markdown (:content e))]))]))

                                                                [:pdf-table {:align :right :width-percent 100 :cell-border false}
                                                                 nil


Test availability of a field

Test availability of a field

--- src/cljs/db_quiz/layout.cljs
+++ src/cljs/db_quiz/layout.cljs
@@ -1,7 +1,7 @@
 (ns db-quiz.layout
   (:require [db-quiz.config :refer [config]]
             [db-quiz.logic :as logic]
-            [db-quiz.state :as state]
+            [db-quiz.state :refer [app-state]]
             [clojure.string :as string]))

 (defn shade-colour
@@ -57,8 +57,13 @@
   (let [absolute-offset (* (/ size 100) (get-in config [:layout :inner-hex-offset]))
         [x y] center]
     (fn []
-      (let [ownership (name (get-in @board [id :ownership]))]
-        [:g {:class (string/join " " (conj ["hexagon"] (if (= ownership "default") "default" "taken")))
+      (let [ownership (name (get-in @board [id :ownership]))
+            {:keys [current-field loading?]} @app-state
+            disabled? (not (nil? current-field))
+            availability (if (or loading? disabled? (not (#{"default" "missed"} ownership)))
+                             "unavailable"
+                             "available")]
+        [:g {:class (str "hexagon " availability)
              :on-click (partial logic/pick-field board id)}
          [:polygon.hex-outer {:fill (str "url(#" ownership "-outer)")
                               :points (hex-coords center size)}]


Update.

Update.

--- src/cljs/reversi/phaser.cljs
+++ src/cljs/reversi/phaser.cljs
@@ -5,6 +5,7 @@
 (def *border* (atom rcore/*default-border*))
 (def *phaser-border* (atom [[] [] [] [] [] [] [] []]))
 (def *visible-possible-grids-pos* (atom '()))
+(def ^:dynamic *game* (js/Phaser.Game. 905 605 js/Phaser.AUTO "game_div"))
 (def ^:dynamic *default-player-use-piece* rcore/*black-piece*)
 (def ^:dynamic *default-pc-use-piece* rcore/*white-piece*)

@@ -84,21 +85,17 @@
              @*phaser-border*)
   (pc-ai-put-piece @*border* @*phaser-border*)
   (let [no-put-piece-ai-and-player?
-        (show-possible-grid-on-pborder @*border* @*phaser-border*)]
-    (when (or (rcore/end-game? @*border*) (nil? no-put-piece-ai-and-player?))
+        (nil? (show-possible-grid-on-pborder @*border* @*phaser-border*))]
+    (when (or (rcore/end-game? @*border*) no-put-piece-ai-and-player?)
       (let [winner (rcore/who-win? @*border*)]
         (if (= winner *default-player-use-piece*)
           (js/alert "you are winner!")
           (js/alert "you are loser!")))))
-
   (let [result-count (rcore/grid-count @*border*)]
-    (set! (.-text (.-pieceCountText game))
+    (set! (.-text (.-pieceCountText *game*))
           (str "black-piece: " (result-count rcore/*black-piece*)
                "\nwhite-piece: " (result-count rcore/*white-piece*)
-               )
-          )
-    )
-  )
+               ))))

 (defn create-pieces [piece-name game]
   (let [piece-color (grid-name->rcore-grid piece-name)]
@@ -150,13 +147,19 @@
         style (clj->js { :font "35px Arial" :fill "#000000" :align "left" })]
     (set! (.-pieceCountText game) (.text (.-add game) 615 20 text style))))

+(defn ^export restart [game]
+  (reset! *border* rcore/*default-border*)
+  (reset! *phaser-border* [[] [] [] [] [] [] [] []])
+  (reset! *visible-possible-grids-pos* '())
+  (.start (.-state game) "main"))
+
 (defn create-buttons [game]
   (let [restart-button
         (.sprite (.-add game) 675 515 "restart-button")]
     (set! (.-inputEnabled restart-button) true)
     (set! (.-useHandCursor (.-input restart-button)) true)
     (.add (.-onInputDown (.-events restart-button))
-          (fn [b] (restart)) game)))
+          (fn [b] (restart game)) game)))

 (defn create [game]
   (set! (.-backgroundColor (.-stage game)) "#ffffff")
@@ -175,14 +178,10 @@
     (.image loader "possible-grid" "assets/gray-grid.png")
     (.image loader "restart-button" "assets/restart-button.png")))

-
 ;; (defn update [game]
 ;;   )

-
-(def ^export game (js/Phaser.Game. 905 605 js/Phaser.AUTO "game_div"))
-
-(defn ^export start []
+(defn ^export start [game]
   (.add (.-state game) "main"
         (clj->js {:preload preload
                   :create create
@@ -190,10 +189,4 @@
                   }))
   (.start (.-state game) "main"))

-(defn ^export restart []
-  (reset! *border* rcore/*default-border*)
-  (reset! *phaser-border* [[] [] [] [] [] [] [] []])
-  (reset! *visible-possible-grids-pos* '())
-  (start))
-
-(start)
+(start *game*)


add excluded-from-index

add excluded-from-index

--- src/datasplash/datastore.clj
+++ src/datasplash/datastore.clj
@@ -21,13 +21,16 @@

 (defn make-ds-entity
   "Generate a datastore entity. Take as parameters the string key of the entity, a map containing the different fields and an options map defining the datastore namespace and kind"
-  [raw-key raw-values {:keys [ds-namespace ds-kind] :as options}]
+  [raw-key raw-values {:keys [ds-namespace ds-kind excluded-from-index] :as options}]
   (let [key-builder (DatastoreHelper/makeKey (into-array [ds-kind raw-key]))
+        excluded-set (into #{} (map name excluded-from-index))
         _ (when ds-namespace (.setNamespaceId (.getPartitionIdBuilder key-builder) ds-namespace))
         entity-builder (Entity/newBuilder)
         _ (.setKey entity-builder (.build key-builder))
         _ (doseq [[v-key v-val] raw-values]
             (.put (.getMutableProperties entity-builder)
                   (if (keyword? v-key) (name v-key) v-key )
-                  (.build (DatastoreHelper/makeValue v-val))))]
+                  (-> (DatastoreHelper/makeValue v-val)
+                      (cond-> (excluded-set (name v-key)) (.setExcludeFromIndexes true))
+                      (.build ))))]
     (.build entity-builder)))


adding selmer to web test setup components

--- resources/leiningen/new/closp/integtest/clj/setup.clj
+++ resources/leiningen/new/closp/integtest/clj/setup.clj
@@ -8,6 +8,7 @@
             [{{ns}}.components.handler :refer [new-handler]]
             [{{ns}}.components.config :as c]
             [{{ns}}.components.db :refer [new-db]]
+            [{{ns}}.components.selmer :as selm]
             [{{ns}}.components.components :refer [prod-system]]
             [{{ns}}.locale :as l]))

@@ -33,6 +34,7 @@
 (defn test-system []
   (component/system-map
     :config (c/new-config test-config)
+    :selmer (selm/new-selmer false)
     :db (component/using (new-db) [:config])
     :handler (component/using (new-handler) [:config :db])
     :web (component/using (new-web-server) [:handler :config])))


Break out a c/then* macro, used when the response vector from c/send has already been de-referenced from the channel

--- src/io/aviso/rook/client.clj
+++ src/io/aviso/rook/client.clj
@@ -161,16 +161,29 @@
     (= 1 (count body)) (first body)
     :else (cons 'do body)))

+(defmacro then*
+  "Alternate version of the then macro, used when the vector returned by c/send is available."
+  ([result-vector success-clause]
+   `(then* ~result-vector (failure#) ~success-clause))
+  ([result-vector [failure & failure-body] [success & success-body]]
+   (assert failure "No failure symbol was provided to the then* macro")
+   (assert success "No success symbol was provided to the then* macro")
+   `(let [[~failure ~success] ~result-vector]
+      (if ~failure
+        ~(make-body failure failure-body)
+        ~(make-body success success-body)))))
+
 (defmacro then
-  "The send function returns a channel from which the eventual result can be taken; this macro makes it easy to response
-  to either the normal success or failure cases, as determined by the default callbacks. Then makes use of <! and can therefore
+  "The send function returns a channel from which the eventual result can be taken; this macro makes it easy to respond
+  to either the normal success or failure cases, as determined by the default callbacks. then makes use of <! and can therefore
   only be used inside a go block.

   channel - the expression which produces the channel, e.g., the result of calling send
-  failure - the symbol which will be assigned the failure response
-  failure-body - evaluated when there's a failure; if omitted, defaults to returning the failure response
-  success - the symbol which will be assigned the success body (from the Ring response)
-  success-body - evaluated when there is no failure, defaults to returning the success body
+  failure-clause - a symbol, followed by zero or more expression to be evaluated with the symbol bound to the failure response
+  success-clause - as with failure-clause, but with the symbol bound to the body of the success response
+
+  The body of either failure-clause or success-clause can be omitted; it defaults to the symbol, meaning that the
+  failure or success body is simply returned.

   Example:
     (-> (c/new-request handler)
@@ -180,13 +193,8 @@
                   (write-success-to-log success)
                   success)))

-  The entire failure clause can be omitted (as in the example)."
+  The entire failure clause can also be omitted (as in the example)."
   ([channel success-clause]
    `(then ~channel (failure#) ~success-clause))
-  ([channel [failure & failure-body] [success & success-body]]
-   (assert failure "No failure symbol was provided to the then macro")
-   (assert success "No success symbol was provided to the then macro")
-   `(let [[~failure ~success] (<! ~channel)]
-      (if ~failure
-        ~(make-body failure failure-body)
-        ~(make-body success success-body)))))+  ([channel failure-clause success-clause]
+   `(then* (<! ~channel) ~failure-clause ~success-clause)))


Adapt formatting to the current payload structure

--- src/io/cyanite/query/ast.clj
+++ src/io/cyanite/query/ast.clj
@@ -44,10 +44,11 @@
                       {}))

       (= 1 (count payload))
-      (-> payload first second)
+      (-> payload first)

       :else
-      (apply mapv f (map second payload)))))
+      (apply mapv f payload))))
+

 (defn index-series
   [series]


Update to reflect API change

Update to reflect API change

--- minicraft/desktop/src-common/minicraft/core.clj
+++ minicraft/desktop/src-common/minicraft/core.clj
@@ -91,10 +91,10 @@
   (fn [screen entities]
     (height! screen u/vertical-tiles))
   :on-key-down
-  (fn [{:keys [keycode]} entities]
+  (fn [{:keys [key]} entities]
     (when-let [player (u/get-player entities)]
       (cond
-        (= keycode (key-code :space))
+        (= key (key-code :space))
         (e/attack entities player))))
   :on-touch-down
   (fn [{:keys [input-x input-y]} entities]


improved performance; pan with arrow keys

git-svn-id: 03a8048b5ee8463be5048a3801110fb50f378627@9387 d0ab736e-dc22-4aeb-8dc9-08def0aa14fd

--- plugins/SlideExplorer2/src/slide_explorer/view.clj
+++ plugins/SlideExplorer2/src/slide_explorer/view.clj
@@ -14,6 +14,9 @@

 ;; tile/pixels

+(defn floor-int [x]
+  (long (Math/floor x)))
+
 (defn tile-to-pixels [[nx ny] [tile-width tile-height] tile-zoom]
   [(int (* (Math/pow 2.0 tile-zoom) nx tile-width))
    (int (* (Math/pow 2.0 tile-zoom) ny tile-height))])
@@ -21,10 +24,10 @@
 (defn tiles-in-pixel-rectangle
   "Returns a list of tile indices found in a given pixel rectangle."
   [rectangle [tile-width tile-height]]
-  (let [nl (Math/floor (/ (.x rectangle) tile-width))
-        nr (Math/floor (/ (+ -1 (.getWidth rectangle) (.x rectangle)) tile-width))
-        nt (Math/floor (/ (.y rectangle) tile-height))
-        nb (Math/floor (/ (+ -1 (.getHeight rectangle) (.y rectangle)) tile-height))]
+  (let [nl (floor-int (/ (.x rectangle) tile-width))
+        nr (floor-int (/ (+ -1 (.getWidth rectangle) (.x rectangle)) tile-width))
+        nt (floor-int (/ (.y rectangle) tile-height))
+        nb (floor-int (/ (+ -1 (.getHeight rectangle) (.y rectangle)) tile-height))]
     (for [nx (range nl (inc nr))
           ny (range nt (inc nb))]
       [nx ny])))
@@ -106,35 +109,25 @@
                            RenderingHints/VALUE_ANTIALIAS_ON
                            RenderingHints/VALUE_ANTIALIAS_OFF)))))

-(defn draw-image [g image x y clip-bounds]
-  (let [image-rect (Rectangle. x y 512 512)]
-    (if (.intersects image-rect clip-bounds)
-      (do ;(println "drawn")
-          (.drawImage g image x y nil))
-      ;(println "not drawn")
-      )))
-
-(defn paint-tiles [^Graphics2D g available-tiles zoom clip-bounds [tile-width tile-height]]
-  ;(println "paint-tiles")
-  ;(println (System/currentTimeMillis))
-  ;(timer
-  (doseq [[{:keys [nx ny nz nt nc]} image] (get available-tiles zoom)]
-    (when image
-      (let [[x y] (tile-to-pixels [nx ny] [tile-width tile-height] zoom)]
-        (draw-image g image x y clip-bounds)
-          ))
-    ;)
-    ))
+(defn paint-tiles [^Graphics2D g available-tiles screen-state [tile-width tile-height]]
+  (let [pixel-rect (Rectangle. (- (screen-state :x)) (- (screen-state :y))
+                               (screen-state :width) (screen-state :height))]
+    ;(println pixel-rect)
+    (doseq [[nx ny] (tiles-in-pixel-rectangle pixel-rect [tile-width tile-height])]
+      ;(println nx ny)
+      (when-let [image (get-in available-tiles [(screen-state :zoom) {:nx nx :ny ny :nz (screen-state :z) :nt 0 :nc 0}])]
+        (let [[x y] (tile-to-pixels [nx ny] [tile-width tile-height] 0)]
+          (.drawImage g image x y nil))))))

 (defn paint-screen [graphics screen-state available-tiles]
   (let [original-transform (.getTransform graphics)]
     (doto graphics
       (.setClip 0 0 (:width @screen-state) (:height @screen-state))
-      (.translate (+ (:x @screen-state) (/ (:width @screen-state) 2))
-                  (+ (:y @screen-state) (/ (:height @screen-state) 2)))
+      (.translate (:x @screen-state)
+                  (:y @screen-state))
       ;(.rotate @angle)
       enable-anti-aliasing
-      (paint-tiles @available-tiles (:zoom @screen-state) (.getClipBounds graphics) [512 512])
+      (paint-tiles @available-tiles @screen-state [512 512])
       (.setColor Color/YELLOW)
       (.fillOval -30 -30
                  60 60)
@@ -164,6 +157,15 @@
       (.addMouseMotionListener mouse-adapter))
     position-atom))

+(defn handle-arrow-pan [component position-atom]
+  (let [binder (fn [key axis step]
+                 (bind-key component key
+                           #(swap! position-atom update-in [axis] + step) true))]
+    (binder "UP" :y 50)
+    (binder "DOWN" :y -50)
+    (binder "RIGHT" :x -50)
+    (binder "LEFT" :x 50)))
+
 (defn handle-wheel [component z-atom]
   (.addMouseWheelListener component
     (proxy [MouseAdapter] []
@@ -220,6 +222,7 @@
     (.add (.getContentPane frame) panel)
     (setup-fullscreen frame)
     (handle-drags panel screen-state)
+    (handle-arrow-pan panel screen-state)
     (handle-wheel panel screen-state)
     (handle-resize panel screen-state)
     (handle-zoom frame screen-state)


reduce frequency slightly

reduce frequency slightly

git-svn-id: 03a8048b5ee8463be5048a3801110fb50f378627@10223 d0ab736e-dc22-4aeb-8dc9-08def0aa14fd

--- plugins/DLLAutoReloader/src/DLLAutoReloader/core.clj
+++ plugins/DLLAutoReloader/src/DLLAutoReloader/core.clj
@@ -140,7 +140,7 @@
   (let [keep-following (atom true)]
     (future
       (while @keep-following
-        (Thread/sleep 300)
+        (Thread/sleep 500)
         (reset! date-atom (file-dates path))))
     #(reset! keep-following false)))


allow any verbs

allow any verbs

--- src/babel/english/lab.cljc
+++ src/babel/english/lab.cljc
@@ -21,7 +21,8 @@
               (for [[k v] (:lexicon model)]
                 (let [filtered-v
                       (filter #(or (= "I" (u/get-in % [:english :english]))
-                                   (= "sleep" (u/get-in % [:english :english])))
+                                   (= "you" (u/get-in % [:english :english]))
+                                   (= :verb (u/get-in % [:synsem :cat])))
                               v)]
                   (if (not (empty? filtered-v))
                     [k filtered-v]))))


start prompt, still doesn't newlin

start prompt, still doesn't newlin

--- src/bitsplit_cli/core.cljs
+++ src/bitsplit_cli/core.cljs
@@ -38,6 +38,7 @@
           (= (take 4 command))))

 (defn start-repl []
+    (.start prompt)
     (execute {
         :storage storage
         :command "list"


improved angle formular for order priority

--- src/mastersign/wordcloud.clj
+++ src/mastersign/wordcloud.clj
@@ -88,9 +88,10 @@
   (let [clean-DE (fn [c] (case c \Ä \A \Ö \O \Ü \U \ß \S c))
         c (clean-DE (first (.toUpperCase text)))
         n (int c)
-        s (- (if (or (< n 64) (> n 90)) 64 n) 65)
-        a (* (/ Math/PI 13) s)]
-    (if (<= a Math/PI) (- Math/PI a) a)))
+        s (- (if (or (< n 64) (> n 90)) 64 n) 65)]
+    (if (< s 14)
+      (- Math/PI (/ Math/PI 28) (* (/ Math/PI 14) s))
+      (+ Math/PI (/ Math/PI 26) (* (/ Math/PI 12) (- s 14))))))

 (defn- ring-step
   [r prec]


added comment

added comment

--- sidecar/src/figwheel_sidecar/components/cljs_autobuild.clj
+++ sidecar/src/figwheel_sidecar/components/cljs_autobuild.clj
@@ -154,6 +154,12 @@
           ;; build once before watching
           ;; tiny experience tweak
           ;; first build shouldn't send notifications
+          ;; this is mainly to discard spurious warnings that originate
+          ;; in projects that are required by this project but are not generated by local
+          ;; code.
+          ;; This is a bad solution
+          ;; A better solution is to differentiate in these warnings and have a system
+          ;; that says wether a warning is a blocking warning
           ((if (= cljs-build-fn figwheel-build)
              (-> cljs-build
                  notify-command-hook


Exercise 1.15

Exercise 1.15


Use numerical comparison, so we don't get 100 != 1e2

I noticed that if I used scientific notation for the number of tests, it would run forever.  This is because `(not= 100 1e2)`, but `(== 100 1e2)`, which is extremely non-obvious, but there you go.

--- src/simple_check/core.clj
+++ src/simple_check/core.clj
@@ -43,7 +43,7 @@
         size-seq (gen/make-size-range-seq max-size)]
     (loop [so-far 0
            size-seq size-seq]
-      (if (= so-far num-tests)
+      (if (== so-far num-tests)
         (complete property num-tests created-seed)
         (let [[size & rest-size-seq] size-seq
               result-map (run-test property rng size)


Increase line height of headings

Increase line height of headings

--- src/catalog/layout/fop.clj
+++ src/catalog/layout/fop.clj
@@ -22,9 +22,9 @@
 (def ^:private default-stylesheet
   {:font {:font-family "Verdana" :font-size "11pt"}
    :block {:text-align "start" :hyphenate "false"}
-   :h1 {:font-size "26.05pt" :font-weight "bold" :space-after "26pt" :keep-with-next "always" :break-before "page" :role "H1"}
-   :h2 {:font-size "19.55pt" :font-weight "bold" :space-after "11pt" :space-before "25pt" :keep-with-next "always" :role "H2"}
-   :h3 {:font-size "14.66pt" :font-weight "bold" :space-after "14pt" :space-before "14pt" :keep-with-next "always" :role "H3"}
+   :h1 {:font-size "26.05pt" :font-weight "bold" :space-after "26pt" :keep-with-next "always" :break-before "page" :role "H1" :line-height "110%"}
+   :h2 {:font-size "19.55pt" :font-weight "bold" :space-after "11pt" :space-before "25pt" :keep-with-next "always" :role "H2" :line-height "110%"}
+   :h3 {:font-size "14.66pt" :font-weight "bold" :space-after "14pt" :space-before "14pt" :keep-with-next "always" :role "H3" :line-height "110%"}
    :header {:text-align-last "justify" :font-weight "bold" :border-bottom "thin solid"}})

 ;; 3:4 perfect fourth scale (http://www.modularscale.com/?17&pt&1.333&web&table)


Remove usage of cats.core functions from cats.monad.either ns.

--- src/cats/monad/either.cljc
+++ src/cats/monad/either.cljc
@@ -37,14 +37,13 @@
       (either/left 1)
       ;; => #<Left [1]>
   "
-  (:require [cats.protocols :as proto]
-            [cats.core :as m]))
+  (:require [cats.protocols :as proto]))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Type constructor and functions
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

 (declare either-monad)
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; Type constructor and functions
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

 (deftype Right [v]
   proto/Context
@@ -205,13 +204,13 @@

 (defn branch
   "Given an either value and two functions, if the either is a
-   left apply the first function to the value it contains; if the
-   either is a right apply the second function to its value."
+  left apply the first function to the value it contains; if the
+  either is a right apply the second function to its value."
   [e lf rf]
   {:pre [(either? e)]}
   (if (left? e)
-    (lf (m/extract e))
-    (rf (m/extract e))))
+    (lf (proto/extract e))
+    (rf (proto/extract e))))

 (defn branch-left
   "Given an either value and a function, if the either is a
@@ -229,7 +228,8 @@
   either is a left, return it."
   [e rf]
   {:pre [(either? e)]}
-  (m/bind e rf))
+  (let [context either-monad]
+    (proto/mbind context e rf)))

 (def lefts
   "Given a collection of eithers, return only the values that are left."
@@ -252,5 +252,5 @@
   [e]
   {:pre [(either? e)]}
   (if (left? e)
-    (right (m/extract e))
-    (left (m/extract e))))
+    (right (proto/extract e))
+    (left (proto/extract e))))


silently control nodes from midi poly player

--- src/overtone/studio/midi.clj
+++ src/overtone/studio/midi.clj
@@ -107,7 +107,8 @@
        (on-event off-event-key (fn [{note :note velocity :velocity}]
                                  (let [velocity (float (/ velocity 127 ))]
                                    (when-let [n (get @notes* note)]
-                                     (node-control n [:gate 0 :after-touch velocity])
+                                     (binding [*non-active-node-modification-exceptions* :silent]
+                                       (node-control n [:gate 0 :after-touch velocity]))
                                      (swap! notes* dissoc note))))
                  off-key)


Put middleware in correct order

Put middleware in correct order

--- src/clj/cglossa/server.clj
+++ src/clj/cglossa/server.clj
@@ -65,8 +65,8 @@
   (let [r (routes #'db-routes #'search-routes #'app-routes)
         r (if (:is-dev env) (-> r reload/wrap-reload wrap-exceptions) r)]
     (-> r
+        wrap-keyword-params
         wrap-json-params
-        wrap-keyword-params
         wrap-params)))

 (defn run [& [port]]


Nothing works! Maybe someday it will!

Nothing works! Maybe someday it will!

--- src/clj/corona/scraper.clj
+++ src/clj/corona/scraper.clj
@@ -38,17 +38,25 @@
 (defrecord CljsCode [variables code compiled]
   browser-executable
   (eval-in-browser [this driver env]
-    (let [params (->> env
+    (spy variables)
+    ;;Compiling things all over the place now. HMm.
+    (let [ns-forms (cljs-forms->js '(ns user.func))
+          params (->> env
                       (map (fn [[sym value]] `(def ~sym ~value)))
                       (map cljs-forms->js)
                       (s/join "\n"))
-          script (str params
-                      "var fn = " compiled ";\n"
-                      "return fn.call(" (s/join "," variables)");")]
+          fn-call (cljs-forms->js (concat ['func] variables))
+          script (str ns-forms
+                      "var cljs = {}; cljs.user = {}; "
+                      params
+                      "cljs.user.func = " compiled ";\n"
+                      "return " fn-call ";")]
       (taxi/execute-script driver script))))

-(defn symbols->CljsCode [variables & rst]
-  (let [code (concat ['fn variables] rst)]
+(defn symbols->CljsCode [[variables & rst]]
+  (spy variables)
+  (spy (s/join "," variables))
+  (let [code (concat ['defn 'func variables] rst)]
     (->CljsCode variables code (cljs-forms->js code))))

 (def readers


Implemented Cobra

Implemented Cobra

--- src/clj/game/cards-ice.clj
+++ src/clj/game/cards-ice.clj
@@ -16,7 +16,7 @@
    Mostly used with tag-trace"
   {:label "Give the Runner 1 tag"
    :msg "give the Runner 1 tag"
-   :effect (effect (tag-runner :runner 1))})
+   :effect (effect (tag-runner :runner 1))})

 (def add-power-counter
   "Adds 1 power counter to the card."
@@ -324,6 +324,9 @@

    "Chum"
    {:abilities [(do-net-damage 3)]}
+
+   "Cobra"
+   {:abilities [trash-program (do-net-damage 2)]}

    "Cortex Lock"
    {:abilities [{:label "Do 1 net damage for each unused memory units the Runner has"


Add enumerate util function

Add enumerate util function

--- src/clj/genartlib/util.clj
+++ src/clj/genartlib/util.clj
@@ -30,3 +30,6 @@

   (defn set-color-mode []
     (color-mode :hsb 360 100 100 1.0))
+
+  (defn enumerate [s]
+    (map-indexed vector s))


Add util/distinct-key fn

Add util/distinct-key fn

--- src/clj/genartlib/util.clj
+++ src/clj/genartlib/util.clj
@@ -76,3 +76,12 @@
     (if (>= remainder (* snap-width 0.5))
       (+ v snap-width (* remainder -1.0))
       (- v remainder))))
+
+(defn distinct-key
+  "Given a function f to uniquely identify items, extracts
+   all of the distinct items in a collection."
+  [f coll]
+  (->> coll
+       (group-by f)
+       vals
+       (map first)))


part instr and save/load

part instr and save/load

--- src/temperaments/core.clj
+++ src/temperaments/core.clj
@@ -140,17 +140,17 @@
    gate 1]
   (let [osc-bank-1 [(o/saw freq) (o/sin-osc freq) (o/pulse freq)]
         osc-bank-2 [(o/saw freq) (o/sin-osc freq) (o/pulse freq)]
-        amp-env    (o/env-gen (o/adsr attack decay sustain release) gate :action o/FREE)
+        amp-env    (o/env-gen (o/adsr attack decay sustain release)
+                              gate :action o/FREE)
         f-env      (o/env-gen (o/adsr fattack fdecay fsustain frelease) gate)
         s1         (* osc1-level (o/select osc1 osc-bank-1))
         s2         (* osc2-level (o/select osc2 osc-bank-2))
         filt       (o/moog-ff (+ s1 s2) (* cutoff f-env) 3)]
     (* amp filt)))

+(def instruments ["Flute" "Piano" "Mooger" "CS80" "SSaw" "Ticker" "Ping"])
+
 (def inst-cur flute)
-
-(defn play-test-tone [e]
-  (inst-cur 440))

 (defn kill-tones [e]
   (o/clear))
@@ -166,18 +166,28 @@
         rev (concat '([:a#4 1] [:g#4 1]) (drop 3 (reverse half)))]
     (concat half rev)))

+(defn str->instr [str]
+  (case str
+    "Flute"   flute,
+    "Piano"   piano,
+    "Mooger"  mooger,
+    "CS80"    cs80,
+    "SSaw"    ssaw,
+    "Ticker"  tick,
+    "Ping"    ping,
+    "Default" inst-cur))

 (defn inst-chooser [e]
-  (let [val (value (.getSource e))]
-    (case val
-      "Flute"  (def inst-cur flute)
-      "Piano"  (def inst-cur piano)
-      "Mooger" (def inst-cur mooger)
-      "CS80"   (def inst-cur cs80)
-      "SSaw"   (def inst-cur ssaw)
-      "Ticker" (def inst-cur tick)
-      "Ping"   (def inst-cur ping))))
-
+  (let [val (value (.getSource e))
+        instr (str->instr val)]
+    (def inst-cur instr)))
+
+(defn inst-chooser-part [id e]
+  (let [val (value (.getSource e))
+        oldmap (get @melody-map id)
+        newmap (assoc oldmap :instr val)]
+    (swap! melody-map assoc id newmap)))
+
 (defn tonic-chooser [e]
   (let [val (value (.getSource e))]
     (case val
@@ -257,14 +267,14 @@
       (concat (list newnote) (string-to-midi tail)))
     '()))

-(def melody (atom [(note-to-midi major)]))
+(def melody (atom [(cons "Default" (note-to-midi major))]))

 (defn melody-chooser [e]
   (let [val (value (.getSource e))]
     (case val
-      "Art of Fugue"  (reset! melody [(note-to-midi aof-subject)])
-      "Major Scale"   (reset! melody [(note-to-midi major)])
-      "Minor Scale"   (reset! melody [(note-to-midi minor)])
+      "Art of Fugue"  (reset! melody [(cons "Default" (note-to-midi aof-subject))])
+      "Major Scale"   (reset! melody [(cons "Default" (note-to-midi major))])
+      "Minor Scale"   (reset! melody [(cons "Default" (note-to-midi minor))])
       "Patterns"      (reset! melody false)
       )))

@@ -302,21 +312,6 @@
 (defn new-panel [e]
   (swap! counter inc)
   (make-melody-panel @counter))
-
-
-
-;(config! control-frame :on-close :exit)
-
-;; keyboard for canvas
-;; (defn keyboard [melid kbnum]
-;;   (let [oct1 (map #(s/join [% "3"]) c-scale)
-;;         oct2 (map #(s/join [% "4"]) c-scale)
-;;         notes (concat oct1 oct2)]
-;;     (map #(action :name %
-;;                   :handler (fn [e]
-;;                              (assoc (get (get melody-map melid) :pitches)
-;;                                     kbnum %)))
-;;          notes)))

 (def keyboard
   (let [oct1 (map #(s/join [% "3"]) c-scale)
@@ -431,8 +426,9 @@
                     melodyseq
                     (concat [nil] melodyseq))
         rhythm (multiply-rhythm rhy-pattern rhy-repeats)
-        total-time (apply + rhythm)]
-    [fixmelody rhythm total-time]))
+        total-time (apply + rhythm)
+        instrstr (get-in @melody-map [id :instr])]
+    [fixmelody rhythm total-time instrstr]))

 (defn make-score []
@@ -444,10 +440,13 @@
         partrepeats (map #(/ totaltime %) times)
         score (atom '())]
     (doseq [i (range len)]
-      (let [rhythm (apply concat (repeat (nth partrepeats i) (second (nth parts i))))
-            melodyseq (apply concat (repeat (nth partrepeats i) (first (nth parts i))))
+      (let [thispart (nth parts i)
+            thisinstr (nth thispart 3)
+            thisrepeats (nth partrepeats i)
+            rhythm (apply concat (repeat thisrepeats (second thispart)))
+            melodyseq (apply concat (repeat thisrepeats (first thispart)))
             notes (map str->midi melodyseq)
-            part (map vector notes rhythm)]
+            part (cons thisinstr (map vector notes rhythm))]
         (swap! score conj part)))
     @score))

@@ -456,14 +455,14 @@
 (defn play-melody [e]
   (let [score (or @melody
                   (make-score))]
-    (doseq [part score]
-      (play one-twenty-bpm inst-cur part {:midi true}))))
-
+    (doseq [[instr & part] score]
+      (play one-twenty-bpm (str->instr instr) part {:midi true}))))
+
 (defn play-solo [id e]
-  (let [[mel rhy] (make-part id)
+  (let [[mel rhy _ instr] (make-part id)
         notes (map str->midi mel)
         part (map vector notes rhy)]
-    (play one-twenty-bpm inst-cur part {:midi true})))
+    (play one-twenty-bpm (str->instr instr) part {:midi true})))

 (defn remove-circle [id kw]
   (let [len (get-in @melody-map [id kw])
@@ -533,14 +532,19 @@
         controls (make-panel-controls id)
         playsolo (button :text "Play Solo"
                          :listen [:action #(play-solo id %)])
+        chinstr (combobox :model (cons "Default" instruments)
+                          :text "Instrument:"
+                          :id (keyword (s/join ["kb-" (str id) "-instr"]))
+                          :listen [:action #(inst-chooser-part id %)])
         f (frame :title (s/join ["Tune " (str id)])
                  :id (s/join ["frame-" (str id)])
                  :listen [:window-closing
                           (fn [e]
                             (swap! melody-map dissoc id))])
-        verticalpanel (vertical-panel :items [pan playsolo controls])
+        verticalpanel (vertical-panel :items [pan chinstr playsolo controls])
         numcbs 1]
-    (swap! melody-map assoc id {:pitches numcbs, :beats numcbs, :root f})
+    (swap! melody-map assoc id {:pitches numcbs, :beats numcbs,
+                                :root f, :instr "Default"})
     (add-note-circles id pan)
     (config! f :content verticalpanel)
     (-> f pack! show!)
@@ -556,7 +560,7 @@
         mellist (map #(keyword (s/join [melprefix (str %)])) (range mellen))
         rhylist (map #(keyword (s/join [rhyprefix (str %)])) (range rhylen))
         idlist (vec (concat mellist rhylist))
-        circhash (atom {})]
+        circhash (atom '())]
     (doseq [k idlist]
       (let [w (select panel [k])]
         (swap! circhash assoc k (value w))))
@@ -581,9 +585,11 @@
         newpanhash (assoc panhash :root newroot)
         numpitbut (select newroot [(keyword (s/join ["#kb-" (str id) "-numpitch"]))])
         numbeabut (select newroot [(keyword (s/join ["#kb-" (str id) "-numbeats"]))])
+        instrubut (select newroot [(keyword (s/join ["#kb-" (str id) "-instr"]))])
         ]
     (value! numpitbut (get panhash :pitches))
     (value! numbeabut (get panhash :beats))
+    (value! instrubut (get panhash :instr))
     (restore-circles id oldid panel circhash)
     (swap! melody-map assoc id newpanhash)))

@@ -637,8 +643,7 @@
                            (label :text ""
                                   :size [100 :by 30])
                            (label "Instrument:")
-                           (combobox :model ["Flute" "Piano" "Mooger" "CS80"
-                                             "SSaw" "Ticker" "Ping"]
+                           (combobox :model instruments
                                      :id :instChooser
                                      :listen [:action inst-chooser])
                            (label "Tonic:")
@@ -651,7 +656,8 @@
                                      :id :tuningChooser
                                      :listen [:action tuning-chooser])
                            (label "Melody:")
-                           (combobox :model ["Major Scale" "Minor Scale" "Art of Fugue" "Patterns"]
+                           (combobox :model ["Major Scale" "Minor Scale"
+                                             "Art of Fugue" "Patterns"]
                                      :id :melodyChooser
                                      :listen [:action melody-chooser])
                            ])))


Handle Facebook's appending junk to URL

Handle Facebook's appending junk to URL

--- src/cljs/db_quiz/core.cljs
+++ src/cljs/db_quiz/core.cljs
@@ -30,6 +30,10 @@
 (defroute "/play" []
   (session/put! :current-page components/play-page))

+; Handle Facebook's appending junk to URL.
+(defroute "/_=_" []
+  (session/put! :current-page components/home-page))
+
 (defroute "*" []
   (session/put! :current-page components/not-found))


Generating mode buttons from map

Generating mode buttons from map

--- src/cljs/guitar1/neck.cljs
+++ src/cljs/guitar1/neck.cljs
@@ -76,14 +76,14 @@
   [key scale]
   [:div.neck
    [:button {:on-click #(set-scale pentatonic-minor)} "Pentatonic Minor"]
-   [:button {:on-click #(set-scale lydian)} "Lydian"]
-   [:button {:on-click #(set-scale mixolydian)} "Mixolydian"]
-   [:button {:on-click #(set-scale aeolian)} "Aeolian"]
-   [:button {:on-click #(set-scale locrian)} "Locrian"]
-   [:button {:on-click #(set-scale ionian)} "Ionian"]
-   [:button {:on-click #(set-scale dorian)} "Dorian"]
-   [:button {:on-click #(set-scale phrygian)} "Phrygian"]
-   ;;(map (fn [mode] [:button {:on-click #(set-scale (mode modes))} (name mode)]) (keys modes))
+   ;; [:button {:on-click #(set-scale lydian)} "Lydian"]
+   ;; [:button {:on-click #(set-scale mixolydian)} "Mixolydian"]
+   ;; [:button {:on-click #(set-scale aeolian)} "Aeolian"]
+   ;; [:button {:on-click #(set-scale locrian)} "Locrian"]
+   ;; [:button {:on-click #(set-scale ionian)} "Ionian"]
+   ;; [:button {:on-click #(set-scale dorian)} "Dorian"]
+   ;; [:button {:on-click #(set-scale phrygian)} "Phrygian"]
+   (map (fn [mode] [:button {:on-click #(set-scale (mode modes))} (name mode)]) (keys modes))
    (conj (map build-string (reverse strings))
          [:ul.string.frets (map #(vector :li %) (into [] (range 24)))])])


Realized we didn't nee custom cookie functions while working on #24

We already have reagent-utils as a dependency, so might as well make
use of it.

--- src/cljs/memento/core.cljs
+++ src/cljs/memento/core.cljs
@@ -1,6 +1,7 @@
 (ns memento.core
   (:require [ajax.core :refer [GET POST PUT]]
             [clojure.string :refer [trim split]]
+            [reagent.cookies :as cookies]
             [reagent.core :as reagent :refer [atom]]
             [re-frame.core :refer [dispatch register-sub register-handler subscribe dispatch-sync]]
             [goog.events :as events]
@@ -12,26 +13,6 @@

-;;;;
-;;;; Helpers
-;;;;
-
-(defn set-cookie [k v]
-  (aset js/document "cookie" (str (name k) "=" v)))
-
-(defn get-cookie [k]
-  (let [cookie (aget js/document "cookie")
-        as-map (->> (split cookie #";")
-                    (map trim)
-                    (map #(split % #"="))
-                    (map #(if (= 1 (count %))
-                           [(first %) nil]
-                           %))
-                    (into {})
-                    (clojure.walk/keywordize-keys))]
-    (k as-map)))
-
-
 ;;;;------------------------------
 ;;;; Queries
 ;;;;------------------------------
@@ -61,7 +42,7 @@
 (register-handler
   :initialize
   (fn [app-state _]
-    (dispatch [:set-token (get-cookie :token)])
+    (dispatch [:set-token (cookies/get :token nil)])
     (merge app-state {:ui-state {:is-busy?      false
                                  :section       :login
                                  :current-query ""
@@ -92,7 +73,7 @@
   (fn [app-state [_ token]]
     (if (not-empty token)
       (dispatch [:set-message ""]))
-    (set-cookie :token token)
+    (cookies/set! :token token)
     (-> app-state
         (assoc-in [:credentials :token] token)
         (assoc-in [:ui-state :section] (if (empty? token) :login :write))


tablify

tablify

--- src/cljs/worktv/views.cljs
+++ src/cljs/worktv/views.cljs
@@ -99,5 +99,12 @@
 (defn tablify [data]
   (cond
     (map? data) (let [[_ v] (first data)
-                      [headers fns] (if (map? v) (keys v) "$value")]
-                  (for [[k v] data] (cons k v)))))
+                      [headers valfns] (if-let [ks (and (map? v) (keys v))]
+                                         [(cons "$key" (map name ks)) (cons first ks)]
+                                         [["$key" "$value"] [first second]])]
+                  (cons headers (map (juxt valfns) data)))
+    (coll? data) (let [x (first data)
+                       [headers valfns] (if-let [ks (and (map? v) (keys v))]
+                                          [(map name ks) ks]
+                                          [["$value"] [identity]])]
+                   (cons headers (map (juxt valfns) data)))))


Adding faction-won? game function

Adding faction-won? game function

--- src/cljs/zetawar/game.cljs
+++ src/cljs/zetawar/game.cljs
@@ -143,6 +143,10 @@
            db (e faction))
       ffirst
       (or 0)))
+
+(defn faction-won? [db faction]
+  (and (= 0 enemy-base-count db faction)
+       (= 0 enemy-unit-count db faction)))

 (defn income [db game faction]
   (let [base-count (faction-base-count db faction)


Fix misplaced docstring

Fix misplaced docstring

--- src/clojure/flambo/api.clj
+++ src/clojure/flambo/api.clj
@@ -144,8 +144,9 @@
   ([rdd]
    (.name rdd)))

-(defn partitionwise-sampled-rdd [rdd sampler preserve-partitioning? seed]
+(defn partitionwise-sampled-rdd
   "Creates a PartitionwiseSampledRRD from existing RDD and a sampler object"
+  [rdd sampler preserve-partitioning? seed]
   (-> (PartitionwiseSampledRDD.
        (.rdd rdd)
        sampler