Not zero padding '0'.

Not zero padding '0'.

--- src-cljs/frontend/components/build_timings.cljs
+++ src-cljs/frontend/components/build_timings.cljs
@@ -47,7 +47,9 @@
   (let [m (js/Math.floor (/ ms-value 1000 60))
         s (js/Math.floor (- (/ ms-value 1000) (* m 60)))]
     (if (<= m 0)
-      (gstring/format "%02ds" s)
+      (if (= s 0)
+        (gstring/format "%ds" s)
+        (gstring/format "%02ds" s))
       (gstring/format "%d:%02dm" m s))))

 (defn create-y-axis [number-of-containers]


Separate the component out into the chart and the upsell message

Fix indentation, remove unnecessary params from chart component

Fix indentation some more [ci skip]

Fix indentation some more [ci skip]

Draw chart on component mount if build is not nil

More indentation

--- src-cljs/frontend/components/build_timings.cljs
+++ src-cljs/frontend/components/build_timings.cljs
@@ -202,44 +202,63 @@
     (draw-label! chart parallel)
     (draw-steps! x-scale chart steps)))

+(defn build-timings-chart [build owner]
+  (reify
+    om/IDidMount
+    (did-mount [_]
+      (let [dom-root (om/get-node owner "build-timings-svg")]
+        (when build
+          (draw-chart! dom-root build))
+        (om/set-state! owner [:resize-key]
+                       (disposable/register
+                        (gevents/listen js/window "resize"
+                                        #(draw-chart!
+                                          dom-root
+                                          build))
+                        gevents/unlistenByKey))))
+
+    om/IWillUnmount
+    (will-unmount [_]
+      (disposable/dispose (om/get-state owner [:resize-key])))
+
+    om/IDidUpdate
+    (did-update [_ _ _]
+      (when build
+        (draw-chart! (om/get-node owner "build-timings-svg") build)))
+
+    om/IRenderState
+    (render-state [_ _]
+      (html
+       [:div
+        (when-not build
+          [:div.loading-spinner common/spinner])
+        [:svg {:ref "build-timings-svg"}]]))))
+
+(defn upsell-message [plan owner]
+  (reify
+    om/IDidMount
+    (did-mount [_]
+      ((om/get-shared owner :track-event) {:event-type :build-timing-upsell-impression}))
+
+    om/IRenderState
+    (render-state [_ _]
+      (let [{{plan-org-name :name
+              plan-vcs-type :vcs_type} :org} plan]
+        (html
+         [:span.message "This release of Build Timing is only available for repos belonging to paid plans. Please "
+          [:a.upgrade-link
+           {:href (routes/v1-org-settings-path {:org plan-org-name
+                                                :vcs_type plan-vcs-type})
+            :on-click #((om/get-shared owner :track-event) {:event-type :build-timing-upsell-click})}
+           "upgrade here."]])))))
+
 ;;;; Main component
 (defn build-timings [{:keys [build project plan]} owner]
   (reify
-    om/IWillMount
-    (will-mount [_]
-      (om/set-state!
-        owner [:resize-key]
-        (disposable/register
-          (gevents/listen js/window "resize"
-                          #(draw-chart!
-                                 (om/get-node owner "build-timings-svg")
-                                 build))
-          gevents/unlistenByKey)))
-
-    om/IWillUnmount
-    (will-unmount [_]
-      (disposable/dispose (om/get-state owner [:resize-key])))
-
-    om/IDidUpdate
-    (did-update [_ _ _]
-      (if (project-model/show-build-timing? project plan)
-        (draw-chart! (om/get-node owner "build-timings-svg") build)
-        ((om/get-shared owner :track-event) {:event-type :build-timing-upsell-impression})))
-
     om/IRenderState
-    (render-state [_ {:keys [loading?]}]
-      (let [{{plan-org-name :name
-              plan-vcs-type :vcs_type} :org} plan]
-        (html
-         [:div.build-timings
-          (if (project-model/show-build-timing? project plan)
-            [:div
-             (when (not (and build project plan))
-               [:div.loading-spinner common/spinner])
-             [:svg {:ref "build-timings-svg"}]]
-            [:span.message "This release of Build Timing is only available for repos belonging to paid plans. Please "
-             [:a.upgrade-link
-              {:href (routes/v1-org-settings-path {:org plan-org-name
-                                                   :vcs_type plan-vcs-type})
-               :on-click #((om/get-shared owner :track-event) {:event-type :build-timing-upsell-click})}
-              "upgrade here."]])])))))
+    (render-state [_ _]
+      (html
+       [:div.build-timings
+        (if (project-model/show-build-timing? project plan)
+          (om/build build-timings-chart build)
+          (om/build upsell-message plan))]))))


Addressed review comment

Addressed review comment

--- src-cljs/frontend/components/documentation.cljs
+++ src-cljs/frontend/components/documentation.cljs
@@ -178,13 +178,15 @@
        [:aside
         (om/build docs-categories {:categories (categories docs) :selected doc})]
        [:div.container-fluid.article-container
-        [:article
-         (om/build docs-search app)
-         (if (= subpage :search)
-           (om/build search-results query-results {:opts {:query query}})
-           [:div
-            (when query
-              [:p.back-to-search [:a {:href "/docs/search"} (gstring/format "Back to search results for \"%s\"" query)]])
-            (if subpage
-              (om/build docs-subpage doc {:opts {:_fragment fragment}})
-              (om/build front-page app))])]]]])))
+        [:div.row
+         [:div.col-sm-12
+          [:article
+           (om/build docs-search app)
+           (if (= subpage :search)
+             (om/build search-results query-results {:opts {:query query}})
+             [:div
+              (when query
+                [:p.back-to-search [:a {:href "/docs/search"} (gstring/format "Back to search results for \"%s\"" query)]])
+              (if subpage
+                (om/build docs-subpage doc {:opts {:_fragment fragment}})
+                (om/build front-page app))])]]]]]])))


Update action form state.

Update action form state.

--- src/cljs/hatnik/web/client/form/add_action.cljs
+++ src/cljs/hatnik/web/client/form/add_action.cljs
@@ -228,19 +228,34 @@
     :type :email}
    new-init-state email-init-state github-issue-init-state))

+(defmulti get-init-state-by-action #(get % "type"))
+(defmethod get-init-state-by-action "noop" [action]
+  (merge email-init-state github-issue-init-state))
+
+(defmethod get-init-state-by-action "email" [action]
+  (merge
+   {:email-template (get action "template")}
+    github-issue-init-state))
+
+(defmethod get-init-state-by-action "github-issue" [action]
+  (let [repo (split (get action "repo") "/")
+        user (first repo)
+        repository (second repo)]
+  (merge
+   {:gh-issue-title (get action "title")
+    :gh-issue-body (get action "body")
+    :gh-user user
+    :gh-repo repository}
+   email-init-state)))
+
 (defmethod get-init-state :update [data _]
   (let [action (:action data)]
-    (.log js/console action)
-    {:type (keyword (get action "type"))
-     :project-id (:project-id data)
-     :artifact-value (get action "library")
-     :action-id (get action "id")
-     :email-template (get action "template")
-     :gh-repo (get action "repo")
-     :gh-issue-title (get action "title")
-     :gh-issue-body (get action "body")
-     :user-email (:user-email data)
-     :callback action/update-email-action}))
+    (merge {:type (keyword (get action "type"))
+            :project-id (:project-id data)
+            :user-email (:user-email data)
+            :artifact-value (get action "library")
+            :action-id (get action "id")}
+           (get-init-state-by-action action))))

 (defmulti get-action-header #(:type %))
 (defmethod get-action-header :add [_ _] (dom/h4 nil "Add new action"))


Fix per https://github.com/MastodonC/kixi.hecuba/pull/643#commitcomment-13184197

--- src/cljs/kixi/hecuba/tabs/hierarchy/xyplot.cljs
+++ src/cljs/kixi/hecuba/tabs/hierarchy/xyplot.cljs
@@ -237,9 +237,9 @@
 (defn process-data
   [[x-data y-data]]
   (let [timestamp-key :timestamp
-        missing-timestamps (clojure.set/difference (set (map timestamp-key x-data)) (set (map timestamp-key y-data)))
-        filtered-x-data (filter (fn [m] (not (some #(= % (timestamp-key m)) missing-timestamps))) x-data)
-        filtered-y-data (filter (fn [m] (not (some #(= % (timestamp-key m)) missing-timestamps))) y-data)
+        same-timestamps (clojure.set/intersection (set (map timestamp-key x-data)) (set (map timestamp-key y-data)))
+        filtered-x-data (filter (fn [m] (some #(= % (timestamp-key m)) same-timestamps)) x-data)
+        filtered-y-data (filter (fn [m] (some #(= % (timestamp-key m)) same-timestamps)) y-data)
         x-raw-data (->> filtered-x-data (sort-by :timestamp) (mapv :value) (map js/parseFloat))
         y-raw-data (->> filtered-y-data (sort-by :timestamp) (mapv :value) (map js/parseFloat))
         data {:values (mapv (fn [x y] (vector x y)) x-raw-data y-raw-data)}


auto-deploy frontend changes

auto-deploy frontend changes

--- src/pc/assets.clj
+++ src/pc/assets.clj
@@ -220,9 +220,8 @@
                      :metadata {:content-length (count manifest-bytes)
                                 :content-type "application/edn"})
       (validate-manifest! (fetch-specific-manifest cdn-bucket manifest-key))
-      ;; (log/infof "moving manifest pointer to %s" manifest-key)
-      ;; (move-manifest-pointer cdn-bucket manifest-key)
-      (log/infof "not moving manifest pointer to %s, should do it manually after deploy" manifest-key)
+      (log/infof "moving manifest pointer to %s" manifest-key)
+      (move-manifest-pointer cdn-bucket manifest-key)
       (log/infof "uploading sourcemap to rollbar")
       (upload-sourcemap sha1 manifest))))


use the proper md5 format

use the proper md5 format

--- src/pc/assets.clj
+++ src/pc/assets.clj
@@ -185,7 +185,7 @@
                                    :key key
                                    :input-stream (java.io.ByteArrayInputStream. gzipped-bytes)
                                    :metadata {:content-type (mime-type-of file)
-                                              :content-md5 tag
+                                              :content-md5 (md5/hex->base64 tag)
                                               :content-encoding "gzip"
                                               :content-length (count gzipped-bytes)
                                               :cache-control "max-age=3155692"})]
@@ -220,7 +220,7 @@
                                             :input-stream (java.io.ByteArrayInputStream. gzipped-bytes)
                                             :metadata {:content-type (mime-type-of file-path)
                                                        :content-length (count gzipped-bytes)
-                                                       :content-md5 (byte-array->md5 gzipped-bytes)
+                                                       :content-md5 (md5/hex->base64 (byte-array->md5 gzipped-bytes))
                                                        :content-encoding "gzip"
                                                        :cache-control "max-age=3155692"})
                              (assoc acc path {:s3-key key :s3-bucket cdn-bucket})))


allow copy-transactions to exclude txids

--- src/pc/replay.clj
+++ src/pc/replay.clj
@@ -77,10 +77,11 @@
              tx))
          txes)))

-(defn copy-transactions [db doc new-doc & {:keys [sleep-ms]
+(defn copy-transactions [db doc new-doc & {:keys [sleep-ms remove-tx]
                                            :or {sleep-ms 1000}}]
   (let [conn (pcd/conn)
         txes (->> (get-document-transactions db doc)
+               (remove (fn [tx] (contains? remove-tx (:db/id (:tx tx)))))
                (map (fn [tx]
                       (update-in tx
                                  [:tx-data]


remove tooltip from account notification settings


Fix reloading issue?

Fix reloading issue?

--- test/clj/comic_reader/sites/test_util.clj
+++ test/clj/comic_reader/sites/test_util.clj
@@ -2,7 +2,7 @@
   (:require [clojure.string :as str]
             [clojure.test :refer :all]
             [clojure.template :as template]
-            [comic-reader.sites :as sites]
+            [comic-reader.sites]
             [clojure.template :refer [do-template]]
             [clj-http.client :as client]
             [loom.graph :as graph]
@@ -102,9 +102,9 @@
   (are [url-fn] (is (= (:status (client/head (url-fn)))
                        200)
                     (str (url-fn) "does not appear to exist."))
-    sites/root-url
-    sites/manga-url
-    sites/manga-list-url))
+    comic-reader.sites/root-url
+    comic-reader.sites/manga-url
+    comic-reader.sites/manga-list-url))

 (defmacro and-template [argv expr & values]
   (let [c (count argv)]


Update and remove tests for consolidated functions

--- test/cljs/love_letter_cljs/game_test.cljs
+++ test/cljs/love_letter_cljs/game_test.cljs
@@ -5,23 +5,23 @@
 ;; helpers
 (defn discard-n [game n]
   (->> game
-       (iterate #(sut/discard-card % [:deck]))
+       (iterate #(sut/move-card % [:deck] [:discard-pile]))
        (drop n)
        first))

 ;; (create-and-deal)
 (def test-game-a
-  {:deck '({:face :guard,    :value 1 :visible []}
-           {:face :baron,    :value 3 :visible []}
-           {:face :priest,   :value 2 :visible []}
-           {:face :guard,    :value 1 :visible []}
-           {:face :handmaid, :value 4 :visible []}
-           {:face :prince,   :value 5 :visible []}
-           {:face :handmaid, :value 4 :visible []}
-           {:face :guard,    :value 1 :visible []}
-           {:face :princess, :value 8 :visible []}
-           {:face :baron,    :value 3 :visible []}
-           {:face :king,     :value 6 :visible []}),
+  {:deck [{:face :guard,    :value 1 :visible []}
+          {:face :baron,    :value 3 :visible []}
+          {:face :priest,   :value 2 :visible []}
+          {:face :guard,    :value 1 :visible []}
+          {:face :handmaid, :value 4 :visible []}
+          {:face :prince,   :value 5 :visible []}
+          {:face :handmaid, :value 4 :visible []}
+          {:face :guard,    :value 1 :visible []}
+          {:face :princess, :value 8 :visible []}
+          {:face :baron,    :value 3 :visible []}
+          {:face :king,     :value 6 :visible []}],
    :discard-pile [],
    :players {1 {:id 1, :hand [{:face :guard,  :value 1 :visible []}], :alive? true, :protected? true},
              2 {:id 2, :hand [{:face :priest, :value 2 :visible []}], :alive? false},
@@ -84,12 +84,6 @@
                (sut/king-ability 1 2)
                (get-in [:players 1 :hand]))))))

-(deftest discard-card-test
-  (is (= [{:face :guard :value 1 :visible []}]
-         (-> test-game-a
-             (sut/discard-card [:players 1 :hand])
-             :discard-pile))))
-
 (deftest prince-ability-test
   (is (= [{:face :guard :value 1 :visible []}]
          (-> test-game-a
@@ -111,7 +105,10 @@
 (deftest countess-check-test
   (is (= true
          (-> test-game-a
-             (sut/countess-check 4)))))
+             (sut/countess-check 4))))
+  (is (= false
+         (-> test-game-a
+             (sut/countess-check 3)))))

 (deftest remove-protection-test
   (is (= false


Don't attempt to locate a file representing the scsynth executable on linux - as it should be in the PATH. Also, throw an error if a suitable path to scsynth couldn't be found.

--- src/overtone/sc/machinery/server/connection.clj
+++ src/overtone/sc/machinery/server/connection.clj
@@ -186,13 +186,27 @@
       (Thread/sleep 250))
     (.destroy proc)))

+(defn- find-sc-path
+  "Find the path for SuperCollider. If linux don't check for a file as it should
+  be in the PATH list."
+  []
+  (let [os    (@config* :os)
+        paths (SC-PATHS os)
+        path  (if (= :linux os)
+                (first paths)
+                (first (filter #(.exists (java.io.File. %)) paths)))]
+    (when-not path
+      (throw (Exception. (str "Unable to locate a valid scsynth executable on your system. I looked in the following places: " paths))))
+
+    path))
+
 (defn- boot-external-server
   "Boot the audio server in an external process and tell it to listen on a
   specific port."
   ([port]
      (when-not (= :connected @connection-status*)
        (println "booting external")
-       (let [sc-path (first (filter #(.exists (java.io.File. %)) (SC-PATHS (@config* :os))))
+       (let [sc-path (find-sc-path)
              cmd (into-array String (concat [sc-path "-u" (str port)] (SC-ARGS (@config* :os))))
              sc-thread (Thread. #(external-booter cmd))]
          (.setDaemon sc-thread true)


Log a more useful error when failing to resolve a service component

--- src/main/workflo/macros/service.cljs
+++ src/main/workflo/macros/service.cljs
@@ -73,8 +73,8 @@
      (let [service-name (symbol (name service-kw))
            component    (try
                           (resolve-service-component service-name)
-                          (catch js/Error e
-                            (println "WARN:" (.-message e))))]
+                          (catch js/Error error
+                            (js/console.warn "Failed to resolve service component:"
+                                             error)))]
        (some-> component
-               (deliver-to-service-component! service-data
-                                              context))))))
+               (deliver-to-service-component! service-data context))))))


test cases

test cases

--- cloc-web/test/cloc_web/core_test.clj
+++ cloc-web/test/cloc_web/core_test.clj
@@ -36,6 +36,13 @@

 (use-fixtures :once setup-server)
 (use-fixtures :each setup-each)
+
+(defn- get-display-lang
+  [id]
+  (-> (r/table "users")
+      (r/get id)
+      (r/run @db-conn)
+      :lang))

 (deftest register-with-unauthorized-user
   (testing "no session"
@@ -114,3 +121,41 @@
                                                                                :content-type :json
                                                                                :throw-exceptions false
                                                                                :cookies {"session_id" {:discard true :value (jwt-token "debug_token" {:expires (-> 28 days)})}}})))))))))
+
+(deftest patch-display-lang-with-authorized-user
+  (scenario "register repos"
+    (-> (r/table "users")
+        (r/insert {:id "github/0of/target"
+                   :user "0of"
+                   :filter "*"
+                   :lang "SUM"})
+        (r/run @db-conn)))
+
+  (with-redefs [clj-http.client/get (fn [& param] {:status 200
+                                                   :body {:login "0of"}})]
+
+    (testing "Clojure as display language"
+      (-> (str url "/user/target/display_lang")
+          (client/patch {:accept :json
+                         :body  (cheshire/generate-string {:lang "Clojure"})
+                         :content-type :json
+                         :as :json
+                         :throw-exceptions false
+                         :cookies {"session_id" {:discard true :value (jwt-token "debug_token" {:expires (-> 28 days)})}}})
+          :status
+          (= 200)
+          (and (= "Clojure" (get-display-lang "github/0of/target")))
+          is)
+
+     (testing "Default display language"
+        (-> (str url "/user/target/display_lang")
+            (client/patch {:accept :json
+                           :body ""
+                           :content-type :json
+                           :as :json
+                           :throw-exceptions false
+                           :cookies {"session_id" {:discard true :value (jwt-token "debug_token" {:expires (-> 28 days)})}}})
+            :status
+            (= 200)
+            (and (= "SUM" (get-display-lang "github/0of/target")))
+            is)))))


Make it possible for code reload to work on kstreams.clj

--- clstreams/src/clstreams/kstreams.clj
+++ clstreams/src/clstreams/kstreams.clj
@@ -1,5 +1,5 @@
 (ns clstreams.kstreams
-  (:refer-clojure :only [import])
+  (:refer-clojure :only [import let])
   (:require [clstreams.kstreams.impl :refer [define-multimethods]]))

 (define-multimethods)


Add :all profile to profiles.clj

Add :all profile to profiles.clj

--- .lein/profiles.clj
+++ .lein/profiles.clj
@@ -160,4 +160,18 @@
         {:jvm-opts ["-Dapple.awt.UIElement=true"]}]

  ;; Use humane test output when running 'lein test'.
- :test [:humane]}
+ :test [:humane]
+
+ ;; Profile that includes everything from this file. This allows for downloading all
+ ;; possible dependencies with 'lein with-profile +all --version'.
+ :all [:cider
+       :humane
+       :inject
+       :alembic
+       :pull
+       :reflection
+       :refresh
+       :lint
+       :pretty
+       :refactor
+       :spyscope]}


Remove superfluous comments

Remove superfluous comments

--- src/tobias/cv.clj
+++ src/tobias/cv.clj
@@ -27,10 +27,9 @@
   (json/read-str (:body body) :key-fn keyword))

 (defprotocol CvProvider
-  "Encapsulates a CV provider"
-  (name      [this]        "The name for this provider")
-  (features  [this image]  "Gets the features for an image")
-  (normalize [this result] "Normalizes a result"))
+  (name      [this])
+  (features  [this image])
+  (normalize [this result]))

 (def microsoft
   (reify CvProvider


Use proper config namespace for ingest migrations

--- ingest-app/src/cmr/ingest/api/routes.clj
+++ ingest-app/src/cmr/ingest/api/routes.clj
@@ -34,7 +34,7 @@
          (conj
           migrate-args
           "-c"
-          "config.migrate-config/app-migrate-config")))
+          "config.ingest-migrate-config/app-migrate-config")))
       {:status 204}))

 (def job-management-routes


Revised root_concept_identifier_gen rule to account for subClasses of owl:Thing

--- resources/rules/pre_identifier_merge/step_a_ontology_to_ice/step_a/root_concept_identifier_gen.clj
+++ resources/rules/pre_identifier_merge/step_a_ontology_to_ice/step_a/root_concept_identifier_gen.clj
@@ -8,9 +8,14 @@
   :reify ([?/id {:ln (:localname ?/root)
                  :ns "ccp" :prefix "" :suffix ""}])
   :sparql-string "select ?root {
-		  ?root rdf:type owl:Class .
-		  minus{?root rdfs:subClassOf ?class}
-		  minus{?root owl:deprecated true}
-		  filter(!contains(str(?root), '/bnode/'))
-		}"
+  ?root rdf:type owl:Class .
+  # return classes that are subClassOf owl:Thing or classes that are not subClassOf anything
+  filter ((exists {?root rdfs:subClassOf owl:Thing}) || (not exists {?root rdfs:subClassOf ?class}))
+  # exclude all deprecated classes
+  filter (not exists {?root owl:deprecated true})
+  # exclude any blank nodes
+  filter (!contains(str(?root), '/bnode/'))
+  # exclude the oboInOwl:ObsoleteClass class
+  minus {?root rdfs:label 'Obsolete Class'}
+  }"
 }


Update core.clj

Update core.clj

--- src/yaml/core.clj
+++ src/yaml/core.clj
@@ -1,7 +1,7 @@
 (ns yaml.core
  (:refer-clojure :exclude [load])
  (:require [clojure.java.io :as io]
-           [yaml.reader :refer [parse-string load]]
+           [yaml.reader :refer [parse-string]]
            [yaml.writer :refer [generate-string dump]]))

 (defn- safe-read


Claned up components.

Claned up components.


comment out version tests

comment out version tests

--- test/cake/tasks/version_test.clj
+++ test/cake/tasks/version_test.clj
@@ -3,55 +3,56 @@
 	[cake.file :only [file]])
   (:require [clojure.java.io :as io]))

-(defn version-wrap [f]
-  (cake "version" "0.1.0-SNAPSHOT")
-  (f)
-  (cake "version" "0.1.0-SNAPSHOT"))
+(comment
+ (defn version-wrap [f]
+   (cake "version" "0.1.0-SNAPSHOT")
+   (f)
+   (cake "version" "0.1.0-SNAPSHOT"))

-(use-fixtures :once in-test-project)
-(use-fixtures :each version-wrap)
+ (use-fixtures :once in-test-project)
+ (use-fixtures :each version-wrap)

-(defn assert-version [expected & [task-output]]
-  (let [results (cake "version")]
-    (testing "in current results from 'cake version'"
-      (is (= (str "test-example " expected "\n")
-	     (:out results))))
-    (testing "in defproject contents"
-      (is (= (str "(defproject test-example \"" expected "\"")
-	     (first (line-seq (io/reader (file "project.clj")))))))
-    (when task-output
-      (testing "in output of called task"
-	(is (re-matches (re-pattern (str ".*-> test-example " expected "\n"))
-			(:out task-output)))))))
+ (defn assert-version [expected & [task-output]]
+   (let [results (cake "version")]
+     (testing "in current results from 'cake version'"
+       (is (= (str "test-example " expected "\n")
+	      (:out results))))
+     (testing "in defproject contents"
+       (is (= (str "(defproject test-example \"" expected "\"")
+	      (first (line-seq (io/reader (file "project.clj")))))))
+     (when task-output
+       (testing "in output of called task"
+	 (is (re-matches (re-pattern (str ".*-> test-example " expected "\n"))
+			 (:out task-output)))))))

-(deftest initial-version
-  (testing "initial version is set to 0.1.0-SNAPSHOT by fixture"
-    (assert-version "0.1.0-SNAPSHOT")))
+ (deftest initial-version
+   (testing "initial version is set to 0.1.0-SNAPSHOT by fixture"
+     (assert-version "0.1.0-SNAPSHOT")))

-(deftest explicit-version
-  (testing "version set to 2.0.0"
-    (let [results (cake "version" "2.0.0")]
-      (assert-version "2.0.0"))))
+ (deftest explicit-version
+   (testing "version set to 2.0.0"
+     (let [results (cake "version" "2.0.0")]
+       (assert-version "2.0.0"))))

-(deftest version-bumping-test
-  (testing "version set with cake version bump"
-    (let [results (cake "version" "bump")]
-      (assert-version "0.1.0" results)))
-  (testing "version set with cake version bump --major"
-    (let [results (cake "version" "bump" "--major")]
-      (assert-version "1.1.0" results)))
-  (testing "version set with cake version bump --minor"
-    (let [results (cake "version" "bump" "--minor")]
-      (assert-version "1.2.0" results)))
-  (testing "version set with cake version bump --patch"
-    (let [results (cake "version" "bump" "--patch")]
-      (assert-version "1.2.1" results)))
-  (testing "version set with cake version bump --major --patch"
-    (let [results (cake "version" "bump" "--major" "--patch")]
-      (assert-version "2.2.2" results)))
-  (testing "version set with cake version bump --snapshot"
-    (let [results (cake "version" "bump" "--snapshot")]
-      (assert-version "2.2.2-SNAPSHOT" results)))
-  (testing "version set with cake version bump --major --snapshot"
-    (let [results (cake "version" "bump" "--major" "--snapshot")]
-      (assert-version "3.2.2-SNAPSHOT" results))))+ (deftest version-bumping-test
+   (testing "version set with cake version bump"
+     (let [results (cake "version" "bump")]
+       (assert-version "0.1.0" results)))
+   (testing "version set with cake version bump --major"
+     (let [results (cake "version" "bump" "--major")]
+       (assert-version "1.1.0" results)))
+   (testing "version set with cake version bump --minor"
+     (let [results (cake "version" "bump" "--minor")]
+       (assert-version "1.2.0" results)))
+   (testing "version set with cake version bump --patch"
+     (let [results (cake "version" "bump" "--patch")]
+       (assert-version "1.2.1" results)))
+   (testing "version set with cake version bump --major --patch"
+     (let [results (cake "version" "bump" "--major" "--patch")]
+       (assert-version "2.2.2" results)))
+   (testing "version set with cake version bump --snapshot"
+     (let [results (cake "version" "bump" "--snapshot")]
+       (assert-version "2.2.2-SNAPSHOT" results)))
+   (testing "version set with cake version bump --major --snapshot"
+     (let [results (cake "version" "bump" "--major" "--snapshot")]
+       (assert-version "3.2.2-SNAPSHOT" results)))))


Better just announce one queue for now.

Better just announce one queue for now.

--- resources/config.sample.clj
+++ resources/config.sample.clj
@@ -17,7 +17,7 @@
                   :host "0.0.0.0"
                   :port 6332
                   ;; List of queues announced via zeroconf
-                  :queues ["documents" "inbox"]}}
+                  :queues ["documents"]}}
  ;; Those origins' pages will appear in the Inbox
  :inbox {:origins #{"scanner"}}
  :ocr {:enable true


CLJS-1394: reify gensyms can clash

CLJS-1394: reify gensyms can clash

namespace reify names

--- src/main/clojure/cljs/core.cljc
+++ src/main/clojure/cljs/core.cljc
@@ -40,10 +40,11 @@
                                        unsafe-bit-and bit-shift-right-zero-fill mask bitpos caching-hash
                                        defcurried rfn specify! js-this this-as implements? array js-obj
                                        simple-benchmark gen-apply-to js-str es6-iterable load-file* undefined?
-                                       specify copy-arguments])])
+                                       specify copy-arguments goog-define])])
   #?(:cljs (:require-macros [cljs.core :as core]))
   (:require clojure.walk
             clojure.set
+            [clojure.string :as string]
             cljs.compiler
             [cljs.env :as env]
             #?(:cljs [cljs.core :as core])
@@ -1220,7 +1221,11 @@
   (meta ^{:k :v} (reify Object (toString [this] \"foo\")))
   == {:k :v}"
   [& impls]
-  (core/let [t        (with-meta (gensym "t") {:anonymous true})
+  (core/let [t        (with-meta
+                        (gensym
+                          (core/str "t_"
+                            (string/replace (core/str (munge ana/*cljs-ns*)) "." "$")))
+                        {:anonymous true})
              meta-sym (gensym "meta")
              this-sym (gensym "_")
              locals   (keys (:locals &env))


fixed regression in menu

fixed regression in menu

--- src/main/untangled/ui/menu.cljc
+++ src/main/untangled/ui/menu.cljc
@@ -94,7 +94,7 @@
 (defn menu-item
   "Build the state map that can be used in a menu as an item. The `id` need only be unique within the menu."
   [id label]
-  {:menu-item/item-id id :menu-item/label label :menu-item/active? false})
+  {:menu-item/item-id id :menu-item/label label})

 (defn- find-first [key value list] (first (filter #(= (get % key) value) list)))

@@ -107,7 +107,8 @@
   (render [this]
     (let [{:keys [menu/id menu/label menu/items menu/open? menu/selected-item]} (om/props this)
           onSelect       (or (om/get-computed this :onSelect) identity)
-          selected-item  (find-first :menu-item/item-id selected-item items)
+          selected-id    selected-item
+          selected-item  (find-first :menu-item/item-id selected-id items)
           selected-label (get selected-item :menu-item/label (tr-unsafe label))
           menu-class     (str "c-menu" (if open? " is-active" ""))]
       (dom/div #js {:key (str "menu-" (name id)) :className "has-menu"}
@@ -115,18 +116,17 @@
                                       (.stopPropagation evt)
                                       (om/transact! this `[(close-all {}) (set-open ~{:id id :open? (not open?)}) :menu/open?])
                                       false)
-                         :className "c-button js-dropdown-toggle"} (tr-unsafe selected-label))
+                         :className "c-button"} (tr-unsafe selected-label))
         (dom/ul #js {:tabIndex "-1" :aria-hidden "true" :className menu-class}
           (map (fn [{:keys [menu-item/item-id menu-item/label]}]
                  (dom/li #js {:key     (str "menu-item-" (name item-id))
                               :onClick (fn [evt]
                                          (.stopPropagation evt)
-                                         (m/set-value! this :menu-item/active? not)
                                          (om/transact! this `[(close-all {}) (select ~{:id id :item-id item-id}) :menu/open?])
                                          (when onSelect (onSelect item-id))
                                          false)}
                    (dom/button #js {:className (str "c-menu__item"
-                                                 (when :menu-item/active? " is-active"))} label))) items))))))
+                                                 (when (= item-id selected-id) " is-active"))} label))) items))))))

 ;; Make sure you either render a key in your DOM or supply keyfn


use getNextException to get the actual SQL exception


durations

durations

--- src/mljalfa/finance/voucher.clj
+++ src/mljalfa/finance/voucher.clj
@@ -116,6 +116,42 @@
                         {:value value :activation 1})))
     (remove empty? (into [] refs))))

+(defn process-duration
+  [fname]
+  (let [raw (->> (open-csv fname)
+                 (cs/split-lines)
+                 (drop 7)
+                 (mapv #(cs/split % #","))
+                 (mapv second)
+                 (mapv #(cs/split % #":"))
+                 (mapv rest)
+                 butlast vec)
+        mins (zipmap (map #(if (< % 10) (str "0" %) (str %)) (range 0 61))
+                     (map (partial * 60) (range 0 61)))
+        secs (zipmap (map #(if (< % 10) (str "0" %) (str %)) (range 0 61))
+                     (range 0 61))]
+    (mapv #(let [[a b] %] (+ (mins a) (secs b))) raw)))
+
+(defn normalise-complete
+  []
+  (let [wateva (open-json "complete")
+        base (map #(zipmap (map keyword (keys %)) (vals %)) wateva)
+        durations (open-edn "duration")
+        result (mapv #(assoc % :duration %2) base durations)]
+    (save-json "complete" result)
+    (save-edn "complete" result)))
+
+(defn add-duration-session
+  [fname]
+  (let [base (open-edn fname)
+        result (mapv #(assoc %
+                       :totalduration
+                       (int (/ (* (:session %) (:duration %)) 1000)))
+                     base)]
+    (doseq [f [save-edn save-json]]
+      (f fname result))))
+
+;; [:session :pageviews :newsession :blogviews :users :seo :direct]

@@ -129,3 +165,5 @@

+
+


Add some io utils for Node.js

Add some io utils for Node.js

--- src/node/replumb/nodejs/io.cljs
+++ src/node/replumb/nodejs/io.cljs
@@ -1,6 +1,5 @@
 (ns replumb.nodejs.io
-  (:require [cljs.nodejs :as nodejs]
-            [replumb.load :as load]))
+  (:require [cljs.nodejs :as nodejs]))

 (def require-fs
   "Delay containing the call to \"require fs\". It returns the File
@@ -18,13 +17,57 @@

   For encoding-or-opts, see
   https://nodejs.org/api/fs.html#fs_fs_readfile_file_options_callback."
-  ([file-name src-cb]
-   (read-file! (force require-fs) "utf-8" file-name src-cb))
-  ([encoding-or-opts file-name src-cb]
-   (read-file! (force require-fs) encoding-or-opts file-name src-cb))
-  ([fs-module encoding-or-opts file-name src-cb]
+  ([file-path src-cb]
+   (read-file! (force require-fs) "utf-8" file-path src-cb))
+  ([encoding-or-opts file-path src-cb]
+   (read-file! (force require-fs) encoding-or-opts file-path src-cb))
+  ([fs-module encoding-or-opts file-path src-cb]
    (try
-     ;; AR the async readFile had weird behavior and was wrecking havoc
-     (src-cb (.readFileSync fs-module file-name encoding-or-opts))
+     ;; AR the async readFile had weird behavior and was wreaking havoc
+     (src-cb (.readFileSync fs-module file-path encoding-or-opts))
      (catch :default e
        (src-cb nil)))))
+
+(defn write-file!
+  "Accepts the fs module object, encoding or file options, file name to
+  write and a callback. Upon success, invokes the callback with the
+  source of the file. Otherwise invokes the callback with nil.
+
+  The arity without explicit module will call require the first time
+  only. The arity without encoding-or-opts will default to no file
+  options and encoding \"UTF-8\".
+
+  It is synchronous and returns undefined as per Node.js doc.
+
+  For encoding-or-opts, see
+  https://nodejs.org/api/fs.html#fs_fs_writefile_file_data_options_callback."
+  ([file-path data]
+   (write-file! "utf-8" file-path data))
+  ([encoding-or-opts file-path data]
+   (write-file! (force require-fs) encoding-or-opts file-path data))
+  ([fs-module encoding-or-opts file-path data]
+   (try
+     (.writeFileSync fs-module file-path data encoding-or-opts)
+     (catch :default e
+       (println (.-stack e))))))
+
+(defn delete-file!
+  "Accepts the fs module object, encoding or file options, file name to
+  write and a callback. Upon success, invokes the callback with the
+  source of the file. Otherwise invokes the callback with nil.
+
+  The arity without explicit module will call require the first time
+  only. The arity without encoding-or-opts will default to no file
+  options and encoding \"UTF-8\".
+
+  It is synchronous and returns undefined as per Node.js doc.
+
+  For encoding-or-opts, see
+  https://nodejs.org/api/fs.html#fs_fs_writefile_file_data_options_callback."
+  ([file-path]
+   (delete-file! (force require-fs) file-path))
+  ([fs-module file-path]
+   (try
+     (.unlinkSync fs-module file-path)
+     (catch :default e
+       (println (.-stack e))))))


Default to reporting assign windows metrics.

--- src/onyx/information_model.cljc
+++ src/onyx/information_model.cljc
@@ -1154,7 +1154,8 @@
             {:doc "Onyx can provide metrics for all lifecycle stages. Simply provide the lifecycle stages to monitor them. Note that tracking all lifecycles may cause a performance hit depending on your workload."
              :type [:keyword]
              :default #{:lifecycle/read-batch :lifecycle/write-batch
-                        :lifecycle/apply-fn :lifecycle/unblock-subscribers}
+                        :lifecycle/apply-fn :lifecycle/unblock-subscribers
+                        :lifecycle/assign-windows}
              :choices [:lifecycle/poll-recover :lifecycle/offer-barriers :lifecycle/offer-barrier-status :lifecycle/recover-input :lifecycle/recover-state :lifecycle/recover-output :lifecycle/unblock-subscribers :lifecycle/next-iteration :lifecycle/input-poll-barriers :lifecycle/check-publisher-heartbeats :lifecycle/seal-barriers? :lifecycle/seal-barriers? :lifecycle/checkpoint-input :lifecycle/checkpoint-state :lifecycle/checkpoint-output :lifecycle/offer-barriers :lifecycle/offer-barrier-status :lifecycle/unblock-subscribers :lifecycle/before-batch :lifecycle/read-batch :lifecycle/check-publisher-heartbeats :lifecycle/after-read-batch :lifecycle/apply-fn :lifecycle/after-apply-fn :lifecycle/assign-windows :lifecycle/prepare-batch :lifecycle/write-batch :lifecycle/after-batch :lifecycle/offer-heartbeats]

              :optional? true


Obtain entry from catalog.

Obtain entry from catalog.

--- src/onyx/peer/task_pipeline.clj
+++ src/onyx/peer/task_pipeline.clj
@@ -45,8 +45,9 @@
   (let [decompressed-msgs (map decompress-message batch)]
     (assoc event :decompressed decompressed-msgs)))

-(defn munge-apply-fn [{:keys [decompressed task] :as event}]
-  (let [results (map (partial apply-fn task) decompressed)]
+(defn munge-apply-fn [{:keys [decompressed task catalog] :as event}]
+  (let [task (first (filter (fn [entry] (= (:onyx/name entry) task)) catalog))
+        results (map (partial apply-fn task) decompressed)]
     (assoc event :results results)))

 (defn munge-compress-tx [{:keys [results] :as event}]
@@ -165,6 +166,8 @@
                          :task (:task/name (:task payload))
                          :status-node (:status (:nodes payload))
                          :completion-node (:completion (:nodes payload))
+                         :catalog (extensions/read-place sync (:catalog (:nodes payload)))
+                         :workflow (extensions/read-place sync (:workflow (:nodes payload)))
                          :queue queue
                          :sync sync
                          :batch-size 1000


Fix component-path on React 16

Fix component-path on React 16

--- src/reagent/impl/component.cljs
+++ src/reagent/impl/component.cljs
@@ -271,21 +271,34 @@
        cljsify
        create-react-class))

-(defn component-path [c]
-  ;; Looks like in React 16, reactInternalFiber is the elem
-  (let [elem (or (some-> c ($ :_reactInternalFiber))
-                 (some-> (or (some-> c ($ :_reactInternalInstance))
-                             c)
-                         ($ :_currentElement)))
-        name (some-> elem
+(defn fiber-component-path [fiber]
+  (let [name (some-> fiber
                      ($ :type)
                      ($ :displayName))
-        path (some-> elem
-                     ($ :_owner)
-                     component-path
+        parent (some-> fiber
+                       ($ :return))
+        path (some-> parent
+                     fiber-component-path
                      (str " > "))
         res (str path name)]
     (when-not (empty? res) res)))
+
+(defn component-path [c]
+  ;; Alternative branch for React 16
+  (if-let [fiber (some-> c ($ :_reactInternalFiber))]
+    (fiber-component-path fiber)
+    (let [elem (or (some-> (or (some-> c ($ :_reactInternalInstance))
+                               c)
+                           ($ :_currentElement)))
+          name (some-> elem
+                       ($ :type)
+                       ($ :displayName))
+          path (some-> elem
+                       ($ :_owner)
+                       component-path
+                       (str " > "))
+          res (str path name)]
+      (when-not (empty? res) res))))

 (defn comp-name []
   (if (dev?)


Updated charts and added CLJS recipes

Updated charts and added CLJS recipes

--- proto-repl-client-cljs/project.clj
+++ proto-repl-client-cljs/project.clj
@@ -4,14 +4,20 @@
                  [org.clojure/clojurescript "1.7.228"]
                  [fipp "0.6.4"]
                  [replumb "0.1.5-3"]
-                 [proto-repl-charts "0.2.1"]]
+                 [proto-repl-charts "0.3.2"]]
   :plugins [[lein-cljsbuild "1.1.2"]]
   :cljsbuild {:builds [{:source-paths ["src-cljs" "src"]
-                        :compiler {:output-to "../lib/proto_repl/main.js"
-                                   :output-dir "../lib/proto_repl"
-                                   :optimizations :none
-                                   :target :nodejs
-                                   :pretty-print true}}]}
+                        :compiler {:output-to "../lib/proto_repl/edn_reader.js"
+                                   :main proto-repl.edn-reader
+                                   :optimizations :simple
+                                   :output-wrapper true
+                                   :target :nodejs}}
+                       {:source-paths ["src-cljs" "src"]
+                        :compiler {:output-to "../lib/proto_repl/self_hosted.js"
+                                   :main proto-repl.self-hosted
+                                   :optimizations :simple
+                                   :output-wrapper true
+                                   :target :nodejs}}]}

   :profiles
   {:dev {:dependencies [[org.clojure/tools.namespace "0.2.11"]


Better more functional implementation without atom.

--- clojure-functional/src/test/clojure/no/knowit/clojure_functional/product_repository.clj
+++ clojure-functional/src/test/clojure/no/knowit/clojure_functional/product_repository.clj
@@ -3,37 +3,31 @@
   (:import [no.knowit.java_functional.product Product])
   (:import [org.joda.time LocalDate]))

-(def product-list (atom []))
-
-(defn product-is-available [local-date]
+(defn product-is-available [local-date product-coll]
   (filter
-    #(.isAvailable %1 local-date) @product-list))
-
-
-(defn clear-state-fn [test-func]
-  (reset! product-list [])
-  (test-func))
-
-(use-fixtures :each clear-state-fn)
+    #(.isAvailable %1 local-date) product-coll))

 (deftest empty_list_when_no_products
-  (is (= (product-is-available (LocalDate.)) [])))
+  (is (= (product-is-available (LocalDate.) []))))

 (deftest product_available_when_matching_date
   (let [today (new LocalDate)
         product (new Product "Cool product" today today)]
-    (swap! product-list
-      #(conj % product))
-    (is (not-empty (product-is-available today)))
-    (is (.contains (product-is-available today) product))))
+    (is (not-empty (product-is-available today [product])))
+    (is (.contains (product-is-available today [product]) product))))

 (deftest empty_list_when_no_products_matching_date
   (let [today (new LocalDate)
         yesterday (.minusDays today 1)
         product (new Product "Cool product" yesterday yesterday)]
-    (swap! product-list
-      #(conj % product))
-    (is (empty (product-is-available today)))))
+    (is (empty (product-is-available today [product])))))
+
+(deftest find_discontinued_products
+  (let [yesterday (.minusDays (new LocalDate) 1)
+        product (new Product "Cool product" yesterday yesterday)]
+    (is (not-empty (product-is-available yesterday [product])))))
+
+

 (run-tests)


change test case to pass valid argument type to 'maybe' function

--- test/cats/monad/maybe_spec.cljc
+++ test/cats/monad/maybe_spec.cljc
@@ -159,7 +159,8 @@
         j (maybe/just 42)]
     (t/is (= 42 (maybe/maybe 42 n inc)))
     (t/is (= 43 (maybe/maybe 42 j inc)))
-    (t/is (= 42 (maybe/maybe 42 n (throw (ex-info "shouldn't run" {})))))
+    (t/is (= 42 (maybe/maybe 42 n (do (throw (ex-info "shouldn't run" {}))
+                                      inc))))
     (t/is (thrown?
             #?(:clj  java.lang.AssertionError
                :cljs js/Error)


basic workflow support

basic workflow support

--- test/celestial/features/gce.clj
+++ test/celestial/features/gce.clj
@@ -2,13 +2,27 @@
   (:require
     [celestial.model :refer (vconstruct)]
     [celestial.fixtures.core :refer (with-conf) :as f]
+    [celestial.fixtures.data :refer (redis-type local-conf redis-gce)]
+    [celestial.fixtures.populate :refer (populate-system)]
+    [celestial.integration.workflows.common :refer (spec)]
+    [celestial.workflows :as wf]
     [celestial.fixtures.data :refer [redis-gce]])
   (:use midje.sweet)
  )

 (with-conf
   (let [{:keys [machine gce]} redis-gce]
-    (fact "legal gce system"
+    (fact "legal gce system" :gce
       (:spec (vconstruct redis-gce)) =>
          (contains {:machineType  "zones/europe-west1-d/machineTypes/n1-standard-1"}))))

+#_(with-admin
+  (with-conf local-conf
+    (with-state-changes [(before :facts (populate-system redis-type redis-freenas))]
+      (fact "freenas creation workflows" :integration :gce :workflow
+          (wf/create (spec)) => nil
+          (wf/create (spec)) => (throws ExceptionInfo  (is-type? :celestial.workflows/machine-exists))
+          (wf/stop (spec)) => nil
+          (wf/create (spec)) => (throws ExceptionInfo  (is-type? :celestial.workflows/machine-exists))
+          (wf/destroy (spec)) => nil
+      ))))


add sell for loss test

add sell for loss test

--- test/clj_money/trading_test.clj
+++ test/clj_money/trading_test.clj
@@ -6,11 +6,11 @@
             [clj-money.factories.user-factory]
             [clj-money.serialization :as serialization]
             [clj-money.test-helpers :refer [reset-db
-                                            find-entity
                                             find-account
                                             find-accounts
                                             find-commodity
-                                            pprint-diff]]
+                                            pprint-diff
+                                            selective=]]
             [clj-money.validation :as validation]
             [clj-money.models.entities :as entities]
             [clj-money.models.accounts :as accounts]
@@ -19,9 +19,7 @@
             [clj-money.models.transactions :as transactions]
             [clj-money.trading :as trading]))

-(def storage-spec (env :db))
-
-(use-fixtures :each (partial reset-db storage-spec))
+(use-fixtures :each (partial reset-db (env :db)))

 (defn items-by-account
   [account-id]
@@ -36,7 +34,7 @@
                 :updated-at
                 :reconciliation-status)
        (transactions/items-by-account
-         storage-spec
+         (env :db)
          account-id
          [(t/local-date 2015 1 1)
           (t/local-date 2017 12 31)])))
@@ -85,13 +83,13 @@
    :value 1000M})

 (deftest purchase-a-commodity
-  (let [context (serialization/realize storage-spec purchase-context)
-        ira (find-account context "IRA")
-        commodity (find-commodity context "AAPL")
-        result (trading/buy storage-spec (purchase-attributes context))
+  (let [context (serialization/realize (env :db) purchase-context)
+        ira (find-account context "IRA")
+        commodity (find-commodity context "AAPL")
+        result (trading/buy (env :db) (purchase-attributes context))
         apple-account (->> {:commodity-id (:id commodity)
                             :entity-id (-> context :entities first :id)}
-                           (accounts/search storage-spec)
+                           (accounts/search (env :db))
                            first)
         expected-transaction {:entity-id (-> context :entities first :id)
                               :transaction-date (t/local-date 2016 1 2)
@@ -179,14 +177,12 @@
     (is (= expected-commodity-account
            actual-commodity-account)
         "The commodity account is created")
-    (is ((->> ira (accounts/reload storage-spec) :tags) :trading)
+    (is ((->> ira (accounts/reload (env :db)) :tags) :trading)
         "The specified account is tagged as a trading account")))

 (deftest purchase-a-commodity-with-string-values
- (let [context (serialization/realize storage-spec purchase-context)
-        ira (find-account context "IRA")
-        commodity (find-commodity context "AAPL")
-        result (trading/buy storage-spec (-> context
+ (let [context (serialization/realize (env :db) purchase-context)
+        result (trading/buy (env :db) (-> context
                                              purchase-attributes
                                              (update-in [:account-id] str)
                                              (update-in [:commodity-id] str)
@@ -197,7 +193,7 @@
         "The transaction is valid")))

 (deftest purchase-a-commodity-with-a-fee
-  (let [context (serialization/realize storage-spec purchase-context)
+  (let [context (serialization/realize (env :db) purchase-context)
         ira (->> context
                  :accounts
                  (filter #(= "IRA" (:name %)))
@@ -205,22 +201,19 @@
         inv-exp (->> context
                      :accounts
                      (filter #(= "Investment Expenses" (:name %)))
-                     first)
-        commodity (find-commodity context "AAPL")
-        result (trading/buy storage-spec (-> context
-                                             purchase-attributes
-                                             (assoc :fee 5M
-                                                    :fee-account-id (:id inv-exp))))]
-    (is (= 995M (:quantity (accounts/reload storage-spec ira)))
+                     first)]
+    (trading/buy (env :db) (-> context
+                                  purchase-attributes
+                                  (assoc :fee 5M
+                                         :fee-account-id (:id inv-exp))))
+    (is (= 995M (:quantity (accounts/reload (env :db) ira)))
         "The investment account balance reflects the fee")
-    (is (= 5M (:quantity (accounts/reload storage-spec inv-exp)))
+    (is (= 5M (:quantity (accounts/reload (env :db) inv-exp)))
         "The investment expense account reflects the fee")))

 (deftest purchase-requires-a-trade-date
-  (let [context (serialization/realize storage-spec purchase-context)
-        ira (find-account context "IRA")
-        commodity (find-commodity context "AAPL")
-        result (trading/buy storage-spec (-> context
+  (let [context (serialization/realize (env :db) purchase-context)
+        result (trading/buy (env :db) (-> context
                                              (purchase-attributes)
                                              (dissoc :trade-date)))]
     (is (= ["Trade date is required"]
@@ -228,20 +221,16 @@
         "The validation message indicates the error")))

 (deftest purchase-trade-date-can-be-a-date-string
-  (let [context (serialization/realize storage-spec purchase-context)
-        ira (find-account context "IRA")
-        commodity (find-commodity context "AAPL")
-        result (trading/buy storage-spec (-> context
+  (let [context (serialization/realize (env :db) purchase-context)
+        result (trading/buy (env :db) (-> context
                                              (purchase-attributes)
                                              (assoc :trade-date "3/2/2016")))]
     (is (empty? (validation/error-messages result))
         "The transaction is valid")))

 (deftest purchase-requires-a-number-of-shares
-  (let [context (serialization/realize storage-spec purchase-context)
-        ira (find-account context "IRA")
-        commodity (find-commodity context "AAPL")
-        result (trading/buy storage-spec (-> context
+  (let [context (serialization/realize (env :db) purchase-context)
+        result (trading/buy (env :db) (-> context
                                              (purchase-attributes)
                                              (dissoc :shares)))]
     (is (= ["Shares is required"]
@@ -249,10 +238,8 @@
         "The validation message indicates the error")))

 (deftest purchase-requires-a-value
-  (let [context (serialization/realize storage-spec purchase-context)
-        ira (find-account context "IRA")
-        commodity (find-commodity context "AAPL")
-        result (trading/buy storage-spec (-> context
+  (let [context (serialization/realize (env :db) purchase-context)
+        result (trading/buy (env :db) (-> context
                                              (purchase-attributes)
                                              (dissoc :value)))]
     (is (= ["Value is required"]
@@ -260,10 +247,10 @@
         "The validation message indicates the error")))

 (deftest a-purchase-creates-a-lot-record
-  (let [context (serialization/realize storage-spec purchase-context)
-        ira (find-account context "IRA")
-        commodity (find-commodity context "AAPL")
-        result (trading/buy storage-spec {:commodity-id (:id commodity)
+  (let [context (serialization/realize (env :db) purchase-context)
+        ira (find-account context "IRA")
+        commodity (find-commodity context "AAPL")
+        _ (trading/buy (env :db) {:commodity-id (:id commodity)
                                      :account-id (:id ira)
                                      :trade-date (t/local-date 2016 1 2)
                                      :shares 100M
@@ -278,14 +265,14 @@
                                      :account-id
                                      :shares-purchased
                                      :shares-owned])
-                    (lots/select-by-commodity-id storage-spec (:id commodity)))]
+                    (lots/select-by-commodity-id (env :db) (:id commodity)))]
     (is (= expected actual) "The lot can be retrieved from the database")))

 (deftest a-purchase-creates-a-price-record
-  (let [context (serialization/realize storage-spec purchase-context)
-        ira (find-account context "IRA")
-        commodity (find-commodity context "AAPL")
-        _ (trading/buy storage-spec {:commodity-id (:id commodity)
+  (let [context (serialization/realize (env :db) purchase-context)
+        ira (find-account context "IRA")
+        commodity (find-commodity context "AAPL")
+        _ (trading/buy (env :db) {:commodity-id (:id commodity)
                                      :account-id (:id ira)
                                      :trade-date (t/local-date 2016 1 2)
                                      :shares 100M
@@ -294,20 +281,20 @@
                    :trade-date (t/local-date 2016 1 2)
                    :price 10M}]
         actual (map #(select-keys % [:commodity-id :trade-date :price])
-                    (prices/search storage-spec {:commodity-id (:id commodity)
+                    (prices/search (env :db) {:commodity-id (:id commodity)
                                                  :trade-date (t/local-date 2016 1 2)}))]
     (is (= expected actual) "The price can be retrieved from the database")))

 (deftest buying-a-commodity-reduces-the-balance-of-the-account
-  (let [context (serialization/realize storage-spec purchase-context)
-        ira (find-account context "IRA")
-        commodity (find-commodity context "AAPL")
-        _ (trading/buy storage-spec {:commodity-id (:id commodity)
+  (let [context (serialization/realize (env :db) purchase-context)
+        ira (find-account context "IRA")
+        commodity (find-commodity context "AAPL")
+        _ (trading/buy (env :db) {:commodity-id (:id commodity)
                                      :account-id (:id ira)
                                      :trade-date (t/local-date 2016 1 2)
                                      :shares 100M
                                      :value 999M})
-        new-balance (:quantity (accounts/reload storage-spec ira))]
+        new-balance (:quantity (accounts/reload (env :db) ira))]
     (is (= 1001M new-balance) "The account balance decreases by the amount of the purchase")))

 (defn- sale-attributes
@@ -333,38 +320,83 @@
      :shares 25M
      :value 375M})) ; Sell at $15/share or $125 gain

-(defn- sell-context
-  ([]
-   (sell-context purchase-context))
-  ([base-context]
-   (let [context (serialization/realize storage-spec base-context)
-         ira (find-account context "IRA")
-         commodity (find-commodity context "AAPL")
-         result  (trading/buy storage-spec {:account-id (:id ira)
-                                            :commodity-id (:id commodity)
-                                            :trade-date (t/local-date 2016 3 2)
-                                            :shares 100M
-                                            :value 1000M})]
-     (-> context
-         (assoc :lots [(:lot result)])
-         (update-in [:transactions] #(conj % (:transaction result)))))))
-
-(deftest sell-a-commodity
-  (let [context (serialization/realize storage-spec purchase-context)
-        ira (find-account context "IRA")
-        ltcg (find-account context "Long-term Capital Gains")
-        commodity (find-commodity context "AAPL")
-        purchase (trading/buy storage-spec {:account-id (:id ira)
-                                            :commodity-id (:id commodity)
-                                            :trade-date (t/local-date 2016 3 2)
-                                            :shares 100M
-                                            :value 1000M})
+(defn sale-exp-trans
+  [context]
+  (let [ltcg (find-account context "Long-term Capital Gains")
+        ira (find-account context "IRA")
+        commodity (find-commodity context "AAPL")
         commodity-account (->> {:entity-id (-> context :entities first :id)
                                 :commodity-id (:id commodity)}
-                               (accounts/search storage-spec)
+                               (accounts/search (env :db))
                                first)
-        lot (:lot purchase)
-        result (trading/sell storage-spec (sale-attributes context))
+        lot (lots/find-by (env :db) {:commodity-id (:id commodity)
+                                     :account-id (:id ira)
+                                     :purchase-date (t/local-date 2016 3 2)})]
+    {:transaction-date (t/local-date 2017 3 2)
+     :description "Sell 25 shares of AAPL at 15.000"
+     :entity-id (-> context :entities first :id)
+     :memo nil
+     :value 375M
+     :items [{:action :debit
+              :account-id (:id ira)
+              :transaction-date (t/local-date 2017 3 2)
+              :description "Sell 25 shares of AAPL at 15.000"
+              :quantity 375M
+              :negative false
+              :polarized-quantity 375M
+              :value 375M
+              :balance 1375M
+              :reconciliation-status nil
+              :reconciled? false
+              :reconciliation-id nil
+              :memo nil
+              :index 2}
+             {:action :credit
+              :account-id (:id ltcg)
+              :memo "Sell 25 shares of AAPL at 15.000"
+              :transaction-date (t/local-date 2017 3 2)
+              :description "Sell 25 shares of AAPL at 15.000"
+              :quantity 125M
+              :negative false
+              :polarized-quantity 125M
+              :value 125M
+              :balance 125M
+              :reconciliation-status nil
+              :reconciled? false
+              :reconciliation-id nil
+              :index 0}
+             {:action :credit
+              :account-id (:id commodity-account)
+              :transaction-date (t/local-date 2017 3 2)
+              :description "Sell 25 shares of AAPL at 15.000"
+              :quantity 25M
+              :negative false
+              :polarized-quantity 25M
+              :balance 75M
+              :value 250M
+              :reconciliation-status nil
+              :reconciled? false
+              :reconciliation-id nil
+              :memo nil
+              :index 1}]
+     :lot-items [{:lot-id (:id lot)
+                  :lot-action :sell
+                  :shares 25M
+                  :price 15M}]}))
+
+(def ^:private sale-context
+  (assoc purchase-context
+         :trades [{:type :purchase
+                   :account-id "IRA"
+                   :commodity-id "AAPL"
+                   :trade-date (t/local-date 2016 3 2)
+                   :shares 100M
+                   :value 1000M}]))
+
+(deftest sell-a-commodity-for-a-gain
+  (let [context (serialization/realize (env :db) sale-context)
+        commodity (find-commodity context "AAPL")
+        result (trading/sell (env :db) (sale-attributes context))
         actual-transaction (-> result
                                :transaction
                                (update-in [:items] #(map (fn [i]
@@ -375,68 +407,21 @@
                                                                    :updated-at))
                                                          %))
                                (dissoc :id :created-at :updated-at))
-        expected-transaction {:transaction-date (t/local-date 2017 3 2)
-                              :description "Sell 25 shares of AAPL at 15.000"
-                              :entity-id (-> context :entities first :id)
-                              :memo nil
-                              :value 375M
-                              :items [{:action :debit
-                                       :account-id (:id ira)
-                                       :transaction-date (t/local-date 2017 3 2)
-                                       :description "Sell 25 shares of AAPL at 15.000"
-                                       :quantity 375M
-                                       :negative false
-                                       :polarized-quantity 375M
-                                       :value 375M
-                                       :balance 1375M
-                                       :reconciliation-status nil
-                                       :reconciled? false
-                                       :reconciliation-id nil
-                                       :memo nil
-                                       :index 2}
-                                      {:action :credit
-                                       :account-id (:id ltcg)
-                                       :memo "Sell 25 shares of AAPL at 15.000"
-                                       :transaction-date (t/local-date 2017 3 2)
-                                       :description "Sell 25 shares of AAPL at 15.000"
-                                       :quantity 125M
-                                       :negative false
-                                       :polarized-quantity 125M
-                                       :value 125M
-                                       :balance 125M
-                                       :reconciliation-status nil
-                                       :reconciled? false
-                                       :reconciliation-id nil
-                                       :index 0}
-                                      {:action :credit
-                                       :account-id (:id commodity-account)
-                                       :transaction-date (t/local-date 2017 3 2)
-                                       :description "Sell 25 shares of AAPL at 15.000"
-                                       :quantity 25M
-                                       :negative false
-                                       :polarized-quantity 25M
-                                       :balance 75M
-                                       :value 250M
-                                       :reconciliation-status nil
-                                       :reconciled? false
-                                       :reconciliation-id nil
-                                       :memo nil
-                                       :index 1}]
-                              :lot-items [{:lot-id (:id lot)
-                                           :lot-action :sell
-                                           :shares 25M
-                                           :price 15M}]}]
+        ira (find-account context "IRA")
+        lot (lots/find-by (env :db) {:commodity-id (:id commodity)
+                                     :account-id (:id ira)
+                                     :purchase-date (t/local-date 2016 3 2)})
+        expected-transaction (sale-exp-trans context)]
     (is (:price result)
         "The result contains a price")
     (is (empty? (-> result :price validation/error-messages))
         "The price is valid")
     (is (:lots result)
         "The result contains the lots affected")
-    (if (seq (:lots result))
-      (doseq [lot (:lots result)]
-        (is (empty? (validation/error-messages lot))
-            "Each lot is valid")))
-    (is (= 75M (:shares-owned (lots/find-by-id storage-spec (-> purchase :lot :id))))
+    (doseq [lot (:lots result)]
+      (is (empty? (validation/error-messages lot))
+          "Each lot is valid"))
+    (is (= 75M (:shares-owned lot))
         "The shares-owned value of the original lot is updated")
     (is (:transaction result)
         "The result contains the transaction record")
@@ -451,7 +436,7 @@
                                           :lt-capital-loss-account-id
                                           :st-capital-loss-account-id
                                           :inventory-method])
-            actual (-> (entities/find-by-id storage-spec (:entity-id commodity))
+            actual (-> (entities/find-by-id (env :db) (:entity-id commodity))
                        :settings
                        (select-keys [:lt-capital-gains-account-id
                                      :st-capital-gains-account-id
@@ -462,26 +447,58 @@
         (is (= expected actual)
             "The entity settings are updated with default account ids")))))

+(deftest sell-a-commodity-for-a-loss
+  (let [context (serialization/realize (env :db) sale-context)
+        commodity (find-commodity context "AAPL")
+        attr (assoc (sale-attributes context) :value 200M) ; 25 shares, $50 loss
+        {:keys [lots transaction price]} (trading/sell (env :db) attr)
+        ira (find-account context "IRA")
+        lot (lots/find-by (env :db) {:commodity-id (:id commodity)
+                                     :account-id (:id ira)
+                                     :purchase-date (t/local-date 2016 3 2)})]
+    (is (= 8M (:price price))
+        "The result contains the correct price")
+    (is (empty? (validation/error-messages price))
+        "The price is valid")
+    (is lots "The result contains the lots affected")
+    (doseq [lot lots]
+      (is (empty? (validation/error-messages lot))
+          "Each lot is valid"))
+    (is (= 75M (:shares-owned lot))
+        "The shares-owned value of the original lot is updated")
+    (is transaction "The result contains the transaction record")
+    (is (empty? (validation/error-messages transaction))
+        "The transaction is valid")
+    (if-let [item (->> (:items transaction)
+                (filter #(= (:lt-capital-loss-account-id attr)
+                           (:account-id %)))
+                first)]
+      (is (selective= {:action :debit
+                       :quantity 50M}
+                      item)
+          "The correct capital loss is recored")
+      (is false "A capital loss item is created"))))
+
 (deftest sell-a-commodity-with-a-fee
-  (let [context (sell-context)
+  (let [context (serialization/realize (env :db) sale-context)
         ira (find-account context "IRA")
         inv-exp (->> context
                      :accounts
                      (filter #(= "Investment Expenses" (:name %)))
-                     first)
-        result (trading/sell storage-spec
-                             (-> context
-                                 sale-attributes
-                                 (assoc :fee 5M
-                                        :fee-account-id (:id inv-exp))))]
-    (is (= 1370M (:quantity (accounts/reload storage-spec ira)))
+                     first)]
+    (trading/sell (env :db)
+                  (-> context
+                      sale-attributes
+                      (assoc :fee 5M
+                             :fee-account-id (:id inv-exp))))
+    (is (= 1370M (:quantity (accounts/reload (env :db) ira)))
         "The investment account balance reflects the fee")
-    (is (= 5M (:quantity (accounts/reload storage-spec inv-exp)))
+    (is (= 5M (:quantity (accounts/reload (env :db) inv-exp)))
         "The investment fee account balance reflects the fee")))

 (deftest sales-requires-a-trade-date
-  (let [context (sell-context)
-        result (trading/sell storage-spec (-> context
+  (let [context (serialization/realize (env :db) sale-context)
+        result (trading/sell (env :db) (-> context
                                               sale-attributes
                                               (dissoc :trade-date)))]
     (is (= ["Trade date is required"]
@@ -489,16 +506,16 @@
         "The correct validation error is present")))

 (deftest sale-trade-date-can-be-a-date-string
-  (let [context (sell-context)
-        result (trading/sell storage-spec (-> context
+  (let [context (serialization/realize (env :db) sale-context)
+        result (trading/sell (env :db) (-> context
                                               sale-attributes
                                               (assoc :trade-date "3/2/2017")))]
     (is (empty?  (validation/error-messages result))
         "The transaction is value")))

 (deftest sales-requires-a-number-of-shares
-  (let [context (sell-context)
-        result (trading/sell storage-spec (-> context
+  (let [context (serialization/realize (env :db) sale-context)
+        result (trading/sell (env :db) (-> context
                                               sale-attributes
                                               (dissoc :shares)))]
     (is (= ["Shares is required"]
@@ -506,8 +523,8 @@
         "The correct validation error is present")))

 (deftest sales-requires-a-value
-  (let [context (sell-context)
-        result (trading/sell storage-spec (-> context
+  (let [context (serialization/realize (env :db) sale-context)
+        result (trading/sell (env :db) (-> context
                                               sale-attributes
                                               (dissoc :value)))]
     (is (= ["Value is required"]
@@ -515,29 +532,29 @@
         "The correct validation error is present")))

 (deftest selling-a-commodity-for-a-profit-increases-the-balance-of-the-account
-  (let [context (serialization/realize storage-spec purchase-context)
+  (let [context (serialization/realize (env :db) purchase-context)
         [ira] (:accounts context)
         commodity (find-commodity context "AAPL")
-        _ (trading/buy storage-spec {:commodity-id (:id commodity)
+        _ (trading/buy (env :db) {:commodity-id (:id commodity)
                                      :account-id (:id ira)
                                      :trade-date (t/local-date 2016 1 2)
                                      :shares 100M
                                      :value 1000M})
-        result (trading/sell storage-spec (-> context
+        _ (trading/sell (env :db) (-> context
                                               sale-attributes
                                               (assoc :shares 50M :value 560M)))
-        new-balance (:quantity (accounts/reload storage-spec ira))]
+        new-balance (:quantity (accounts/reload (env :db) ira))]
     (is (= 1560M new-balance) "The account balance decreases by the amount of the purchase")))

 (deftest selling-a-commodity-updates-a-lot-record
-  (let [context (sell-context)
-        ira (find-account context "IRA")
-        commodity (find-commodity context "AAPL")
-        _ (trading/sell storage-spec (-> context
+  (let [context (serialization/realize (env :db) sale-context)
+        ira (find-account context "IRA")
+        commodity (find-commodity context "AAPL")
+        _ (trading/sell (env :db) (-> context
                                          sale-attributes
                                          (assoc :shares 25M :value 375M)))
         lots (map #(dissoc % :id :created-at :updated-at)
-                  (lots/search storage-spec {:account-id (:id ira)
+                  (lots/search (env :db) {:account-id (:id ira)
                                              :commodity-id (:id commodity)}))
         expected [{:purchase-date (t/local-date 2016 3 2)
                    :account-id (:id ira)
@@ -548,11 +565,9 @@
     (is (= expected lots) "The lot is updated to reflect the sale")))

 (deftest selling-a-commodity-for-a-profit-after-1-year-credits-long-term-capital-gains
-  (let [context (sell-context)
-        ira (find-account context "IRA")
+  (let [context (serialization/realize (env :db) sale-context)
         lt-capital-gains (find-account context "Long-term Capital Gains")
-        commodity (find-commodity context "AAPL")
-        _ (trading/sell storage-spec (-> context
+        _ (trading/sell (env :db) (-> context
                                          sale-attributes
                                          (assoc :shares 25M :value 375M)))
         gains-items (items-by-account (:id lt-capital-gains))
@@ -571,11 +586,9 @@
     (is (= expected gains-items) "The capital gains account is credited the correct amount")))

 (deftest selling-a-commodity-for-a-profit-before-1-year-credits-short-term-capital-gains
-  (let [context (sell-context)
-        ira (find-account context "IRA")
+  (let [context (serialization/realize (env :db) sale-context)
         st-capital-gains (find-account context "Short-term Capital Gains")
-        commodity (find-commodity context "AAPL")
-        _ (trading/sell storage-spec (-> context
+        _ (trading/sell (env :db) (-> context
                                          sale-attributes
                                          (assoc :shares 25M
                                                 :value 375M
@@ -596,11 +609,9 @@
     (is (= expected gains-items) "The capital gains account is credited the correct amount")))

 (deftest selling-a-commodity-for-a-loss-debits-capital-loss
-  (let [context (sell-context)
-        ira (find-account context "IRA")
+  (let [context (serialization/realize (env :db) sale-context)
         capital-loss (find-account context "Long-term Capital Loss")
-        commodity (find-commodity context "AAPL")
-        _ (trading/sell storage-spec (-> context
+        _ (trading/sell (env :db) (-> context
                                          sale-attributes
                                          (assoc :shares 100M :value 850M)))
         gains-items (items-by-account (:id capital-loss))
@@ -630,7 +641,7 @@
        account-names))

 (deftest lifo-sale
-  (let [context (serialization/realize storage-spec purchase-context)
+  (let [context (serialization/realize (env :db) purchase-context)
         commodity (find-commodity context "AAPL")
         [ira
          lt-gains
@@ -642,17 +653,17 @@
                                 "Short-term Capital Gains"
                                 "Long-term Capital Loss"
                                 "Short-term Capital Loss")
-        _ (trading/buy storage-spec {:trade-date (t/local-date 2015 3 2)
+        _ (trading/buy (env :db) {:trade-date (t/local-date 2015 3 2)
                                           :account-id (:id ira)
                                           :commodity-id (:id commodity)
                                           :shares 100M
                                           :value 1000M})
-        _ (trading/buy storage-spec {:trade-date (t/local-date 2016 3 2)
+        _ (trading/buy (env :db) {:trade-date (t/local-date 2016 3 2)
                                           :account-id (:id ira)
                                           :commodity-id (:id commodity)
                                           :shares 100M
                                           :value 2000M})
-        sale (trading/sell storage-spec {:trade-date (t/local-date 2017 3 2)
+        _ (trading/sell (env :db) {:trade-date (t/local-date 2017 3 2)
                                       :account-id (:id ira)
                                       :commodity-id (:id commodity)
                                       :shares 50M
@@ -664,7 +675,7 @@
                                       :st-capital-loss-account-id (:id st-loss)})
         actual (->> {:commodity-id (:id commodity)
                      :account-id (:id ira)}
-                    (lots/search storage-spec)
+                    (lots/search (env :db))
                     (sort-by :purchase-date)
                     (map #(dissoc %
                                   :id
@@ -684,7 +695,7 @@

 (deftest fifo-sale
   (let [context (serialization/realize
-                  storage-spec
+                  (env :db)
                   (update-in purchase-context
                              [:entities 0]
                              #(assoc-in % [:settings :inventory-method] :fifo)))
@@ -699,17 +710,17 @@
                                 "Short-term Capital Gains"
                                 "Long-term Capital Gains"
                                 "Short-term Capital Gains")
-        _ (trading/buy storage-spec {:trade-date (t/local-date 2015 3 2)
+        _ (trading/buy (env :db) {:trade-date (t/local-date 2015 3 2)
                                           :account-id (:id ira)
                                           :commodity-id (:id commodity)
                                           :shares 100M
                                           :value 1000M})
-        _ (trading/buy storage-spec {:trade-date (t/local-date 2016 3 2)
+        _ (trading/buy (env :db) {:trade-date (t/local-date 2016 3 2)
                                           :account-id (:id ira)
                                           :commodity-id (:id commodity)
                                           :shares 100M
                                           :value 2000M})
-        sale (trading/sell storage-spec {:trade-date (t/local-date 2017 3 2)
+        _ (trading/sell (env :db) {:trade-date (t/local-date 2017 3 2)
                                       :account-id (:id ira)
                                       :commodity-id (:id commodity)
                                       :shares 50M
@@ -720,7 +731,7 @@
                                       :st-capital-loss-account-id (:id st-loss)})
         actual (->> {:commodity-id (:id commodity)
                      :account-id (:id ira)}
-                    (lots/search storage-spec)
+                    (lots/search (env :db))
                     (sort-by :purchase-date)
                     (map #(dissoc %
                                   :id
@@ -739,70 +750,68 @@
     (is (= expected actual) "Shares are sold from the most recent lot")))

 (deftest undo-a-purchase
-  (let [context (serialization/realize storage-spec purchase-context)
-        ira (find-account context "IRA")
-        commodity (find-commodity context "AAPL")
-        purchase (trading/buy storage-spec {:trade-date (t/local-date 2017 3 2)
+  (let [context (serialization/realize (env :db) purchase-context)
+        ira (find-account context "IRA")
+        commodity (find-commodity context "AAPL")
+        purchase (trading/buy (env :db) {:trade-date (t/local-date 2017 3 2)
+                                            :shares 100M
+                                            :commodity-id (:id commodity)
+                                            :account-id (:id ira)
+                                            :value 1000M})]
+    (trading/unbuy (env :db) (:transaction purchase))
+    ; TODO Should we delete the price that was created?
+    (testing "the account balance"
+      (is (= 2000M (:quantity (accounts/reload (env :db) ira)))
+          "The account balance is restored"))
+    (testing "the affected lots"
+      (is (= [] (lots/search (env :db) {:account-id (:id ira)}))
+          "The lot is deleted"))))
+
+(deftest cannot-undo-a-purchase-if-shares-have-been-sold
+  (let [context (serialization/realize (env :db) purchase-context)
+        ira (find-account context "IRA")
+        commodity (find-commodity context "AAPL")
+        purchase (trading/buy (env :db) {:trade-date (t/local-date 2017 3 2)
                                             :shares 100M
                                             :commodity-id (:id commodity)
                                             :account-id (:id ira)
                                             :value 1000M})
-        result (trading/unbuy storage-spec (:transaction purchase))]
-    ; TODO Should we delete the price that was created?
-    (testing "the account balance"
-      (is (= 2000M (:quantity (accounts/reload storage-spec ira)))
-          "The account balance is restored"))
-    (testing "the affected lots"
-      (is (= [] (lots/search storage-spec {:account-id (:id ira)}))
-          "The lot is deleted"))))
-
-(deftest cannot-undo-a-purchase-if-shares-have-been-sold
-  (let [context (serialization/realize storage-spec purchase-context)
-        ira (find-account context "IRA")
-        commodity (find-commodity context "AAPL")
-        purchase (trading/buy storage-spec {:trade-date (t/local-date 2017 3 2)
+        _ (trading/sell (env :db) (sale-attributes context))]
+    (is (thrown-with-msg? IllegalStateException #"Cannot undo"
+                          (trading/unbuy (env :db) (:transaction purchase))))))
+
+(deftest undo-a-sale
+  (let [context (serialization/realize (env :db) purchase-context)
+        ira (find-account context "IRA")
+        commodity (find-commodity context "AAPL")
+        _ (trading/buy (env :db) {:trade-date (t/local-date 2017 3 2)
                                             :shares 100M
                                             :commodity-id (:id commodity)
                                             :account-id (:id ira)
                                             :value 1000M})
-        _ (trading/sell storage-spec (sale-attributes context))]
-    (is (thrown-with-msg? IllegalStateException #"Cannot undo"
-                          (trading/unbuy storage-spec (:transaction purchase))))))
-
-(deftest undo-a-sale
-  (let [context (serialization/realize storage-spec purchase-context)
-        ira (find-account context "IRA")
-        commodity (find-commodity context "AAPL")
-        purchase (trading/buy storage-spec {:trade-date (t/local-date 2017 3 2)
-                                            :shares 100M
-                                            :commodity-id (:id commodity)
-                                            :account-id (:id ira)
-                                            :value 1000M})
-        sale (trading/sell storage-spec (sale-attributes context))
-        result (trading/unsell storage-spec (:transaction sale))]
+        sale (trading/sell (env :db) (sale-attributes context))
+        _ (trading/unsell (env :db) (:transaction sale))]
     ; IRA balance balance before purchase: $2,000
     ;                      after purchase: $1,000
     ;                          after sale: $1,375
     ;                        after unsale: $1,000
-    (is (= 1000M (:quantity (accounts/reload storage-spec ira)))
+    (is (= 1000M (:quantity (accounts/reload (env :db) ira)))
         "The account balance is restored")
     (testing "the affected lots"
       (doseq [lot (:lots sale)]
-        (let [lot (lots/find-by-id storage-spec (:id lot))]
+        (let [lot (lots/find-by-id (env :db) (:id lot))]
           (is (= (:shares-owned lot) (:shares-purchased lot))
               "The shares-owned should be restored"))))))

-(defn- transfer-context []
-  (-> purchase-context
-      (update-in [:accounts] #(conj % {:name "IRA 2"
-                                       :type :asset}))
-      sell-context))
+(def ^:private transfer-context
+  (update-in sale-context [:accounts] conj {:name "IRA 2"
+                                            :type :asset}))

 (deftest transfer-a-commodity
-  (let [context (transfer-context)
+  (let [context (serialization/realize (env :db) transfer-context)
         [ira ira-2] (find-accounts context "IRA" "IRA 2")
         commodity (find-commodity context "AAPL")
-        result (trading/transfer storage-spec {:commodity-id (:id commodity)
+        result (trading/transfer (env :db) {:commodity-id (:id commodity)
                                                :from-account-id (:id ira)
                                                :to-account-id (:id ira-2)
                                                :shares 100
@@ -811,13 +820,12 @@
          ira-2-commodity-account] (->> [ira ira-2]
                                        (map :id)
                                        (map #(accounts/search
-                                               storage-spec
+                                               (env :db)
                                                {:parent-id %
                                                 :commodity-id (:id commodity)}))
                                        (map first))
-        entity (find-entity context "Personal")
         actual-lots (map #(dissoc % :created-at :updated-at :id)
-                         (lots/search storage-spec {:commodity-id (:id commodity)}))
+                         (lots/search (env :db) {:commodity-id (:id commodity)}))
         expected-lots [{:commodity-id (:id commodity)
                         :account-id (:id ira-2)
                         :shares-owned 100M
@@ -865,24 +873,24 @@
     ; Original account balance was 2,000, we bought 1,000 worth of
     ; shares of AAPL, then transfered those shares out of the account
     ; leaving 1,000 in cash
-    (is (= 1000M (:quantity (accounts/reload storage-spec ira)))
+    (is (= 1000M (:quantity (accounts/reload (env :db) ira)))
         "The balance in the 'from' account is updated correctly")
     ; No money was ever addedto the second account, so the balance
     ; is still 0
-    (is (= 0M (:quantity (accounts/reload storage-spec ira-2)))
+    (is (= 0M (:quantity (accounts/reload (env :db) ira-2)))
         "The balance in the 'to' account is updated correclty")))

 (deftest split-a-commodity
-  (let [context (sell-context)
-        ira (find-account context "IRA")
-        commodity (find-commodity context "AAPL")
-        commodity-account (accounts/find-by storage-spec {:commodity-id (:id commodity)
+  (let [context (serialization/realize (env :db) sale-context)
+        ira (find-account context "IRA")
+        commodity (find-commodity context "AAPL")
+        commodity-account (accounts/find-by (env :db) {:commodity-id (:id commodity)
                                                           :entity-id (:entity-id commodity)})
-        result (trading/split storage-spec {:commodity-id (:id commodity)
+        result (trading/split (env :db) {:commodity-id (:id commodity)
                                             :account-id (:id ira)
                                             :shares-gained 100M
                                             :split-date (t/local-date 2016 3 3)})
-        lots (lots/search storage-spec {:commodity-id (:id commodity)})
+        lots (lots/search (env :db) {:commodity-id (:id commodity)})
         actual-lots (map #(dissoc % :id :created-at :updated-at :commodity-id) lots)
         expected-lots [{:purchase-date (t/local-date 2016 3 2)
                         :account-id (:id ira)
@@ -924,7 +932,7 @@
     (pprint-diff expected-lots actual-lots)
     (is (= expected-lots actual-lots)
         "The lots are adjusted correctly")
-    #_(is (= 200M (:quantity (accounts/reload storage-spec ira)))
+    #_(is (= 200M (:quantity (accounts/reload (env :db) ira)))
         "The account has the correct balance after the transfer.")))

 (def ^:private rev-split-context


Removed cryptography tests from test.compojure.http.session

--- test/compojure/http/session.clj
+++ test/compojure/http/session.clj
@@ -38,15 +38,8 @@

 ;; Cookie sessions

-(def *test-key*
-     (decode-hex "7bf5cf06baceab51168eff10d3e665d6ab503504bbce196f653fddc74bce55f7"))
-
 (deftest create-cookie-session
   (is (= (create-session {:type :cookie}) {})))
-
-(deftest session-hmac-secret-key
-  (is (= (session-hmac {:type :cookie, :encryption {:hash-key *test-key*}} "foobar")
-         "R3Bi861ypOw+EooGuQuE/QWsSmcaRU6zgzUQAaDYk+o=")))

 ;; Associating session with request


postgres 9.4-1206-jdbc41

postgres 9.4-1206-jdbc41

--- radiolamp-6P3/project.clj
+++ radiolamp-6P3/project.clj
@@ -20,7 +20,7 @@
                  [clj-time "0.12.0"]

                  ;;[org.postgresql/postgresql "9.4.1211"]
-                 [postgresql "9.3-1102.jdbc41"]
+                 [postgresql "9.4-1206-jdbc41"]
                  [korma "0.4.2"]


Extract generic vary from split.

Extract generic vary from split.

--- src/african_polyphony_and_polyrhythm/talk.clj
+++ src/african_polyphony_and_polyrhythm/talk.clj
@@ -25,16 +25,21 @@
 (defmethod live/play-note :clap2 [_]
   ((sample "samples/select-click.wav")))

-(defn split [t fraction]
+(defn vary [t f]
   (fn [notes]
     (let [before? #(-> % :time (< t))
           before (->> notes (take-while before?))
-          [note & after] (->> notes (drop-while before?))
-          first-note (assoc note :duration fraction)
-          second-note (-> note
-                          (update-in [:duration] - fraction)
-                          (update-in [:time] + fraction))]
-      (concat before [first-note second-note] after))))
+          [note & after] (->> notes (drop-while before?))]
+      (concat before (f note) after))))
+
+(defn split [t fraction]
+  (letfn [ (f [note]
+             [(-> note
+                  (assoc :duration fraction))
+              (-> note
+                  (update-in [:duration] - fraction)
+                  (update-in [:time] + fraction))])]
+    (vary t f)))

 (definst horn [freq 440 vol 0.5 pan 0]
   (-> (sin-osc freq)
@@ -43,7 +48,8 @@
       (+ (* 1/8 (sin-osc 9) (sin-osc (* 4.99 freq))))
       (+ (* 1/8 (sin-osc (* 7.01 freq))))
       (clip2 0.8)
-      (* (env-gen (adsr 0.1 0.3 0.15 0.2) (line:kr 1 0 0.1) :action FREE))
+      (rlpf (line:kr freq (* 7 freq) 0.4) 1/3)
+      (* (env-gen (adsr 0.2 0.4 0.15 0.2) (line:kr 1 0 0.1) :action FREE))
       (pan2 pan)
       (* vol)))

@@ -115,7 +121,7 @@
        (reduce with)
        (map pan)))

-(def inverse-pentatonic (comp (partial + 12) pentatonic -))
+(def inverse-pentatonic (comp pentatonic -))

 (comment
   (fx-reverb)


less logging

less logging

--- src/ardoq/swagger/sync_overview_workspace.clj
+++ src/ardoq/swagger/sync_overview_workspace.clj
@@ -50,10 +50,10 @@

 (defn ensure-entry-in-overview-ws [client spec-root-component overview]
   (if-let [workspace (common/find-existing-resource client (:overview-workspace overview) #(api-client/map->Workspace {}))]
+    (prn "Populating Overview workspace" overview)
     (if-let [existing-component (->> (:name spec-root-component)
                                   (api-client/find-components-by-name client (:_id workspace))
                                   (filter #(= (:type %) (:overview-component-type overview)))
                                   first)]
       (update-overview-component client spec-root-component existing-component)
-      (create-overview-component client spec-root-component workspace (:overview-component-type overview) (:overview-reference-type overview)))
-    (prn "Workspace " (:overview-workspace overview) "not found")))
+      (create-overview-component client spec-root-component workspace (:overview-component-type overview) (:overview-reference-type overview)))))


Bug fix when viewing app

Bug fix when viewing app

The nil parameter was not being passed in, so not sure what it was
getting

--- idecode/myappshare/mainapp.cljs
+++ idecode/myappshare/mainapp.cljs
@@ -396,7 +396,7 @@
                                    }
                      :onClick     #(do
                                      (write-ui app [:mode] "view")
-                                     (reeval  (read-ui app [:app-id]))   nil)
+                                     (reeval  (read-ui app [:app-id]) nil))
                      :disabled  (if (= (read-ui app [:mode]) "edit") "" "true")
                      }
                     "Run"


Make bikeshed happy.

Make bikeshed happy.

--- spec/freefrog/lang_spec.clj
+++ spec/freefrog/lang_spec.clj
@@ -121,7 +121,8 @@

   (it "should be able to create a new anchor with special characters"
     (should= (g/create-circle "Courage & Labs!@#$%^&*()")
-      (l/execute-governance "CREATE ANCHOR CIRCLE \"Courage & Labs!@#$%^&*()\".")))
+      (l/execute-governance
+        "CREATE ANCHOR CIRCLE \"Courage & Labs!@#$%^&*()\".")))

   (it "should not allow nonsense in role/circle conversions"
     ;Currently someone can say 'convert circle "blah" into a circle.' and it


:pencil: Add spacing to get-all-response

--- src/antlion_clojure/bot.clj
+++ src/antlion_clojure/bot.clj
@@ -296,6 +296,7 @@
          (map (fn [{:keys [name keywords response-text]}]
                 (str name ": "
                      (as-> keywords $ (clojure.string/join "," $))
+                     " "
                      (as-> response-text $ (clojure.string/replace $ #"\`|\n" "") (take 30 $) (apply str $))))
               responses)
          (clojure.string/join "\n"))


Added basic AST type to parser

Added basic AST type to parser

--- parser/parser.clj
+++ parser/parser.clj
@@ -26,8 +26,8 @@

 (typ range (Range int32 int32))

-(typ expression (Symbol (list int32)      range)
-                (List   (list expression) range))
+(typ sexp (Symbol (list int32)      range)
+          (List   (list sexp)       range))

 (typ (parse-result i e) (ParseNext i e)
                         (ParseOut i)
@@ -68,7 +68,7 @@
             (ParseOut input)         (Pair input (list-reverse expressions))
             (ParseNext input result) (parse-expressions input (Cons result expressions))))

-(export parse (input)
+(def parse-sexp (input)
      (match (parse-expressions (Pair input 0) Empty)
             (Pair _ expressions) expressions))

@@ -80,6 +80,23 @@
             (Symbol name _)      name
             (List expressions _) (wrap-in-brackets (stringify expressions))))

+(def stringify-sexp (expressions)
+     (string-join (string-of-char 32) (list-map (stringify-expression stringify-sexp) expressions)))
+
+
+(typ argument-list (ArgumentList        (list (list int32))))
+(typ expression    (Identifier          (list int32))
+                   (Application         expression (list expression))
+                   (Lambda              argument-list expression))
+(typ type          (SimpleType          (list int32))
+                   (ComplexType         (list int32) (list type)))
+(typ constructor   (Constructor         (list int32) (list type)))
+(typ definition    (TypeDefinition      (list int32) (list constructor))
+                   (ExportDefinition    (list int32) argument-list expression)
+                   (FunctionDefinition  (list int32) argument-list expression))
+
+(export parse (input)
+    (parse-sexp input))
+
 (export stringify (expressions)
-     (string-join (string-of-char 32) (list-map (stringify-expression stringify) expressions)))
-
+    (stringify-sexp expressions))