First cut at namespace-dispatch-table

First cut at namespace-dispatch-table

Dispatch tables can now include "context entries" distinguished by the
omission of the method keyword. The pathvec of such entries serves as
the context-pathvec for the nested entries. Providing a pipeline is
optional; if present, it will be used as the default pipeline for the
nested entries.

Regular entries can now omit the pipeline field or specify nil to use
the default pipeline inherited from the context.

--- src/io/aviso/rook/dispatcher.clj
+++ src/io/aviso/rook/dispatcher.clj
@@ -2,7 +2,29 @@
   (:require [clojure.core.match :refer [match]]
             [clojure.string :as string]
             [clojure.pprint :as pp]
-            [io.aviso.rook.internals :as internals]))
+            [io.aviso.rook.internals :as internals]
+            [io.aviso.rook :as rook]
+            [io.aviso.rook.schema-validation :as sv]))
+
+(def ^:private default-mappings
+
+  "Default function -> route spec mappings.
+
+  Namespace dispatch tables will by default include entries for public
+  Vars named by the keys in this map, with methods and pathvecs
+  provided by the values."
+
+  {
+   'new     [:get    ["new"]]
+   'edit    [:get    [:id "edit"]]
+   'show    [:get    [:id]]
+   'update  [:put    [:id]]
+   'patch   [:patch  [:id]]
+   'destroy [:delete [:id]]
+   'index   [:get    []]
+   'create  [:post   []]
+   }
+  )

 (defn pprint-code [form]
   (pp/write form :dispatch pp/code-dispatch))
@@ -39,20 +61,40 @@

     [[method pathvec verb-fn pipeline]
      [method' (into pathvec pathvec') verb-fn' pipeline']
-     ...]."
+     ...].
+
+  Entries may also take the alternative form of
+
+    [pathvec pipeline? & entries],
+
+  In which case pathvec and pipeline? (if present) will provide a
+  context pathvec and a default pipeline for the nested entries
+  without introducing a separate route."
   [dispatch-table]
-  (letfn [(unnest-entry [[method pathvec verb-fn pipeline
-                          & nested-table
-                          :as entry]]
-            (if nested-table
-              (into [[method pathvec verb-fn pipeline]]
-                (unnest-table pathvec nested-table))
-              [entry]))
-          (unnest-table [context-pathvec entries]
+  (letfn [(unnest-entry [default-pipeline [x :as entry]]
+            (cond
+              (keyword? x)
+              (let [[method pathvec verb-fn pipeline & nested-table] entry]
+                (if nested-table
+                  (into [[method pathvec verb-fn
+                          (or pipeline default-pipeline)]]
+                    (unnest-table pathvec nested-table))
+                  (cond-> [entry]
+                    (nil? pipeline) (assoc-in [0 3] default-pipeline))))
+
+              (vector? x)
+              (let [[context-pathvec & maybe-pipeline+entries] entry
+                    pipeline (if-not (vector? (first maybe-pipeline+entries))
+                               (first maybe-pipeline+entries))
+                    entries  (if pipeline
+                               (next maybe-pipeline+entries)
+                               maybe-pipeline+entries)]
+                (unnest-table context-pathvec pipeline entries))))
+          (unnest-table [context-pathvec default-pipeline entries]
             (mapv (fn [[_ pathvec :as unnested-entry]]
                     (assoc unnested-entry 1 (into context-pathvec pathvec)))
-              (mapcat unnest-entry entries)))]
-    (unnest-table [] dispatch-table)))
+              (mapcat (partial unnest-entry default-pipeline) entries)))]
+    (unnest-table [] nil dispatch-table)))

 (defn keywords->symbols
   "Converts keywords in xs to symbols, leaving other items unchanged."
@@ -113,3 +155,37 @@
 #_
 (defmacro define-dispatch-table [name & opts-and-entries]
   (def ~name `(compile-dispatch-table ~@opts-and-entries)))
+
+(defn default-pipeline [handler]
+  (-> handler
+    rook/wrap-with-function-arg-resolvers
+    sv/wrap-with-schema-validation))
+
+(defn namespace-dispatch-table
+  "Examines the given namespace and produces a dispatch table in a
+  format intelligible to compile-dispatch-table."
+  ([ns-sym]
+     (namespace-dispatch-table [] ns-sym))
+  ([context-pathvec ns-sym]
+     (namespace-dispatch-table context-pathvec ns-sym default-pipeline))
+  ([context-pathvec ns-sym pipeline]
+     (try
+       (require ns-sym)
+       (catch Exception e
+         (throw (ex-info "failed to require ns in namespace-dispatch-table"
+                  {:context-pathvec context-pathvec
+                   :ns              ns-sym
+                   :pipeline        pipeline}
+                  e))))
+     (let [context-pathvec ((fnil conj [])
+                            context-pathvec
+                            (peek (string/split (name ns-sym) #"\.")))]
+       [(->> ns-sym
+          ns-publics
+          (keep (fn [[k v]]
+                  (if (ifn? @v)
+                    (if-let [route-spec (or (:route-spec (meta v))
+                                            (get default-mappings k))]
+                      (conj route-spec (symbol (name ns-sym) (name k)))))))
+          (list* context-pathvec pipeline)
+          vec)])))


remove unused binding :yum:

remove unused binding :yum:

--- src/metabase/driver/generic_sql/query_processor.clj
+++ src/metabase/driver/generic_sql/query_processor.clj
@@ -218,7 +218,7 @@

 (defn process-structured
   "Convert QUERY into a korma `select` form, execute it, and annotate the results."
-  [{{:keys [source-table] :as query} :query, {:keys [set-timezone-sql], :as driver} :driver, database :database, :as outer-query}]
+  [{{:keys [source-table] :as query} :query, driver :driver, database :database, :as outer-query}]
   (binding [*query* outer-query]
     (try
       (let [entity      (korma-entity database source-table)


Fix wrong value for radius used in collision detection

--- src/cljs/chocolatier/engine/systems/collision.cljs
+++ src/cljs/chocolatier/engine/systems/collision.cljs
@@ -35,8 +35,8 @@
                     :offset-x :offset-y
                     :height :width
                     :hit-radius]
-          [x1 y1 off-x1 off-y1 r1 h1 w1] (map #(% e1) key-list)
-          [x2 y2 off-x2 off-y2 r2 h2 w2] (map #(% e2) key-list)
+          [x1 y1 off-x1 off-y1 h1 w1 r1] (map #(% e1) key-list)
+          [x2 y2 off-x2 off-y2 h2 w2 r2] (map #(% e2) key-list)
           ;; The hit circles are drawn around the center of the entity
           ;; by halving the height and width
           [center-x1 center-y1] (map + [x1 y1] (map halve [w1 h1]))


remove unnecessary comment

remove unnecessary comment

--- src-cljs/frontend/components/app.cljs
+++ src-cljs/frontend/components/app.cljs
@@ -74,7 +74,6 @@
       (d/unlisten! (om/get-shared (om/get-shared owner :db)) (om/get-state owner :listener-key)))
     om/IDidUpdate
     (did-update [_ _ _]
-      ;; maybe scroll chat
       (when (and (get-in app state/aside-menu-opened-path)
                  (seq (om/get-state owner :unseen-eids)))
         (om/set-state! owner :unseen-eids #{})))


Remove path-for Projects

Remove path-for Projects

        Currently this function isn't called and it should exist in the routes namespace.

--- src-cljs/frontend/models/project.cljs
+++ src-cljs/frontend/models/project.cljs
@@ -20,11 +20,6 @@
   (if-let [vcs-type (:vcs_type project)]
     vcs-type
     (vcs-url/vcs-type (:vcs_url project))))
-
-(defn path-for [project & [branch]]
-  (str "/" (-> project vcs-type routes/->short-vcs) "/" project-name project)
-       (when branch
-         (str "/tree/" (gstring/urlEncode branch))))

 (defn settings-path [project]
   (str "/" (-> project vcs-type routes/->short-vcs) "/" (vcs-url/project-name project) "/edit"))


Update deps

Update deps

--- planck-cljs/project.clj
+++ planck-cljs/project.clj
@@ -1,6 +1,5 @@
 (defproject planck "0.1.0"
   :dependencies [[org.clojure/clojure "1.7.0"]
-                 [org.clojure/clojurescript "1.7.28"]
-                 [tailrecursion/cljson "1.0.7"]
-                 [org.omcljs/ambly "0.6.0"]]
+                 [org.clojure/clojurescript "1.7.48"]
+                 [tailrecursion/cljson "1.0.7"]]
   :clean-targets ["out" "target"])


Added dissoc! to TransientHashMap

Added dissoc! to TransientHashMap

--- src/main/cljs/lean_map/core.cljs
+++ src/main/cljs/lean_map/core.cljs
@@ -359,6 +359,21 @@
         tcoll)
       (throw (js/Error. "assoc! after persistent!"))))

+  (without! [tcoll k]
+    (if edit
+      (if (nil? root)
+        tcoll
+        (let [removed-leaf? (Box. false false)
+              node (.inode-without root edit 0 (hash k) k removed-leaf?)]
+          (if (identical? node root)
+            nil
+            (set! root node))
+          (if (.-modified removed-leaf?)
+            (set! count (dec count)))
+          tcoll))
+      (throw (js/Error. "dissoc! after persistent!"))))
+
+
   (persistent! [tcoll]
     (if edit
       (do (set! edit nil)
@@ -377,7 +392,10 @@
   (-persistent! [tcoll] (.persistent! tcoll))

   ITransientAssociative
-  (-assoc! [tcoll key val] (.assoc! tcoll key val)))
+  (-assoc! [tcoll key val] (.assoc! tcoll key val))
+
+  ITransientMap
+  (-dissoc! [tcoll key] (.without! tcoll key)))

 (deftype NodeSeq [meta nodes dlen nloc i s ^:mutable __hash]
   Object


Add missing require

Add missing require

--- src/main/clojure/pigpen/oven.clj
+++ src/main/clojure/pigpen/oven.clj
@@ -25,7 +25,8 @@
 See pigpen.core and pigpen.exec
 "
   (:refer-clojure :exclude [ancestors])
-  (:require [pigpen.raw :as raw]
+  (:require [clojure.set]
+            [pigpen.raw :as raw]
             [pigpen.code :as code])
   (:import [org.apache.pig.data DataBag]))


link to clojuredocs.org for now

link to clojuredocs.org for now

--- cljs-server/cljsinfo_server/pages/cheatsheet.cljs
+++ cljs-server/cljsinfo_server/pages/cheatsheet.cljs
@@ -2,12 +2,17 @@
   (:require-macros [hiccups.core :as hiccups])
   (:require
     hiccups.runtime
+    clojure.string
     [cljsinfo-server.util :refer [js-log log]]))

 ;; TODO: text for footer:
 ;; "Please copy, improve, and share this work."

 (def encode js/goog.string.htmlEscape)
+(def encode-uri js/encodeURIComponent)
+
+(def clj-string "clojure.string")
+(def clj-set "clojure.set")

 ;;------------------------------------------------------------------------------
 ;; Helpers
@@ -19,8 +24,22 @@
 (hiccups/defhtml literal [n]
   [:span.literal-c3029 n])

-(hiccups/defhtml fn-link [nme]
-  [:a.fn-a8476 (encode nme)])
+(defn- nme->cljdocs-url [nme]
+  (-> nme
+    (clojure.string/replace "?" "_q")
+    encode-uri))
+
+(defn- docs-href [nme nme-space]
+  (str "http://clojuredocs.org/"
+       (encode-uri nme-space) "/"
+       (nme->cljdocs-url nme)))
+
+(hiccups/defhtml fn-link
+  ([nme] (fn-link nme "clojure.core"))
+  ([nme nme-space]
+    [:a.fn-a8476
+      {:href (docs-href nme nme-space)}
+      (encode nme)]))

 ;;------------------------------------------------------------------------------
 ;; Sections
@@ -196,13 +215,13 @@
             (fn-link "get")
             (fn-link "subs")
             (literal "(clojure.string/)")
-            (fn-link "join")
-            (fn-link "escape")
-            (fn-link "split")
-            (fn-link "split-lines")
-            (fn-link "replace")
-            (fn-link "replace-first")
-            (fn-link "reverse")]]
+            (fn-link "join" clj-string)
+            (fn-link "escape" clj-string)
+            (fn-link "split" clj-string)
+            (fn-link "split-lines" clj-string)
+            (fn-link "replace" clj-string)
+            (fn-link "replace-first" clj-string)
+            (fn-link "reverse" clj-string)]]
         [:tr.odd-372e6
           [:td.label-9e0b7 "Regex"]
           [:td.body-885f4
@@ -212,30 +231,30 @@
             (fn-link "re-matches")
             (fn-link "re-pattern")
             (literal "(clojure.string/)")
-            (fn-link "replace")
-            (fn-link "replace-first")]]
+            (fn-link "replace" clj-string)
+            (fn-link "replace-first" clj-string)]]
         [:tr.even-ff837
           [:td.label-9e0b7 "Letters"]
           [:td.body-885f4
             (literal "(clojure.string/)")
-            (fn-link "capitalize")
-            (fn-link "lower-case")
-            (fn-link "upper-case")]]
+            (fn-link "capitalize" clj-string)
+            (fn-link "lower-case" clj-string)
+            (fn-link "upper-case" clj-string)]]
         [:tr.odd-372e6
           [:td.label-9e0b7 "Trim"]
           [:td.body-885f4
             (literal "(clojure.string/)")
-            (fn-link "trim")
-            (fn-link "trim-newline")
-            (fn-link "triml")
-            (fn-link "trimr")]]
+            (fn-link "trim" clj-string)
+            (fn-link "trim-newline" clj-string)
+            (fn-link "triml" clj-string)
+            (fn-link "trimr" clj-string)]]
         [:tr.even-ff837
           [:td.label-9e0b7 "Test"]
           [:td.body-885f4
             (fn-link "char")
             (fn-link "string?")
             (literal "(clojure.string/)")
-            (fn-link "blank?")]]]]])
+            (fn-link "blank?" clj-string)]]]]])

 (hiccups/defhtml atoms-section []
   [:div.section-31efe
@@ -454,16 +473,16 @@
           [:td.label-9e0b7 "Set Ops"]
           [:td.body-885f4
             (literal "(clojure.set/)")
-            (fn-link "union")
-            (fn-link "difference")
-            (fn-link "intersection")
-            (fn-link "select")]]
+            (fn-link "union" clj-set)
+            (fn-link "difference" clj-set)
+            (fn-link "intersection" clj-set)
+            (fn-link "select" clj-set)]]
         [:tr.odd-372e6
           [:td.label-9e0b7 "Test"]
           [:td.body-885f4
             (literal "(clojure.set/)")
-            (fn-link "subset?")
-            (fn-link "superset?")]]]]])
+            (fn-link "subset?" clj-set)
+            (fn-link "superset?" clj-set)]]]]])

 (hiccups/defhtml maps-section []
   [:div.section-31efe


[#6066]: Update Livepeer listing + add livepeer.tv

Signed-off-by: Aleksandr Pantiukhov <33cce7019c5ec80a74fe74102c4c2175a8341f94@gmail.com>

--- src/status_im/ui/screens/browser/default_dapps.cljs
+++ src/status_im/ui/screens/browser/default_dapps.cljs
@@ -110,19 +110,28 @@
              :dapp-url    "https://cryptopurr.co/"
              :photo-path  "contacts://cryptopurr"
              :description "A social network for CryptoKitties"}]}
+   {:title (i18n/label :t/default-dapps-media)
+    :data  [{:name        "livepeer.tv"
+             :dapp-url    "http://livepeer.tv/"
+             :photo-path  "contacts://livepeer"
+             :description "Decentralized video broadcasting"}]}
    {:title (i18n/label :t/default-dapps-social-utilities)
     :data  [{:name        "Civitas"
              :dapp-url    "https://communities.colu.com/"
              :photo-path  "contacts://civitas"
              :description "Blockchain-powered local communities"}
+            {:name        "ETHLend"
+             :dapp-url    "https://app.ethlend.io"
+             :photo-path  "contacts://ethlend"
+             :description "Decentralized lending on Ethereum"}
             {:name        "Hexel"
              :dapp-url    "https://www.onhexel.com/"
              :photo-path  "contacts://hexel"
              :description "Create your own cryptocurrency"}
-            {:name        "ETHLend"
-             :dapp-url    "https://app.ethlend.io"
-             :photo-path  "contacts://ethlend"
-             :description "Decentralized lending on Ethereum"}
+            {:name        "Livepeer"
+             :dapp-url    "https://explorer.livepeer.org/"
+             :photo-path  "contacts://livepeer"
+             :description "Decentralized video broadcasting"}
             {:name        "Smartz"
              :dapp-url    "https://smartz.io"
              :photo-path  "contacts://smartz"
@@ -130,9 +139,4 @@
             {:name        "Status Test DApp"
              :dapp-url    "https://status-im.github.io/dapp/"
              :description "Request test assets and test basic web3 functionality."
-             :developer?  true}]}
-   {:title (i18n/label :t/default-dapps-media)
-    :data  [{:name        "LivePeer"
-             :dapp-url    "https://media.livepeer.org/"
-             :photo-path  "contacts://livepeer"
-             :description "Decentralized video broadcasting"}]}])
+             :developer?  true}]}])


Add cljsbuild section

Add cljsbuild section

--- template/src/leiningen/new/cljs_lambda/project.clj
+++ template/src/leiningen/new/cljs_lambda/project.clj
@@ -13,4 +13,12 @@
   {:defaults {:role "FIXME"}
    :functions
    [{:name   "work-magic"
-     :invoke {{name}}.core/work-magic}]})
+     :invoke {{name}}.core/work-magic}]}
+  :cljsbuild
+  {:builds [{:id "{{name}}"
+             :source-paths ["src"]
+             :compiler {:output-to "out/{{sanitized}}.js"
+                        :output-dir "out"
+                        :target :nodejs
+                        :optimizations :none
+                        :source-map true}}]})


Add more interesting cases

Add more interesting cases

--- test/dependable/resolve_interesting_cases_test.clj
+++ test/dependable/resolve_interesting_cases_test.clj
@@ -57,3 +57,40 @@
                  :spec [[{:relation :greater-than :version "2.2.0"}]]}]]
               query-asc
               :compare cmp))))))
+
+(deftest ^:resolve-interesting-cases implied-dependencies-case
+  (let [a1
+        {
+         :id "a"
+         :version "1.0.0"
+         :location "http://example.com/repo/a-1.0.0.zip"
+         :requirements [[{:status :present
+                          :id "b"}]]
+         }
+        b23
+        {
+         :id "b"
+         :version "2.3.0"
+         :location "http://example.com/repo/b-2.3.0.zip"
+         }
+        c353
+        {
+         :id "c"
+         :version "3.5.3"
+         :location "http://example.com/repo/c-3.5.3.zip"
+         }
+        repo-info {"a" [a1]
+                       "b" [b23]
+                       "c" [c353]}
+        query (map-query repo-info)]
+    (testing "Implied dependencies"
+      (is (= [:successful
+              #{a1 b23 c353}]
+             (resolve-dependencies
+              [[{:status :present
+                 :id "a"}]
+               [{:status :absent
+                 :id "b"}
+                {:status :present
+                 :id "c"}]]
+              query))))))


multiple target records denormalization test

--- test/er_cassandra/model/alia/relationship_test.clj
+++ test/er_cassandra/model/alia/relationship_test.clj
@@ -18,7 +18,7 @@
   (tu/create-table :simple_relationship_test_target
                    "(id timeuuid primary key, parent_id uuid, nick text)")
   (tu/create-table :simple_relationship_test_target_by_parent_id
-                   "(id timeuuid, parent_id uuid primary key, nick text)")
+                   "(id timeuuid, parent_id uuid, nick text, primary key (parent_id, id))")
   (let [target (t/create-entity
                 {:primary-table {:name :simple_relationship_test_target
                                  :key [:id]}
@@ -42,11 +42,34 @@

         resp @(rel/denormalize tu/*model-session* s sr :upsert {})
         potr (fetch-record :simple_relationship_test_target [:id] [tid])
-        potri (fetch-record :simple_relationship_test_target_by_parent_id [:parent_id] [sid])
+        potri (fetch-record :simple_relationship_test_target_by_parent_id
+                            [:parent_id] [sid])
         ]
     (is (= [[:test [:ok]]] resp))
     (is (= "foo" (:nick potr)))
     (is (= "foo" (:nick potri)))))
+
+(deftest update-simple-relationship-multiple-records-test
+  (let [[s t] (create-simple-relationship)
+        [sid tida tidb] [(uuid/v1) (uuid/v1) (uuid/v1)]
+        sr {:id sid :nick "foo"}
+        _ (insert-record :simple_relationship_test sr)
+        _ (upsert-instance t {:id tida :parent_id sid :nick "bar"})
+        _ (upsert-instance t {:id tidb :parent_id sid :nick "bar"})
+
+        resp @(rel/denormalize tu/*model-session* s sr :upsert {})
+        potra (fetch-record :simple_relationship_test_target [:id] [tida])
+        potrai (fetch-record :simple_relationship_test_target_by_parent_id
+                             [:parent_id :id] [sid tida])
+        potrb (fetch-record :simple_relationship_test_target [:id] [tidb])
+        potrbi (fetch-record :simple_relationship_test_target_by_parent_id
+                             [:parent_id :id] [sid tidb])
+        ]
+    (is (= [[:test [:ok]]] resp))
+    (is (= "foo" (:nick potra)))
+    (is (= "foo" (:nick potrai)))
+    (is (= "foo" (:nick potrb)))
+    (is (= "foo" (:nick potrbi)))))

 (defn create-composite-key-relationship
   []


Clip. Refactor tests in preparation for adding another one.

--- test/dependable/core_test.clj
+++ test/dependable/core_test.clj
@@ -3,23 +3,38 @@
             [dependable.core :refer :all]))

 (deftest simple-find
-         (let [package-a
+         (let [package-a30
                {:name "a"
                 :version 30
                 :url "a_loc30"}
+               package-a20
+               {:name "a"
+                :version 20
+                :url "a_loc20"}
+               package-c10
+               {:name "c"
+                :version 10
+                :url "c_loc10"}
                repo-info
                {"a"
-                [package-a]}
-               query (fn [nm]
-                       (let [result (find repo-info nm)]
-                         (if (nil? result)
-                           :unsatisfiable
-                           (get result 1))))]
-           (testing (is (= (resolve-dependencies
-                                 ["a"]
-                                 query)
-                           [package-a])))
-           (testing (is (= (resolve-dependencies
-                             ["b"]
+                [package-a30
+                 package-a20]
+                "c"
+                [package-c10]}
+               query
+               (fn [nm]
+                 (let [result (find repo-info nm)]
+                   (if (nil? result)
+                     []
+                     (get result 1))))]
+           (testing "Asking for a present package succeeds."
+                    (is (= (resolve-dependencies
+                             [{:name "a"}]
                              query)
-                           [:unsatisfiable])))))
+                           [:successful [package-a30]])))
+           (testing "Asking for a nonexistent package fails."
+                    (is (= (resolve-dependencies
+                             [{:name "b"
+                               :trace :b-isnt-there}]
+                             query)
+                           [:unsatisfiable [:b-isnt-there]])))))


Change sparkfn argument to be more consistent with other definitions

--- test/flambo/example/tfidf.clj
+++ test/flambo/example/tfidf.clj
@@ -11,8 +11,8 @@
                  "or" "our" "so" "this" "the" "that" "to" "we"})

 ;; Returns a seq of (doc_id, term) tuples
-(f/defsparkfn gen-docid-term-tuples [x]
-  (let [[doc-id content] x
+(f/defsparkfn gen-docid-term-tuples [doc-tuple]
+  (let [[doc-id content] doc-tuple
         terms (clojure.string/split content #" ")]
     (map (fn [term] [doc-id term]) terms)))


Finish GC test.

Finish GC test.

--- test/onyx/log/gc_log_test.clj
+++ test/onyx/log/gc_log_test.clj
@@ -53,31 +53,21 @@

 (onyx.api/gc peer-config)

-;;(def zk (zk/connect "127.0.0.1:2185"))
-
-(last (sort (zk/children zk (str "/onyx/" onyx-id "/log"))))
-(clojure.pprint/pprint (clojure.data.fressian/read (:data (zk/data zk (str "/onyx/" onyx-id "/origin/origin")))))
-
+(def v-peers (onyx.api/start-peers! n-peers peer-config system/onyx-fake-peer))

 (def ch (chan 100))

-(def origin (extensions/subscribe-to-log (:log env) ch))
-
-(future
-  (loop [replica origin]
-    (let [position (<!! ch)
-          entry (extensions/read-log-entry (:log env) position)
-          new-replica (extensions/apply-log-entry entry replica)]
-      (prn "===")
-      (println position)
-      (println entry)
-      (clojure.pprint/pprint new-replica)
+(loop [replica (extensions/subscribe-to-log (:log env) ch)]
+  (let [position (<!! ch)
+        entry (extensions/read-log-entry (:log env) position)
+        new-replica (extensions/apply-log-entry entry replica)]
+    (when-not (= (count (:peers new-replica)) 10)
       (recur new-replica))))

-;; (fact "peers balanced on 1 jobs" true => true)
+(fact "Starting peers after GC succeeded" true => true)

-;; (doseq [v-peer v-peers]
-;;   (onyx.api/shutdown-peer v-peer))
+(doseq [v-peer v-peers]
+  (onyx.api/shutdown-peer v-peer))

-;; (onyx.api/shutdown-env env)
+(onyx.api/shutdown-env env)


Update default User-Agent.

Update default User-Agent.

Updated user agent to reflect current version.
This should be build from version constant, that should be
automatically updated with releases, not sure how to do it yet.

--- src/clj/http/async/client/request.clj
+++ src/clj/http/async/client/request.clj
@@ -32,7 +32,7 @@
                     ByteArrayInputStream
                     ByteArrayOutputStream)))

-(def ^:dynamic *user-agent* "http.async.client/0.2.3-dev")
+(def ^:dynamic *user-agent* "http.async.client/0.4.1-dev")

 (def ^:dynamic *CLIENT* nil)


extract dereferenced-account-base-items

extract dereferenced-account-base-items

--- src/clj_money/models/transactions.clj
+++ src/clj_money/models/transactions.clj
@@ -716,6 +716,21 @@
                 item))
          (mapv #(get-previous-item storage %)))))

+(defn- dereferenced-account-base-items
+  "Find accounts IDs that are no longer referenced
+  by the transaction and looks up base items for
+  recalculating affected account items"
+  [storage updated-tx existing-tx]
+  (let [dereferenced-account-ids (apply difference (->> [existing-tx updated-tx]
+                                                        (map :items)
+                                                        (map #(map :account-id %))
+                                                        (map set)))]
+    (->> dereferenced-account-ids
+         (map #(hash-map :account-id %
+                         :transaction-date (:transaction-date updated-tx) ; TODO: get the earlier date
+                         :index (Integer/MAX_VALUE)))
+         (map #(get-previous-item storage %)))))
+
 (defn- find-existing-transaction
   "Given a transaction that has been updated, find the existing
   transaction in storage. If none can be found, throw an exception."
@@ -738,18 +753,7 @@
         validated
         (let [existing (find-existing-transaction storage validated)
               dereferenced-base-items (remove-dereferenced-items storage validated existing)
-
-              ; dereferenced accounts - accounts removed from the transaction by changing account-id
-              dereferenced-account-ids (apply difference (->> [existing validated]
-                                                              (map :items)
-                                                              (map #(map :account-id %))
-                                                              (map set)))
-
-              dereferenced-account-id-base-items (->> dereferenced-account-ids
-                                                      (map #(hash-map :account-id %
-                                                                      :transaction-date (:transaction-date validated)
-                                                                      :index (Integer/MAX_VALUE)))
-                                                      (map #(get-previous-item storage %)))
+              dereferenced-account-base-items (dereferenced-account-base-items storage validated existing)

               ; current items
               upserted-items (mapv #(as-> % i
@@ -771,7 +775,7 @@
               ; process all item updates
               _ (->> current-base-items
                      (concat dereferenced-base-items
-                             dereferenced-account-id-base-items)
+                             dereferenced-account-base-items)
                      (mapv #(recalculate-account-items storage %)))

               ; update the transaction record itself


return bigdec from balance aggregation functions

--- src/clj_money/models/transactions.clj
+++ src/clj_money/models/transactions.clj
@@ -474,10 +474,10 @@
   [storage-spec account-id start end]
   (let [t1 (find-last-item-before storage-spec account-id (tc/to-long start))
         t2 (find-last-item-on-or-before storage-spec account-id (tc/to-long end))
-        prior-balance (if t1 (:balance t1) 0)]
+        prior-balance (if t1 (:balance t1) 0M)]
     (if t2
       (- (:balance t2) prior-balance)
-      0)))
+      0M)))

 (defn balance-as-of
   "Returns the balance for the specified account as of the specified date"
@@ -485,4 +485,4 @@
   (let [t (find-last-item-on-or-before storage-spec account-id (tc/to-long as-of))]
     (if t
       (:balance t)
-      (bigdec 0))))
+      0M)))


Add missing requires in parts panel

Add missing requires in parts panel

--- src/day8/re_frame_10x/view/parts.cljs
+++ src/day8/re_frame_10x/view/parts.cljs
@@ -1,7 +1,10 @@
 (ns day8.re-frame-10x.view.parts
   (:require [day8.re-frame-10x.utils.re-com :as rc]
             [re-frame.registrar]
-            [re-frame.events]))
+            [re-frame.events]
+            [re-frame.subs]
+            [re-frame.fx]
+            [re-frame.cofx]))

 (defn render-registered [kind]
   (for [[k v] (sort-by key (get @re-frame.registrar/kind->id->handler kind))]


default key-segment -str-rep

default key-segment -str-rep

--- src/er_cassandra/concatenated_key.clj
+++ src/er_cassandra/concatenated_key.clj
@@ -22,6 +22,11 @@
   (-str-rep [v]
     (cut/unparse-timestamp-utc-millis v)))

+(extend-type java.lang.Object
+  IConcatenatedKeySegment
+  (-str-rep [v]
+    (str v)))
+
 (def default-separator "/")

 (defn concatenate-keys


Fix update machine tags in aws provisioner

--- src/gamlor/rochla/aws_provisioner.clj
+++ src/gamlor/rochla/aws_provisioner.clj
@@ -146,7 +146,7 @@

 (defn update-tags [cred machine tags]
-  (ec2/create-tags cred {:resources [machine] :tags (map-to-tags tags)})
+  (ec2/create-tags cred {:resources [(:id machine)] :tags (map-to-tags tags)})
   )


fix externs inference to account for hinted types

  (:require ["some-npm" :as Thing])

and then used as a tag

  (.requiresExterns ^Thing x)

should add externs, but just discarded since every non js tag
was treated as cljs/closure and safe to rename. resolve only
accounted for ^alias/Thing uses but not the unqualified version

--- src/main/shadow/build/cljs_hacks.cljc
+++ src/main/shadow/build/cljs_hacks.cljc
@@ -465,7 +465,7 @@
         ;; (def Alias js/Foo)
         ;; (extend-protocol Foo Alias (foo [x] (.shouldNotRename x))
         ;; x will have target-tag that.ns/Alias, resolving to check if that is tagged as js
-        (when (and (qualified-symbol? target-tag) (not (ana/js-tag? target-tag)))
+        (when (and (symbol? target-tag) (not (ana/js-tag? target-tag)))
           (when-let [{:keys [tag]} (shadow-resolve-var env target-tag nil false)]
             (when (ana/js-tag? tag)
               (shadow-js-access-property


fix build reports

fix build reports

fixes #993

--- src/main/shadow/cljs/build_report.clj
+++ src/main/shadow/cljs/build_report.clj
@@ -159,8 +159,12 @@
           sources-info
           (->> build-sources
                (map (fn [src-id]
-                      (let [{:keys [resource-name fs-root pom-info npm-info package-name output-name type provides] :as src}
+                      (let [{:keys [resource-name fs-root pom-info package-name output-name type provides] :as src}
                             (data/get-source-by-id state src-id)
+
+                            npm-info
+                            (when-some [package (:shadow.build.npm/package src)]
+                              (select-keys package [:package-id :package-name :version]))

                             {:keys [js source] :as output}
                             (data/get-output! state src)]
@@ -347,4 +351,8 @@
 ;; FIXME: parse args properly, need support for tag and output-dir
 (defn -main [build-id report-file]
   (generate (keyword build-id) {:print-table true
-                                :report-file report-file}))+                                :report-file report-file}))
+
+
+(comment
+  (generate :browser {:print-table true :report-file "tmp/report.html"}))


DM + CM #17 - Remove invitation credentials from session when accepting invitation

--- src/objective8/handlers/front_end.clj
+++ src/objective8/handlers/front_end.clj
@@ -305,11 +305,17 @@
                                                    :signed-in (signed-in?)}))
     (error-404-response t' locale)))

+(defn remove-invitation-credentials [response current-session]
+  (assoc response :session (dissoc current-session :invitation)))
+
 (defn accept-invitation [{:keys [session]}]
+  (prn (str "request: " session))
   (if-let [invitation-credentials (:invitation session)]
     (let [invitation-response {:invitee-id (get (friend/current-authentication) :username)
                                :invitation-id (:invitation-id invitation-credentials)
                                :objective-id (:objective-id invitation-credentials)}]
       (http-api/accept-invitation invitation-response)
-      (response/redirect (str utils/host-url "/objectives/" (:objective-id invitation-credentials) "/candidate-writers")))
+      (-> (str utils/host-url "/objectives/" (:objective-id invitation-credentials) "/candidate-writers")
+          response/redirect
+          (remove-invitation-credentials session)))
     {:status 401}))


No need for long cooercian

No need for long cooercian

--- src/onyx/messaging/protocol_aeron.clj
+++ src/onyx/messaging/protocol_aeron.clj
@@ -124,7 +124,7 @@
         message-payload-bytes (byte-array payload-size)
         _ (.getBytes buf offset message-payload-bytes)
         message-payloads (decompress-f message-payload-bytes)
-        offset (long (unchecked-add offset payload-size))]
+        offset (unchecked-add offset payload-size)]
     (loop [messages (transient [])
            payloads (seq message-payloads)
            offset offset]


Add some more tests for fact/resource subqueries

--- test/com/puppetlabs/puppetdb/test/http/v2/facts.clj
+++ test/com/puppetlabs/puppetdb/test/http/v2/facts.clj
@@ -187,29 +187,78 @@
           (is (= status pl-http/status-bad-request))
           (is (= body "[] is not well-formed; queries must contain at least one operator")))))))

-(deftest queries-by-resources
+(defn is-query-result
+  [query results]
+  (let [request (make-request "/v2/facts" {"query" (json/generate-string query)})
+        {:keys [status body]} (*app* request)]
+    (is (= status pl-http/status-ok))
+    (is (= (json/parse-string body true) results))))
+
+(deftest fact-subqueries
   (testing "subqueries using a resource"
     (scf-store/add-certname! "foo")
     (scf-store/add-certname! "bar")
     (scf-store/add-certname! "baz")
-    (scf-store/add-facts! "foo" {"ipaddress" "192.168.1.100"} (now))
-    (scf-store/add-facts! "bar" {"ipaddress" "192.168.1.101"} (now))
-    (scf-store/add-facts! "baz" {"ipaddress" "192.168.1.102"} (now))
+    (scf-store/add-facts! "foo" {"ipaddress" "192.168.1.100" "operatingsystem" "Debian"} (now))
+    (scf-store/add-facts! "bar" {"ipaddress" "192.168.1.101" "operatingsystem" "Ubuntu"} (now))
+    (scf-store/add-facts! "baz" {"ipaddress" "192.168.1.102" "operatingsystem" "CentOS"} (now))
+
     (let [catalog (:empty catalogs)
           apache-resource {:type "Class" :title "Apache"}
           apache-catalog (update-in catalog [:resources] conj {apache-resource (assoc apache-resource :exported false)})]
       (scf-store/replace-catalog! (assoc apache-catalog :certname "foo") (now))
       (scf-store/replace-catalog! (assoc apache-catalog :certname "bar") (now))
       (scf-store/replace-catalog! (assoc catalog :certname "baz") (now)))
-    (let [query ["and"
-                 ["=" ["fact" "name"] "ipaddress"]
-                 ["subquery" "resource"
-                  ["and"
-                   ["=" "type" "Class"]
-                   ["=" "title" "Apache"]]]]
-          request (make-request "/v2/facts" {"query" (json/generate-string query)})
-          {:keys [status body]} (*app* request)
-          result (json/parse-string body true)]
-      (is (= status pl-http/status-ok))
-      (is (= result [{:node "bar" :fact "ipaddress" :value "192.168.1.101"}
-                     {:node "foo" :fact "ipaddress" :value "192.168.1.100"}])))))
+
+    (testing "subqueries using a resource"
+      (doseq [[query results]  {["and"
+                                 ["=" ["fact" "name"] "ipaddress"]
+                                 ["subquery" "resource"
+                                  ["and"
+                                   ["=" "type" "Class"]
+                                   ["=" "title" "Apache"]]]]
+
+                                [{:node "bar" :fact "ipaddress" :value "192.168.1.101"}
+                                 {:node "foo" :fact "ipaddress" :value "192.168.1.100"}]
+
+                                ;; Multiple matching resources
+                                ["and"
+                                 ["=" ["fact" "name"] "ipaddress"]
+                                 ["subquery" "resource"
+                                  ["=" "type" "Class"]]]
+
+                                [{:node "bar" :fact "ipaddress" :value "192.168.1.101"}
+                                 {:node "baz" :fact "ipaddress" :value "192.168.1.102"}
+                                 {:node "foo" :fact "ipaddress" :value "192.168.1.100"}]
+
+                                ;; Multiple facts
+                                ["and"
+                                 ["or"
+                                  ["=" ["fact" "name"] "ipaddress"]
+                                  ["=" ["fact" "name"] "operatingsystem"]]
+                                 ["subquery" "resource"
+                                  ["and"
+                                   ["=" "type" "Class"]
+                                   ["=" "title" "Apache"]]]]
+
+                                [{:node "bar" :fact "ipaddress" :value "192.168.1.101"}
+                                 {:node "bar" :fact "operatingsystem" :value "Ubuntu"}
+                                 {:node "foo" :fact "ipaddress" :value "192.168.1.100"}
+                                 {:node "foo" :fact "operatingsystem" :value "Debian"}]
+
+                                ;; No matching resources
+                                ["and"
+                                 ["=" ["fact" "name"] "ipaddress"]
+                                 ["subquery" "resource"
+                                  ["=" "type" "NotRealAtAll"]]]
+
+                                []
+
+                                ;; No matching facts
+                                ["and"
+                                 ["=" ["fact" "name"] "nosuchfact"]
+                                 ["subquery" "resource"
+                                  ["=" "type" "Class"]]]
+
+                                []}]
+        (is-query-result query results)))))


Support disable render

Support disable render

--- test/com/wsscode/pathom/connect/run_graph_test.cljc
+++ test/com/wsscode/pathom/connect/run_graph_test.cljc
@@ -46,14 +46,15 @@
     (io/copy (tangle/dot->image dot "png") (io/file "out.png"))
     graph))

-(defn compute-run-graph [{::keys [resolvers out] :as options}]
-  (render-graph
-    (pcrg/compute-run-graph*
-      (merge (pcrg/base-out) out)
-      (cond-> (merge (base-graph-env)
-                     options)
-        resolvers
-        (pc/merge-indexes (register-index resolvers))))))
+(defn compute-run-graph [{::keys [resolvers out disable-render?] :as options}]
+  (cond-> (pcrg/compute-run-graph*
+            (merge (pcrg/base-out) out)
+            (cond-> (merge (base-graph-env)
+                           options)
+              resolvers
+              (pc/merge-indexes (register-index resolvers))))
+    (not disable-render?)
+    (render-graph)))

 (deftest test-compute-root-or
   (testing "set root when no root is the current"
@@ -1371,6 +1372,7 @@
       (-> {::eql/query           [:customer/id :customer/name :customer/dob
                                   :customer/cpf :account/interest-rate]
            ::pcrg/available-data {:customer/id {}}
+           ::disable-render?     true
            ::resolvers           [{::pc/sym    'customer-by-id
                                    ::pc/input  #{:customer/id}
                                    ::pc/output [:customer/id


Add explicit exception type on accessrules tests.

--- test/buddy/auth/accessrules_tests.clj
+++ test/buddy/auth/accessrules_tests.clj
@@ -63,7 +63,7 @@

   (testing "restrict handler with failure 1"
     (let [handler (restrict test-handler {:handler {:or [fail fail]}})]
-      (is (thrown? Exception (handler 1)))))
+      (is (thrown? clojure.lang.ExceptionInfo (handler 1)))))

   (testing "restrict handler with failure 2"
     (let [handler (restrict test-handler {:handler {:or [fail fail]}})
@@ -132,10 +132,10 @@
       (is (= {:uri "/path2"} (:body rsp)))))

   (testing "check access rules 3"
-    (is (thrown? Exception (handler1 {:uri "/path3"}))))
+    (is (thrown? clojure.lang.ExceptionInfo (handler1 {:uri "/path3"}))))

   (testing "check access rules 4"
-    (is (thrown? Exception (handler1 {:uri "/path4"}))))
+    (is (thrown? clojure.lang.ExceptionInfo (handler1 {:uri "/path4"}))))

   (testing "check access rules 5"
     (let [rsp (handler2 {:uri "/path3"})]
@@ -158,10 +158,10 @@
       (is (= {:uri "/path2"} (:body rsp)))))

   (testing "check access rules 3"
-    (is (thrown? Exception (handler3 {:uri "/path3"}))))
+    (is (thrown? clojure.lang.ExceptionInfo (handler3 {:uri "/path3"}))))

   (testing "check access rules 4"
-    (is (thrown? Exception (handler3 {:uri "/path4"}))))
+    (is (thrown? clojure.lang.ExceptionInfo (handler3 {:uri "/path4"}))))
 )

 (defn method-handler [type type-param allowed]
@@ -182,13 +182,12 @@
         (testing "with keyword as allowed method"
           (let [handler (method-handler :get)]
             (is (= (:body (handler allowed)) allowed))
-            (is (thrown? Exception (handler forbidden)))))
+            (is (thrown? clojure.lang.ExceptionInfo (handler forbidden)))))

         (testing "with set of keywords as allowed method"
           (let [handler (method-handler #{:get})]
             (is (= (:body (handler allowed)) allowed))
-            (handler forbidden)
-            (is (thrown? Exception (handler forbidden)))))
+            (is (thrown? clojure.lang.ExceptionInfo (handler forbidden)))))

         (testing "with nil as allowed request method"
           (let [handler (method-handler nil)]
@@ -200,12 +199,12 @@
         (testing "with keyword as allowed method"
           (let [handler (method-handler :get)]
             (is (= (:body (handler allowed)) allowed))
-            (is (thrown? Exception (handler forbidden)))))
+            (is (thrown? clojure.lang.ExceptionInfo (handler forbidden)))))

         (testing "with set of keywords as allowed method"
           (let [handler (method-handler #{:get})]
             (is (= (:body (handler allowed)) allowed))
-            (is (thrown? Exception (handler forbidden)))))
+            (is (thrown? clojure.lang.ExceptionInfo (handler forbidden)))))

         (testing "with nil as allowed request method"
           (let [handler (method-handler nil)]
@@ -217,12 +216,12 @@
         (testing "with keyword as allowed method"
           (let [handler (method-handler :get)]
             (is (= (:body (handler allowed)) allowed))
-            (is (thrown? Exception (handler forbidden)))))
+            (is (thrown? clojure.lang.ExceptionInfo (handler forbidden)))))

         (testing "with set of keywords as allowed method"
           (let [handler (method-handler #{:get})]
             (is (= (:body (handler allowed)) allowed))
-            (is (thrown? Exception (handler forbidden)))))
+            (is (thrown? clojure.lang.ExceptionInfo (handler forbidden)))))

         (testing "with nil as allowed request method"
           (let [handler (method-handler nil)]


If any buffered data has been read, return it

--- planck-cljs/src/planck/core.cljs
+++ planck-cljs/src/planck/core.cljs
@@ -53,13 +53,17 @@
 (defrecord BufferedReader [raw-read raw-close buffer]
   IReader
   (-read [_]
-    (raw-read))
+    (if-let [b @buffer]
+      (do
+        (reset! buffer nil)
+        b)
+      (raw-read)))
   IBufferedReader
   (-read-line [this]
     (if-let [buffered @buffer]
       (let [n (.indexOf buffered "\n")]
         (if (neg? n)
-          (if-let [next-characters (-read this)]
+          (if-let [next-characters (raw-read)]
             (do
               (swap! buffer (fn [s] (str s next-characters)))
               (recur this))
@@ -69,7 +73,7 @@
                                         nil
                                         residual))
                                     (subs s 0 n)]))))
-      (when (reset! buffer (-read this))
+      (when (reset! buffer (raw-read))
         (recur this))))
   IClosable
   (-close [_]


Track execution errors in *e

Track execution errors in *e

--- planck-cljs/src/planck/core.cljs
+++ planck-cljs/src/planck/core.cljs
@@ -236,4 +236,5 @@
               (when error
                 (print-error error))))
           (catch :default e
+            (set! *e e)
             (print-error e)))))))


return joins along with their pk

return joins along with their pk

--- dada2-core/src/test/clojure/org/dada2/test_join_model.clj
+++ dada2-core/src/test/clojure/org/dada2/test_join_model.clj
@@ -108,19 +108,21 @@

 (defn- derive-joins [rhs-indeces lhs-fk-keys lhs join-fn]
   (map
-   (fn [args] (apply join-fn lhs args))
+   (fn [rhses] (let [join (apply join-fn lhs rhses)] [(:name join) join])) ;TODO - pass in join-pk
    (permute [[]] (rhses-get rhs-indeces lhs-fk-keys lhs))))

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

 (defn- lhs-upsert [old-indeces lhs-pk-key lhs-fk-keys lhs join-fn joined-model]
   (let [new-indeces (lhs-assoc old-indeces lhs-pk-key lhs-fk-keys lhs)
-	joins (derive-joins (second new-indeces) lhs-fk-keys lhs join-fn)]
+	join-pairs (derive-joins (second new-indeces) lhs-fk-keys lhs join-fn)
+	joins (vals (reduce conj {} join-pairs))]
     [new-indeces (fn [_] (on-upserts joined-model joins))]))

 (defn- lhs-delete [old-indeces lhs-pk-key lhs-fk-keys lhs join-fn joined-model]
   (let [new-indeces (lhs-dissoc old-indeces lhs-pk-key lhs-fk-keys lhs)
-	joins (derive-joins (second new-indeces) lhs-fk-keys lhs join-fn)]
+	join-pairs (derive-joins (second new-indeces) lhs-fk-keys lhs join-fn)
+	joins (vals (reduce conj {} join-pairs))]
     [new-indeces (fn [_] (on-deletes joined-model joins))]))

 ;;; TODO
@@ -145,8 +147,11 @@
 	lhs-indeces (first old-indeces)
 	lhses (lhses-get lhs-indeces i fk)
 	rhs-indeces (second new-indeces)
-	joins (mapcat (fn [lhs] (derive-joins rhs-indeces lhs-fk-keys lhs join-fn)) lhses)
-	]
+	joins (mapcat
+	       (fn [lhs]
+		   (let [join-pairs (derive-joins rhs-indeces lhs-fk-keys lhs join-fn)]
+		     (vals (reduce conj {} join-pairs))))
+	       lhses)]
     [new-indeces (fn [_] (on-upserts joined-model joins))]
     ))

@@ -156,10 +161,14 @@
 	old-rhs-indeces (second old-indeces)
 	lhs-indeces (first old-indeces)
 	lhses (lhses-get lhs-indeces i fk)
-	old-joins (mapcat (fn [lhs] (derive-joins old-rhs-indeces lhs-fk-keys lhs join-fn)) lhses)
+	old-joins (mapcat
+		   (fn [lhs] (vals (reduce conj {} (derive-joins old-rhs-indeces lhs-fk-keys lhs join-fn))))
+		   lhses)
 	new-indeces (rhs-dissoc old-indeces i rhs-pk-key fk rhs)
 	new-rhs-indeces (second new-indeces)
-	new-joins (mapcat (fn [lhs] (derive-joins new-rhs-indeces lhs-fk-keys lhs join-fn)) lhses)
+	new-joins (mapcat
+		   (fn [lhs] (vals (reduce conj {} (derive-joins new-rhs-indeces lhs-fk-keys lhs join-fn))))
+		   lhses)
 	joins (remove (fn [i] (contains? (apply hash-set new-joins) i)) old-joins)
 	]
     [new-indeces (fn [_] (on-deletes joined-model joins))]


Add a reserved org slug.

Add a reserved org slug.

--- src/oc/storage/resources/org.clj
+++ src/oc/storage/resources/org.clj
@@ -48,7 +48,7 @@
                       "faq" "features" "forum" "forums" "founder" "founders" "help" "home"
                       "investor" "investors" "invite" "ios" "jobs" "login" "logout"
                       "news" "newsletter" "press" "pricing" "privacy" "profile" "register" "reset"
-                      "section" "sections" "signin" "signout" "signup"
+                      "section" "sections" "signin" "signout" "signup" "sign-up"
                       "subscription-completed" "team" "terms" "topic" "topics"
                       "update" "updates" "stuart" "sean" "iacopo" "nathan"})


Only choose from :ackers.

Only choose from :ackers.

--- src/onyx/peer/task_lifecycle.clj
+++ src/onyx/peer/task_lifecycle.clj
@@ -28,7 +28,7 @@
   (assoc m :ack-val (acker/gen-ack-value)))

 (defn add-acker-id [event m]
-  (let [peers (:peers @(:onyx.core/replica event))
+  (let [peers (get-in @(:onyx.core/replica event) [:ackers (:onyx.core/job-id event)])
         n (mod (.hashCode (:message m)) (count peers))]
     (assoc m :acker-id (nth peers n))))


Clear messenger buffer at task start

Clear messenger buffer at task start

--- src/onyx/peer/task_lifecycle.clj
+++ src/onyx/peer/task_lifecycle.clj
@@ -1,5 +1,5 @@
 (ns ^:no-doc onyx.peer.task-lifecycle
-    (:require [clojure.core.async :refer [alts!! <!! >!! <! >! timeout chan close! thread go]]
+    (:require [clojure.core.async :refer [alts!! alt!! <!! >!! <! >! timeout chan close! thread go]]
               [com.stuartsierra.component :as component]
               [taoensso.timbre :refer [info warn trace fatal level-compile-time] :as timbre]
               [rotating-seq.core :as rsc]
@@ -539,6 +539,12 @@
                       (operation/resolve-fn {:onyx/fn (:onyx/group-by-fn entry)})]))
               (into {}))))

+(defn clear-messenger-buffer!
+  "Clears the messenger buffer of all messages related to prevous task lifecycle.
+  In an ideal case, this might transfer messages over to another peer first as it help with retries."
+  [{:keys [inbound-ch] :as messenger-buffer}]
+  (while (first (alts!! [inbound-ch] :default false))))
+
 (defrecord TaskLifeCycle
     [id log messenger-buffer messenger job-id task-id replica peer-replica-view restart-ch
      kill-ch outbox-ch seal-resp-ch completion-ch opts task-kill-ch]
@@ -604,6 +610,7 @@

             pipeline-data (merge pipeline-data ((:onyx.core/compiled-before-task-start-fn pipeline-data) pipeline-data))]

+        (clear-messenger-buffer! messenger-buffer)
         (>!! outbox-ch (entry/create-log-entry :signal-ready {:id id}))

         (loop [replica-state @replica]


Filter out hamcrest assertions as well

Filter out hamcrest assertions as well

--- src/radicalzephyr/boot_junit.clj
+++ src/radicalzephyr/boot_junit.clj
@@ -57,7 +57,8 @@
             (println))))

       (defn- skip-assert-traces [traces]
-        (filter #(not= (:class %) "org.junit.Assert") traces))
+        (filter #(not (or (= (:class %) "org.junit.Assert")
+                          (= (:class %) "org.hamcrest.MatcherAssert"))) traces))

       (defn- take-until-reflection [traces]
         (take-while #(not (.contains (:class %) "reflect")) traces))
@@ -78,7 +79,7 @@
           (format "%s: %s\n       %s"
                   (:class ex-map)
                   (:message ex-map)
-                  (str/join "\n      " relevant-traces))))
+                  (str/join "\n       " relevant-traces))))

       (defn- print-failed-tests [test-failures]


Fix test

Fix test

--- test/obb_rules_api/index_test.clj
+++ test/obb_rules_api/index_test.clj
@@ -10,7 +10,7 @@
       (is (= (:status response) 200))
       (let [result (json/read-str (:body response))]
         (is (= "obb-rules-api" (result "name")))
-        (is (= "1.0.0-SNAPSHOT" (result "version"))))))
+        (is (= "1.0.0" (result "version"))))))

  (testing "not-found route"
     (let [response (app (request :get "/invalid"))]


(enable-console-print!)

(enable-console-print!)

--- radiolamp-6P3S/src/r6p3s/io.cljs
+++ radiolamp-6P3S/src/r6p3s/io.cljs
@@ -3,6 +3,8 @@
             [goog.net.EventType]
             [goog.events :as events]))

+
+(enable-console-print!)

 ;; (defn file-upload [form-e uri & [{:keys [success error complete] :as map-e->fns}]]


Remove requirement on ES6

Remove requirement on ES6

In the function encode-string-as-sha1, the character codes were
retrieved using .codePointAt() which is only available in ES6.
However, in this particular function there is no need to use this
function since the characters are always limited to 8-bit entities
anyway. This change replaces this call with a call to .charCodeAt()
which should be available everywhere.

--- web-app/src/cljs/potato/core.cljs
+++ web-app/src/cljs/potato/core.cljs
@@ -1106,7 +1106,7 @@
   ;; correctly.
   ;; See this bug report for details: https://github.com/google/closure-library/issues/470
   (let [digester (new js/goog.crypt.Sha1)]
-    (.update digester (clj->js (map (fn [x] (.codePointAt x 0)) (js/unescape (js/encodeURIComponent s)))))
+    (.update digester (clj->js (map (fn [x] (.charCodeAt x 0)) (js/unescape (js/encodeURIComponent s)))))
     (cljs.pprint/cl-format nil "~{~2,'0x~}" (.digest digester))))

 (defn- make-draft-message [text-string html]


Remove attempt at fail early logic (#108)

--- waiter/src/waiter/service.clj
+++ waiter/src/waiter/service.clj
@@ -213,8 +213,7 @@
             (statsd/histo! metric-group "get_instance" nanos))
           (counters/inc! (metrics/service-counter service-id "request-counts" "waiting-for-available-instance"))
           (statsd/gauge-delta! metric-group "request_waiting_for_instance" +1)
-          (let [expiry-time (t/plus (t/now) (t/millis queue-timeout-ms))
-                failed-instances-at-start (counters/value (metrics/service-counter service-id "instance-counts" "failed"))]
+          (let [expiry-time (t/plus (t/now) (t/millis queue-timeout-ms))]
             (loop [iterations 1]
               (let [instance (get-rand-inst instance-rpc-chan service-id reason-map #{} queue-timeout-ms)]
                 (if-not (nil? (:id instance)) ; instance is nil or :no-matching-instance-found
@@ -226,39 +225,37 @@
                   (if (and instance (not= instance :no-matching-instance-found))
                     ; instance is a deployment error if it (1) does not have an :id tag, (2) is not nil, and (3) does not equal :no-matching-instance-found
                     (ex-info (str "Deployment error: " (utils/message instance)) {:service-id service-id :status 503})
-                    (let [failed-instances (counters/value (metrics/service-counter service-id "instance-counts" "failed"))
-                          healthy-instances (counters/value (metrics/service-counter service-id "instance-counts" "healthy"))]
-                      (if-not (or (t/before? (t/now) expiry-time)
-                                  ; at least three failed instances since start and no healthy-instances
-                                  (and (zero? healthy-instances) (> (- failed-instances failed-instances-at-start) 3)))
-                        (do
-                          ;; No instances were started in a reasonable amount of time
-                          (meters/mark! (metrics/service-meter service-id "no-available-instance-timeout"))
-                          (statsd/inc! metric-group "no_instance_timeout")
-                          (let [outstanding-requests (counters/value (metrics/service-counter service-id "request-counts" "outstanding"))
-                                requests-waiting-to-stream (counters/value (metrics/service-counter service-id "request-counts" "waiting-to-stream"))
-                                waiting-for-available-instance (counters/value (metrics/service-counter service-id "request-counts" "waiting-for-available-instance"))
-                                unhealthy-instances (counters/value (metrics/service-counter service-id "instance-counts" "unhealthy"))]
-                            (ex-info (str "After " (t/in-seconds (t/millis queue-timeout-ms))
-                                          " seconds, no instance available to handle request."
-                                          (when (and (zero? healthy-instances) (or (pos? unhealthy-instances) (pos? failed-instances)))
-                                            " Check that your service is able to start properly!")
-                                          (when (and (pos? outstanding-requests) (pos? healthy-instances))
-                                            " Check that your service is able to scale properly!"))
-                                     {:service-id service-id
-                                      :outstanding-requests outstanding-requests
-                                      :requests-waiting-to-stream requests-waiting-to-stream
-                                      :waiting-for-available-instance waiting-for-available-instance
-                                      :slots-assigned (counters/value (metrics/service-counter service-id "instance-counts" "slots-assigned"))
-                                      :slots-available (counters/value (metrics/service-counter service-id "instance-counts" "slots-available"))
-                                      :slots-in-use (counters/value (metrics/service-counter service-id "instance-counts" "slots-in-use"))
-                                      :work-stealing-offers-received (counters/value (metrics/service-counter service-id "work-stealing" "received-from" "in-flight"))
-                                      :work-stealing-offers-sent (counters/value (metrics/service-counter service-id "work-stealing" "sent-to" "in-flight"))
-                                      :status 503})))
-                        (do
-                          (app-not-found-fn)
-                          (async/<! (async/timeout 1500))
-                          (recur (inc iterations)))))))))))
+                    (if-not (t/before? (t/now) expiry-time)
+                      (do
+                        ;; No instances were started in a reasonable amount of time
+                        (meters/mark! (metrics/service-meter service-id "no-available-instance-timeout"))
+                        (statsd/inc! metric-group "no_instance_timeout")
+                        (let [outstanding-requests (counters/value (metrics/service-counter service-id "request-counts" "outstanding"))
+                              requests-waiting-to-stream (counters/value (metrics/service-counter service-id "request-counts" "waiting-to-stream"))
+                              waiting-for-available-instance (counters/value (metrics/service-counter service-id "request-counts" "waiting-for-available-instance"))
+                              healthy-instances (counters/value (metrics/service-counter service-id "instance-counts" "healthy"))
+                              unhealthy-instances (counters/value (metrics/service-counter service-id "instance-counts" "unhealthy"))
+                              failed-instances (counters/value (metrics/service-counter service-id "instance-counts" "failed"))]
+                          (ex-info (str "After " (t/in-seconds (t/millis queue-timeout-ms))
+                                        " seconds, no instance available to handle request."
+                                        (when (and (zero? healthy-instances) (or (pos? unhealthy-instances) (pos? failed-instances)))
+                                          " Check that your service is able to start properly!")
+                                        (when (and (pos? outstanding-requests) (pos? healthy-instances))
+                                          " Check that your service is able to scale properly!"))
+                                   {:service-id service-id
+                                    :outstanding-requests outstanding-requests
+                                    :requests-waiting-to-stream requests-waiting-to-stream
+                                    :waiting-for-available-instance waiting-for-available-instance
+                                    :slots-assigned (counters/value (metrics/service-counter service-id "instance-counts" "slots-assigned"))
+                                    :slots-available (counters/value (metrics/service-counter service-id "instance-counts" "slots-available"))
+                                    :slots-in-use (counters/value (metrics/service-counter service-id "instance-counts" "slots-in-use"))
+                                    :work-stealing-offers-received (counters/value (metrics/service-counter service-id "work-stealing" "received-from" "in-flight"))
+                                    :work-stealing-offers-sent (counters/value (metrics/service-counter service-id "work-stealing" "sent-to" "in-flight"))
+                                    :status 503})))
+                      (do
+                        (app-not-found-fn)
+                        (async/<! (async/timeout 1500))
+                        (recur (inc iterations))))))))))
         (catch Exception e
           (log/error e "Error in get-available-instance")
           e)


helper fn to sort tracks

helper fn to sort tracks

because track sorting will have to get a lot more complicated

--- src-cljs/core.cljs
+++ src-cljs/core.cljs
@@ -95,6 +95,13 @@
            )
     channel))

+(defn sorted-tracks [tracks]
+  (sort-by
+   #(vector (get % "artist")
+            (get % "album")
+            (js/parseInt (get % "track")))
+   tracks))
+
 (defn results-view [results owner]
   (reify
     om/IWillMount
@@ -103,11 +110,7 @@
         (go (loop []
               (let [search-for (<! channel)
                     tracks (<! (xhr-search search-for))
-                    sorted (sort-by
-                            #(vector (get % "artist")
-                                     (get % "album")
-                                     (js/parseInt (get % "track")))
-                            tracks)]
+                    sorted (sorted-tracks tracks)]
                 (om/update! results (vec sorted))
                 (recur))))))
     om/IRenderState


detect mobility (e.g phone/tablet) on the fly

copes better with rotate/resize

--- src-cljs/core.cljs
+++ src-cljs/core.cljs
@@ -11,8 +11,15 @@

 (enable-console-print!)

-(defn mobile? [owner]
-  (= (om/get-shared owner :device-type) :phone))
+(defn detect-platform []
+  (let [w (.-innerWidth js/window)]
+    (condp > w
+      480 :phone
+      600 :tablet
+      :desktop)))
+
+(defn mobile? []
+  (= (detect-platform) :phone))

 (def app-state
   (atom
@@ -53,7 +60,7 @@
             button (dom/button #js {:onClick (fn [e] (put! enqueue @track))}
                                "+")]
         (apply dom/div #js {:className "track"}
-               (if (mobile? owner)
+               (if (mobile?)
                  [title artist album duration button]
                  [artist album title duration button]))))))

@@ -83,7 +90,7 @@
                           {:init-state
                            {:update-filters update-filters
                             :enqueue enqueue}})]
-        (if (mobile? owner)
+        (if (mobile?)
           (apply dom/div #js {:className "results tracks" }
                  (dom/div #js {:className "track"}
                           (dom/span {:id "queue-all-tracks"}
@@ -233,13 +240,6 @@
                                  })
                  )))))

-(defn detect-platform []
-  (let [w (.-innerWidth js/window)]
-    (condp > w
-      480 :phone
-      600 :tablet
-      :desktop)))
-
 (defn app-view [app owner]
   (reify
     om/IInitState


Doubled max points

Doubled max points

--- src/clojush/problems/software/sum_of_squares.clj
+++ src/clojush/problems/software/sum_of_squares.clj
@@ -127,7 +127,7 @@
 (def argmap
   {:error-function (sum-of-squares-error-function sum-of-squares-data-domains)
    :atom-generators sum-of-squares-atom-generators
-   :max-points 800
+   :max-points 1600
    :max-genome-size-in-initial-program 200
    :evalpush-limit 4000
    :population-size 1000


added guard for CustomEvent

added guard for CustomEvent

returning websocket from initialization code
commenting websocket message format

--- support/src/figwheel/client.cljs
+++ support/src/figwheel/client.cljs
@@ -138,6 +138,29 @@
   (set! (.-CLOSURE_IMPORT_SCRIPT (.-global js/goog)) figwheel-closure-import-script))

 (defn have-websockets? [] (js*  "(\"WebSocket\" in window)"))
+(defn have-custom-events? [] (js*  "(\"CustomEvent\" in window)"))
+
+;; handle messages coming over the WebSocket
+;; messages have the following formats
+
+;; files-changed message
+;; { :msg-name :files-changed
+;;   :files    [{:file "/js/compiled/out/example/core.js",
+;;               :type :javascript,
+;;               :msg-name :file-changed,
+;;               :namespace "example.core" }] }
+
+;; css-files-changed message
+;; there should really only be one file in here at a time
+;; { :msg-name :css-files-changed
+;;   :files    [{:file "/css/core.js",
+;;               :type :javascript }] }
+
+;; compile-failed message
+;; { :msg-name :compile-failed
+;;   :exception-data {:cause { ... lots of exception info ... } }}
+;; the exception data is nested raw info obtained for the compile time
+;; exception

 (defn watch-and-reload* [{:keys [retry-count websocket-url
                                  jsload-callback
@@ -166,12 +189,14 @@
                                                     (watch-and-reload*
                                                      (assoc opts :retry-count (dec retry-count))))
                                                   2000))))
-        (set! (.-onerror socket) (fn [x] (log opts "Figwheel: socket error ")))))))
+        (set! (.-onerror socket) (fn [x] (log opts "Figwheel: socket error ")))
+        socket))))

 (defn default-on-jsload [url]
-  (.dispatchEvent (.querySelector js/document "body")
-                  (js/CustomEvent. "figwheel.js-reload"
-                                   (js-obj "detail" url))))
+  (when (have-custom-events?)
+    (.dispatchEvent (.querySelector js/document "body")
+                    (js/CustomEvent. "figwheel.js-reload"
+                                     (js-obj "detail" url)))))

 (defn get-essential-messages [ed]
   (when ed


core.async: Change  all `(range 5)` to `[0 1 2 3 4]`.

--- test/com/nomistech/clojure_the_language/core_async_mapping_etc_test.clj
+++ test/com/nomistech/clojure_the_language/core_async_mapping_etc_test.clj
@@ -18,7 +18,7 @@

 (fact "About `a/map`"
   (chan->seq (a/map (partial * 100)
-                    [(a/to-chan (range 5))]))
+                    [(a/to-chan [0 1 2 3 4])]))
   => [0 100 200 300 400])

 (fact "About `a/reduce`"
@@ -34,7 +34,7 @@

 (fact "About `a/map<` (N.B. This is deprecated)"
   (chan->seq (a/map< (partial * 100)
-                     (a/to-chan (range 5))))
+                     (a/to-chan [0 1 2 3 4])))
   => [0 100 200 300 400])

 (fact "About `a/map>` (N.B. This is deprecated)"
@@ -42,7 +42,7 @@
         wrapping-ch (a/map> (partial * 100)
                             wrapped-ch)]
     (a/go
-      (doseq [i (range 5)]
+      (doseq [i [0 1 2 3 4]]
         (a/>! wrapping-ch i))
       (a/close! wrapping-ch))
     (chan->seq wrapped-ch))
@@ -50,7 +50,7 @@

 (fact "About `a/filter<` (N.B. This is deprecated)"
   (chan->seq (a/filter< even?
-                        (a/to-chan (range 5))))
+                        (a/to-chan [0 1 2 3 4])))
   => [0 2 4])

 (fact "About `a/filter>` (N.B. This is deprecated)"
@@ -58,7 +58,7 @@
         wrapping-ch (a/filter> even?
                                wrapped-ch)]
     (a/go
-      (doseq [i (range 5)]
+      (doseq [i [0 1 2 3 4]]
         (a/>! wrapping-ch i))
       (a/close! wrapping-ch))
     (chan->seq wrapped-ch))
@@ -66,7 +66,7 @@

 (fact "About `a/mapcat< (N.B. This is deprecated)"
   (chan->seq (a/mapcat< (fn [x] [x :plop])
-                        (a/to-chan (range 5))))
+                        (a/to-chan [0 1 2 3 4])))
   => [0 :plop 1 :plop 2 :plop 3 :plop 4 :plop])

 ;;;; ___________________________________________________________________________
@@ -74,19 +74,19 @@

 (fact "A `map` transducer"
   (let [c (a/chan 1 (map (partial * 100)))]
-    (a/onto-chan c (range 5))
+    (a/onto-chan c [0 1 2 3 4])
     (chan->seq c))
   => [0 100 200 300 400])

 (fact "Transducers do nothing when there is no buffer (when buffer size is 0)"
   (let [c (a/chan 0 (map (partial * 100)))]
-    (a/onto-chan c (range 5))
+    (a/onto-chan c [0 1 2 3 4])
     (chan->seq c))
-  => (range 5))
+  => [0 1 2 3 4])

 (fact "My second transducer example"
   (let [c (a/chan 1 (filter even?))]
-    (a/onto-chan c (range 5))
+    (a/onto-chan c [0 1 2 3 4])
     (chan->seq c))
   => [0 2 4])

@@ -97,12 +97,12 @@
   ;;    before mapping in this example)."
   (let [c (a/chan 1 (comp (filter even?)
                           (map (partial * 100))))]
-    (a/onto-chan c (range 5))
+    (a/onto-chan c [0 1 2 3 4])
     (chan->seq c))
   => [0 200 400])

 (fact "A `mapcat` transducer"
   (let [c (a/chan 1 (mapcat (fn [x] [x x])))]
-    (a/onto-chan c (range 5))
+    (a/onto-chan c [0 1 2 3 4])
     (chan->seq c))
   => [0 0 1 1 2 2 3 3 4 4])


:bug: Fixes counters in libraries popup

:bug: Fixes counters in libraries popup

--- frontend/src/app/main/ui/workspace/libraries.cljs
+++ frontend/src/app/main/ui/workspace/libraries.cljs
@@ -9,6 +9,7 @@
   (:require
    [rumext.alpha :as mf]
    [cuerdas.core :as str]
+   [okulary.core :as l]
    [app.util.dom :as dom]
    [app.util.i18n :as i18n :refer [t tr]]
    [app.util.data :refer [classnames matches-search]]
@@ -17,6 +18,9 @@
    [app.main.data.workspace :as dw]
    [app.main.ui.icons :as i]
    [app.main.ui.modal :as modal]))
+
+(def workspace-file
+  (l/derived :workspace-file st/state))

 (mf/defc libraries-tab
   [{:keys [file libraries shared-files] :as props}]
@@ -50,32 +54,30 @@
         (mf/use-callback (mf/deps file) #(st/emit! (dw/unlink-file-from-library (:id file) %)))

         contents-str
-        (fn [library graphics-count colors-count]
-          ;; Include a   so this block has always some content
-          (str
-           (str/join " · "
-                     (cond-> []
-                       (< 0 graphics-count)
-                       (conj (tr "workspace.libraries.graphics" graphics-count))
+        (fn [library]
+          (let [graphics-count (count (get-in library [:data :media] []))
+                colors-count (count (get-in library [:data :colors] []))]
+            ;; Include a   so this block has always some content
+            (str
+             (str/join " · "
+                       (cond-> []
+                         (< 0 graphics-count)
+                         (conj (tr "workspace.libraries.graphics" graphics-count))

-                       (< 0 colors-count)
-                       (conj (tr "workspace.libraries.colors" colors-count))))
-           "\u00A0"))]
+                         (< 0 colors-count)
+                         (conj (tr "workspace.libraries.colors" colors-count))))
+             "\u00A0")))]
     [:*
      [:div.section
       [:div.section-title (tr "workspace.libraries.in-this-file")]
       [:div.section-list
        [:div.section-list-item
         [:div.item-name (tr "workspace.libraries.file-library")]
-        [:div.item-contents (contents-str file
-                                          (count (:media-objects file))
-                                          (count (:colors file)))]]
+        [:div.item-contents (contents-str file)]]
        (for [library sorted-libraries]
          [:div.section-list-item {:key (:id library)}
           [:div.item-name (:name library)]
-          [:div.item-contents (contents-str library
-                                            (count (:media-objects library))
-                                            (count (:colors library)))]
+          [:div.item-contents (contents-str library)]
           [:input.item-button {:type "button"
                                :value (tr "workspace.libraries.remove")
                                :on-click #(unlink-library (:id library))}]])
@@ -99,9 +101,7 @@
          (for [file filtered-files]
            [:div.section-list-item {:key (:id file)}
             [:div.item-name (:name file)]
-            [:div.item-contents (contents-str file
-                                              (:graphics-count file)
-                                              (:colors-count file))]
+            [:div.item-contents (contents-str file)]
             [:input.item-button {:type "button"
                                  :value (tr "workspace.libraries.add")
                                  :on-click #(link-library (:id file))}]])]
@@ -125,7 +125,7 @@

         locale       (mf/deref i18n/locale)
         project      (mf/deref refs/workspace-project)
-        file         (mf/deref refs/workspace-file)
+        file         (mf/deref workspace-file)
         libraries    (mf/deref refs/workspace-libraries)
         shared-files (mf/deref refs/workspace-shared-files)


Update lein-ancient to v0.5.5

Update lein-ancient to v0.5.5

--- roles/clojure/files/profiles.clj
+++ roles/clojure/files/profiles.clj
@@ -10,7 +10,7 @@
         :plugins [[cider/cider-nrepl "0.7.0-SNAPSHOT"]
                   [codox "0.6.6"]
                   [jonase/eastwood "0.1.4"]
-                  [lein-ancient "0.5.4" :exclusions [commons-codec]]
+                  [lein-ancient "0.5.5" :exclusions [commons-codec]]
                   [lein-cljsbuild "1.0.0"]
                   [lein-clojars "0.9.1"]
                   [lein-cloverage "1.0.2"]


cleanup

cleanup

--- src/babel/html.clj
+++ src/babel/html.clj
@@ -602,73 +602,6 @@
     [:a {:href link}
      name ]]))

-(defn footer []
-  (html
-   [:div {:class "poweredbox major"}
-    [:h2 [:i "imparare l'Italiano"] " è alimentato da .."]
-    [:table
-     [:tr
-      [:td {:colspan "5"}
-       [:div {:class "groupinglabel"}
-        (powered-by "italianquiz" "https://github.com/ekoontz/italianquiz")]
-
-       [:table {:class "italianquiz"}
-        [:tr
-         [:td {:colspan "3"}
-          [:div {:class "groupinglabel2"}
-           [:span {:class "label"} "app layer"]
-           [:table {:class "groupinglabel2"}
-            [:tr
-             [:td {:colspan "1"}
-              (powered-by "quiz" "https://github.com/ekoontz/italianquiz/tree/master/src/italianverbs/quiz.clj")]
-             [:td {:colspan "1"}
-              (powered-by "workbook" "https://github.com/ekoontz/italianquiz/tree/master/src/italianverbs/workbook.clj")]
-             [:td {:colspan "1"}
-              "others.."]]]]]]
-
-         [:tr
-          [:td {:colspan "3"}
-           (powered-by "forest" "https://github.com/ekoontz/italianquiz/tree/master/src/italianverbs/forest.clj")
-           ]
-          ]
-         [:tr
-          [:td
-           (powered-by "grammar" "https://github.com/ekoontz/italianquiz/tree/master/src/italianverbs/grammar.clj")]
-          [:td {:rowspan "1"}
-           (powered-by "lexicon" "https://github.com/ekoontz/italianquiz/tree/master/src/italianverbs/lexicon.clj")
-           ]
-          [:td {:rowspan "1"}
-           (powered-by "morphology" "https://github.com/ekoontz/italianquiz/tree/master/src/italianverbs/morphology.clj")
-           ]
-          ]
-
-         [:tr
-          [:td {:colspan "3"}
-           (powered-by "dag-unify" "https://github.com/ekoontz/dag-unify")
-           ]
-          ]
-
-         ]]]
-     [:tr
-      [:td {:colspan "2"}
-       (powered-by "compojure" "https://github.com/weavejester/compojure")]
-      [:td {:rowspan "2" :colspan "1"}
-       (powered-by "clojail" "https://github.com/flatland/clojail")]
-      [:td {:rowspan "2" :colspan "2"}
-       (powered-by "korma" "https://sqlkorma.com")]]
-      [:tr
-       [:td {:colspan "2"}
-        (powered-by "ring" "https://github.com/mmcgrana/ring")]]
-     [:tr
-      [:td
-       (powered-by "jetty" "http://jetty.codehaus.org/jetty/")]
-      [:td {:colspan "3"}
-       (powered-by "clojure" "http://clojure.org/")]
-      [:td {:colspan "1"}
-       (powered-by "postgres" "http://www.postgresql.org/")
-       ]]]]))
-
-
 (defn includes-js [includes]
   (if (not (empty? includes))
     (do


Use #'cats.context/get-current

Use #'cats.context/get-current

... instead of the deprecated #'cats.core/get-current-context

--- src/cats/core.cljc
+++ src/cats/core.cljc
@@ -530,7 +530,7 @@
   "
   ([f z xs]
    (if (empty? xs)
-     (return (get-current-context) z)
+     (return (ctx/get-current) z)
      (let [[h & t] xs]
        (mlet [z' (f z h)]
          (if (empty? t)


parinfer formatting

parinfer formatting

--- src-cljs/cuttle/projects.cljs
+++ src-cljs/cuttle/projects.cljs
@@ -38,21 +38,19 @@
   (log-info "parsing project:" filename)
   (let [contents (replace contents "#(" "(") ;; prevent "Could not find tag parser for" error
         prj1 (try-read-string contents)]
-        (if (contains? prj1 :error)
-          ;; then
-          (assoc prj1
-                 :filename filename
-                 :name filename
-                 :cljsbuild {})
-          ;; else
-          (let [project (apply hash-map (drop 3 prj1))
-                cljsbuild (when-let [opts (:cljsbuild project)]
-                            (normalize-cljsbuild-opts opts))]
-            (assoc project
-                   :cljsbuild cljsbuild
-                   :filename filename
-                   :name (name (nth prj1 1))
-                   :version (nth prj1 2))))))
+    (if (contains? prj1 :error)
+      ;; then
+      (assoc prj1 :filename filename
+                  :name filename
+                  :cljsbuild {})
+      ;; else
+      (let [project (apply hash-map (drop 3 prj1))
+            cljsbuild (when-let [opts (:cljsbuild project)]
+                        (normalize-cljsbuild-opts opts))]
+        (assoc project :cljsbuild cljsbuild
+                       :filename filename
+                       :name (name (nth prj1 1))
+                       :version (nth prj1 2))))))

 ;; TODO: Refactor this
 (defn- check-builds
@@ -63,12 +61,11 @@
     (if (and (not (empty? out-dirs)) (not (empty? out-paths)))
       ;; then
       (if-not (and (apply distinct? out-dirs)
-                 (apply distinct? out-paths))
+                   (apply distinct? out-paths))
         ;; then
-        (assoc prj
-               :error (str "Error: "
-                           "output-to and output-dir must be distinct "
-                           "in the builds profile."))
+        (assoc prj :error (str "Error: "
+                               "output-to and output-dir must be distinct "
+                               "in the builds profile."))
         ;; else
         prj)
       ;; else
@@ -83,7 +80,7 @@
           path (path-dirname filename)
           cljsbuild (<! (get-cljsbuild-with-profiles path))
           cljsbuild2 (normalize-cljsbuild-opts cljsbuild)]
-            (assoc project :cljsbuild cljsbuild2))))
+      (assoc project :cljsbuild cljsbuild2))))

 ;; TODO:
 ;; - need to do some quick validation of project.clj


Add vcs-type to the invite-teammates-org route

--- src-cljs/frontend/routes.cljs
+++ src-cljs/frontend/routes.cljs
@@ -201,8 +201,9 @@
     (open-to-inner! nav-ch :project-insights {:org org :repo repo :branch branch :vcs_type (->lengthen-vcs short-vcs-type)}))
   (defroute v1-invite-teammates "/invite-teammates" []
     (open-to-inner! nav-ch :invite-teammates {}))
-  (defroute v1-invite-teammates-org "/invite-teammates/organization/:org" [org]
-    (open-to-inner! nav-ch :invite-teammates {:org org}))
+  (defroute v1-invite-teammates-org #"/invite-teammates/organization/(gh|bb)/([^/]+)" [short-vcs-type org]
+    (open-to-inner! nav-ch :invite-teammates {:vcs_type (->lengthen-vcs short-vcs-type)
+                                              :org org}))
   (defroute v1-account "/account" []
     (open-to-inner! nav-ch :account {:subpage :notifications}))
   (defroute v1-account-subpage "/account/:subpage" [subpage]


Shutdown the exchange properly

Shutdown the exchange properly

--- web/src/immutant/web/undertow.clj
+++ web/src/immutant/web/undertow.clj
@@ -97,10 +97,12 @@

 (defn handle-request [f ^HttpServerExchange exchange]
   (.startBlocking exchange)
-  (with-open [output-stream (.getOutputStream exchange)]
+  (try
     (if-let [response (f (ring-request exchange))]
       (write-response exchange response)
-      (throw (NullPointerException. "Ring handler returned nil")))))
+      (throw (NullPointerException. "Ring handler returned nil")))
+    (finally
+      (.endExchange exchange))))

 (defn create-http-handler [handler]
   (reify HttpHandler


support undertow ajp listener

support undertow ajp listener

--- web/src/immutant/web/undertow.clj
+++ web/src/immutant/web/undertow.clj
@@ -42,19 +42,22 @@
   instance set accordingly, mapped to :configuration in the return
   value. If :ssl-port is non-nil, either :ssl-context or :key-managers
   should be set, too"
-  [{:keys [configuration host port ssl-port ssl-context key-managers trust-managers]
+  [{:keys [configuration host port ssl-port ssl-context key-managers trust-managers ajp?]
     :or {host "localhost"}
     :as options}]
+  (when (and ajp? (not-every? nil? [ssl-port ssl-context key-managers]))
+    (throw (IllegalArgumentException. "Don't use SSL options(:ssl-port :ssl-context :key-managers) with Ajp")))
   (when (and ssl-port (every? nil? [ssl-context key-managers]))
     (throw (IllegalArgumentException. "Either :ssl-context or :key-managers is required for SSL")))
   (let [^Undertow$Builder builder (or configuration (Undertow/builder))]
     (-> options
       (assoc :configuration
         (cond-> builder
+          (and port ajp?) (.addAjpListener port host)
           (and ssl-port ssl-context)  (.addHttpsListener ssl-port host ssl-context)
           (and ssl-port key-managers) (.addHttpsListener ssl-port host key-managers trust-managers)
-          port (.addHttpListener port host)))
-      (dissoc :host :port :ssl-port :ssl-context :key-managers :trust-managers))))
+          (and port (not ajp?)) (.addHttpListener port host)))
+      (dissoc :host :port :ssl-port :ssl-context :key-managers :trust-managers :ajp?))))

 (defn client-auth
   "Possible values are :want or :need (:requested and :required are


Update some site data

Update some site data

--- _config.clj
+++ _config.clj
@@ -22,9 +22,9 @@
  :lang "en"

  ;; default site data
- :site {:atom-base  "http://www.pbarnett.me"
+ :site {:atom-base  "http://www.peterb.name"
         :charset    "utf-8"
-        :site-title "Pance's Blog"
+        :site-title "Peter Barnett"
         :twitter    "pance888"
         :css        #_["http://fonts.googleapis.com/css?family=Josefin+Sans"
                      "/css/main.css"


Got score pair looking awful

Got score pair looking awful

--- yatzy-clj/src/yatzy_clj/yatzy.clj
+++ yatzy-clj/src/yatzy_clj/yatzy.clj
@@ -81,19 +81,18 @@
     )
   )

-
-
-
 (defn score_pair [dice]
-  (let [tallies (tally-die dice)
-
-
-
-        result (->> (range 0 5)
-                    (map #(- 5 %))
-                    (filter #(> (nth tallies %) 1))
-                    (map #(* (+ % 1) 2))
-                    (first))]
+  (let [counts (tally-die dice)
+      result (first
+               (remove nil?
+                       (for [at (range 0 6)]
+                         (if (>= (nth counts (- 6 at 1)) 2)
+                           (* (- 6 at) 2)
+                           nil
+                           )
+                         )
+                       )
+               )]
     (if (= nil result) 0 result)))

 (defn two-pair [dice]


dependencies are fine with soon-to-be preview9

--- profiles.clj
+++ profiles.clj
@@ -6,6 +6,6 @@
        (use '[table.core :only (table)])
        (use '[clojure.repl :only (dir-fn)])
        (load-file (str (System/getProperty "user.home") "/.lein/user.clj"))) }
- :dependencies {table "0.3.2" com.datomic/datomic "0.1.3164" clj-stacktrace "0.2.4"}
+   :dependencies {table "0.3.2" com.datomic/datomic "0.1.3164"}
  }
 }


Fix profiles commenting error

Fix profiles commenting error

--- profiles.clj
+++ profiles.clj
@@ -12,4 +12,4 @@
  {:plugins [[lein-set-version "0.3.0"]]
   :set-version
   {:updates [{:path "README.md" :no-snapshot true}]}}
- :no-checkouts {:checkout-deps-shares ^:replace []} ; disable checkouts}
+ :no-checkouts {:checkout-deps-shares ^:replace []}} ; disable checkouts


Fix invalid code failing to reset

Fix invalid code failing to reset

The metadata copying causes an unusual bug in relation to reload with
reset/halt failing.

--- lib.app.dev/src/dev_extras.clj
+++ lib.app.dev/src/dev_extras.clj
@@ -11,11 +11,7 @@
 (defmacro ^:private proxy-ns
   [ns & vars]
   (cons `do
-        (map (fn [v] `(do
-                        (def ~v ~(symbol (str ns) (str v)))
-                        (alter-meta!
-                          (resolve '~v)
-                          (constantly (meta (resolve '~(symbol (str ns) (str v)))))))) vars)))
+        (map (fn [v] `(def ~v ~(symbol (str ns) (str v)))) vars)))

 (proxy-ns integrant.repl clear halt prep init reset reset-all)


Fix #73 Stack parsing tripped up by http source

--- Clojure/src/ambly/repl/jsc.clj
+++ Clojure/src/ambly/repl/jsc.clj
@@ -10,7 +10,8 @@
   (:import java.net.Socket
            java.lang.StringBuilder
            [java.io File BufferedReader BufferedWriter IOException]
-           (javax.jmdns JmDNS ServiceListener)))
+           (javax.jmdns JmDNS ServiceListener)
+           (java.net URI)))

 (defn sh
   [& args]
@@ -155,24 +156,47 @@
           (when-not (.isClosed (:socket @(:socket repl-env)))
             (.printStackTrace e)))))))

+(defn source-uri->file
+  "Takes a source URI and returns a file value suitable for inclusion
+  in a canonical stack frame."
+  [source-uri opts]
+  {:pre [(string? source-uri) (map? opts)]}
+  (let [uri (URI. source-uri)
+        uri-scheme (.getScheme uri)]
+    (case uri-scheme
+      "file" (let [uri-path (.getPath uri)
+                   relative-path (if (.startsWith uri-path "/")
+                                   (subs uri-path 1)
+                                   uri-path)]
+               (str (io/file (util/output-directory opts) relative-path)))
+      (str "<" source-uri ">"))))
+
 (defn stack-line->canonical-frame
   "Parses a stack line into a frame representation, returning nil
   if parse failed."
   [stack-line opts]
-  {:pre [(string? stack-line) (map? opts)]}
-  (let [[function file line column]
-        (rest (re-matches #"(.*)@file:///(.*):([0-9]+):([0-9]+)"
+  {:pre  [(string? stack-line) (map? opts)]}
+  (let [[function source-uri line column]
+        (rest (re-matches #"(.*)@(.*):([0-9]+):([0-9]+)"
                 stack-line))]
-    (if (and file function line column)
-      {:file     (str (io/file (util/output-directory opts) file))
+    (if (and source-uri function line column)
+      {:file     (source-uri->file source-uri opts)
        :function function
        :line     (Long/parseLong line)
        :column   (Long/parseLong column)}
-      (when-not (string/blank? stack-line)
-        {:file nil
-         :function (string/trim stack-line)
-         :line nil
-         :column nil}))))
+      (let [[source-uri line column]
+            (rest (re-matches #"(.*):([0-9]+):([0-9]+)"
+                              stack-line))]
+        (if (and source-uri line column)
+          {:file     (source-uri->file source-uri opts)
+           :function nil
+           :line     (Long/parseLong line)
+           :column   (Long/parseLong column)}
+          (when-not (string/blank? stack-line)
+            {:file     nil
+             :function (string/trim stack-line)
+             :line     nil
+             :column   nil}))))))

 (defn raw-stacktrace->canonical-stacktrace
   "Parse a raw JSC stack representation, parsing it into stack frames.
@@ -371,7 +395,9 @@
                          file-path))
                      (str url)))]
       (doseq [{:keys [function file url line column]}
-              (repl/mapped-stacktrace stacktrace build-options)]
+              (map #(merge-with (fn [a b] (or a b)) %1 %2)
+                   (repl/mapped-stacktrace stacktrace build-options)
+                   stacktrace)]
         (let [url (when url (string/trim (.toString url)))
               file (when file (string/trim (.toString file)))]
           (println


now that I've sorted out my deps issue, use all dem jars

--- profiles.clj
+++ profiles.clj
@@ -4,8 +4,11 @@
    :repl-options {
      :init (do
        (use '[table.core :only (table)])
+       (use 'desc.core)
+       (use 'rubydoc.core)
        (use '[clojure.repl :only (dir-fn)])
        (load-file (str (System/getProperty "user.home") "/.lein/user.clj"))) }
-   :dependencies {table "0.3.2" com.datomic/datomic "0.1.3164"}
+   :dependencies [[table "0.3.2"] [com.datomic/datomic "0.1.3164"] [desc "0.1.0"]
+                  [rubydoc "0.2.0"]]
  }
 }


Horrible horrible hack to work around bad sqlite locking behaviour.

Fixes #105, I think.

--- src/clojars/db.clj
+++ src/clojars/db.clj
@@ -47,6 +47,20 @@
 (defentity users)
 (defentity groups)
 (defentity jars)
+
+;; über-hack to work around hard-coded sqlite busy-timeout:
+;; https://github.com/ato/clojars-web/issues/105
+;; http://sqlite.org/c3ref/busy_timeout.html
+;; https://bitbucket.org/xerial/sqlite-jdbc/issue/27
+(defonce _
+  (alter-var-root #'clojure.java.jdbc.internal/prepare-statement*
+                  (fn [prepare]
+                    (fn timeout-prepare [& args]
+                      (let [stmt (apply prepare args)]
+                        (doto stmt
+                          ;; Note that while .getQueryTimeout returns
+                          ;; milliseconds, .setQueryTimeout takes seconds!
+                          (.setQueryTimeout 30)))))))

 (defn split-keys [s]
   (map str/trim (str/split s #"\s*\n\s*")))


Provide more realistic test cases

Provide more realistic test cases

--- spec/rook/swagger_spec.clj
+++ spec/rook/swagger_spec.clj
@@ -90,18 +90,17 @@
             ": bar desc"
             ""
             "baz"
-            ":baz desc"
+            ": baz desc"
             "")
           (sw/cleanup-indentation-for-markdown
-            (join-lines
-              "foo"
-              "  "
-              "  bar"
-              "  : bar desc"
-              "  "
-              "  baz"
-              "  :baz desc"
-              "  "))))
+            "foo
+
+            bar
+            : bar desc
+
+            baz
+            : baz desc
+            ")))

     (it "handles edge cases"

@@ -113,7 +112,8 @@
         (let [input "multiple lines\r\nwithout\nindentation"]
           (should-be-same input (sw/cleanup-indentation-for-markdown input)))

-        (let [input "only a single\n  line is indented"]
+        (let [input "only a single
+        line is indented"]
           (should-be-same input (sw/cleanup-indentation-for-markdown input)))))

   (context "requests"


Debug derive js adapt implementation result

--- backend/src/akvo/lumen/lib/transformation/engine.clj
+++ backend/src/akvo/lumen/lib/transformation/engine.clj
@@ -450,7 +450,9 @@
          columns         new-columns
          applied-txs     []]
     (if-let [transformation (first transformations)]
-      (let [transformation       (adapt-transformation transformation old-columns columns)
+      (let [_ (log/error :before-adapt-transformation :apply-dataset-transformations-on-table transformation)
+            transformation       (adapt-transformation transformation old-columns columns)
+            _ (log/error :after-adapt-transformation :apply-dataset-transformations-on-table transformation)
             avoid-tranformation? (let [t (w/keywordize-keys transformation)]
                                    (and
                                     (avoidable-if-missing? t)


Upload with a request

Upload with a request

--- src/airhead_cljs/core.cljs
+++ src/airhead_cljs/core.cljs
@@ -1,16 +1,12 @@
 (ns airhead-cljs.core
   (:require-macros [cljs.core.async.macros :refer [go]])
   (:require [reagent.core :as r]
-            [ajax.core :refer [GET PUT]]))
+            [ajax.core :refer [GET POST PUT]]))

 (defn get-json [url handler params]
   (GET url {:handler handler
             :params params
             :response-format :json}))
-
-(defn enqueue-track [track]
-  (let [uuid (track "uuid")]
-    (PUT (str "/api/queue/" uuid))))

 ;; -------------------------
 ;; Views
@@ -30,7 +26,8 @@

 (defn enqueue-button [track]
   [:input {:type "button" :value "Enqueue"
-           :on-click #(enqueue-track track)}])
+           :on-click #(PUT (str "/api/queue/"
+                                (track "uuid")))}])

 (defn tracks-list [tracks]
   [:ul (for [track @tracks]
@@ -38,11 +35,16 @@
           [enqueue-button track]
           [track-span track]])])

+(defn post-track []
+  (let [form (.getElementById js/document "upload-form")]
+    (POST "/api/tracks" {:enc-type "multipart/form-data"
+                         :body (js/FormData. form)})))
+
 (defn upload-form []
-  [:form {:enc-type "multipart/form-data"
-          :method "POST" :action "/api/tracks"}
+  [:form {:id "upload-form"}
    [:input {:type "file" :name "track"}]
-   [:input {:type "submit" :value "Upload"}]])
+   [:input {:type "button" :value "Upload"
+            :on-click post-track}]])

 (defn tracks-section []
   (let [tracks (r/atom [])


Fix upload

Fix upload

--- src/airhead_cljs/core.cljs
+++ src/airhead_cljs/core.cljs
@@ -79,9 +79,9 @@
 (defn upload-component []
   [:section#upload
    [:h2 "Upload"]
-   [:form {:id "upload"}
+   [:form {:id "upload-form"}
     [:input {:type "file" :name "track"}]
-    [:input {:type "button" :value "Upload" :on-submit upload!}]]
+    [:input {:type "button" :value "Upload" :on-click upload!}]]
    [:p (@state :upload-status)]])

 (defn playlist-add-component [track]


Simplify tx->* functions

Simplify tx->* functions

--- src/datemo/arb.clj
+++ src/datemo/arb.clj
@@ -10,6 +10,29 @@

 (defn get-in-metadata [k metadata]
   (k (first (filter #(k %) metadata))))
+
+(defn walk-tx-fn [wrap-node process-node]
+  (fn walk [tx]
+    (let [{metadata :arb/metadata, nodes :arb/value} tx]
+      (clojure.pprint/pprint {:metadata metadata, :nodes nodes})
+      (wrap-node
+       metadata
+       (apply vector (for [node nodes]
+                       (if (:content/text node)
+                         (process-node node)
+                         (walk node))))))))
+
+(defn tx->html [tx]
+  (-> tx (tx->arb) (arb->hiccup) (html)))
+
+(defn tx->arb [tx]
+  (let [process-node #(:content/text %)
+        wrap-node    #(vec
+                       (concat
+                        [:arb {:original-tag (get-in-metadata :metadata/html-tag %1)}]
+                        %2))
+        convert      (walk-tx-fn wrap-node process-node)]
+    (convert tx)))

 (defn walk-arb-fn [wrap-node process-node]
   (fn walk [arb]
@@ -35,16 +58,6 @@
         convert (walk-arb-fn wrap-node proccess-node)]
     (convert arb)))

-(defn html->hiccup
-  ([html] (as-hiccup (parse html)))
-  ([html as-fragment]
-   (if (false? as-fragment)
-     (html->hiccup html)
-     (let [result (map as-hiccup (parse-fragment html))]
-       (if (not= 1 (count result))
-         (into [:div {}] result)
-         (first result))))))
-
 (defn hiccup->arb [hiccup]
   (let [[tag attrs & value] hiccup]
     (if (or (nil? value) (and (= 1 (count value) (string? (first value)))))
@@ -56,6 +69,16 @@
             (recur (conj values (first items)) (next items))
             (recur (conj values (hiccup->arb (first items))) (next items))))))))

+(defn html->hiccup
+  ([html] (as-hiccup (parse html)))
+  ([html as-fragment]
+   (if (false? as-fragment)
+     (html->hiccup html)
+     (let [result (map as-hiccup (parse-fragment html))]
+       (if (not= 1 (count result))
+         (into [:div {}] result)
+         (first result))))))
+
 (defn html->arb
   ([html] (html->arb html true))
   ([html as-fragment]
@@ -63,25 +86,7 @@
     (hiccup->arb (html->hiccup html)))
     (hiccup->arb (html->hiccup html as-fragment))))

-(defn tx->arb [tx]
-  (let [{metadata :arb/metadata value :arb/value} tx]
-    (if (and (= 1 (count value)) (not (nil? (:content/text (first value)))))
-      [:arb
-       {:original-tag (get-in-metadata :metadata/html-tag metadata)}
-       (:content/text (first value))]
-      (loop [arbs [], items value]
-        (if (= 0 (count items))
-          (into
-            [:arb {:original-tag (:metadata/html-tag (first metadata))}]
-            arbs)
-          (recur
-            (conj arbs (if-not (arb? (first items))
-                         (:content/text (first items)) ;; If it's not an arb it must be a :content/text
-                         (tx->arb (first items)))) (next items)))))))
-
 (defn html->tx [html & metadata]
   (let [tx (-> html (html->arb) (arb->tx))]
     (assoc tx :arb/metadata (into (:arb/metadata tx) metadata))))

-(defn tx->html [tx]
-  (-> tx (tx->arb) (arb->hiccup) (html)))


Make site traversal test quit early

Make site traversal test quit early

When not all dependencies are defined.

--- test/comic_reader/sites_test.clj
+++ test/comic_reader/sites_test.clj
@@ -177,20 +177,21 @@
   (tu/ensure-dependencies-defined get-image-data))

 (defn test-full-site-traversal [site]
-  (call-with-options site #(ensure-all-dependencies))
-
-  (is (not
-       (nil?
-        (let [site ((get-sites) site-name)
-              comic-list (get-comic-list site)
-              first-comic (first comic-list)
-
-              chapter-list (get-chapter-list site (:id first-comic))
-              last-chapter (last chapter-list)
-
-              page-list (get-page-list site last-chapter)
-              third-page (nth 3 page-list)]
-          (get-image-data site third-page))))))
+  (and
+   (call-with-options site #(ensure-all-dependencies))
+
+   (is (not
+        (nil?
+         (let [site ((get-sites) site-name)
+               comic-list (get-comic-list site)
+               first-comic (first comic-list)
+
+               chapter-list (get-chapter-list site (:id first-comic))
+               last-chapter (last chapter-list)
+
+               page-list (get-page-list site last-chapter)
+               third-page (nth 3 page-list)]
+           (get-image-data site third-page)))))))

 (defn testdef-form [site-name]
   `(deftest ~(symbol (str site-name "-test"))