:tada: Add new storage implementation (builtin in backend).

error: pathspec 'backend/src/uxbox/util/storage.clj' did not match any file(s) known to git

--- backend/src/uxbox/util/storage.clj
+++ backend/src/uxbox/util/storage.clj
@@ -0,0 +1,181 @@
+;; This Source Code Form is subject to the terms of the Mozilla Public
+;; License, v. 2.0. If a copy of the MPL was not distributed with this
+;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
+;;
+;; This Source Code Form is "Incompatible With Secondary Licenses", as
+;; defined by the Mozilla Public License, v. 2.0.
+;;
+;; Copyright (c) 2020 Andrey Antukh <niwi@niwi.nz>
+
+(ns uxbox.util.storage
+  "A local filesystem storage implementation."
+  (:require
+   [clojure.java.io :as io]
+   [clojure.spec.alpha :as s]
+   [cuerdas.core :as str]
+   [datoteka.core :as fs]
+   [datoteka.proto :as fp]
+   [sodi.prng :as sodi.prng]
+   [sodi.util :as sodi.util]
+   [uxbox.common.exceptions :as ex])
+  (:import
+   java.io.ByteArrayInputStream
+   java.io.InputStream
+   java.io.OutputStream
+   java.net.URI
+   java.nio.file.Files
+   java.nio.file.NoSuchFileException
+   java.nio.file.Path
+   java.security.MessageDigest))
+
+(defn uri
+  [v]
+  (cond
+    (instance? URI v) v
+    (string? v) (URI. v)
+    :else (throw (IllegalArgumentException. "unexpected input"))))
+
+(defn- normalize-path
+  [^Path base ^Path path]
+  (when (fs/absolute? path)
+    (ex/raise :type :filesystem-error
+              :code :suspicious-operation
+              :hint "Suspicios operation: absolute path not allowed."
+              :contex {:path path :base base}))
+  (let [^Path fullpath (.resolve base path)
+        ^Path fullpath (.normalize fullpath)]
+    (when-not (.startsWith fullpath base)
+      (ex/raise :type :filesystem-error
+                :code :suspicious-operation
+                :hint "Suspicios operation: go to parent dir is not allowed."
+                :contex {:path path :base base}))
+    fullpath))
+
+(defn- transform-path
+  [storage ^Path path]
+  (if-let [xf (::xf storage)]
+    ((xf (fn [a b] b)) nil path)
+    path))
+
+(defn blob
+  [v]
+  (let [data (.getBytes v "UTF-8")]
+    (ByteArrayInputStream. ^bytes data)))
+
+(defn save!
+  [storage path content]
+  (s/assert ::storage storage)
+  (let [^Path base (::base-path storage)
+        ^Path path (->> (fs/path path)
+                        (transform-path storage))
+        ^Path fullpath (normalize-path base path)]
+    (when-not (fs/exists? (.getParent fullpath))
+      (fs/create-dir (.getParent fullpath)))
+    (loop [iteration nil]
+      (let [[basepath ext] (fs/split-ext fullpath)
+            candidate (fs/path (str basepath iteration ext))]
+        (if (fs/exists? candidate)
+          (recur (if (nil? iteration) 1 (inc iteration)))
+          (with-open [^InputStream src (io/input-stream content)
+                      ^OutputStream dst (io/output-stream candidate)]
+            (io/copy src dst)
+            (fs/relativize candidate base)))))))
+
+(defn delete!
+  [storage path]
+  (s/assert ::storage storage)
+  (try
+    (->> (fs/path path)
+         (normalize-path (::base-path storage))
+         (fs/delete))
+    true
+    (catch java.nio.file.NoSuchFileException e
+      false)))
+
+(defn clear!
+  [storage]
+  (s/assert ::storage storage)
+  (fs/delete (::base-path storage))
+  (fs/create-dir (::base-path storage))
+  nil)
+
+(defn exists?
+  [storage path]
+  (s/assert ::storage storage)
+  (->> (fs/path path)
+       (normalize-path (::base-path storage))
+       (fs/exists?)))
+
+(defn lookup
+  [storage path]
+  (s/assert ::storage storage)
+  (->> (fs/path path)
+       (normalize-path (::base-path storage))))
+
+(defn public-uri
+  [storage path]
+  (s/assert ::storage storage)
+  (let [^URI base (::base-uri storage)
+        ^String path (str path)]
+    (.resolve base path)))
+
+(s/def ::base-path (s/or :path fs/path? :str string?))
+(s/def ::base-uri (s/or :uri #(instance? URI %) :str string?))
+(s/def ::xf fn?)
+
+(s/def ::storage
+  (s/keys :req [::base-path] :opt [::xf ::base-uri]))
+
+(s/def ::create-options
+  (s/keys :req-un [::base-path] :opt-un [::xf ::base-uri]))
+
+(defn create
+  "Create an instance of local FileSystem storage providing an
+  absolute base path.
+
+  If that path does not exists it will be automatically created,
+  if it exists but is not a directory, an exception will be
+  raised.
+
+  This function expects a map with the following options:
+  - `:base-path`: a fisical directory on your local machine
+  - `:base-uri`: a base uri used for resolve the files
+  "
+  [{:keys [base-path base-uri xf] :as options}]
+  (s/assert ::create-options options)
+  (let [^Path base-path (fs/path base-path)]
+    (when (and (fs/exists? base-path)
+               (not (fs/directory? base-path)))
+      (ex/raise :type :filesystem-error
+                :code :file-already-exists
+                :hint "File already exists, expects directory."))
+    (when-not (fs/exists? base-path)
+      (fs/create-dir base-path))
+    (cond-> {::base-path base-path}
+      base-uri (assoc ::base-uri (uri base-uri))
+      xf (assoc ::xf xf))))
+
+(defn- bytes->sha256
+  [^bytes data]
+  (let [^MessageDigest md (MessageDigest/getInstance "SHA-256")]
+    (.update md data)
+    (.digest md)))
+
+(defn hash-path
+  [^Path path]
+  (let [name (str (.getFileName path))
+        hash (-> (sodi.prng/random-nonce 64)
+                 (bytes->sha256)
+                 (sodi.util/bytes->b64s))
+        tokens (re-seq #"[\w\d\-\_]{3}" hash)
+        path-tokens (take 6 tokens)
+        rest-tokens (drop 6 tokens)
+        path (fs/path path-tokens)
+        frest (apply str rest-tokens)]
+    (fs/path (list path frest name))))
+
+(defn slugify-filename
+  [path]
+  (let [parent (or (fs/parent path) "")
+        [name ext] (fs/split-ext (fs/name path))]
+    (fs/path parent (str (str/uslug name) ext))))


to array

to array

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/clojure-ml/cml.git/'


usage exmaples

usage exmaples

error: pathspec 'usage.clj' did not match any file(s) known to git

--- usage.clj
+++ usage.clj
@@ -0,0 +1,86 @@
+(ns usage)
+
+(use 'gyptis.core)
+
+(use 'clj-time.core)
+
+(def data [{:x "a", :y 0.1 :facet_y "a"}
+           {:x "b", :y 1 :facet_y "a"}
+           {:x "c", :y 2 :facet_y "a"}
+           {:x "d", :y 3 :facet_y "c"}])
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Let's make a bar chart
+
+;; plot every hashmap in `data' as a point
+(plot :bar-plot
+      (point data))
+
+(plot :bar-plot
+      (point data))
+
+;; plot every hashmap in `data' as a rectangle. Stacks bars with the same `x' value
+(plot :bar-plot
+      (bar data))
+
+;; dodge bars with the same `x' value
+(plot :bar-plot
+       (dodged-bar data))
+
+;; add labels
+(plot :bar-plot
+       (-> (dodged-bar data)
+           (assoc-in [:labels :x] "hii")
+           (assoc-in [:labels :y] "freq")))
+
+;; add mouse-over interactions
+(plot
+ :bar-plot
+ (-> (bar data)
+     (assoc-in [:marks 0 :properties :hover]
+               {:fill {:value "red"}})))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Works on time series.
+
+(require 'clj-time.core :refer [date-time])
+
+(def time-series-data
+  [{:x (date-time 2015 1 1), :y 100 :fill ""}
+   {:x (date-time 2015 1 1), :y 0 :fill "fb"}
+   {:x (date-time 2015 1 2), :y 1}
+   {:x (date-time 2015 1 3), :y 3}])
+
+(plot! :
+       (line time-data))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Plays well with jdbc
+
+(require 'clojure.java.jdbc :as sql)
+(require 'gyptis.usage-helpers :as h)
+
+(def unemployment-rate-by-county-id
+  (sql/query h/db [(str "SELECT id as x,"
+                        "rate as y "
+                        "FROM unemployment"
+                        "ORDER BY y desc"
+                        "LIMIT 20")]))
+
+(plot! :bar-plot (stacked-bar unemployment-rate-by-county-id))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Let's make a map
+
+(def county-unemployment-geo
+  (sql/query h/db [(str "SELECT us_10m.state as layout_path,"
+                        "rate as fill"
+                        "FROM unemployment"
+                        "WHERE us_10m.state=state")]))
+
+(plot! "unemploy-map"
+       (choropleth unemployment-rate-by-county))


confidencr interval

confidencr interval


refactoring and fixing segment issues Still not done.

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/yokalona/threen.git/'


refactor syncat.cio/watch-dir

refactor syncat.cio/watch-dir

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/runoshun/syncat.git/'


[WM] update export test for authority levels

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/democracyworks/election-authority-works.git/'


Update docstrings.

Update docstrings.

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/mtravers/incidents.git/'


client clojurescript code

client clojurescript code

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/sbondaryev/cljs-client-server.git/'


quick comment to keep track of next steps.

--- src/metabase/api/qs.clj
+++ src/metabase/api/qs.clj
@@ -20,7 +20,9 @@
                 :sql (:sql body)
                 :timezone (get body :timezone)
                 }}
-    (execute-query)))
+    (execute-query)
+    ;; TODO - format the response of execute-query for the client
+    ))

 ;; TODO - not using defendpoint due to string params causing number format exceptions


Add PG Native Query Type Mapping

Add PG Native Query Type Mapping

--- src/metabase/driver.clj
+++ src/metabase/driver.clj
@@ -31,16 +31,17 @@

 (def ^:const class->base-type
   "Map of classes returned from DB call to metabase.models.field/base-types"
-  {java.lang.Boolean    :BooleanField
-   java.lang.Double     :FloatField
-   java.lang.Float      :FloatField
-   java.lang.Integer    :IntegerField
-   java.lang.Long       :IntegerField
-   java.lang.String     :TextField
-   java.math.BigDecimal :DecimalField
-   java.math.BigInteger :BigIntegerField
-   java.sql.Date        :DateField
-   java.sql.Timestamp   :DateTimeField})
+  {java.lang.Boolean            :BooleanField
+   java.lang.Double             :FloatField
+   java.lang.Float              :FloatField
+   java.lang.Integer            :IntegerField
+   java.lang.Long               :IntegerField
+   java.lang.String             :TextField
+   java.math.BigDecimal         :DecimalField
+   java.math.BigInteger         :BigIntegerField
+   java.sql.Date                :DateField
+   java.sql.Timestamp           :DateTimeField
+   org.postgresql.util.PGobject :UnknownField}) ; this mapping included here since Native QP uses class->base-type directly. TODO - perhaps make *class-base->type* driver specific?

 ;; ## Driver Lookup


Back up previous orthotope valuation stuff.

error: pathspec 'extra/dnf_orthotope_valuations.clj' did not match any file(s) known to git

--- extra/dnf_orthotope_valuations.clj
+++ extra/dnf_orthotope_valuations.clj
@@ -0,0 +1,156 @@
+(ns edu.berkeley.ai.angelic.hybrid-dnf-simple-valuations
+  (:use [edu.berkeley.ai.angelic :as angelic])
+  (:import [java.util HashMap])
+  (:require [edu.berkeley.ai [util :as util] [envs :as envs]]
+            [edu.berkeley.ai.util [propositions :as props] [hybrid :as hybrid]]
+	    ))
+
+;;; Like DNF simple valuations, but keep a Polytope (orthotope?) for numeric vars.
+
+; TODO: think about splitting out constant part of state.
+
+(defstruct hybrid-dnf-clause :conj :imap)
+(defn make-hybrid-dnf-clause [conj imap] (struct hybrid-dnf-clause conj imap))
+
+
+(derive ::HybridDNFSimpleValuation :edu.berkeley.ai.angelic/PropositionalValuation)
+(defstruct hybrid-dnf-simple-valuation :class :clauses)
+(defn make-hybrid-dnf-simple-valuation [clauses]
+  (if (not (empty? clauses))
+      (struct hybrid-dnf-simple-valuation ::HybridDNFSimpleValuation clauses)
+    *pessimal-valuation*))
+
+
+(def *reward-var* [(gensym "reward")]) ; Special dummy variable used to store reward
+
+
+(defmethod state->valuation     ::HybridDNFSimpleValuation [type state]
+  (let [[discrete-atoms numeric-fns] state]
+    (make-hybrid-dnf-simple-valuation
+     [(make-hybrid-dnf-clause
+       (util/map-map #(vector % :true) discrete-atoms)
+       (assoc (util/map-vals #(util/make-point-interval %) numeric-fns)
+	 *reward-var* 0))])))
+
+(defmethod get-valuation-lower-bound ::HybridDNFSimpleValuation [val]
+  (reduce min (map #(util/safe-get-in % [:imap *reward-var*]) (:clauses val))))
+
+(defmethod get-valuation-upper-bound ::HybridDNFSimpleValuation [val]
+  (reduce max (map #(util/safe-get-in % [:imap *reward-var*]) (:clauses val))))
+
+(defmethod empty-valuation?         ::HybridDNFSimpleValuation [val]
+  false)
+
+
+;; Hierarchical preconditions for use with this sort of valuation
+;(derive ::HybridHierarchicalPrecondition ::envs/Conddition
+(defstruct hybrid-hierarchical-precondition :pos :neg :var-const :var-form :form-form :form-const)
+
+(defn make-hybrid-hierarchical-precondition [pos neg var-const var-form form-form form-const]
+  (struct hybrid-hierarchical-precondition pos neg var-const var-form form-form form-const))
+
+(def *true-hhp* (make-hybrid-hierarchical-precondition nil nil nil nil nil nil))
+
+(defn conjoin-hybrid-hierarchical-preconditions [h1 h2]
+  (cond (= h1 *true-hhp*) h2
+	(= h2 *true-hhp*) h1
+	:else             (merge-with concat h1 h2)))
+
+(let [types
+      [[::hybrid/NumVar ::hybrid/NumConst]
+       [::hybrid/NumVar ::hybrid/NumForm]
+       [::hybrid/NumForm ::hybrid/NumForm]
+       [::hybrid/NumForm ::hybrid/NumConst]]]
+  (defn extract-hybrid-hierarchical-precondition [pos neg num var-map constant-numeric-functions numeric-vals]
+    (let [diffs (hybrid/extract-difference-constraints num var-map constant-numeric-functions numeric-vals)
+	  cdiffs (util/group-by #(vector (:class (:left %)) (:class (:right %))) diffs)]
+      (util/assert-is (empty? (util/difference-coll (util/keyset types) types)))
+      (apply make-hybrid-hierarchical-precondition
+	     (map #(props/simplify-atom var-map %) pos)
+	     (map #(props/simplify-atom var-map %) neg)
+	     (map cdiffs types)))))
+
+;; TODO: change to dish out
+(defn split-and-var-translate-hhp [con var-pos-map expansion-len]
+  (let [{:keys [pos neg var-form form-form form-const]} con
+	ret (vec (cons (make-hybrid-hierarchical-precondition
+			pos neg nil nil form-form form-const)
+		       (repeat (dec expansion-len) *true-hhp*)))]
+    (reduce (fn [ret vf]
+	      (let [var (util/safe-get vf :var)
+		    [ind nv] (util/safe-get var-pos-map var)]
+		(assoc ret ind
+		       (util/assoc-cons (nth ret ind)
+			  :var-form (hybrid/make-numeric-var nv)))))
+	    var-form)))
+
+
+; TODO: what if we have two constraints on a given variable.
+; Are we required to properly implement tightest transitive closure for pessimistic?
+; Not here, but below ...
+
+; Say x > y, x < z, y = [1, 3], z = [0, 2]
+; y = 3 is not achievable under any primitive refinement
+
+; Vars can say whatever they want (as long as you don't care about hierarchical preconditions ...)
+
+(defn restrict-var-map [val con var-map]
+  "Perform inference the opposite way of restrict-valuation."
+  ;; TODO!!
+  )
+
+
+
+;; TODO: here we are *required* to, at least for pessimistic, find transitive closure of constraints or some such.
+; This can require considering arbitrary numbers of state variables & constraints together?
+; X > Y + 1 > Z + 2 > Q + 4 > R. R in [0,1].  These chains may pass through HLA vars.
+; Constraints form a lattice?  Except there may be cycles with different diffs.
+
+; --> Simple Temporal Problem !!!!
+; Set of STP intervals correct for optimistic
+; For pessimistic, need non-overlapping intervals (*every* state)
+ ; idea: take upper-maximal and lower-maximal intervals?  This will make clause set grow exp'lly in general...
+   ; otherwise, which is right?  fill up on gas, or buy no gas ???
+
+; Be sure to leave var constraints in there.
+
+
+(defmethod restrict-valuation       [::HybridDNFSimpleValuation :edu.berkeley.ai.envs/ConjunctiveCondition] [val con]
+  (throw (UnsupportedOperationException.)))
+
+(defmethod explicit-valuation-map ::HybridDNFSimpleValuation [val]
+  (throw (UnsupportedOperationException.)))
+
+(defmethod get-valuation-states   ::HybridDNFSimpleValuation [val]
+  (throw (UnsupportedOperationException.)))
+
+(defmethod valuation->pred-maps   ::HybridDNFSimpleValuation [val]
+  (for [clause (util/safe-get val :clauses)]
+    (let [true-map (HashMap.) poss-map (HashMap.)]
+      (doseq [[#^clojure.lang.APersistentVector pred stat] (util/safe-get clause :conj)]
+	(let [#^HashMap m (if (= stat :true) true-map poss-map)
+	      pred-name (.get pred 0)]
+	  (.put m pred-name (cons pred (.get m pred-name)))))
+      [true-map poss-map])));)
+
+
+(comment
+
+(defn restrict-clause [clause pos neg]
+  (when-let [after-pos
+	     (loop [pos pos clause clause]
+	       (cond (empty? pos)                   clause
+		     (contains? clause (first pos)) (recur (next pos) (assoc clause (first pos) :true))
+		     :else nil))]
+    (loop [neg neg clause after-pos]
+      (cond (empty? neg)                       clause
+	    (= :true (get clause (first neg))) nil
+	    :else  (recur (next neg) (dissoc clause (first neg)))))))
+
+(defmethod restrict-valuation       [::HybridDNFSimpleValuation :edu.berkeley.ai.envs/ConjunctiveCondition] [val con]
+  (let [pos (envs/get-positive-conjuncts con)
+	neg (envs/get-negative-conjuncts con)]
+    (make-dnf-simple-valuation
+     (filter identity (for [clause (:dnf val)] (restrict-clause clause pos neg)))
+     (:bound val))))
+)


Test group-by-key interaction with windowing

error: pathspec 'test/onyx/windowing/group_by_test.clj' did not match any file(s) known to git

--- test/onyx/windowing/group_by_test.clj
+++ test/onyx/windowing/group_by_test.clj
@@ -0,0 +1,130 @@
+(ns onyx.windowing.group-by-test
+  (:require [clojure.core.async :refer [chan >!! <!! close! sliding-buffer]]
+            [clojure.test :refer [deftest is]]
+            [onyx.plugin.core-async :refer [take-segments!]]
+            [onyx.test-helper :refer [load-config with-test-env]]
+            [onyx.api]
+            [taoensso.timbre :refer [info error warn trace fatal] :as timbre]))
+
+(def input
+  [{:id 1  :age 21 :event-time #inst "2015-09-13T03:00:00.829-00:00"}
+   {:id 2  :age 12 :event-time #inst "2015-09-13T03:04:00.829-00:00"}
+   {:id 3  :age 3  :event-time #inst "2015-09-13T03:05:00.829-00:00"}
+   {:id 4  :age 64 :event-time #inst "2015-09-13T03:06:00.829-00:00"}
+   {:id 5  :age 53 :event-time #inst "2015-09-13T03:07:00.829-00:00"}
+   {:id 6  :age 52 :event-time #inst "2015-09-13T03:08:00.829-00:00"}
+   ;; Extra values which have been seen to sum
+   {:id 7  :age 3 :event-time #inst "2015-09-13T03:08:00.829-00:00"}
+   {:id 8  :age 12 :event-time #inst "2015-09-13T03:08:00.829-00:00"}])
+
+(def expected-windows
+  [[Double/NEGATIVE_INFINITY
+    Double/POSITIVE_INFINITY
+    {21 21, 12 24, 3 6, 64 64, 53 53, 52 52}]])
+
+(def test-state (atom []))
+
+(defn update-atom! [event window-id lower-bound upper-bound state]
+  (swap! test-state conj [lower-bound upper-bound state]))
+
+(def in-chan (atom nil))
+
+(def out-chan (atom nil))
+
+(defn inject-in-ch [event lifecycle]
+  {:core.async/chan @in-chan})
+
+(defn inject-out-ch [event lifecycle]
+  {:core.async/chan @out-chan})
+
+(def in-calls
+  {:lifecycle/before-task-start inject-in-ch})
+
+(def out-calls
+  {:lifecycle/before-task-start inject-out-ch})
+
+(deftest min-test
+  (let [id (java.util.UUID/randomUUID)
+        config (load-config)
+        env-config (assoc (:env-config config) :onyx/id id)
+        peer-config (assoc (:peer-config config) :onyx/id id)
+        batch-size 20
+        workflow
+        [[:in :identity] [:identity :out]]
+
+        catalog
+        [{:onyx/name :in
+          :onyx/plugin :onyx.plugin.core-async/input
+          :onyx/type :input
+          :onyx/medium :core.async
+          :onyx/batch-size batch-size
+          :onyx/max-peers 1
+          :onyx/doc "Reads segments from a core.async channel"}
+
+         {:onyx/name :identity
+          :onyx/fn :clojure.core/identity
+          :onyx/type :function
+          :onyx/group-by-key :age
+          :onyx/min-peers 1
+          :onyx/max-peers 1
+          :onyx/flux-policy :recover
+          :onyx/batch-size batch-size}
+
+         {:onyx/name :out
+          :onyx/plugin :onyx.plugin.core-async/output
+          :onyx/type :output
+          :onyx/medium :core.async
+          :onyx/batch-size batch-size
+          :onyx/max-peers 1
+          :onyx/doc "Writes segments to a core.async channel"}]
+
+        windows
+        [{:window/id :collect-segments
+          :window/task :identity
+          :window/type :global
+          :window/aggregation [:onyx.windowing.aggregation/sum :age]
+          :window/window-key :event-time
+          :window/init 99}]
+
+        triggers
+        [{:trigger/window-id :collect-segments
+          :trigger/refinement :accumulating
+          :trigger/on :segment
+          :trigger/fire-all-extents? true
+          :trigger/threshold [8 :elements]
+          :trigger/sync ::update-atom!}]
+
+        lifecycles
+        [{:lifecycle/task :in
+          :lifecycle/calls ::in-calls}
+         {:lifecycle/task :in
+          :lifecycle/calls :onyx.plugin.core-async/reader-calls}
+         {:lifecycle/task :out
+          :lifecycle/calls ::out-calls}
+         {:lifecycle/task :out
+          :lifecycle/calls :onyx.plugin.core-async/writer-calls}]]
+
+    (reset! in-chan (chan (inc (count input))))
+    (reset! out-chan (chan (sliding-buffer (inc (count input)))))
+    (reset! test-state [])
+
+    (with-test-env [test-env [3 env-config peer-config]]
+      (onyx.api/submit-job
+       peer-config
+       {:catalog catalog
+        :workflow workflow
+        :lifecycles lifecycles
+        :windows windows
+        :triggers triggers
+        :task-scheduler :onyx.task-scheduler/balanced})
+
+      (doseq [i input]
+        (>!! @in-chan i))
+      (>!! @in-chan :done)
+
+      (close! @in-chan)
+
+      (let [results (take-segments! @out-chan)]
+        (is (= (into #{} input) (into #{} (butlast results))))
+        (is (= :done (last results)))
+        (is (= expected-windows @test-state))))))


did the filtering problem hackerrank is incorrect

error: pathspec 'src/hackerrank/filter_elements.clj' did not match any file(s) known to git

--- src/hackerrank/filter_elements.clj
+++ src/hackerrank/filter_elements.clj
@@ -0,0 +1,62 @@
+(ns hackerrank.filter-elements)
+
+;;; https://www.hackerrank.com/challenges/filter-elements
+
+;;; Given a list of N integers A = [a1, a2, …, aN], you have to find those integers which are repeated at least K times. In case no such element exists you have to print -1.
+;;;
+;;; If there are multiple elements in A which are repeated at least K times, then print these elements ordered by their first occurrence in the list.
+;;;
+;;; Let’s say A = [4, 5, 2, 5, 4, 3, 1, 3, 4] and K = 2. Then the output is
+;;;
+;;; 4 5 3
+;;; because these numbers have appeared at least 2 times.
+;;; Among these numbers,
+;;; 4 has appeared first at position 1,
+;;; 5 has appeared next at position 2,
+;;; and 3 has appeared thereafter at position 6.
+;;; That’s why, we print in the order 4, 5 and finally 3.
+;;;
+;;; Input
+;;; First line contains an integer, T, the number of test cases. Then T test cases follow.
+;;; Each test case consist of two lines. First line will contain two space separated integers, N and K, where N is the size of list A, and K represents the repetition count. In the second line, there are N space separated integers which represent the elements of list A = [a1, a2, …, aN].
+;;;
+;;; Output
+;;; For each test case, you have to print all those integers which have appeared in the list at least K times in the order of their first appearance, separated by space. If no such element exists, then print -1.
+;;;
+;;; Constraints
+;;; 1 <= T <= 10
+;;; 1 <= N <= 10000
+;;; 1 <= K <= N
+;;; 1 <= ai <= 109
+;;;
+;;; Sample Input
+;;;
+;;; 3
+;;; 9 2
+;;; 4 5 2 5 4 3 1 3 4
+;;; 9 4
+;;; 4 5 2 5 4 3 1 3 4
+;;; 10 2
+;;; 5 4 3 2 1 1 2 3 4 5
+;;; Sample Output
+;;;
+;;; 4 5 3
+;;; -1
+;;; 5 4 3 2 1
+;;; Explanation
+;;; Sample Case #01: This is the same example mentioned in the problem statement above.
+;;; Sample Case #02: As no elements repeats more than 3 times, we don’t have any elements satisfying the criteria of minimum K times.
+;;; Sample Case #03: All elements are repeated 2 times. So we print all of them according to their order of occurance, which is 5 -> 4 -> 3 -> 2 -> 1.
+
+(defn -main
+  []
+  (let [num-cases (read-string (read-line))]
+    (dotimes [_ num-cases]
+      (let [min-frequency (read-string (second (clojure.string/split (read-line) #" ")))
+            coll (clojure.string/split (read-line) #" ")
+            has-min-frequency #(<= min-frequency (second %))
+            elements-with-minimum-frequency (map first (filter has-min-frequency (frequencies coll)))]
+        (if-not (empty? elements-with-minimum-frequency)
+          (apply println elements-with-minimum-frequency)
+          (println "-1"))))))
+(-main)


coalesce splits by host as well

coalesce splits by host as well

--- src/riemann/streams.clj
+++ src/riemann/streams.clj
@@ -1030,10 +1030,10 @@

 (defn coalesce
   "Combines events over time. Coalesce remembers the most recent event for each
-  service that passes through it (limited by :ttl). Every time it receives an
-  event, it passes on *all* events it remembers. When events expire, they are
-  included in the emitted sequence of events *once*, and removed from the state
-  table thereafter.
+  service/host combination that passes through it (limited by :ttl). Every time
+  it receives an event, it passes on *all* events it remembers. When events
+  expire, they are included in the emitted sequence of events *once*, and
+  removed from the state table thereafter.

   Use coalesce to combine states that arrive at different times--for instance,
   to average the CPU use over several hosts."


Don't update named_links for other source entities

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/physion/ovation-v3-migration.git/'


maybe-declare instead of using Exceptions to figure it out - test suite back to normal

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/michaelsbradleyjr/shen.clj.git/'


islands

islands

error: pathspec 'src/clj/xl/lang/google/number_of_islands.clj' did not match any file(s) known to git

--- src/clj/xl/lang/google/number_of_islands.clj
+++ src/clj/xl/lang/google/number_of_islands.clj
@@ -0,0 +1,122 @@
+"
+A 2d grid map of m rows and n columns is initially filled with water. We may perform an addLand operation which turns the water at position (row, col) into a land. Given a list of positions to operate, count the number of islands after each addLand operation. An island is surrounded by water and is formed by connecting adjacent lands horizontally or vertically. You may assume all four edges of the grid are all surrounded by water.
+
+Example:
+
+Given m = 3, n = 3, positions = [[0,0], [0,1], [1,2], [2,1]].
+Initially, the 2d grid grid is filled with water. (Assume 0 represents water and 1 represents land).
+
+0 0 0
+0 0 0
+0 0 0
+Operation #1: addLand(0, 0) turns the water at grid[0][0] into a land.
+
+1 0 0
+0 0 0   Number of islands = 1
+0 0 0
+Operation #2: addLand(0, 1) turns the water at grid[0][1] into a land.
+
+1 1 0
+0 0 0   Number of islands = 1
+0 0 0
+Operation #3: addLand(1, 2) turns the water at grid[1][2] into a land.
+
+1 1 0
+0 0 1   Number of islands = 2
+0 0 0
+Operation #4: addLand(2, 1) turns the water at grid[2][1] into a land.
+
+1 1 0
+0 0 1   Number of islands = 3
+0 1 0
+We return the result as an array: [1, 1, 2, 3]
+
+Challenge:
+
+Can you do it in time complexity O(k log mn), where k is the length of the positions?
+
+Analysis:
+to turn it into a union-join problem: initially, set root[i, j] = [i, j] or nil.
+whenever a new island is added, check all its neighbors and union when see one.
+keep track of current possible islands cells, one per island at most.
+the number of islands is the number of potential roots which has root[i,j] is itself.
+So cost is:
+add: depth of node to root, no more than number of adds, we collapse path heuristically.
+
+"
+
+(ns xl.lang.google.number-of-islands)
+
+(defn islands [row col add-cells]
+  (let [deltas [[0 1] [1 0] [0 -1] [-1 0]]
+        get-neighbors
+          (fn [[r c]]
+            (for [[delta-r delta-c] deltas
+                  :let [nr (+ r delta-r) nc (+ c delta-c)]
+                  :when (and (nat-int? nr) (< nr row) (nat-int? nc) (< nc col))
+                  ]
+                                            [nr nc])
+            )
+        merge-roots
+          (fn [cell1 cell2 [roots root-cells]]
+            (let [find-root-path
+                  (fn [cell]
+                    (loop [path [cell]]
+                      (let [root (roots cell)]
+                        (if (= root cell) path
+                                          (recur (conj path root)))))
+                    )
+                  ]
+              (if (every? identity (map (comp some? roots) [cell1 cell2]))
+                (let [[path1 path2] (map find-root-path [cell1 cell2])
+                      [depth1 depth2] (map count [path1 path2])
+                       new-root (if (<= depth1 depth2) (last path2) (last path1))
+                      new-roots
+                      (reduce
+                        #(assoc %1 %2 new-root)
+                        roots
+                        (concat path1 path2))
+                      new-root-cells (disj root-cells (last path1) (last path2))
+                      new-root-cells (conj new-root-cells new-root)
+                      ]
+                  [new-roots new-root-cells]
+                  )
+                [roots root-cells]
+                )
+
+              )
+
+              )
+        ]
+    (reduce
+      (fn [{:keys [counts roots root-cells]} add-cell]
+          (let [roots (assoc roots add-cell add-cell)
+                root-cells (conj root-cells add-cell)
+                [roots root-cells] (reduce
+                        #(merge-roots add-cell %2 %1)
+                        [roots root-cells]
+                        (get-neighbors add-cell))
+                new-count (reduce
+                             (fn [c root-cell]
+                               (if (= root-cell (roots root-cell)) (inc c) c)
+                               )
+                             0 root-cells)
+                ]
+            {:counts (conj counts new-count) :roots roots :root-cells root-cells}
+            )
+        )
+      {:counts [] :roots {} :root-cells #{}}
+      add-cells)
+
+    )
+
+  )
+
+
+(defn samples []
+  (let [row 3 col 3 add-cells [[0,0], [0,1], [1,2], [2,1]]]
+    (println (:counts (islands row col add-cells)))
+    )
+  )
+
+(samples)


three levels of "warp plan" function factories

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/michaelsbradleyjr/transwarp.git/'


correct typo

correct typo

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/starcity-properties/odin.git/'


Updated snoRNA gene type assertion rule to work with ccp ext ontology

error: pathspec 'resources/rules/post_identifier_merge/ice_to_bio/snorna_gene_type_assertions.clj' did not match any file(s) known to git

--- resources/rules/post_identifier_merge/ice_to_bio/snorna_gene_type_assertions.clj
+++ resources/rules/post_identifier_merge/ice_to_bio/snorna_gene_type_assertions.clj
@@ -0,0 +1,21 @@
+;; ----------------------------------------------
+;; --------- snoRNA Gene Type Assertion ---------
+;; -----------------------------------------------
+ `{:name "snoRNA-gene-type-assertion"
+   :description "This rule asserts snoRNA gene type"
+   :head ((?/gene rdfs/subClassOf obo/S0_0000275)) ; SO:snoRNA
+
+   :body ((?/record rdf/type ccp/IAO_EXT_0000681) ; ccp:NCBI_gene_info_record
+         (?/record obo/BFO_0000051 ?/dna_field_value) ; BFO:has_part
+         (?/gene_field_value rdf/type ccp/IAO_EXT_0000876) ; ccp:NCBI_gene_info_record__gene_identifier_field_value
+         (?/gene_field_value rdf/type ?/gene_ice_id)
+         (?/gene_ice_id obo/IAO_0000219 ?/gene) ; IAO:denotes
+
+         ;; retrieve gene type
+         (?/record obo/BFO_0000051 ?/type_field_value) ; BFO:has_part
+         (?/type_field_value rdf/type ccp/IAO_EXT_0000884) ; ccp:NCBI_gene_info_record__type_of_gene_field_value
+         (?/type_field_value rdf/type ?/type_ice_id)
+         (?/type_ice_id obo/IAO_0000219 ?/type) ; IAO:denotes
+
+         (= ?/type "snoRNA"))
+   }


(fix meta test)

(fix meta test)

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/fhirbase/fhirplace.git/'


removing println

removing println

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/B2W-BIT/restQL-server.git/'


Final commit post successful merge of data

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/MitchellJThomas/medir.git/'


WIP: experimenting with loading prefixes

error: pathspec 'src/rdf-common/grafter/rdf/prefix.clj' did not match any file(s) known to git

--- src/rdf-common/grafter/rdf/prefix.clj
+++ src/rdf-common/grafter/rdf/prefix.clj
@@ -0,0 +1,21 @@
+(ns rdf-common.grafter.rdf.prefix
+  (:require [grafter.rdf.io :refer [default-prefixes]]
+            [grafter.rdf :refer [subject predicate object context]]
+            [grafter.url :refer [path-segments url-fragment scheme]]))
+
+
+(defn parse-prefix [uri]
+  (if (url-fragment uri)
+    (last (path-segments uri))
+    (last (butlast (path-segments uri)))))
+
+(defn find-prefixes [quads]
+  (->> quads
+       (mapcat (fn [quad]
+                 [(subject quad) (predicate quad) (object quad)]))
+       (filter #(and (instance? java.net.URI %)
+                               (#{"http" "https"} (scheme %))))
+       #_parse-prefix
+       #_set
+
+       ))


First pass at nrepl component

First pass at nrepl component

error: pathspec 'src/strange_coop/components/nrepl.clj' did not match any file(s) known to git

--- src/strange_coop/components/nrepl.clj
+++ src/strange_coop/components/nrepl.clj
@@ -0,0 +1,23 @@
+(ns strange-coop.components.nrepl
+  (:require [clojure.tools.nrepl.server :as nrepl-server]
+            [com.stuartsierra.component :as component]
+            [strange-coop.util :refer [log log-tr]]))
+
+
+(defrecord NRepl [config]
+  component/Lifecycle
+  (start [component]
+    (log "Starting nrepl")
+    (let [port   (get-in config [:config :nrepl-port] 1818)
+          server (nrepl-server/start-server :port port)]
+      (assoc component :nrepl server)))
+
+  (stop [component]
+    (log "Stopping nrepl")
+    (nrepl-server/stop-server (:nrepl component))
+    (assoc component :nrepl nil)))
+
+
+(defn nrepl []
+  (map->NRepl {}))
+


add keenio test

add keenio test

error: pathspec 'test/riemann/keenio_test.clj' did not match any file(s) known to git

--- test/riemann/keenio_test.clj
+++ test/riemann/keenio_test.clj
@@ -0,0 +1,26 @@
+(ns riemann.keenio-test
+  (:require [clj-http.client :as client]
+            [clojure.test :refer :all]
+            [riemann.keenio :as k]
+            [riemann.time :refer [unix-time]]
+            [riemann.test-utils :refer [with-mock]]))
+
+(deftest keenio-test
+  (with-mock [calls client/post]
+    (let [k (k/keenio "ships" "tau-ceti-v" "shodan")]
+      (k {:host    "vonbraun"
+          :service "the many"
+          :description "the glory of the flesh"
+          :state   "perfect"
+          :time    12345678
+          :ttl     300})
+      (is (= 1 (count @calls)))
+      (is (= (last @calls)
+             ["https://api.keen.io/3.0/projects/tau-ceti-v/events/ships"
+              {:body "{\"description\":\"the glory of the flesh\",\"service\":\"the many\",\"time\":12345678,\"state\":\"perfect\",\"host\":\"vonbraun\",\"ttl\":300}"
+               :query-params {"api_key" "shodan"}
+               :socket-timeout 5000
+               :conn-timeout 5000
+               :content-type :json
+               :accept :json
+               :throw-entire-message? true}])))))


Adding station usage queries

Adding station usage queries

error: pathspec 'src/main/clojure/hikesaber/analysis/station_usage.clj' did not match any file(s) known to git

--- src/main/clojure/hikesaber/analysis/station_usage.clj
+++ src/main/clojure/hikesaber/analysis/station_usage.clj
@@ -0,0 +1,32 @@
+(ns hikesaber.analysis.station-usage
+  (:require [hikesaber.ride-records.helpers :as h]
+            [hikesaber.dates :as dates]))
+
+(def recs (hikesaber.record-cache/load-cached-records))
+
+(def trimmed (h/trimmed-records recs "06/01/2015" "06/30/2015"))
+
+(def station-id 511)
+
+(defn for-station [station-id record]
+  (or
+   (= station-id (:from-station-id record))
+   (= station-id (:to-station-id record))))
+
+(def user-type :member)
+
+(defn for-user-type [user-type record]
+  (= user-type (:user-type record)))
+
+(def xform (comp (filter (partial for-station station-id))))
+
+(def filtered (transduce xform conj [] trimmed))
+
+(def members (transduce (comp (filter (partial for-station station-id))
+                              (filter (partial for-user-type :member))) conj [] trimmed))
+
+(def customers (transduce (comp (filter (partial for-station station-id))
+                              (filter (partial for-user-type :customer))) conj [] trimmed))
+
+
+


finish clojure version

finish clojure version

error: pathspec 'Kill-Process/KP.clj' did not match any file(s) known to git

--- Kill-Process/KP.clj
+++ Kill-Process/KP.clj
@@ -0,0 +1,20 @@
+(defn kill-process [pid ppid kill]
+  (let [tempdic (atom {})]
+    (doseq [i (range (count ppid))]
+      (if (get @tempdic (nth ppid i))
+        (swap! tempdic update (nth ppid i) conj (nth pid i))
+        (swap! tempdic conj {(nth ppid i) [(nth pid i)]})))
+    (loop [stack (list kill)
+           rest '()]
+      ;(println stack)
+      (cond (empty? stack) rest
+            :else
+            (recur (flatten (for [this stack
+                                  :let [value (get @tempdic this)]
+                                  :when value]
+                              value))
+                   (concat rest stack))))
+    ))
+
+(kill-process [1 3 10 5] [3 0 5 3] 5)
+(kill-process [1 3 10 5] [3 0 5 3] 3)


Use of as-file to determine last-modified times

--- src/yada/resources/url_resource.clj
+++ src/yada/resources/url_resource.clj
@@ -2,10 +2,10 @@

 (ns yada.resources.url-resource
   (:require
-   [clojure.java.io :as io]
    [yada.charset :as charset]
    [yada.protocols :as p]
    [yada.methods :refer (Get)]
+   [yada.util :refer [as-file]]
    [ring.util.mime-type :refer (ext-mime-type)])
   (:import [java.net URL]
            [java.util Date]
@@ -24,9 +24,9 @@
       [{:media-type #{(ext-mime-type (.getPath u))}
         :charset charset/platform-charsets}]})
     ([u ctx]
-     {:last-modified (let [f (io/file (.getFile u))]
+     {:last-modified (when-let [f (as-file u)]
                        (when (.exists f)
-                         (Date. (.lastModified f))))}))
+                         (.lastModified f)))}))

   ;; TODO: This is wrong. First, an InputStreamReader does not coerce the
   ;; encoding, simply converts a byte stream to a character stream and is


Remove unneeded attribute

Remove unneeded attribute

text/javascript is assumed if not present:
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script#Attributes

--- src/clojars/web/common.clj
+++ src/clojars/web/common.clj
@@ -28,8 +28,7 @@
          ;; more info: http://getbootstrap.com/css/#grid
          ["reset.css" "vendor/bootstrap/bootstrap.css" "screen.css"])
     (include-js "//use.typekit.net/zhw0tse.js")
-    [:script {:type "text/javascript"}
-     "try{Typekit.load();}catch(e){}"]
+    [:script "try{Typekit.load();}catch(e){}"]
     (raw (when-ie (include-js "/js/html5.js")))]
    [:body.container-fluid
     [:div.hero.row


Formatting

Formatting

--- test/yada/charset_test.clj
+++ test/yada/charset_test.clj
@@ -1,6 +1,7 @@
 (ns yada.charset-test
-  (:require [clojure.test :refer :all]
-            [yada.charset :as ch]))
+  (:require
+   [clojure.test :refer :all]
+   [yada.charset :as ch]))

 (deftest no-charset-appears-twice-in-platform-charsets
   (let [charset-aliases (map :alias ch/platform-charsets)]


Bump noir-async version to beta10

Bump noir-async version to beta10

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/terrancesnyder/engulf.git/'


bump version and core version to 3.5.3

bump version and core version to 3.5.3


Set snapshot version

Set snapshot version

--- project.clj
+++ project.clj
@@ -1,4 +1,4 @@
-(defproject funcool/cats "1.1.0"
+(defproject funcool/cats "1.2.0-SNAPSHOT"
   :description "Category Theory abstractions for Clojure"
   :url         "https://github.com/funcool/cats"
   :license {:name "BSD (2 Clause)"


bump clojure to 1.9-beta4

bump clojure to 1.9-beta4

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/democracyworks/election-authority-works.git/'


Update newrelic-agent to latest

Update newrelic-agent to latest

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/democracyworks/email-works.git/'


Removed closure-warnings compiler option.

--- project.clj
+++ project.clj
@@ -35,8 +35,7 @@
                                                     :output-dir "target/dev"
                                                     :optimizations :none
                                                     :pretty-print true
-                                                    :source-map true
-                                                    :closure-warnings {:non-standard-jsdoc :off}}}
+                                                    :source-map true}}
                                         {:id "test"
                                          :source-paths ["test" "target/classes" "target/test-classes"]
                                          :compiler {:output-to "target/test/sablono.js"
@@ -47,8 +46,7 @@
                                                                "phantomjs-shims.js"
                                                                "react/react.min.js"]
                                                     :externs ["react/externs/react.js"
-                                                              "externs/jquery-1.9.js"]
-                                                    :closure-warnings {:non-standard-jsdoc :off}}}]
+                                                              "externs/jquery-1.9.js"]}}]
                                :test-commands {"phantom" ["phantomjs" :runner "target/test/sablono.js"]}}
                    :repl-options {:nrepl-middleware [cljx.repl-middleware/wrap-cljx]}
                    :resource-paths ["test-resources"]


Docstrings + XOR impl

Docstrings + XOR impl

error: pathspec 'src/caesium/magicnonce/secretbox.clj' did not match any file(s) known to git

--- src/caesium/magicnonce/secretbox.clj
+++ src/caesium/magicnonce/secretbox.clj
@@ -0,0 +1,128 @@
+(ns caesium.magicnonce.secretbox
+  "\"Magic\" nonce schemes for secretbox.
+
+  There are two kinds of schemes in this namespace:
+
+   * schemes that take a nonce, but do something with it to make the
+     resulting system safer or easier to use,
+   * schemes that produce the nonce for you automatically.
+
+  See individual function docstrings for details, but the most interesting
+  function in this namespace is almost certainly [[secretbox-nmr]]. If you
+  just want a random nonce and do not care about nonce-misuse resistance,
+  use [[secretbox-rnd]]. The other functions are fairly limited use.")
+
+(defn secretbox-pfx
+  "secretbox, with the given nonce embedded in the ciphertext as a prefix.
+
+  This is only useful if there is an obvious nonce in your protocol
+  that can not repeat, you have ways of detecting when your peer
+  repeats nonces, your nonce is not implicitly part of your protocol
+  so you have to specify it as part of the ciphertext, and you can not
+  afford to use a nonce-misuse resistant scheme. As you can see,
+  that's a fairly rare circumstance; this function is mainly used
+  internally by other, easier to use schemes in this namespace. Check
+  out [[secretbox-nmr]] instead.
+
+  To decrypt, use [[decrypt]] or [[open]], depending on which argument order
+  you prefer."
+  [msg nonce key])
+
+(defn secretbox-rnd
+  "secretbox, with randomized prefix nonce.
+
+  This is useful if you don't have an obvious nonce in your protocol
+  you can use. However, it does rely on having a cryptographically
+  secure CSPRNG available during encryption. It is *not* nonce-misuse
+  resistant. Unless you can't afford the minor performance penalty for
+  a nonce-misuse resistant scheme, consider using [[secretbox-nmr]].
+
+  To decrypt, use [[decrypt]] or [[open]], depending on which argument
+  order you prefer."
+  [msg key])
+
+(defn ^:private synthetic-nonce
+  "Creates a synthetic nonce from the given plaintext.
+
+  This function is pure in the sense that it is deterministic and has
+  no visible side effects: the same plaintext will always generate the
+  same byte array. However, note that the returned nonce will be a
+  mutable byte array."
+  [plaintext])
+
+(defn ^:private random-nonce!
+  "Creates a random nonce suitable for use in secretbox.
+
+  This function is not pure: it will request a different random nonce from
+  the CSPRNG every time."
+  [])
+
+(defn ^:private xor!
+  "Populates `out` with the XOR of matching elements in `a`, `b`.
+
+  All three arrays should be of identical length. Returns `out`."
+  [^bytes out ^bytes a ^bytes b]
+  (dotimes [i (alength a)]
+    (aset-byte out i (bit-xor (aget a i) (aget b i))))
+  out)
+
+(defn ^:private xor-inplace!
+  "XORs elements of array `a` in-place with the matching elem from `b`."
+  [^bytes a ^bytes b]
+  (xor! a a b))
+
+(defn secretbox-det
+  "secretbox, with deterministic nonce.
+
+  This means the encryption operation requires no new randomness; it
+  is a fully deterministic cryptosystem. This means identical
+  plaintexts will map to identical ciphertexts. That has to be
+  acceptable for your protocol!
+
+  Because the nonce is determined from the plaintext, adding any
+  non-determinism to your message will make the nonce not repeat and
+  hence hide repeated messages from the attacker. A high-resolution
+  timestamp will do that effectively in most cases.
+
+  This scheme does not change the requirements for the key: the key
+  must still be a cryptographically random byte array of appropriate
+  size ([[caesium.crypto.secretbox/keybytes]]).
+
+  Unless you know for sure that repeat messages are OK or that your
+  messages will not repeat or you can't rely on encryption-time
+  randomness, consider [[secrebox-nmr]].
+
+  To decrypt, use [[decrypt]] or [[open]], depending on which argument order
+  you prefer."
+  [msg key])
+
+(defn secretbox-nmr
+  "Encrypt a message like secretbox, but nonce-misuse resistant.
+
+  This still optionally takes a nonce, but that nonce will be combined
+  with a synthetic nonce. This means that if the nonce incidentally
+  repeats, an attacker will only be able to tell that a message
+  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."
+  ([msg nonce key])
+  ([msg key]
+   (secretbox-nmr msg (random-nonce!) key)))
+
+(defn decrypt-to-buf!
+  "Decrypts any secretbox message with a prefix nonce into the given buffer."
+  [out key ctext])
+
+(defn decrypt
+  "Decrypts any secretbox message with a prefix nonce."
+  [key ctext])
+
+(defn open-to-buf!
+  "Open (decrypt and verify) a nonce-prefixed secretbox message."
+  [out ctext key])
+
+(defn open
+  "Like [[decrypt]], but with different argument order; analogous to
+  [[caesium.crypto.secretbox/secretbox-open-easy]]."
+  [])


cleanup

cleanup

--- src/metabase/api/common/throttle.clj
+++ src/metabase/api/common/throttle.clj
@@ -63,8 +63,8 @@
                       ;; according to DELAY-EXPONENT.
                       ^Integer initial-delay-ms
                       ;; For each subsequent failure past ATTEMPTS-THRESHOLD, increase the delay by
-                      ;; (num-attempts-over-theshold ^ DELAY-EXPONENT). e.g. if `initial-delay-ms` is 15 and
-                      ;; `delay-exponent` is 2, the first attempt past attempts-threshold will require the user to wait
+                      ;; (num-attempts-over-theshold ^ DELAY-EXPONENT). e.g. if INITIAL-DELAY-MS is 15 and
+                      ;; DELAY-EXPONENT is 2, the first attempt past attempts-threshold will require the user to wait
                       ;; 15 seconds (15 * 1^2), the next attempt after that 60 seconds (15 * 2^2), then 135, and so on.
                       ^Integer delay-exponent])


Also inspect currently existing files.

Also inspect currently existing files.

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/cstorey/nrod.git/'


add clj->python namespace

add clj->python namespace

error: pathspec 'src/seathree/translate.clj' did not match any file(s) known to git

--- src/seathree/translate.clj
+++ src/seathree/translate.clj
@@ -0,0 +1,16 @@
+(ns seathree.translate
+  (use clojure.java.shell))
+
+(defn failed? [result] (> (:exit result) 0))
+
+(defn translate
+  "Given some string, pass it off to the Python script that interacts
+   with the Python API. Note that this is blocking and Google often takes
+   a long time to respond. You probably want to invoke this with future."
+  [text src tgt retries]
+  (if (> retries 0)
+    (let [result (sh "python" "resources/python/translate.py" src tgt (format "'%s'" text))]
+      (if (failed? result)
+        (translate text (- retries 1))
+        (:out result)))))
+


Removed dumb question.

Removed dumb question.

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/inchingforward/eon.git/'


Force pmap to evaluate

Force pmap to evaluate

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/physion/ovation-webapi.git/'


clean up js/console.logs

clean up js/console.logs

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/starcity-properties/odin.git/'


add first frontend design

add first frontend design

error: pathspec 'src/cljs/link_collective/view.cljs' did not match any file(s) known to git

--- src/cljs/link_collective/view.cljs
+++ src/cljs/link_collective/view.cljs
@@ -0,0 +1,79 @@
+(ns link-collective.view
+  (:require [figwheel.client :as fw :include-macros true]
+            [kioo.om :refer [content set-attr do-> substitute listen prepend append html remove-class]]
+            [kioo.core :refer [handle-wrapper]]
+            [om.core :as om :include-macros true]
+            [om.dom :as dom :include-macros true])
+  (:require-macros [kioo.om :refer [defsnippet deftemplate]]))
+
+(enable-console-print!)
+
+(println "Resistance is futile!")
+
+(fw/watch-and-reload
+  ;; :websocket-url "ws://localhost:3449/figwheel-ws" default
+ :jsload-callback (fn [] (print "reloaded"))) ;; optional callback
+
+
+(def test-data
+  (atom
+   [{:user "jane"
+     :id 1
+     :title "How to get a Designer"
+     :detail-url "https://medium.com/coding-design/how-to-get-a-designer-b3afdf5a853d"
+     :detail-text "Just some thoughts ..."
+     :comments [{:text "awesome :D" :user "adam" :date "today"}]
+     :hashtags #{"#coding" "#design"}}
+    {:user "john"
+     :id 2
+     :title "Greenwald's 'No Place to Hide': a compelling, vital narrative about official criminality"
+     :detail-text "Interesting article"
+     :detail-url "http://boingboing.net/2014/05/28/greenwalds-no-place-to-hid.html"
+     :comments [{:text "lies, all lies ..." :user "adam" :date "yesterday"} {:text "Sucker" :user "eve" :date "today"}]
+     :hashtags #{"#greenwald" "#snowden" "#nsa"}}]))
+
+
+(defsnippet link-detail-comment "main.html" [:.link-detail-comment-item]
+  [comment]
+  {[:.link-detail-comment-text] (content (:text comment))
+   [:.link-detail-comment-user] (content (:user comment))
+   [:.link-detail-comment-timestamp] (content (:date comment))})
+
+
+(defsnippet link-header-hashtag "main.html" [:.link-header-hashtag-item]
+  [hashtag]
+  {[:.link-header-hashtag-item-text] (content hashtag)})
+
+
+(defsnippet link-detail "main.html" [:.link-detail]
+  [record]
+  {[:.link-detail] (set-attr "id" (str "link-item-" (:id record)))
+   [:.link-detail-url] (do-> (set-attr "href" (:detail-url record))
+                         (content (:detail-url record)))
+   [:.link-detail-text] (content (:detail-text record))
+   [:.link-detail-comment-list] (content (map link-detail-comment (:comments record)))})
+
+
+(defsnippet link-header "main.html" [:.link-header]
+  [record]
+  {[:.link-header] (set-attr "href" (str "#link-item-" (:id record)))
+   [:.link-header-text] (content (:title record))
+   [:.link-header-user] (content (:user record))
+   [:.link-header-hashtag-list] (content (map link-header-hashtag (:hashtags record)))})
+
+
+(defsnippet link-item "main.html" [:.link-item]
+  [record]
+  {[:.link-comment-counter] (content (-> record :comments count))
+   [:.link-header] (substitute (link-header record))
+   [:.link-detail] (substitute (link-detail record))})
+
+
+(deftemplate main-view "main.html" [data]
+  {[:.list-group] (substitute (map #(link-item %) data))})
+
+
+(om/root
+ #(om/component (main-view %))
+ test-data
+ {:target (. js/document (getElementById "main-container"))})


get rid of overly agressive shutdown on unhandled error... let errors just bubble up in client calls instead

--- src/clj/backtype/storm/zookeeper.clj
+++ src/clj/backtype/storm/zookeeper.clj
@@ -42,21 +42,21 @@
                  (watcher (zk-keeper-states (.getState event))
                           (zk-event-types (.getType event))
                           (.getPath event))))))))
-    (.. fk
-        (getUnhandledErrorListenable)
-        (addListener
-         (reify UnhandledErrorListener
-           (unhandledError [this msg error]
-             (if (or (exception-cause? InterruptedException error)
-                     (exception-cause? java.nio.channels.ClosedByInterruptException error))
-               (do (log-warn-error error "Zookeeper exception " msg)
-                   (let [to-throw (InterruptedException.)]
-                     (.initCause to-throw error)
-                     (throw to-throw)
-                     ))
-               (do (log-error error "Unrecoverable Zookeeper error " msg)
-                   (halt-process! 1 "Unrecoverable Zookeeper error")))
-             ))))
+;;    (.. fk
+;;        (getUnhandledErrorListenable)
+;;        (addListener
+;;         (reify UnhandledErrorListener
+;;           (unhandledError [this msg error]
+;;             (if (or (exception-cause? InterruptedException error)
+;;                     (exception-cause? java.nio.channels.ClosedByInterruptException error))
+;;               (do (log-warn-error error "Zookeeper exception " msg)
+;;                   (let [to-throw (InterruptedException.)]
+;;                     (.initCause to-throw error)
+;;                     (throw to-throw)
+;;                     ))
+;;               (do (log-error error "Unrecoverable Zookeeper error " msg)
+;;                   (halt-process! 1 "Unrecoverable Zookeeper error")))
+;;             ))))
     (.start fk)
     fk))


Addded clojars plugin

Addded clojars plugin

--- project.clj
+++ project.clj
@@ -10,7 +10,8 @@
     [[swank-clojure "1.2.0"]
      [ring/ring-jetty-adapter "0.3.5"]
      [ring/ring-devel "0.3.5"]
-     [robert/hooke "1.1.0"]]
+     [robert/hooke "1.1.0"]
+     [lein-clojars "0.7.0"]]
   :test-selectors {:default  #(not (:integration %))
                    :integration :integration
                    :all (constantly true)})


bump core version to 3.5.6

bump core version to 3.5.6

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/B2W-BIT/restQL-server.git/'


Version 1.12.2-SNAPSHOT

Version 1.12.2-SNAPSHOT


Version 0.1.2-SNAPSHOT

Version 0.1.2-SNAPSHOT

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/jenshaase/sockjs-clojure.git/'


Bump to 0.3.4

Bump to 0.3.4

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/nvbn/rerenderer.git/'


Version 129-SNAPSHOT

Version 129-SNAPSHOT

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/tobias/clojars-web.git/'


lein-release plugin: preparing 0.2.8 release

--- project.clj
+++ project.clj
@@ -1,4 +1,4 @@
-(defproject sablono "0.2.8-SNAPSHOT"
+(defproject sablono "0.2.8"
   :description "Lisp style templating for Facebook's React."
   :url "http://github.com/r0man/sablono"
   :author "Roman Scherer"


fix on-delete of symlink action for directory added in dest

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/runoshun/syncat.git/'


check for validation errors specifically

they will have a :schema property

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/democracyworks/election-mail-works.git/'


Adding CQL row.

Adding CQL row.

error: pathspec 'src/clojure/clojurewerkz/cassaforte/thrift/cql_row.clj' did not match any file(s) known to git

--- src/clojure/clojurewerkz/cassaforte/thrift/cql_row.clj
+++ src/clojure/clojurewerkz/cassaforte/thrift/cql_row.clj
@@ -0,0 +1,10 @@
+(ns clojurewerkz.cassaforte.thrift.cql-row
+  (:import [org.apache.cassandra.thrift CqlRow]))
+
+(defn get-key
+  [^CqlRow row]
+  (.getKey row))
+
+(defn get-columns
+  [^CqlRow row]
+  (.getColumns row))


fixes

fixes

--- src/metabase/api/common/internal.clj
+++ src/metabase/api/common/internal.clj
@@ -216,11 +216,14 @@
          (symbol? arg-symb)]}
   `[~arg-symb ~((eval 'metabase.api.common/arg-annotation-fn) annotation-kw arg-symb)])

-(defn process-arg-annotations [annotations]
-  {:pre [(or (nil? annotations)
-             (map? annotations))]}
-  (some->> annotations
+(defn process-arg-annotations [annotations-map]
+  {:pre [(or (nil? annotations-map)
+             (map? annotations-map))]}
+  (some->> annotations-map
            (mapcat (fn [[arg annotations]]
+                     {:pre [(symbol? arg)
+                            (or (symbol? annotations)
+                                (every? symbol? annotations))]}
                      (if (sequential? annotations) (->> annotations
                                                         (map keyword)
                                                         (map (u/rpartial vector arg)))


Check in initial gamepad ns code.

Check in initial gamepad ns code.

error: pathspec 'src/org/playasophy/wonderdome/input/gamepad.clj' did not match any file(s) known to git

--- src/org/playasophy/wonderdome/input/gamepad.clj
+++ src/org/playasophy/wonderdome/input/gamepad.clj
@@ -0,0 +1,100 @@
+(ns org.playasophy.wonderdome.input.gamepad
+  "A gamepad input watches for button presses from a USB game controller."
+  (:require
+    [clojure.core.async :as async :refer [>!!]]
+    [com.stuartsierra.component :as component])
+  (:import
+    (com.codeminders.hidapi
+      HIDDevice
+      HIDManager)))
+
+
+(def nes-vendor-id   4797)
+(def nes-product-id 53269)
+
+(def snes-vendor-id  0x12bd)
+(def snes-product-id 0xd015)
+
+
+(defn get-device
+  ^HIDDevice
+  [vendor-id product-id]
+  (try
+    (clojure.lang.RT/loadLibrary "hidapi-jni")
+    (-> (HIDManager/getInstance)
+        (.openById vendor-id product-id nil))
+    #_ (catch UnsatisfiedLinkError e
+      (println "Failed to load USB library:" e)
+      nil)
+    (catch RuntimeException e
+      (println "Error loading gamepad input device:" e)
+      nil)))
+
+
+(defn read-device
+  "Returns a state map showing the current buttons pressed."
+  [^HIDDevice device ^bytes buffer]
+  (let [len (.readTimeout device buffer 1000)]
+    (println (apply str "Read " len " bytes of output from gamepad: "
+                   (map (partial format "%02X") buffer)))
+    ; TODO: build state map
+    {}))
+
+
+(defn- input-loop
+  "Constructs a new runnable looping function which reads the gamepad state
+  and sends any detected button presses. The loop can be terminated by
+  interrupting the thread."
+  ^Runnable
+  [device buffer channel]
+  (fn []
+    (try
+      (loop []
+        ;(Thread/sleep period)
+        (let [state (read-device device buffer)]
+          ; TODO: calculate individual button events, rather than sending entire state
+          (>!! channel {:type :gamepad, :buttons state}))
+        (recur))
+      (catch InterruptedException e
+        nil))))
+
+
+(defrecord GamepadInput
+  [channel ^HIDDevice device ^Thread process]
+
+  component/Lifecycle
+
+  (start
+    [this]
+    (if process
+      this
+      (assoc this :process
+        (doto (Thread. (input-loop device (byte-array 512) channel) "GamepadInput")
+          (.setDaemon true)
+          (.start)))))
+
+
+  (stop
+    [this]
+    (when process
+      (.interrupt process)
+      (.join process 1000))
+    (assoc this :process nil))
+
+
+  Object
+
+  (toString
+    [this]
+    (if device
+      (str (.getManufacturerString device) "/"
+           (.getProductString device))
+      "(no device)")))
+
+
+(defn gamepad
+  "Creates a new gamepad input which will send button press events to the given
+  channel."
+  [channel vendor-id product-id]
+  {:pre [(some? channel)]}
+  (GamepadInput. channel (get-device vendor-id product-id) nil))


Added clojurescript shism for the Objective-C shell implementation mimicking clojure.java.sh

Signed-off-by: Mike Fikes <mike@fikesfarm.com>

Former-commit-id: bdb4e8357077a04b918947af2748f83a7eefe81d

error: pathspec 'planck-cljs/src/planck/sh.cljs' did not match any file(s) known to git

--- planck-cljs/src/planck/sh.cljs
+++ planck-cljs/src/planck/sh.cljs
@@ -0,0 +1,38 @@
+(ns planck.sh)
+
+(def ^:dynamic *sh-dir* nil)
+(def ^:dynamic *sh-env* nil)
+
+(defn- parse-args
+  [args]
+  (let [default-encoding nil
+         default-opts {:out-enc default-encoding :in-enc default-encoding :dir *sh-dir* :env *sh-env*}
+         [cmd opts] (split-with string? args)]
+    [cmd (merge default-opts (apply hash-map opts))]))
+
+(defn sh
+  "Passes the given strings to Runtime.exec() to launch a sub-process.
+  Options are
+  :in      may be given followed by a string of one of the following formats:
+           String conforming to URL Syntax: 'file:///tmp/test.txt'
+           String pointing at an *existing* 'file: '/tmp/test.txt'
+           String with string input: 'Printing input frmo stdin with funy chars like $@ &'
+           to be fed to the sub-process's stdin.
+  :in-enc  option may be given followed by a String, used as a character
+           encoding name (for example \"UTF-8\" or \"ISO-8859-1\") to
+           convert the input string specified by the :in option to the
+           sub-process's stdin.  Defaults to UTF-8.
+  :out-enc option may be given followed by :bytes or a String. If a
+           String is given, it will be used as a character encoding
+           name (for example \"UTF-8\" or \"ISO-8859-1\") to convert
+           the sub-process's stdout to a String which is returned.
+  :env     override the process env with a map of String: String.
+  :dir     override the process dir with a String.
+  sh returns a map of
+    :exit => sub-process's exit code
+    :out  => sub-process's stdout (as String)
+    :err  => sub-process's stderr (String via platform default encoding)"
+  [& args]
+  (let [[cmd opts] (parse-args args)
+         {:keys [in in-enc out-enc env dir]} opts]
+    (js->clj (js/PLANCK_SHELL_SH (clj->js cmd) in in-enc out-enc env dir) :keywordize-keys true)))


Removed old code

Removed old code

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/acessocard/microscope.git/'


[EN] Test both existing and non-existing

voter-registration-method

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/democracyworks/election-authority-works.git/'


New namespace clj-chess.square-set.

New namespace clj-chess.square-set.

error: pathspec 'src/clojure/clj_chess/square_set.clj' did not match any file(s) known to git

--- src/clojure/clj_chess/square_set.clj
+++ src/clojure/clj_chess/square_set.clj
@@ -0,0 +1,55 @@
+(ns clj-chess.square-set
+  (:refer-clojure :exclude [complement])
+  (:import (chess SquareSet)))
+
+(defn squares
+  "A vector containing the members of a square set."
+  [set]
+  (loop [result []
+         set set]
+    (if (zero? set)
+      result
+      (recur (conj result (SquareSet/first set))
+             (SquareSet/removeFirst set)))))
+
+(defn intersection
+  "The intersection of one or more square sets, i.e. the set of all squares
+  that are members of all the input sets."
+  [& sets]
+  (apply bit-and sets))
+
+(defn union
+  "The union of one or more square sets, i.e. the set of squares that are
+  members of at least one of the input sets."
+  [& sets]
+  (apply bit-or sets))
+
+(defn complement
+  "The complement of a square set, i.e all squares that are *not* members
+  of the input set. The optional 'board-mask' parameter can be used to
+  restrict the universe of squares in the case of boards of sizes smaller
+  than 8x8."
+  ([set] (bit-not set))
+  ([set board-mask] (intersection (complement set)
+                                  board-mask)))
+
+(defn difference
+  "The set of squares that are members of the first set, but not members
+  of any of the remaining sets."
+  ([set] set)
+  ([set-1 set-2]
+    (intersection set-1 (complement set-2)))
+  ([set-1 set-2 & sets]
+    (reduce difference (difference set-1 set-2) sets)))
+
+(defn subset?
+  "True if all members of set-1 are also members of set-2."
+  [set-1 set-2]
+  (= set-1
+     (intersection set-1 set-2)))
+
+(defn superset?
+  "True if all members of set-2 are also members of set-1."
+  [set-1 set-2]
+  (= set-1
+     (union set-1 set-2)))


Add forecast lookup for a location.

Add forecast lookup for a location.

Uses open weather map.

error: pathspec 'src/forecast/repository/location_forecast.clj' did not match any file(s) known to git

--- src/forecast/repository/location_forecast.clj
+++ src/forecast/repository/location_forecast.clj
@@ -0,0 +1,53 @@
+(ns forecast.repository.location-forecast
+  (:require [clj-http.client :as client]
+            [cheshire.core :refer [parse-string]]
+            [clojure.string :refer [split]]
+            [clojure.walk :refer [keywordize-keys]]
+            )
+  (:import [java.util Calendar]))
+
+(defonce locations (atom {}))
+(defn clear-locations [] (reset! locations {}))
+
+(defn api
+  []
+  (or (System/getenv "WEATHER_API") (throw "Must set WEATHER_API envrionment variable")))
+
+(defn tomorrow
+  []
+  (.format (java.text.SimpleDateFormat. "yyyy-MM-dd")
+           (java.util.Date. (+ (* 1 86400 1000) (.getTime (java.util.Date.))))
+           ))
+;; (tomorrow)
+
+(defn force-location->forecast
+  [location]
+  (try
+    (let [url (str "http://api.openweathermap.org/data/2.5/forecast?units=imperial&lat=" (:latitude location) "&lon=" (:longitude location) "&APPID=" (api))
+          response (client/get url {:accept :json :socket-timeout 1000 :conn-timeout 1000})
+          day (re-pattern (str (tomorrow) ".*"))
+          ]
+      (if (= (:status response) 200)
+        (->>
+         (keywordize-keys (parse-string (:body response)))
+         :list
+         (filter #(re-matches day (:dt_txt %)))
+         (map #(-> % :main :temp_max))
+         (apply max)
+         )
+        {:error (str "error response for location (" (:status response) ")")}
+        ))
+    (catch Exception e {:error (str e)})))
+;; (prn (force-location->forecast {:latitude 37.386 :longitude -122.0838}))
+;; (prn (location->forecast {:latitude 37.386 :longitude -122.0838}))
+
+(defn location->forecast
+  [location]
+  (if-let [forecast (@locations location)]
+    forecast
+    (let [forecast (force-location->forecast location)]
+      (swap! locations assoc location forecast)
+      forecast)))
+
+;; (clear-locations)
+;; (prn (force-location->forecast {:latitude 37.386 :longitude -122.0838}))


reorg main api section

reorg main api section

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/michaelsbradleyjr/transwarp.git/'


views: prepare unit details panel

views: prepare unit details panel

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/pyr/bundes.git/'


fix `wrap-response-if-needed` so it can handle `nil` `:body`

--- src/metabase/api/common/internal.clj
+++ src/metabase/api/common/internal.clj
@@ -126,8 +126,8 @@
   "If RESPONSE isn't already a map with keys :status and :body, wrap it in one (using status 200)."
   [response]
   (letfn [(is-wrapped? [resp] (and (map? resp)
-                                   (:status resp)
-                                   (:body resp)))]
+                                   (contains? resp :status)
+                                   (contains? resp :body)))]
     (if (is-wrapped? response) response
         {:status 200
          :body response})))


code cleanup

code cleanup

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/starcity-properties/odin.git/'


Enable full screen button on OS X

Enable full screen button on OS X

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/bsmr-clojure/Nightcode.git/'


Add a ns for working with Ruby from Clojure

error: pathspec 'backend/src/circle/ruby.clj' did not match any file(s) known to git

--- backend/src/circle/ruby.clj
+++ backend/src/circle/ruby.clj
@@ -0,0 +1,28 @@
+(ns circle.ruby
+  (:import javax.script.ScriptEngine)
+  (:import javax.script.ScriptEngineManager)
+  (:import org.jruby.embed.ScriptingContainer)
+  (:import org.jruby.RubySymbol))
+
+(def engine
+  (->
+   (ScriptEngineManager.)
+   (.getEngineByName "jruby")))
+
+(defn eval-ruby
+  "Eval a ruby string."
+  [s]
+  (-> engine
+      (.eval s)))
+
+(defn ruby
+  "Returns the org.jruby.Ruby object"
+  []
+  (-> (ScriptingContainer.)
+      (.getProvider)
+      (.getRuntime)))
+
+(defn intern-keyword
+  "Given a java string, return a ruby keyword"
+  [s]
+  (RubySymbol/newSymbol (ruby) s))


system.core test ns added

system.core test ns added

error: pathspec 'test/clj/hellhound/system/core.clj' did not match any file(s) known to git

--- test/clj/hellhound/system/core.clj
+++ test/clj/hellhound/system/core.clj
@@ -0,0 +1,3 @@
+(ns hellhound.system.core
+  (:require [hellhound.system.core :as sut]
+            [clojure.test :as t]))


Started a little problem for fun

Started a little problem for fun

error: pathspec 'cannons/cannons.clj' did not match any file(s) known to git

--- cannons/cannons.clj
+++ cannons/cannons.clj
@@ -0,0 +1,13 @@
+(ns app.core
+  (:require clojure.set))
+
+(defn word-collision
+  "I don't do a whole lot."
+  [w1 w2]
+  (clojure.set/union
+    (set (map (fn [x] (when (not (.contains w2 (.toString x))) x)) w1))
+    (set (map (fn [x] (when (not (.contains w1 (.toString x))) x)) w2))))
+
+(defn main
+  []
+  (println (word-collision "hill" "bill")))


sorting order was fixed

sorting order was fixed

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/abtv/personal-aggregator.git/'


functioning deg2rad test

functioning deg2rad test

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/tiagoantao/turtle.git/'


Update to ClojureScript 0.0-3115

Update to ClojureScript 0.0-3115

--- Clojure/project.clj
+++ Clojure/project.clj
@@ -4,6 +4,6 @@
   :license {:name "Eclipse Public License"
             :url "http://www.eclipse.org/legal/epl-v10.html"}
   :dependencies [[org.clojure/clojure "1.6.0"]
-                 [org.clojure/clojurescript "0.0-3058"]
+                 [org.clojure/clojurescript "0.0-3115"]
                  [com.github.rickyclarkson/jmdns "3.4.2-r353-1"]]
   :source-paths ["src"])


Generative Testing Part 5 – Composing Generators 2 (WIP)

error: pathspec 'src/sheepish/test/sheepish/f_better_sheepish_examples.cljc' did not match any file(s) known to git

--- src/sheepish/test/sheepish/f_better_sheepish_examples.cljc
+++ src/sheepish/test/sheepish/f_better_sheepish_examples.cljc
@@ -0,0 +1,56 @@
+(ns sheepish.f-better-sheepish-examples
+  (:require [clojure.spec.alpha :as s]
+            [clojure.spec.gen.alpha :as gen]
+            [clojure.string :as string]
+            [clojure.test :as test :refer [deftest testing is]]
+            clojure.test.check.generators #_ "This is necessary at runtime"))
+
+(defn generate-examples
+  [spec example-count]
+  (let [generator (s/gen spec)
+        generate-example #(gen/generate generator)
+        examples (repeatedly generate-example)]
+    (take example-count examples)))
+
+;; Let's say we want to compose the test string into before, the `b`, intermediate characters, `a` characters, and "after".
+
+(s/def ::usually-empty-string
+  (s/with-gen string?
+   #(gen/frequency [[9 (gen/return "")]
+                    [1 (s/gen string?)]])))
+
+; (generate-examples ::usually-empty-string 40)
+
+(s/def ::string-of-a
+  (s/with-gen string?
+    #(gen/fmap
+      (fn [n] (string/join (repeat (max n 0) \a)))
+      (s/gen (s/int-in -3 4)))))
+
+(s/def ::string-of-b
+  (s/with-gen string?
+    #(gen/fmap
+      (fn [n] (string/join (repeat (max n 0) \b)))
+      (s/gen (s/int-in 0 3)))))
+
+; (generate-examples ::string-of-a 40)
+
+(s/def ::sheepish-like-substrings
+  (s/with-gen
+    (s/coll-of any?)
+    #(gen/tuple (s/gen ::usually-empty-string)
+                (s/gen ::string-of-b)
+                (s/gen ::usually-empty-string)
+                (s/gen ::string-of-a)
+                (s/gen ::usually-empty-string)
+                (s/gen ::string-of-a))))
+
+; (generate-examples ::sheepish-like-substrings 10)
+
+(s/def ::sheepish-like-string
+  (s/with-gen
+    string?
+    #(gen/fmap string/join (s/gen ::sheepish-like-substrings))))
+
+; (generate-examples ::sheepish-like-string 10)
+


datomic insert string

datomic insert string

error: pathspec 'datomic-dsl/src/datomic_dsl/add.clj' did not match any file(s) known to git

--- datomic-dsl/src/datomic_dsl/add.clj
+++ datomic-dsl/src/datomic_dsl/add.clj
@@ -0,0 +1,24 @@
+(ns datomic-dsl.add
+  (:require
+   [datomic.api :as d]))
+
+(defn convert-dsl-to-keywords-fn
+  "Pass this in as a  parameter so we can use it later."
+  [schema-name]
+  (fn [[attribute-key attribute-value]]
+    ;;Build a vector for the datomic fact add, if the value is a map then we'll set ID
+    [(keyword schema-name attribute-key) attribute-value]))
+
+;;TODO: why concat?
+(defn convert-to-map
+  "Format the input vector for the Datomic map syntax."
+  [input]
+  [(apply hash-map (first (concat input)))])
+
+(defn add-datom
+  "Given a schema name and some key-value pairs, generate a Datomic insert string. Nested values are out of scope."
+  [schema-name attributes]
+  (let [convert-dsl-to-keywords (convert-dsl-to-keywords-fn schema-name)]
+    (convert-to-map
+     [(concat [:db/id (d/tempid :db.part/user)]
+              (mapcat convert-dsl-to-keywords attributes))])))


minor changes

minor changes

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/Zallin/fhirvc.git/'


Add missing file.

Add missing file.

error: pathspec 'src/circle/model/build.clj' did not match any file(s) known to git

--- src/circle/model/build.clj
+++ src/circle/model/build.clj
@@ -0,0 +1,207 @@
+(ns circle.model.build
+  "Main definition of the Build object. "
+  (:require [clojure.string :as str])
+  (:require fs)
+  (:use [arohner.utils :only (inspect)])
+  (:use [circle.util.except :only (throw-if-not)]
+        [circle.util.args :only (require-args)])
+  (:require [clj-time.core :as time])
+  (:require [circle.util.model-validation :as v])
+  (:require [circle.backend.ssh :as ssh])
+  (:require [circle.model.project :as project])
+  (:use [circle.util.model-validation-helpers :only (is-ref? require-keys)])
+  (:use [circle.util.predicates :only (ref?)])
+  (:require [somnium.congomongo :as mongo])
+  (:require [circle.util.mongo :as c-mongo])
+  (:require [circle.sh :as sh])
+  (:use [clojure.tools.logging :only (log)])
+  (:require [circle.backend.github-url :as github-url])
+  (:require [robert.hooke :as hooke]))
+
+(def build-coll :builds) ;; mongo collection for builds
+
+(def build-defaults {:continue? true
+                     :action-results []})
+
+(def node-validation
+  [(require-keys [:username])])
+
+(def build-validations
+  [(require-keys [:_project_id
+                  :build_num
+                  :vcs_url
+                  :vcs_revision
+                  :node])
+   (fn [build]
+     (v/validate node-validation (-> build :node)))
+   (fn [b]
+     (when (and (= :deploy (:type b)) (not (-> b :vcs_revision)))
+       "version-control revision is required for deploys"))
+   (fn [b]
+     (when-not (and (-> b :build_num (integer?))
+                    (-> b :build_num (pos?)))
+       "build_num must be a positive integer"))])
+
+(defn validate [b]
+  (v/validate build-validations b))
+
+(defn valid? [b]
+  (v/valid? build-validations b))
+
+(defn validate!
+  "Validates the contents of a build. i.e. pass the map, not the ref"
+  [b]
+  {:pre [(not (ref? b))]}
+  (v/validate! build-validations b))
+
+(def build-dissoc-keys
+  ;; Keys on build that shouldn't go into mongo, for whatever reason
+  [:actions :action-results])
+
+(defn insert! [row]
+  (mongo/insert! :builds (apply dissoc row build-dissoc-keys)))
+
+(defn update-mongo
+  "Given a build ref, update the mongo row with the current values of b."
+  [b]
+  (assert (-> @b :_id))
+  (c-mongo/ensure-object-id-ref build-coll b)
+  (mongo/update! build-coll
+                 {:_id (-> @b :_id)}
+                 (apply dissoc @b build-dissoc-keys)))
+
+(defn sync-with-db [b id]
+  "Fetch the build from the db using id and merge it with b"
+  (dosync
+   (let [old (mongo/fetch-by-id build-coll (mongo/object-id id))]
+     (alter b merge old)
+     (update-mongo b))))
+
+(defn add-to-db [b id]
+  "If id is null, add build to database, else sync contents with existing db object"
+  (if id
+    (sync-with-db b id)
+    (insert! b)))
+
+(defn project-name [b]
+  {:pre [(-> @b :_project_id)]
+   :post [(seq %)]}
+  (or (-> @b :_project_id (project/get-by-id) :name)
+      (-> @b :vcs_url (github-url/parse) :project)))
+
+(defn build [{:keys [build_num    ;; int
+                     vcs_url
+                     vcs_revision ;; if present, the commit that caused the build to be run, or nil
+                     notify_emails ;; a seq of email addresses to notify when build is done
+                     actions      ;; a seq of actions
+                     action-results
+                     node         ;; Map containing keys required by ec2/start-instance
+                     lb-name      ;; name of the load-balancer to use
+                     continue?    ;; if true, continue running the build. Failed actions will set this to false
+                     ]
+              :as args}]
+  (let [project (project/get-by-url! vcs_url)
+        build_num (or build_num (project/next-build-num project))]
+    (ref (merge build-defaults
+                args
+                {:build_num build_num
+                 :_project_id (-> project :_id)})
+         :validator validate!)))
+
+(defn extend-group-with-revision
+  "update the build, setting the pallet group-name to extends the
+  existing group with the VCS revision."
+  [build]
+  (dosync
+   (alter build
+          assoc-in [:group :group-name] (keyword (.toLowerCase (format "%s-%s" (project-name build) (-> @build :vcs_revision))))))
+  build)
+
+(defn build-name
+  ([build]
+     (build-name (project-name build) (-> @build :build_num)))
+  ([project-name build-num]
+     (str project-name "-" build-num)))
+
+(defn checkout-dir
+  "Directory where the build will be checked out, on the build box."
+  ([build]
+     (checkout-dir (project-name build) (-> @build :build_num)))
+  ([project-name build-num]
+     (str/replace (build-name project-name build-num) #" " "-")))
+
+(defn successful? [build]
+  (and (-> @build :stop_time)
+       (-> @build :continue?)))
+
+(defn log-ns
+  "returns the name of the logger to use for this build "
+  [build]
+  (symbol (str "circle.build." (project-name build) "-" (-> @build :build_num))))
+
+(defn get-project [build]
+  {:post [%]}
+  (project/get-by-id (-> @build :_project_id)))
+
+(def ^:dynamic *log-ns* nil) ;; contains the name of the logger for the current build
+
+(defn ssh-build-log
+  "This is a different function from the normal build log because 1)
+  ssh/handle-out won't pass format arguments. 2) if the string does happen to
+  contain a %s, we don't want format throwing because we have a %s and
+  no extra args"
+  [str level]
+  (when *log-ns*
+    (log *log-ns* level nil str)))
+
+(defn log-ssh-out
+  [level]
+  (fn [f str]
+    (ssh-build-log str level)
+    (f str)))
+
+;; def, so hooke doesn't re-add hooks on every fn call
+(def handle-out (log-ssh-out :info))
+(def handle-err (log-ssh-out :error))
+
+(hooke/add-hook #'ssh/handle-out handle-out)
+(hooke/add-hook #'ssh/handle-error handle-err)
+
+(defmacro with-build-log-ns [build & body]
+  `(binding [*log-ns* (log-ns ~build)]
+     ~@body))
+
+(defn build-log [message & args]
+  (when *log-ns*
+    (log *log-ns* :info nil (apply format message args))))
+
+(defn build-log-error [message & args]
+  (when *log-ns*
+    (log *log-ns* :error nil (apply format message args))))
+
+(defn build-with-instance-id
+  "Returns the build from the DB with the given instance-id"
+  [id]
+  (mongo/fetch-one build-coll :where {:instance-ids id}))
+
+(defn ssh
+  "Opens a terminal window that SSHs into instance with the provided id.
+
+Assumes:
+  1) the instance was started by a build
+  2) the build is in the DB
+  3) the instance is still running
+  4) this clojure process is on OSX"
+
+  [instance-id]
+  (let [build (build-with-instance-id instance-id)
+        ssh-private-key (-> build :node :private-key)
+        username (-> build :node :username)
+        ip-addr (-> build :node :ip-addr)
+        key-temp-file (fs/tempfile "ssh")
+        _ (spit key-temp-file ssh-private-key)
+        _ (fs/chmod "-r" key-temp-file)
+        _ (fs/chmod "u+r" key-temp-file)
+        ssh-cmd (format "ssh -i %s %s@%s" key-temp-file username ip-addr)
+        tell-cmd (format "'tell app \"Terminal\" \ndo script \"%s\"\n end tell'" ssh-cmd)]
+    (sh/shq (osascript -e ~tell-cmd))))


rev comment

rev comment


rev ns requires

rev ns requires


Iruzkinetan beti datu guztiak lortu

Iruzkinetan beti datu guztiak lortu

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/lnmnd/magnet.zer.git/'


Play random swarams that sort of fit in a */4 talam

error: pathspec 'src/movertone/random.clj' did not match any file(s) known to git

--- src/movertone/random.clj
+++ src/movertone/random.clj
@@ -0,0 +1,45 @@
+(ns movertone.random
+  (:require [movertone.core :as c]
+            [movertone.swarams :as sw]
+            [movertone.ragams :as r]))
+
+(defn adjacent-differences [nums]
+  (loop [num-list nums
+         res []]
+    (let [two-nums (take 2 num-list)]
+      (if (= 2 (count two-nums))
+        (recur (rest num-list)
+               (conj res (Math/abs (apply - two-nums))))
+        res))))
+
+(defn gen-durations []
+  (let [m 16
+        n 8
+        sum (- m n)]
+    (->> (repeatedly n #(rand-nth (range (inc sum))))
+         (cons sum)
+         sort
+         adjacent-differences
+         (map inc))))
+
+(defn random-swarams [swarams num]
+  (repeatedly num #(rand-nth swarams)))
+
+(defn random-durations [jathi num]
+  ;; [1, 2, 1, 1, 4, 1, 1, 2, 2, 4]
+  (take num (flatten (repeatedly gen-durations))))
+
+(defn random-phrase [ragam-name jathi num]
+  (let [ragam (ragam-name r/ragams)
+        swarams-in-ragam (sw/actual-swarams->simple-swarams
+                          (sw/madhya-swarams-in-ragam ragam))]
+    (c/phrase ragam
+              (vec (random-swarams swarams-in-ragam num))
+              (vec (random-durations jathi num))
+              (:lower c/kalams))))
+
+(defn play-random-phrase [ragam-name jathi num]
+  (c/play-phrase (random-phrase ragam-name jathi num)))
+
+(comment
+  (play-random-phrase :vasanti 3 100))


wgseq phase-2 flow

wgseq phase-2 flow

error: pathspec 'Jobs/wgseq-phase-2-job-template.clj' did not match any file(s) known to git

--- Jobs/wgseq-phase-2-job-template.clj
+++ Jobs/wgseq-phase-2-job-template.clj
@@ -0,0 +1,10 @@
+
+{:nodes
+ {:ph2
+  {:name "wgseq-phase2",
+   :type "tool",
+   :args []}
+  :prn1 {:type "func",
+         :name "prn"}},
+ :edges
+ {:ph2 [:prn1]}}


Add midje config to print facts as they are verified

error: pathspec '.midje.clj' did not match any file(s) known to git

--- .midje.clj
+++ .midje.clj
@@ -0,0 +1 @@
+(change-defaults :print-level :print-facts)


Add tests over oxcart.passes/tree-shake

Add tests over oxcart.passes/tree-shake

Not my best cases, but they'll do. The tree shaking emitter is pretty
trivially correct if the reach sets are correct, but they could use
their own tests in future.

error: pathspec 'test/oxcart/passes/tree_shake_test.clj' did not match any file(s) known to git

--- test/oxcart/passes/tree_shake_test.clj
+++ test/oxcart/passes/tree_shake_test.clj
@@ -0,0 +1,22 @@
+;;   Copyright (c) Reid McKenzie, Rich Hickey & contributors. The use
+;;   and distribution terms for this software are covered by the
+;;   Eclipse Public License 1.0
+;;   (http://opensource.org/licenses/eclipse-1.0.php) which can be
+;;   found in the file epl-v10.html at the root of this distribution.
+;;   By using this software in any fashion, you are agreeing to be
+;;   bound by the terms of this license.  You must not remove this
+;;   notice, or any other, from this software.
+
+(ns oxcart.passes.tree-shake-test
+  (:require [oxcart.passes.tree-shake :refer :all]
+            [clojure.test :refer :all]))
+
+
+(deftest global-reach-set-test
+  (let [tree {:foo #{}
+              :bar #{:foo}
+              :baz #{:bar}}
+        tree (global-reach-set tree)]
+    (is (= (:foo tree) #{}))
+    (is (= (:bar tree) #{:foo}))
+    (is (= (:baz tree) #{:bar :foo}))))


forgot to add file

forgot to add file

error: pathspec 'src/com/zensol/cisql/process_query.clj' did not match any file(s) known to git

--- src/com/zensol/cisql/process_query.clj
+++ src/com/zensol/cisql/process_query.clj
@@ -0,0 +1,86 @@
+(ns com.zensol.cisql.process-query
+  (:require [clojure.tools.logging :as log]
+            [clojure.string :as str])
+  (:import (java.io BufferedReader InputStreamReader StringReader))
+  (:require [com.zensol.cisql.conf :as c]
+            [com.zensol.cisql.db-access :as db]))
+
+(def ^:dynamic *std-in* nil)
+
+(def ^{:private true
+       :dynamic true}
+  *query* nil)
+
+(defmacro with-query [& body]
+  `(.append *query* (with-out-str ~@body)))
+
+(defn- add-line [line]
+  (letfn [(has-eol [key]
+            (let [conform (str/lower-case (str/trim line))]
+              (.endsWith conform (c/config key))))
+          (find-keyword [key]
+            (str/trim
+             (subs line 0 (- (count line)
+                             (count (c/config key))))))]
+    (cond (has-eol :line-terminator)
+          (do (with-query
+                (print (find-keyword :line-terminator)))
+              :end-query)
+
+          (has-eol :end-directive)
+          (do (with-query
+                (print (find-keyword :end-directive)))
+              :end-session)
+
+          :default
+          (do (with-query
+                (println line))
+              :continue))))
+
+(defn- read-query []
+  (binding [*query* (StringBuilder.)]
+    (let [lines-left (atom 20)
+          directive (atom nil)]
+      (letfn [(end [dir]
+                (log/debugf "query: %s" *query*)
+                (reset! lines-left 0)
+                (reset! directive dir))]
+        (while (> @lines-left 0)
+   (log/tracef "lines left: %d" @lines-left)
+   (let [user-input (.readLine *std-in*)]
+     (log/debugf "line: %s" user-input)
+     (if-not user-input
+       (do
+         (log/debugf "read EOF from input")
+         (end :end-file))
+       (let [dir (add-line user-input)]
+         (log/tracef "dir: %s" dir)
+         (log/tracef "query so far: %s" *query*)
+         (case dir
+           :end-query (end dir)
+           :end-session (end dir)
+           :continue (log/tracef "continue...")
+           :default (throw (IllegalStateException.
+                            (str "unknown directive: " dir)))))))
+   (swap! lines-left dec)))
+      {:query (str/trim (.toString *query*))
+       :directive @directive})))
+
+(defn process-queries [dir-fns]
+  (let [prompt-fn (get dir-fns :prompt-for-input)]
+    (prompt-fn)
+    (loop [query-data (read-query)]
+      (log/tracef "query data: %s" query-data)
+      (log/debugf "query: <%s>" (:query query-data))
+      (if-let [dir-fn (get dir-fns (:directive query-data))]
+        (dir-fn query-data)
+        (throw (IllegalArgumentException.
+                (str "no mapping for directive: "
+                     (:directive query-data)))))
+      (when (= :end-query (:directive query-data))
+        (prompt-fn)
+        (recur (read-query))))))
+
+(defn process-query-string [query-string dir-fns]
+  (binding [*std-in* (BufferedReader. (StringReader. query-string))]
+    (process-queries dir-fns)))