langcheckbox corrected

langcheckbox corrected

--- src/clj/webapp/routes/langcheckbx.clj
+++ src/clj/webapp/routes/langcheckbx.clj
@@ -7,7 +7,7 @@
             [webapp.models.sparql :as sparql]
             [compojure.handler :as handler]
             [compojure.route :as route]
-            [clojure.string :refer [capitalize split]]
+            [clojure.string :refer [capitalize split upper-case]]
             [stencil.core :as tmpl]
             [clj-http.client :as http]
             ;;[boutros.matsu.sparql :refer :all]
@@ -69,25 +69,23 @@
             [:table
              [:tr [:td "PDGM Type: " ]
               [:td
-               (check-box {:name "pos" :value pos :checked "true"} pos) (str pos)]]
+               (check-box {:name "pos" :value pos :checked "true"} pos) (str (upper-case pos))]]
               [:tr [:td [:hr]]]
-             (for [language languages]
-               (let [valclusterfile (str "pvlists/pname-" pos "-list-" language ".txt")
-                     valclusterlist (slurp valclusterfile)
-                     valclusters (clojure.string/split valclusterlist #"\r\n")]
-                 [:div [:tr [:td "PDGM Language: " ]
-                  [:td (capitalize language)]]
+                 [:tr [:td "PDGM Language(s): " ]
+                  [:td
+                   (for [language languages]
+                     [:div (str (capitalize language) " ")])]]
                  [:tr [:td "PDGM Value Clusters: " ]
                   [:td
                    {:title "Choose a value.", :name "valcluster"}
-                   (for [valcluster valclusters]
-                     [:div {:class "form-group"}
-                      [:label
-                       (check-box {:name "valclusters[]" :value (str language "," valcluster)} valcluster) (str valcluster)]
-                      ])]]]))
-                     ;; from https://groups.google.com/forum/#!topic/compojure/5Vm8QCQLsaQ
-                     ;; (check-box "valclusters[]" false valcluster) (str valcluster)]]
-
+                   (for [language languages]
+                     (let [valclusterfile (str "pvlists/pname-" pos "-list-" language ".txt")
+                           valclusterlist (slurp valclusterfile)
+                           valclusters (split valclusterlist #"\n")]
+                       (for [valcluster valclusters]
+                         [:div {:class "form-group"}
+                          [:label
+                           (check-box {:name "valclusters[]" :value (str language "," valcluster) } valcluster) (str (capitalize language) ": " valcluster)]])))]]
                  ;;(submit-button "Get pdgm")
                  [:tr [:td ]
                   [:td [:input#submit


Backfill selections with transparent pixels

--- src/cljs/goya/components/drawing.cljs
+++ src/cljs/goya/components/drawing.cljs
@@ -170,11 +170,11 @@
         (recur img keys-to-assoc)))))

-(defn create-sub-image-for-rect [rect color]
+(defn create-sub-image-for-rect [rect]
   (let [width (geometry/rect-width rect)
         height (geometry/rect-height rect)
         pixel-count (* width height)
-        image-data (vec (take pixel-count (repeat color)))]
+        image-data (vec (take pixel-count (repeat "#T")))]
     {:width width
      :height height
      :image-data image-data}))
@@ -421,8 +421,7 @@
               paste-x (- doc-x xOff)
               paste-y (- doc-y yOff)
               selection-was-pasted (om/get-state owner :selection-was-pasted)
-              backfill (create-sub-image-for-rect (om/get-state owner :selection)
-                                                  (get-in @app [:tools :paint-color]))]
+              backfill (create-sub-image-for-rect (om/get-state owner :selection))]
         (when (not selection-was-pasted)
           (paste-image app owner x1 y1 backfill))
         (paste-image app owner paste-x paste-y (om/get-state owner :selection-image)))


Make metadata repair tool more robust

Make metadata repair tool more robust

--- src/clojars/tools/repair_metadata.clj
+++ src/clojars/tools/repair_metadata.clj
@@ -4,10 +4,15 @@
             [clojure.java.io :as io])
   (:import (java.io File)
            (org.apache.commons.io FileUtils)
-           (org.apache.maven.artifact.repository.metadata Metadata)
+           (org.apache.maven.artifact.repository.metadata Metadata Versioning)
            (java.text SimpleDateFormat)
            (java.util Date))
   (:gen-class))
+
+(defn get-versioning [metadata]
+  (if-let [versioning (.getVersioning metadata)]
+    versioning
+    (get-versioning (doto metadata (.setVersioning (Versioning.))))))

 (defn find-bad-metadata [repo]
   ;; This is gross, mainly because maven uses maven-metadata.xml files for three things:
@@ -35,7 +40,7 @@
                                            (not (.exists (io/file dir "maven-metadata.xml"))))]
                              dir)
               versions (set (map (memfn getName) version-dirs))
-              missing-versions? (not= versions (set (.getVersions (.getVersioning metadata))))
+              missing-versions? (not= versions (set (.getVersions (get-versioning metadata))))
               invalid-sums? (not (futil/valid-sums? f))]
         :when (or missing-versions? invalid-sums?)]
     {:file              f
@@ -56,17 +61,17 @@
                   [file (futil/sum-file file :sha1) (futil/sum-file file :md5)]))))

 (defn repair-versions [{:keys [file metadata version-dirs]}]
-  (let [versioning (.getVersioning metadata)
+  (let [versioning (get-versioning metadata)
         sorted-dirs (sort-by #(.lastModified %) version-dirs)]
     ;; remove existing versions, then write dir versions in dir creation order
     (run! #(.removeVersion versioning %) (into [] (.getVersions versioning)))
     (run! #(.addVersion versioning %) (map (memfn getName) sorted-dirs))
     ;; set release to latest !snapshot
     (.setRelease versioning
-                 (->> sorted-dirs
-                      (filter #(not (.endsWith (.getName %) "SNAPSHOT")))
-                      last
-                      .getName))
+                 (when-let [v (->> sorted-dirs
+                                   (filter #(not (.endsWith (.getName %) "SNAPSHOT")))
+                                   last)]
+                   (.getName v)))
     ;; set lastUpdated to latest version
     (.setLastUpdated versioning (.format date-formatter
                                          (-> sorted-dirs last .lastModified Date.)))
@@ -85,8 +90,8 @@
     (println "Usage: repo-path backup-path (:repair|:report)")
     (let [[repo backup-dir action] args]
       (doseq [md (find-bad-metadata repo)]
-        (when (= ":repair" action)
-          (repair-metadata (io/file backup-dir) md))
         (prn (-> md
                  (dissoc :version-dirs :metadata)
-                 (update :file (memfn getAbsolutePath))))))))
+                 (update :file (memfn getAbsolutePath))))
+        (when (= ":repair" action)
+          (repair-metadata (io/file backup-dir) md))))))


toggle setting menu with invite button as well

--- frontend/components/aside.cljs
+++ frontend/components/aside.cljs
@@ -124,7 +124,10 @@
              (common/ico :fail-light)]]
            [:div.aside-user-options
             [:a.aside-item {:href "/account"} "Settings"]
-            [:a.aside-item {:on-click #(utils/open-modal "#inviteForm")} "Invite a Teammate"]
+            [:a.aside-item {:on-click #(do
+                                        (utils/open-modal "#inviteForm")
+                                        (put! controls-ch [:user-options-toggled]))}
+             "Invite a Teammate"]
             [:a.aside-item {:href "/logout"} "Logout"]]])))))

 (defn activity [app owner opts]


Preserve fileset metadata -- fixes #386

Preserve fileset metadata -- fixes #386

--- boot/core/src/boot/core.clj
+++ boot/core/src/boot/core.clj
@@ -881,7 +881,8 @@
         (add-user-asset    (first (user-asset-dirs)))
         (add-user-source   (first (user-source-dirs)))
         (add-user-resource (first (user-resource-dirs)))
-        (update-in [:tree] merge (:tree fileset)))))
+        (update-in [:tree] merge (:tree fileset))
+        (vary-meta merge (meta fileset)))))

 (defn reset-build!
   "Resets mutable build state to default values. This includes such things as


fixed build script

fixed build script

--- test/datascript/test.cljc
+++ test/datascript/test.cljc
@@ -2,6 +2,7 @@
   (:require
     #?(:cljs [cljs.test    :as t :refer-macros [is are deftest testing]]
        :clj  [clojure.test :as t :refer        [is are deftest testing]])
+    #?(:clj [clojure.java.shell :as sh])
     datascript.test.core

     datascript.test.btset
@@ -46,7 +47,7 @@

 #?(:clj
 (defn test-node [& args]
-  (let [res (apply clojure.java.shell/sh "node" "test_node.js" args)]
+  (let [res (apply sh/sh "node" "test_node.js" args)]
     (println (:out res))
     (binding [*out* *err*]
       (println (:err res)))


CMR-6235 reformatted tests and corrected test params

--- system-int-test/test/cmr/system_int_test/search/autocomplete_collection_facet_search_test.clj
+++ system-int-test/test/cmr/system_int_test/search/autocomplete_collection_facet_search_test.clj
@@ -138,9 +138,9 @@
      (is (= a b))))

   (testing "page_num should yield different 'first' results test"
-   (let [page-one-entry (as-> (query->json-response-body "q=b&page_size=2&page_num=1") response1
-                              (response-body->entries response1))
+   (let [page-one (as-> (query->json-response-body "q=b&page_size=1&page_num=1") response
+                        (response-body->entries response))

-         page-two-entry (as-> (query->json-response-body "q=b&page_size=2&page_num=2") response2
-                              (response-body->entries response2))]
-     (is (not= page-one-entry page-two-entry)))))
+         page-two(as-> (query->json-response-body "q=b&page_size=1&page_num=2") response
+                       (response-body->entries response))]
+     (is (not= page-one page-two)))))


allow some non-alphanumeric symbols

allow some non-alphanumeric symbols

--- test/funcgo/core_test.clj
+++ test/funcgo/core_test.clj
@@ -177,7 +177,8 @@
       )
 (test/fact "symbols can contain non-alphanumerics"
            (parse "foo(a,=>,b)") => (parsed "(foo a => b)")
-           ;;(parse "test.fact(\"interesting\", parse(\"a\"), =>, parsed(\"a\")")  => (parsed "(test/fact \"interesting\" (parse \"a\") => (parsed \"a\")")
+           (parse "test.fact(\"interesting\", parse(\"a\"), =>, parsed(\"a\"))")
+           => (parsed "(test/fact \"interesting\" (parse \"a\") => (parsed \"a\"))")
            )


minor debugging code change

minor debugging code change

--- src/flatgui/widgets/componentbase.clj
+++ src/flatgui/widgets/componentbase.clj
@@ -328,12 +328,13 @@
                has-changes (or prev-has-changes new-has-changes)
                with-evolved-target (assoc with-evolved-target-fresh :has-changes has-changes)
                new-aux (:aux-container with-evolved-target)
-;               _ (if (= [:main :tiket :ticket-panel :aggr-slider :base] target-id-path)
-;                   (println " JUST EVOLVED target-id-path " target-id-path
-;                     " new-has-changes " new-has-changes
-;                     " init " initialization
-;                     " props " (:clip-size (get-in new-aux (fgc/conjv k :latest-changed-properties)))
-;                     ))
+               ;_ (if (= [:main :app-panel :hello] target-id-path)
+               ;    (println " JUST EVOLVED target-id-path " target-id-path
+               ;      " new-has-changes " new-has-changes
+               ;      " init " initialization
+               ;      " props " (:position-matrix (get-in new-aux (fgc/conjv k :latest-changed-properties)))
+               ;      " val " (get-in container (fgc/conjv k :position-matrix))
+               ;      ))
                ]
               ;@todo Without this initialization check :children for table content pane do not get evolved on initialization. Why?
               (if (or new-has-changes (and initialization has-changes))


Temporary fix to range inputs on Customfeed.cljs.  Would like to accomplish this dynamically using vectors or lists.

--- src-cljs/rmfu_ui/customfeed.cljs
+++ src-cljs/rmfu_ui/customfeed.cljs
@@ -1,208 +1,208 @@
-(ns rmfu-ui.customfeed)
+(ns rmfu-ui.customfeed
+  (:require
+    [reagent.core :as reagent :refer [atom]]))
+
+  (defn input-range-component
+    [state param descriptiontext]
+    [:div.row
+     [:p.bullet.col-lg-7
+      descriptiontext]
+     [:p.col-lg-5
+      "Agree "
+      [:input
+       {:type "range"
+        :min 0
+        :max 3
+        :step 1
+        :list "agreevalues"
+        :value (:agreeness @state);; <---- notice the binding of the value to the input
+        :on-change (fn [e]
+                     (println (-> e .-target .-value));; <----- checkout out the console,
+                     ;; we should see this value printed
+                     (swap! state assoc param (-> e .-target .-value)) ;; <--- state transition happening here!
+                     )}]
+      " Disagree"]])

 (defn customfeed []
+(let [app-state1 (atom {:agreeness 0})
+      app-state2 (atom {:agreeness 0})
+      app-state3 (atom {:agreeness 0})
+      app-state4 (atom {:agreeness 0})
+]
 [:div.container.jumbotron.largemain
+[:div.row
+[:div.col-lg-12
+ [:h1
+  "Custom Feed"]
+ [:div.dategroup
+  [:h4
+   "New Legislation that will impact you! "]
+  [:p.date
+   "October 1, 2015"]]
+ [:div.borderbox
+  "\n                Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute\n              irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n          "]
+ [:br]
+ [:ul.list-inline
+  [:li
+   [:button.btn.btn-default
+    {:type "button", :value "add"}
+    "Collapse"]]
+  [:li
+   [:button.btn.btn-default
+    {:type "button", :value "add"}
+    "Topics"]]
+  [:li
+   [:button.btn.btn-default
+    {:type "button", :value "add"}
+    "Comments"]]
+  [:li
+   [:button.btn.btn-default
+    {:type "button", :value "add"}
+    "Share"]]
+  [:li
+   [:button.btn.btn-default
+    {:type "button", :value "add"}
+    "Archive"]]]
+ [:ul.list-inline
+  [:li
+   [:a
+    {:href "#"}
+    "Fertilizer"]]
+  [:li
+   [:a
+    {:href "#"}
+    "Legislation"]]
+  [:li
+   [:a
+    {:href "#"}
+    "Vegetables"]]
+  [:li
+   [:a
+    {:href "#"}
+    "Grain"]]
+  [:li
+   [:a
+    {:href "#"}
+    "Fruit"]]
+  [:li
+   "80246 +5 Miles"]]
+ [:hr]
+ [:div.dategroup
+  [:h4.articleheading
+   "Please help us serve you better"]
+  [:p.date
+   "September 20th, 2015"]]
+   [input-range-component app-state1 :agreeness "Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."]
+   [input-range-component app-state2 :agreeness "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris."]
+   [input-range-component app-state3 :agreeness "Duis aute irure dolor in pariatur."]
+   [input-range-component app-state4 :agreeness "Excepteur sint occaecat deserunt mollit anim id est laborum."]
+ [:ul.list-inline
+  [:li
+   [:button.btn.btn-default
+    {:type "button", :value "add"}
+    "Submit"]]
+  [:li
+   [:button.btn.btn-default
+    {:type "button", :value "add"}
+    "Topics"]]
+  [:li
+   [:button.btn.btn-default
+    {:type "button", :value "add"}
+    "Comments"]]
+  [:li
+   [:button.btn.btn-default
+    {:type "button", :value "add"}
+    "Share"]]
+  [:li
+   [:button.btn.btn-default
+    {:type "button", :value "add"}
+    "Archive"]]]
+ [:ul.list-inline
+  [:li
+   [:a
+    {:href "#"}
+    "Polls"]]
+  [:li
+   [:a
+    {:href "#"}
+    "Legislation"]]
+  [:li
+   [:a
+    {:href "#"}
+    "Youth"]]
+  [:li
+   [:a
+    {:href "#"}
+    "Funding"]]
+  [:li
+   "80246 +5 Miles"]]
+ [:hr]
+ [:div.dategroup
+  [:h4.articleheading
+   "Review the latest proposal"]
+  [:p.date
+   " September 1st, 2015"]]
  [:div.row
-  [:div.col-lg-12
-   [:h1
-    "Custom Feed"]
-   [:div.dategroup
-    [:h4
-     "New Legislation that will impact you! "]
-    [:p.date
-     "October 1, 2015"]]
-   [:div.borderbox
-    "\n                Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute\n              irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n          "]
-   [:br]
-   [:ul.list-inline
+  [:div.col-lg-4
+   [:p.document
+    "New Legislation Proposal Draft.doc"]]
+  [:div.col-lg-8
+   [:ul.commentlist
     [:li
-     [:button.btn.btn-default
-      {:type "button", :value "add"}
-      "Collapse"]]
+     "Joe - Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididul"]
     [:li
-     [:button.btn.btn-default
-      {:type "button", :value "add"}
-      "Topics"]]
+     "Bob - Consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et!"]
     [:li
-     [:button.btn.btn-default
-      {:type "button", :value "add"}
-      "Comments"]]
-    [:li
-     [:button.btn.btn-default
-      {:type "button", :value "add"}
-      "Share"]]
-    [:li
-     [:button.btn.btn-default
-      {:type "button", :value "add"}
-      "Archive"]]]
-   [:ul.list-inline
-    [:li
-     [:a
-      {:href "#"}
-      "Fertilizer"]]
-    [:li
-     [:a
-      {:href "#"}
-      "Legislation"]]
-    [:li
-     [:a
-      {:href "#"}
-      "Vegetables"]]
-    [:li
-     [:a
-      {:href "#"}
-      "Grain"]]
-    [:li
-     [:a
-      {:href "#"}
-      "Fruit"]]
-    [:li
-     "80246 +5 Miles"]]
-   [:hr]
-   [:div.dategroup
-    [:h4.articleheading
-     "Please help us serve you better"]
-    [:p.date
-     "September 20th, 2015"]]
-   [:div.row
-    [:p.bullet.col-lg-7
-     "Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."]
-    [:p.col-lg-5
-     "Agree "
-     [:input
-      {:type "range", :min "0", :max "3", :value "0", :step "1", :list "agreevalues"}]
-     " Disagree"]]
-   [:div.row
-    [:p.bullet.col-lg-7
-     "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris."]
-    [:p.col-lg-5
-     "Agree "
-     [:input
-      {:type "range", :min "0", :max "3", :value "0", :step "1", :list "agreevalues"}]
-     " Disagree"]]
-   [:div.row
-    [:p.bullet.col-lg-7
-     "Duis aute irure dolor in pariatur."]
-    [:p.col-lg-5
-     "Agree "
-     [:input
-      {:type "range", :min "0", :max "3", :value "0", :step "1", :list "agreevalues"}]
-     " Disagree"]]
-   [:div.row
-    [:p.bullet.col-lg-7
-     "Excepteur sint occaecat deserunt mollit anim id est laborum."]
-    [:p.col-lg-5
-     "Agree "
-     [:input
-      {:type "range", :min "0", :max "3", :value "0", :step "1", :list "agreevalues"}]
-     " Disagree"]]
-   [:ul.list-inline
-    [:li
-     [:button.btn.btn-default
-      {:type "button", :value "add"}
-      "Submit"]]
-    [:li
-     [:button.btn.btn-default
-      {:type "button", :value "add"}
-      "Topics"]]
-    [:li
-     [:button.btn.btn-default
-      {:type "button", :value "add"}
-      "Comments"]]
-    [:li
-     [:button.btn.btn-default
-      {:type "button", :value "add"}
-      "Share"]]
-    [:li
-     [:button.btn.btn-default
-      {:type "button", :value "add"}
-      "Archive"]]]
-   [:ul.list-inline
-    [:li
-     [:a
-      {:href "#"}
-      "Polls"]]
-    [:li
-     [:a
-      {:href "#"}
-      "Legislation"]]
-    [:li
-     [:a
-      {:href "#"}
-      "Youth"]]
-    [:li
-     [:a
-      {:href "#"}
-      "Funding"]]
-    [:li
-     "80246 +5 Miles"]]
-   [:hr]
-   [:div.dategroup
-    [:h4.articleheading
-     "Review the latest proposal"]
-    [:p.date
-     " September 1st, 2015"]]
-   [:div.row
-    [:div.col-lg-4
-     [:p.document
-      "New Legislation Proposal Draft.doc"]]
-    [:div.col-lg-8
-     [:ul.commentlist
-      [:li
-       "Joe - Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididul"]
-      [:li
-       "Bob - Consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et!"]
-      [:li
-       "Joe - Adipisicing elit?"]]]]
-   [:ul.list-inline
-    [:li
-     [:button.btn.btn-default
-      {:type "button", :value "add"}
-      "Download"]]
-    [:li
-     [:button.btn.btn-default
-      {:type "button", :value "add"}
-      "Topics"]]
-    [:li
-     [:button.btn.btn-default
-      {:type "button", :value "add"}
-      "Comments"]]
-    [:li
-     [:button.btn.btn-default
-      {:type "button", :value "add"}
-      "Share"]]
-    [:li
-     [:button.btn.btn-default
-      {:type "button", :value "add"}
-      "Archive"]]]
-   [:ul.list-inline
-    [:li
-     [:a
-      {:href "#"}
-      "Documents"]]
-    [:li
-     [:a
-      {:href "#"}
-      "Legislation"]]
-    [:li
-     [:a
-      {:href "#"}
-      "Vegetables"]]
-    [:li
-     [:a
-      {:href "#"}
-      "Fruit"]]
-    [:li
-     "80246 +5 Miles"]]]]
+     "Joe - Adipisicing elit?"]]]]
+ [:ul.list-inline
+  [:li
+   [:button.btn.btn-default
+    {:type "button", :value "add"}
+    "Download"]]
+  [:li
+   [:button.btn.btn-default
+    {:type "button", :value "add"}
+    "Topics"]]
+  [:li
+   [:button.btn.btn-default
+    {:type "button", :value "add"}
+    "Comments"]]
+  [:li
+   [:button.btn.btn-default
+    {:type "button", :value "add"}
+    "Share"]]
+  [:li
+   [:button.btn.btn-default
+    {:type "button", :value "add"}
+    "Archive"]]]
+ [:ul.list-inline
+  [:li
+   [:a
+    {:href "#"}
+    "Documents"]]
+  [:li
+   [:a
+    {:href "#"}
+    "Legislation"]]
+  [:li
+   [:a
+    {:href "#"}
+    "Vegetables"]]
+  [:li
+   [:a
+    {:href "#"}
+    "Fruit"]]
+  [:li
+   "80246 +5 Miles"]]]]

-     [:datalist#agreevalues
-      [:option
-       "Strongly Agree"]
-      [:option
-       "Agree"]
-      [:option
-       "Disagree"]
-      [:option
-       "Strongly Disagree"]]
-     ]
-)
+   [:datalist#agreevalues
+    [:option
+     "Strongly Agree"]
+    [:option
+     "Agree"]
+    [:option
+     "Disagree"]
+    [:option
+     "Strongly Disagree"]]
+   ]
+))


cider-nrepl update

cider-nrepl update

--- profiles.clj
+++ profiles.clj
@@ -1,7 +1,7 @@
 {:dev {:dependencies [[weasel "0.2.0"]
                       [com.cemerick/piggieback "0.1.3"]]

-       :plugins [[cider/cider-nrepl "0.1.0-SNAPSHOT"]]
+       :plugins [[cider/cider-nrepl "0.7.0"]]

        :repl-options {:nrepl-middleware [cemerick.piggieback/wrap-cljs-repl]}


Bugfix for alembic/distill outside of projects

Previously, you couldn't pull from *any* external repositories -- even
the default ones, Central and Clojars -- when outside a project. This
was because the hack for allowing distill to work outside of projects
defaulted the repository list to the empty vector. Replacing the default
repository list with a vector containing the Central and Clojars
repositories fixes the issue.

--- profiles.clj
+++ profiles.clj
@@ -56,7 +56,13 @@
                             (fn [dependencies & args]
                               (if (= (first args) :project)
                                 (apply distill dependencies (rest args))
-                                (apply distill dependencies :repositories [] args)))))
+                                (apply distill dependencies :repositories
+                                       [["central"
+                                         {:snapshots false
+                                          :url "https://repo1.maven.org/maven2/"}]
+                                        ["clojars"
+                                         {:url "https://clojars.org/repo/"}]]
+                                       args)))))

                         ;; For some reason, Leiningen tries to resolve every unquoted
                         ;; symbol in the :injections code, even the ones that wouldn't


Fix basic EDN renderer test (#257)

Fix basic EDN renderer test (#257)

--- test/selmer/core_test.clj
+++ test/selmer/core_test.clj
@@ -1256,4 +1256,4 @@
   (is (str/includes? (render "{% debug %}" {:debug-value 1})
                      "debug-value"))
   (testing "basic rendering escapes HTML"
-    (println (basic-edn->html {:a "<pre>"}))))
+    (is (str/includes? (basic-edn->html {:a "<pre>"}) "&quot"))))


deactivated warning

deactivated warning

pops up on legit actions as well.

--- src-cljs/checkmate/views/show_list.cljs
+++ src-cljs/checkmate/views/show_list.cljs
@@ -46,7 +46,6 @@
   (reset! list-model model))

 (defn ^:export init [id]
-  (views/warn-of-unsaved-changes)
   (hook-up-buttons)
   (add-watch list-model ::auto (fn [_ __ ___ n]
                                  (render-list n)


Add rudimentary validation logic for submit form.

--- src-cljs/kata/pages/submit_problem.cljs
+++ src-cljs/kata/pages/submit_problem.cljs
@@ -6,10 +6,15 @@
   (fn [event]
     (swap! form-data assoc id (.. event -target -value))))

+(defn fields-present? [form-data fields]
+  (not-any? empty? (map @form-data fields)))
+
 (defn submit-problem [form-data result]
-  (POST "/api/add-example"
-        {:params {:problem @form-data}
-         :handler #(reset! result %)}))
+  (if-not (fields-present? form-data [:title :submitter :description])
+    (js/alert "Required field(s) are missing.")
+    (POST "/api/add-example"
+      {:params {:problem @form-data}
+       :handler #(reset! result %)})))

 (defn render-code [this]
   (->> this reagent/dom-node (.highlightBlock js/hljs)))
@@ -50,6 +55,29 @@
          ;:error-handler #(reset! error %)
          }))

+(defn text-field
+  ([form-data field-name]
+   (text-field form-data field-name (name field-name)))
+  ([form-data field-name label]
+   [:div.form-group
+    {:class (if (empty? (field-name @form-data)) "has-error")}
+    [:input.form-control
+     {:type :text
+      :placeholder label
+      :value (field-name @form-data)
+      :on-change (save-input! form-data field-name)}]]))
+
+(defn textarea
+  ([form-data field-name]
+   (textarea form-data field-name (name field-name)))
+  ([form-data field-name label]
+   [:div.form-group
+    {:class (if (empty? (field-name @form-data)) "has-error")}
+    [:textarea.form-control
+     {:placeholder label
+      :value (field-name @form-data)
+      :on-change (save-input! form-data field-name)}]]))
+
 (defn submit-problem-form []
   (let [form-data (reagent/atom {})
         result (reagent/atom {})
@@ -57,32 +85,24 @@
     (fn []
       [:div.row>div.col-md-12
        [:h2 "Submit a problem"]
-       [:input.form-control
-        {:type :text
-         :placeholder "title"
-         :value (:title @form-data)
-         :on-change (save-input! form-data :title)}]
-       [:input.form-control
-        {:type :text
-         :placeholder "name"
-         :value (:submitter @form-data)
-         :on-change (save-input! form-data :submitter)}]
-       [:textarea.form-control
-        {:placeholder "description"
-         :value (:description @form-data)
-         :on-change (save-input! form-data :description)}]
-       [:div.row>div.col-md-12
-          [editor form-data]]
+       (text-field form-data :title)
+       (text-field form-data :submitter "your name")
+       (textarea form-data :description)
+       [:div.form-group
+        [:div.row>div.col-md-12
+         [editor form-data]]]
        [:div.row
-        [:div.col-md-1>label "Result"]
-        [:div.col-md-11
-        [eval-view eval-result]]]
-       [:button.btn.btn-primary
-        {:on-click #(evaluate-code form-data eval-result)}
-        "evaluate"]
-       [:button.btn.btn-primary
-        {:on-click #(submit-problem form-data result)}
-        "submit"]
+        [:div.form-group
+         [:div.col-md-1>label "Result"]
+         [:div.col-md-11
+          [eval-view eval-result]]]]
+       [:div.form-group
+        [:button.btn.btn-primary
+         {:on-click #(evaluate-code form-data eval-result)}
+         "evaluate"]
+        [:button.btn.btn-primary
+         {:on-click #(submit-problem form-data result)}
+         "submit"]]
        (when-let [result @result]
          [:h2 result])])))


Add start timeout property

Add start timeout property

--- src/leiningen/new/cljskel/project.clj
+++ src/leiningen/new/cljskel/project.clj
@@ -47,11 +47,12 @@
         :production false
         :requestlog-enabled false
         :requestlog-retainhours 24
+        :restdriver-port 8081
         :service-name "{{name}}"
         :service-port 8080
         :service-url "http://localhost:%s"
         :shutdown-timeout-millis 5000
-        :restdriver-port 8081
+        :start-timeout-seconds 120
         :threads 254}

   :lein-release {:deploy-via :shell


Bumped nokia ring-utils version up to 1.2.1 which includes default handling of exception-info as well as Exceptions.

--- src/leiningen/new/cljskel/project.clj
+++ src/leiningen/new/cljskel/project.clj
@@ -22,7 +22,7 @@
                  [cheshire "5.2.0"]
                  [clj-time "0.6.0"]
                  [environ "0.4.0"]
-                 [nokia/ring-utils "1.0.1"]
+                 [nokia/ring-utils "1.2.1"]
                  [metrics-clojure "1.0.1"]
                  [metrics-clojure-ring "1.0.1"]]


Fixed spelling and grammar

Fixed spelling and grammar

--- src/cljs/conference_rating/add_rating_page/add_rating_page.cljs
+++ src/cljs/conference_rating/add_rating_page/add_rating_page.cljs
@@ -91,10 +91,10 @@
    [:span "I found this conference ..."]
    [:div {:class "row"}
     [:div {:class "col-lg-12 col-md-12 col-sm-12 col-xs-12"}
-     (checkbox-description-right :tags.inspiring "inspiring" "This conference had an impact one me.")
+     (checkbox-description-right :tags.inspiring "inspiring" "This conference had an impact on me.")
      (checkbox-description-right :tags.informative "informative" "I learned a lot during the workshops, sessions and talks.")
      (checkbox-description-right :tags.entertaining "entertaining" "The speakers where showmasters and the after party was amazing.")
-     (checkbox-description-right :tags.hires "good to meet potential hires" "I meet amazing people I would like to work with in the future.")
+     (checkbox-description-right :tags.hires "good to meet potential hires" "I met amazing people I would like to work with in the future.")
      (checkbox-description-right :tags.clients "good to meet potential clients" "The business sponsoring or being present at this conference coud be our next client.")]]])

 (defn experience-checkbox [id input-label]


Whitespace

Whitespace

--- dev-src/braid/dev/figwheel.clj
+++ dev-src/braid/dev/figwheel.clj
@@ -12,5 +12,3 @@
             :watch-dirs ["src"]}
            "dev")
   :stop (repl-api/stop-all))
-
-


[#1441] Add custom generator for maps.layer pointSize and color

--- backend/specs/akvo/lumen/specs/visualisation/maps/layer.clj
+++ backend/specs/akvo/lumen/specs/visualisation/maps/layer.clj
@@ -31,7 +31,10 @@
 (defn string-pos-int? [s] (try (pos-int? (Integer/parseInt s))
                           (catch Exception e false)))

-(s/def ::pointSize  (s/or :s string-pos-int? :i pos-int?)) ;; only in geo-location we receive a string :!
+(s/def ::pointSize  (s/with-gen
+                      (s/or :s string-pos-int? :i pos-int?)
+                      #(s/gen #{"1" 1 "2" 2})
+                      )) ;; only in geo-location we receive a string :!

 (create-ns  'akvo.lumen.specs.visualisation.maps.layer.point-color-mapping)
 (alias 'layer.point-color-mapping.s 'akvo.lumen.specs.visualisation.maps.layer.point-color-mapping)
@@ -44,7 +47,9 @@
                        (Color/decode s)
                        (catch Exception e false)))

-(s/def ::layer.point-color-mapping.s/color valid-hex?)
+(s/def ::layer.point-color-mapping.s/color (s/with-gen
+                                             valid-hex?
+                                             #(s/gen #{"000" "256256256" "101010"})))

 (s/def ::point-color-mapping-item (s/keys :req-un [::layer.point-color-mapping.s/op
                                                    ::layer.point-color-mapping.s/value


only schedule default dates when in edit mode

--- iwaswhere-web/src/cljs/iwaswhere_web/ui/entry/task.cljs
+++ iwaswhere-web/src/cljs/iwaswhere_web/ui/entry/task.cljs
@@ -20,7 +20,7 @@
               (put-fn [:entry/update-local updated]))))]
     (fn [entry put-fn edit-mode?]
       (when (contains? (:tags entry) "#task")
-        (when-not (:task entry)
+        (when (and edit-mode? (not (:task entry)))
           (let [d (* 24 60 60 1000)
                 now (st/now)
                 updated (assoc-in entry [:task] {:start (+ now d)


[#111] Use binding defined in previous binding in loop

--- priv/examples/pattern.clj
+++ priv/examples/pattern.clj
@@ -77,3 +77,10 @@
              (erlang/+.e sum x)
              (recur xs (erlang/+.e sum x))))
        5 x])
+
+(let* [x (loop* [#erl(x & xs) #erl(1 40)
+                 sum x]
+           (if (erlang/=:=.e xs #erl())
+             (erlang/+.e sum x)
+             (recur xs (erlang/+.e sum x))))
+       42 x])


Remove spurious println statements.

Remove spurious println statements.

--- src/clj/qualityclj/linters/eastwood.clj
+++ src/clj/qualityclj/linters/eastwood.clj
@@ -17,9 +17,7 @@
   "Parse the complete output from running eastwood."
   [output user project]
   (let [lines (line-seq (BufferedReader. (StringReader. output)))
-        _ (println "Lines to parse: " (count lines))
         comments (filter #(not (nil? (re-find #".*:.*:.*:.*" %))) lines)
-        _ (println "Comments from eastwood: " (count comments))
         comments (map parse-comment comments)]
     (doseq [entry comments]
       (println "Adding note: " entry)
@@ -35,7 +33,8 @@
   [user project]
   (let [output (docker/run user project
                  ["lein" "eastwood"
+                  ;; Ideally we'll limit this at some point, but
+                  ;; I haven't been able to pass this properly yet
                   ;;"\"{:namespaces [:source-paths]}\""
                   ])]
-    (println "Output from eastwood: " output)
     (parse-eastwood-output (:out output)  user project)))


Whitespace

Whitespace

--- src/clj/salava/extra/application/db.clj
+++ src/clj/salava/extra/application/db.clj
@@ -210,19 +210,14 @@

 (defn create-connection-badge-advert! [ctx user_id badge_advert_id]
   (try+
-   (insert-connect-badge-advert<! {:user_id user_id :badge_advert_id badge_advert_id}  (u/get-db ctx))
-
-   {:status "success"}
-   (catch Object _
-     {:status "error"}
-     )))
+    (insert-connect-badge-advert<! {:user_id user_id :badge_advert_id badge_advert_id}  (u/get-db ctx))
+    {:status "success"}
+    (catch Object _
+      {:status "error"})))

 (defn delete-connection-badge-advert! [ctx user_id  badge_advert_id]
   (try+
-   (delete-connect-badge-advert! {:user_id user_id :badge_advert_id badge_advert_id} (u/get-db ctx))
-
-   {:status "success" }
-   (catch Object _
-     {:status "error"}
-     )))
-
+    (delete-connect-badge-advert! {:user_id user_id :badge_advert_id badge_advert_id} (u/get-db ctx))
+    {:status "success" }
+    (catch Object _
+      {:status "error"})))


Change function call to hiccup with component

Makes sure that reagent doesn't rerender single-input-view unless arguments or ratom values change

--- src/cljs/cglossa/search_inputs/cwb.cljs
+++ src/cljs/cglossa/search_inputs/cwb.cljs
@@ -160,8 +160,8 @@
                           (let [value (aget event "target" "value")
                                 query (if (= value "") "" (phrase->cqp value phonetic?))]
                             (swap! query-cursor assoc :query query)))]
-    (single-input-view corpus query-cursor displayed-query show-remove-btn?
-                       true remove-query-handler on-text-changed)))
+    [single-input-view corpus query-cursor displayed-query show-remove-btn?
+     true remove-query-handler on-text-changed]))

 (defn- extended [query-cursor]
   [:span])
@@ -173,8 +173,8 @@
         on-text-changed (fn [event query-cursor phonetic?]
                           (let [query (aget event "target" "value")]
                             (swap! query-cursor assoc :query query)))]
-    (single-input-view corpus query-cursor displayed-query show-remove-btn?
-                       false remove-query-handler on-text-changed)))
+    [single-input-view corpus query-cursor displayed-query show-remove-btn?
+     false remove-query-handler on-text-changed]))

 (defn search-inputs
   "Component that lets the user select a search view (simple, extended


Use the namespaced keys being returned by the API now

--- src/cljs/comic_reader/ui/site_list.cljs
+++ src/cljs/comic_reader/ui/site_list.cljs
@@ -33,8 +33,8 @@
     :list-element [:ul.inline-list]
     :item->li (fn [site]
                 [:a.large.button.radius
-                 {:on-click #(view-site (:id site))}
-                 (:name site)])}
+                 {:on-click #(view-site (:site/id site))}
+                 (:site/name site)])}
    sites))

 (defn site-list-container []


[#1142] Always grab latest columns titles in map metadata

--- backend/src/akvo/lumen/lib/visualisation/map_metadata.clj
+++ backend/src/akvo/lumen/lib/visualisation/map_metadata.clj
@@ -115,7 +115,7 @@
   (map
     (fn [column-object] { "columnName" (get column-object "columnName") "title" (get column-object "title")})
     (get
-      (first (jdbc/query tenant-conn (format "SELECT columns FROM dataset_version WHERE %s='%s'" selector-name selector-value)))
+      (first (jdbc/query tenant-conn (format "SELECT columns, modified FROM dataset_version WHERE %s='%s' ORDER BY modified DESC LIMIT 1" selector-name selector-value)))
       :columns
     )
   )


Remove experiment code

Remove experiment code

--- backend/test/circle/backend/action/test_load_balancer.clj
+++ backend/test/circle/backend/action/test_load_balancer.clj
@@ -28,23 +28,4 @@
     (run-build build :cleanup-on-failure false)
     (successful? build) => falsey))

-(fact "stubbing works"
-  (lb/healthy? "lb-bogus" ["i-foo"]) => false
-  (provided
-    (lb/healthy? "lb-bogus" ["i-bogus"]) => false))

-(defn bogus [x] x)
-
-(fact "stubbing works"
-  (bogus "foo") => "foo"
-  (provided
-    (bogus :bar) => "foo"))
-
-(fact "provided can stub invisible fns"
-  (circle.bogus/bar 3) => 10
-  (provided (circle.bogus/foo 3) => 5))
-
-(fact "provided can stub apply'd fns"
-  (circle.bogus/bar* 3) => 10
-  (provided
-    (apply circle.bogus/foo [3]) => 5))


core.async: Replacing nil with a sentinel value.

--- test/com/nomistech/clojure_the_language/core_async_mapping_etc_test.clj
+++ test/com/nomistech/clojure_the_language/core_async_mapping_etc_test.clj
@@ -91,7 +91,7 @@
   => [0 2 4])

 (fact "Composing transducers -- ordering is different to composing functions!"
-  ;; See http://clojure.org/transducers :
+  ;; See http://clojure.org/transducers:
   ;; - "Composition of the transformer runs right-to-left but builds a
   ;;    transformation stack that runs left-to-right (filtering happens
   ;;    before mapping in this example)."
@@ -106,3 +106,57 @@
     (a/onto-chan c [0 1 2 3 4])
     (chan->seq c))
   => [0 0 1 1 2 2 3 3 4 4])
+
+;;;; ___________________________________________________________________________
+;;;; How to replace `nil` with a sentinel value on channels.
+
+
+;;;; Motivation
+;;;; ==========
+;;;;
+;;;; You can do this...
+
+(comment
+  (let [c (a/chan)]
+    (when-let [x ...]
+      (a/>! c ...))
+    c))
+
+;;;; ...but that doesn't play nicely in a mappy/filtery context.
+
+
+;;;; What to do about it
+;;;; ===================
+
+;;;; You can replace nil with a sentinel value, like this:
+
+(def the-sentynil-value
+  "A sentinel value that is put on channels instead of nil."
+  (cons nil nil))
+
+(defn nil->sentynil [x] (if (nil? x) the-sentynil-value x))
+
+(defn sentynil? [x] (= x the-sentynil-value))
+
+(defn sentynil-chan [ch] (a/remove> sentynil? ch))
+
+(fact "About using a sentynil value for nil"
+
+  (fact "In Clojure 1.6"
+    (let [wrapped-ch  (a/chan)
+          wrapping-ch (sentynil-chan wrapped-ch)]
+      (a/go
+        (doseq [i [0 1 nil 3 nil]]
+          (a/>! wrapping-ch (nil->sentynil i)))
+        (a/close! wrapping-ch))
+      (chan->seq wrapped-ch))
+    => [0 1 3])
+
+  (fact "In Clojure 1.7"
+    (let [c (a/chan 1 (remove sentynil?))]
+      (a/go
+        (doseq [i [0 1 nil 3 nil]]
+          (a/>! c (nil->sentynil i)))
+        (a/close! c))
+      (chan->seq c))
+    => [0 1 3]))


[#7] Define with-local-api to use stub server

--- api/src/api/datastore.clj
+++ api/src/api/datastore.clj
@@ -24,6 +24,17 @@
          (finally
            (.uninstall installer#))))))

+(defmacro with-local-api [& body]
+  `(let [options# (-> (RemoteApiOptions.)
+                      (.server "localhost" 8080))]
+     (.useDevelopmentServerCredential options#)
+     (let [installer# (RemoteApiInstaller.)]
+       (.install installer# options#)
+       (try
+         ~@body
+         (finally
+           (.uninstall installer#))))))
+
 (def ^:private date-format (.toFormat (DateTimeFormatter/ISO_INSTANT)))

 (defn- to-iso-8601 [date]


Aligns code for price save button.

Aligns code for price save button.

--- src/cljs/proto/goods_search_reframe.cljs
+++ src/cljs/proto/goods_search_reframe.cljs
@@ -192,8 +192,13 @@
                           :on-change #(dispatch [:change-price shop (-> % .-target .-value)])} ]]
             [:td
              (cond
-               (or (not (:price shop)) (empty? (:price shop))) [:button {:class "btn btn-primary btn-lg" :disabled true} "Save"]
-               (is-saving? (:shop shop) @saving-q) [:button {:class "btn btn-primary btn-lg" :disabled true} "Saving"]
+               (or (not (:price shop))
+                   (empty? (:price shop))) [:button
+                                            {:class "btn btn-primary btn-lg"
+                                             :disabled true} "Save"]
+               (is-saving? (:shop shop) @saving-q) [:button
+                                                    {:class "btn btn-primary btn-lg"
+                                                     :disabled true} "Saving"]
                :else  [:button
                        {:class "btn btn-primary btn-lg"
                         :on-click #(dispatch [:start-saving-price @good (:shop shop) (:price shop)])}


add more info to dashboard, add some tips

--- src/cljs/salava/social/ui/dashboard.cljs
+++ src/cljs/salava/social/ui/dashboard.cljs
@@ -15,11 +15,16 @@
             [salava.core.ui.notactivated :refer [not-activated-banner]]
             [salava.badge.ui.pending :as pb]))

-
+(defn init-gallery-stats [state]
+  (ajax/GET
+    (path-for (str "/obpv1/gallery/stats"))
+    {:handler (fn [data]
+                (swap! state assoc :gallery data))}))

 (defn init-dashboard [state]
   (stream/init-data state)
   (pb/init-data state)
+  (init-gallery-stats state)
   (ajax/GET
     (path-for (str "/obpv1/user/dashboard"))
     {:handler (fn [data]
@@ -134,19 +139,22 @@

 (defn welcome-block [state]
-  [:div#welcome-block {:class "block"}
-   [:div.welcome-block.block-content.row
-    [:a {:data-toggle "collapse" :href "#hidden" :role "button" :aria-expanded "false" :aria-controls "hidden"}
-     [:div.content
-      [:div
-       [:i.fa.fa-chevron-down.icon] (str (t :core/Welcometo) " " (session/get :site-name) " " (get-in @state [:user-profile :user :first_name] "") "!")]]
-     [:div.collapse.hidden-content {:id "hidden" }
-      [:p "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."]
-      ]
-     ]]])
+  (let [welcome-tip (get-in @state [:tips :welcome-tip])
+        site-name (session/get :site-name)]
+    [:div#welcome-block {:class "block"}
+     [:div.welcome-block.block-content.row
+      [:a {:data-toggle "collapse" :href "#hidden" :role "button" :aria-expanded "false" :aria-controls "hidden"}
+       [:div.content
+        [:div
+         [:i.fa.fa-chevron-down.icon] (if welcome-tip  (str (t :core/Welcometo) " " site-name (t :core/Service)) (str (t :core/Welcometo) " " (session/get :site-name) " " (get-in @state [:user-profile :user :first_name] "") "!"))]]
+       [:div.collapse.hidden-content {:id "hidden" }
+        [:p "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."]
+        ]
+       ]]]))

 (defn notifications-block [state]
-  (let [events (->> (:events @state) (remove #(= (:verb %) "ticket")) (take 5))]
+  (let [events (->> (:events @state) (remove #(= (:verb %) "ticket")) (take 5))
+        tips (:tips @state)]
     [:div {:class "box col-md-4" }
      [:div#box_1
       [:div.col-md-12.block
@@ -154,18 +162,28 @@
        [:div.notifications-block.row_1.notifications;.block-content
         [:div.heading_1 [:i.fa.fa-rss.icon]
          [:a {:href "social/stream"} [:span.title (t :social/Stream)]] [:span.badge (count (:events @state))]]
-        (reduce (fn [r event]
-                  (conj r [:div.notification-div.ax_default
-                           (cond
-                             (and (= "badge" (:type event)) (= "follow" (:verb event))) (follow-event-badge event state)
-                             (and (= "user" (:type event)) (= "follow" (:verb event))) (follow-event-user event state)
-                             (and (= "badge" (:type event)) (= "publish" (:verb event))) (publish-event-badge event state)
-                             (and (= "page" (:type event)) (= "publish" (:verb event))) (publish-event-page event state)
-                             (= "advert" (:type event)) (badge-advert-event event state)
-                             (= "message" (:verb event)) [message-event event state]
-                             :else "")
-                           ])
-                  )[:div.content] events)
+        (if (not-activated?)
+          [:div.content
+           [:div {:style {:font-size "initial"}}
+            [:p (t :social/Notactivatedbody1)]
+            [:ul
+             [:li (t :social/Notactivatedbody2)]
+             [:li (t :social/Notactivatedbody3)]
+             [:li (t :social/Notactivatedbody4)]
+             [:li (t :social/Notactivatedbody5)]
+             [:li (t :social/Notactivatedbody6)]]]]
+          (reduce (fn [r event]
+                    (conj r [:div.notification-div.ax_default
+                             (cond
+                               (and (= "badge" (:type event)) (= "follow" (:verb event))) (follow-event-badge event state)
+                               (and (= "user" (:type event)) (= "follow" (:verb event))) (follow-event-user event state)
+                               (and (= "badge" (:type event)) (= "publish" (:verb event))) (publish-event-badge event state)
+                               (and (= "page" (:type event)) (= "publish" (:verb event))) (publish-event-page event state)
+                               (= "advert" (:type event)) (badge-advert-event event state)
+                               (= "message" (:verb event)) [message-event event state]
+                               :else "")
+                             ])
+                    )[:div.content] events))
         ]]]]))

 (defn latest-earnable-badges []
@@ -180,7 +198,8 @@

 (defn badges-block [state]
   (fn []
-    (let [badges (:badges @state )]
+    (let [badges (:badges @state )
+          welcome-tip (get-in @state [:tips :welcome-tip])]
       [:div {:class "box col-md-5 "}
        [:div#box_2
         [:div.col-md-12.block
@@ -206,14 +225,16 @@
                                                              (conj r [:a {:href (path-for "/badge")} [:img {:src (str "/" (:image_file badge)) :alt (:name badge) :title (:name badge)}]])
                                                              ) [:div] (take 5 (:pending-badges @state)))
                                                    )])
-           [:div.badges
-            [:p.header (t :social/Lastestearnedbadges)]
-            (reduce (fn [r badge]
-                      (conj r [:a {:href "#" :on-click #(do
-                                                          (.preventDefault %)
-                                                          (mo/open-modal [:badge :info] {:badge-id (:id badge )} {:hidden (fn [] (init-dashboard state))}))} [:img {:src (str "/" (:image_file badge)) :alt (:name badge) :title (:name badge)}]])
-                      ) [:div] badges)
-            ]
+           (if welcome-tip
+             [:div.pending [:p.header (str (t :social/Youdonthaveanyanybadgesyet) ".")]]
+             [:div.badges
+              [:p.header (t :social/Lastestearnedbadges)]
+              (reduce (fn [r badge]
+                        (conj r [:a {:href "#" :on-click #(do
+                                                            (.preventDefault %)
+                                                            (mo/open-modal [:badge :info] {:badge-id (:id badge )} {:hidden (fn [] (init-dashboard state))}))} [:img {:src (str "/" (:image_file badge)) :alt (:name badge) :title (:name badge)}]])
+                        ) [:div] badges)
+              ])
            [latest-earnable-badges]]]]]])))

 (defn explore-block [state]
@@ -288,7 +309,8 @@
             ]]]]]]]]]])

 (defn profile-block [state]
-  (let [user (:user-profile @state)]
+  (let [user (:user-profile @state)
+        profile-picture-tip (get-in @state [:tips :profile-picture-tip])]
     [:div.box.col-md-3
      [:div {:id "box_3"}
       [:div.col-md-12.block
@@ -296,7 +318,7 @@
         [:div.heading_1
          [:i.fa.fa-user.icon]
          [:a {:href (str (path-for "/user/profile/" ) (get-in user [:user :id]))}[:span.title
-          (t :user/Profile)]]]
+                                                                                (t :user/Profile)]]]
         [:div.content
          (when-not (not-activated?) [:a.btn.button {:href (path-for "/user/edit/profile")} (t :page/Edit)])
          [:div.visibility
@@ -305,7 +327,7 @@
             "internal" [:div [:i.fa.fa-eye-slash.icon ] [:span.text (t :core/Internal)]]
             nil)]

-         [:div
+         [:div.row
           [:img.img-rounded {:src (profile-picture (get-in user [:user :profile_picture]))}]
           [:div.stats
            [:div.text
@@ -313,7 +335,10 @@
             [:p.desc (t :page/Pages)]]
            [:div.text
             [:p.num (:files_count @state)]
-            [:p.desc (t :file/Files)]]]]]]]]]))
+            [:p.desc (t :file/Files)]]]]
+          [:br]
+          [:div.row.small-text ;{:style {:font-size "initial"}}
+           (when profile-picture-tip  [:p (str (t :social/Profilepicturebody) ".")])]]]]]]))

 (defn help-block [state]
   [:div {:class "box col-md-3"}
@@ -324,11 +349,12 @@
        [:i.fa.fa-info-circle.icon]
        [:span.title.help (t :core/Help)]]
       [:div.content
-       [:a {:href (str (path-for "/user/profile/") (session/get-in [:user :id]))}[:p (t :social/Iwanttoseeprofile)]]
+       [:p  {:style {:font-size "20px" :color "black"} } (t :social/Iwantto)]
+       [:div.content[:a {:href (str (path-for "/user/profile/") (session/get-in [:user :id]))}[:p (t :social/Iwanttoseeprofile)]]
        [:a {:href (str (path-for "/user/edit/profile"))}[:p (t :social/Iwanttoeditprofile)]]
        [:a {:href (str (path-for "/badge"))}[:p (t :social/Iwanttoseemysbadges)]]
        (when (some #(= % "extra/application") (session/get :plugins))[:p (t :social/Iwanttoearnnewbadges)])
-       [:a {:href (str (path-for "/gallery/badges"))} [:p (t :social/Iwanttofindbadges)]]]]]]])
+       [:a {:href (str (path-for "/gallery/badges"))} [:p (t :social/Iwanttofindbadges)]]]]]]]])

 (defn content [state]
   [:div#dashboard-container
@@ -347,7 +373,13 @@

 (defn handler [site-navi]
-  (let [state (atom {})]
+  (let [state (atom {:endorsing 0
+                     :endorsers 0
+                     :badges []
+                     :pending-endorsements 0
+                     :connections {:badges 0}
+                     :pages_count 0
+                     :files_count 0})]
     (init-dashboard state)
     (fn [] (layout/dashboard site-navi [content state]))))


:sparkles: Make persistence separatted from undo/redo.


solved problem 8

solved problem 8


Use one map for first line test strings.

--- nav_source_test.clj
+++ nav_source_test.clj
@@ -2,24 +2,38 @@
   (:use nav-source clojure.test))

 (def expected-first-line-tokens {:type "Table" :id 70902 :name "Test Table (48)"})
-(def valid-first-line "OBJECT Table 70902 Test Table (48)")
-(def invalid-first-line "OOBJECT Table 70902 Test Table (48)") ; see "OOBJECT"!
-(def first-line-of-right-structure-but-with-invalid-token "OBJECT Bird 70902 Test Table (48)")
-(def first-line-with-invalid-structure "OBJECT 70902 Table Test Table (48)")
-(def valid-last-line "}")
-(def invalid-last-line " }")

-(deftest matches-first-line-structure?__given-a-string-with-an-invalid-structure-for-a-first-line__should-return-false
-  (is (false? (matches-first-line-structure? first-line-with-invalid-structure))))
-(deftest matches-first-line-structure?__given-a-string-with-a-valid-structure-for-a-first-line__should-return-true
-  (is (true? (matches-first-line-structure? valid-first-line))))
+(def lines {:first {
+              :valid-structure {
+                :valid-tokens "OBJECT Table 70902 Test Table (48)"
+                :invalid-object-type "OBJECT Bird 70902 Test Table (48)"}
+              :invalid-structure {
+                :id-at-wrong-position "OBJECT 70902 Table Test Table (48)"
+                :wrong-start-token "OOBJECT Table 70902 Test Table (48)"}}
+            :last {
+              :valid "}"
+              :invalid " }"}})
+
+; matches-first-line-structure? tests
+(deftest matches-first-line-structure?__given-a-string-of-valid-structure-and-with-valid-tokens__should-return-true
+  (is (true? (matches-first-line-structure? (get-in lines [:first :valid-structure :valid-tokens])))))
+
+(deftest matches-first-line-structure?__given-a-string-with-id-at-wrong-position__should-return-false
+  (is (false? (matches-first-line-structure? (get-in lines [:first :invalid-structure :id-at-wrong-position])))))
+
+(deftest matches-first-line-structure?__given-a-string-of-valid-structure-but-with-an-invalid-object-type-token__should-return-true
+  (is (true? (matches-first-line-structure? (get-in lines [:first :valid-structure :invalid-object-type])))))
+
+(deftest matches-first-line-structure?__given-a-string-with-wrong-start-token__should-return-false
+  (is (false? (matches-first-line-structure? (get-in lines [:first :invalid-structure :wrong-start-token])))))

-
+; matches-last-line-structure? tests
 (deftest matches-last-line-structure?__given-a-valid-last-line__should-return-true
-  (is (true? (matches-last-line-structure? valid-last-line))))
+  (is (true? (matches-last-line-structure? (get-in lines [:last :valid])))))
+
 (deftest matches-last-line-structure?__given-an-invalid-last-line__should-return-false
-  (is (false? (matches-last-line-structure? invalid-last-line))))
+  (is (false? (matches-last-line-structure? (get-in lines [:last :invalid])))))

@@ -28,13 +42,13 @@

-(deftest first-line-tokens__given-a-valid-first-line__should-return-a-map-with-first-line-tokens
-  (let [tokens (first-line-tokens valid-first-line)]
+(deftest first-line-tokens__given-a-string-of-valid-structure__should-return-a-map-with-tokens
+  (let [tokens (first-line-tokens (get-in lines [:first :valid-structure :valid-tokens]))]
     (is (= expected-first-line-tokens tokens))))

 (deftest make-single-file-name__given-a-valid-map-of-first-line-tokens__should-return-a-string-for-a-uniquely-identifiable-filename
-  (is (= "1-Table-70902.txt" (make-single-file-name (first-line-tokens valid-first-line)))))
+  (is (= "1-Table-70902.txt" (make-single-file-name (first-line-tokens (get-in lines [:first :valid-structure :valid-tokens]))))))

 (run-tests 'nav-source-test)


Further fix last two commits. Wrap second arg in anon fn.

--- lein-light-nrepl/src/lighttable/nrepl/cljs.clj
+++ lein-light-nrepl/src/lighttable/nrepl/cljs.clj
@@ -472,12 +472,14 @@
           (with-compiler-env compiler-env
             (comp/with-core-cljs
               nil
-             (if-not (first forms)
-               (core/respond msg :editor.eval.cljs.no-op {})
-               (core/respond msg :editor.eval.cljs.code {:results (doall (for [f forms]
-                                                                           (eval-cljs env f)))
-                                                         :ns cljs/*cljs-ns*
-                                                         :meta (or meta {})}))))))
+              (fn []
+                (if-not (first forms)
+                  (core/respond msg :editor.eval.cljs.no-op {})
+                  (core/respond msg :editor.eval.cljs.code {:results (doall (for [f forms]
+                                                                              (eval-cljs env f)))
+                                                            :ns cljs/*cljs-ns*
+                                                            :meta (or meta {})})))
+             ))))
    (catch Exception e
       (let [ex (ex-data e)]
         (core/respond msg :editor.eval.cljs.exception {:stack (exception/clean-trace e)


better iPhone rendering of a-z

better iPhone rendering of a-z

--- src/checkmate/views/overview.clj
+++ src/checkmate/views/overview.clj
@@ -15,9 +15,9 @@
                 cls-link (keyword (if-not (= num-all num-done) "strong" "strong.checked"))]
             [(keyword (format "div#%s.row" (:_id i)))
              [:p
-              [:div.col-md-8
+              [:div.col-md-8.col-xs-6
                [cls-link (elm/link-to (str "/show/" (:_id i)) (str (:name i) "  (" num-done "/" num-all ")"))]]
-              [:div.col-md-4
+              [:div.col-md-4.col-xs-6
                [:div.btn-group
                 [:a {:class "btn btn-default btn-xs" :href (str "/edit/" (:_id i))} [:span.glyphicon.glyphicon-edit] "Edit"]
                 [:a {:class "btn btn-default btn-xs":href "#" :onclick (format "checkmate.views.overview.try_delete_list('%s', '%s');" (:_id i) (:name i))} [:span.glyphicon.glyphicon-trash] "Delete"]]]]]))])]))


Add link and adjust copy

Add link and adjust copy

--- src/clj/chili_dog_night/data.clj
+++ src/clj/chili_dog_night/data.clj
@@ -4,7 +4,7 @@
 (def gatherings [{:date "2016/02/03"
                   :address "3828 Meridian Ave N, Seattle, WA 98103, USA"
                   :synopsis "February 3rd, 2016: Jake's Birthday, War Room, and Divergent."
-                  :food ["Pagliacci"
+                  :food ["Cheese and Pepperoni Pizza from Pagliacci"
                          "Chips Ahoy! Chewy Chocolate Chip Cookies"
                          "Tillamook Chocolate Ice Cream"]
                   :attendees ["Alex Sanchez"
@@ -17,6 +17,8 @@
                   :media [{:title "War Room" :uri "http://www.imdb.com/title/tt3832914/"}
                           {:title "Divergent" :uri "http://www.imdb.com/title/tt1840309/"}]
                   :notes [:p
+                          (el/link-to "https://www.youtube.com/watch?v=wNNL9FIkF2E" "What if We Don't Want to Be Warm?")
+                          [:br]
                           (el/link-to "https://www.youtube.com/watch?v=pXRviuL6vMY&feature=youtu.be" "Blurryface")
                           " and "
                           (el/link-to "https://www.youtube.com/watch?v=Y_rl4ZGdy34&feature=youtu.be" "White Privilege, II")
@@ -54,7 +56,8 @@
                           [:br]
                           (el/link-to "https://en.wikipedia.org/wiki/Amusing_Ourselves_to_Death" "Amusing Ourselves to Death")
                           [:br]
-                          (el/link-to "http://www.jamonexperience.com/en/" "A different kind of Beast Feast (for Alex)")
+                          (el/link-to "http://www.jamonexperience.com/en/" "A different kind of Beast Feast")
+                          " (for Alex)"
                           [:br]
                           (el/link-to "http://www.beanogas.com/" "Possible remedy for Jason/Kaia")
                           [:br]


Add some comments for fun

Add some comments for fun

--- src/cljs/modern_cljs/modern.cljs
+++ src/cljs/modern_cljs/modern.cljs
@@ -2,7 +2,10 @@
   (:require [clojure.string :as string]
             [jquery] [ember]))

+;; set Ember as a variable so I don't have to
+;; type 'js/Ember' all the time.
 (def Ember js/Ember)
+
 (def HomeRoute
   (.extend (.-Route Ember)
     #js {:model
@@ -21,8 +24,12 @@

 (let [application (.create (.-Application Ember))
       router (.-Router application)]
+
+  ;; Attach route and component to the application
   (set! (.-HomeRoute application) HomeRoute)
   (set! (.-SmallComponentComponent application) SmallComponentComponent)
+
+  ;; Set up the router
   (.map router (fn []
                  (this-as r
                    (.route r "home" #js {:path "/"})


stale js is bad. very bad

stale js is bad. very bad

--- src/clojure/staircase/assets.clj
+++ src/clojure/staircase/assets.clj
@@ -123,7 +123,7 @@
 ;; Allow content to be cached
 (defn caching
   [{max-age :max-age}]
-  {"Cache-Control" (str "public,must-revalidate,max-age=" (or max-age 0))})
+  {"Cache-Control" (str "public,no-cache,must-revalidate,max-age=" (or max-age 0))})

 (defn generate-response [asset-file]
   (case (ext asset-file)


Don't toggle sidebar when clicking on reference (for demo)

--- src/discuss/references/main.cljs
+++ src/discuss/references/main.cljs
@@ -39,7 +39,7 @@
   [reference]
   (lib/change-view! :reference-dialog)
   (rlib/save-selected-reference! reference)
-  (sidebar/show)
+  #_(sidebar/show)
   (lib/update-state-item! :layout :reference (fn [_] (:text reference))))

@@ -70,7 +70,9 @@
                              :onClick #(save-statement-change-view data)}
                         (dom/strong nil (:text statement)))
                  (dom/div nil "Issue: " (:title issue))
-                 (dom/div nil "Author: " (:nickname author)))))))
+
+                 #_(dom/div nil "Author: " (:nickname author))
+                 )))))

 (defn usages-view
   "List with details showing the usages of the given reference."


Fix hardcoded upload type.

Fix hardcoded upload type.

--- src/kixi/hecuba/api/entities/upload.clj
+++ src/kixi/hecuba/api/entities/upload.clj
@@ -49,7 +49,7 @@
         uuid      (uuid)]
     (map (fn [{:keys [tempfile content-type filename]}]
            {:dest      :upload
-            :type      :images
+            :type      (keyword feed-name)
             :entity_id entity_id
             :src-name  "uploads"
             :feed-name feed-name


Allow buffer size of the audio chunker to be configured

--- src/main/audio_utils/audio_chunker.cljs
+++ src/main/audio_utils/audio_chunker.cljs
@@ -51,8 +51,16 @@
             (.process-sample this channel sample-val)))))))

 (defn audio-chunker
-  [{:keys [ctx samples on-chunk-ready] :as config}]
-  (let [node    (.createScriptProcessor ctx 4096 1 1)
+  [{:keys [ctx
+           buffer-size
+           samples
+           on-chunk-ready]
+    :or   {buffer-size 4096
+           samples     4410}}]
+  (let [node    (.createScriptProcessor ctx buffer-size 1 1)
+        config  {:ctx            ctx
+                 :samples        samples
+                 :on-chunk-ready on-chunk-ready}
         chunker (map->AudioChunker {:config  config
                                     :node    node
                                     :buffers (util/aatom [#js []


Autoshift: as for paredit, its behaviour can be prevented via Esc Key

--- ccw.core/src/clj/ccw/editors/clojure/PareditAutoAdjustWhitespaceStrategyImpl.clj
+++ ccw.core/src/clj/ccw/editors/clojure/PareditAutoAdjustWhitespaceStrategyImpl.clj
@@ -83,7 +83,9 @@
         locs (take-while continue-search (iterate next-node-loc loc))]
     (first (remove lu/whitespace? locs))))

-(defn noop-diff? [diff]
+(defn empty-diff?
+  "Is the text diff empty (nothing replaced and nothing added)?"
+  [diff]
   (and (zero? (:length diff))
        (zero? (count (:text diff)))))

@@ -100,55 +102,57 @@
 (defn customizeDocumentCommand
   "Work only if no command has been added via (.addCommand)"
   [^PareditAutoAdjustWhitespaceStrategy this, #^IDocument document, #^DocumentCommand command]
-  (let [^IClojureEditor editor (-> this .state deref :editor)
-        {:keys [parse-tree buffer]} (.getParseState editor)
-        text-before (lu/node-text parse-tree)
-        ;_ (println "text-before:" (str "'" text-before "'"))
-        parse-tree (-> buffer
-                     (p/edit-buffer (.offset command) (.length command) (.text command))
-                     (p/buffer-parse-tree 0))
-        text (lu/node-text parse-tree)
-        ;_ (println "text:" (str "'" text "'"))
-        offset (+ (.offset command) (count (.text command)))
-        offset-before (+ (.offset command) (.length command))
-        col (tu/col text offset)
-        delta (- col
-                 (tu/col text-before offset-before))
-       ; _ (println "delta:" delta)
-        rloc (lu/parsed-root-loc parse-tree)
-        loc (lu/loc-for-offset rloc offset)
-       ; _ (if loc (println "loc for offset:"
-       ;                    (pr-str (clean-tree (zip/node loc)))))
-        loc (if (or
-                  (= (lu/start-offset loc) offset)
-                  (whitespace-end-of-line? text offset))
-              loc
-              (next-node-loc loc))
-        loc (find-loc-to-shift loc)
-        ;_ (when-not loc (println "no loc found"))
-        ]
-    (when  loc
-      (let [col (- (lu/loc-col loc) delta)
-         ;   _ (println "final loc node:" (pr-str (clean-tree (zip/node loc))))
-         ;   _ (println "col" col)
-         ;   _ (println "(lu/loc-col loc)" (lu/loc-col loc))
-            [shifted-loc _] (lu/propagate-delta loc col delta)
-            shifted-text (lu/node-text (zip/root shifted-loc))
-            ;_ (println "shifted-text:" (with-out-str (pr shifted-text)))
-            ;_ (println "text        :" (with-out-str (pr text)))
-            loc-diff (tu/text-diff text shifted-text)
-            ;_ (println "loc-diff" (with-out-str (pr loc-diff)))
-            diff (update-in
-                   loc-diff
-                   [:offset] + (.length command) (- (count (.text command))))
-            ;_ (println "diff" (with-out-str (pr diff)))
-            ]
-        (when-not (noop-diff? loc-diff)
-          (.addCommand command
-            (:offset diff)
-            (:length diff)
-            (:text diff)
-            nil)
-          (set! (.shiftsCaret command) false)
-          (set! (.caretOffset command) offset))))))
+  (when (and (.doit command)
+             (not (.isInEscapeSequence editor)))
+    (let [^IClojureEditor editor (-> this .state deref :editor)
+          {:keys [parse-tree buffer]} (.getParseState editor)
+          text-before (lu/node-text parse-tree)
+          ;_ (println "text-before:" (str "'" text-before "'"))
+          parse-tree (-> buffer
+                       (p/edit-buffer (.offset command) (.length command) (.text command))
+                       (p/buffer-parse-tree 0))
+          text (lu/node-text parse-tree)
+          ;_ (println "text:" (str "'" text "'"))
+          offset (+ (.offset command) (count (.text command)))
+          offset-before (+ (.offset command) (.length command))
+          col (tu/col text offset)
+          delta (- col
+                   (tu/col text-before offset-before))
+        ; _ (println "delta:" delta)
+         rloc (lu/parsed-root-loc parse-tree)
+         loc (lu/loc-for-offset rloc offset)
+        ; _ (if loc (println "loc for offset:"
+        ;                    (pr-str (clean-tree (zip/node loc)))))
+         loc (if (or
+                   (= (lu/start-offset loc) offset)
+                   (whitespace-end-of-line? text offset))
+               loc
+               (next-node-loc loc))
+         loc (find-loc-to-shift loc)
+         ;_ (when-not loc (println "no loc found"))
+         ]
+      (when  loc
+        (let [col (- (lu/loc-col loc) delta)
+           ;   _ (println "final loc node:" (pr-str (clean-tree (zip/node loc))))
+           ;   _ (println "col" col)
+           ;   _ (println "(lu/loc-col loc)" (lu/loc-col loc))
+              [shifted-loc _] (lu/propagate-delta loc col delta)
+              shifted-text (lu/node-text (zip/root shifted-loc))
+              ;_ (println "shifted-text:" (with-out-str (pr shifted-text)))
+              ;_ (println "text        :" (with-out-str (pr text)))
+              loc-diff (tu/text-diff text shifted-text)
+              ;_ (println "loc-diff" (with-out-str (pr loc-diff)))
+              diff (update-in
+                     loc-diff
+                     [:offset] + (.length command) (- (count (.text command))))
+              ;_ (println "diff" (with-out-str (pr diff)))
+              ]
+          (when-not (empty-diff? loc-diff)
+            (.addCommand command
+              (:offset diff)
+              (:length diff)
+              (:text diff)
+              nil)
+            (set! (.shiftsCaret command) false)
+            (set! (.caretOffset command) offset)))))))


changed the ordering of dones returned by the retreive method to inverse. That simplifies the frontend work

--- src/done/db.clj
+++ src/done/db.clj
@@ -73,7 +73,7 @@
   [email]
   (try
     (let [rows (jdbc/query mysql (sql/select * :done (sql/where
-       {:email email}) (sql/order-by :date)))]
+        {:email email}) (sql/order-by {:date :desc})))]
       (if (empty? rows)
         {:status "ok" :rows []}
         {:status "ok" :rows rows}))


get rhs joined and unjoined models into position

--- dada2-core/src/test/clojure/org/dada2/test_join_model.clj
+++ dada2-core/src/test/clojure/org/dada2/test_join_model.clj
@@ -213,23 +213,24 @@
         old-lhs (lhs-get old-lhs-index key)
         tmp-lhs-indeces (if old-lhs (lhs-dissoc old-lhs-index lhs-pk-key lhs-fk-keys old-lhs) old-lhs-index)
         new-lhs-indeces (lhs-assoc tmp-lhs-indeces lhs-pk-key lhs-fk-keys lhs)
-        d-joins (vals (get-lhs-join-map old-joins key))
-	u-joins (lhs-join rhs-indeces lhs-fk-keys lhs join-fn)
-        tmp-joins (if old-lhs (dissoc-joins old-joins join-pk d-joins) old-joins)
-	new-joins (assoc-joins tmp-joins join-pk u-joins)]
+        stale-joins (vals (get-lhs-join-map old-joins key))
+	fresh-joins (lhs-join rhs-indeces lhs-fk-keys lhs join-fn)
+        tmp-joins (if old-lhs (dissoc-joins old-joins join-pk stale-joins) old-joins)
+	new-joins (assoc-joins tmp-joins join-pk fresh-joins)]
     [[new-lhs-indeces rhs-indeces new-joins]
      (fn [_]
-       (on-deletes joined-model d-joins)
-       (on-upserts joined-model u-joins))]))
+       (on-deletes joined-model stale-joins)
+       (on-upserts joined-model fresh-joins)
+       )]))

 (defn- lhs-delete [[old-lhs-indeces rhs-indeces old-joins] lhs-pk-key lhs-fk-keys lhs join-fn join-pk joined-model lhs-joined-model lhs-unjoined-model]
   (let [new-lhs-indeces (lhs-dissoc old-lhs-indeces lhs-pk-key lhs-fk-keys lhs)
         key (lhs-pk-key lhs)
-        joins (vals (get-lhs-join-map old-joins key))
-	new-joins (dissoc-joins old-joins join-pk joins)]
+        stale-joins (vals (get-lhs-join-map old-joins key))
+	new-joins (dissoc-joins old-joins join-pk stale-joins)]
     [[new-lhs-indeces rhs-indeces new-joins]
      (fn [_]
-       (on-deletes joined-model joins))]))
+       (on-deletes joined-model stale-joins))]))

 ;;; TODO
 (defn- lhs-upserts [old-indeces i ks vs join-fn])
@@ -249,40 +250,46 @@
    (on-upserts [_ upsertions] (swap! indeces lhs-upserts lhs-fk-keys upsertions join-fn) nil)
    (on-deletes [_ deletions]  (swap! indeces lhs-deletes lhs-fk-keys deletions join-fn) nil)))

-(defn- rhs-upsert [[lhs-indeces old-rhs-indeces old-joins] i rhs-pk-key rhs-fk-key lhs-fk-keys rhs join-fn join-pk joined-model]
+(defn- rhs-upsert [[lhs-indeces old-rhs-indeces old-joins] i rhs-pk-key rhs-fk-key lhs-fk-keys rhs join-fn join-pk joined-model rhs-joined-model rhs-unjoined-model]
   (let [pk (rhs-pk-key rhs)
         old-rhs (rhs-get old-rhs-indeces i pk)
         tmp-rhs-indeces (if old-rhs (rhs-dissoc old-rhs-indeces i rhs-pk-key (rhs-fk-key old-rhs) old-rhs) old-rhs-indeces)
         fk (rhs-fk-key rhs)
 	new-rhs-indeces (rhs-assoc tmp-rhs-indeces i rhs-pk-key fk rhs)
         key (rhs-pk-key rhs)
-        d-joins (vals (get-rhs-join-map old-joins i key))
-	u-joins (rhs-join new-rhs-indeces lhs-fk-keys join-fn lhs-indeces i fk)
-	new-joins (assoc-joins (dissoc-joins old-joins join-pk d-joins) join-pk u-joins)]
-    [[lhs-indeces new-rhs-indeces new-joins] (fn [_] (on-deletes joined-model d-joins)(on-upserts joined-model u-joins))]
+        stale-joins (vals (get-rhs-join-map old-joins i key))
+	fresh-joins (rhs-join new-rhs-indeces lhs-fk-keys join-fn lhs-indeces i fk)
+	new-joins (assoc-joins (dissoc-joins old-joins join-pk stale-joins) join-pk fresh-joins)]
+    [[lhs-indeces new-rhs-indeces new-joins]
+     (fn [_]
+       (on-deletes joined-model stale-joins)
+       (on-upserts joined-model fresh-joins))]
     ))

 ;;; TODO - ugly, slow, ...
 (defn- rhs-delete [[lhs-indeces old-rhs-indeces old-joins]
-		   i rhs-pk-key rhs-fk-key lhs-fk-keys rhs join-fn join-pk joined-model]
+		   i rhs-pk-key rhs-fk-key lhs-fk-keys rhs join-fn join-pk joined-model rhs-joined-model rhs-unjoined-model]
   (let [fk (rhs-fk-key rhs)
 	new-rhs-indeces (rhs-dissoc old-rhs-indeces i rhs-pk-key fk rhs)
         key (rhs-pk-key rhs)
-        joins (vals (get-rhs-join-map old-joins i key))
-	new-joins (dissoc-joins old-joins join-pk joins)]
-    [[lhs-indeces new-rhs-indeces new-joins] (fn [_] (on-deletes joined-model joins))]
+        stale-joins (vals (get-rhs-join-map old-joins i key))
+	new-joins (dissoc-joins old-joins join-pk stale-joins)]
+    [[lhs-indeces new-rhs-indeces new-joins]
+     (fn [_]
+       (on-deletes joined-model stale-joins))]
     ))

 ;;; TODO
 (defn- rhs-upserts [old-indeces i ks vs join-fn])
 (defn- rhs-deletes [old-indeces i ks vs join-fn])

-(defn- rhs-view [indeces i rhs-pk-key rhs-fk-key lhs-fk-keys join-fn join-pk joined-model]
+(defn- rhs-view [indeces i rhs-pk-key rhs-fk-key lhs-fk-keys join-fn join-pk joined-model rhs-joined-model rhs-unjoined-model]
   (reify
    View
    ;; singleton changes
-   (on-upsert [_ upsertion] ((swap*! indeces rhs-upsert i rhs-pk-key rhs-fk-key lhs-fk-keys upsertion join-fn join-pk joined-model) []) nil) ;TODO: pass in views to notifier
-   (on-delete [_ deletion]  ((swap*! indeces rhs-delete i rhs-pk-key rhs-fk-key lhs-fk-keys deletion  join-fn join-pk joined-model) []) nil) ;TODO: pass in views to notifier
+   (on-upsert [_ upsertion]
+     ((swap*! indeces rhs-upsert i rhs-pk-key rhs-fk-key lhs-fk-keys upsertion join-fn join-pk joined-model rhs-joined-model rhs-unjoined-model) []) nil) ;TODO: pass in views to notifier
+   (on-delete [_ deletion]  ((swap*! indeces rhs-delete i rhs-pk-key rhs-fk-key lhs-fk-keys deletion  join-fn join-pk joined-model rhs-joined-model rhs-unjoined-model) []) nil) ;TODO: pass in views to notifier
    ;; batch changes
    (on-upserts [_ upsertions] (swap! indeces rhs-upserts i lhs-fk-keys upsertions join-fn) nil)
    (on-deletes [_ deletions]  (swap! indeces rhs-deletes i lhs-fk-keys deletions join-fn) nil)))
@@ -302,12 +309,10 @@
      (lhs-view indeces lhs-pk-key lhs-fk-keys join-fn join-pk joined-model lhs-joined-model lhs-unjoined-model))
     ;; view rhses
     (doall
-     (mapv
-      (fn [[rhs-model rhs-pk-key rhs-fk-key rhs-initial-state] i]
-        (log2 :info (str " rhs: " rhs-model ", " i ", " rhs-fk-key))
-        ;; view rhs model
-        (attach rhs-model (rhs-view indeces i rhs-pk-key rhs-fk-key lhs-fk-keys join-fn join-pk joined-model))
-        [{} (or rhs-initial-state {})])
+     (map
+      (fn [[rhs-model rhs-pk-key rhs-fk-key rhs-initial-state rhs-joined-model rhs-unjoined-model] i]
+        (attach rhs-model (rhs-view indeces i rhs-pk-key rhs-fk-key lhs-fk-keys join-fn join-pk joined-model rhs-joined-model rhs-unjoined-model))
+        )
       rhses
       (range)))
     indeces))
@@ -370,12 +375,14 @@
 	joined-model (versioned-optimistic-map-model (str :joined) :name :version abc-more-recent-than?)
 	as-joined-model (versioned-optimistic-map-model (str :as-joined) :name :version >)
 	as-unjoined-model (versioned-optimistic-map-model (str :as-unjoined) :name :version >)
+	a-b-joined-model (versioned-optimistic-map-model (str :a-b-joined) :name :version >)
+	a-b-unjoined-model (versioned-optimistic-map-model (str :a-b-unjoined) :name :version >)
 	joined-model (versioned-optimistic-map-model (str :joined) :name :version abc-more-recent-than?)
 	join (join-model
               "join-model"
               joined-model
               [[as :name [:fk-b :fk-c] as-joined-model as-unjoined-model]
-               [bs :name :b]
+               [bs :name :b {} a-b-joined-model a-b-unjoined-model]
                [cs :name :c]]
               join-abc :name)
 	view (test-view "test")


hacky fix - should probably clean this up

--- src/dynamodb_expression/core.clj
+++ src/dynamodb_expression/core.clj
@@ -1,7 +1,7 @@
 (ns dynamodb-expression.core
   (:require [clojure.string :as st]))

-(defn sanitize-placeholder [ph]
+(defn- sanitize-placeholder [ph]
   (st/replace ph #"[^0-9a-zA-Z_]" "_"))

 (defn update-expr []
@@ -58,9 +58,8 @@
        (group-by :op)
        (into (sorted-map))
        (reduce (fn [ex [op ops]]
-                 (prn '>> ops)
                  (->> ops
-                      (map :expr-part)
+                      (keep :expr-part)
                       (st/join ", ")
                       (str ex (when ex " ") (st/upper-case (name op)) " ")))
                nil)))
@@ -68,7 +67,7 @@
 (defn- attr-map [name-or-value key ops]
   (->> ops
        (map (juxt name-or-value key))
-       ;; (remove #(some nil? %))
+       (clojure.core/remove #(-> % first nil?))
        (into {})))

 (defn expr [{:keys [ops] :as expr}]


Updates armstrong-numbers to 1.1.0

Updates armstrong-numbers to 1.1.0

--- exercises/armstrong-numbers/test/armstrong_numbers_test.clj
+++ exercises/armstrong-numbers/test/armstrong_numbers_test.clj
@@ -1,6 +1,10 @@
 (ns armstrong-numbers-test
   (:require [clojure.test :refer [deftest is testing]]
             [armstrong-numbers :refer [armstrong?]]))
+
+(deftest armstrong-number-0
+  (testing "Zero is an Armstrong number"
+    (is (armstrong? 0))))

 (deftest armstrong-number-5
   (testing "Single digit numbers are Armstrong numbers"


Test that the cipher opposite direction rotation.

A true rotational cipher does not care whether one rotates forwards or backwards.  The solution should be tested for this case.

--- exercises/rotational-cipher/test/rotational_cipher_test.clj
+++ exercises/rotational-cipher/test/rotational_cipher_test.clj
@@ -29,6 +29,9 @@

   (testing "rotate punctuation"
     (is (= (rotational-cipher/rotate "Let's eat, Grandma!" 21) "Gzo'n zvo, Bmviyhv!")))
+
+  (testing "rotate in the opposite direction"
+    (is (= (rotational-cipher/rotate "b" -1) "a")))

   (testing "rotate all letters"
     (is (= (rotational-cipher/rotate "The quick brown fox jumps over the lazy dog." 13) "Gur dhvpx oebja sbk whzcf bire gur ynml qbt."))))


fixed validation

fixed validation

--- s3/src/s3/webutil.clj
+++ s3/src/s3/webutil.clj
@@ -30,16 +30,16 @@

 (defn json-resp [data & status]
   (if data
-    {:status (or status 200)
+    {:status 200
      :headers {"Content-Type" "application/json"}
      :body (generate-string data)}
-    {:status (or status 400)
+    {:status 400
      :headers {"Content-Type" "application/json"}
      :body "Invalid request."}))

 (defmacro no-auth [data & [status]]
   `(try
-     (json-resp ~data ~status)
+     (json-resp ~data)
      (catch Exception ex#
        (error-status ex#))))


Fix layout of tags in thread header when many tags

--- src/braid/core/client/ui/styles/thread.cljs
+++ src/braid/core/client/ui/styles/thread.cljs
@@ -16,7 +16,7 @@
     :box-sizing "border-box"}

    [:>.tags
-    {:display "inline-block"}
+    {:display "inline"}

     [:>.add
      {:position "relative"}


Clean up

Clean up

--- src/cljs/whatishistory/core.cljs
+++ src/cljs/whatishistory/core.cljs
@@ -6,28 +6,9 @@

 (enable-console-print!)

-;; -------------------------
-;; Parse Utilities
-
-; (def definition (js/Parse.Object.extend "Definition"))
-
-; (def query (js/Parse.Query. definition))
-;
-; (.find query #js {:success (fn [result] (js/console.log result))
-;                   :error #(js/console.log %2)})
-
-; ((js/Parse.Cloud.run "getDefnCount"
-;                      ""
-;                      #js {:success (fn [result] (js/console.log result))
-;                           :error #(js/console.log %2)})))
-
 (def app-atom (reagent/atom {}))
 (def countries-list js/window.countries)
 (def ^:const parse-defn-class "Definition")
-
-; (defmacro handler-fn
-;   ([& body]
-;     `(fn [~'event] ~@body nil)))  ; always return nil

 (defn parse-init []
   (js/Parse.initialize


Add tests for A-0 and A-1

Add tests for A-0 and A-1

--- test/hydrofoil/expectations/model.clj
+++ test/hydrofoil/expectations/model.clj
@@ -224,3 +224,8 @@
 (expect 2.1932
         (round-double (coefficient-of-lift (NACA-design 0 0.5 10) (run-constants 0 0 20))))

+;;;-------- coefficient-of-lift-Components ---------
+(expect -0.0045
+        (round-double (A-0 (NACA-design 2 4 12) (run-constants 0 0 0))))
+(expect 0.0815
+        (round-double (A-1 (NACA-design 2 4 12) (run-constants 0 0 0))))


Add metrics to the test run

Add metrics to the test run

--- test/onyx/metrics/throughput_test.clj
+++ test/onyx/metrics/throughput_test.clj
@@ -5,6 +5,7 @@
             [onyx.lifecycle.metrics.throughput]
             [onyx.lifecycle.metrics.latency]
             [onyx.lifecycle.metrics.timbre]
+            [onyx.lifecycle.metrics.websocket]
             [onyx.api]))

 (def id (java.util.UUID/randomUUID))
@@ -92,6 +93,12 @@
     :lifecycle/doc "Instruments a task's latency metrics per batch"}

    {:lifecycle/task :inc
+    :lifecycle/calls :onyx.lifecycle.metrics.websocket/calls
+    :websocket/address "ws://127.0.0.1:3000/metrics"
+    :websocket/interval-ms 2000
+    :lifecycle/doc "Sends metric data to a websocket."}
+
+   {:lifecycle/task :inc
     :lifecycle/calls :onyx.lifecycle.metrics.timbre/calls
     :timbre/interval-ms 2000
     :lifecycle/doc "Prints task metrics to Timbre every 2000 ms"}
@@ -127,4 +134,4 @@

 (onyx.api/shutdown-peer-group peer-group)

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


WIP for HashCollision node kv removal

WIP for HashCollision node kv removal

--- src/main/cljs/lean_map/core.cljs
+++ src/main/cljs/lean_map/core.cljs
@@ -221,6 +221,24 @@
       (cond (< idx 0)              not-found
             (key-test key (aget arr idx)) [(aget arr idx) (aget arr (inc idx))]
             :else                  not-found)))
+
+  (inode-without [inode wedit shift hash key changed?]
+    (let [idx (hash-collision-node-find-index arr cnt key)]
+      (if (== idx -1)
+        inode
+        (do
+          (set! (.-modified changed?) true)
+          (case cnt
+           1 (.-EMPTY BitmapIndexedNode)
+           2 (.inode_assoc (.-EMPTY BitmapIndexedNode) wedit shift hash
+                            (aget arr idx) (aget arr (inc idx))
+                            changed?)
+           (let [i (quot idx 2)
+                 new-arr (make-array (- (alength arr) 2))]
+             (array-copy arr 0 new-arr 0 (* 2 i))
+             (array-copy arr (* 2 (inc i)) new-arr (* 2 i) (- (alength new-arr) (* 2 i)))
+             (HashCollisionNode. wedit hash (dec cnt) new-arr)))))))
+
   (single-kv? [_]
     false))


Fix kw call.

Fix kw call.

--- src/onyx/peer/task_lifecycle.clj
+++ src/onyx/peer/task_lifecycle.clj
@@ -175,7 +175,7 @@
                       results-by-acker))]
       (measure-latency
        #(extensions/internal-ack-messages messenger event link acks)
-       #(extensions/emit (:onyx.core/monitoring) {:event :peer/ack-messages :latency %}))))
+       #(extensions/emit (:onyx.core/monitoring event) {:event :peer/ack-messages :latency %}))))
   event)

 (defn flow-retry-messages [replica state messenger {:keys [onyx.core/results] :as event}]
@@ -185,7 +185,7 @@
             link (operation/peer-link @replica state event (:completion-id root))]
         (measure-latency
          #(extensions/internal-retry-message messenger event (:id root) link)
-         #(extensions/emit (:onyx.core/monitoring) {:event :peer/retry-message :latency %})))))
+         #(extensions/emit (:onyx.core/monitoring event) {:event :peer/retry-message :latency %})))))
   event)

 (defn inject-batch-resources [compiled-before-batch-fn pipeline event]
@@ -237,14 +237,14 @@
   (when (sentinel-found? event)
     (if (p-ext/drained? pipeline event)
       (do (complete-job event)
-          (extensions/emit (:onyx.core/monitoring) {:event :peer/try-complete-job}))
+          (extensions/emit (:onyx.core/monitoring event) {:event :peer/try-complete-job}))
       (p-ext/retry-message pipeline event (sentinel-id event))))
   event)

 (defn strip-sentinel
   [event]
   (if (= (:onyx/type (:onyx.core/task-map event)) :input)
-    (do (extensions/emit (:onyx.core/monitoring) {:event :peer/strip-sentinel})
+    (do (extensions/emit (:onyx.core/monitoring event) {:event :peer/strip-sentinel})
         (update-in event
                    [:onyx.core/batch]
                    (fn [batch]
@@ -335,7 +335,7 @@
                         peer-link (operation/peer-link @replica state event peer-id)]
                     (measure-latency
                      #(extensions/internal-complete-message messenger event id peer-link)
-                     #(extensions/emit (:onyx.core/monitoring) {:event :peer/complete-message :latency %})))
+                     #(extensions/emit (:onyx.core/monitoring event) {:event :peer/complete-message :latency %})))

                   (= ch retry-ch)
                   (->> (p-ext/retry-message pipeline event v)


List out the ignored tests at the end

List out the ignored tests at the end

--- src/radicalzephyr/boot_junit.clj
+++ src/radicalzephyr/boot_junit.clj
@@ -49,7 +49,8 @@
        set))

 (defn- run-listener [packages]
-  (let [running-tests (atom #{})]
+  (let [running-tests (atom #{})
+        ignored-tests (atom #{})]
     (proxy [RunListener]
         []
       (testRunStarted [description]
@@ -57,7 +58,14 @@
                  (str/join ", " packages)))

       (testRunFinished [result]
-        (println "\nTest run finished!")
+        (println "\n")
+        (when @ignored-tests
+          (println "Ignored:")
+          (println)
+          (doseq [ignored @ignored-tests]
+            (println (style (.getDisplayName ignored) :yellow))
+            (println)))
+
         (when (> (.getFailureCount result) 0)
           (println (result->map result))))

@@ -65,6 +73,7 @@
         (swap! running-tests conj description))

       (testIgnored [description]
+        (swap! ignored-tests conj description)
         (print (style "*" :yellow)))

       (testFinished [description]


Fixed call to sensors/delete-measurements

This brings this utility in line with the other hierarchical delete
functions.

--- src/kixi/hecuba/data/devices.clj
+++ src/kixi/hecuba/data/devices.clj
@@ -72,7 +72,7 @@
 (defn delete-measurements [session device_id]
   (doall (->> (sensors/get-sensors device_id session)
               (map :type)
-              (map #(sensors/delete-measurements session device_id %)))))
+              (map #(sensors/delete-measurements session {:device_id device_id :type %})))))

 (defn delete-sensors [device_id measurements? session]
   (let [sensors         (sensors/get-sensors device_id session)


Remove sorting from autocomplete results - takes ~300ms

--- src/lt/objs/sidebar/command.cljs
+++ src/lt/objs/sidebar/command.cljs
@@ -235,7 +235,9 @@
             score1 (.. score0  (map map-func) (sort score-sort))
             score2 (.. score1 (slice 0 50) (map map-func2) (filter has-score) (sort score-sort2))]
         score2)
-      (.. items (map #(array % (key %) nil nil)) (sort #(.localeCompare (second %) (second %2)))))))
+      (.. items (map #(array % (key %) nil nil))))))
+
+

 (defui item [this x]
   [:li {:index x}]


Renameja

Renameja

--- clj-test-utils/src/clj_test_utils/elasticsearch_docker_utils.clj
+++ clj-test-utils/src/clj_test_utils/elasticsearch_docker_utils.clj
@@ -4,7 +4,7 @@
     [robert.hooke :refer [add-hook]]
     [clojure.java.shell :refer [sh]]))

-(defn- stop-docker-elastic []
+(defn- stop-elasticsearch []
   (sh "docker" "kill" "kouta-elastic"))

 (defn- elastic-has-started? [elastic-ip]
@@ -19,7 +19,7 @@
       (Thread/sleep 1000)
       (recur (- tries 1)))))

-(defn- init-docker-elastic []
+(defn- start-elasticsearch []
   (let [port (find-free-local-port)
         elastic-ip (str "http://127.0.0.1:" port)
         elastic-docker-ip (str "127.0.0.1:" port ":9200")]
@@ -33,8 +33,8 @@
   (defn- run-tests-hook
     [f & nss]
     (let [embedded-elasticsearch? (find-ns 'clj-elasticsearch.elastic-utils)]
-      (when embedded-elasticsearch? (init-docker-elastic))
+      (when embedded-elasticsearch? (start-elasticsearch))
       (let [result (apply f nss)]
-        (when embedded-elasticsearch? (stop-docker-elastic))
+        (when embedded-elasticsearch? (stop-elasticsearch))
         result)))
   (add-hook #'clojure.test/run-tests #'run-tests-hook))


ArrayBuilder now has a getAt method

ArrayBuilder now has a getAt method

--- src/transit.clj
+++ src/transit.clj
@@ -139,6 +139,7 @@
     (init [_] (transient []))
     (init [_ ^int size] (transient []))
     (add [_ ab item] (conj! ab item))
+    (getAt [_ ab index] (nth ab index))
     (^java.util.List array [_ ab] (persistent! ab))))

 (deftype Reader [r])


Minor tidy

Minor tidy

--- go-fighweel/src/cloj/core.cljc
+++ go-fighweel/src/cloj/core.cljc
@@ -23,23 +23,18 @@

 (def quit-keys [:key-escape :key-q])

-(defn any-keys-pressed? [ks keypfn]
-  (reduce (fn [r v]
-            (or r
-                (keypfn v)))
-          false
-          ks)
-  )
+(defn any-keys-pressed? [keypfn ks]
+  (->
+    (fn [r v]
+      (or r (keypfn v)))
+    (reduce false ks)))

-(defn any-quit-keys-pressed? [keypfn]
-  (any-keys-pressed? quit-keys keypfn))
+(defn any-quit-keys-pressed? [keypfn] (any-keys-pressed? keypfn quit-keys))

 (defn draw-frame [r t]
   (do
     (clear! r (funny-col t))
-    (box! r (v2 10 10) (v2 100 100) [0 0 0 1])
-    )
-  )
+    (box! r (v2 10 10) (v2 100 100) [0 0 0 1])))

 (defn main [sys]
   (let [window (sys-p/get-window sys)


Refactor common code into a fixture

Refactor common code into a fixture

--- test/clj/coffee_table/resource_test.clj
+++ test/clj/coffee_table/resource_test.clj
@@ -16,6 +16,8 @@
             [cheshire.core :refer [parse-string]]
             [byte-streams :as bs :refer [convert]]))

+(def ^:dynamic *handler*)
+
 (def config (ctcfg/config (keyword (env :clj-profile))))

 (defn test-system
@@ -28,10 +30,17 @@
     :visits (sut/new-visits))
    {:visits {:db :db}}))

+(defn include-handler [f]
+  (let [visits (:visits cts/*system*)
+        handler (make-handler (vhosts-model [:* (sut/visit-routes visits)]))]
+    (binding [*handler* handler]
+      (f))))
+
 (t/use-fixtures :once schema.test/validate-schemas)
 (t/use-fixtures :each
   (cts/with-system-fixture test-system)
-  (cts/with-transaction-fixture [:visits :db :spec]))
+  (cts/with-transaction-fixture [:visits :db :spec])
+  include-handler)

 (s/def example-visit :- m/Visit
   "Minimally-defined visit for our testing purposes"
@@ -39,11 +48,9 @@

 (deftest create-visits-valid-data
   (testing "POST /visits (valid data)"
-    (let [visits (:visits cts/*system*)
-          handler (make-handler (vhosts-model [:* (sut/visit-routes visits)]))
-          data example-visit
+    (let [data example-visit
           request (mock/json-body (mock/request :post "/visits") data)
-          response @(handler request)]
+          response @(*handler* request)]
       (is (= 201 (:status response)))
       (is (contains? (:headers response) "location"))
       (is (not (nil? (re-matches #"/visits/(\d+)"
@@ -51,30 +58,24 @@

 (deftest create-visits-invalid-data
   (testing "POST /visits (invalid data)"
-    (let [visits (:visits cts/*system*)
-          handler (make-handler (vhosts-model [:* (sut/visit-routes visits)]))
-          request (mock/json-body (mock/request :post "/visits") {})
-          response @(handler request)]
+    (let [request (mock/json-body (mock/request :post "/visits") {})
+          response @(*handler* request)]
       (is (= 400 (:status response))))))

 (deftest list-visits-no-entries-yet
   (testing "GET /visits (no entries yet)"
-    (let [visits (:visits cts/*system*)
-          handler (make-handler (vhosts-model [:* (sut/visit-routes visits)]))
-          request (mock/json-body (mock/request :get "/visits") {})
-          response @(handler request)]
+    (let [request (mock/json-body (mock/request :get "/visits") {})
+          response @(*handler* request)]
       (is (= 200 (:status response)))
       (is (= {:data []} (parse-string (bs/to-string (:body response)) keyword))))))

 (deftest list-visits-entries-exist
   (testing "Get /visits (a couple of entries)"
-    (let [visits (:visits cts/*system*)
-          handler (make-handler (vhosts-model [:* (sut/visit-routes visits)]))
-          numtimes 2
+    (let [numtimes 2
           _ (dotimes [_ numtimes]
-              @(handler (mock/json-body (mock/request :post "/visits") example-visit)))
+              @(*handler* (mock/json-body (mock/request :post "/visits") example-visit)))
           list-request (mock/request :get "/visits")
-          list-response @(handler list-request)
+          list-response @(*handler* list-request)
           list-body (:data (parse-string (bs/to-string (:body list-response)) keyword))]
       (is (= 200 (:status list-response)))
       (is (= numtimes (count list-body)))
@@ -84,24 +85,18 @@

 (deftest get-visit-id-does-not-exist
   (testing "GET /visits/<someid> (nonexistant entity)"
-    (let [visits (:visits cts/*system*)
-          handler (make-handler (vhosts-model [:* (sut/visit-routes visits)]))
-          request (mock/request :get "/visits/9999")
-          response @(handler request)]
+    (let [request (mock/request :get "/visits/9999")
+          response @(*handler* request)]
       (is (= 404 (:status response))))))

 (deftest get-visits-id-exists
   (testing "GET /visits/<someid> (existing entry)"
-    (let [visits (:visits cts/*system*)
-          visit-routes (vhosts-model [:* (sut/visit-routes visits)])
-          create-handler (make-handler visit-routes)
-          data example-visit
+    (let [data example-visit
           create-request (mock/json-body (mock/request :post "/visits") data)
-          create-response @(create-handler create-request)
-          get-handler (make-handler visit-routes)
+          create-response @(*handler* create-request)
           get-request (mock/request :get (get-in create-response [:headers "location"]))
           get-response (-> get-request
-                           get-handler
+                           *handler*
                            deref
                            :body
                            bs/to-string
@@ -111,24 +106,18 @@

 (deftest update-visits-entry-exists
   (testing "PUT /visits/<id> (<id> existed already)"
-    (let [visits (:visits cts/*system*)
-          visit-routes (vhosts-model [:* (sut/visit-routes visits)])
-          handler (make-handler visit-routes)
-          create-request (mock/json-body (mock/request :post "/visits") example-visit)
-          location (get-in @(handler create-request) [:headers "location"])
+    (let [create-request (mock/json-body (mock/request :post "/visits") example-visit)
+          location (get-in @(*handler* create-request) [:headers "location"])
           put-body (assoc example-visit :cafe_name "Updated Café")
           put-request (mock/json-body (mock/request :put location) put-body)
-          put-response @(handler put-request)]
+          put-response @(*handler* put-request)]
       (is (= 204 (:status put-response))))))

 (deftest update-visits-entry-does-not-exist
   (testing "PUT /visits/<id> (<id> doesn't exist)"
-    (let [visits (:visits cts/*system*)
-          visit-routes (vhosts-model [:* (sut/visit-routes visits)])
-          put-handler (make-handler visit-routes)
-          put-body (-> example-visit (assoc :id 0) (assoc :cafe_name "Updated Café"))
+    (let [put-body (-> example-visit (assoc :id 0) (assoc :cafe_name "Updated Café"))
           put-request (mock/json-body (mock/request :put "/visits/0") put-body)
-          put-response @(put-handler put-request)]
+          put-response @(*handler* put-request)]
       (is (= 404 (:status put-response))))))

 (deftest update-visits-invalid-data
@@ -145,24 +134,18 @@

 (deftest delete-visits-id-exists
     (testing "DELETE /visits/<someid> (existing entry)"
-      (let [visits (:visits cts/*system*)
-            visit-routes (vhosts-model [:* (sut/visit-routes visits)])
-            handler (make-handler visit-routes)
-            create-request (mock/json-body (mock/request :post "/visits") example-visit)
-            create-response @(handler create-request)
+      (let [create-request (mock/json-body (mock/request :post "/visits") example-visit)
+            create-response @(*handler* create-request)
             location (get-in create-response [:headers "location"])
             delete-request (mock/request :delete location)
-            delete-response @(handler delete-request)
+            delete-response @(*handler* delete-request)
             get-request (mock/request :get location)
-            get-response @(handler get-request)]
+            get-response @(*handler* get-request)]
         (is (= 204 (:status delete-response)))
         (is (= 404 (:status get-response))))))

 (deftest delete-visits-id-does-not-exist
   (testing "DELETE /visits/<id> (<id> doesn't exist)"
-    (let [visits (:visits cts/*system*)
-          visit-routes (vhosts-model [:* (sut/visit-routes visits)])
-          handler (make-handler visit-routes)
-          delete-request (mock/request :delete "/visits/0")
-          delete-response @(handler delete-request)]
+    (let [delete-request (mock/request :delete "/visits/0")
+          delete-response @(*handler* delete-request)]
       (is (= 204 (:status delete-response))))))