Remove unused (commented) spec assertions

--- src/tick/interval.cljc
+++ src/tick/interval.cljc
@@ -18,17 +18,6 @@
 ;; Use of Allen's Interval Algebra, inspired from a working
 ;; demonstration of time-count by Eric Evans.

-(s/def ::local (s/and #(t/local? (t/beginning %)) #(t/local? (t/end %))))
-(s/def ::non-local (s/and #(not (t/local? (t/beginning %))) #(not (t/local? (t/end %)))))
-
-(s/def ::interval
-  (s/and
-    (s/or :local ::local :non-local ::non-local)
-    #(let [[_ t] %]
-       (let [t1 (t/beginning t)
-             t2 (t/end t)]
-         (t/< t1 t2)))))
-
 (defrecord Interval [beginning end]
   t/ITimeSpan
   (beginning [_] beginning)
@@ -195,8 +184,6 @@
 (defrecord GeneralRelation [relations]
   #?(:clj clojure.lang.IFn :cljs cljs.core/IFn)
   (#?(:clj invoke :cljs -invoke) [_ x y]
-    #_(s/assert ::interval x)
-    #_(s/assert ::interval y)
     (some (fn [f] (when (f x y) f)) relations)))

 ;; Relations are 'basic relations' in [ALSPAUGH-2009]. Invoking a
@@ -707,7 +694,7 @@
   (group-by [grouping ivals]))

 (extend-protocol IGroupable
-  #?(:clj clojure.lang.Fn :cljs function)
+  #?(:clj clojure.lang.Fn :cljs function)
   (group-by [f ivals]
     (if (empty? ivals)
       {}
@@ -716,10 +703,10 @@
             e (f (t/end r))
             groups (t/range b (t/inc e))]
         (group-by groups ivals))))
-  #?(:clj Iterable :cljs LazySeq)
+  #?(:clj Iterable :cljs LazySeq)
   (group-by [groups ivals]
     (group-by-intervals groups ivals))
-  #?(:cljs PersistentVector)
+  #?(:cljs PersistentVector)
   #?(:cljs
      (group-by [groups ivals]
        (group-by-intervals groups ivals))))


Apply h2 defaults if user sets none.

Apply h2 defaults if user sets none.

--- src/cavm/core.clj
+++ src/cavm/core.clj
@@ -131,13 +131,43 @@
   (when (not (.exists (io/file dir)))
     (str "Unable to create directory: " dir)))

+; Use MVCC so our bulk writes don't block readers.
+;
+; Use LOG=0 because otherwise bulk writes are pathologically slow, and we don't
+; need to worry about dropping data. A problem with LOG=0 is that we can't tell
+; if the db shut down cleanly, so we don't know when to recover. We might be able
+; to partly mitigate this by periodically closing & opening the db (maybe once or
+; twice a day?). We shouldn't lose transactions committed before the last close,
+; and we can detect files that we've lost due to unclean shutdown.
+;
+; UNDO_LOG allows us to add a dataset atomically (i.e. rollback on error).
+;
+; A more idiomatic usage of h2 would be to break the bulk write into chunks and use
+; LOG=1 or LOG=2. This would require building another "transaction" system over
+; the transaction system, flagging incompletely loaded datasets such that readers
+; could filter those results out of their queries. It would add a lot of complexity.
+(def default-h2-opts ";CACHE_SIZE=65536;UNDO_LOG=1;LOG=0;MVCC=TRUE")
+
+; Might want to allow more piecemeal setting of options, by
+; parsing them & allowing cli overrides. For now, if the
+; user sets options they must be comprehensive. If the user
+; doesn't set options, we use default-h2-opts.
+
+(defn h2-opts
+  "Add default h2 options if none are specified"
+  [database]
+  (if (= -1 (.indexOf database ";"))
+    (str database default-h2-opts)
+    database))
+
 ; XXX create dir for database as well?
 (defn -main [& args]
   (let [{:keys [options arguments summary errors]} (parse-opts args argspec)
         docroot (:root options)
         port (:port options)
         host (:host options)
-        tmp (:tmp options)]
+        tmp (:tmp options)
+        database (h2-opts (:database options))]
     (if errors
       (binding [*out* *err*]
         (println (s/join "\n" errors)))
@@ -150,7 +180,7 @@
                   (println error))
                 (do
                   (h2/set-tmp-dir! tmp)
-                  (let [db (h2/create-xenadb (str (:database options) ";MVCC=TRUE")) ; XXX guard against double semicolon
+                  (let [db (h2/create-xenadb database)
                         detector (apply cr/detector docroot detectors)
                         loader (cl/loader-agent db detector docroot)]
                     (when (:auto options)


Comment on kvs sync.

Comment on kvs sync.

--- src/cbfg/kvs.cljs
+++ src/cbfg/kvs.cljs
@@ -12,7 +12,7 @@
 ; - scan-keys
 ; - scan-changes
 ; - snapshot
-; - sync (like fsync)
+; - sync (commits any unpersisted, dirty changes)
 ;
 ; Note on res-ch: the kvs always closes the res-ch on request completion.


aot regression: qualify call to boot.util, fixes #90 - not sure why this broke - maybe because of recent pod changes?

--- boot/core/src/boot/task/built_in.clj
+++ boot/core/src/boot/task/built_in.clj
@@ -433,7 +433,7 @@
         (pod/with-eval-in @compile-pod
           (binding [*compile-path* ~(.getPath tgt)]
             (doseq [ns '~nses]
-              (util/info "Compiling %s...\n" ns)
+              (boot.util/info "Compiling %s...\n" ns)
               (compile ns)))))
       (-> fileset (core/add-resource tgt) core/commit!))))


remove diamond.clj

remove diamond.clj

--- exercises/diamond/src/diamond.clj
+++ exercises/diamond/src/diamond.clj
@@ -1,21 +0,0 @@
-(ns diamond)
-
-(defn- pad [x]
-  (apply str (repeat x " ")))
-
-(defn- one-row [letter [inner-pedding outer-pedding]]
-  (if (= inner-pedding 0)
-    (str (pad outer-pedding) letter (pad outer-pedding))
-    (str (pad outer-pedding) letter (pad inner-pedding) letter (pad outer-pedding))))
-
-(defn- row-peddings [num-letters]
-  (let [inner-pedding (conj (iterate (partial + 2) 1) 0)
-        outer-pedding (iterate dec (dec num-letters))]
-    (take num-letters (map vector inner-pedding outer-pedding))))
-
-(defn diamond [c]
-  (let [alphabet (map char (range (int \A) (inc (int \Z))))
-        num-letters (- (int c) (dec (int \A)))
-        top-row (map one-row alphabet (row-peddings num-letters))]
-    (concat top-row (rest (reverse top-row)))))
-


Update alfa.clj

Update alfa.clj

--- clein/src/practice/alfa.clj
+++ clein/src/practice/alfa.clj
@@ -132,12 +132,11 @@
       col)))

 (defn drop-while'' [f col]
-  (loop [ls col
-         res []]
+  (loop [ls col]
     (if (zero? (count ls))
-      res
+      ls
       (if (f (first ls))
-        (recur (rest ls) res)
+        (recur (rest ls))
         ls))))

 (defn drop-while$


Fix tests

Fix tests

--- test/cljc/reitit/dependency_test.cljc
+++ test/cljc/reitit/dependency_test.cljc
@@ -1,6 +1,6 @@
 (ns reitit.dependency-test
-  (:require [clojure.test :refer :all]
-            [reitit.dependency :refer [post-order]])
+  (:require [clojure.test :refer [deftest testing is are]]
+            [reitit.dependency :as rc])
   #?(:clj (:import [clojure.lang ExceptionInfo])))

 (deftest post-order-test
@@ -9,26 +9,25 @@
                           {:name ::foo, :provides #{:foo}, :requires #{}, :wrap identity}]]
     (testing "happy cases"
       (testing "default ordering works"
-        (is (= (post-order base-middlewares)
+        (is (= (rc/post-order base-middlewares)
                (into (vec (drop 2 base-middlewares)) (take 2 base-middlewares)))))

       (testing "custom provides and requires work"
-        (is (= (post-order (comp hash-set :name)
-                           (fn [node
-                                ](into #{} (map (fn [k] (keyword "reitit.dependency-test" (name k))))
-                                       (:requires node)))
-                           base-middlewares)
+        (is (= (rc/post-order (comp hash-set :name)
+                              (fn [node] (into #{} (map (fn [k] (keyword "reitit.dependency-test" (name k))))
+                                               (:requires node)))
+                              base-middlewares)
                (into (vec (drop 2 base-middlewares)) (take 2 base-middlewares))))))

     (testing "errors"
       (testing "missing dependency detection"
         (is (thrown-with-msg? ExceptionInfo #"missing"
-                              (post-order (drop 1 base-middlewares)))))
+                              (rc/post-order (drop 1 base-middlewares)))))

       (testing "ambiguous dependency detection"
         (is (thrown-with-msg? ExceptionInfo #"multiple providers"
-                              (post-order (update-in base-middlewares [0 :provides] conj :foo)))))
+                              (rc/post-order (update-in base-middlewares [0 :provides] conj :foo)))))

       (testing "circular dependency detection"
         (is (thrown-with-msg? ExceptionInfo #"circular"
-                              (post-order (assoc-in base-middlewares [2 :requires] #{:baz}))))))))
+                              (rc/post-order (assoc-in base-middlewares [2 :requires] #{:baz}))))))))


Two tests for function read-running-jobs

--- test/emender_jenkins/results_test.clj
+++ test/emender_jenkins/results_test.clj
@@ -535,3 +535,19 @@
                    {"state" "BUILDING", "jobName" "test-Example_Documentation-1.0-Guide-en-US (preview)"}
                    {"state" "BUILDING", "jobName" "test-Example_Documentation-1.0-Guide-en-US (stage)"}]))))))

+(deftest test-read-running-jobs
+    "Check the function emender-jenkins.results/read-running-jobs."
+    (testing "the function emender-jenkins.results/read-running-jobs."
+        (reset! jobs-in-queue-jenkins-response [])
+        (reset! currently-building-jobs-jenkins-response [])
+        (read-running-jobs nil)
+        (is (seq? @running-jobs))))
+
+(deftest test-read-running-jobs-negative
+    "Check the function emender-jenkins.results/read-running-jobs."
+    (testing "the function emender-jenkins.results/read-running-jobs."
+        (reset! jobs-in-queue-jenkins-response nil)
+        (reset! currently-building-jobs-jenkins-response nil)
+        (read-running-jobs nil)
+        (is (nil? @running-jobs))))
+


CMR-5374: Change test to count public collections.

--- system-int-test/test/cmr/system_int_test/search/data_json_search_test.clj
+++ system-int-test/test/cmr/system_int_test/search/data_json_search_test.clj
@@ -66,7 +66,7 @@
 (deftest data-json-response
   (let [tag (tag-util/make-tag {:tag-key "gov.nasa.eosdis"})
         public-collections-with-tag (create-collections 5)
-        public-collections-without-tag (create-collections 5)
+        public-collections-without-tag (create-collections 10)
         private-collections-with-tag (create-collections 5)
         private-collections-without-tag (create-collections 5)]
     (tag-util/create-tag (config/echo-system-token) tag)
@@ -87,6 +87,6 @@
       (let [data-json (search-util/retrieve-data-json)
             datasets (get-in data-json [:results :dataset])]
         (is (= 200 (:status data-json)))
-        (is (= 5 (count datasets)))
+        (is (= (count public-collections-with-tag) (count datasets)))
         (is (= (set (map :concept-id public-collections-with-tag))
                (set (map :identifier datasets))))))))


[#533] Updated docs on add-tenant script.

--- backend/src/akvo/lumen/admin/add_tenant.clj
+++ backend/src/akvo/lumen/admin/add_tenant.clj
@@ -1,6 +1,8 @@
 (ns akvo.lumen.admin.add-tenant
   "The following env vars are assumed to be present:
-  KEYCLOAK, KEYCLOAK_SECRET, PGHOST, PGDATABASE, PGUSER, PGPASSWORD
+  KEYCLOAK, KEYCLOAK_SECRET These can be found in the Keycloak admin in the
+  akvo-lumen-confidential client section.
+  PGHOST, PGDATABASE, PGUSER, PGPASSWORD
   These can be found in the ElephantSQL console for the appropriate instance
   Use this as follow
   $ env KEYCLOAK=dev KEYCLOAK_ID=akvo-lumen-confidential KEYCLOAK_SECRET=*** \\


Use tangle code, remove duplicate

Use tangle code, remove duplicate

--- src/archi/core.clj
+++ src/archi/core.clj
@@ -199,15 +199,6 @@
          svg
          scripts]))

-(defn dot->svg [s]
-  (let [{:keys [out err]} (sh/sh "dot" "-Tsvg" :in s)]
-    (or
-     out
-     (println err))))
-
-(defn remove-viewbox [svg]
-  (string/replace svg #"viewBox=\"[^\"]+\"" ""))
-
 (defn render! [features & opts]
   (let [{:keys [node->descriptor edge->descriptor filename]
          :or {node->descriptor (fn [node] node) edge->descriptor (fn [i1 i2 m] m) filename "archi"}} opts
@@ -220,8 +211,7 @@
                   :node->descriptor node->descriptor
                   :edge->descriptor edge->descriptor}
          svg (->> (tangle/graph->dot nodes edges options)
-                  (dot->svg)
-                  (remove-viewbox))
+                  (tangle/dot->svg))
          styles [:style ""]
          scripts (make-scripts edges)
          html (wrap-html filename svg styles scripts)]


Exclude resolve.

Exclude resolve.

--- src/bide/core.cljs
+++ src/bide/core.cljs
@@ -23,7 +23,7 @@
 ;; OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

 (ns bide.core
-  (:refer-clojure :exclude [empty])
+  (:refer-clojure :exclude [empty resolve])
   (:require [bide.impl.router :as rtr]
             [bide.impl.helpers :as helpers]
             [clojure.string :as str]


just use the object's class

just use the object's class

--- src/bzzz/index.clj
+++ src/bzzz/index.clj
@@ -162,9 +162,9 @@
 (defn fragment->map [^TextFragment fragment]
   {:text (.toString fragment)
    :score (.getScore fragment)
-   :frag-num (wall-hack-field TextFragment :fragNum fragment)
-   :text-start-pos (wall-hack-field TextFragment :textStartPos fragment)
-   :text-end-pos (wall-hack-field TextFragment :textEndPos fragment)})
+   :frag-num (wall-hack-field (class fragment) :fragNum fragment)
+   :text-start-pos (wall-hack-field (class fragment) :textStartPos fragment)
+   :text-end-pos (wall-hack-field (class fragment) :textEndPos fragment)})

 (defn- make-highlighter
   [^Query query ^IndexSearcher searcher config analyzer]


removed a errant space in shell command

removed a errant space in shell command

--- src/dmgr/core.clj
+++ src/dmgr/core.clj
@@ -42,7 +42,7 @@
 (defn git-deploy-cmds
   "Creates the shell commands"
   [{:keys [app-name github-repo-uri heroku-repo-uri] :as args}]
-  {:fetch-and-reset  (format   "cd  %s /repo && git fetch && git reset --hard origin/master" app-name)
+  {:fetch-and-reset  (format   "cd  %s/repo && git fetch && git reset --hard origin/master" app-name)
    :clone (format "cd %s  && git clone https://%s repo" app-name  github-repo-uri)
    ;;   :push-to-heroku (format "cd %s/repo && heroku git:remote -a %s && git push heroku master" app-name app-name app-name  heroku-repo-uri)
    :push-to-heroku (format "cd %s/repo && git remote add heroku git@heroku.com:%s.git &&  git config heroku.remote heroku && git push heroku master"


Fix arguments for clj-sub-command

Fix arguments for clj-sub-command

--- src/cljam/core.clj
+++ src/cljam/core.clj
@@ -90,13 +90,20 @@
     [[foo "foo" 1]]
     (println "index " foo)))

+(defn faidx [& args]
+  (with-command-line args
+    "Usage: cljam faidx <ref.fasta>"
+    [files]
+    nil))
+
 (defn -main [& args]
   (do-sub-command args
     "Usage: cljam [-h] {view,convert,sort,index,idxstats,merge,pileup} ..."
-    [:view "Extract/print all or sub alignments in SAM or BAM format." view]
-    [:convert "Convert SAM to BAM or BAM to SAM." convert]
-    [:sort "Sort alignments by leftmost coordinates." sort]
-    [:index "Index sorted alignment for fast random access. Index file <in.bam>.bai will be created." index]
-    [:idxstats "Retrieve  and print stats in the index file." idxstats]
-    [:merge "Merge multiple SAM/BAM." merge]
-    [:pileup "" pileup]))
+    [:view     cljam.core/view     "Extract/print all or sub alignments in SAM or BAM format."]
+    [:convert  cljam.core/convert  "Convert SAM to BAM or BAM to SAM."]
+    [:sort     cljam.core/sort     "Sort alignments by leftmost coordinates."]
+    [:index    cljam.core/index    "Index sorted alignment for fast random access."]
+    [:idxstats cljam.core/idxstats "Retrieve  and print stats in the index file."]
+    [:merge    cljam.core/merge    "Merge multiple SAM/BAM."]
+    [:pileup   cljam.core/pileup   "todo"]
+    [:faidx    cljam.core/faidx    "todo"]))


Correct expected data structure for externs

--- src/cljs/deps.cljs
+++ src/cljs/deps.cljs
@@ -1,3 +1,3 @@
 {:foreign-libs [{:file "js/fuse/fuse.min.js"
                  :provides ["cljsjs.fuse"]}]
- :externs "js/fuse/fuse.ext.js"}
+ :externs ["js/fuse/fuse.ext.js"]}


need to dereference language models twice

--- test/babel/test/translate.cljc
+++ test/babel/test/translate.cljc
@@ -21,9 +21,9 @@
 ;; In English we indicate feminine and masculine gender with ♀ and ♂,
 ;; respectively.

-(def italiano-model @(get models :it))
-(def english-model @(get models :en))
-(def latin-model @(get models :la))
+(def italiano-model @@(get models :it))
+(def english-model @@(get models :en))
+(def latin-model @@(get models :la))

 ;; Test that gender agreement is correctly translated.
 (deftest past-and-gender-agreement-feminine


Added test for backward-looking moving average


Run summary calculations in parallel.

Run summary calculations in parallel.

--- src/frmr/dstt.clj
+++ src/frmr/dstt.clj
@@ -80,15 +80,15 @@
           request-futures (map #(issue-timed-request test-start-time-ns request-invoker % handler network-pool) request-delays)
           results (doall (cp/pmap cpu-pool deref (doall request-futures)))
           grouped-result-categories (partition (count results) (apply interleave results))
-          average-per-category (mapv #(apply-to-numbers % average) grouped-result-categories)
-          min-per-category (mapv #(apply-to-numbers % (fn [x] (apply min x))) grouped-result-categories)
-          max-per-category (mapv #(apply-to-numbers % (fn [x] (apply max x))) grouped-result-categories)
-          stddev-per-category (mapv #(apply-to-numbers % standard-deviation) grouped-result-categories)]
-      {"Averages" average-per-category
-       "Minimums" min-per-category
-       "Maximums" max-per-category
-       "StandardDeviations" stddev-per-category
-       "RawResults" results})))
+          average-per-category (cp/pmap cpu-pool #(apply-to-numbers % average) grouped-result-categories)
+          min-per-category (cp/pmap cpu-pool #(apply-to-numbers % (fn [x] (apply min x))) grouped-result-categories)
+          max-per-category (cp/pmap cpu-pool #(apply-to-numbers % (fn [x] (apply max x))) grouped-result-categories)
+          stddev-per-category (cp/pmap cpu-pool #(apply-to-numbers % standard-deviation) grouped-result-categories)]
+      {"Averages" (vec average-per-category)
+       "Minimums" (vec min-per-category)
+       "Maximums" (vec max-per-category)
+       "StandardDeviations" (vec stddev-per-category)
+       "RawResults" (vec results)})))

 (defn- select-function-for-http-method
  [http-method]


Make test a bit more easygoing

Make test a bit more easygoing

--- test/onix/persistence_test.clj
+++ test/onix/persistence_test.clj
@@ -30,8 +30,9 @@
                                                                                :secret-key ..secret-key..}}))

 (fact "that creating standard credentials does what we want"
-      (create-standard-credentials) => (contains {:access-key anything
-                                                  :secret-key anything}))
+      (create-standard-credentials) => anything
+      (provided
+       (sts/assume-role anything) => anything :times 0))

 (fact "that creating an application which already exists returns a falsey value"
       (create-application {:name "dummy"}) => falsey


Add static mixin to shape componet.

Add static mixin to shape componet.

Improves dramatically the rendering performance
for huge number of objects.

--- src/uxbox/ui/workspace/canvas.cljs
+++ src/uxbox/ui/workspace/canvas.cljs
@@ -102,7 +102,7 @@
   (mx/component
    {:render shape-render
     :name "shape"
-    :mixins [(mx/local {}) rum/reactive]}))
+    :mixins [(mx/local {}) rum/reactive mx/static]}))

 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; Canvas


All values need to be quoted

All values need to be quoted

--- src/mdr2/abacus.clj
+++ src/mdr2/abacus.clj
@@ -181,13 +181,6 @@
    (map import-metadata-update)
    (delete-files!)))

-(defn escape
-  "Escape a string `s` for ABACUS consumption"
-  [s]
-  (if (or (char? s) (string? s))
-    (str "'" s "'") ; only escape strings
-    s))
-
 (defn wrap-rows
   "Wrap an export record according to ABACUS conventions"
   [rs]
@@ -200,7 +193,7 @@
   [k v]
   (when v
     (let [section (if (= k 4) "IBF" "ADO")]
-      (list "D" section k (escape v)))))
+      (list "D" section k (format "'%s'" v))))) ; all values need to be quoted

 (def ^:private date-format "%1$td.%1$tm.%1$tY")


Revert "Use nio/copy! for large files"

Revert "Use nio/copy! for large files"

This reverts commit aa50495bcb7bc94f77cc59b90073a2f2c9ce0a63.

--- src/mdr2/repair.clj
+++ src/mdr2/repair.clj
@@ -116,7 +116,7 @@
              (nio/create-directory! tmp-dir)
              (with-open [input (:body response)
                          output (io/output-stream tar-file)]
-               (nio/copy! input output))
+               (io/copy input output))
              ;; extract the tar
              (compress/untar tar-file tar-dir)
              ;; extract the relevant parts to the structured-path


improved store read/write fns

improved store read/write fns

--- src/ctia/store.clj
+++ src/ctia/store.clj
@@ -100,7 +100,7 @@
                        :identity []}))

 (defn write-store [e write-fn]
-  (first (doall (map write-fn (e @stores)))))
+  (first (doall (pmap write-fn (e @stores)))))

 (defn read-store [e read-fn]
-  (first (map read-fn (e @stores))))
+  (read-fn (rand-nth (e @stores))))


restart listener

restart listener

--- src/mount/core.cljc
+++ src/mount/core.cljc
@@ -301,6 +301,25 @@
                   (var-to-str to) :state))
    states))

+;; restart on events
+
+(defprotocol ChangeListener
+  (add-watcher [this ks watcher])
+  (on-change [this k]))
+
+(deftype RestartListener [watchers]
+  ChangeListener
+
+  (add-watcher [_ ks state]
+    (doseq [k ks]
+      (swap! watchers update k #(conj % state))))
+
+  (on-change [_ k]
+    (let [states (@watchers k)]
+      (apply stop states)
+      (apply start states))))
+
+
 ;; explicit, not composable (subject to depreciate?)

 (defn stop-except [& states]


bringing start-with-args into master

bringing start-with-args into master

--- src/mount/mount.clj
+++ src/mount/mount.clj
@@ -7,6 +7,7 @@

 ;; (defonce ^:private session-id (System/currentTimeMillis))
 (defonce ^:private mount-state 42)
+(defonce ^:private -args (atom :no-args))                  ;; mostly for command line args and external files
 (defonce ^:private state-seq (atom 0))
 (defonce ^:private state-order (atom {}))

@@ -57,6 +58,9 @@
           (throw (RuntimeException. (str "could not stop [" name "] due to") t)))))
     (alter-meta! var assoc :started? false)))

+;;TODO args might need more thinking
+(defn args [] @-args)
+
 (defn mount-state? [var]
   (= (-> var meta :mount-state)
      mount-state))
@@ -82,7 +86,7 @@
        doall))

 (defn start [& states]
-  (let [states (or states (find-all-states))]
+  (let [states (or (seq states) (find-all-states))]
     (bring states up <)
     :started))

@@ -90,3 +94,9 @@
   (let [states (or states (find-all-states))]
     (bring states down >)
     :stopped))
+
+(defn start-with-args [xs & states]
+  (reset! -args xs)
+  (if (first states)
+    (start states)
+    (start)))


Fix tests

Fix tests

--- test/swagger_gen/core_test.clj
+++ test/swagger_gen/core_test.clj
@@ -16,13 +16,13 @@
 (deftest parse-swagger-test []
   (testing "it should parse a swagger spec"
     (is (= (keys petstore)
-           '(:schemes :definitions :produces :paths :consumes :host :info :swagger :basePath)))))
+           '(:swagger :info :host :basePath :schemes :consumes :produces :paths :definitions)))))

 (deftest parse-swagger-string-test []
   (testing "it should parse a swagger spec string"
     (let [from-string (parse-swagger-string (slurp petstore-yaml))]
-    (is (= (keys from-string)
-           '(:schemes :definitions :produces :paths :consumes :host :info :swagger :basePath))))))
+      (is (= (keys from-string)
+           '(:swagger :info :host :basePath :schemes :consumes :produces :paths :definitions))))))

 (deftest check-paths-test []
   (testing "paths should be a vector of paths containing method and path"


Add tests for file store deletions and control for file-store tests.

--- test/vault/blob/store_test.clj
+++ test/vault/blob/store_test.clj
@@ -2,6 +2,7 @@
   (:require
     [byte-streams :refer [bytes=]]
     [clojure.java.io :as io]
+    [clojure.string :as str]
     [clojure.test :refer :all]
     (vault.blob
       [core :as blob]
@@ -98,27 +99,36 @@
         (test-blob-content store id content))
       (let [[id content] (first (seq stored-content))]
         (test-restore-blob store id content))
-      #_
-      (doseq [id (keys blobs)]
-        (is (blob/delete! store id) "delete returns true"))
-      #_
-      (is (empty? (blob/list store)) "ends empty")
-      #_
-      (is (not (blob/delete! store (first (keys blobs))))
-          "gives false when removing a nonexistent blob"))))
+      (when (satisfies? store/DestructiveBlobStore store)
+        (doseq [id (keys stored-content)]
+          (is (store/delete! store id) "delete returns true"))
+        (is (empty? (blob/list store)) "ends empty")
+        (is (not (store/delete! store (first (keys stored-content))))
+          "gives false when removing a nonexistent blob")))))

-(deftest test-memory-blob-store
+(defn store-enabled?
+  "Uses the VAULT_STORE_TESTS environment variable to determine which tests
+  to run."
+  [store-type]
+  (some->
+    (System/getenv "VAULT_STORE_TESTS")
+    (str/split #",")
+    set
+    (contains? store-type)))
+
+
+(deftest test-memory-store
   (let [store (memory-store)]
     (test-blob-store (memory-store))
     (store/destroy!! store)))

-(defn test-file-blob-store
-  []
-  (let [tmpdir (io/file "target" "test" "tmp"
+(deftest test-file-store
+  (when (store-enabled? "file")
+   (let [tmpdir (io/file "target" "test" "tmp"
                         (str "file-blob-store."
                              (System/currentTimeMillis)))
         store (file-store tmpdir)]
     (test-blob-store (file-store tmpdir))
-    (store/destroy!! store)))
+    (store/destroy!! store))))


Add more peer-opts to schema definition

Add more peer-opts to schema definition

--- src/onyx/schema.clj
+++ src/onyx/schema.clj
@@ -186,12 +186,18 @@
    (s/optional-key :onyx.peer/retry-start-interval) s/Int
    (s/optional-key :onyx.peer/join-failure-back-off) s/Int
    (s/optional-key :onyx.peer/drained-back-off) s/Int
+   (s/optional-key :onyx.peer/job-not-ready-back-off) s/Int
    (s/optional-key :onyx.peer/peer-not-ready-back-off) s/Int
-   (s/optional-key :onyx.peer/job-not-ready-back-off) s/Int
    (s/optional-key :onyx.peer/fn-params) s/Any
    (s/optional-key :onyx.peer/backpressure-check-interval) s/Int
    (s/optional-key :onyx.peer/backpressure-low-water-pct) s/Int
    (s/optional-key :onyx.peer/backpressure-high-water-pct) s/Int
+   (s/optional-key :onyx.bookkeeper/starting-port) s/Int
+   (s/optional-key :onyx.bookkeeper/base-dir) s/Str
+   (s/optional-key :onyx.bookkeeper/timeout) s/Int
+   (s/optional-key :onyx.bookkeeper/ledger-id-written-back-off) s/Int
+   (s/optional-key :onyx.bookkeeper/ledger-ensemble-size) s/Int
+   (s/optional-key :onyx.bookkeeper/ledger-quorum-size) s/Int
    (s/optional-key :onyx.zookeeper/backoff-base-sleep-time-ms) s/Int
    (s/optional-key :onyx.zookeeper/backoff-max-sleep-time-ms) s/Int
    (s/optional-key :onyx.zookeeper/backoff-max-retries) s/Int


Adds windows to the schema checks.

Adds windows to the schema checks.

[ci skip]

--- src/onyx/schema.clj
+++ src/onyx/schema.clj
@@ -102,12 +102,21 @@
    :flow/predicate (s/either s/Keyword [s/Any])
    s/Keyword s/Any})

+(def Window
+  {:window/id s/Keyword
+   :window/type s/Keyword
+   :window/window-key s/Any
+   :window/range [s/Int s/Keyword]
+   :window/slide [s/Int s/Keyword]
+   (s/optional-key :window/doc) s/Str})
+
 (def Job
   {:catalog Catalog
    :workflow Workflow
    :task-scheduler s/Keyword
    (s/optional-key :percentage) s/Int
    (s/optional-key :flow-conditions) [FlowCondition]
+   (s/optional-key :windows) [Window]
    (s/optional-key :lifecycles) [Lifecycle]
    (s/optional-key :acker/percentage) s/Int
    (s/optional-key :acker/exempt-input-tasks?) s/Bool


migration to populate user info

migration to populate user info

--- src/pc/admin/db.clj
+++ src/pc/admin/db.clj
@@ -2,6 +2,7 @@
   (:require [datomic.api :refer [db q] :as d]
             [clj-time.core :as time]
             [clj-time.coerce :refer [to-date]]
+            [pc.auth]
             [pc.datomic :as pcd]))

 (defn interesting-doc-ids [{:keys [start-time end-time layer-threshold limit]
@@ -27,3 +28,10 @@
                                                               db doc-id))
                                                  0)))
                         doc-ids))))
+
+(defn populate-user-info-from-sub []
+  (let [db (pcd/default-db)]
+    (doseq [[eid] (d/q '{:find [?t]
+                         :where [[?t :google-account/sub]]}
+                       db)]
+      (pc.auth/update-user-from-sub (d/entity db eid)))))


Don't show a rating box for the current user.

--- src/regarde/web.clj
+++ src/regarde/web.clj
@@ -61,8 +61,8 @@
 (defn list-exercises [request]
   (templates/exercises (exercise/all)))

-(defn new-exercise-ratings [exercise]
-  (let [users (user/all)]
+(defn new-exercise-ratings [exercise request]
+  (let [users (user/all-except (current-user request))]
     (templates/new-ratings exercise users)))

 (defn find-or-create-user [request]
@@ -91,9 +91,9 @@
   (GET "/exercises/:id" [id]
        (let [ex (exercise/find id)]
          (show-exercise ex)))
-  (GET "/exercises/:id/rating_sets/new" [id]
+  (GET "/exercises/:id/rating_sets/new" [id :as request]
        (let [ex (exercise/find id)]
-         (new-exercise-ratings ex)))
+         (new-exercise-ratings ex request)))
   (POST "/exercises/:id/ratings" [id]
         create-ratings)
   (ANY "*" []


cyanite: fix system creation, fixes #182

--- src/io/cyanite.clj
+++ src/io/cyanite.clj
@@ -43,12 +43,9 @@
    an updated system with top-level keys.
    components are created by call f on them
    options."
-  [system k f]
-  (if (seq (get system k))
-    (merge (dissoc system k)
-           (reduce merge {} (map (juxt :type f) (get system k))))
-    ;; When key didn't exist in map, create, call the constructor
-    ;; on an empty option map
+  [system config k f]
+  (if (seq config)
+    (reduce merge system (map (juxt :type f) config))
     (assoc system k (f {}))))

 (defn config->system
@@ -65,12 +62,12 @@
            :drift  (build-drift (:drift config))
            :engine (map->Engine (:engine config))
            :writer (map->Writer (:writer config))
-           :api    (map->Api (:api config))
+           :api    (map->Api {:options (:api config)})
            :index  (index/build-index (:index config))
            :store  (store/build-store (:store config))
            :reporter (reporter/make-reporter (:reporter config)))
-          (build-components :input input/build-input)
-          (component/system-using {:drift [:clock]
+          (build-components (:input config) :input input/build-input)
+          (component/system-using {:drift  [:clock]
                                    :queues [:reporter]
                                    :engine [:drift :queues :writer]
                                    :writer [:index :store :queues]


Up to printing the board

Up to printing the board

--- pegthing/src/pegthing/core.clj
+++ pegthing/src/pegthing/core.clj
@@ -2,10 +2,13 @@
   (:require [clojure.set :as set])
   (:gen-class))

-(declare successful-move prompt-move game-over query-rows)
+(declare successful-move prompt-move game-over prompt-rows)

 ;; in the data structure, each position is associated with a map like
 ;; {:pegged true, :connections {6 3, 4 2}}
+
+
+;; Functions to create the board:

 (defn tri*
   "Generates lazy sequence of triangular numbers"
@@ -13,6 +16,8 @@
   ([sum n]
      (let [new-sum (+ sum n)]
        (cons new-sum (lazy-seq (tri* new-sum (inc n)))))))
+
+(def tri (tri*))

 (defn triangular?
   "Is the number triangular? e.g. 1, 3, 6, 10, 15, etc"
@@ -55,3 +60,167 @@
             board
             [[pos destination] [destination pos]])
     board))
+
+(defn connect-right
+  [board max-pos pos]
+  (let [neighbor (inc pos)
+        destination (inc neighbor)]
+    (if-not (or (triangular? neighbor) (triangular? pos))
+      (connect board max-pos pos neighbor destination)
+      board)))
+
+(defn connect-down-left
+  [board max-pos pos]
+  (let [row (row-num pos)
+        neighbor (+ row pos)
+        destination (+ 1 row neighbor)]
+    (connect board max-pos pos neighbor destination)))
+
+(defn connect-down-right
+  [board max-pos pos]
+  (let [row (row-num pos)
+        neighbor (+ 1 row pos)
+        destination (+ 2 row neighbor)]
+    (connect board max-pos pos neighbor destination)))
+
+;;(connect-down-left {} 15 1)
+;;=> {1 {:connections {4 2}}, 4 {:connections {1 2}}}
+
+;;(connect-down-right {} 15 3)
+;;=> {3 {:connections {10 6}}, 10 {:connections {3 6}}}
+
+(defn add-pos
+  "Pegs the position and performs connections"
+  [board max-pos pos]
+  (let [pegged-board (assoc-in board [pos :pegged] true)]
+    (reduce (fn [new-board connection-creation-fn]
+              (connection-creation-fn new-board max-pos pos))
+            pegged-board
+            [connect-right connect-down-left connect-down-right])))
+
+;;(add-pos {} 15 1)
+;;=> {1 {:pegged true, :connections {4 2, 6 3}}, 4 {:connections {1 2}}, 6 {:connections {1 3}}}
+
+(defn new-board
+  "Creates a new board with the given number of rows"
+  [rows]
+  (let [initial-board {:rows rows}
+        max-pos (row-tri rows)]
+    (reduce (fn [board pos] (add-pos board max-pos pos))
+            initial-board
+            (range 1 (inc max-pos)))))
+
+;; Moving pegs
+
+(defn pegged?
+  "Does the position have a peg in it?"
+  [board pos]
+  (get-in board [pos :pegged]))
+
+(defn remove-peg
+  "Take the peg at given position out of the board"
+  [board pos]
+  (assoc-in board [pos :pegged] false))
+
+(defn place-peg
+  "Put a peg in the board at a given postion"
+  [board pos]
+  (assoc-in board [pos :pegged] true))
+
+(defn move-peg
+  "Take peg out of p1 and place it in p2"
+  [board p1 p2]
+  (place-peg (remove-peg board p1) p2))
+
+(defn valid-moves
+  "Return a map of all valid moves for pos, where the key is the destination and the value is the jumped position"
+  [board pos]
+  (into {}
+        (filter (fn [[destination jumped]]
+                  (and (not (pegged? board destination))
+                       (pegged? board jumped)))
+                (get-in board [pos :connections]))))
+
+;;(def my-board (assoc-in (new-board 5) [4 :pegged] false))
+
+;;(valid-moves my-board 1)  ; => {4 2}
+;;(valid-moves my-board 6)  ; => {4 5}
+;;(valid-moves my-board 11) ; => {4 7}
+;;(valid-moves my-board 5)  ; => {}
+;;(valid-moves my-board 8)  ; => {}
+
+(defn valid-move?
+  "Return jumped position if the move from p1 to p2 is valid, nil otherwise"
+  [board p1 p2]
+  (get (valid-movies board p1) p2))
+
+;;(valid-move? my-board 8 4)
+;;=> nil
+;; (valid-move? my-board 1 4)
+;;=> 2
+
+(defn make-move
+  "Move peg from p1 to p2, removing jumped peg"
+  [board p1 p2]
+  (if-let [jumped (valid-move? board p1 p2)]
+    (move-peg (remove-peg board jumped) p1 p2)))
+
+(defn can-move?
+  "Do any of the pegged positions have valid moves?"
+  [board]
+  (some (comp not-empty (partial valid-moves board))
+        (map first (filter #(get (second %) :pegged) board))))
+
+;; Printing the board
+
+(def alpha-start 97)
+(def alpha-end 123)
+(def letters (map (comp str char) (range alpha-start alpha-end)))
+(def pos-chars 3)
+
+(def ansi-styles
+  {:red  "[31m"
+   :green "[32m"
+   :blue  "[34m"
+   :reset "[0m"})
+
+(defn ansi
+  "Produce a string which will apply an ANSI style"
+  [style]
+  (str \u001b (style ansi-styles)))
+
+(defn colorize
+  "Apply ANSI color to text"
+  [text color]
+  (str (ansi color) text (ansi :reset)))
+
+(defn render-pos
+  [board pos]
+  (str (nth letters (dec pos))
+       (if (get-in board [pos :pegged])
+         (colorize "O" :blue)
+         (colorize "-" :red))))
+
+(defn row-positions
+  "Return all positions in the given row"
+  [row-num]
+  (range (inc (or (row-tri (dec row-num)) 0))
+         (inc (row-tri row-num))))
+
+(defn row-padding
+  "String of spaces to add to the beginning of a row to center it"
+  [row-num rows]
+  (let [pad-length (/ (* (- rows row-num) pos-chars) 2)]
+    (apply str (take pad-length (repeat " ")))))
+
+(defn render-row
+  [board row-num]
+  (str (row-padding row-num (:rows board))
+       (clojure.string/join " " (map (partial render-pos  board)
+                                     (row-positions row-num)))))
+
+(defn print-board
+  [board]
+  (doseq [row-num (range 1 (inc (:rows board)))]
+    (println (render-row board row-num))))
+


make the tooltip a span

make the tooltip a span

so that it doesnt pop up over the entire page

--- src-cljs/frontend/components/insights/project.cljs
+++ src-cljs/frontend/components/insights/project.cljs
@@ -171,7 +171,8 @@
    [:div.card-header
     [:h2
      (popover/tooltip {:placement :top-left
-                       :body "Results pulled from the last ten failed builds."}
+                       :body "Results pulled from the last ten failed builds."
+                       :container :span}
        "Failed Tests")]]
    [:div.card-body.failed-tests
     (cond


simple kern grammar for sudoku rules implemented

--- src/logic/kern.clj
+++ src/logic/kern.clj
@@ -1,4 +1,38 @@
-(ns logic.util
-  (:use [blancas.kern.core]))
+(ns logic.kern
+  (:use [blancas.kern core expr]))

-(run digit "123")+stop
+
+#_(
+  pseudocode grammar
+
+  or     := and "|" and
+  and    := unexp "&" unexp
+  unexp  := "!"? exp
+  exp    := atom | "(" or ")"
+
+  atom   := "c" digit*
+)
+
+(declare or-parser)
+
+(def atom-parser (<+> letter (many1 digit)))
+(def atom (<$> symbol atom-parser))
+
+(def exp (<|> atom (<< (>> (one-of* "(") or-parser) (one-of* ")"))))
+
+(def not-sym (>> (token* "!") (return #(list 'not %))))
+(def unexp (prefix1 exp not-sym))
+
+(def and-sym (>> (token* "&") (return #(list 'and %1 %2))))
+(def and-parser (chainl1 unexp and-sym))
+
+(def or-sym (>> (token* "|") (return #(list 'or %1 %2))))
+(def or-parser (chainl1 and-parser or-sym))
+
+
+; examples
+(parse or-parser "c1&!(c2|!c3)&(c4&!c5)")
+(run or-parser "(((((c1)))))")
+
+(time (run or-parser sudoku))


less strict checking of relevant data

less strict checking of relevant data

--- frontend/controllers/api.cljs
+++ frontend/controllers/api.cljs
@@ -223,7 +223,7 @@

 (defmethod api-event [:project-settings :success]
   [target message status {:keys [resp context]} state]
-  (if-not (= (:project-name context) (:project-settings-project-name state))
+  (if-not (= (:project-name context) (str (get-in state [:navigation-data :org]) "/" (get-in state [:navigation-data :repo])))
     state
     (update-in state state/project-path merge resp)))


Kilo : Fixing group.clj : Needed to cast id to Long prior to calling
get-data function in resource-accessor.

--Tom

--- src/kilo/resources/group.clj
+++ src/kilo/resources/group.clj
@@ -16,7 +16,7 @@
   :allowed-methods [:get]
   :available-media-types ["application/json" "application/edn"]
   :exists? (fn [ctx]
-             (if-let [group (k-data-accessor/get-data (keyword "group") id)]
+             (if-let [group (k-data-accessor/get-data (keyword "group") (Long/parseLong id))]
                {::group group}))
   :handle-ok (fn [ctx]
                (::group ctx)))


Batch fn & flux policy.

Batch fn & flux policy.

--- src/onyx/spec.cljc
+++ src/onyx/spec.cljc
@@ -82,6 +82,7 @@
                 :onyx/type
                 :onyx/batch-size]
           :opt [:onyx/batch-timeout
+                :onyx/batch-fn?
                 :onyx/fn
                 :onyx/uniqueness-key
                 :onyx/deduplicate?
@@ -105,6 +106,7 @@
                 :onyx/max-peers
                 :onyx/group-by-key
                 :onyx/group-by-fn
+                :onyx/flux-policy
                 :onyx/params
                 :onyx/required-tags
                 :onyx/plugin
@@ -118,11 +120,13 @@
                 :onyx/type
                 :onyx/batch-size]
           :opt [:onyx/batch-timeout
+                :onyx/batch-fn?
                 :onyx/fn
                 :onyx/uniqueness-key
                 :onyx/deduplicate?
                 :onyx/group-by-key
                 :onyx/group-by-fn
+                :onyx/flux-policy
                 :onyx/n-peers
                 :onyx/min-peers
                 :onyx/max-peers


fix ns conflict

fix ns conflict

--- src/leiningen/namespaces.clj
+++ src/leiningen/namespaces.clj
@@ -1,4 +1,5 @@
 (ns leiningen.namespaces
+  (:refer-clojure :exclude [run!])
   (:require [clojure.string :as str]
             [clojure.java.io :as io]
             [leiningen.constant :as c]


better strategy to update resource if there are many options to update or create new resource

--- src/leiningen/namespaces.clj
+++ src/leiningen/namespaces.clj
@@ -94,7 +94,7 @@

 (defn initial-question [namespace project]
   (str "The location of " namespace " on " project
-       " couldn't determined.  Please choose one of options:"))
+       " could not be determined.  Please choose one of options:"))

 (defn localtion-question-with
   ([ns project [first & rest]]
@@ -107,14 +107,21 @@
             ffirst
             rrest))))

-(defn ask-for-localtion-and-update! [namespace project source-path target-paths]
+(defn ask-for-localtion [namespace project paths]
+  (nth paths
+       (-> namespace
+           (localtion-question-with project paths)
+           (u/ask-user (partial u/is-number (count paths)))
+           (read-string))))
+
+(defn ask-for-localtion-and-update! [namespace project source-paths target-paths]
   (update-files!
-   source-path
-   (nth target-paths
-        (-> namespace
-            (localtion-question-with project target-paths)
-            (u/ask-user (partial u/is-number (count target-paths)))
-            (read-string)))))
+   (if (= 1 (count source-paths))
+     (first source-paths)
+     (ask-for-localtion namespace project source-paths))
+   (if (= 1 (count target-paths))
+     (first target-paths)
+     (ask-for-localtion namespace project target-paths))))

 (defn update-file-if-exists! [name target-project source-paths target-paths]
   (let [existing-source-paths (filter ns-exists? source-paths)
@@ -130,12 +137,11 @@
            (= 1 (count target-paths)))
       (update-files! (first existing-source-paths) (first target-paths))
       ;source  exists, target  doen't exist and its location is unique, so ask user
-      (and (= 1 (count existing-source-paths))
-           (= 0 (count existing-target-paths))
-           (< 1 (count target-paths)))
-      (ask-for-localtion-and-update! name target-project (first existing-source-paths) target-paths)
+      (<= 1 (count existing-source-paths))
+      (ask-for-localtion-and-update! name target-project existing-source-paths target-paths)
       ;default: do nothing
-      :else (m/info "Could not find strategy to update" name "on project" target-project))))
+      :else (m/info "WARNING: Could not find strategy to update" name "on project" target-project
+                    "\n    ==>" name "may not exist on the source project"))))

 (defn update-name-space! [name-space target-project source-project-desc]
   (if (should-update? sync-ns-def name-space target-project)


Remove redundant db/notify! in store-file*!

--- src/pepa/model.clj
+++ src/pepa/model.clj
@@ -26,14 +26,12 @@
   (assert content-type)
   (assert origin)
   (assert data)
-  (let [[file] (db/insert! db
-                           :files
-                           {:content_type content-type
-                            :origin origin
-                            :name name
-                            :data data})]
-    (db/notify! db :files/new {:files [(:id file)]})
-    file))
+  (first (db/insert! db
+                     :files
+                     {:content_type content-type
+                      :origin origin
+                      :name name
+                      :data data})))

 (defn store-file! [db attrs]
   (db/with-transaction [db db]


Remove try/catch clause

Remove try/catch clause

The try/catch was used to debug why I wasn't able to persist the date.
I removed it now since it was a debugging artifact.

--- src/pepa/model.clj
+++ src/pepa/model.clj
@@ -253,27 +253,25 @@
   (log/info db "Updating document" id {:props props
                                        :tags/added added-tags
                                        :tags/removed removed-tags})
-  (try
-    (db/with-transaction [conn db]
-      (if-let [document (get-document conn id)]
-        (let [added-tags (set added-tags)
-              removed-tags (set removed-tags)
-              props (assoc props :document_date (string->timestamp (:document_date props)))
-              ;; Subtract removed-tags from added-tags so we don't
-              ;; create tags which will be removed instantly
-              added-tags (set/difference added-tags removed-tags)]
-          (remove-tags*! conn id removed-tags)
-          (add-tags*! conn id added-tags)
-          ;; Update document title if necessary
-          (when (seq props)
-            (db/update! conn :documents
-                        props
-                        ["id = ?" id]))
-          (db/notify! conn :documents/updated {:id id}))
-        (throw (ex-info (str "Couldn't find document with id " id)
-                        {:document/id id
-                         :db db}))))
-    (catch SQLException e (throw (.getNextException e)))))
+  (db/with-transaction [conn db]
+    (if-let [document (get-document conn id)]
+      (let [added-tags (set added-tags)
+            removed-tags (set removed-tags)
+            props (assoc props :document_date (string->timestamp (:document_date props)))
+            ;; Subtract removed-tags from added-tags so we don't
+            ;; create tags which will be removed instantly
+            added-tags (set/difference added-tags removed-tags)]
+        (remove-tags*! conn id removed-tags)
+        (add-tags*! conn id added-tags)
+        ;; Update document title if necessary
+        (when (seq props)
+          (db/update! conn :documents
+                      props
+                      ["id = ?" id]))
+        (db/notify! conn :documents/updated {:id id}))
+      (throw (ex-info (str "Couldn't find document with id " id)
+                      {:document/id id
+                       :db db})))))

 ;;; Tag Functions


Streamline the handling of a file asset

Streamline the handling of a file asset

--- src/main/clojure/cascade.clj
+++ src/main/clojure/cascade.clj
@@ -102,7 +102,7 @@
   [path]
   (let [file-path (str (:public-folder @asset-configuration) "/" path)
         file (File. file-path)
-        client-url (str (:file-path @assset-configuration) path)]
+        client-url (str (:file-path @asset-configuration) path)]
     (->FileAsset file client-url)))

 (defn get-content-type [asset]
@@ -120,15 +120,6 @@
     (if stream
       (-> (ring/response stream)
         (ring/content-type (get-content-type asset))))))
-
-; TODO: perhaps we should create a single handler for the virtual folder, then delegate out to it by domain
-; ("file", "classpath")
-(defn create-file-asset-handler
-  [path-prefix]
-  (fn [req]
-    (let [uri (:uri req)
-          path (.substring uri (.length path-prefix))]
-      (generic-asset-handler (->FileAsset path)))))

 (defn wrap-exception-handling
   "Middleware for standard Cascade exception reporting; exceptions are caught and reported using the Cascade
@@ -149,18 +140,19 @@
   [application-version & {:keys [virtual-folder public-folder file-extensions]
                           :or {virtual-folder "assets"
                                public-folder "public"}}]
-  (let [root (str "/" virtual-folder "/" application-version)
-        file-path (str root "/file/")]
+  (let [root (str "/" virtual-folder "/" application-version)]
     (reset! asset-configuration
       {:application-version application-version
        :public-folder public-folder
        :virtual-folder virtual-folder
-       :file-path file-path
+       :file-path (str root "/file/")
        :file-extensions (merge default-file-extension-to-mime-type file-extensions)})
-    (printf "Initialized file system resource access to directory '%s' at %s\n" public-folder file-path)
+    (printf "Initialized asset access at virtual folder %s\n" root)
     (wrap-exception-handling
       (routes
-        (GET (str file-path "*") [] (create-file-asset-handler file-path))))))
+        (GET [(str root "/file/:path") :path #".*"]
+          [path]
+          (generic-asset-handler (file-asset path)))))))

 (defn wrap-html
   "Ring middleware that wraps a handler so that the return value from the handler (a seq of DOM nodes)


add worker test

add worker test

--- test/hivewing_core/worker_test.clj
+++ test/hivewing_core/worker_test.clj
@@ -16,6 +16,7 @@
           new-worker     (worker-reset-access-token worker-uuid)
           new-access     (:access_token (worker-get worker-uuid :include-access-token true))
           ]
+      (is (not (= "unnamed" (:name (worker-get worker-uuid)))))
       (is (not (reduce = (map str [prior-access new-access]))))
         ))
 (deftest deleting-a-worker-via-worker-list


Make csv-corpus-to-tf-idf-data! also write out idf map to file.

--- project/analyze-data/src/analyze_data/corpus_to_tf_idf.clj
+++ project/analyze-data/src/analyze_data/corpus_to_tf_idf.clj
@@ -61,16 +61,19 @@

 (defn csv-corpus-to-tf-idf-data!
   "Transform a csv containing a corpus of documents into a file of tf-idf
-  vectors.
+  vectors and a file of idf values.

   in-path: path to a csv file. It should contain the headers 'item-name' and
            'item-text', with values as described in corpus-to-tf-idf-data.
-  out-path: path where the tf-idf vectors will be written as a gzipped file.
-            Each line of the output file will be an edn list, and each will
-            correspond to an entry from the return value of
-            corpus-to-tf-idf-data."
-  [in-path out-path]
-  (with-open [in (io/reader in-path)]
+  idf-path: path to write an edn map from term to idf value.
+  tf-idf-path: path where the tf-idf vectors will be written as a gzipped
+               file. Each line of the output file will be an edn list, and
+               each will correspond to an entry from the :tf-idf key in the
+               return value of corpus-to-tf-idf-data."
+  [in-path idf-path tf-idf-path]
+  (with-open [in (io/reader in-path)
+              idf-out (io/writer idf-path)]
     (let [corpus (csv-to-map in)
           tf-idf-data (corpus-to-tf-idf-data corpus)]
-      (write-sequence! (:tf-idf tf-idf-data) out-path, :compress? true))))
+      (binding [*out* idf-out] (prn (:idf tf-idf-data)))
+      (write-sequence! (:tf-idf tf-idf-data) tf-idf-path, :compress? true))))


Fewer locking

Fewer locking

--- src/yadic/core.clj
+++ src/yadic/core.clj
@@ -210,17 +210,19 @@

 (def-map-type Container [parent-container activators cache-atom]
   (get [this k default-value]
-       (locking cache-atom
-         (if (contains? (:instances @cache-atom) k)
-           (get-in @cache-atom [:instances k])
-           (let [value (if-let [activator (get activators k)]
-                         (activate* k activator this)
-                         (get parent-container k default-value))]
-             (swap! cache-atom (fn [m]
-                                 (-> m
-                                     (assoc-in [:instances k] value)
-                                     (assoc :creation-order (cons k (:creation-order m))))))
-             value))))
+       (if (contains? (:instances @cache-atom) k)
+         (get-in @cache-atom [:instances k])
+         (locking cache-atom
+           (if (contains? (:instances @cache-atom) k)
+             (get-in @cache-atom [:instances k])
+             (let [value (if-let [activator (get activators k)]
+                           (activate* k activator this)
+                           (get parent-container k default-value))]
+               (swap! cache-atom (fn [m]
+                                   (-> m
+                                       (assoc-in [:instances k] value)
+                                       (assoc :creation-order (cons k (:creation-order m))))))
+               value)))))

   (assoc [this key value]
     (throw (UnsupportedOperationException. "assoc and dissoc are not yet defined for a Container")))


refactor cell rendering

refactor cell rendering

--- src/cljs/org/broadinstitute/firecloud_ui/common/table.cljs
+++ src/cljs/org/broadinstitute/firecloud_ui/common/table.cljs
@@ -89,10 +89,10 @@
      ((:onChange props)))})

-(defn- render-cell [width content cell-style cell-padding-left content-container-style onResizeMouseDown onSortClick sortOrder]
+(defn- render-cell [{:keys [width onResizeMouseDown onSortClick sortOrder] :as props}]
   [:div {:style (merge {:float "left" :position "relative" :width width :minWidth 10}
-                       cell-style)}
-   (when onResizeMouseDown
+                  (:cell-style props))}
+   (when (:onResizeMouseDown props)
      [:div {:style {:position "absolute" :width 20 :top 0 :bottom 0 :left (- width 10) :zIndex 1
                     :cursor "col-resize"}
             :onMouseDown onResizeMouseDown}])
@@ -104,37 +104,43 @@
      [:div {:style {:position "absolute" :top "50%" :right 0 :width 16 :transform "translateY(-50%)"}}
       (if (= :asc sortOrder) "↑" "↓")])
    [:div {:style (merge {:whiteSpace "nowrap" :overflow "hidden" :textOverflow "ellipsis"
-                         :width (str "calc(" (- width (if sortOrder 16 0)) "px - " cell-padding-left ")")}
-                   content-container-style)}
-    content]])
-
-
-(defn- render-header-cell [props index width content onResizeMouseDown onSortClick sortOrder]
-  (render-cell
-    width
-    content
-    (when onResizeMouseDown {:borderRight "1px solid #777777" :marginRight -1})
-    (or (:cell-padding-left props) 0)
-    (merge
-      {:padding (str "0.8em 0 0.8em " (or (:cell-padding-left props) 0))}
-      (:header-style props))
-    onResizeMouseDown
-    onSortClick
-    sortOrder))
-
-
-(defn- render-body-cell [props width content]
-  (render-cell
-    width
-    content
-    nil
-    (or (:cell-padding-left props) 0)
-    (merge
-      {:padding (str "0.6em 0 0.6em " (or (:cell-padding-left props) 0))}
-      (:cell-content-style props))
-    nil
-    nil
-    nil))
+                         :width (str "calc(" (- width (if sortOrder 16 0)) "px - " (:cell-padding-left props) ")")}
+                   (:content-container-style props))}
+    (:content props)]])
+
+
+(defn- render-header [state props]
+[:div {:style (merge
+                {:fontWeight 500 :fontSize "80%"
+                 :color "#fff" :backgroundColor (:header-darkgray style/colors)}
+                (:header-row-style props))}
+ (map-indexed
+   (fn [i column]
+     (let [onResizeMouseDown (when (get column :resizable? (:resizable-columns? props))
+                               (fn [e] (swap! state assoc
+                                         :dragging? true :mouse-x (.-clientX e) :drag-column i)))]
+       (render-cell
+         {:width (nth (:column-widths @state) i)
+          :content (:header column)
+          :cell-style (when onResizeMouseDown {:borderRight "1px solid #777777" :marginRight -1})
+          :cell-padding-left (or (:cell-padding-left props) 0)
+          :content-container-style (merge
+                                     {:padding (str "0.8em 0 0.8em " (or (:cell-padding-left props) 0))}
+                                     (:header-style props))
+          :onResizeMouseDown onResizeMouseDown
+          :onSortClick (when-let [sorter (:sort-by column)]
+                         #(if (= i (:sort-column @state))
+                           (case (:sort-order @state)
+                             :asc (swap! state assoc :sort-order :desc)
+                             :desc (swap! state dissoc :sort-column :sort-order :key-fn)
+                             (assert false "bad state"))
+                           (swap! state assoc :sort-column i :sort-order :asc
+                             :key-fn (if (= :value sorter)
+                                       (fn [row] (nth row i))
+                                       (fn [row] (sorter (nth row i)))))))
+          :sortOrder (when (= i (:sort-column @state)) (:sort-order @state))})))
+   (:columns props))
+ (common/clear-both)])

 (react/defc Body
@@ -161,10 +167,13 @@
              (map-indexed
                (fn [col-index col]
                  (let [render-content (or (:content-renderer col) (fn [i data] data))]
-                   (render-body-cell
-                     props
-                     (nth (:column-widths props) col-index)
-                     (render-content row-index (nth row col-index)))))
+                   (render-cell
+                     {:width (nth (:column-widths props) col-index)
+                      :content (render-content row-index (nth row col-index))
+                      :cell-padding-left (or (:cell-padding-left props) 0)
+                      :content-container-style (merge
+                                                 {:padding (str "0.6em 0 0.6em " (or (:cell-padding-left props) 0))}
+                                                 (:cell-content-style props))})))
                (:columns props))
              (common/clear-both)]))
         (:rows @state))])})
@@ -218,34 +227,7 @@
                                        assoc (:drag-column @state) (+ current-width drag-amount))
                                      (swap! state assoc :mouse-x new-mouse-x)))))
                 :onMouseUp #(swap! state assoc :dragging? false)}
-          [:div {:style (merge
-                          {:fontWeight 500 :fontSize "80%"
-                           :color "#fff" :backgroundColor (:header-darkgray style/colors)}
-                          (:header-row-style props))}
-           (map-indexed
-             (fn [i column]
-               (let [width (nth (:column-widths @state) i)]
-                 (render-header-cell
-                   props
-                   i
-                   width
-                   (:header column)
-                   (when (get column :resizable? (:resizable-columns? props))
-                     (fn [e] (swap! state assoc
-                               :dragging? true :mouse-x (.-clientX e) :drag-column i)))
-                   (when-let [sorter (:sort-by column)]
-                     #(if (= i (:sort-column @state))
-                       (case (:sort-order @state)
-                         :asc (swap! state assoc :sort-order :desc)
-                         :desc (swap! state dissoc :sort-column :sort-order :key-fn)
-                         (assert false "bad state"))
-                       (swap! state assoc :sort-column i :sort-order :asc
-                         :key-fn (if (= :value sorter)
-                                   (fn [row] (nth row i))
-                                   (fn [row] (sorter (nth row i)))))))
-                   (when (= i (:sort-column @state)) (:sort-order @state)))))
-             (:columns props))
-           (common/clear-both)]
+          (render-header state props)
           [Body (assoc props
                   :ref "body"
                   :columns (:columns props)


Fix reflection warning :wrench:

Fix reflection warning :wrench:

--- src/metabase/sample_data.clj
+++ src/metabase/sample_data.clj
@@ -7,13 +7,13 @@
             [metabase.sync-database :as sync-database]
             [metabase.util :as u]))

-
 (def ^:private ^:const ^String sample-dataset-name     "Sample Dataset")
 (def ^:private ^:const ^String sample-dataset-filename "sample-dataset.db.mv.db")

 (defn- db-details []
-  (let [resource (or (io/resource sample-dataset-filename)
-                     (throw (Exception. (format "Can't load sample dataset: the DB file '%s' can't be found." sample-dataset-filename))))]
+  (let [resource (io/resource sample-dataset-filename)]
+    (when-not resource
+      (throw (Exception. (format "Can't load sample dataset: the DB file '%s' can't be found." sample-dataset-filename))))
     {:db (-> (.getPath resource)
              (s/replace #"^file:" "zip:")           ; to connect to an H2 DB inside a JAR just replace file: with zip:
              (s/replace #"\.mv\.db$" "")            ; strip the .mv.db suffix from the path


Honor the :channel :type in share-request, defaulting to channel

--- src/oc/storage/async/bot.clj
+++ src/oc/storage/async/bot.clj
@@ -58,12 +58,14 @@
   "Given an entry for an org and a share request, create the share trigger."
   [org board entry share-request user]
   (let [slack-org-id (-> share-request :channel :slack-org-id)
+        channel-type (or (-> share-request :channel :type keyword)
+                         :channel)
         comments (:existing-comments entry)
         comment-count (str (count comments))]
     {
       :type "share-entry"
       :receiver {
-        :type :channel
+        :type channel-type
         :slack-org-id slack-org-id
         :id (-> share-request :channel :channel-id)
       }
@@ -100,4 +102,4 @@
   (timbre/info "Request sent to:" config/aws-sqs-bot-queue))

 (schema/defn ^:always-validate send-share-entry-trigger! [trigger :- ShareEntryTrigger]
-  (send-trigger! trigger))+  (send-trigger! trigger))


Add optimized function to select entries with status and board index. Keep the old fn for comparison temporarily. Improve the replies query index.

--- src/oc/storage/db/common.clj
+++ src/oc/storage/db/common.clj
@@ -8,15 +8,15 @@
             [oc.storage.config :as config]
             [oc.lib.db.common :as db-common]))

-(defn read-paginated-entries
+(defn read-paginated-entries-old
  ([conn table-name index-name index-value order start direction limit sort-type relation-table-name allowed-boards
    relation-fields {:keys [count unseen] :or {count false unseen false}}]
- (read-paginated-entries conn table-name index-name index-value order start direction limit sort-type relation-table-name allowed-boards
+ (read-paginated-entries-old conn table-name index-name index-value order start direction limit sort-type relation-table-name allowed-boards
   nil nil relation-fields nil {:count count :unseen false :container-id nil}))

  ([conn table-name index-name index-value order start direction limit sort-type relation-table-name allowed-boards
    relation-fields user-id {:keys [count unseen] :or {count false unseen false}}]
-  (read-paginated-entries conn table-name index-name index-value order start direction limit sort-type relation-table-name allowed-boards
+  (read-paginated-entries-old conn table-name index-name index-value order start direction limit sort-type relation-table-name allowed-boards
   nil nil relation-fields user-id {:count count :unseen false :container-id nil}))

  ([conn table-name index-name index-value order start direction limit sort-type relation-table-name allowed-boards
@@ -172,6 +172,165 @@
             (r/run query conn)
             (db-common/drain-cursor query))))))

+(defn read-paginated-entries
+  ([conn table-name index-name index-value order start direction limit sort-type relation-table-name allowed-boards
+    relation-fields {:keys [count unseen] :or {count false unseen false}}]
+   (read-paginated-entries conn table-name index-name index-value order start direction limit sort-type relation-table-name allowed-boards
+                           nil nil relation-fields nil {:count count :unseen false :container-id nil}))
+
+  ([conn table-name index-name index-value order start direction limit sort-type relation-table-name allowed-boards
+    relation-fields user-id {:keys [count unseen] :or {count false unseen false}}]
+   (read-paginated-entries conn table-name index-name index-value order start direction limit sort-type relation-table-name allowed-boards
+                           nil nil relation-fields user-id {:count count :unseen false :container-id nil}))
+
+  ([conn table-name index-name index-value order start direction limit sort-type relation-table-name allowed-boards
+    follow-data container-last-seen-at relation-fields user-id {:keys [count unseen container-id] :or {count false unseen false}}]
+   {:pre [(db-common/conn? conn)
+          (db-common/s-or-k? table-name)
+          (db-common/s-or-k? index-name)
+          (or (string? index-value) (sequential? index-value))
+          (db-common/s-or-k? relation-table-name)
+          (#{:desc :asc} order)
+          (not (nil? start))
+          (#{:after :before} direction)
+          (integer? limit)
+          (or (#{:recent-activity :recently-posted :digest} sort-type)
+              (and (= sort-type :bookmarked-at)
+                   (seq user-id)))
+          (or (nil? container-last-seen-at)
+              (string? container-last-seen-at))
+          (or (nil? follow-data)
+              (coll? follow-data))
+          (sequential? relation-fields)
+          (every? db-common/s-or-k? relation-fields)
+          (boolean? count)
+          (boolean? unseen)]}
+   (let [order-fn (if (= order :desc) r/desc r/asc)
+         unseen-cap-ms (* 1000 60 60 24 config/unseen-cap-days)
+         pins-sort-pivot-ms (* 1000 60 60 24 config/pins-sort-pivot-days)
+         allowed-board-uuids (map :uuid allowed-boards)
+         private-board-uuids (map :uuid (filter #(= (:access %) "private") allowed-boards))
+         pins-allowed-boards (when container-id
+                               (set (conj allowed-board-uuids config/seen-home-container-id)))
+         fixed-container-id (when (and pins-allowed-boards
+                                       (pins-allowed-boards container-id))
+                              container-id)]
+     (db-common/with-timeout db-common/default-timeout
+       (as-> (r/table table-name) query
+         (r/get-all query index-value {:index index-name})
+            ;; Merge in last-activity-at, last-seen-at and sort-value
+         (r/merge query (r/fn [post-row]
+                          (let [last-activity-at (-> (r/table relation-table-name)
+                                                     (r/get-all [[(r/get-field post-row :uuid) true]] {:index :resource-uuid-comment})
+                                                     (r/max :created-at)
+                                                     (r/get-field :created-at)
+                                                     (r/default (r/get-field post-row :published-at))
+                                                     (r/default (r/get-field post-row :created-at)))
+                                can-pin-to-container? (r/and (r/default (r/get-field post-row [:pins fixed-container-id]) nil)
+                                                             (r/or (r/ne container-id config/seen-home-container-id)
+                                                                   (r/not (r/contains (r/coerce-to private-board-uuids :array)
+                                                                                (r/get-field post-row [:board-uuid])))))
+                                sort-field (cond ;; Recent activity sort
+                                             (= sort-type :recent-activity)
+                                             last-activity-at
+                                     ;; Digest sort (recently published without pins at the top)
+                                             (= sort-type :digest)
+                                             (r/default (r/get-field post-row :published-at)
+                                               (r/get-field post-row :created-at))
+                                             (= sort-type :bookmarked-at)
+                                             (-> (r/get-field post-row [:bookmarks])
+                                                 (r/filter {:user-id user-id})
+                                                 (r/nth 0)
+                                                 (r/get-field :bookmarked-at)
+                                                 (r/default (r/get-field post-row :published-at))
+                                                 (r/default (r/get-field post-row :created-at)))
+                                     ;; In all other cases, check if container can contain pins
+                                             :else
+                                             (r/branch can-pin-to-container?
+                                                       (-> (r/get-field post-row [:pins fixed-container-id :pinned-at])
+                                                           (r/default (r/get-field post-row :published-at))
+                                                           (r/default (r/get-field post-row :created-at)))
+                                               ;:else
+                                                       (r/default (r/get-field post-row :published-at)
+                                                         (r/get-field post-row :created-at))))
+                                sort-value-base (-> sort-field
+                                                    (r/iso8601)
+                                                    (r/to-epoch-time)
+                                                    (r/mul 1000)
+                                                    (r/round))
+                                unseen-entry? (r/and (seq container-last-seen-at)
+                                                     (r/gt (r/get-field post-row :published-at) container-last-seen-at))
+                                unseen-with-cap? (r/and unseen-entry?
+                                                        (r/gt sort-value-base
+                                                              (-> (r/now) (r/to-epoch-time) (r/mul 1000) (r/round) (r/sub unseen-cap-ms))))
+                                sort-value (r/branch (r/eq sort-type :digest)
+                                                     sort-value-base
+                                                     (r/branch can-pin-to-container?
+                                                   ;; If the item is pinned and was published (for recently posted) in the cap window
+                                                   ;; let's add the cap window to the publish timestamp so it will sort before the seen ones
+                                                               (r/add sort-value-base pins-sort-pivot-ms)
+                                                   ;; :else
+                                                               (r/branch unseen-with-cap?
+                                                             ;; If the item is unseen and was published (for recently posted) or bookmarked
+                                                             ;; (for bookmarks) or last activity was (for recent activity) in the cap window
+                                                             ;; let's add the cap window to the publish timestamp so it will sort before the seen ones
+                                                                         (r/add sort-value-base unseen-cap-ms)
+                                                             ;; :else
+                                                                         sort-value-base)))]
+                            {;; Date of the last added comment on this entry
+                             :last-activity-at last-activity-at
+                 ;; Sorting base value: the timestamp of the event without pins or unseen changes
+                             :sort-base sort-value-base
+                 ;; The real value used for the sort
+                             :sort-value sort-value
+                 ;; If the entry is unseen
+                             :unseen unseen-with-cap?})))
+            ;; Filter out:
+         (r/filter query (r/fn [row]
+                           (r/and ;; and filter on follow data
+                            (r/or ;; no filter if it's nil
+                             (not (map? follow-data))
+                           ;; filter on followed authors and on not unfollowed boards
+                             (r/and (:following follow-data)
+                                    (r/or (r/contains (vec (:follow-publisher-uuids follow-data)) (r/get-field row [:publisher :user-id]))
+                                          (r/not (r/contains (vec (:unfollow-board-uuids follow-data)) (r/get-field row :board-uuid)))))
+                           ;; filter on not followed authors and on unfollowed boards
+                             (r/and (:unfollowing follow-data)
+                                    (r/not (r/contains (vec (:follow-publisher-uuids follow-data)) (r/get-field row [:publisher :user-id])))
+                                    (r/contains (vec (:unfollow-board-uuids follow-data)) (r/get-field row :board-uuid))))
+                     ;; Filter out seen entries if unseen flag is on
+                            (r/or (r/not unseen)
+                                  (r/default (r/get-field row :unseen) false))
+                     ;; When sorting from most recent and using before limit
+                     ;; it's necessary to use the sort-base value to avoid cutting out posts sorted at the top
+                            (r/or (r/and (= direction :before)
+                                         (r/gt start (r/get-field row :sort-base)))
+                           ;; for after instead we can use the sort-value since
+                           ;; there is no top limit
+                                  (r/and (= direction :after)
+                                         (r/le start (r/get-field row :sort-value)))))))
+            ;; Merge in all the interactions
+         (if-not count
+           (r/merge query (r/fn [post-row]
+                            {:interactions (-> (r/table relation-table-name)
+                                               (r/get-all [(r/get-field post-row :uuid)] {:index :resource-uuid})
+                                               (r/pluck relation-fields)
+                                               (r/coerce-to :array))}))
+           query)
+         (if-not count
+           (r/order-by query (order-fn :sort-value))
+           query)
+            ;; Apply count if needed
+         (if count (r/count query) query)
+            ;; Apply limit
+         (if (and (pos? limit)
+                  (not count))
+           (r/limit query limit)
+           query)
+            ;; Run!
+         (r/run query conn)
+         (db-common/drain-cursor query))))))
+
 (defn read-all-inbox-for-user

  ([conn table-name index-name index-value order start limit relation-table-name allowed-boards user-id
@@ -192,13 +351,12 @@
         (string? user-id)
         (sequential? relation-fields)
         (every? db-common/s-or-k? relation-fields)]}
-  (let [index-values (if (sequential? index-value) index-value [index-value])
-        order-fn (if (= order :desc) r/desc r/asc)
+  (let [order-fn (if (= order :desc) r/desc r/asc)
         minimum-date-timestamp (f/unparse lib-time/timestamp-format (t/minus (t/now) (t/days config/unread-days-limit)))
         allowed-board-uuids (map :uuid allowed-boards)]
     (db-common/with-timeout db-common/default-timeout
       (as-> (r/table table-name) query
-            (r/get-all query index-values {:index index-name})
+            (r/get-all query index-value {:index index-name})
             ;; Filter out:
             (r/filter query (r/fn [post-row]
               (r/and ;; All records in boards the user has no access
@@ -473,13 +631,18 @@
          (boolean? unseen)]}
   (let [order-fn (if (= order :desc) r/desc r/asc)
         unseen-cap-ms (- (lib-time/now-ts) (* 1000 60 60 24 config/unseen-cap-days))
-        board-uuid-org-uuid-vals (mapv #(vec [true (:uuid %) org-uuid]) allowed-boards)
         has-seen-at? (seq container-last-seen-at)
         container-seen-ms (when has-seen-at?
-                            (lib-time/millis container-last-seen-at))]
+                            (lib-time/millis container-last-seen-at))
+        index-name (if allowed-boards
+                     :comment-board-uuid-org-uuid
+                     :comment-org-uuid)
+        index-value (if allowed-boards
+                      (map #(vec [true (:uuid %) org-uuid]) allowed-boards)
+                      [[true org-uuid]])]
     (db-common/with-timeout db-common/default-timeout
       (as-> (r/table "interactions") query
-        (r/get-all query board-uuid-org-uuid-vals {:index :comment-board-uuid-org-uuid})
+        (r/get-all query index-value {:index index-name})
         (r/group query :resource-uuid) ;;(r/group query {:index :resource-uuid})
         (r/max query :created-at)
         (r/ungroup query)


Add publication-pool to defrecord keys

Add publication-pool to defrecord keys

--- src/onyx/messaging/aeron.clj
+++ src/onyx/messaging/aeron.clj
@@ -24,9 +24,8 @@
   (format "udp://%s:%s" addr port))

 (defrecord AeronMessenger
-    [peer-group messaging-group publication-group short-circuitable?
-     publications virtual-peers acking-daemon acking-ch send-idle-strategy
-     compress-f]
+    [peer-group messaging-group publication-group short-circuitable? publication-pool
+     virtual-peers acking-daemon acking-ch send-idle-strategy compress-f]
   component/Lifecycle

   (start [component]
@@ -380,8 +379,8 @@
         (pubm/write pub-man buf 0 protocol/ack-msg-length)))))

 (defmethod extensions/internal-ack-segments AeronMessenger
-  [messenger event {:keys [acker-id] :as conn-spec} acks]
-  (if ((:short-circuitable? messenger) (:channel conn-spec))
+  [messenger event {:keys [acker-id channel] :as conn-spec} acks]
+  (if ((:short-circuitable? messenger) channel)
     (ack-segments-short-circuit (lookup-channels messenger acker-id) acks)
     (let [pub-man (get-publication (:publication-pool messenger) conn-spec)
           buf ^UnsafeBuffer (protocol/build-acker-messages acker-id acks)


add tests for assertion errors

add tests for assertion errors

--- test/open_company/unit/representations/company.clj
+++ test/open_company/unit/representations/company.clj
@@ -9,4 +9,7 @@
   (fact "returns only links that have been provided"
     (let [links (#'c/company-links* {:name "Test" :slug "test"} [:self :partial-update])]
       (map (comp keyword :rel) links) => [:self :partial-update]
-      (count links) => 2)))+      (count links) => 2))
+  (fact "throws assertions when wrong args are passed"
+    (#'c/company-links* {:name "Test" :slug "test"} :bogus) => (throws AssertionError)
+    (#'c/company-links* {:name "Test" :slug "test"} [:bogus]) => (throws AssertionError)))


delete unused file

delete unused file

--- src/pc/views/blog/common.clj
+++ src/pc/views/blog/common.clj
@@ -1 +0,0 @@
-(ns pc.views.blog.common)


Revert "Add input processors backwards"

Revert "Add input processors backwards"

This reverts commit e50bf569d14749b6d38e7aba0677f56fa83d8b36.

--- src/play_clj/core_basics.clj
+++ src/play_clj/core_basics.clj
@@ -140,7 +140,7 @@
 (defn ^:private add-input!
   [^InputProcessor p]
   (when-let [^InputMultiplexer multi (input! :get-input-processor)]
-    (.setProcessors multi (doto (.getProcessors multi) (.insert 0 p)))))
+    (.addProcessor multi p)))

 (defn ^:private remove-input!
   [^InputProcessor p]


Further outline what needs to be done

Further outline what needs to be done

--- src/bejeweled_bot/gem_classifier.clj
+++ src/bejeweled_bot/gem_classifier.clj
@@ -9,18 +9,21 @@
    :opal        {:red 224  :green 224 :blue 224}
    :diamond     {:red 16 :green 139 :blue 254}})

+(defn abs [n] (max n (- n)))
+
 (defn rgb-to-gems
   [rgb-array]

   (map
     (fn [row]
       (fn [item]
-        ())
+        (classify item))
       row)
     rgb-array))

 ()
 (defn- classify
+  "Takes a map with red/green/blue values, returns the gem type or nil if no gem types match"
   [item]
   ())


Improve docstring

Improve docstring

--- src/caesium/magicnonce/secretbox.clj
+++ src/caesium/magicnonce/secretbox.clj
@@ -106,7 +106,7 @@
   repeated, instead of the usual plaintext disclosure that happens.

   If no nonce argument is specified, a random nonce is automatically
-  selected for you, and the nmr scheme is still applied."
+  selected for you, and the NMR scheme is applied on top of that."
   ([msg nonce key])
   ([msg key]
    (secretbox-nmr msg (random-nonce!) key)))


handle create responses

handle create responses

--- src/chat/server/extensions/asana.clj
+++ src/chat/server/extensions/asana.clj
@@ -123,8 +123,9 @@
                                      :oauth-token (ext :token)}
                                     opts))]
      (condp = (:status resp)
-       200
-       (-> resp :body json/read-str)
+       200 (-> resp :body json/read-str)
+
+       201 (-> resp :body json/read-str)

        401
        (do (timbre/warnf "token expired %s %s" (:status resp) (:body resp))


Out shouldn't be seeded with random

Out shouldn't be seeded with random

--- benchmarks/caesium/crypto/secretbox_benchmark.clj
+++ benchmarks/caesium/crypto/secretbox_benchmark.clj
@@ -48,5 +48,5 @@
       (println f (fmt-bytes size))
       (let [key (randombytes s/keybytes)
             nonce (randombytes s/noncebytes)
-            out (randombytes (+ s/macbytes size))]
+            out (byte-array (+ s/macbytes size))]
         (bench (f out msg nonce key))))))


Correction of the rule to avoid duplicates

--- src/clj/algorithms_clj/ancestors.clj
+++ src/clj/algorithms_clj/ancestors.clj
@@ -63,7 +63,9 @@
   "Indicates whether x and y had a child together"
   [x y]
   (fresh [z]
-    (!= x y)
+    (project [x y]
+      (compare x y))
+    ;;(!= x y)
     (parent x z)
     (parent y z)
     ))


Added docstring to mk-date-header

Added docstring to mk-date-header

--- src/clj/forma/postprocess/output.clj
+++ src/clj/forma/postprocess/output.clj
@@ -73,6 +73,9 @@
   (reduce str (split date-str #"-")))

 (defn mk-date-header
+  "(mk-date-header \"16\" \"p\" (s/timeseries-value 827 (range 141)))
+    63
++  => (\"p20051219\" \"p20060101\" \"p20060117\" ... \"p20120117\")"
   [tres prefix ts]
   (map (comp (partial str prefix)
              date-no-sep


accept-ws function broke into several interceptors

--- src/clj/hellhound/http/websocket.clj
+++ src/clj/hellhound/http/websocket.clj
@@ -106,10 +106,12 @@
 ;;   [service-map {:keys [packer url] :as options}])

 (defn bad-request
-  [{:keys [request]}]
-  {:status 400
-   :headers {"content-type" "application/text"}
-   :body (str "Expected a websocket request.")})
+  ([context]
+   (bad-request context ""))
+  ([{:keys [request]} msg]
+   {:status 400
+    :headers {"content-type" "application/text"}
+    :body (str "Expected a websocket request." msg)}))

 ;; (defn setup-event-router
@@ -138,14 +140,12 @@
   [{:keys [request input output uid send->user?] :as context}]
   (->
    (deferred/chain
-     (http/websocket-connection request)
-     (setup-user-connection uid input output send->user?)
-     (fn [socket] (stream/connect socket output) socket))
+     (http/websocket-connection request))
    (deferred/catch
        Exception
        ;; TODO: We need to return the exception message
        ;; instead of its instance.
-       (fn [e] (non-websocket-request (.getMessage e))))))
+       (fn [e] (bad-request context (.getMessage e))))))

 (defn ws
   [{:keys [uid] :as context}]
@@ -166,10 +166,33 @@
   (assoc context
          :uid (str (java.util.UUID/randomUUID))))

+(defn setup-ws-output
+  [{:keys [uid output socket] :as context}]
+  (when uid
+    ;; TODO: inject the uid or even the context to the
+    ;; outgoing message.
+    (stream/connect socket output))
+  ;; TODO: If uid was nil, should we kill the connection ?
+  context)
+
+(defn setup-ws-input
+  [{:keys [uid input socket send->user?] :as context}]
+  (when uid
+    (stream/connect-via input
+                        #(when (send->user? context) (stream/put! socket %))
+                        socket))
+  context)
+
 (defn interceptor-factory
   []
-  [{:name ::websocket-user-id-interceptor
+  [{:name  ::ws-user-id-interceptor
     :enter get-or-create-user-id}

-   {:name ::websocket-interceptor
-    :enter ws}])
+   {:name  ::ws-connection-interceptor
+    :enter ws}
+
+   {:name  ::ws-output-interceptor
+    :enter setup-ws-output}
+
+   {:name  ::ws-input-interceptor
+    :enter setup-ws-input}])


Bugfix

Bugfix

--- src/cljs_bjj_tournament/matches.cljs
+++ src/cljs_bjj_tournament/matches.cljs
@@ -60,25 +60,25 @@
                           :on-click #(dispatch [:delete-match (:guid m)])]]]))
         empty-selection? #(nil? (first %))]

-    (fn []
-      [v-box
-       :children
-       [[h-box
-         :justify :between
-         :children [[title :label "Matches" :level :level2]
-                    [button
-                     :label "Show all"
-                     :on-click #(reset! division #{})]]]
-        (for [[id m first? last?] (enumerate (filter (fn [m]
-                                                       (let [div (first @division)]
-                                                         (if div
-                                                           (= (:division m)
-                                                              (:name div))
-                                                           true)))
-                                                     @matches))]
-          ^{:key id} (if (first @division)
-                       [match-link m id]
-                       [match-link m]))
+(fn []
+  [v-box
+   :children
+   [[h-box
+     :justify :between
+     :children [[title :label "Matches" :level :level2]
+                [button
+                 :label "Show all"
+                 :on-click #(reset! division #{})]]]
+    (doall (for [[id m first? last?] (enumerate (filter (fn [m]
+                                                          (let [div (first @division)]
+                                                            (if div
+                                                              (= (:division m)
+                                                                 (:name div))
+                                                              true)))
+                                                        @matches))]
+             (if (first @division)
+               ^{:key id} [match-link m id]
+               ^{:key id} [match-link m])))
         [button
          :label "Clear Matches"
          :on-click #(dispatch [:clear-matches (first @division)])]


[BUILD BROKEN] Currently changing jdbc usage and versions

--- src/clojure_rest/config/database.clj
+++ src/clojure_rest/config/database.clj
@@ -2,30 +2,15 @@
   (:import com.mchange.v2.c3p0.ComboPooledDataSource)
   (:require [clojure.java.jdbc :as sql]))

-(def db-config
+(def db
       {:classname "org.h2.Driver"
        :subprotocol "h2"
        :subname "mem:documents"
-       :user ""
+       :user "sa"
        :password ""})

-(defn pool
-     [config]
-     (let [cpds (doto (ComboPooledDataSource.)
-                  (.setDriverClass (:classname config))
-                  (.setJdbcUrl (str "jdbc:" (:subprotocol config) ":" (:subname config)))
-                  (.setUser (:user config))
-                  (.setPassword (:password config))
-                  (.setMaxPoolSize 6)
-                  (.setMinPoolSize 1)
-                  (.setInitialPoolSize 1))]
-       {:datasource cpds}))
-
-(def pooled-db (delay (pool db-config)))
-
-(defn db-connection [] @pooled-db)
-
-(sql/with-connection (db-connection)
-      (sql/create-table :documents [:id "varchar(256)" "primary key"]
-                                   [:title "varchar(1024)"]
-                                   [:text :varchar]))
+(sql/db-do-commands db
+      (sql/create-table-ddl :documents
+                            [:id "integer" "primary key"]
+                            [:title "varchar(1024)"]
+                            [:text :varchar]))


more api checks

more api checks

--- src/com/dollfreaks/bbb_gpio_test.clj
+++ src/com/dollfreaks/bbb_gpio_test.clj
@@ -9,7 +9,10 @@
     (prn "exported?" (pin/exported? p))
     (pin/output! p)
     (prn "output?" (pin/output? p))
+    (pin/high! p)
     (prn ":high?" (pin/high? p))
+    (pin/input! p)
+    (prn "input?" (pin/input? p))
     (pin/unexport! p)
     (prn "exported?" (pin/exported? p))
     (println "Hello, World!")))


Allow top level :shared key

Allow top level :shared key

--- src/cider_ci/builder/jobs/validator/project_configuration.clj
+++ src/cider_ci/builder/jobs/validator/project_configuration.clj
@@ -81,9 +81,11 @@
 ;##############################################################################

 (def project-config-meta-spec
-  {:jobs {:validator (build-map-of-validator validate-job!)}
+  {:jobs {:validator (build-map-of-validator validate-job!)
+          :required true }
    :name {:validator validate-string!}
    :description {:validator validate-string!}
+   :shared nil
    })

 (defn validate! [project-config]


Further neatening of (interposep) using destructuring

--- src/shared/hyjinks/core.cljc
+++ src/shared/hyjinks/core.cljc
@@ -14,12 +14,12 @@

 (defn- str-join [& items] (join "" (flatten items)))

-(defn- interposep [sep pred coll]
+(defn- interposep [sep pred [x & [y :as more]]]
   (cond
-    (empty? coll)                     (empty coll)
-    (= 1 (count coll))                coll
-    (pred (first coll) (second coll)) (concat [(first coll) sep] (interposep sep pred (rest coll)))
-    :else                             (concat [(first coll)] (interposep sep pred (rest coll)))))
+    (empty? coll)      (empty coll)
+    (= 1 (count coll)) coll
+    (pred x y)         (concat [x sep] (interposep sep pred more))
+    :else              (concat [x] (interposep sep pred more))))

 (defn- str-join-extra-spaces [& items]
   (->> items


update dependencies, with report from lein-ancient

Tests still passing, this is the output from lein-ancient now,
jsonevent-layout and netty must remain at these versions for now.

```
[net.logstash.log4j/jsonevent-layout "1.6"] is available but we use "1.5"
[io.netty/netty "4.0.0.Alpha8"] is available but we use "3.8.0.Final"
[log4j/apache-log4j-extras "1.2.17"] is available but we use "1.0"
[org.antlr/antlr "3.5.2"] is available but we use "3.2"
```

--- project.clj
+++ project.clj
@@ -10,33 +10,33 @@
   }
   :maintainer {:email "aphyr@aphyr.com"}
   :dependencies [
-    [org.clojure/algo.generic "0.1.1"]
+    [org.clojure/algo.generic "0.1.2"]
     [org.clojure/clojure "1.5.1"]
-    [org.clojure/math.numeric-tower "0.0.2"]
+    [org.clojure/math.numeric-tower "0.0.4"]
     [org.clojure/tools.logging "0.2.6"]
     [org.clojure/tools.nrepl "0.2.3"]
     [org.clojure/core.cache "0.6.3"]
-    [org.clojure/java.classpath "0.2.1"]
+    [org.clojure/java.classpath "0.2.2"]
     [clojure-complete "0.2.3"]
-    [log4j/log4j "1.2.16" :exclusions [javax.mail/mail
+    [log4j/log4j "1.2.17" :exclusions [javax.mail/mail
                                        javax.jms/jms
                                        com.sun.jdmk/jmxtools
                                        com.sun.jmx/jmxri]]
     [net.logstash.log4j/jsonevent-layout "1.5"]
-    [aleph "0.3.1"]
-    [clj-http "0.7.7"]
-    [cheshire "5.2.0"]
+    [aleph "0.3.2"]
+    [clj-http "0.9.1"]
+    [cheshire "5.3.1"]
     [clj-librato "0.0.4-SNAPSHOT"]
     [clj-time "0.6.0"]
     [clj-wallhack "1.0.1"]
-    [com.boundary/high-scale-lib "1.0.3"]
+    [com.boundary/high-scale-lib "1.0.4"]
     [com.draines/postal "1.11.1"]
-    [com.amazonaws/aws-java-sdk "1.4.1"]
+    [com.amazonaws/aws-java-sdk "1.7.5"]
     [interval-metrics "0.0.2"]
     [io.netty/netty "3.8.0.Final"]
     [log4j/apache-log4j-extras "1.0"]
     [org.antlr/antlr "3.2"]
-    [org.slf4j/slf4j-log4j12 "1.7.5"]
+    [org.slf4j/slf4j-log4j12 "1.7.7"]
     [riemann-clojure-client "0.2.10-SNAPSHOT"]
     [slingshot "0.10.3"]
     [clj-campfire "2.2.0"]
@@ -45,7 +45,7 @@
   ]
   :plugins [[codox "0.6.1"]
             [lein-rpm "0.0.5"]]
-  :profiles {:dev {:dependencies [[criterium "0.4.1"]]}}
+  :profiles {:dev {:dependencies [[criterium "0.4.3"]]}}
   :test-selectors {:default (fn [x] (not (or (:integration x)
                                              (:time x)
                                              (:bench x))))


revert to Clojure 1.7.0-RC1

revert to Clojure 1.7.0-RC1

--- project.clj
+++ project.clj
@@ -4,7 +4,7 @@
   :license {:name "MIT"
             :url "http://opensource.org/licenses/MIT"}

-  :dependencies [[org.clojure/clojure "1.7.0"]
+  :dependencies [[org.clojure/clojure "1.7.0-RC1"]
                  [org.clojure/clojurescript "0.0-3308"]
                  [org.clojure/core.async "0.1.346.0-17112a-alpha"]
                  [aleph "0.4.0"]


0.1.0 release w/ correct maven.

0.1.0 release w/ correct maven.

--- project.clj
+++ project.clj
@@ -1,4 +1,4 @@
-(defproject think.datatype "0.2.0-SNAPSHOT"
+(defproject thinktopic/datatype "0.1.0"
   :description "Library for efficient manipulation of contiguous mutable containers of primitive datatypes."
   :url "http://github.com/thinktopic/think.datatype"
   :license {:name "Eclipse Public License"


remove support for clojure 1.2/1.3

remove support for clojure 1.2/1.3

--- project.clj
+++ project.clj
@@ -19,4 +19,4 @@
              :1.5 {:dependencies [[org.clojure/clojure "1.5.1"]]}
              :1.7 {:repositories [["snapshots" "https://oss.sonatype.org/content/repositories/snapshots/"]]
                    :dependencies [[org.clojure/clojure "1.7.0-master-SNAPSHOT"]]}}
-  :aliases {"test-all" ["with-profile" "dev,default:dev,1.2,default:dev,1.3,default:dev,1.4,default:dev,1.5,default:dev,1.7,default" "test"]})
+  :aliases {"test-all" ["with-profile" "dev,default:dev,1.4,default:dev,1.5,default:dev,1.7,default" "test"]})


bump to 0.3.22-SNAPSHOT

bump to 0.3.22-SNAPSHOT

--- project.clj
+++ project.clj
@@ -3,7 +3,7 @@
   [path]
   (str "resources/public/js/lib/" path))

-(defproject onaio/hatti "0.3.21"
+(defproject onaio/hatti "0.3.22-SNAPSHOT"
   :description "A cljs dataview from your friends at Ona.io"
   :license "Apache 2, see LICENSE"
   :url "https://github.com/onaio/hatti"


Depend on Hayt 1.1.1

Depend on Hayt 1.1.1

--- project.clj
+++ project.clj
@@ -5,7 +5,7 @@
   :license {:name "Eclipse Public License"
             :url "http://www.eclipse.org/legal/epl-v10.html"}
   :dependencies [[org.clojure/clojure                          "1.5.1"]
-                 [cc.qbits/hayt                                "1.1.0"
+                 [cc.qbits/hayt                                "1.1.1"
                   :exclusions [org.flatland/useful]]
                  [com.datastax.cassandra/cassandra-driver-core "1.0.0"]]
   :source-paths      ["src/clojure"]


Version 0.0.7-SNAPSHOT

Version 0.0.7-SNAPSHOT

--- project.clj
+++ project.clj
@@ -1,4 +1,4 @@
-(defproject day8.re-frame/abra "0.0.6"
+(defproject day8.re-frame/abra "0.0.7-SNAPSHOT"
   :description "Tracing and developer tools for re-frame apps"
   :url         "https://github.com/Day8/re-frame-trace"
   :license     {:name "MIT"}


Cleaned-up project file.

Cleaned-up project file.

--- project.clj
+++ project.clj
@@ -4,7 +4,6 @@
   :license {:name "MIT"
             :url "http://opensource.org/licenses/MIT"}
   :plugins [[lein-pprint "1.1.2"]
-            [lein-marginalia "0.8.0"]
             [codox "0.8.10"]]
   :dependencies [[org.clojure/clojure "1.6.0"]
                  [org.clojure/tools.logging "0.3.1"]
@@ -19,9 +18,11 @@
                  [org.clojure/tools.nrepl "0.2.7"]]
   :resource-paths ["resources"]
   :profiles {:dev {:source-paths ["dev"]  ;ensures 'user.clj' gets auto-loaded
-                   :plugins [[cider/cider-nrepl "0.9.0-SNAPSHOT"]]
+                   :plugins [[cider/cider-nrepl "0.8.2"]]
                    :dependencies [[org.clojure/tools.namespace "0.2.7"]
                                   [org.clojure/java.classpath "0.2.2"]
                                   [org.clojure/data.json "0.2.5"]]
                    :resource-paths ["test-resources"]}
-             :test {:resource-paths ["test-resources"]}})
+             :test {:resource-paths ["test-resources"]}}
+  :repositories [["releases" {:url "https://clojars.org/repo"
+                              :creds :gpg}]])


Add link to extra ugens dependency

Add link to extra ugens dependency

--- project.clj
+++ project.clj
@@ -52,6 +52,7 @@
                  [overtone/midi-clj "0.4.0"]
                  [overtone/libs.handlers "0.2.0"]
                  [overtone/scsynth "3.5.3-SNAPSHOT"]
+                 [overtone/scsynth-extras "3.5.2-SNAPSHOT"]
                  [clj-glob "1.0.0"]
                  [org.clojure/core.match "0.2.0-alpha9"]
                  [seesaw "1.4.1"]]


(maint) Update version to 7.1.0-SNAPSHOT

--- project.clj
+++ project.clj
@@ -1,4 +1,4 @@
-(def ps-version "7.0.4-SNAPSHOT")
+(def ps-version "7.1.0-SNAPSHOT")

 (defn deploy-info
   [url]


Adding version number for the main dev system project.

--- project.clj
+++ project.clj
@@ -34,7 +34,9 @@
                   ["shell" "ln" "-s" (str "../../" (name project-name)) "checkouts/,"])
                 (keys projects)))))

-(defproject nasa-cmr/cmr-dev-system "0.1.0-SNAPSHOT"
+;; The version number here is for the sprint number. It will be incremented each sprint. The second
+;; number is for which delivery of the version was given to ECHO for use.
+(defproject nasa-cmr/cmr-dev-system "0.11.0"
   :description "Dev System combines together the separate microservices of the CMR into a single
                application to make it simpler to develop."
   :url "***REMOVED***projects/CMR/repos/cmr-dev-system/browse"


Bump version number to 1.3.0

Bump version number to 1.3.0

--- project.clj
+++ project.clj
@@ -1,4 +1,4 @@
-(defproject degasolv/degasolv "1.2.1-SNAPSHOT"
+(defproject degasolv/degasolv "1.3.0"
   :description "Dependency tracker with an eye toward building and shipping software."
   :url "http://github.com/djhaskin987/degasolv"
   :license {:name "Eclipse Public License"


Updated ring dependencies to 0.3.11

Updated ring dependencies to 0.3.11

--- project.clj
+++ project.clj
@@ -3,6 +3,6 @@
   :url "https://github.com/weavejester/lein-ring"
   :dependencies [[org.clojure/clojure "1.2.0"]
                  [org.clojure/clojure-contrib "1.2.0"]
-                 [ring/ring-jetty-adapter "0.3.10"]
-                 [ring/ring-devel "0.3.10"]
+                 [ring/ring-jetty-adapter "0.3.11"]
+                 [ring/ring-devel "0.3.11"]
                  [ring-reload-modified "0.1.1"]])


Continue development on 0.6.0.

Continue development on 0.6.0.

--- project.clj
+++ project.clj
@@ -1,4 +1,4 @@
-(defproject com.damballa/parkour "0.6.0-alpha5"
+(defproject com.damballa/parkour "0.6.0-SNAPSHOT"
   :description "Hadoop MapReduce in idiomatic Clojure."
   :url "http://github.com/damballa/parkour"
   :license {:name "Apache License, Version 2.0"