-- additional logs and minor refactoring in autoscaler (#140)

--- waiter/src/waiter/scaling.clj
+++ waiter/src/waiter/scaling.clj
@@ -22,8 +22,8 @@
             [waiter.metrics :as metrics]
             [waiter.scheduler :as scheduler]
             [waiter.service :as service]
-            [waiter.utils :as utils]
-            [slingshot.slingshot :refer [try+]]))
+            [waiter.utils :as utils])
+  (:import (org.joda.time DateTime)))

 (defn get-app-instance-stats
   "Queries scheduler to find the number of instances and running tasks for all apps"
@@ -352,44 +352,50 @@
                                :service-id->scheduler-state service-id->scheduler-state
                                :service-id->scale-state service-id->scale-state
                                :scale-ticks scale-ticks})
-    (zipmap service-ids
-            (map (fn [service-id]
-                   (let [outstanding-requests (or (service-id->outstanding-requests service-id) 0)
-                         {:keys [healthy-instances expired-instances]} (service-id->router-state service-id)
-                         {:keys [instances task-count] :as scheduler-state} (service-id->scheduler-state service-id)
-                         ; if we don't have a target instance count, default to the number of tasks
-                         target-instances (get-in service-id->scale-state [service-id :target-instances] task-count)
-                         {:keys [target-instances scale-to-instances scale-amount]}
-                         (if (and target-instances scale-ticks)
-                           (scale-app-fn (assoc (get service-id->service-description service-id)
-                                           "scale-ticks" scale-ticks)
-                                         {:healthy-instances healthy-instances
-                                          :expired-instances expired-instances
-                                          :outstanding-requests outstanding-requests
-                                          :target-instances target-instances
-                                          :total-instances instances})
-                           (do
-                             (log/info "no target instances available for service"
-                                       {:scheduler-state scheduler-state, :service-id service-id})
-                             {:scale-to-instances instances :target-instances target-instances :scale-amount 0}))]
-                     (when-not (zero? scale-amount)
-                       (apply-scaling-fn service-id
-                                         {:outstanding-requests outstanding-requests
-                                          :task-count task-count
-                                          :total-instances instances
-                                          :scale-amount scale-amount
-                                          :scale-to-instances scale-to-instances}))
-                     {:target-instances target-instances
-                      :scale-to-instances scale-to-instances
-                      :scale-amount scale-amount}))
-                 service-ids))
+    (pc/map-from-keys
+      (fn [service-id]
+        (let [outstanding-requests (or (service-id->outstanding-requests service-id) 0)
+              {:keys [healthy-instances expired-instances]} (service-id->router-state service-id)
+              {:keys [instances task-count] :as scheduler-state} (service-id->scheduler-state service-id)
+              ; if we don't have a target instance count, default to the number of tasks
+              target-instances (get-in service-id->scale-state [service-id :target-instances] task-count)
+              {:keys [target-instances scale-to-instances scale-amount]}
+              (if (and target-instances scale-ticks)
+                (scale-app-fn (assoc (get service-id->service-description service-id)
+                                "scale-ticks" scale-ticks)
+                              {:healthy-instances healthy-instances
+                               :expired-instances expired-instances
+                               :outstanding-requests outstanding-requests
+                               :target-instances target-instances
+                               :total-instances instances})
+                (do
+                  (log/info "no target instances available for service"
+                            {:scheduler-state scheduler-state, :service-id service-id})
+                  {:scale-to-instances instances :target-instances target-instances :scale-amount 0}))]
+          (when-not (zero? scale-amount)
+            (apply-scaling-fn service-id
+                              {:outstanding-requests outstanding-requests
+                               :task-count task-count
+                               :total-instances instances
+                               :scale-amount scale-amount
+                               :scale-to-instances scale-to-instances}))
+          {:target-instances target-instances
+           :scale-to-instances scale-to-instances
+           :scale-amount scale-amount}))
+      service-ids)
     (catch Exception e
       (log/error e "exception in scale-apps")
       service-id->scale-state)))

+(defn- difference-in-millis
+  "Helper method to compute time difference in millis.
+   Added type hints to avoid warn-on-relfection warnings."
+  [^DateTime end-time ^DateTime start-time]
+  (- (.getMillis end-time) (.getMillis start-time)))
+
 (defn autoscaler-goroutine
   "Autoscaler encapsulated in goroutine.
-  Acquires state of services and passes to scale-apps."
+   Acquires state of services and passes to scale-apps."
   [initial-state leader?-fn service-id->metrics-fn executor-multiplexer-chan scheduler timeout-interval-ms scale-app-fn
    service-id->service-description-fn state-mult]
   (let [exit-chan (async/chan)
@@ -453,21 +459,29 @@
                                     (if (seq service-id->router-state)
                                       (cid/with-correlation-id
                                         correlation-id
-                                        (let [scalable-service-ids (set/intersection (set (keys service-id->router-state))
-                                                                                (set (keys service-id->scheduler-state')))]
+                                        (let [router-service-ids (set (keys service-id->router-state))
+                                              scheduler-service-ids (set (keys service-id->scheduler-state'))
+                                              scalable-service-ids (set/intersection router-service-ids scheduler-service-ids)
+                                              excluded-service-ids (-> (set/union router-service-ids scheduler-service-ids)
+                                                                       (set/difference scalable-service-ids))
+                                              scale-ticks (when previous-cycle-start-time
+                                                            (-> (difference-in-millis cycle-start-time previous-cycle-start-time)
+                                                                (/ 1000)
+                                                                int))]
+                                          (when (seq excluded-service-ids)
+                                            (cid/cinfo correlation-id "services excluded this iteration" excluded-service-ids))
                                           (scale-apps scalable-service-ids
                                                       (pc/map-from-keys #(service-id->service-description-fn %) scalable-service-ids)
                                                       ; default to 0 outstanding requests for services without metrics
                                                       (pc/map-from-keys #(get-in global-state' [% "outstanding"] 0) scalable-service-ids)
                                                       service-id->scale-state
                                                       apply-scaling-fn
-                                                      (when previous-cycle-start-time
-                                                        (int (/ (- (.getMillis cycle-start-time) (.getMillis previous-cycle-start-time)) 1000)))
+                                                      scale-ticks
                                                       scale-app-fn
                                                       service-id->router-state
                                                       service-id->scheduler-state')))
                                       service-id->scale-state)]
-                                (cid/cinfo correlation-id "scaling iteration took" (- (.getMillis (t/now)) (.getMillis cycle-start-time))
+                                (cid/cinfo correlation-id "scaling iteration took" (difference-in-millis (t/now) cycle-start-time)
                                            "ms for" (count service->scale-state') "services.")
                                 (assoc current-state
                                   :global-state global-state'


Only call callbacks from lanes if they are actually passed down

--- src/kanban/components/lane.cljs
+++ src/kanban/components/lane.cljs
@@ -18,17 +18,20 @@
             (om/get-computed this)]
       (dom/div #js {:className "lane"
                     :onDragOver (fn [e] (.preventDefault e))
-                    :onDrop #((:drop card-drag-fns) (om/get-ident this))}
+                    :onDrop #(some-> card-drag-fns
+                                     :drop
+                                     (apply [(om/get-ident this)]))}
         (dom/h3 #js {:className "lane-title"}
-          name
-          (dom/span #js {:className "count"}
-            (count cards)))
+          (dom/span #js {:className "text"} name)
+          (dom/span #js {:className "count"} (count cards)))
         (dom/div #js {:className "add"}
-          (dom/a #js {:onClick #(card-create-fn (om/get-ident this))} "+"))
+          (dom/a #js {:onClick #(some-> card-create-fn
+                                        (apply [(om/get-ident this)]))} "+"))
         (dom/div #js {:className "cards"}
           (let [ref      (om/get-ident this)
-                drag-fns (into {} (map (fn [[k f]] [k (partial f ref)])
-                                       card-drag-fns))]
+                drag-fns (some->> card-drag-fns
+                                  (map (fn [[k f]] [k (partial f ref)]))
+                                  (into {}))]
             (for [c cards]
               (card (om/computed c {:drag-fns drag-fns
                                     :activate-fn card-edit-fn})))))))))


Fully qualify core/str in case and time macros.

--- src/main/clojure/cljs/core.cljc
+++ src/main/clojure/cljs/core.cljc
@@ -2036,7 +2036,7 @@
                        (last clauses)
                        `(throw
                           (js/Error.
-                            (core/str "No matching clause: " ~e))))
+                            (cljs.core/str "No matching clause: " ~e))))
              env     &env
              pairs   (reduce
                        (core/fn [m [test expr]]
@@ -2443,7 +2443,7 @@
   [expr]
   `(let [start# (.getTime (js/Date.))
          ret# ~expr]
-     (prn (core/str "Elapsed time: " (- (.getTime (js/Date.)) start#) " msecs"))
+     (prn (cljs.core/str "Elapsed time: " (- (.getTime (js/Date.)) start#) " msecs"))
      ret#))

 (core/defmacro simple-benchmark


update cljs.repl stacktrace mapping code comments

--- src/main/clojure/cljs/repl.cljc
+++ src/main/clojure/cljs/repl.cljc
@@ -228,16 +228,16 @@
                (some-> (js-src->cljs-src f) ana/parse-ns :ns))]
       (when ns
         (as-> @env/*compiler* compiler-env
-         (let [t (util/last-modified smf)]
-           (if (or (and (= ns 'cljs.core)
-                        (nil? (get-in compiler-env [::source-maps ns])))
-                 (and (not= ns 'cljs.core)
-                      (> t (get-in compiler-env [::source-maps ns :last-modified] 0))))
-             (swap! env/*compiler* assoc-in [::source-maps ns]
-               {:last-modified t
-                :source-map (sm/decode (json/read-str (slurp smf) :key-fn keyword))})
-             compiler-env))
-         (get-in compiler-env [::source-maps ns :source-map]))))))
+          (let [t (util/last-modified smf)]
+            (if (or (and (= ns 'cljs.core)
+                         (nil? (get-in compiler-env [::source-maps ns])))
+                    (and (not= ns 'cljs.core)
+                         (> t (get-in compiler-env [::source-maps ns :last-modified] 0))))
+              (swap! env/*compiler* assoc-in [::source-maps ns]
+                {:last-modified t
+                 :source-map (sm/decode (json/read-str (slurp smf) :key-fn keyword))})
+              compiler-env))
+          (get-in compiler-env [::source-maps ns :source-map]))))))

 (defn ns-info
   "Given a path to a js source file return the ns info for the corresponding
@@ -351,25 +351,30 @@
            "(" file (when line (str ":" line)) (when column (str ":" column)) ")"))))))

 (comment
+  (def st (env/default-compiler-env))
+
   (cljsc/build "samples/hello/src"
     {:optimizations :none
      :output-dir "samples/hello/out"
      :output-to "samples/hello/out/hello.js"
-     :source-map true})
-
-  (mapped-stacktrace
-    [{:file "hello/core.js"
-      :function "first"
-      :line 2
-      :column 1}]
-    {:output-dir "samples/hello/out"})
-
-  (print-mapped-stacktrace
-    [{:file "hello/core.js"
-      :function "first"
-      :line 2
-      :column 1}]
-    {:output-dir "samples/hello/out"})
+     :source-map true}
+    st)
+
+  (env/with-compiler-env st
+    (mapped-stacktrace
+      [{:file "hello/core.js"
+        :function "first"
+        :line 6
+        :column 0}]
+      {:output-dir "samples/hello/out"}))
+
+  (env/with-compiler-env st
+    (print-mapped-stacktrace
+      [{:file "hello/core.js"
+        :function "first"
+        :line 6
+        :column 0}]
+      {:output-dir "samples/hello/out"}))

   ;; URL example

@@ -377,21 +382,24 @@
     {:optimizations :none
      :output-dir "out"
      :output-to "out/hello.js"
-     :source-map true})
-
-  (mapped-stacktrace
-    [{:file "cljs/core.js"
-      :function "first"
-      :line 2
-      :column 1}]
-    {:output-dir "out"})
-
-  (print-mapped-stacktrace
-    [{:file "cljs/core.js"
-      :function "first"
-      :line 2
-      :column 1}]
-    {:output-dir "out"})
+     :source-map true}
+    st)
+
+  (env/with-compiler-env st
+    (mapped-stacktrace
+      [{:file "cljs/core.js"
+        :function "first"
+        :line 2
+        :column 1}]
+      {:output-dir "out"}))
+
+  (env/with-compiler-env st
+    (print-mapped-stacktrace
+      [{:file "cljs/core.js"
+        :function "first"
+        :line 2
+        :column 1}]
+      {:output-dir "out"}))
   )

 (defn- display-error


Added tests for searching with non existant granule ids.

--- test/cmr/system_int_test/search/granule_search_test.clj
+++ test/cmr/system_int_test/search/granule_search_test.clj
@@ -311,7 +311,7 @@
                (search/find-refs :granule srch2)))))))

 ;; Find granules by echo_granule_id, echo_collection_id and concept_id params
-(deftest granule-concept-id-search-test
+(deftest search-by-concept-id
   (let [coll1 (d/ingest "CMR_PROV1" (dc/collection))
         coll2 (d/ingest "CMR_PROV2" (dc/collection))
         gran1 (d/ingest "CMR_PROV1" (dg/granule coll1))
@@ -395,6 +395,8 @@
            [gran5] gran5-cid {}
            ;; Multiple values
            [gran1 gran2 gran3 gran4 gran5] [gran1-cid gran2-cid gran3-cid gran4-cid gran5-cid] {}
+           ;; an non existant granule along with existing granules
+           [gran1 gran5] [gran1-cid "G555-CMR_PROV1" "G555-NON_EXIST" gran5-cid] {}
            [] [gran1-cid gran5-cid] {:and true}))
     (testing "Search with wildcards in concept_id param not supported."
       (is (= {:status 422


Omify docs-title

Omify docs-title

--- frontend/components/documentation.cljs
+++ frontend/components/documentation.cljs
@@ -75,6 +75,13 @@
    [:div
     (om/build-all docs-category categories)]))

+(defrender docs-title [doc]
+  (html
+   [:div
+    [:h1 (:title doc)]
+    (when-let [last-updated (:lastUpdated doc)]
+      [:p.meta [:strong "Last Updated "] last-updated])]))
+
 (defrender front-page [app owner]
   (let [query-results (get-in app state/docs-articles-results-path)
         query (get-in app state/docs-articles-results-query-path)
@@ -131,7 +138,7 @@
     (render [_]
       (html
        [:div
-        (doc-utils/render-haml-template "docs_title" {:article doc})
+        (om/build docs-title doc)
         (if-not (empty? (:children doc))
           (om/build article-list (:children doc))
           (doc-utils/render-haml-template (:slug doc) (assoc doc :article doc)))]))))


th styling improved

th styling improved

--- src/notehub/css.clj
+++ src/notehub/css.clj
@@ -235,6 +235,7 @@
                }]
       [:th {
             :padding (em 0.3)
+            :line-height (em 2.5)
             :background-color background-halftone
             }]
       [:td {


add some basic inference tests

add some basic inference tests

--- test/clj/cljs/analyzer_tests.clj
+++ test/clj/cljs/analyzer_tests.clj
@@ -1,5 +1,7 @@
 (ns cljs.analyzer-tests
-  (:require [cljs.analyzer :as a])
+  (:require [clojure.java.io :as io]
+            [cljs.analyzer :as a]
+            [cljs.env :as e])
   (:use clojure.test))

 ;;******************************************************************************
@@ -31,3 +33,60 @@

 (deftest all-warn
   (is (every? #(= 1 %) (map (fn [[name form]] (a/all-warn (warn-count form))) warning-forms))))
+
+;; =============================================================================
+;; Inference tests
+
+(def test-cenv (atom {}))
+(def test-env (assoc-in (a/empty-env) [:ns :name] 'cljs.core))
+
+(e/with-compiler-env test-cenv
+  (a/analyze-file (io/file "src/cljs/cljs/core.cljs")))
+
+(deftest basic-inference
+  (is (= (e/with-compiler-env test-cenv
+           (:tag (a/analyze test-env '1)))
+         'number))
+  (is (= (e/with-compiler-env test-cenv
+           (:tag (a/analyze test-env '"foo")))
+         'string))
+  (is (= (e/with-compiler-env test-cenv
+           (:tag (a/analyze test-env '(make-array 10))))
+         'array))
+  (is (= (e/with-compiler-env test-cenv
+           (:tag (a/analyze test-env '(js-obj))))
+         'object))
+  (is (= (e/with-compiler-env test-cenv
+           (:tag (a/analyze test-env '[])))
+         'cljs.core/IVector))
+  (is (= (e/with-compiler-env test-cenv
+           (:tag (a/analyze test-env '{})))
+         'cljs.core/IMap))
+  (is (= (e/with-compiler-env test-cenv
+           (:tag (a/analyze test-env '#{})))
+         'cljs.core/ISet))
+  (is (= (e/with-compiler-env test-cenv
+           (:tag (a/analyze test-env ())))
+         'cljs.core/IList))
+  (is (= (e/with-compiler-env test-cenv
+           (:tag (a/analyze test-env '(fn [x] x))))
+         'function)))
+
+(deftest if-inference
+  (is (= (e/with-compiler-env test-cenv
+           (:tag (a/analyze test-env '(if true "foo" 1))))
+         '#{number string})))
+
+(deftest lib-inference
+  (is (= (e/with-compiler-env test-cenv
+           (:tag (a/analyze test-env '(-conj [] 1))))
+         'clj))
+  (is (= (e/with-compiler-env test-cenv
+           (:tag (a/analyze test-env '(conj [] 1))))
+         'clj))
+  (is (= (e/with-compiler-env test-cenv
+           (:tag (a/analyze test-env '(assoc nil :foo :bar))))
+         'clj))
+  (is (= (e/with-compiler-env test-cenv
+           (:tag (a/analyze test-env '(dissoc {:foo :bar} :foo))))
+         'clj)))


Fixing broken test

Fixing broken test

--- test/cljs/zetawar/game_test.cljs
+++ test/cljs/zetawar/game_test.cljs
@@ -396,10 +396,10 @@
         damaged-db (-> db
                        (d/db-with (game/teleport-tx db game 2 2 1 2))
                        (d/db-with [[:db/add (e unit) :unit/count 9]]))
-        damaged-unit (game/unit-at damaged-db game 2 2)]
+        damaged-unit (game/unit-at damaged-db game 1 2)]
     (testing "repairing damaged unit"
       (let [repaired-db (d/db-with damaged-db (game/repair-tx damaged-db game damaged-unit))
-            repaired-unit (game/unit-at repaired-db game 2 2)]
+            repaired-unit (game/unit-at repaired-db game 1 2)]
         (is (= (:unit/count repaired-unit) 10))))))

 ;; TODO: test repair!


Improve the error messages for regex group counts

--- test/comic_reader/sites_test.clj
+++ test/comic_reader/sites_test.clj
@@ -76,10 +76,14 @@

 (defn test-regexes []
   (and
-   (is (= 1 (num-groups (manga-pattern))))
-   (is (= 1 (num-groups (chapter-number-match-pattern))))
-   (is (= 0 (num-groups (page-normalize-pattern))))
-   (is (= 0 (num-groups (chapter-number-pattern))))))
+   (is (= 1 (num-groups (manga-pattern)))
+       "There should be exactly 1 matching group in the `manga-pattern' regex.")
+   (is (= 1 (num-groups (chapter-number-match-pattern)))
+       "There should be exactly 1 matching group in the `chapter-number-match-pattern' regex.")
+   (is (= 0 (num-groups (page-normalize-pattern)))
+       "There should not be any matching groups in the `page-normalize-pattern' regex.")
+   (is (= 0 (num-groups (chapter-number-pattern)))
+       "There should not be any matching groups in the `page-normalize-pattern' regex.")))

 (defn valid-selector? [selector]
   (and


support request options: ignore, before and after

--- src/rester/core.clj
+++ src/rester/core.clj
@@ -38,6 +38,7 @@
                           "hour" Calendar/HOUR "hours" Calendar/HOUR
                           "min" Calendar/MINUTE "mins" Calendar/MINUTE
                           "sec" Calendar/SECOND "secs" Calendar/SECOND})
+(def socket-timeout (Integer/parseInt (or (System/getenv "SOCK_TIMEOUT") "60000")))

 (defn- eval-date-exp [cal [num name]]
   (.add cal (date-fields name Calendar/DATE) num))
@@ -145,7 +146,8 @@
          (log/error e "failed coercing payload" payload)
          payload)))

-(def conn-mgr (delay (make-reusable-conn-manager {:insecure? true})))
+(def conn-mgr (delay (make-reusable-conn-manager
+                      {:insecure? true})))

 (defn mk-request [{:keys[test url verb headers params payload] :as  req}]
   (log/info "executing" test ": " verb " " url)
@@ -158,7 +160,8 @@
                          :body (if (string? payload) payload
                                    (and (seq payload) (json/generate-string payload)))
                          :insecure? true
-                         :connection-manager @conn-mgr})
+                         :connection-manager @conn-mgr
+                         :socket-timeout socket-timeout})
         (catch ExceptionInfo e
           (.getData e)))
       (#(update % :body coerce-payload (get-in % [:headers "Content-Type"])))))


hl result

hl result

--- src/secon3/core.clj
+++ src/secon3/core.clj
@@ -48,6 +48,7 @@
                                     [:span (hl k) " " (hl v)]
                                     ) x))
               (gray "}")]
+    (seq? x) [:span (gray "(") (interpose " " (map hl x)) (gray ")")]
     :else (pr-str x)))

 (defn myeval [s]
@@ -55,7 +56,8 @@
     (let [res (with-out-str
                 (-> (read-string s)
                     (eval)
-                    (pr-str)
+                    (hl)
+                    (hc/html)
                     (println)))]
       [:div.message [:pre (hl (read-string s))] [:pre res]])
     (catch Exception e


remove extra slash

remove extra slash

--- src/shuppet/git.clj
+++ src/shuppet/git.clj
@@ -103,7 +103,7 @@

 (defn- repo-path
   ([repo-name branch-name]
-     (str base-git-path "/" repo-name "/" branch-name))
+     (str base-git-path repo-name "/" branch-name))
   ([repo-name]
      (repo-path repo-name "master")))


scheduler to work

scheduler to work

--- src/shuppet/web.clj
+++ src/shuppet/web.clj
@@ -21,9 +21,8 @@
                                      replace-guid replace-mongoid replace-number]]
    [nokia.ring-utils.ignore-trailing-slash :refer [wrap-ignore-trailing-slash]]
    [metrics.ring.expose :refer [expose-metrics-as-json]]
-   [metrics.ring.instrument :refer [instrument]]))
-
-(use 'overtone.at-at)
+   [metrics.ring.instrument :refer [instrument]]
+   [overtone.at-at :as at-at]))

 (def ^:dynamic *version* "none")
 (def ^:private cf-info-room (env :service-campfire-default-info-room))
@@ -32,7 +31,7 @@
 (def ^:private can-post? (not (Boolean/valueOf (env :service-production))))
 (def ^:private default-interval (Integer/parseInt (env :service-default-update-interval)))

-(def shuppet-pool (mk-pool))
+(def shuppet-pool (at-at/mk-pool))

 (defn set-version!
   [version]
@@ -114,12 +113,12 @@

 (defn- schedule
   [env action interval]
-  (stop-and-reset-pool! shuppet-pool :strategy :kill)
+  (at-at/stop-and-reset-pool! shuppet-pool :strategy :kill)
   (if (= action "stop")
     (response {:message "Succefully stopped the shuppet scheduler"})
     (do
       (let [interval (if interval (Integer/parseInt interval) default-interval)]
-        (future (every (* interval 60 1000) (apps-apply env) shuppet-pool))
+         (at-at/every (* interval 60 1000) #(apps-apply env) shuppet-pool)
         (response {:message (str "Succesfully started the shuppet scheduler. The scheduler will run in every " interval " minutes.") })))))

 (def ^:private resources


removed extraneous slash in path

removed extraneous slash in path

--- test/corpus_utils/bccwj_test.clj
+++ test/corpus_utils/bccwj_test.clj
@@ -11,8 +11,8 @@
 (alter-var-root #'s/*explain-out* (constantly (expound/custom-printer {:show-valid-values? true :print-specs? false :theme :figwheel-theme})))

 (def options
-  {:metadata-dir "/home/bor/Projects/bccwj/DOC/"
-   :corpus-dir   "/home/bor/Projects/bccwj/C-XML/VARIABLE/"})
+  {:metadata-dir "/home/bor/Projects/bccwj/DOC"
+   :corpus-dir   "/home/bor/Projects/bccwj/C-XML/VARIABLE"})

 (deftest parse-metadata-test
   (let [m (vals (parse-metadata (:metadata-dir options)))]


Converted original tile_dict Python dictionary to Clojure map country-tiles, to be sure there're no typos


fix Cerebral Cast message

fix Cerebral Cast message

--- src/clj/game/cards-operations.clj
+++ src/clj/game/cards-operations.clj
@@ -103,7 +103,7 @@

    "Cerebral Cast"
    {:psi {:not-equal {:player :runner :prompt "Take 1 tag or 1 brain damage?"
-                      :choices ["1 tag" "1 brain damage"] :msg (msg "The Runner takes " target)
+                      :choices ["1 tag" "1 brain damage"] :msg (msg "give the Runner " target)
                       :effect (req (if (= target "1 tag")
                                      (tag-runner state side 1)
                                      (damage state side :brain 1 {:card card})))}}}


implement Sunset

implement Sunset

--- src/clj/game/cards-operations.clj
+++ src/clj/game/cards-operations.clj
@@ -359,6 +359,29 @@

    "Successful Demonstration"
    {:req (req (:unsuccessful-run runner-reg)) :effect (effect (gain :credit 7))}
+
+   "Sunset"
+   (let [ice-index (fn [state i] (first (keep-indexed #(when (= (:cid %2) (:cid i)) %1)
+                                                      (get-in @state (cons :corp (:zone i))))))
+         sunhelp (fn sun [serv] {:prompt "Select two pieces of ICE to swap positions"
+                                 :choices {:req #(and (= serv (rest (butlast (:zone %))))
+                                                      (= (:type %) "ICE")) :max 2}
+                                 :effect (req (if (= (count targets) 2)
+                                                (let [fndx (ice-index state (first targets))
+                                                      sndx (ice-index state (second targets))
+                                                      fnew (assoc (first targets) :zone (:zone (second targets)))
+                                                      snew (assoc (second targets) :zone (:zone (first targets)))]
+                                                  (swap! state update-in (cons :corp (:zone (first targets)))
+                                                         #(assoc % fndx snew))
+                                                  (swap! state update-in (cons :corp (:zone (second targets)))
+                                                         #(assoc % sndx fnew))
+                                                  (update-ice-strength state side fnew)
+                                                  (update-ice-strength state side snew)
+                                                  (resolve-ability state side (sun serv) card nil))
+                                                (system-msg state side "has finished rearranging ICE")))})]
+     {:prompt "Choose a server" :choices (req servers) :msg (msg "rearrange ICE protecting " target)
+      :effect (req (let [serv (next (server->zone state target))]
+                     (resolve-ability state side (sunhelp serv) card nil)))})

    "Sweeps Week"
    {:effect (effect (gain :credit (count (:hand runner))))}


tests for Closed Accounts, Neural EMP, Successful Demonstration

--- src/clj/test/cards-operations.clj
+++ src/clj/test/cards-operations.clj
@@ -30,12 +30,16 @@
     (is (= 1 (:click (get-corp))))
     (is (= 7 (count (:hand (get-corp)))) "Drew 2 cards")))

-(deftest hedge-fund
-  (do-game
-    (new-game (default-corp) (default-runner))
-    (is (= 5 (:credit (get-corp))))
-    (core/play state :corp {:card (first (:hand (get-corp)))})
-    (is (= 9 (:credit (get-corp))))))
+(deftest closed-accounts
+  "Closed Accounts - Play if Runner is tagged to make Runner lose all credits"
+  (do-game
+    (new-game (default-corp [(qty "Closed Accounts" 1)])
+              (default-runner))
+    (play-from-hand state :corp "Closed Accounts")
+    (is (and (= 3 (:click (get-corp))) (= 5 (:credit (get-runner)))) "Closed Accounts precondition not met; card not played")
+    (core/gain state :runner :tag 1)
+    (play-from-hand state :corp "Closed Accounts")
+    (is (= 0 (:credit (get-runner))) "Runner lost all credits")))

 (deftest diversified-portfolio
   (do-game
@@ -49,6 +53,13 @@
     (play-from-hand state :corp "PAD Campaign" "New remote")
     (play-from-hand state :corp "Diversified Portfolio")
     (is (= 7 (:credit (get-corp))) "Ignored remote with ICE but no server contents")))
+
+(deftest hedge-fund
+  (do-game
+    (new-game (default-corp) (default-runner))
+    (is (= 5 (:credit (get-corp))))
+    (core/play state :corp {:card (first (:hand (get-corp)))})
+    (is (= 9 (:credit (get-corp))))))

 (deftest midseason-replacements
   "Midseason Replacements - Trace to give Runner tags after they steal an agenda"
@@ -71,6 +82,21 @@
       (prompt-choice :corp 0) ; default trace
       (prompt-choice :runner 0) ; Runner won't match
       (is (= 6 (:tag (get-runner))) "Runner took 6 tags"))))
+
+(deftest neural-emp
+  "Neural EMP - Play if Runner made a run the previous turn to do 1 net damage"
+  (do-game
+    (new-game (default-corp [(qty "Neural EMP" 1)])
+              (default-runner))
+    (play-from-hand state :corp "Neural EMP")
+    (is (= 3 (:click (get-corp))) "Neural precondition not met; card not played")
+    (take-credits state :corp)
+    (core/click-run state :runner {:server "Archives"})
+    (core/no-action state :corp nil)
+    (core/successful-run state :runner nil)
+    (take-credits state :runner)
+    (play-from-hand state :corp "Neural EMP")
+    (is (= 1 (count (:discard (get-runner)))) "Runner took 1 net damage")))

 (deftest news-cycle
   (do-game
@@ -192,3 +218,18 @@
       (prompt-select :corp iwall)
       (is (= 5 (:credit (get-corp))))
       (is (= 2 (:advance-counter (refresh iwall)))))))
+
+(deftest successful-demonstration
+  "Successful Demonstration - Play if only Runner made unsuccessful run last turn; gain 7 credits"
+  (do-game
+    (new-game (default-corp [(qty "Successful Demonstration" 1)])
+              (default-runner))
+    (play-from-hand state :corp "Successful Demonstration")
+    (is (and (= 3 (:click (get-corp))) (= 5 (:credit (get-runner)))) "Successful Demonstration precondition not met; card not played")
+    (take-credits state :corp)
+    (core/click-run state :runner {:server "R&D"})
+    (core/no-action state :corp nil)
+    (core/jack-out state :runner nil)
+    (take-credits state :runner)
+    (play-from-hand state :corp "Successful Demonstration")
+    (is (= 13 (:credit (get-corp))) "Paid 2 to play event; gained 7 credits")))


WIP rework entity validation

WIP rework entity validation

--- src/clj_money/models/entities.clj
+++ src/clj_money/models/entities.clj
@@ -1,10 +1,10 @@
 (ns clj-money.models.entities
   (:refer-clojure :exclude [update])
   (:require [clojure.pprint :refer [pprint]]
+            [clojure.spec :as s]
             [clojure.tools.logging :as log]
             [clojure.set :refer [rename-keys]]
             [clojure.reflect :refer :all]
-            [schema.core :as s]
             [clj-money.validation :as validation]
             [clj-money.models.helpers :refer [with-storage]]
             [clj-money.models.storage :refer [create-entity
@@ -13,52 +13,28 @@
                                               update-entity
                                               delete-entity]]))

-(def BaseEntity
-  "Shared entity attributes"
-  {:name s/Str
-   (s/optional-key :monitored-account-ids) [s/Int]})
+(s/def ::name string?)
+(s/def ::id integer?)
+(s/def ::user-id integer?)
+(s/def ::monitored-account-ids (s/coll-of integer?))
+(s/def ::new-entity (s/keys :req-un [::name ::user-id] :opt-un [::monitored-account-ids]))
+(s/def ::existing-entity (s/keys :req-un [::id ::name] :opt-un [::monitored-account-ids ::user-id]))

-(def NewEntity
-  "Schema for unsaved entities"
-  (merge BaseEntity
-         {:user-id s/Int}))
-
-(def ExistingEntity
-  "Schema for saved entities"
-  (merge BaseEntity
-         {:id s/Int
-          (s/optional-key :user-id) s/Int
-          (s/optional-key :created-at) s/Any
-          (s/optional-key :updated-at) s/Any}))
-
-(defn- name-must-be-unique
-  "Validation rule function that ensures an account
-  name is unique within an entity"
-  [storage {entity-name :name
-            entity-id :id
-            user-id :user-id
-            :as model}]
-  {:model model
-   :errors (let [existing (when (and entity-name user-id)
-                            (->> (select-entities storage user-id)
-                                 (remove #(= (:id %) entity-id))
-                                 (filter #(= (:name %) entity-name))))]
-             (if (seq existing)
-               [[:name "Name is already in use"]]
-               []))})
-
-(defn validation-rules
-  [schema storage]
-  [(partial validation/apply-schema schema)
-   (partial name-must-be-unique storage)])
-
-(defn- validate-new-entity
-  [storage entity]
-  (validation/validate-model entity (validation-rules NewEntity storage)))
-
-(defn- validate-existing-entity
-  [storage entity]
-  (validation/validate-model entity (validation-rules ExistingEntity storage)))
+;(defn- name-must-be-unique
+;  "Validation rule function that ensures an account
+;  name is unique within an entity"
+;  [storage {entity-name :name
+;            entity-id :id
+;            user-id :user-id
+;            :as model}]
+;  {:model model
+;   :errors (let [existing (when (and entity-name user-id)
+;                            (->> (select-entities storage user-id)
+;                                 (remove #(= (:id %) entity-id))
+;                                 (filter #(= (:name %) entity-name))))]
+;             (if (seq existing)
+;               [[:name "Name is already in use"]]
+;               []))})

 (defn- before-save
   [entity]
@@ -71,15 +47,12 @@
   "Creates a new entity"
   [storage-spec entity]
   (with-storage [s storage-spec]
-    (let [validated (validate-new-entity s entity)]
-      (when (not validated)
-        (throw (ex-info "The validated data is null" {:entity entity
-                                                      :validated validated})))
-      (if (validation/has-error? validated)
-        validated
+    (let [validated (validation/validate ::new-entity entity)]
+      (if (validation/valid? validated)
         (->> validated
              before-save
-             (create-entity s ))))))
+             (create-entity s ))
+        validated))))

 (defn select
   "Returns entities for the specified user"
@@ -112,7 +85,7 @@
   "Updates the specified entity"
   [storage-spec entity]
   (with-storage [s storage-spec]
-    (let [validated (validate-existing-entity s entity)]
+    (let [validated (validation/validate ::existing-entity entity)]
       (if (validation/valid? validated)
         (do
           (->> validated


fix dates

fix dates

--- src/cljs/cs95/views/syllabus.cljs
+++ src/cljs/cs95/views/syllabus.cljs
@@ -17,7 +17,7 @@

 (def class-days
   (let [dates (recurring-event {:interval (ti/weeks 1)
-                                :dates [(ti/date-time 2018 1 9) (ti/date-time 2018 3 16)]})]
+                                :dates [(ti/date-time 2018 1 9) (ti/date-time 2018 1 11)]})]
     (map day->str dates)))

 (def topics (mapv (fn [t] [md/md-div t])


Change cards so that its not an atom

Change cards so that its not an atom

--- src/cljs/decktouch/card-data.cljs
+++ src/cljs/decktouch/card-data.cljs
@@ -1,9 +1,9 @@
 (ns decktouch.card-data)

-(defonce cards (atom [
-                      {:name "Bile Blight"
-                       :mana-cost [:B :B]}
-                      {:name "Seeker of the Way"
-                       :mana-cost [:1 :W]}
-                      {:name "Magma Jet"
-                       :mana-cost [:1 :R]}]))+(def cards [
+            {:name "Bile Blight"
+             :mana-cost [:B :B]}
+            {:name "Seeker of the Way"
+             :mana-cost [:1 :W]}
+            {:name "Magma Jet"
+             :mana-cost [:1 :R]}])


Fix cljs warning

Fix cljs warning

apply must take a seq as its last arg

--- src/cljs/gc_api_browser/core.cljs
+++ src/cljs/gc_api_browser/core.cljs
@@ -79,6 +79,6 @@
                                                 (get-in app [:request :text]))))
                    (if schema
                      (render-request-and-response app)
-                     (schema-select/schema-file (:request app))))))))
+                     [(schema-select/schema-file (:request app))]))))))
     app-state
     {:target (.getElementById js/document "app")}))


modify game board to show Cyber-Cypher text overlay

--- src/cljs/netrunner/gameboard.cljs
+++ src/cljs/netrunner/gameboard.cljs
@@ -269,7 +269,7 @@

 (defn card-view [{:keys [zone code type abilities counter advance-counter advancementcost current-cost subtype
                          advanceable rezzed strength current-strength title remotes selected hosted
-                         side rec-counter facedown]
+                         side rec-counter facedown named-target]
                   :as cursor}
                  owner {:keys [flipped] :as opts}]
   (om/component
@@ -296,6 +296,7 @@
          (when (> advance-counter 0) [:div.darkbg.advance.counter advance-counter])]
         (when (and current-strength (not= strength current-strength))
               current-strength [:div.darkbg.strength current-strength])
+        (when named-target [:div.darkbg.named-target named-target])
         (when (and (= zone ["hand"]) (#{"Agenda" "Asset" "ICE" "Upgrade"} type))
           (let [centrals ["HQ" "R&D" "Archives"]
                 remotes (conj (remote-list remotes) "New remote")


renaming for better understanding

renaming for better understanding

--- src/cljs/triboard/logic/turn.cljs
+++ src/cljs/triboard/logic/turn.cljs
@@ -23,12 +23,15 @@
     :red :green
     :green :blue))

+(defn- next-3-players
+  [player]
+  (take 3 (iterate next-player (next-player player))))
+
 (defn- with-next-player
   "Find the next player to act - dismiss those that cannot play any move"
-  [{:keys [moves player] :as game}]
-  (let [nexts (take 3 (iterate next-player (next-player player)))
-        next-valid (some #(if (get moves %) % false) nexts)]
-    (assoc game :player next-valid)
+  [{:keys [moves player] :as turn}]
+  (let [who-can-play (filter #(get moves %) (next-3-players player))]
+    (assoc turn :player (first who-can-play))
     ))

 (defn- apply-moves


Add escape to completer keys

Add escape to completer keys

--- src/clojure/nightcode/editors.clj
+++ src/clojure/nightcode/editors.clj
@@ -313,7 +313,8 @@
 (def ^:const wrap-exts #{"md" "txt"})
 (def ^:const completer-keys #{KeyEvent/VK_ENTER
                               KeyEvent/VK_UP
-                              KeyEvent/VK_DOWN})
+                              KeyEvent/VK_DOWN
+                              KeyEvent/VK_ESCAPE})
 (def ^:const console-ignore-shortcut-keys #{KeyEvent/VK_Z
                                             KeyEvent/VK_Y})


Ensure services have a token.

Ensure services have a token.

--- src/clojure/staircase/handler.clj
+++ src/clojure/staircase/handler.clj
@@ -61,6 +61,12 @@
       ACCEPTED)
     NOT_FOUND))

+(defn register-for ;; currently gets anon session. Needs api hf to be applied.
+  [service]
+  (let [session-url (str (:root service) "/session")
+        resp (client/get session-url {:as :json :throw-exceptions false})]
+    (get-in resp [:body :token])))
+
 (defn get-end-of-history [histories id]
   (or
     (when-let [end (first (data/get-steps-of histories id :limit 1))]
@@ -227,16 +233,23 @@
                       configured-services (->> config :services (map (fn [[k v]] {:root v :ident k})))]
                   (response (left-outer-join configured-services user-services :root :root))))
             (context "/:ident" [ident]
-                    (GET "/" []
+                     (GET "/" []
                           (let [ident (real-id ident)
                                 uri (get-in config [:services ident])
-                                user-services (get-where services [:= :uri uri])]
-                            (-> (left-outer-join [{:root uri :ident ident}] user-services :root :root)
-                                first
-                                response)))
+                                user-services (get-where services [:= :root uri])
+                                service (-> (left-outer-join [{:root uri :ident ident}]
+                                                             user-services
+                                                             :root
+                                                             :root)
+                                            first)]
+                            (response (if (:token service)
+                                        service
+                                        (let [token (register-for service)
+                                              id (create services {:root (:root service) :token token})]
+                                          (merge service (get-one services id)))))))
                     (PUT "/" {doc :body}
                           (let [uri (get-in config [:services (real-id ident)])]
-                            (create-new services (assoc doc :uri uri))))))))
+                            (create-new services (assoc doc :root uri))))))))

 (defn- build-api-session-routes [router]
   (-> (routes


Deduplicate usage of call-with-options

Deduplicate usage of call-with-options

--- test/comic_reader/sites_test.clj
+++ test/comic_reader/sites_test.clj
@@ -108,45 +108,36 @@
           (extract-pages-list html "")))))

 (defn test-image-page-extraction []
-  (let [site ((get-sites) site-name)
-        results (try-read-file
+  (let [results (try-read-file
                  (site-test-resource "image.clj"))]
     (if-let [html (image-page-html)]
-      (call-with-options
-       site
-       #(and
-         (test-extract-image-tag html (:image-tag results))
-         (test-extract-pages-list html (:pages-list results))))
+      (and
+       (test-extract-image-tag html (:image-tag results))
+       (test-extract-pages-list html (:pages-list results)))
       (is false
           (str "There must be a sample image html page at "
                "`resources/test/" site-name "/image.html'")))))

 (defn test-extract-chapters-list []
-  (let [site ((get-sites) site-name)
-        results (try-read-file
+  (let [results (try-read-file
                  (site-test-resource "chapter_list.clj"))]
     (if-let [html (chapter-list-html)]
-      (call-with-options
-       site
-       #(and
-         (tu/ensure-dependencies-defined extract-chapters-list)
-         (is (= (:chapter-list results)
-                (extract-chapters-list html "")))))
+      (and
+       (tu/ensure-dependencies-defined extract-chapters-list)
+       (is (= (:chapter-list results)
+              (extract-chapters-list html ""))))
       (is false
           (str "There must be a sample chapter list html page "
                "at `resources/test/" site-name "/image.html'")))))

 (defn test-extract-comic-list []
-  (let [site ((get-sites) site-name)
-        results (try-read-file
+  (let [results (try-read-file
                  (site-test-resource "comic_list.clj"))]
     (if-let [html (comic-list-html)]
-      (call-with-options
-       site
-       #(and
-         (tu/ensure-dependencies-defined extract-comics-list)
-         (is (= (:comic-list results)
-                (extract-comics-list html)))))
+      (and
+       (tu/ensure-dependencies-defined extract-comics-list)
+       (is (= (:comic-list results)
+              (extract-comics-list html))))
       (is false
           (str "There must be a sample chapter list html page "
                "at `resources/test/" site-name "/image.html'")))))
@@ -157,10 +148,12 @@
       (binding [~'site-name ~site-name]
         (expect-opts-are-map ~site-name)
         (if (has-test-folder?)
-          (and
-            (test-image-page-extraction)
-            (test-extract-chapters-list)
-            (test-extract-comic-list))
+          (call-with-options
+           ((get-sites) site-name)
+           #(and
+             (test-image-page-extraction)
+             (test-extract-chapters-list)
+             (test-extract-comic-list)))
           (error-must-have-test-data))
         true))))


Try to fix weather unit test failure

Try to fix weather unit test failure

--- test/env_logger/weather_test.clj
+++ test/env_logger/weather_test.clj
@@ -6,18 +6,20 @@
             [cheshire.core :refer [generate-string]]
             [java-time :as t]
             [next.jdbc :as jdbc]
-            [env-logger.weather :refer [-convert-to-iso8601-str
-                                        -convert-to-tz-iso8601-str
-                                        calculate-start-time
-                                        extract-forecast-data
-                                        extract-weather-data
-                                        -update-fmi-weather-forecast
-                                        -update-fmi-weather-data
-                                        -fetch-owm-data
-                                        get-fmi-weather-data
-                                        get-wd-str
-                                        get-weather-data
-                                        weather-query-ok?]])
+            [env-logger
+             [config :refer [get-conf-value]]
+             [weather :refer [-convert-to-iso8601-str
+                              -convert-to-tz-iso8601-str
+                              calculate-start-time
+                              extract-forecast-data
+                              extract-weather-data
+                              -update-fmi-weather-forecast
+                              -update-fmi-weather-data
+                              -fetch-owm-data
+                              get-fmi-weather-data
+                              get-wd-str
+                              get-weather-data
+                              weather-query-ok?]]])
   (:import java.time.ZonedDateTime))

 (def fmi-current (atom {}))
@@ -29,10 +31,11 @@
 (deftest test-iso8601-str-generation
   (testing "ZonedDateTime to ISO 8601 string conversion"
     (is (= "2022-06-06T15:33:50Z"
-           (-convert-to-iso8601-str (ZonedDateTime/of 2022 6 6
-                                                      18 33 50 0
-                                                      (t/zone-id
-                                                       "Europe/Helsinki")))))))
+           (-convert-to-iso8601-str
+            (ZonedDateTime/of 2022 6 6
+                              18 33 50 0
+                              (t/zone-id
+                               (get-conf-value :weather-timezone))))))))

 (deftest test-iso8601-and-tz-str-formatting
   (testing "Date and time to ISO 8601 with timezone string conversion"
@@ -41,7 +44,8 @@
             (ZonedDateTime/of 2022 6 6
                               18 33 50 0
                               (t/zone-id
-                               "Europe/Helsinki")))))))
+                               (get-conf-value
+                                :weather-timezone))))))))

 ;; FMI


Fix file-size extraction for small files

--- src/kixi/datastore/web_server.clj
+++ src/kixi/datastore/web_server.clj
@@ -209,7 +209,7 @@

 (defn file-size
   [piece]
-  (let [^String fs (get-in piece [:request-headers :file-size])]
+  (let [^String fs (get-in piece [:request-headers "file-size"])]
     (Long/valueOf fs)))

 (defrecord PartConsumer
@@ -218,7 +218,7 @@
     (consume-part [this state part]
       (if (file-part? part)
         (let [id (uuid)
-              complete-chan-r (flush-tiny-file! filestore id part (file-size state))]
+              complete-chan-r (flush-tiny-file! filestore id part (file-size part))]
           (-> part
               (assoc :id id
                      :count 1


sequece接口

sequece接口

--- src/learnclojure/chapt3/core2.clj
+++ src/learnclojure/chapt3/core2.clj
@@ -43,3 +43,54 @@
 (count [1 2 4 5])
 ;;count保证所有对于所有集合操作耗时都是高效的，序列除外（因为它的长度可能是未知的）

+;;Sequence接口定义了一个获取和遍历各种集合的一个顺序视图的方法
+;;常用函数：
+;;seq返回传入参数的一个序列
+;;first，rest，next提供了遍历序列的方法
+;;lazy-seq创建一个内容是一个表达式结果的惰性序列
+
+;;seq支持的参数类型：
+;;1.所以clojure集合类型
+;;2.所有java集合类型,即java.util.*
+;;3.所有java map
+;;4.所有java.lang.CharSequence，包括String
+;;5.实现了java.lang.Iterable的类型
+;;6.数组
+;;7.nil（或者java方法返回的null）
+;;8.任何实现了clojure.lang.Seqable接口的类型
+;;一部分例子：
+(seq "Clojure")
+;=(\C \l \o \j \u \r \e)
+(seq {:a 5 :b 6})
+;=([:a 5] [:b 6])
+(seq (java.util.ArrayList. (range 5)))
+(seq (into-array ["Clojure" "Programming"]))
+;=("Clojure" "Programming")
+(seq [])
+;=nil
+(seq nil)
+;=nil
+;;seq对于nil和空集合都返回nil
+
+;;许多和序列打交道的函数都隐式调用了seq,比如:
+(map str "Clojure")
+(set "Programming")
+
+;;如果用现有的序列函数来定义自己的操作序列的函数，不需要对参数调用seq，除了使用lazy-seq
+
+;;clojure标准库clojure.core也有很多方法创建操作序列，最基本的是first，rest，next
+(first "Clojure")
+(rest "Clojure")
+(next "Clojure")
+;;rest和next大多数情况是一样的，对待空集合和只有一个元素的集合它们不一样
+(rest "")
+;=()
+(next "")
+;=nil
+(rest "1")
+;=()
+(next "1")
+;=nil
+(= (next "1")
+   (seq (rest "1")))
+;;这个区别看起来很小 ，但使我们很容易实现惰性序列


Implemented push-back.

Implemented push-back.

--- PersistentDataStructures/finger_trees.clj
+++ PersistentDataStructures/finger_trees.clj
@@ -5,24 +5,49 @@
 (defrecord finger-tree-single [v])
 (defrecord finger-tree-deep [l m r])

-; Adds a new element to the finger tree
+(defn make-node-3 [a b c] (node-3. a b c))
+
+; Reverse cons
+(defn snoc [a lst] (concat lst [a]))
+; Reverse rest
+(defn tser [lst] (take (dec (count lst)) lst))
+
+; Adds a new element to the front of the finger tree
 (defmulti push-front (fn [a _] (class a)))
 (defmethod push-front nil [_ a]
     (finger-tree-single. a))
 (defmethod push-front finger-tree-single [{r :v} a]
-    (finger-tree-deep. [a] nil [r]))
-(defn make-node-3 [a b c] (node-3. a b c))
+    (finger-tree-deep. [a] (delay nil) [r]))
 (defmethod push-front finger-tree-deep [{l :l m :m r :r} a]
     (if (<= (count l) 3)
         (finger-tree-deep. (cons a l) m r)
         (finger-tree-deep.
             [a (first l)]
-            (push-front m (apply make-node-3 (rest l)))
-            r))) ; not finished - needs to keep 'm'
+            (delay (push-front (force m) (apply make-node-3 (rest l))))
+            r)))

-(defn go [t n]
-    (do (println t)
-        (if (<= n 0) nil (go (push-front t n) (dec n)))))

-(go nil 20)
+; Adds a new element to the back of the finger tree
+(defmulti push-back (fn [a _] (class a)))
+(defmethod push-back nil [_ a]
+    (finger-tree-single. a))
+(defmethod push-back finger-tree-single [{r :v} a]
+    (finger-tree-deep. [r] (delay nil) [a]))
+(defmethod push-back finger-tree-deep [{l :l m :m r :r} a]
+    (if (<= (count r) 3)
+        (finger-tree-deep. l m (snoc a r))
+        (finger-tree-deep.
+            l
+            (delay (push-back (force m) (apply make-node-3 (tser r))))
+            [(last r) a])))

+(defn go [t n func]
+    (do (println t "\n")
+        (if (<= n 0) nil (go (func t n) (dec n) func))))
+
+(println "Forwards..")
+(go nil 20 push-front)
+
+(println "Backwards..")
+(go nil 20 push-back)
+


adjust error on chime-time

adjust error on chime-time


DM + RS - #5 Log exception details in api handler

--- src/objective8/handlers/api.clj
+++ src/objective8/handlers/api.clj
@@ -79,6 +79,7 @@
                  "Location" resource-location}
        :body stored-comment})
     (catch Exception e
+      (log/info "Error when posting comment: " e)
       {:status 400
        :body "Invalid comment post request"})))


Move fn.

Move fn.

--- src/onyx/peer/task_pipeline.clj
+++ src/onyx/peer/task_pipeline.clj
@@ -17,68 +17,68 @@
     (extensions/write-place sync peer-node updated-contents)
     node))

+(defn munge-open-session [event session]
+  (assoc event :session session))
+
+(defn munge-read-batch [event]
+  (let [rets (p-ext/read-batch event)]
+    (merge event rets)))
+
+(defn munge-decompress-batch [event]
+  (let [rets (p-ext/decompress-batch event)]
+    (merge event rets)))
+
+(defn munge-strip-sentinel [event]
+  (let [segments (:decompressed event)]
+    (if (= (last segments) :done)
+      (assoc event :tail-batch? true :decompressed (or (butlast segments) []))
+      (assoc event :tail-batch? false))))
+
+(defn munge-requeue-sentinel [{:keys [queue session ingress-queues tail-batch?] :as event}]
+  (when tail-batch?
+    ;; Caps all queues - only supports 1 consumers
+    (extensions/cap-queue queue ingress-queues))
+  event)
+
+(defn munge-apply-fn [event]
+  (let [rets (p-ext/apply-fn event)]
+    (merge event rets)))
+
+(defn munge-compress-batch [event]
+  (let [rets (p-ext/compress-batch event)]
+    (merge event rets)))
+
+(defn munge-write-batch [event]
+  (let [rets (p-ext/write-batch event)]
+    (merge event rets)))
+
+(defn munge-status-check [{:keys [sync status-node] :as event}]
+  (assoc event :commit? (extensions/place-exists? sync status-node)))
+
+(defn munge-ack [{:keys [queue batch commit?] :as event}]
+  (if commit?
+    (let [rets (p-ext/ack-batch event)]
+      (merge event rets))
+    event))
+
+(defn munge-commit-tx [{:keys [queue session commit?] :as event}]
+  (if commit?
+    (do (extensions/commit-tx queue session)
+        (assoc event :committed true))
+    event))
+
+(defn munge-close-resources [{:keys [queue session producers consumers] :as event}]
+  (doseq [producer producers] (extensions/close-resource queue producer))
+  (doseq [consumer consumers] (extensions/close-resource queue consumer))
+  (extensions/close-resource queue session)
+  (assoc event :closed true))
+
 (defn munge-new-payload [{:keys [sync peer-node peer-version payload-ch] :as event}]
   (if (= (extensions/version sync peer-node) peer-version)
     (let [node (new-payload sync peer-node payload-ch)]
       (extensions/on-change sync node #(>!! payload-ch %))
       (assoc event :new-payload-node node :completion? true))
     event))
-
-(defn munge-open-session [event session]
-  (assoc event :session session))
-
-(defn munge-read-batch [event]
-  (let [rets (p-ext/read-batch event)]
-    (merge event rets)))
-
-(defn munge-decompress-batch [event]
-  (let [rets (p-ext/decompress-batch event)]
-    (merge event rets)))
-
-(defn munge-strip-sentinel [event]
-  (let [segments (:decompressed event)]
-    (if (= (last segments) :done)
-      (assoc event :tail-batch? true :decompressed (or (butlast segments) []))
-      (assoc event :tail-batch? false))))
-
-(defn munge-requeue-sentinel [{:keys [queue session ingress-queues tail-batch?] :as event}]
-  (when tail-batch?
-    ;; Caps all queues - only supports 1 consumers
-    (extensions/cap-queue queue ingress-queues))
-  event)
-
-(defn munge-apply-fn [event]
-  (let [rets (p-ext/apply-fn event)]
-    (merge event rets)))
-
-(defn munge-compress-batch [event]
-  (let [rets (p-ext/compress-batch event)]
-    (merge event rets)))
-
-(defn munge-write-batch [event]
-  (let [rets (p-ext/write-batch event)]
-    (merge event rets)))
-
-(defn munge-status-check [{:keys [sync status-node] :as event}]
-  (assoc event :commit? (extensions/place-exists? sync status-node)))
-
-(defn munge-ack [{:keys [queue batch commit?] :as event}]
-  (if commit?
-    (let [rets (p-ext/ack-batch event)]
-      (merge event rets))
-    event))
-
-(defn munge-commit-tx [{:keys [queue session commit?] :as event}]
-  (if commit?
-    (do (extensions/commit-tx queue session)
-        (assoc event :committed true))
-    event))
-
-(defn munge-close-resources [{:keys [queue session producers consumers] :as event}]
-  (doseq [producer producers] (extensions/close-resource queue producer))
-  (doseq [consumer consumers] (extensions/close-resource queue consumer))
-  (extensions/close-resource queue session)
-  (assoc event :closed true))

 (defn munge-complete-task
   [{:keys [sync completion-node completion?] :as event}]


add demand ugen docstrings

add demand ugen docstrings

--- src/overtone/sc/ugen/demand.clj
+++ src/overtone/sc/ugen/demand.clj
@@ -4,16 +4,21 @@
 (def specs
      [
       {:name "Demand",
-       :args [{:name "trig"}
-              {:name "reset"}
+       :args [{:name "trig" :doc "Can be any signal. A trigger happens when the signal changes from non-positive to positive."}
+              {:name "reset" :doc "Resets the list of ugens when triggered."}
               {:name "demandUGens", :mode :append-sequence-set-num-outs}],
        :check (same-rate-as-first-input)
-       :doc "On every trigger it demands the next value from each of the demand ugens passed as args.  Used to pull values from the other demand rate ugens."}
+       :doc "On every trigger it demands the next value from each of the demand ugens passed as args.  Used to pull values from the other demand rate ugens.
+
+By design, a reset trigger only resets the demand ugens; it does not reset the value at Demand's output. Demand continues to hold its value until the next value is demanded, at which point its output value will be the first expected item in the list."}
+
+

       {:name "Duty",
-       :args [{:name "dur", :default 1.0}
-              {:name "reset", :default 0.0}
-              {:name "level", :default 1.0}
+       :args [{:name "dur", :default 1.0 :doc "time values. Can be a demand ugen or any signal. The next level is acquired after duration.
+"}
+              {:name "reset", :default 0.0 :doc "trigger or reset time values. Resets the list of ugens and the duration ugen when triggered. The reset input may also be a demand ugen, providing a stream of reset times."}
+              {:name "level", :default 1.0 :doc "demand ugen providing the output values."}
               {:name "action", :default :none :map DONE-ACTIONS}]
        :check (fn [rate num-outs [dur reset & _] spec]
                 (if (and (dr? dur)
@@ -21,29 +26,39 @@
                                   (ir? reset)
                                   (rate-of? reset rate))))
                   "TODO write error string. and understad why this is an error"))
-       :doc "Expects demand ugen args for dur and level.  Uses successive dur values to determine how long to wait before emitting each level value."}
+       :doc "Expects demand ugen args for dur and level.  Uses successive dur values to determine how long to wait before emitting each level value.
+
+A value is demanded each ugen in the list and output according to a stream of duration values.
+The unit generators in the list should be 'demand' rate.
+
+When there is a trigger at the reset input, the demand rate ugens in the list and the duration are reset. The reset input may also be a demand ugen, providing a stream of reset times."}

       {:name "TDuty" :extends "Duty"
-       :args [{:name "dur", :default 1.0}
-              {:name "reset", :default 0.0}
-              {:name "level", :default 1.0}
+       :args [{:name "dur", :default 1.0 :doc "time values. Can be a demand ugen or any signal. The next trigger value is acquired after the duration provided by the last time value."}
+              {:name "reset", :default 0.0 :doc "trigger or reset time values. Resets the list of ugens and the duration ugen when triggered. The reset input may also be a demand ugen, providing a stream of reset times."}
+              {:name "level", :default 1.0 :doc "demand ugen providing the output values."}
               {:name "action", :default 0 :map DONE-ACTIONS}
-              {:name "gapFirst", :default 0}]}
+              {:name "gapFirst", :default 0}]
+       :doc "A value is demanded each ugen in the list and output  as a trigger according to a stream of duration values. The unit generators in the list should be 'demand' rate.
+
+When there is a trigger at the reset input, the demand rate ugens in the list and the duration are reset.The reset input may also be a demand ugen, providing a stream of reset times."}

       {:name "DemandEnvGen",
-       :args [{:name "level"}
-              {:name "dur"}
-              {:name "shape", :default 1}
-              {:name "curve", :default 0}
-              {:name "gate", :default 1.0}
-              {:name "reset", :default 1.0}
-              {:name "levelScale", :default 1.0}
-              {:name "levelBias", :default 0.0}
-              {:name "timeScale", :default 1.0}
+       :args [{:name "level" :doc "demand ugen (or other ugen) returning level values"}
+              {:name "dur" :doc "demand ugen (or other ugen) returning time values"}
+              {:name "shape", :default 1 :doc "demand ugen (or other ugen) returning shape number - the number given is the shape number"}
+              {:name "curve", :default 0 :doc "demand ugen (or other ugen) returning curve values -  if shape is 5, this is the curve factor. Thee possible values are: 0 - flat segments, 1 - linear segments, the default, 2 - natural exponential growth and decay. In this case, the levels must all be nonzero and the have the same sign, 3 - sinusoidal S shaped segments, 4 - sinusoidal segments shaped like the sides of a Welch window, a Float - a curvature value for all segments, an Array of Floats - curvature values for each segments."
+               }
+              {:name "gate", :default 1.0 :doc "control rate gate if gate is x >= 1, the ugen runs, if gate is 0 > x > 1, the ugen is released at the next level (doneAction), if gate is x <= 0, the ugen is sampled end held"}
+              {:name "reset", :default 1.0 :doc "if reset crosses from nonpositive to positive, the ugen is reset at the next level. If it is > 1, it is reset immediately."}
+              {:name "levelScale", :default 1.0 :doc "demand ugen returning level scaling values"}
+              {:name "levelBias", :default 0.0 :doc "demand ugen returning level offset values"}
+              {:name "timeScale", :default 1.0 :doc "demand ugen returning time scaling values"}
               {:name "action", :default :none :map DONE-ACTIONS}]
        :init (fn [rate [l d s c gate reset ls lb ts da] spec]
                (if (or (ar? gate) (ar? reset))
-                 [l d s c (as-ar gate) (as-ar reset) ls lb ts da]))}
+                 [l d s c (as-ar gate) (as-ar reset) ls lb ts da]))
+       :doc "Plays back break point envelope contours (levels, times, shapes) given by demand ugens. The next values are called when the next node is reached."}

       ;; DUGen : UGen {
       ;;  init { arg ... argInputs;
@@ -77,87 +92,87 @@
       ;; which is implemented in the pseudo-ugen DUGen parent of below

       {:name "Dseries",
-       :args [{:name "start", :default 1}
-              {:name "step", :default 1}
-              {:name "length", :default INFINITE}]
+       :args [{:name "start", :default 1, :doc "start value"}
+              {:name "step", :default 1, :doc "step value"}
+              {:name "length", :default INFINITE, :doc "number of values to create"}]
        :rates #{:dr}
        :doc "Generate a series of incrementing values on demand."}

       {:name "Dgeom",
-       :args [{:name "start", :default 1}
-              {:name "grow", :default 2}
-              {:name "length", :default INFINITE}]
+       :args [{:name "start", :default 1, :doc "start value"}
+              {:name "grow", :default 2, :doc "value by which to grow ( x = x[-1] * grow )"}
+              {:name "length", :default INFINITE, :doc "doc number of values to create"}]
        :rates #{:dr}
-       :doc "Generate a geometric sequence on demand."}
+       :doc "Generate a geometric sequence on demand. The arguments can be a number or any other ugen"}

       {:name "Dbufrd",
-       :args [{:name "bufnum", :default 0.0}
-              {:name "phase", :default 0.0}
-              {:name "loop", :default 1.0}],
+       :args [{:name "bufnum", :default 0.0, :doc "buffer number to read from"}
+              {:name "phase", :default 0.0, :doc "index into the buffer"}
+              {:name "loop", :default 1.0, :doc "when phase exceeds number of frames in buffer, loops when set to 1"}],
        :rates #{:dr}
-       :doc "Read values from a buffer on demand, using phase (index) value that is also pulled on demand."}
+       :doc "Read values from a buffer on demand, using phase (index) value that is also pulled on demand. All inputs can be either demand ugen or any other ugen."}

       {:name "Dbufwr",
-       :args [{:name "input", :default 0.0}
-              {:name "bufnum", :default 0}
-              {:name "phase", :default 0.0}
-              {:name "loop", :default 1.0}],
+       :args [{:name "input", :default 0.0 :doc "single channel input"}
+              {:name "bufnum", :default 0, :doc "buffer number to read from (single channel buffer)"}
+              {:name "phase", :default 0.0, :doc "index into the buffer"}
+              {:name "loop", :default 1.0, :doc "when phase exceeds number of frames in buffer, loops when set to 1"}],
        :rates #{:dr}
-       :doc "Write a demand sequence into a buffer."}
+       :doc "Write a demand sequence into a buffer. All inputs can be either demand ugen or any other ugen."}

       {:name "Dseq",
-       :args [{:name "list", :mode :append-sequence, :array true}
-              {:name "repeats", :default 1}],
+       :args [{:name "list", :mode :append-sequence, :array true, :doc "array of values or other ugens"}
+              {:name "num-repeats", :default 1, :doc "number of repeats"}],
        :rates #{:dr}
-       :doc "Output a sequence of values, possibly repeating multiple times."}
+       :doc "Demand rate sequence generator. Outputs a sequence of values, possibly repeating multiple times. Use INFINITY as a repeat val to create an endless loop."}

       {:name "Dser"
-       :args [{:name "list", :mode :append-sequence, :array true}
-              {:name "count", :default 1}],
-       :doc "Generates a sequence of values Like dseq, except outputs only count total values, rather than repeating."}
+       :args [{:name "list", :mode :append-sequence, :array true :doc "array of values or other ugens"}
+              {:name "count", :default 1 :doc "number of values to return"}],
+       :doc "Demand rate sequence generator. Generates a sequence of values Like dseq, except outputs only count total values, rather than repeating."}

       {:name "Dshuf" :extends "Dseq"
-       :doc "Shuffle a sequence once and then output it one or more times."}
+       :doc "Demand rate random sequence generator. Shuffle a sequence once and then output it one or more times."}

       {:name "Drand" :extends "Dseq"
-       :doc "Generate a random ordering of an input sequence."}
+       :doc "Demand rate random sequence generator. Generate a random ordering of an input sequence."}

       {:name "Dxrand" :extends "Dseq"
-       :doc "Generate a random ordering of the given sequence without repeating any element until all elements have been returned."}
+       :doc "Demand rate random sequence generator. Generate a random ordering of the given sequence without repeating any element until all elements have been returned."}

       {:name "Dswitch1",
-       :args [{:name "list", :mode :append-sequence, :array true}
-              {:name "index"}],
+       :args [{:name "list", :mode :append-sequence, :array true :doc "array of values or other ugens"}
+              {:name "index" :doc "which of the inputs to return"}],
        :rates #{:dr}
        :doc "A demand rate switch that can be used to select one of multiple demand rate inputs."}

       {:name "Dswitch" :extends "Dswitch1"
-       :doc "A demand rate switch."}
+       :doc "A demand rate switch. In difference to Dswitch1, Dswitch embeds all items of an input demand ugen first before looking up the next index."}

       {:name "Dwhite",
-       :args [{:name "lo", :default 0.0}
-              {:name "hi", :default 1.0}
-              {:name "length", :default INFINITE}]
+       :args [{:name "lo", :default 0.0 :doc "minimum value"}
+              {:name "hi", :default 1.0 :doc "maximum value"}
+              {:name "length", :default INFINITE :doc "number of values to create"}]
        :rates #{:dr}
-       :doc "Generate a sequence of random values between lo and hi."}
+       :doc "Generate a sequence of random values in the continuous range between lo and hi."}

       {:name "Diwhite" :extends "Dwhite"
-       :doc "Generates a sequence of random integer values between lo and hi."}
+       :doc "Generates a sequence of random integer values between lo and hi. The arguments can be a number or any other ugen"}

       {:name "Dbrown",
-       :args [{:name "lo", :default 0.0}
-              {:name "hi", :default 1.0}
-              {:name "step", :default 0.01}
-              {:name "length", :default INFINITE}]
+       :args [{:name "lo", :default 0.0 :doc "minimum value"}
+              {:name "hi", :default 1.0 :doc "maximum value"}
+              {:name "step", :default 0.01 :doc "maximum step for each new value"}
+              {:name "length", :default INFINITE :doc "number of values to create"}]
        :rates #{:dr}
-       :doc "Generates a sequence of random values betweeen lo and hi, not exceeding step from one value to the next."}
+       :doc "Generates a sequence of random values in the continuous range betweeen lo and hi, not exceeding step from one value to the next. The arguments can be a number or any other ugen"}

       {:name "Dibrown" :extends "Dbrown"
-       :doc "Generates a sequence of random integer values betweeen lo and hi, not exceeding step from one value to the next."}
+       :doc "Generates a sequence of random integer values betweeen lo and hi, not exceeding step from one value to the next. The arguments can be a number or any other ugen"}

       {:name "Dstutter",
-       :args [{:name "n"}
-              {:name "in"}],
+       :args [{:name "num-repeats" :doc "number of repeats (can be a demand ugen)"}
+              {:name "in" :doc "input ugen"}],
        :rates #{:dr}
        :doc "Replicates input values n times on demand.  Both inputs can be demand rate ugens."}

@@ -170,5 +185,8 @@
               {:name "label" :doc "a label string"}
               {:name "run", :default 1.0 :doc "activation switch 0 or 1"}],
        :rates #{:dr}
-       :doc "Print the value of an input demand ugen."}
+       :doc "Print the value of an input demand ugen. The print-out is in the form: label: value block offset: offset.
+
+WARNING: Printing values from the Server in intensive for the CPU. Poll should be used for debugging purposes.
+"}
       ])


delaney.clj: small usability improvements for the Restriction type

--- clojure/org/gavrog/clojure/delaney.clj
+++ clojure/org/gavrog/clojure/delaney.clj
@@ -367,8 +367,11 @@
          (into #{} (elements ds)) ")")
     w))

+(defn restriction [ds idcs elms]
+  (Restriction. ds (into #{} idcs) (into #{} elms)))
+
 (defn orbit [ds idcs seed]
-  (Restriction. ds (into #{} idcs) (orbit-elements ds idcs seed)))
+  (restriction ds idcs (orbit-elements ds idcs seed)))

 ;; === Factories for DSymbol instances

@@ -446,6 +449,9 @@
   DSymbolSource
   (dsymbol [ds] (ds-from-ds ds)))

+(extend-type Restriction
+  DSymbolSource
+  (dsymbol [ds] (ds-from-ds ds)))

 ;; === Building a flat Java DSymbol instance


bump http-kit

bump http-kit

--- sidecar/project.clj
+++ sidecar/project.clj
@@ -15,7 +15,7 @@
    [com.stuartsierra/component "0.3.2"]
    [suspendable "0.1.1"
     :exclusions [org.clojure/clojure com.stuartsierra/component]]
-   [http-kit "2.2.0"]
+   [http-kit "2.3.0"]
    [ring-cors "0.1.11"
     :exclusions [ring/ring-core org.clojure/clojure]]
    [ring/ring-core "1.6.3"


Make render function part of prototype

Make render function part of prototype

--- src/reagent/impl/component.cljs
+++ src/reagent/impl/component.cljs
@@ -10,6 +10,7 @@
 (declare ^:dynamic *current-component*)

 (def cljs-state "cljsState")
+(def cljs-render "cljsRender")

 ;;; Accessors

@@ -102,34 +103,37 @@
   (set! (.-cljsIsDirty C) true)
   (.queue-render render-queue C))

-(defn do-render [C f]
+(defn do-render [C]
   (set! (.-cljsIsDirty C) false)
   (binding [*current-component* C]
-    (let [p (js-props C)
-          argv (aget p cljs-argv)
-          n (count argv)
+    (let [f (aget C cljs-render)
+          _ (assert (fn? f))
+          p (js-props C)
           res (if (nil? (aget C "componentFunction"))
                 (f C)
-                (case n
-                  1 (f)
-                  2 (f (argv 1))
-                  3 (f (argv 1) (argv 2))
-                  4 (f (argv 1) (argv 2) (argv 3))
-                  5 (f (argv 1) (argv 2) (argv 3) (argv 4))
-                  (apply f (subvec argv 1))))
-          conv (if (vector? res)
-                 (tmpl/as-component res (aget p cljs-level))
-                 (if (fn? res)
-                   (do-render C (set! (.-cljsRenderFn C) res))
-                   res))]
-      conv)))
-
-(defn render [C]
+                (let [argv (aget p cljs-argv)
+                      n (count argv)]
+                  (case n
+                    1 (f)
+                    2 (f (argv 1))
+                    3 (f (argv 1) (argv 2))
+                    4 (f (argv 1) (argv 2) (argv 3))
+                    5 (f (argv 1) (argv 2) (argv 3) (argv 4))
+                    (apply f (subvec argv 1)))))]
+      (if (vector? res)
+        (tmpl/as-component res (aget p cljs-level))
+        (if (fn? res)
+          (do
+            (aset C cljs-render res)
+            (do-render C))
+          res)))))
+
+(defn reactive-render [C]
   (assert C)
   (when (nil? (.-cljsRatom C))
     (set! (.-cljsRatom C)
           (ratom/make-reaction
-           #(do-render C (.-cljsRenderFn C))
+           #(do-render C)
            :auto-run (if tmpl/isClient
                        #(queue-render C)
                        identity))))
@@ -179,11 +183,6 @@
       (set! (.-cljsIsDirty C) false)
       (when f (f C)))

-    :render
-    (fn [C]
-      (if (nil? (.-cljsRenderFn C))
-        (set! (.-cljsRenderFn C) f))
-      (render C))
     nil))

 (defn default-wrapper [f]
@@ -192,12 +191,17 @@
       (this-as C (apply f C args)))
     f))

+(def dont-wrap #{:cljsRender})
+
 (defn get-wrapper [key f name]
-  (let [wrap (custom-wrapper key f)]
-    (when (and wrap f)
-      (assert (fn? f)
-              (str "Expected function in " name key " but got " f)))
-    (default-wrapper (or wrap f))))
+  (if (dont-wrap key)
+    (doto f
+      (aset "__reactDontBind" true))
+    (let [wrap (custom-wrapper key f)]
+      (when (and wrap f)
+        (assert (fn? f)
+                (str "Expected function in " name key " but got " f)))
+      (default-wrapper (or wrap f)))))

 (def obligatory {:shouldComponentUpdate nil
                  :componentWillUnmount nil})
@@ -209,18 +213,24 @@
 (defn add-obligatory [fun-map]
   (merge obligatory fun-map))

+(defn add-render [fun-map render-f]
+  (assoc fun-map
+    :cljsRender render-f
+    :render reactive-render))
+
 (defn wrap-funs [fun-map]
-  (let [name (or (:displayName fun-map)
-                 (when-let [r (or (:componentFunction fun-map)
-                                  (:render fun-map))]
-                   (or (.-displayName r)
-                       (.-name r))))
-        name1 (if (empty? name) (str (gensym "reagent")) name)
-        fmap (if-let [cf (:componentFunction fun-map)]
-               (assoc fun-map :render cf)
-               fun-map)]
-    (into {} (for [[k v] (assoc fmap :displayName name1)]
-               [k (get-wrapper k v name1)]))))
+  (let [render-fun (or (:componentFunction fun-map)
+                       (:render fun-map))
+        _ (assert (ifn? render-fun))
+        name (or (:displayName fun-map)
+                 (.-displayName render-fun)
+                 (.-name render-fun))
+        name' (if (empty? name) (str (gensym "reagent")) name)
+        fmap (-> fun-map
+                 (assoc :displayName name')
+                 (add-render render-fun))]
+    (into {} (for [[k v] fmap]
+               [k (get-wrapper k v name')]))))

 (defn cljsify [body]
   (-> body


add workaround for google/closure-compiler#3890

--- src/main/shadow/build/closure.clj
+++ src/main/shadow/build/closure.clj
@@ -2523,7 +2523,11 @@
           ;; goog and classpath-js will :advanced compiled
           ;; and will compile the polyfills as well which makes
           ;; them unusable for shadow-js which stays simple
-          shadow-js-injected-libs
+          (set/union
+            shadow-js-injected-libs
+            ;; workaround for https://github.com/google/closure-compiler/issues/3890
+            ;; so we can fix it by config and not rely on the automatic injection
+            (set (get-in state [:js-options :force-library-injection])))
           (set/union
             (when (contains? #{:es3 :es5} (get-in state [:compiler-options :output-feature-set]))
               ;; cannot figure out how to make closure report these
@@ -2551,6 +2555,7 @@
             goog-injected-libs
             shadow-js-injected-libs
             classpath-js-injected-libs
+            (set (get-in state [:js-options :force-library-injection]))
             (set (get-in state [:compiler-options :force-library-injection]))))]

     (if (or (not (seq all))


Update tests for new output order

Update tests for new output order

Moving misspellings above other options slipped in in a previous commit;
this updates the tests that reflect that change.

--- core/src/test/clojure/vdx_test/handlers.clj
+++ core/src/test/clojure/vdx_test/handlers.clj
@@ -213,25 +213,27 @@
                     (.element (QName. "urn:vdx:test" "ham"))
                     (.alternatives #{"ahm"})))]
         (assert-message (second (.primaryMessages res))
+          I18N$Key/DID_YOU_MEAN
+          "ahm")
+        (assert-message (nth (.primaryMessages res) 2)
           I18N$Key/ELEMENTS_ALLOWED_HERE
           ["ahm"])
-        (assert-message (nth (.primaryMessages res) 2)
+        ))
+
+    (testing "misspelled element without provided alternatives"
+      (let [res (.handle (UnexpectedElementHandler.)
+                  ctx
+                  (-> (ValidationError. ErrorType/UNEXPECTED_ELEMENT
+                        ""
+                        (location 6 4))
+                    (.element (QName. "urn:vdx:test" "ham"))))]
+        (assert-message (second (.primaryMessages res))
           I18N$Key/DID_YOU_MEAN
-          "ahm")))
-
-    (testing "misspelled element without provided alternatives"
-      (let [res (.handle (UnexpectedElementHandler.)
-                  ctx
-                  (-> (ValidationError. ErrorType/UNEXPECTED_ELEMENT
-                        ""
-                        (location 6 4))
-                    (.element (QName. "urn:vdx:test" "ham"))))]
-        (assert-message (second (.primaryMessages res))
+          "bar")
+        (assert-message (nth (.primaryMessages res) 2)
           I18N$Key/ELEMENTS_ALLOWED_HERE
           ["bar" "biscuit"])
-        (assert-message (nth (.primaryMessages res) 2)
-          I18N$Key/DID_YOU_MEAN
-          "bar")))
+        ))

     (testing "matchable element"
       (let [res (.handle (UnexpectedElementHandler.)


a little cleanup

a little cleanup

--- src/makerbar/pov/console/leap.clj
+++ src/makerbar/pov/console/leap.clj
@@ -93,10 +93,12 @@
                                         [x0 y0] :img-offset
                                         s0 :img-scale
                                         d0 :distance} @start-pan-zoom
+                                       ; pan
                                        [dx dy dz] (as-vec (.translation frame start-frame))
+                                       box (.interactionBox frame)
+                                       ; zoom
                                        [left-x left-y left-z] (as-vec (.palmPosition left-hand))
-                                       [right-x right-y right-z] (as-vec (.palmPosition right-hand))
-                                       box (.interactionBox frame)]
+                                       [right-x right-y right-z] (as-vec (.palmPosition right-hand))]
                                    (s/set-state! :img-offset [(+ x0 (* s/pov-width (/ dx (.width box)))) (+ y0 (- (* s/pov-height (/ dy (.height box)))))])
                                    (s/set-state! :img-scale (* s0 (/ (hand-distance left-hand right-hand) d0)))))
                                (reset! start-pan-zoom nil)))


Version bump to v1.59.4-SNAPSHOT

Version bump to v1.59.4-SNAPSHOT

--- scheduler/project.clj
+++ scheduler/project.clj
@@ -13,7 +13,7 @@
 ;; See the License for the specific language governing permissions and
 ;; limitations under the License.
 ;;
-(defproject cook "1.59.3"
+(defproject cook "1.59.4-SNAPSHOT"
   :description "This launches jobs on a Mesos cluster with fair sharing and preemption"
   :license {:name "Apache License, Version 2.0"}
   :dependencies [[org.clojure/clojure "1.10.3"]


Proper processing of word classes and 'use it' drop down list

--- src/zg/dictionary_interface.clj
+++ src/zg/dictionary_interface.clj
@@ -25,6 +25,31 @@
     [word]
     (re-matches #"[A-Za-z0-9.'\-\s_]+" word))

+(defn process-use-it
+    [use-it]
+    (condp = use-it
+        "Yes" 1
+        "No"  0
+              2))
+
+(defn process-class
+    [class]
+    (condp = (.toLowerCase class)
+        "N/A" nil
+        "n/a" nil
+        "verb" 1
+        "noun" 2
+        "adverb" 3
+        "adjective" 4
+        "pronoun" 5
+        "conjunction"  6
+        "preposition"  7
+        "interjection" 8
+        "article"      9
+        "numeral"      10
+        "determiner"  11
+        "exclamation" 12))
+
 (defn store-word
     "Store one word into the dictionary."
     ([word correct-form description user-name dictionary-type]
@@ -33,7 +58,7 @@
     (db-interface/add-new-word-into-dictionary word correct-form description (or user-name "(*unknown*)") dictionary-type))
     ([word description class use-it internal copyright source correct-forms incorrect-forms user-name dictionary-type]
     (log/info "About to store following word:" word " with description: " description " into dictionary: " (str dictionary-type))
-    (db-interface/add-new-word-into-dictionary word description class use-it internal copyright source correct-forms incorrect-forms (or user-name "(*unknown*)") dictionary-type)))
+    (db-interface/add-new-word-into-dictionary word description (process-class class) (process-use-it use-it) internal copyright (inc source) correct-forms incorrect-forms (or user-name "(*unknown*)") dictionary-type)))

 (defn store-words
     "Store sequence of words into the dictionary."


Set the yetibot-user on all handle-raw usage in IRC adapter

--- src/yetibot/core/adapters/irc.clj
+++ src/yetibot/core/adapters/irc.clj
@@ -132,8 +132,6 @@
    (let [config (:config a)
          {yetibot-nick :nick} @irc
          yetibot-user (construct-yetibot-from-nick yetibot-nick)
-         ;; print `irc` to see what's available
-         ;; also maybe this is a good time to spec it out :D
          user-id (:user info)
          chan (or (recognized-chan? a (:target info)) (:nick info))
          user (users/get-user (chat-source chan) user-id)]
@@ -141,16 +139,18 @@
      (binding [*target* chan]
        (handle-raw (chat-source chan) user :message (:text info) yetibot-user))))

-(defn handle-part [a _ {:keys [target] :as info}]
+(defn handle-part [a irc {:keys [target] :as info}]
   (binding [*target* target]
     (handle-raw (chat-source target)
-                (create-user info) :leave nil nil)))
-
-(defn handle-join [a _ {:keys [target] :as info}]
+                (create-user info) :leave nil
+                (construct-yetibot-from-nick (:nick @irc)))))
+
+(defn handle-join [a irc {:keys [target] :as info}]
   (log/debug "handle-join" info)
   (binding [*target* target]
     (handle-raw (chat-source (:target info))
-                (create-user info) :enter nil nil)))
+                (create-user info) :enter nil
+                (construct-yetibot-from-nick (:nick @irc)))))

 (defn handle-nick [a _ info]
   (let [[nick] (:params info)


fix typo

fix typo

--- src_patient/patient/routes.cljs
+++ src_patient/patient/routes.cljs
@@ -5,7 +5,7 @@
             [mobile-patient.color :as color]
             [mobile-patient.route-helpers :as rh]
             [mobile-patient.routes :refer [routes]]
-            [patiient.drawer :refer [Drawer]]))
+            [patient.drawer :refer [Drawer]]))

 (defn dumb-component [text]
   (r/reactify-component (fn [] [ui/text text])))


fixing build

fixing build

--- data/celestial/fixtures/populate.clj
+++ data/celestial/fixtures/populate.clj
@@ -63,7 +63,7 @@
     (fn [v]
       (g/fmap #(merge % v)
         (g/one-of
-          (into [(g/return d/redis-ec2-spec)] (mapv with-ids [d/redis-ec2-spec d/redis-openstack-spec])))))))
+          (into [(g/return d/redis-kvm-spec)] (mapv with-ids [d/redis-ec2-spec d/redis-openstack-spec])))))))

 (def systems-with-machines
   (g/bind machines


Fix namespace.

Fix namespace.

--- test/c2/t_ticks.clj
+++ test/c2/t_ticks.clj
@@ -1,4 +1,4 @@
-(ns c2.t-scale
+(ns c2.t-ticks
   (:use midje.sweet
         [c2.ticks :only [search]]))


add :top as default return value for (get-in) => :top

--- src/babel/over.cljc
+++ src/babel/over.cljc
@@ -100,15 +100,14 @@
                   (get-in child [:synsem :infl] :top)))
    (fail? (unifyc (get-in parent [:head :synsem :sem :tense] :top)
                   (get-in child [:synsem :sem :tense] :top)))
-   (fail? (unifyc (get-in parent [:synsem :cat])
-                  (get-in child [:synsem :cat])))
-   (fail? (unifyc (get-in parent [:head :synsem :cat])
-                  (get-in child [:synsem :cat])))
-   (fail? (unifyc (get-in parent [:head :synsem :subcat :1])
-                  (get-in child [:synsem :subcat :1])))
-   (fail? (unifyc (get-in parent [:head :synsem :subcat :2])
-                  (get-in child [:synsem :subcat :2])))
-   ))
+   (fail? (unifyc (get-in parent [:synsem :cat] :top)
+                  (get-in child [:synsem :cat] :top)))
+   (fail? (unifyc (get-in parent [:head :synsem :cat] :top)
+                  (get-in child [:synsem :cat] :top)))
+   (fail? (unifyc (get-in parent [:head :synsem :subcat :1] :top)
+                  (get-in child [:synsem :subcat :1] :top)))
+   (fail? (unifyc (get-in parent [:head :synsem :subcat :2] :top)
+                  (get-in child [:synsem :subcat :2] :top)))))

 (defn comp-pre-checks [parent child]
   (or
@@ -197,7 +196,9 @@

   (let [result
         (if (comp-pre-checks parent child)
-          :fail
+          (do
+            (log/trace (str "child: " child " failed pre-check."))
+            :fail)
           (unify
            (merge
             (copy parent)


Make Static nodes store a single String, not a vector of Strings

--- src/cascade/dom.clj
+++ src/cascade/dom.clj
@@ -13,14 +13,14 @@
 ;;; and limitations under the License.

 (ns
-  cascade.dom
+    cascade.dom
   "DOM node structure, rendering and manipulation"
   (:import
-    (clojure.lang Keyword Sequential))
+   (clojure.lang Keyword Sequential))
   (:require
-    (clojure [zip :as z] [string :as str]))
+   (clojure [zip :as z] [string :as str]))
   (:use
-    (cascade fail utils)))
+   (cascade fail utils)))

 ;;; TODO: For testing purposes (i.e., to get consistent results across JVMs, etc.)
 ;;; it may be necessary to sort attributes when rendering (but I'd rather not bother
@@ -28,36 +28,36 @@

 (def char-to-entity-map
   (merge
-    ; Start with whitespace plus all ASCII printable
-    (reduce #(assoc %1 (char %2) (char %2)) {}
-      (concat [9 10 13 32 33 \' \"] (range 35 38) (range 40 126)))
-    ; Then merge in the characters that must be XML entities
-    {
-      \< "<"
-      \> ">"
-      \& "&"
-      }))
+                                        ; Start with whitespace plus all ASCII printable
+   (reduce #(assoc %1 (char %2) (char %2)) {}
+           (concat [9 10 13 32 33 \' \"] (range 35 38) (range 40 126)))
+                                        ; Then merge in the characters that must be XML entities
+   {
+    \< "<"
+    \> ">"
+    \& "&"
+    }))

 (defn char-to-entity
   "Converts a single character to an entity, returning the entity or the original character."
   [ch]
   (or
-    (char-to-entity-map ch)
-    (format "&#x%x;" (int ch))))
+   (char-to-entity-map ch)
+   (format "&#x%x;" (int ch))))

 (defn encode-string
   "Encodes a string, replacing all non-ASCII characters with XML escape codes. In addition,
   unsafe characters are replaced with HTML entities."
   [s]
-  ; Could rewrite to more efficiently determine if out == s
-  ; Perhaps a regexp to see if encoding is necessary?
+                                        ; Could rewrite to more efficiently determine if out == s
+                                        ; Perhaps a regexp to see if encoding is necessary?
   (let [out (apply str (map #(char-to-entity %) (seq s)))]
     (if (= s out) s out)))

 (defprotocol ToAttributeValueString
   "Converts an attribute value to a string. It is not necessary to apply quotes (those come at a later stage)."
-  ; TODO control over quotes inside the value string; I think
+                                        ; TODO control over quotes inside the value string; I think
   (to-attribute-value-string [value]
     "Converts the value to a string that can be safely streamed as an attribute value."))

@@ -108,7 +108,7 @@

   DOMSerializing
   (serialize [node strategy]
-    ; The field 'name' shadows clojure.core/name, so we have to be explicit
+                                        ; The field 'name' shadows clojure.core/name, so we have to be explicit
     (let [element-name (clojure.core/name name)
           preamble ["<" element-name]
           attribute-pairs (serialize-attribute-pairs attributes strategy)
@@ -116,16 +116,16 @@
       (concat preamble attribute-pairs postamble))))

 ;;; Static is used for statically defined portions of the DOM tree, such as literal strings and
-;;; comments.
-(defrecord Static [strings]
+                          ;;; comments.
+(defrecord Static [string]

   DOMSerializing
-  (serialize [node strategy] strings))
+  (serialize [node strategy] string))

 (defrecord Comment [text]

   DOMSerializing
-  ; TODO: seems a bit wasteful to create a new vector each time a Comment is asked to serialize itself.
+                                        ; TODO: seems a bit wasteful to create a new vector each time a Comment is asked to serialize itself.
   (serialize [node strategy]
     ["<!--" text "-->"]))

@@ -138,7 +138,7 @@
 (defn raw-node
   "Wraps a string as a Static DOM node, but does not do any encoding of the value."
   [s]
-  (->Static [s]))
+  (->Static s))

 (defn text-node
   "Creates a Static DOM node from the string. The string is encoded when the node is constructed."
@@ -146,14 +146,14 @@
   (raw-node (encode-string text)))

 (defn comment-node
-  "Creates a Static DOM node from the string, providing the comment prefix and suffix. "
+  "Creates a Comment DOM node from the string, providing the comment prefix and suffix. "
   [comment]
-  (->Static ["<!--" comment "-->"]))
+  (->Comment comment))

 (def xml-strategy {
-  :serialize-attribute-pair (create-serialize-attribute-pair "\"")
-  :write-empty-element-close (constantly ["/>"])
-  })
+                   :serialize-attribute-pair (create-serialize-attribute-pair "\"")
+                   :write-empty-element-close (constantly ["/>"])
+                   })

 (defn serialize-xml
   "Serializes a seq of DOM nodes representing a complete document into a lazy seq of strings. Generally the dom-nodes seq will include just
@@ -170,9 +170,9 @@
     [">"]))

 (def html-strategy {
-  :serialize-attribute-pair (create-serialize-attribute-pair "\"")
-  :write-empty-element-close html-empty-element-writer
-  })
+                    :serialize-attribute-pair (create-serialize-attribute-pair "\"")
+                    :write-empty-element-close html-empty-element-writer
+                    })

 (defn serialize-html
   "Serializes a seq of DOM nodes representing a complete document (as with serialize-xml) but with HTML
@@ -191,16 +191,17 @@
   "Is the object some kind of DOM node?"
   [node]
   (or (element? node)
-    (instance? Static node)))
+      (instance? Static node)
+      (instance? Comment node)))

 (defn dom-zipper
   [root-node]
   (fail-unless (element? root-node) "Root node for dom-zipper must be an element node.")
   (z/zipper
-    element? ; can have children
-    :content ; children are (already) a seq in the :content key
-    (fn [node children] (assoc node :content children))
-    root-node))
+   element? ; can have children
+   :content ; children are (already) a seq in the :content key
+   (fn [node children] (assoc node :content children))
+   root-node))

 (defn navigate-dom-path
   "Starting from the root location (from dom-zipper) search for the first element child
@@ -213,15 +214,15 @@
          target-element (first path)
          remaining-path (rest path)]
     (lcond
-      (nil? loc) nil
-      :let [n (z/node loc)]
-      ; if matching element?
-      (and (element? n) (= (:name n) target-element))
-      ; then either we've found it, or we need to go into the element and continue searching down.
-      (if (empty? remaining-path)
-        loc
-        (recur (z/down loc) (first remaining-path) (rest remaining-path)))
-      true (recur (z/right loc) target-element remaining-path))))
+     (nil? loc) nil
+     :let [n (z/node loc)]
+                                        ; if matching element?
+     (and (element? n) (= (:name n) target-element))
+                                        ; then either we've found it, or we need to go into the element and continue searching down.
+     (if (empty? remaining-path)
+       loc
+       (recur (z/down loc) (first remaining-path) (rest remaining-path)))
+     true (recur (z/right loc) target-element remaining-path))))

 (defn update-dom
   "Updates the DOM using a DOM zipper, a position (:before, :after, :top, :bottom)
@@ -229,11 +230,11 @@
  be retrieved."
   [loc position new-nodes]
   (cond
-    (= position :before) (reduce z/insert-left loc new-nodes)
-    (= position :top) (reduce z/insert-child loc (reverse new-nodes))
-    (= position :after) (reduce z/insert-right loc (reverse new-nodes))
-    (= position :bottom) (reduce z/append-child loc new-nodes)
-    :else (fail "Unexpected position: %s" position)))
+   (= position :before) (reduce z/insert-left loc new-nodes)
+   (= position :top) (reduce z/insert-child loc (reverse new-nodes))
+   (= position :after) (reduce z/insert-right loc (reverse new-nodes))
+   (= position :bottom) (reduce z/append-child loc new-nodes)
+   :else (fail "Unexpected position: %s" position)))

 (defn extend-root-element
   "Extends the DOM from the root DOM element, returning a new DOM.
@@ -258,12 +259,12 @@
   New DOM nodes to insert."
   [root-node rules new-nodes]
   (or
-    (->>
-      (map (fn [[path position]]
-        (extend-root-element root-node path position new-nodes)) rules)
-      (remove nil?)
-      first)
-    root-node))
+   (->>
+    (map (fn [[path position]]
+           (extend-root-element root-node path position new-nodes)) rules)
+    (remove nil?)
+    first)
+   root-node))

 (defn extend-dom
   "Extends a DOM (a set of root DOM nodes), adding new nodes at a specific position. Uses the path
@@ -274,14 +275,14 @@
 Does nothing if the targetted node can't be found. Returns a new
 sequence of dom nodes.
 dom-nodes
-  A seq of nodes representing the document. The first element node is considered the root.
+A seq of nodes representing the document. The first element node is considered the root.
 rules
-  A seq of rules identifying where to place the new nodes. Each rule is a pair of values.
-  The first value is a seq of element types (as keywords) to navigate down. The second
-  value is a position (:before, :after:, :top, or :bottom). The first matching rule
-  is used.
+A seq of rules identifying where to place the new nodes. Each rule is a pair of values.
+The first value is a seq of element types (as keywords) to navigate down. The second
+value is a position (:before, :after:, :top, or :bottom). The first matching rule
+is used.
 new-nodes
-  The new nodes to insert in a position within the document."
+The new nodes to insert in a position within the document."
   [dom-nodes rules new-nodes]
   (loop [result []
          queue dom-nodes]