Added view to see item details

Added view to see item details

Detail is opened also when editing providing
live preview when input field gets unfocused

--- src/cljs/repodoc/core.cljs
+++ src/cljs/repodoc/core.cljs
@@ -25,7 +25,8 @@

 (def db {:data (get REPO "tree")
          :start 0
-         :editing #{}})
+         :editing #{}
+         :opened #{}})

 (defn ^:export updatedb [fields value]
   (set! db (assoc-in db fields value))
@@ -33,6 +34,23 @@

 (defn querydb [fields]
   (get-in db fields))
+
+
+;; Utils
+
+(defn blob?
+  [item]
+  (if (= (get item "type") "blob") true false))
+
+(defn editing?
+  [pos]
+  (contains? (querydb [:editing]) pos))
+
+(defn opened?
+  [pos]
+  (contains? (querydb [:opened]) pos))
+
+;; Handlers

 (defn edit [pos]
   (let [editing (querydb [:editing])]
@@ -51,20 +69,18 @@
     (println "Editing: " pos key value)
     (save item pos)))

-(defn close
+(defn toggle-item-detail
+  [pos]
+  (let [opened (querydb [:opened])]
+    (if (contains? opened pos)
+      (updatedb [:opened] (disj opened pos))
+      (updatedb [:opened] (conj opened pos)))))
+
+(defn close-editor
   [pos]
   (let [editing (querydb [:editing])]
-    (updatedb [:editing] (disj editing pos))))
-
-;; Utils
-
-(defn blob?
-  [item]
-  (if (= (get item "type") "blob") true false))
-
-(defn editing?
-  [pos]
-  (contains? (querydb [:editing]) pos))
+    (updatedb [:editing] (disj editing pos))
+    (if (opened? pos) (toggle-item-detail pos))))

 ;; App

@@ -78,6 +94,7 @@
 (defn annotate-editor
   [pos item]
   (let [title (get item "title")]
+    (if (not (opened? pos)) (toggle-item-detail pos))
     (nm "div" [(e/text "title" title 40 #(update_field pos "title" %))])))

 (defn annotate-button
@@ -86,13 +103,19 @@
     (nm "button.pure-button" {:onclick #(edit pos)} "Annotate")))

 (defn annotate
-  [index item]
-  (if (false? (editing? index))
-      (nm "div.pure-u-1.pure-u-sm-1-2" [(annotate-button index item)])
+  [pos item]
+  (if (false? (editing? pos))
+      (nm "div.pure-u-1.pure-u-sm-1-2" [(annotate-button pos item)])
       [(nm "div.pure-u-1.pure-u-sm-1-2"
-           [(nm "button.pure-button" {:onclick #(close index)} "Close")])
+           [(nm "button.pure-button" {:onclick #(close-editor pos)} "Close")])
        (nm "div.pure-u-1-1.pure-u-sm-1"
-           [(annotate-editor index item)])]))
+           [(annotate-editor pos item)])]))
+
+(defn item-detail
+  [pos item]
+  (if (and (get item "mtime" false) (opened? pos))
+    (let [title (get item "title")]
+      (nm "div.pure-u-1-1.pure-u-sm-1" title))))

 (defn node
   "Renders one node from tree with indentation"
@@ -102,8 +125,10 @@
         level (count parts)
         base (last parts)
         icon (if (blob? item) (ftype-to-icon base) (nm "i.ftype.fa.fa-folder-open-o"))]
-    (nm "div.pure-g" [(nm "div.pure-u-1.pure-u-sm-1-2" [(nm (str "div.level" level) [icon base])])
-                      (annotate index item)])))
+    (nm "div.pure-g" [(nm "div.pure-u-1.pure-u-sm-1-2"
+                          [(nm (str "div.level" level) {:onclick #(toggle-item-detail index)} [icon base])])
+                      (annotate index item)
+                      (item-detail index item)])))

 (defn reporender
   "Render repository trees"


current-item->navigate

current-item->navigate

--- src/cljs/unfolds/core.cljs
+++ src/cljs/unfolds/core.cljs
@@ -35,14 +35,14 @@
 ;; =============================================================================
 ;; Helpers

-(defn add-item [item owner {:keys [event current-item]}]
+(defn add-item [item owner {:keys [event navigate]}]
   (let [new-text (-> (om/get-node owner "new-item-text")
                      .-value)
         new-title (-> (om/get-node owner "new-item-title")
                       .-value)]
     (when (and new-title new-text)
       (put! event {:op :create
-                  :data {:item/title new-title :item/text new-text}}))))
+                   :data {:item/title new-title :item/text new-text}}))))

 (defn handle-item-text-change [e owner {:keys [text]}]
   (let [value (.. e -target -value)
@@ -80,7 +80,7 @@
 ;; =============================================================================
 ;; Components

-(defn item-view [item owner {:keys [current-item event]}]
+(defn item-view [item owner {:keys [navigate event]}]
   (reify
     om/IRender
     (render [_]
@@ -88,16 +88,16 @@
                (dom/h2 nil (:item/title item))
                (dom/br nil "")
                (link (str "#/" (:item/id item)) (:item/id item))
-               (dom/br nil "") ;; XXX: ghetto paragraph
+               (dom/br nil "")
                (dom/br nil "")
                (apply dom/div nil
                       (prepare-item (:item/text item)))))))

-(defn item-add-view [item owner {:keys [current-item event]}]
+(defn item-add-view [item owner {:keys [navigate event]}]
   (reify
     om/IRenderState
     (render-state [_ state] ;; keys chan as etc?
-      (let [opts {:current-item current-item ;;; XXX
+      (let [opts {:navigate navigate
                   :event event}]
         (dom/div #js {:id "item-add-view"}
         (dom/div #js {:id "item-info"}
@@ -128,17 +128,17 @@
   (let [value (.. e -target -value)]
     (om/set-state! owner :text text)))

-(defn search [owner {:keys [event current-item]}] ;; XXX: current-item really?
+(defn search [owner {:keys [event navigate]}]
   (let [search (-> (om/get-node owner "search")
                    .-value)]
     (when (and search (not= search ""))
       (put! event {:op :search :data {:subs search}}))))

-(defn search-view [items owner {:keys [current-item event]}]
+(defn search-view [items owner {:keys [navigate event]}]
   (reify
     om/IRenderState
     (render-state [_ state]
-      (let [opts {:current-item current-item ;;; XXX
+      (let [opts {:navigate navigate
                   :event event}]
         (dom/div #js {:id "search-view"}
                  (dom/p nil "Currently only title's are searchable. It
@@ -169,7 +169,7 @@
   (reify
     om/IInitState
     (init-state [_]
-      {:current-item (chan)
+      {:navigate (chan)
        :event (chan)})

     om/IWillMount
@@ -193,7 +193,7 @@

       ;; routing loop
       (go (loop []
-            (let [id (<! (om/get-state owner :current-item))]
+            (let [id (<! (om/get-state owner :navigate))]
               (cond
                (= id :new)
                (do
@@ -203,14 +203,15 @@
                               :item/text ""}))

                (= id :search)
-               (do
-                 (.setToken history "/search"))))
+               (.setToken history "/search")))
             (recur)))

       ;; event loop
       (go (loop []
-            (let [{:keys [op data]} (<! (om/get-state owner :event))]
+            (let [event (om/get-state owner :event)
+                  {:keys [op data]} (<! event)]
               (condp = op
+
                 :create
                 (let [data (<! (util/edn-chan
                                 {:method :post :url "/items"
@@ -228,15 +229,15 @@
                                 {:url (str "/search/" (:subs data))}))]
                   ;; XXX: what if there's no hit?
                   ;;(.setToken history (str "/items")) ;; XXX
-                  (om/transact! app :items (fn [_] data)) ;; search results
+                  (om/transact! app :items (fn [_] data))
                   )

                 (recur))))))

     om/IRenderState
-    (render-state [_ {:keys [current-item event]}]
+    (render-state [_ {:keys [navigate event]}]
       (let [route (:route app)
-            opts {:opts {:current-item current-item
+            opts {:opts {:navigate navigate
                          :event event}}]
         ;; menu bar
         (dom/div nil
@@ -248,22 +249,19 @@
             (dom/button
              #js {:id "add-item"
                   :className "button"
-                  :onClick (fn [e] (put! current-item :new))}
+                  :onClick (fn [e] (put! navigate :new))}
              "Add")

             (dom/button
              #js {:id "search-item"
                   :className "button"
-                  :onClick (fn [e] (put! current-item :search))}
+                  :onClick (fn [e] (put! navigate :search))}
              "Search"))

           (dom/div nil
             (case (first (:route app))
-                      ;; what need? XXX
               :add-item (om/build item-add-view (:current-item app) opts)
-              ;; why bring current-item here?
               :search-item (om/build search-view (:items app)  opts)
-              ;;:list-items (om/build items-view (:items app) opts)
               :view-item (om/build item-view (:current-item app) opts))))))))

 (util/edn-xhr


Enable Prism syntax coloring.

Enable Prism syntax coloring.

--- src/cljs/website/core.cljs
+++ src/cljs/website/core.cljs
@@ -148,7 +148,7 @@
         (.getElementById js/document "notebook")
           (.render (.parse js/nb (.parse js/JSON data)))
       )
-      (js/Prism.highlightAll.)
+      (js/Prism.highlightAll)
     ) 150
   )
 )


Add new piece.

Add new piece.

--- src/cljs/website/core.cljs
+++ src/cljs/website/core.cljs
@@ -129,6 +129,9 @@
         (str "#/music/" (js/btoa "https://musescore.com/user/25292271/scores/4583261/embed"))}
         [:img {:src (str js/context "/img/music.png")}] "Elegy in D Minor"]
       [:a {:href
+        (str "#/music/" (js/btoa "https://musescore.com/user/25292271/scores/4724766/embed"))}
+        [:img {:src (str js/context "/img/music.png")}] "Elegy in F# Minor \"Rain Dance\""]
+      [:a {:href
         (str "#/music/" (js/btoa "https://musescore.com/user/25292271/scores/4691681/embed"))}
         [:img {:src (str js/context "/img/music.png")}] "Rhapsody for Viola and Piano in A Minor"]
       [:a {:href


show nil types as "nil" instead of "", and remove Object pseudo protocol listings

--- src/cljs_api_gen/parse.clj
+++ src/cljs_api_gen/parse.clj
@@ -240,6 +240,9 @@
        :methods pmethods
        :type "protocol"})))

+(defn valid-protocol? [form]
+  (and (symbol? form) (not= form 'Object)))
+
 (defn parse-deftype
   [form]
   (when (not= *cur-ns* "cljs.pprint") ;; ignore custom deftypes here
@@ -249,7 +252,7 @@
           form (drop 2 form)
           signature (first form)
           protocols (->> (drop 1 form)
-                         (filter symbol?)
+                         (filter valid-protocol?)
                          (map str)
                          (set))]
       (when (or *parse-private-defs?*
@@ -263,13 +266,13 @@
         types (filter symbol? (drop 2 form))]
     {:type-extension
      {:protocols #{(str protocol)}
-      :types (set (map str types))}}))
+      :types (set (map pr-str types))}}))

 (defn parse-extend-type [form]
   (let [type (second form)
-        protocols (filter symbol? (drop 2 form))]
+        protocols (filter valid-protocol? (drop 2 form))]
     {:type-extension
-     {:types #{(str type)}
+     {:types #{(pr-str type)}
       :protocols (set (map str protocols))}}))

 (defn parse-defmulti


drop unused require

drop unused require

--- src/cognitect/transit.cljs
+++ src/cognitect/transit.cljs
@@ -16,8 +16,7 @@
   (:refer-clojure :exclude [integer?])
   (:require [com.cognitect.transit :as t]
             [com.cognitect.transit.types :as ty]
-            [com.cognitect.transit.eq :as eq]
-            [goog.array :as garray])
+            [com.cognitect.transit.eq :as eq])
   (:import [goog.math Long]))

 ;; patch cljs.core/UUID IEquiv


Removed reflection warnings from conexp.io.contexts

Signed-off-by: Daniel Borchmann <25857343a15bf1edafebc2912e82ecf775c585c1@mailbox.tu-dresden.de>

--- src/conexp/io/contexts.clj
+++ src/conexp/io/contexts.clj
@@ -28,7 +28,7 @@

 (add-context-input-format :simple
                           (fn [rdr]
-                            (= "conexp-clj simple" (.readLine rdr))))
+                            (= "conexp-clj simple" (read-line))))

 (define-context-output-format :simple
   [ctx file]
@@ -54,7 +54,7 @@

 (add-context-input-format :burmeister
                           (fn [rdr]
-                            (= "B" (.readLine rdr))))
+                            (= "B" (read-line))))

 (define-context-output-format :burmeister
   [ctx file]
@@ -105,7 +105,7 @@
 (defn- find-tag [seq-of-hashes tag]
   (first (find-tags seq-of-hashes tag)))

-(defn- trim [str]
+(defn- trim [^String str]
   (.trim str))

 (defn- hash-from-pairs [pairs]
@@ -264,20 +264,20 @@

 (define-context-input-format :colibri
   [file]
-  (loop [in (reader file)
-         objs #{}
-         inz #{}]
-    (let [line (.readLine in)]
-      (cond
-        (not line)
-        (make-context-nc objs (set-of m [[g m] inz]) inz),
-        (or (re-matches #"^\s*$" line)     ; blank
-            (re-matches #"^\s*#.*$" line)) ; comment
-        (recur in objs inz),
-        :else
-        (let [[_ g atts] (re-matches #"^\s*(.+)\s*:\s*(.+)?\s*;\s*(?:#.*)?$" line)
-              atts (and atts (split atts #"\s+"))]
-          (recur in (conj objs g) (union inz (set-of [g m] [m atts]))))))))
+  (with-in-reader file
+    (loop [objs #{},
+           inz  #{}]
+      (let [line (read-line)]
+        (cond
+         (not line)
+         (make-context-nc objs (set-of m [[g m] inz]) inz),
+         (or (re-matches #"^\s*$" line)     ; blank
+             (re-matches #"^\s*#.*$" line)) ; comment
+         (recur objs inz),
+         :else
+         (let [[_ g atts] (re-matches #"^\s*(.+)\s*:\s*(.+)?\s*;\s*(?:#.*)?$" line)
+               atts (and atts (split atts #"\s+"))]
+           (recur (conj objs g) (union inz (set-of [g m] [m atts])))))))))

 ;; Comma Seperated Values (.csv)
@@ -285,14 +285,14 @@
 (add-context-input-format :csv
                           (fn [rdr]
                             (try
-                             (re-matches #"^[^,]+,[^,]+$" (.readLine rdr))
+                             (re-matches #"^[^,]+,[^,]+$" (read-line))
                              (catch Exception _))))

 (define-context-input-format :csv
   [file]
-  (let [in (reader file)]
+  (with-in-reader file
     (loop [inz #{}]
-      (let [line (.readLine in)]
+      (let [line (read-line)]
         (if (not line)
           (make-context-nc (set-of g [[g m] inz])
                            (set-of m [[g m] inz])


Use correct function for taking items off channel in thread.

--- src/uswitch/bifrost/s3.clj
+++ src/uswitch/bifrost/s3.clj
@@ -90,7 +90,7 @@
       (create-bucket credentials bucket))
     (thread
      (loop []
-       (let [msg (<! rotated-event-ch)]
+       (let [msg (<!! rotated-event-ch)]
          (if (nil? msg)

            (debug "Terminating S3 uploader")


Flattened amount/commodity into Entry record. Added verify-balanced function.

--- src/wealthpulse/parser.clj
+++ src/wealthpulse/parser.clj
@@ -7,8 +7,7 @@
 ;

 (defrecord Header [date status code payee note])
-(defrecord Amount [quantity commodity])
-(defrecord Entry [header account account-lineage entry-type amount note])
+(defrecord Entry [header account account-lineage entry-type amount commodity note])

@@ -20,11 +19,28 @@
   "Virtual unbalanced transactions must have an amount (since they are unbalanced)"
   [entries]
   (let [vu-entries (filter #(and (= (:entry-type %) :virtual-unbalanced)
-                                 (or (nil? (:amount %))
-                                     (nil? (:quantity (:amount %)))))
+                                 (nil? (:amount %)))
                            entries)]
     (if (> (count vu-entries) 0)
-      (println "This transaction has" (count vu-entries) "virtual unbalanced entries."))))
+      (throw
+        (Exception. (with-out-str
+                      (print "This entry is a virtual unbalanced entry with no amount:"
+                             (first vu-entries))))))))
+
+(defn verify-balanced
+  "Generic balance checker for balanced entry types. Balanced entries should sum 0 or have only 1 amount missing (which can be auto-balanced).
+  Returns a map with :sum and :num-nil.
+  NOTE: Commodities are completely ignored right now (TODO)"
+  [entries entry-type]
+  (let [b-entries (filter #(= (:entry-type %) entry-type) entries)
+        sum (reduce (fn [sum entry]
+                      (if (nil? (:amount entry))
+                          sum
+                          (+ sum (:amount entry))))
+                    0 b-entries)
+        num-nil (count (filter #(nil? (:amount %)) b-entries))]
+    {:sum sum :num-nil num-nil}))
+

 ;
@@ -64,7 +80,7 @@

 (defn transform-amount
-  "Transform a parse-tree amount into an Amount record."
+  "Transform a parse-tree amount into a map containing :amount and :commodity."
   [first-val second-val]
   (let [quantity (if (= (first first-val) :quantity)
                    (bigdec (string/replace (first (drop 1 first-val)) "," ""))
@@ -73,7 +89,7 @@
                      (= (first first-val) :commodity) (string/trim (first (drop 1 first-val)))
                      (not (nil? second-val)) (string/trim (first (drop 1 second-val)))
                      :else nil)]
-    (->Amount quantity commodity)))
+    {:amount quantity :commodity commodity}))

 (defn transform-entry
@@ -83,7 +99,7 @@
           (fn [coll [key value opt?]]
             (cond
                (= key :account) (merge coll (transform-account value))
-               (= key :amount) (assoc coll :amount (transform-amount value opt?))
+               (= key :amount) (merge coll (transform-amount value opt?))
                (= key :note) (assoc coll :note (string/trim value))))
         entry-map (assoc (reduce collect-values {} values) :header header)]
     (map->Entry entry-map)))


fixed import

fixed import

--- src/corpus_utils/bccwj.clj
+++ src/corpus_utils/bccwj.clj
@@ -10,7 +10,7 @@
             [schema.macros :as sm]
             [corpus-utils.c-code :refer [c-code]]
             [corpus-utils.text :as text]
-            [corpus-utils.document :refer [MetadataSchema DocumentSchema]]))
+            [corpus-utils.document :refer [MetadataSchema SentencesSchema]]))

 ;; # Importer for BCCWJ-Formatted C-XML Data
 ;;


New functions wrong-job-name and send-wrong-job-name

--- src/emender_jenkins/rest_api.clj
+++ src/emender_jenkins/rest_api.clj
@@ -147,6 +147,10 @@
     [job-name command]
     (create-error-response job-name (get commands command) "Job does not exist"))

+(defn wrong-job-name
+    [job-name command]
+    (create-error-response job-name (get commands command) "The name of job is wrong"))
+
 (defn job-already-exist-response
     [job-name command]
     (create-error-response job-name (get commands command) "Job already exist"))
@@ -156,6 +160,11 @@
     (-> (job-does-not-exist-response job-name command)
         (send-error-response request :not-found)))

+(defn send-wrong-job-name
+    [request job-name command]
+    (-> (wrong-job-name job-name command)
+        (send-error-response request :not-found)))
+
 (defn send-job-not-specified-response
     [request command]
     (-> (create-bad-request-response (get commands command) "job name is not specified")
@@ -191,14 +200,16 @@
     [request function command]
     (let [job-name (get-job-name-from-body request)]
         (if job-name
-            (if (results/job-exists? job-name)
-                (-> (function (config/get-jenkins-url request)
-                              (config/get-jenkins-auth request)
-                              (config/include-jenkins-reply? request)
-                              job-name)
-                    (reload-job-list request)
-                    (send-response request))
-                (send-job-does-not-exist-response request job-name command))
+            (if (test-job? job-name request)
+                (if (results/job-exists? job-name)
+                    (-> (function (config/get-jenkins-url request)
+                                  (config/get-jenkins-auth request)
+                                  (config/include-jenkins-reply? request)
+                                  job-name)
+                        (reload-job-list request)
+                        (send-response request))
+                    (send-job-does-not-exist-response request job-name command))
+                (send-wrong-job-name-response request job-name command))
             (send-job-not-specified-response request command))))

 (defn start-job


Refactoring: read-jobs-in-queue, read-queue-info-from-jenkins, get-jobs-in-queue-url and so on

--- src/emender_jenkins/rest_api.clj
+++ src/emender_jenkins/rest_api.clj
@@ -447,19 +447,15 @@
         (-> (http-response/response output)
             (http-response/content-type mime-type))))

-(defn get-running-jobs
-    [request]
-)
-
-(defn building-jobs-url
+(defn get-building-jobs-url
     "Construct URL used to read all jobs that are currently building."
     [request]
     (let [jenkins-url   (config/get-jenkins-url request)
-          view          "Queue";(config/get-currently-building-view request)
+          view          (config/get-currently-building-view request)
           ]
           (str jenkins-url "view/" view "/")))

-(defn read-building-jobs
+(defn read-building-jobs-from-jenkins
     "Read info about building jobs via Jenkins REST API."
     [url job-list-part]
     (try
@@ -472,31 +468,34 @@
     [jobs]
     (map #(get % "name") jobs))

+(defn read-currently-building-jobs
+    [request]
+    (let [url           (get-building-jobs-url request)
+          job-list-part (config/get-job-list-url request)]
+          (read-building-jobs-from-jenkins url job-list-part)))
+
 (defn get-currently-building-jobs
     "Get (and return) all jobs that are currently building."
     [request]
-    (let [url           (building-jobs-url request)
-          job-list-part (config/get-job-list-url request)
-          jobs          (read-building-jobs url job-list-part)]
-          (if jobs
-              (-> (create-currently-building-jobs-response jobs)
-                  (send-response request))
-              (-> (create-bad-request-response "currently_building_jobs" "Can not read Jenkins view")
-                  (send-error-response request :internal-server-error)))))
+    (if-let [jobs (read-currently-building-jobs request)]
+             (-> (create-currently-building-jobs-response jobs)
+                 (send-response request))
+             (-> (create-bad-request-response "currently_building_jobs" "Can not read Jenkins view")
+                 (send-error-response request :internal-server-error))))

 (defn get-job-name-from-queue-info
     "Read job name from the structure about one item in Jenkins build queue."
     [job-info]
     (-> job-info (get "task") (get "name")))

-(defn jobs-in-queue-url
+(defn get-jobs-in-queue-url
     "Construct URL used to read all jobs that are put into Jenkins build queue."
     [request]
     (let [jenkins-url   (config/get-jenkins-url request)
           job-list-part (config/get-in-queue-url request)]
           (str jenkins-url job-list-part)))

-(defn read-queue-info
+(defn read-queue-info-from-jenkins
     "Read info about queue via Jenkins REST API."
     [url]
     (try
@@ -515,14 +514,22 @@
              {"queuePos" queue-position
               "jobName"  job-name})))

+(defn read-jobs-in-queue
+    [request]
+    (let [url   (get-jobs-in-queue-url request)]
+         (read-queue-info-from-jenkins url)))
+
 (defn get-jobs-in-queue
     "Get (and return) all jobs that are in Jenkins queue."
     [request]
-    (let [url   (jobs-in-queue-url request)
-          items (read-queue-info url)]
-          (if items
-              (-> (create-jobs-in-queue-response items)
-                  (send-response request))
-              (-> (create-bad-request-response "jobs_in_queue" "Can not read Jenkins queue")
-                  (send-error-response request :internal-server-error)))))
-
+    (if-let [items (read-jobs-in-queue request)]
+             (-> (create-jobs-in-queue-response items)
+                 (send-response request))
+             (-> (create-bad-request-response "jobs_in_queue" "Can not read Jenkins queue")
+                 (send-error-response request :internal-server-error))))
+
+(defn get-running-jobs
+    "Get (and return) all jobs that are in Jenkins queue or that are currently building."
+    [request]
+)
+


fixing extra methods

fixing extra methods

--- src/epicea/utils/defmultiple.clj
+++ src/epicea/utils/defmultiple.clj
@@ -90,8 +90,8 @@
 (defn defmultiple-extra-sub [parsed]
   `(add-extra-methods
     (quote ~(:name parsed))
-    (quote ~(map make-method
-                 (:methods parsed)))))
+    ~(vec (map make-method
+               (:methods parsed)))))


New, fixed version compiles.

New, fixed version compiles.

--- src/exp/simple_dag_hierarchy.clj
+++ src/exp/simple_dag_hierarchy.clj
@@ -177,9 +177,9 @@
   SDH-HLA
     (active-var-set  []  (leaf-var-set inactive-leaf))
     (leaf-var-set    []  (active-var-set inactive-leaf))
-    (needs-expand?   []  (not (satisfied? this)))
+    (needs-expand?   []  (not (satisfied? this :dummy)))
     (expand          [lv]
-      (let [{:keys [hierarchy var dst-val]} inactive-leaf]
+      (let [{:keys [hierarchy var dst-val dtg]} inactive-leaf]
        (cond (empty? (clojure.set/intersection lv ((:interfering-set hierarchy) var)))
                [[[inactive-leaf] (advance-active-leaf-precond-hla this dst-val)]]
              (= cur-val dst-val)
@@ -259,10 +259,10 @@
     (active-var-set []  (apply clojure.set/union (map active-var-set precond-hlas)))
     (leaf-var-set   []  (apply clojure.set/union (map leaf-var-set precond-hlas)))
     (needs-expand?  []  expand-index)
-    (expand         []
+    (expand         [lv]
       (assert expand-index)
-      (for [[prefix new-precond] (expand (precond-hlas expand-index))]
-        (if (and (satisfied? new-precond) (every? #(and (active? %) (satisfied? % :dummy)) precond-hlas))
+      (for [[prefix new-precond] (expand (precond-hlas expand-index) lv)]
+        (if (and (satisfied? new-precond :dummy) (every? #(and (active? %) (satisfied? % :dummy)) precond-hlas))
             [(conj prefix action) nil]
           [prefix (SDH-Action-HLA hierarchy name action precond-var-set
                                   (assoc precond-hlas expand-index new-precond)
@@ -270,7 +270,7 @@
     (greedy-select? [s v av]
       (or (every? #(and (satisfied? % s) (or (active? %) (not (av (:var %))))) precond-hlas)
           (some #(greedy-select? % s v av) (util/make-safe (seq (filter #(contains? (leaf-var-set %) v) precond-hlas))))))
-    (select-leaf    [s v av lv]
+    (select-leaf    [s v av]
       (let [possible-vals  (filter #(contains? (leaf-var-set (precond-hlas %)) v) (range (count precond-hlas)))
             [deep shallow] (util/separate (comp active? precond-hlas) possible-vals)
             val-options    (or (and (:greedy-optimization? hierarchy)
@@ -280,7 +280,7 @@
         (assert (seq val-options))
         (assert (<= (count shallow) 1))
         (for [idx         val-options,
-              next        (select-leaf (precond-hlas idx) s v a v lv)
+              next        (select-leaf (precond-hlas idx) s v av)
               :let [new-precond-hlas (assoc precond-hlas idx next)]]
           (SDH-Action-HLA. hierarchy [:!A* (env/action-name action) (map env/action-name new-precond-hlas)]
                            action precond-var-set new-precond-hlas idx))))
@@ -291,16 +291,15 @@
     (precondition-context [s] precond-var-set)
   hierarchy/HighLevelAction
     (immediate-refinements- [s]
-      (if (every? #(satisfied? % s) precond-hlas) (do (println "gREED!") [[action]])
-        (let [var-actives (active-var-set this)
-              var-leaves  (leaf-var-set this)
-              var-options (clojure.set/difference var-leaves var-actives)]
-          (if (empty? var-options)
-              (println "Dead end!")
-            (for [[prefix remaining]
-                  (do-refinement this s (util/first-maximal-element (:var-levels hierarchy) var-options)
-                                 var-actives var-leaves)]
-              (if remaining (concat prefix [remaining]) prefix))))))
+      (let [var-leaves  (leaf-var-set this)]
+       (if (needs-expand? this)
+         (let [[prefix next] (expand this var-leaves)]
+           (if next (conj prefix next) prefix))
+         (let [var-actives (active-var-set this)
+               var-options (clojure.set/difference var-leaves var-actives)]
+           (if (empty? var-options)
+             (println "Dead end!")
+             (select-leaf this s (util/first-maximal-element (:var-levels hierarchy) var-options) var-actives))))))
     (cycle-level-           [s] nil))

 (defn- make-action-hla [hierarchy action]


remove comments

remove comments

--- src/gamma_examples/triangle.cljs
+++ src/gamma_examples/triangle.cljs
@@ -29,36 +29,3 @@
       (dp/program d (example-program))
       (example-data))))

-(comment
-  (with-out-str
-   (fipp.engine/pprint-document
-     '[:group
-       ([:group
-         [:group
-          "("
-          ("f" " - "
-            [:group "(" ("f" " + " "1.0") ")"]) ")"] ";"])]
-     {:width 80}))
-
-  (do (def x
-     (with-out-str
-       (fipp.engine/pprint-document
-         '[:group
-           "a"
-           ]
-         {:width 80})))
-      "asdf")
-  (fipp.engine/pprint-document
-    '[:group
-      "a"
-      ]
-    {:width 80})
-
-
-  (with-out-str
-    (fipp.clojure/pprint '(let [foo "abc 123"
-                               bar {:x 1 :y 2 :z 3}]
-                           (do-stuff foo (assoc bar :w 4)))
-                        {:width 40}))
-
-  )


Clear units when making a new board

Clear units when making a new board

--- src/glory_of_empires/command.clj
+++ src/glory_of_empires/command.clj
@@ -16,7 +16,11 @@
   (run-command (fn [ game ] (update game :map command))))

 (defn- make-board-command [ new-board ]
-  (run-command (fn [ game ] (assoc game :map new-board))))
+  (run-command
+    (fn [ game ]
+      (-> game
+          (assoc :map new-board)
+          (assoc :ship-counters {})))))

 ;----------- map commands --------------------


Remove log statement

Remove log statement

--- src-cljs/tamarack/routes.cljs
+++ src-cljs/tamarack/routes.cljs
@@ -51,7 +51,6 @@
               (dissoc params :last)
               params))
           (remove-conflicting [params]
-            (tamarack.util/log params)
             (if (nil? (:tracking-now params))
               (dissoc params :from :to)
               (dissoc params :last)))]


Refactor

Refactor

--- backend/src/akvo/lumen/lib/auth.clj
+++ backend/src/akvo/lumen/lib/auth.clj
@@ -24,10 +24,10 @@

 (defrecord AuthServiceImpl [auth-datasets-set auth-visualisations-set auth-dashboards-set]
   p/AuthService
-  (allow? [this d]
-    (and (set/subset? (:visualisation-ids d) auth-visualisations-set)
-         (set/subset? (:dataset-ids d) auth-datasets-set)
-         (set/subset? (:dashboard-ids d) auth-dashboards-set)))
+  (allow? [this ids]
+    (and (set/subset? (:visualisation-ids ids) auth-visualisations-set)
+         (set/subset? (:dataset-ids ids) auth-datasets-set)
+         (set/subset? (:dashboard-ids ids) auth-dashboards-set)))
   (auth [this {:keys [dataset-ids visualisation-ids dashboard-ids]}]
     {:auth-datasets (set/intersection auth-datasets-set (set dataset-ids))
      :auth-visualisations (set/intersection auth-visualisations-set (set visualisation-ids))


[#2925] Only create FKs when we have a "metadata" group

Co-Authored-By @tangrammer
Co-Authored-By @kardan

--- backend/src/akvo/lumen/postgres.clj
+++ backend/src/akvo/lumen/postgres.clj
@@ -91,11 +91,11 @@
   (add-key-constraints conn table-name columns))

 (defn create-data-group-foreign-keys [conn group-tables]
-  (let [metadata-table-name (get group-tables "metadata")
-        fks (for [[group-id group-table-name] group-tables
-                  :when (not (= "metadata" group-id))]
-              (format "ALTER TABLE %s ADD FOREIGN KEY (instance_id) REFERENCES %s (instance_id) ON DELETE CASCADE"
-                      group-table-name metadata-table-name))]
+  (when-let [metadata-table-name (get group-tables "metadata")
+             fks (for [[group-id group-table-name] group-tables
+                       :when (not (= "metadata" group-id))]
+                   (format "ALTER TABLE %s ADD FOREIGN KEY (instance_id) REFERENCES %s (instance_id) ON DELETE CASCADE"
+                           group-table-name metadata-table-name))]
     (doseq [fk fks]
       (jdbc/execute! conn fk))))


Making hatti record components into multimethods so they can be over-ridden.

--- src/hatti/record/components.cljs
+++ src/hatti/record/components.cljs
@@ -36,7 +36,10 @@
                   #(put! shared/event-chan {:submission-unclicked true}))
        :class "btn-close right" :href "#"} "×"])

-(defn print-xls-report-btn
+(defmulti print-xls-report-btn
+  (fn [_ owner & args]
+    (om/get-shared owner :view-type)))
+(defmethod print-xls-report-btn :default
   [cursor owner]
   (om/component
    (html nil)))
@@ -89,7 +92,10 @@
            :show-instance-id true
            :h4-cls ""}})

-(defn repeat-view
+(defmulti repeat-view
+  (fn [_ owner & args]
+    (om/get-shared owner :view-type)))
+(defmethod repeat-view :default
   [{:keys [data repeat-field lang]} owner {:keys [view]}]
   "Renders data for a repeat field, which is complex; repeat fields are subforms.
    data is expected to be an vector of repeated data, in each element of which
@@ -139,12 +145,18 @@
              (not (get data (:full-name geofield))))
     [:span.no-geo.t-normal.right "No geodata"]))

-(defn edit-delete
+(defmulti edit-delete
+  (fn [_ owner & args]
+    (om/get-shared owner :view-type)))
+(defmethod edit-delete :default
   [instance-id owner {:keys [delete-record!]}]
   (om/component
    (html nil)))

-(defn submission-view
+(defmulti submission-view
+  (fn [_ owner & args]
+    (om/get-shared owner :view-type)))
+(defmethod submission-view :default
   [view]
   (fn [cursor owner opts]
     (reify


Removed unneeded logging.

Removed unneeded logging.

--- src/kixi/hecuba/api/entities.clj
+++ src/kixi/hecuba/api/entities.clj
@@ -81,7 +81,6 @@
   (update-in e [:full_entity] assoc :editable (editable? (:programme_id e) (:project_id e) allowed-programmes allowed-projects roles)))

 (defn parse-entities [results allowed-programmes allowed-projects roles file-bucket]
-  (log/infof "parsing entities!")
   (->> results
        esr/hits-from
        (map :_source)


Add helper function for map + filter nil

--- src/braid/common/util.cljc
+++ src/braid/common/util.cljc
@@ -35,6 +35,11 @@
   (fn [& args]
     (apply f (reverse args))))

+(defn extract
+  "Like `map` but filter out nil results"
+  [f & colls]
+  (remove nil? (apply map f colls)))
+
 (def bot-name-re
   #"(?:\w|\d){1,30}")


add x-platform uuid?

add x-platform uuid?

--- src/braid/common/util.cljc
+++ src/braid/common/util.cljc
@@ -37,3 +37,8 @@

 (def bot-name-re
   #"(?:\w|\d){1,30}")
+
+(defn uuid?
+  [u]
+  #?(:clj (instance? java.util.UUID u)
+     :cljs (cljs.core/uuid? u)))


OO: Simplify condition check Use if instead of cond

--- src/hatti/utils/style.cljs
+++ src/hatti/utils/style.cljs
@@ -87,8 +87,7 @@
    defaulting to an inbuilt palette if the field is not a select-one or
    any of the choices lack an appearance attribute"
   [{:keys [children] :as field} answers]
-  (cond
-    (and (form-utils/select-one? field)
-         (every? :appearance children))
+  (if (and (form-utils/select-one? field)
+           (every? :appearance children))
     (group-user-defined-colors-by-answer field)
-    :else (zipmap answers (field->colors field))))
+    (zipmap answers (field->colors field))))


RR: pass is-filtered-dataview? as optional param

--- src/hatti/views/table.cljs
+++ src/hatti/views/table.cljs
@@ -26,7 +26,7 @@
       extra-field
       (conj extra-field forms/submission-time-field))))

-(defn all-fields [form is-filtered-dataview?]
+(defn all-fields [form & {:keys [is-filtered-dataview?]}]
   "Given a (flat-)form, returns fields for table display.
    Puts extra fields in the beginning, metadata at the end of the table,
    and drops fields that have no data (eg. group/note)."
@@ -77,7 +77,7 @@
   ([form get-label?] (flat-form->sg-columns form get-label? nil))
   ([form get-label? language & {:keys [is-filtered-dataview?]}]
    (clj->js
-    (for [field (all-fields form is-filtered-dataview?)]
+    (for [field (all-fields form :is-filtered-dataview? is-filtered-dataview?)]
       (let [{:keys [name type full-name]} field
             label (if get-label? (get-label field language) name)]
         {:id name :field full-name :type type
@@ -95,7 +95,7 @@
   "Creates a Slick.Grid backed by Slick.Data.DataView from data and fields.
    Most events are handled by slickgrid. On double-click, event is put on chan.
    Returns [grid dataview]."
-  (let [columns (flat-form->sg-columns form true nil :is-filtered-dataview? true)
+  (let [columns (flat-form->sg-columns form true nil :is-filtered-dataview? is-filtered-dataview?)
         SlickGrid (.. js/Slick -Grid)
         DataView (.. js/Slick -Data -DataView)
         Pager (.. js/Slick -Controls -Pager)


remove dev dependencies from the constructed war

lein ring war includes all dev dependencies and resources when using
lein 2 (lein ring uberwar had the same issue:
https://github.com/weavejester/lein-ring/pull/62 - used that solution
here as well.)

--- src/leiningen/ring/war.clj
+++ src/leiningen/ring/war.clj
@@ -2,6 +2,7 @@
   (:require [leiningen.compile :as compile]
             [clojure.java.io :as io]
             [clojure.string :as string]
+            [leinjacker.utils :as lju]
             [leinjacker.deps :as deps])
   (:use [clojure.data.xml :only [sexp-as-element indent-str]]
         leiningen.ring.util)
@@ -198,6 +199,12 @@
       (dir-entry war-stream project "" path))
     war-stream))

+(defn unmerge-profiles [project]
+  (if-let [unmerge-fn (and (= 2 (lju/lein-generation))
+                           (lju/try-resolve 'leiningen.core.project/unmerge-profiles))]
+    (unmerge-fn project [:default])
+    project))
+
 (defn add-servlet-dep [project]
   (deps/add-if-missing project '[ring/ring-servlet "1.2.1"]))

@@ -207,7 +214,10 @@
      (war project (default-war-name project)))
   ([project war-name]
      (ensure-handler-set! project)
-     (let [project (add-servlet-dep project)
+;     (let [project (add-servlet-dep project)
+      (let [project (-> project
+                        add-servlet-dep
+                        unmerge-profiles)
            result  (compile/compile project)]
        (when-not (and (number? result) (pos? result))
          (let [war-path (war-file-path project war-name)]


Added lookup and find

Added lookup and find

--- src/main/cljs/fast_map/core.cljs
+++ src/main/cljs/fast_map/core.cljs
@@ -92,7 +92,34 @@
           (aset new-arr (inc (* 2 idx)) val)
           (array-copy arr (* 2 idx) new-arr (* 2 (inc idx)) (* 2 (- n idx)))
           (set! (.-added changed?) true)
-          (BitmapIndexedNode. aedit (bit-or datamap bit) nodemap new-arr))))))
+          (BitmapIndexedNode. aedit (bit-or datamap bit) nodemap new-arr)))))
+
+  (inode-lookup [inode shift hash key not-found]
+    (let [bit (bitpos hash shift)]
+      (cond
+        (not (zero? (bit-and datamap bit)))
+        (let [idx (bitmap-indexed-node-index datamap bit)
+              k (aget arr (* 2 idx))]
+          (if (=  k key)
+            (aget arr (inc (* 2 idx)))
+            not-found))
+        (not (zero? (bit-and nodemap bit)))
+        (.inode-lookup (node-at arr nodemap bit) (+ shift 5) hash key not-found)
+        :else
+        not-found)))
+  (inode-find [inode shift hash key not-found]
+    (let [bit (bitpos hash shift)]
+      (cond
+        (not (zero? (bit-and datamap bit)))
+        (let [idx (bitmap-indexed-node-index datamap bit)
+              k (aget arr (* 2 idx))]
+          (if (= k key)
+            [k (aget arr (inc (* 2 idx)))]
+            not-found))
+        (not (zero? (bit-and nodemap bit)))
+        (.inode-lookup (node-at arr nodemap bit) (+ shift 5) hash key not-found)
+        :else
+        not-found))))

 (set! (.-EMPTY BitmapIndexedNode) (BitmapIndexedNode. nil 0 0 (make-array 0)))

@@ -114,7 +141,19 @@
           (HashCollisionNode. nil collision-hash (inc cnt) new-arr))
         (if (= (aget arr idx) val)
           inode
-          (HashCollisionNode. nil collision-hash cnt (clone-and-set arr (inc idx) val)))))))
+          (HashCollisionNode. nil collision-hash cnt (clone-and-set arr (inc idx) val))))))
+
+  (inode-lookup [inode shift hash key not-found]
+    (let [idx (hash-collision-node-find-index arr cnt key)]
+      (cond (< idx 0)              not-found
+            (key-test key (aget arr idx)) (aget arr (inc idx))
+            :else                  not-found)))
+
+  (inode-find [inode shift hash key not-found]
+    (let [idx (hash-collision-node-find-index arr cnt key)]
+      (cond (< idx 0)              not-found
+            (key-test key (aget arr idx)) [(aget arr idx) (aget arr (inc idx))]
+            :else                  not-found))))

 (defn- create-node [edit shift key1 val1 key2hash key2 val2]
   (let [key1hash (hash key1)]
@@ -290,9 +329,11 @@
     (print-map coll pr-writer writer opts)))

 (comment
-    (let [em (.-EMPTY PersistentHashMap)
-          hm1 (loop [m em i 0]
-                (if (< i 50)
-                  (recur (assoc m (str "key" i) i) (inc i))
-                  m))]
-      (println hm1)))+  (let [em (.-EMPTY PersistentHashMap)
+        hm1 (loop [m em i 0]
+              (if (< i 50)
+                (recur (assoc m (str "key" i) i) (inc i))
+                m))]
+    (println hm1)
+    [(= (into #{} (vals hm1)) (into #{} (map #(get hm1 (str "key" %)) (range 50))))
+     (= (keys hm1) (map (fn [[k v]] k) hm1))]))


core: number

core: number

--- data/core.clj
+++ data/core.clj
@@ -1702,3 +1702,9 @@
   "Coerce to bool"
   {:added "1.0"}
   [x] (bool* x))
+
+(defn number?
+  "Returns true if x is a Number"
+  {:added "1.0"}
+  [x]
+  (instance? Number x))


make release task more general and customizable with :release key in project.clj

--- src/cake/tasks/release.clj
+++ src/cake/tasks/release.clj
@@ -139,21 +139,23 @@
               (send-ack out)
               (wait-for-ack in)))))))

-(defn upload-to-clojars [jarfile]
-  (log "Releasing jar:" jarfile)
-  (ssh-session {:host "clojars.org" :username "clojars"}
-    (upload ["pom.xml" jarfile])))
-
-(deftask release #{jar}
-  "Release project jar to clojars."
-  (upload-to-clojars (jarfile)))
-
 (defn- lookup-file [file]
   (case file
     :jar     (jarfile)
     :uberjar (uberjarfile)
     :war     (warfile)
     file))
+
+(deftask release #{jar}
+  "Release project jar (to clojars by default)."
+  (let [release  (:release *project*)
+        files    (or (:files    release) [:jar "pom.xml"])
+        host     (or (:host     release) "clojars.org")
+        username (or (:username release) "clojars")
+        dest     (or (:dest     release) ".")]
+    (when (#{"y" "Y"} (prompt-read (format "Are you sure you want to release to %s? [y/N]" host)))
+      (ssh-session {:host host :username username}
+        (upload (map lookup-file files) dest)))))

 (deftask deploy
   "Deploy project to a group of servers."


dont read readme.txt, just pngs

dont read readme.txt, just pngs

--- examples/src/worksheets/captcha_wikipedia.clj
+++ examples/src/worksheets/captcha_wikipedia.clj
@@ -51,7 +51,7 @@
       ;; ABC observe
       (observe (abc-dist rendered-image abc-sigma) baseline-image)

-      ;; Retunrs
+      ;; Returns
       {:letters letters
        :font-size font-size
        :kerning kerning})))
@@ -98,7 +98,8 @@

 ;; @@
 (def directory (clojure.java.io/file "resources/wikipedia-dataset"))
-(def files (take 100 (rest (file-seq directory))))
+(def files (take 100 (filter #(= ".png" (apply str (take-last 4 (.getPath %))))
+                             (rest (file-seq directory)))))
 (def num-observes (count files))
 (def observes (doall (map vec (map (fn [f] (map vec (.load oxCaptcha (.getPath f)))) files))))
 (def ground-truth-letters (map (fn [f] (clojure.string/replace (.getName f) ".png" "")) files))


Ensure jobs have keypath

Ensure jobs have keypath

--- src-cljs/frontend/send.cljs
+++ src-cljs/frontend/send.cljs
@@ -93,8 +93,8 @@
                          (assoc-in [:job/run :run/id] run-id)))
                    (:workflow/jobs response))
         jobs-by-id (into {} (map (juxt :job/id identity) jobs))
-        jobs-with-normalized-required (map #(denormalize-required % jobs-by-id)
-                                           jobs)
+        jobs-with-normalized-required (mapv #(denormalize-required % jobs-by-id)
+                                            jobs)
         {:keys [build/vcs-type build/org build/repo]} (get-in response
                                                               [:workflow/jobs
                                                                0


Make the logo slightly bigger

Make the logo slightly bigger

--- src/catalog/layout/fop.clj
+++ src/catalog/layout/fop.clj
@@ -527,10 +527,10 @@
        (mapcat #(format-sexp (get subitems %) % 1 path-to-numbers false) (keys subitems))])]])

 (defn- logo []
-  [:fo:block {:space-before "120mm"}
+  [:fo:block {:space-before "110mm"}
    [:fo:external-graphic
     {:src (io/resource "images/sbs_logo.jpg")
-     :height "25mm"
+     :height "35mm"
      :scaling "uniform"
      :content-width "scale-to-fit"
      :content-height "scale-to-fit"}]])


Fix a subtle bug to do with bindings and lazy sequences

That manifests itself in the large print output

--- src/catalog/layout/fop.clj
+++ src/catalog/layout/fop.clj
@@ -487,7 +487,15 @@
                                 :recommendation recommendations))]
         [:fo:flow {:flow-name "xsl-region-body"}
          (toc subitems [fmt] 2 nil :heading? true)
-         (mapcat #(genre-sexp (get subitems %) fmt % 1) (keys subitems))])]]))
+         ;; FIXME: there is a subtle bug to do with bindings and lazy
+         ;; sequences. Since we return a lazy seq here the mapcat
+         ;; might be realized outside the binding scope and might get
+         ;; the wrong *stylesheet*. So as a workaround we make sure
+         ;; the sequence is fully realized with `doall` (see also
+         ;; http://cemerick.com/2009/11/03/be-mindful-of-clojures-binding/).
+         ;; Maybe the binding solution isn't the bees knees after all.
+         (doall
+          (mapcat #(genre-sexp (get subitems %) fmt % 1) (keys subitems)))])]]))

 (defmethod document-sexp :hörbuch
   [items fmt editorial recommendations {:keys [description date]}]


Fix spelling

Fix spelling

ettiket is spelled etikett

--- src/catalog/layout/fop.clj
+++ src/catalog/layout/fop.clj
@@ -576,10 +576,10 @@

 (defn- coverpage-recto-internal
   "Return a hiccup style sexp for the recto (the front) of the coverpage
-  for given `title`, `year`, `issue`, `svg`, `ettiket` and `colophon`.
-  The `svg` is expected to contain the right background. The `ettiket`
+  for given `title`, `year`, `issue`, `svg`, `etikett` and `colophon`.
+  The `svg` is expected to contain the right background. The `etikett`
   and `colophon` can be nil."
-  [title year issue svg ettiket colophon]
+  [title year issue svg etikett colophon]
   (let [fill-color (format "fill:%s device-%s" (color-rgb issue) (color issue))]
     [:fo:page-sequence {:id "cover-recto" :master-reference "cover-recto"
                         :force-page-count "even"
@@ -592,9 +592,9 @@
                {:src (io/resource svg)
                 :width "100%" :content-width "scale-to-fit"
                 :fox:alt-text "Seiten-Hintergrund mit SBS Logo"}])]
-      (coverpage-recto-background fill-color (some? ettiket))]
+      (coverpage-recto-background fill-color (some? etikett))]
      [:fo:flow {:flow-name"xsl-region-body"}
-      ettiket
+      etikett
       (block {:start-indent "3mm" :end-indent "3mm"
               :font-size "90pt" :color (color :warmgrey) :line-height "0.9"
               :text-align "start" :hyphenate "false"
@@ -627,13 +627,13 @@
 (defmethod coverpage-recto :grossdruck
   [title year issue _]
   (let [svg "covers/cover-recto-grossdruck.svg"]
-    ;; a large print recto page has no ettiket but it has a colophon
+    ;; a large print recto page has no etikett but it has a colophon
     (coverpage-recto-internal title year issue svg nil coverpage-colophon)))

 (defmethod coverpage-recto :default
   [title year issue _]
   (let [svg "covers/cover-recto.svg"
-        ettiket [:fo:wrapper {:role "artifact"}
+        etikett [:fo:wrapper {:role "artifact"}
                  [:fo:block-container {:absolute-position "fixed" :width "33mm" :height "15mm"
                                        :left "56mm" :top "135mm" :display-align "center"
                                        :background-color "transparent"}
@@ -641,8 +641,8 @@
                           :text-align "center" :color (color :white)
                           :role "H2"}
                          "neu")]]]
-    ;; a default recto page has an ettiket but no colophon
-    (coverpage-recto-internal title year issue svg ettiket nil)))
+    ;; a default recto page has an etikett but no colophon
+    (coverpage-recto-internal title year issue svg etikett nil)))

 (defn- coverpage-verso-internal
   "Return a hiccup style sexp for the verso (the back) of the coverpage


improved try-either function

improved try-either function

previously it would only take a single form as the body
now it returns the last item in the body as a right, as is normal

--- src/cats/monad/either.cljc
+++ src/cats/monad/either.cljc
@@ -324,5 +324,7 @@
      if an exception is throw return the exception as a left,
      otherwise returns the result as a right"
      [& body]
-     `(try (right ~@body)
-           (catch Exception e# (left e#)))))
+     `(try
+        ~@(butlast body)
+        (right ~(last body))
+        (catch Exception e# (left e#)))))


removing n

removing n

--- src/celestial/api/jobs.clj
+++ src/celestial/api/jobs.clj
@@ -115,8 +115,8 @@
          :notes "job status can be pending, processing, done or nil"}
         (success {:job (jobs/status queue uuid)}))

-  (GET- "/jobs/runnning" []
-        {:nickname "jobsStatus" :summary "Global job status tracking"
+  (GET- "/jobs/running" []
+        {:nickname "getRunningJobs" :summary "Get currently running jobs"
          :notes "job status can be either pending, processing, done or nil"}
         (let [{:keys [username]} (friend/current-authentication)
               {:keys [envs] :as user} (u/get-user username)]


2016 day 1

2016 day 1

--- src/advent_2016/day_01.cljs
+++ src/advent_2016/day_01.cljs
@@ -1 +1,80 @@
-(ns advent-2016.day-01)
+(ns advent-2016.day-01
+  (:require [clojure.set :as set]))
+
+(defn parse-turn
+  [s]
+  (case s
+    "R" :right
+    "L" :left))
+
+(defn parse-blocks
+  [s]
+  (js/parseInt s))
+
+(defn parse-move
+  [move]
+  (let [move-str (str move)]
+    {:turn   (parse-turn (first move-str))
+     :blocks (parse-blocks (subs move-str 1))}))
+
+(def directions-clockwise [:north :east :south :west])
+
+(def right-turns (zipmap directions-clockwise (concat (rest directions-clockwise) [(first directions-clockwise)])))
+
+(def left-turns (set/map-invert right-turns))
+
+(defn update-direction
+  [direction turn]
+  (let [turns (case turn
+                :right right-turns
+                :left left-turns)]
+    (get turns direction)))
+
+(defn update-location
+  [location direction blocks]
+  (case direction
+    :north (update location :blocks-north + blocks)
+    :east (update location :blocks-east + blocks)
+    :south (update location :blocks-north - blocks)
+    :west (update location :blocks-east - blocks)))
+
+(defn update-state
+  [{:keys [direction location]}
+   {:keys [turn blocks]}]
+  (let [direction (update-direction direction turn)
+        location (update-location location direction blocks)]
+    {:direction direction
+     :location  location}))
+
+(defn follow-moves
+  [state moves]
+  (reduce update-state state moves))
+
+(defn distance
+  [{:keys [blocks-east blocks-north]}]
+  (+ (Math/abs blocks-east) (Math/abs blocks-north)))
+
+(defn calcluate-solution
+  [initial-state moves]
+  (-> (follow-moves initial-state moves)
+    :location
+    distance))
+
+(defn solve
+  []
+  (let [raw-moves '[R3, L2, L2, R4, L1, R2, R3, R4, L2, R4, L2, L5, L1, R5,
+                    R2, R2, L1, R4, R1, L5, L3, R4, R3, R1, L1, L5, L4, L2,
+                    R5, L3, L4, R3, R1, L3, R1, L3, R3, L4, R2, R5, L190,
+                    R2, L3, R47, R4, L3, R78, L1, R3, R190, R4, L3, R4, R2,
+                    R5, R3, R4, R3, L1, L4, R3, L4, R1, L4, L5, R3, L3, L4,
+                    R1, R2, L4, L3, R3, R3, L2, L5, R1, L4, L1, R5, L5, R1,
+                    R5, L4, R2, L2, R1, L5, L4, R4, R4, R3, R2, R3, L1, R4,
+                    R5, L2, L5, L4, L1, R4, L4, R4, L4, R1, R5, L1, R1, L5,
+                    R5, R1, R1, L3, L1, R4, L1, L4, L4, L3, R1, R4, R1, R1,
+                    R2, L5, L2, R4, L1, R3, L5, L2, R5, L4, R5, L5, R3, R4,
+                    L3, L3, L2, R2, L5, L5, R3, R4, R3, R4, R3, R1]
+        moves (map parse-move raw-moves)
+        initial-state {:direction :north
+                       :location  {:blocks-east  0
+                                   :blocks-north 0}}]
+    (calcluate-solution initial-state moves)))


Slight speedup of ebmd

Slight speedup of ebmd

--- src/bluebell/utils/ebmd.clj
+++ src/bluebell/utils/ebmd.clj
@@ -635,7 +635,7 @@
 (defn- promotion-path-sub [visited arg-spec x]
   (cond
     (contains? visited arg-spec) nil
-    (matches-arg-spec? arg-spec x) []
+    (matches-arg-spec? arg-spec x) (transient [])
     :default (let [visited (conj visited arg-spec)
                    chain (trace-arg-spec-chain arg-spec)
                    candidates (transduce
@@ -647,7 +647,7 @@
                                               (when-let
                                                   [p (promotion-path-sub
                                                       visited k x)]
-                                                (conj p kv)))))
+                                                (conj! p kv)))))
                                      (filter identity))
                                (completing shortest-path)
                                nil
@@ -915,7 +915,8 @@
   nil)

 (defn promotion-path [arg-spec x]
-  (promotion-path-sub #{} arg-spec x))
+  (if-let [result (promotion-path-sub #{} arg-spec x)]
+    (persistent! result)))

 (defn promote-along-path
   ([promotion-path x]


Fix bad return value in artifact-versions

It was returning a list of list of versions, it should be a list of versions.

--- src/refactor_nrepl/artifacts.clj
+++ src/refactor_nrepl/artifacts.clj
@@ -94,7 +94,7 @@
 (defn- artifact-versions [{:keys [transport artifact] :as msg}]
   (when (stale-cache?)
     (update-artifact-cache!))
-  (let [versions (->> artifact (@artifacts) list)]
+  (let [versions (->> artifact (@artifacts) list*)]
     (transport/send transport (response-for msg :versions versions  :status :done))))

 (defn- hotload-dependency


Slightly better code.

Slightly better code.

--- src/clj/game/core-costs.clj
+++ src/clj/game/core-costs.clj
@@ -37,7 +37,7 @@
         cost-msg (or (some #(toast-msg-helper state side %) costs)
                      (when (and forfeit-cost (empty? scored)) "Unable to forfeit an Agenda"))]
     ; no cost message - hence can pay
-    (if (not cost-msg)
+    (if-not cost-msg
       {:costs costs, :forfeit-cost forfeit-cost, :scored scored}
       ; only toast if title is specified
       (when title (toast state side (str cost-msg " for " title)) false))))


renamings

renamings

--- src/cljs/triboard/core.cljs
+++ src/cljs/triboard/core.cljs
@@ -34,10 +34,10 @@
   (atom {:games (game/new-game)
          :help false}))

-(def game (reaction (game/current-turn (:games @app-state))))
-(def board (reaction (turn/get-board @game)))
-(def scores (reaction (turn/get-scores @game)))
-(def current-player (reaction (turn/current-player @game)))
+(def current-turn (reaction (game/current-turn (:games @app-state))))
+(def board (reaction (turn/get-board @current-turn)))
+(def scores (reaction (turn/get-scores @current-turn)))
+(def current-player (reaction (turn/current-player @current-turn)))

 ;; -----------------------------------------
@@ -52,7 +52,7 @@

 (defn- handle-ai! []
   ;; TODO - Find a way to cache the cells-strenght as it was done before
-  (let [move (ai/best-move (ai/compute-cells-strength @board) @game @current-player)]
+  (let [move (ai/best-move (ai/compute-cells-strength @board) @current-turn @current-player)]
     (play-game-turn! move)))

 (defn- handle-game-event!
@@ -65,7 +65,7 @@
 (defn start-game-loop
   "Manage transitions between player moves, ai moves, and generic game events"
   []
-  (let [game-on-xf (fn [_] (not (turn/game-over? @game)))
+  (let [game-on-xf (fn [_] (not (turn/game-over? @current-turn)))
         is-human-xf (fn [_] (not (is-ai? @current-player)))
         player-events (chan 1 (comp (filter game-on-xf) (filter is-human-xf)))
         game-events (chan 1)]
@@ -101,7 +101,7 @@
   (and
     (:help @app-state)
     (not (is-ai? @current-player))
-    (turn/get-move-at @game @current-player [x y])))
+    (turn/get-move-at @current-turn @current-player [x y])))

 (def interactions
   (reify view/CallBacks


out links analytics fix

out links analytics fix

--- src/clojure/nossal/data.clj
+++ src/clojure/nossal/data.clj
@@ -53,7 +53,7 @@
     {:vars {:account (env :google-analytics)}
      :triggers {:trackPageview {:on "visible" :request "pageview"}
                 :outboundLinks {:on "click"
-                                :selector "a"
+                                :selector "a.out"
                                 :request "event"
                                 :vars {:eventCategory "outbound"
                                        :eventLabel "${outboundLink}"


remove invlid urls, expand relative ones and bump timeout

--- src/link_checker/github.clj
+++ src/link_checker/github.clj
@@ -6,7 +6,8 @@
             [com.github.ragnard.hamelito.hiccup :as haml]
             [net.cgrand.enlive-html :as enlive]
             [link-checker.util :refer [get! average difference-in-hours format-date]]
-            [clostache.parser :as clostache]))
+            [clostache.parser :as clostache])
+  (:import [java.net URL]))

 ;;; helpers
 (defn gh-auth
@@ -65,8 +66,8 @@
 (def default-clj-http-options
   {:max-redirects 5
    :throw-exceptions false
-   :conn-timeout 100
-   :socket-timeout 1000})
+   :conn-timeout 3000
+   :socket-timeout 3000})

 (defn- fetch-link [url]
   (log/info :msg (format "Fetching link %s" url))
@@ -95,13 +96,29 @@
                          #(get-in % [:attrs :href])
                          enlive-maps))))

+(defn- invalid-link?
+  [link]
+  (or (contains? #{nil "" "#"} link)
+      (re-find #"^(javascript:|irc:)" link)))
+
+;;; thanks to alida's util.cl
+(defn- expand-relative-links
+  [url links]
+  (let [jurl (URL. url)]
+    (map #(str (URL. jurl %)) links)))
+
 (defn- url->links
   [url]
   (let [resp (try
                (client/get url default-clj-http-options)
                (catch Exception e nil))]
     (when (= 200 (:status resp))
-      (filter #(re-find #"^http" (str %)) (doto (body->links (:body resp)) prn)))))
+      (expand-relative-links
+       url
+       (->> (:body resp)
+            body->links
+            distinct
+            (remove invalid-link?))))))

 (defn- stream-repositories*
   "Sends 3 different sse events (message, results, end-message) depending on


remove dead comment

remove dead comment

--- src/clj/cljs/repl/node.clj
+++ src/clj/cljs/repl/node.clj
@@ -102,9 +102,7 @@
       (let [core-js (closure/compile core
                       (assoc opts
                         :output-file
-                        (closure/src-file->target-file core)
-                        ;:static-fns true
-                        ))
+                        (closure/src-file->target-file core)))
             deps    (closure/add-dependencies opts core-js)]
         ;; output unoptimized code and the deps file
         ;; for all compiled namespaces


Run tests in the process rather than in Leiningen by default.

--- src/clj/leiningen/spec.clj
+++ src/clj/leiningen/spec.clj
@@ -30,7 +30,7 @@

 That ought to do the trick."
   [project & args]
-  (let [project (assoc project :eval-in (get project :speclj-eval-in :leiningen))
+  (let [project (assoc project :eval-in (get project :speclj-eval-in :subprocess))
         speclj-args (build-args project args)]
     (exit-if-needed
       (eval-in-project project


Remove rulesclj junk file

Remove rulesclj junk file

--- src/clj/libx/rulesclj.cljc
+++ src/clj/libx/rulesclj.cljc
@@ -1,202 +0,0 @@
-(ns libx.rulesclj)
-;   (:require [clara.rules :refer [insert!
-;                                  insert-all
-;                                  insert-all!
-;                                  insert-unconditional!
-;                                  insert-all-unconditional!
-;                                  retract! query fire-rules
-;                                  mk-session
-;                                  defrule defquery defsession]]
-;             [libx.tuplerules :refer [def-tuple-session def-tuple-rule]]
-;             [libx.util :refer [retract
-;                                 insert
-;                                map->tuples
-;                                 entities-where
-;                                 entity
-;                                 attr-ns]]
-;             [clara.rules.accumulators :as acc]
-;             [clara.tools.inspect :as inspect]
-;             [clara.tools.tracing :as trace]
-;             [clara.rules.compiler :as com]
-;             [clojure.tools.namespace.repl :refer [refresh]]
-;             [clara.rules.engine :as eng]
-;             [clara.rules.listener :as l])
-;  (:import clara.tools.tracing.TracingListener))
-;[clara.tools.watch :as watch]
-
-;
-;(defn random-uuid []
-;  (java.util.UUID/randomUUID))
-
-;(defn todo-tx [id title done]
-;  (merge
-;    {:db/id      id
-;     :todo/title title
-;    (when-not (nil? done)
-;      {:todo/done done}))
-;
-;(defn visibility-filter-tx [id kw]
-;  {:db/id                id
-;   :ui/visibility-filter kw))
-;
-;(defn toggle-tx [id bool]
-;  {:db/id              id
-;   :ui/toggle-complete bool))
-;
-;(def clear-completed-action
-;  {:db/id              (random-uuid)
-;   :ui/clear-completed :tag))
-
-;(def-tuple-rule todo-is-visible-when-filter-is-all
-;  [[_ :ui/visibility-filter :all]]
-;  [[?e :todo/title]]
-;  =>
-;  (insert! [?e :todo/visible :tag]))
-
-;(defrule todo-is-visible-when-filter-is-done-and-todo-done
-;  [:ui/visibility-filter [[e a v]] (= v :done)]
-;  [:todo/done [[e a v]] (= e ?e)]
-;  =>
-;  (insert! [?e :todo/visible :tag]))
-;
-;(defrule todo-is-visible-when-filter-active-and-todo-not-done
-;  [:ui/visibility-filter [[e a v]] (= v :active)]
-;  [:todo/title [[e a v]] (= ?e e)]
-;  [:not [:todo/done [[e a v]] (= e ?e)]]
-;  =>
-;  (insert! [?e :todo/visible :tag]))
-
-;(defrule toggle-all-complete
-;  ; when toggle complete action exists
-;  [:exists [:ui/toggle-complete]]
-;  ; and there's a todo that isn't marked "done"
-;  [:todo/title [[e a v]] (= ?e e)]
-;  [:not [:todo/done [[e a v]] (= ?e e)]]
-;  =>
-;  (println "Marked done via toggle complete:" ?e)
-;  (insert-unconditional! [?e :todo/done :done]))
-;
-;(defrule remove-toggle-complete-when-all-todos-done
-;  [?toggle <- :ui/toggle-complete [[e a v]] (= v true)]
-;  [?total <- (acc/count) :from [:todo/title]]
-;  [?total-done <- (acc/count) :from [:todo/done]]
-;  [:test (not (not (= ?total ?total-done)))]
-;  =>
-;  (println "Total todos: " ?total)
-;  (println "Total done: " ?total-done)
-;  (println "Retracting toggle-all-complete action: " ?toggle)
-;  (retract! ?toggle))
-
-;(defrule no-done-todos-when-clear-completed-action
-;  ; when clear completed action exists
-;  [:exists [:ui/clear-completed]]
-;  ; and there's a todo that is marked "done"
-;  [:todo/title [[e a v]] (= ?e e)]
-;  [:todo/done [[e a v]] (= ?e e)]
-;  [?entity <- (acc/all) :from [:all [[e a v]] (= ?e e)]]
-;  =>
-;  ; (retract {:todo/keys :all})
-;  ; (retract {:todo/keys [title visible done]})
-;  ; (retract-entity ?e)
-;  ;; can we run a query in RHS???
-;  (println "Retracting entity " ?entity)
-;  (doseq [tuple ?entity] (retract! tuple)))
-;
-;(defrule clear-completed-action-is-done-when-no-done-todos
-;  [?action <- :ui/clear-completed]
-;  [:not [:exists [:todo/done]]]
-;  =>
-;  (println "Clear-completed action finished. Retracting " ?action)
-;  (retract! ?action))
-
-;(defrule todo-is-visible-when-a-friday
-;  [:exists [:today/is-friday]]
-;  [:todo/title [[e a v]] (= ?e e)]
-;  =>
-;  (println "BOOM")
-;  (insert! [?e :todo/visible* :tag]))
-;
-;(defrule todo-visible-*
-;  [:exists [:todo/visible* [[e a v]] (= e? e)]]
-;  =>
-;  (insert! [?e :todo/visible :tag]))
-
-;(defrule print-all-facts
-;  [?fact <- :all [[e a v]] (= ?e e) (= ?a a) (= ?v v)]
-;  =>
-;  (println "FACT" ?fact))
-;
-;(defrule mytuplerule
-;  [:all [[e a v]] (= ?v v) (= ?e e)]
-;  [:all [[e a v]] (= a ?v) (= ?e2 e)]
-;  [:test (= ?e2 ?e)]
-;  =>
-;  (println "Found :entity whose value is the same as one of its attributes!"))
-
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; Queries
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
-;(defquery find-all-done []
-;  [:all [[e a v]] (= e ?e) (= a ?a) (= v ?v)]
-;  [:test (= (attr-ns ?a) "todo")])
-;
-;(defquery find-done-count []
-;  [?count <- (acc/count) :from [:todo/done]])
-
-;(defsession todos 'libx.rulesclj
-;  :fact-type-fn (fn [[e a v]] a)
-;  :ancestors-fn (fn [type] [:all]))
-
-;(def empty-session
-;  (mk-session 'libx.rulesclj
-;    :fact-type-fn (fn [x] (second x))
-;    :ancestors-fn (fn [type] [:all])))
-
-;(def facts
-;  (apply concat
-;    (map->tuples (toggle-tx (random-uuid) true))
-;    (map->tuples (visibility-filter-tx (random-uuid) :active))
-;    (mapv map->tuples (repeatedly 5 #(todo-tx (random-uuid) 1111 nil)))))
-;
-;
-;(def wfacts (fire-rules (insert-all empty-session facts)))
-;
-;(-> [wfacts] clara.rules.compiler/to-beta-graph clojure.pprint/pprint)
-;(-> [wfacts] clara.rules.compiler/to-alpha-graph clojure.pprint/pprint)
-;(inspect/inspect wfacts)
-
-;(defrecord Entity [e a v])
-
-;(defrule myrule
-;  [Entity (= ?v v) (= ?e e)]
-;  [Entity (= a ?v) (= ?e2 e)]
-;  [:test (= ?e2 ?e)]
-;  =>
-;  (println "Found Entity whose value is the same as one of its attributes!"))
-
-
-;(->Entity 1 2 3)
-
-;(def record-session
-;  (->
-;    (mk-session [myrule])
-;    (trace/with-tracing)
-;    (insert-all (into
-;                    [(->Entity 123 :hi "there")
-;                     (->Entity 123 :oh :hi)
-;                   (repeatedly 5 #(->Entity "null" true "null"))
-;    (fire-rules))
-;(-> [record-session] clara.rules.compiler/to-beta-graph clojure.pprint/pprint)
-;(-> [record-session] clara.rules.compiler/to-alpha-graph clojure.pprint/pprint)
-;(inspect/inspect record-session)
-;(inspect/explain-activations record-session)
-;(trace/get-trace record-session)
-;(-> [record-session] com/to-beta-graph clojure.pprint/pprint)
-
-;(-> [tuple-session] clara.rules.compiler/to-beta-graph clojure.pprint/pprint)
-;(-> [tuple-session] clara.rules.compiler/to-alpha-tree clojure.pprint/pprint)
-;(inspect/inspect tuple-session)
-;(inspect/explain-activations tuple-session)
-


Lists all orders.

Lists all orders.

--- src/cljs/pos_clj/core.cljs
+++ src/cljs/pos_clj/core.cljs
@@ -1,16 +1,20 @@
 (ns pos-clj.core
   (:require [om.core :as om :include-macros true]
-            [om.dom :as dom :include-macros true]))
+            [om.dom :as dom :include-macros true]
+            [sablono.core :as html :refer-macros [html]]))

 (enable-console-print!)

-(defonce app-state (atom {:text "POS CLJ"}))
+(defonce app-state (atom {:orders [{:table-number 1 :status "OPEN"} {:table-number 2 :status "CLOSE"}]}))

 (defn root-component [app owner]
   (reify
     om/IRender
     (render [_]
-      (dom/div nil (dom/h1 nil (:text app))))))
+      (html
+       [:div
+        [:h1 "Orders"]
+        [:div (map (fn [order] [:div (str "order: " (:table-number order))]) (:orders app))]]))))

 (om/root
  root-component


(SERVER-377) Make environment variable tests more robust

Filter the proxy-related environment variables out in the
jruby-environment-vars-test, so that in case they are set in any environment,
this test won't fail.

--- test/integration/puppetlabs/services/jruby/jruby_puppet_pool_int_test.clj
+++ test/integration/puppetlabs/services/jruby/jruby_puppet_pool_int_test.clj
@@ -28,6 +28,7 @@
             [puppetlabs.services.jruby-pool-manager.jruby-pool-manager-service :as jruby-utils]
             [puppetlabs.kitchensink.core :as ks]
             [puppetlabs.services.jruby.jruby-puppet-core :as jruby-puppet-core]
+            [puppetlabs.services.jruby-pool-manager.jruby-core :as jruby-core]
             [puppetlabs.services.jruby-pool-manager.impl.jruby-agents :as jruby-agents]
             [puppetlabs.trapperkeeper.config :as tk-config])
   (:import (org.jruby RubyInstanceConfig$CompileMode CompatVersion)))
@@ -450,12 +451,14 @@
             jruby-scripting-container (:scripting-container jruby-instance)
             jruby-env (.runScriptlet jruby-scripting-container "ENV")]
         (try
-         ;; Note that if this test is run in an environment where the
-         ;; variables HTTP_PROXY, HTTPS_PROXY, NO_PROXY, or their lowercase
-         ;; variants are set, this will fail.
+         ;; Note that other environment variables are allowed through
+         ;; (HTTP_PROXY, HTTPS_PROXY, NO_PROXY, or their lowercase
+         ;; variants) but are not expected to be set in most environments.
+         ;; However, in order to make this test more robust, these variables
+         ;; are always filtered out.
           (is (= #{"HOME" "PATH" "GEM_HOME" "GEM_PATH"
                    "JARS_NO_REQUIRE" "JARS_REQUIRE" "RUBY" "FOO"}
-                 (set (keys jruby-env))))
+                 (set (remove (set jruby-core/proxy-vars-allowed-list) (keys jruby-env)))))
           (is (= (.get jruby-env "FOO") (System/getenv "HOME")))
           (finally
             (jruby-testutils/return-instance jruby-service jruby-instance :test)))))))


Made unicode exact matching

Made unicode exact matching

--- src/demogorgon/unicode.clj
+++ src/demogorgon/unicode.clj
@@ -12,7 +12,7 @@
                 (let [tokens (.split line "\t")
                       ^String name (.trim (aget tokens 0))
                       ^String codepoint (.trim (aget tokens 1))]
-                  (if (or (.startsWith (.toLowerCase name) symbol)
+                  (if (or (= symbol (.toLowerCase name))
                           (= symbol (.toLowerCase codepoint)))
                     {:name name :codepoint codepoint}
                     nil))) lines)))))


Improve Testbed image download log output even more

--- src/env_logger/handler.clj
+++ src/env_logger/handler.clj
@@ -169,14 +169,20 @@
                                                  (t/now)))
                               (let [image (get-testbed-image)]
                                 (if (or (nil? image)
-                                        (zero? (count image)))
+                                        (< (count image) 5000))
                                   (do
-                                    (log/error (format (str "Testbed image at"
-                                                            " %s is empty")
-                                                       (f/unparse
-                                                        (f/formatters
-                                                         :date-time-no-ms)
-                                                        (t/now))))
+                                    (log/error (format
+                                                (str "Testbed image at"
+                                                     " %s is empty"
+                                                     (if-not (nil? image)
+                                                       (str " (size "
+                                                            (count image)
+                                                            " bytes")
+                                                       ""))
+                                                (f/unparse
+                                                 (f/formatters
+                                                  :date-time-no-ms)
+                                                 (t/now))))
                                     nil)
                                   image)))
               insert-status (db/insert-observation


added pause button to uninitialized uploads

--- src/frontend/renderer.cljs
+++ src/frontend/renderer.cljs
@@ -103,6 +103,9 @@
                                                           (dissoc (:uploads @app-state/app-state)
                                                                   (:id data)))}
                                     "CANCEL")
+                        (if (:paused? data)
+                          (dom/button #js {:onClick #(core/resume-upload! (:id data))} "RESUME")
+                          (dom/button #js {:onClick #(core/pause-upload!  (:id data))} "PAUSE"))
                         "Not yet started: "
                         (:filename data))))))


RR: convert to hiccup style

RR: convert to hiccup style

--- src/hatti/views/table.cljs
+++ src/hatti/views/table.cljs
@@ -11,7 +11,7 @@
                                  label-changer submission-view]]
             [hatti.views.record]
             [hatti.shared :as shared]
-            [hatti.utils :refer [click-fn hyphen->camel-case
+            [hatti.utils :refer [click-fn generate-html hyphen->camel-case
                                  last-url-param safe-regex url]]
             [cljsjs.slickgrid-with-deps]))

@@ -90,13 +90,13 @@
         project-id (last-url-param project)
         edit-link (url form-owner project-id formid
                        (str "webform?instance-id=" value))]
-    (str
-     ""
-     ""
+    (generate-html
+     [:a.view-record {:title "View"}
+      [:i.fa.fa-clone {:data-id value}]]
      "  "
-     ""
-     "")))
+     [:a.edit-record {:data-id value :target "_blank" :title "Edit"
+                      :href edit-link}
+      [:i.fa.fa-pencil-square-o]])))

 (def actions-column
   {:id "actions" :field _id :type "text"
@@ -146,13 +146,11 @@
   (let [actions (.getElementsByClassName js/document "record-actions")
         sg-viewport (first (.getElementsByClassName js/document
                                                     "slick-viewport"))]
-
     (doseq [action actions]
       (let [leftOffset (js/parseInt (.-offsetLeft action))]
         (.addEventListener sg-viewport "scroll"
                            (fn []
                              (set! (.-left (.-style action))
-
                                    (str (+ (.-scrollLeft  sg-viewport)
                                            leftOffset)
                                         "px"))))))))


formatter bug: prevent quote from being interpretted inside a comment

--- src/parinfer/formatter.cljs
+++ src/parinfer/formatter.cljs
@@ -115,6 +115,7 @@
   (cond
     (escaping? stack) {:stack (pop stack)}
     (in-str? stack) {:stack (pop stack)}
+    (in-comment? stack) nil
     :else {:stack (conj stack [x-pos ch])}))

 (defmethod push-char* :default


Explicit namespaces

Explicit namespaces

--- test/caesium/crypto/box_test.clj
+++ test/caesium/crypto/box_test.clj
@@ -1,20 +1,20 @@
 (ns caesium.crypto.box-test
   (:require
-   [caesium.crypto.box :refer :all]
-   [caesium.util :refer :all]
+   [caesium.crypto.box :as b]
+   [caesium.util :as u]
    [clojure.test :refer :all]
    [caesium.vectors :as v]))

 (deftest box-keypair-generation
   (testing "generates new keypairs"
-    (is (let [kp1 (generate-keypair)
-              kp2 (generate-keypair)]
-          (and (not (array-eq (:public kp1) (:public kp2)))
-               (not (array-eq (:secret kp1) (:secret kp2)))))))
+    (is (let [kp1 (b/generate-keypair)
+              kp2 (b/generate-keypair)]
+          (and (not (u/array-eq (:public kp1) (:public kp2)))
+               (not (u/array-eq (:secret kp1) (:secret kp2)))))))
   (testing "generate public key from secret key"
-    (is (let [kp1 (generate-keypair)
-              kp2 (generate-keypair (:secret kp1))]
-          (array-eq (:public kp1) (:public kp2))))))
+    (is (let [kp1 (b/generate-keypair)
+              kp2 (b/generate-keypair (:secret kp1))]
+          (u/array-eq (:public kp1) (:public kp2))))))

 (def nonce (v/hex-resource "vectors/box/nonce"))
 (def plaintext (v/hex-resource "vectors/box/plaintext"))
@@ -25,14 +25,14 @@
 (def alice-public-key (v/hex-resource "vectors/box/alice-public-key"))

 (deftest box-encrypt-decrypt-test
-  (is (array-eq ciphertext
-                (encrypt alice-public-key bob-secret-key nonce plaintext))
+  (is (u/array-eq ciphertext
+                  (b/encrypt alice-public-key bob-secret-key nonce plaintext))
       "Bob can encrypt a message for Alice")
-  (is (array-eq plaintext
-                (decrypt bob-public-key alice-secret-key nonce ciphertext))
+  (is (u/array-eq plaintext
+                  (b/decrypt bob-public-key alice-secret-key nonce ciphertext))
       "Alice can decrypt the message from Bob")
-  (let [hex-public-key (hexify alice-public-key)
-        hex-private-key (hexify bob-secret-key)]
+  (let [hex-public-key (u/hexify alice-public-key)
+        hex-private-key (u/hexify bob-secret-key)]
     (is (thrown? java.lang.ClassCastException
-                 (encrypt hex-public-key hex-private-key nonce plaintext))
+                 (b/encrypt hex-public-key hex-private-key nonce plaintext))
         "encrypt does not accept strings")))


Implement basic tests for accumulator api

--- test/flambo/accumulator_test.clj
+++ test/flambo/accumulator_test.clj
@@ -1,6 +1,23 @@
 (ns flambo.accumulator-test
-  (:use midje.sweet))
+  (:use midje.sweet)
+  (:require [flambo.accumulator :as a]
+            [flambo.conf :as conf]
+            [flambo.api :as f]))

 (facts
  "about accumulators"
- (future-fact "some tests"))
+  (let [conf (-> (conf/spark-conf)
+                 (conf/master "local")
+                 (conf/app-name "accumulator-test"))]
+    (f/with-context c conf
+      (facts "about basic accumulation"
+        (let [acc (a/accumulator c 0)
+              named-acc (a/accumulator c 0 "my-acc")
+              rdd (f/parallelize c (range 21))]
+          (fact "acc should be 210"
+            (f/foreach rdd (f/fn [x] (a/add acc x)))
+            (a/value acc) => 210)
+          (fact "named-acc should be 210 and have a name"
+            (f/foreach rdd (f/fn [x] (a/add named-acc x)))
+            (a/value named-acc) => 210
+            (a/name named-acc) => "my-acc"))))))


Fixing unit tests.

Fixing unit tests.

--- test/poky/protocol/http_test.clj
+++ test/poky/protocol/http_test.clj
@@ -67,35 +67,35 @@

 (facts :put :post
        (#'http/wrap-put ..store.. ..bucket.. ..key..
-                        ..params.. ..headers.. ..body..) => (contains {:body ""
+                        ..params.. ..headers.. ..body.. ..uri..) => (contains {:body ""
                                                                        :headers map?
                                                                        :status 200})
        (provided
          (kv/set* ..store.. ..bucket.. ..key.. ..body.. {:modified nil}) => :updated)

        (#'http/wrap-put ..store.. ..bucket.. ..key..
-                        ..params.. ..headers.. ..body..) => (contains {:body ""
+                        ..params.. ..headers.. ..body.. ..uri..) => (contains {:body ""
                                                                        :headers map?
                                                                        :status 200})
        (provided
          (kv/set* ..store.. ..bucket.. ..key.. ..body.. {:modified nil}) => :inserted)

        (#'http/wrap-put ..store.. ..bucket.. ..key..
-                        ..params.. ..headers.. ..body..) => (contains {:body ""
+                        ..params.. ..headers.. ..body.. ..uri..) => (contains {:body ""
                                                                        :headers map?
                                                                        :status 412})
        (provided
          (kv/set* ..store.. ..bucket.. ..key.. ..body.. {:modified nil}) => :rejected)

        (#'http/wrap-put ..store.. ..bucket.. ..key..
-                        ..params.. ..headers.. ..body..) => (contains {:body "Error, PUT/POST could not be completed."
+                        ..params.. ..headers.. ..body.. ..uri..) => (contains {:body "Error, PUT/POST could not be completed."
                                                                        :headers map?
                                                                        :status 500})
        (provided
          (kv/set* ..store.. ..bucket.. ..key.. ..body.. {:modified nil}) => false)

        (#'http/wrap-put ..store.. ..bucket.. ..key..
-                        ..params.. {"if-unmodified-since" "bogus"} ..body..) => (contains
+                        ..params.. {"if-unmodified-since" "bogus"} ..body.. ...uri...) => (contains
                                                                                {:body "Error in If-Unmodified-Since format. Use RFC 1123 date format."
                                                                                :headers map?
                                                                                :status 400}))


entry sorting

entry sorting

--- src/cljs/iwaswhere_web/ui/entry/briefing.cljs
+++ src/cljs/iwaswhere_web/ui/entry/briefing.cljs
@@ -56,16 +56,13 @@
                  [:td [:strong story]]
                  [:td.time (u/duration-string v)]]))]])))))

-(defn entry-compare
-  "Compare by prio first, then by active-from."
-  [k]
-  (fn [x y]
-    (let [prio-x (get-in x [k :priority] :X)
-          prio-y (get-in y [k :priority] :X)
-          c (compare prio-x prio-y)
-          active-x (get-in x [k :active-from])
-          active-y (get-in y [k :active-from])]
-      (if (not= c 0) c (compare active-x active-y)))))
+(defn habit-sorter
+  "Sorts tasks."
+  [x y]
+  (let [c (compare (get-in x [:habit :priority] :X)
+                   (get-in y [:habit :priority] :X))]
+    (if (not= c 0) c (compare (get-in y [:habit :points])
+                              (get-in x [:habit :points])))))

 (defn waiting-habits-list
   "Renders table with open entries, such as started tasks and open habits."
@@ -77,11 +74,10 @@
         entries-list
         (reaction
           (let [entries-map @entries-map
-                sorter (entry-compare :habit)
                 find-missing (u/find-missing-entry entries-map put-fn)
                 entries (->> @waiting-habits
                              (map (fn [ts] (find-missing ts)))
-                             (sort sorter))
+                             (sort habit-sorter))
                 conf (merge @cfg @options)]
             (if (:show-pvt @cfg)
               entries
@@ -117,6 +113,14 @@
                            s/split-lines
                            first)]]))]]])))))

+(defn task-sorter
+  "Sorts tasks."
+  [x y]
+  (let [c (compare (get-in x [:task :priority] :X)
+                   (get-in y [:task :priority] :X))]
+    (if (not= c 0) c (compare (get-in x [:task :active-from])
+                              (get-in y [:task :active-from])))))
+
 (defn started-tasks-list
   "Renders table with open entries, such as started tasks and open habits."
   [tab-group local put-fn]
@@ -143,13 +147,12 @@
                       (name fk)])
         entries-list (reaction
                        (let [entries-map @entries-map
-                             sorter (entry-compare :task)
                              find-missing (u/find-missing-entry entries-map put-fn)
                              entries (->> @started-tasks
                                           (map (fn [ts] (find-missing ts)))
                                           (filter on-hold-filter)
                                           (filter saga-filter)
-                                          (sort sorter))
+                                          (sort task-sorter))
                              conf (merge @cfg @options)]
                          (if (:show-pvt @cfg)
                            entries


Ditto

Ditto

--- src/clojure/clojurewerkz/cassaforte/utils.clj
+++ src/clojure/clojurewerkz/cassaforte/utils.clj
@@ -1,5 +1,5 @@
 (ns clojurewerkz.cassaforte.utils
-  (:use clojurewerkz.cassaforte.cql))
+  (:refer [clojurewerkz.cassaforte.cql :refer :all]))

 (defn- group-map
   "Groups by and applies f to each group"


fix plugin building

fix plugin building

Signed-off-by: Chris Granger <5654cde260ae99bc4d30054171b8bcd902efd19a@gmail.com>

--- lein-light-nrepl/src/lighttable/nrepl/cljs.clj
+++ lein-light-nrepl/src/lighttable/nrepl/cljs.clj
@@ -86,12 +86,12 @@

 (defn source-map-ref []
   (if-let [c (resolve 'cljs.compiler/*source-map-data*)]
-    (@c :source-map)
+    (@@c :source-map)
     @(resolve 'comp/*cljs-source-map*)))

 (defn gen-line []
   (if-let [c (resolve 'cljs.compiler/*source-map-data*)]
-    (@c :gen-line)
+    (@@c :gen-line)
     @(resolve 'comp/*cljs-gen-line*)))

 (defmacro with-cljs-env [cur & body]


Refactor Aeron driver

Refactor Aeron driver

--- src/desdemona/launcher/aeron_media_driver.clj
+++ src/desdemona/launcher/aeron_media_driver.clj
@@ -15,26 +15,23 @@
 (defn -main [& args]
   (let [opts (parse-opts args cli-options)
         {:keys [help threading-mode delete-dirs]} (:options opts)
-        _ (when help
-            (run! (fn [opt]
-                    (println (clojure.string/join " " (take 3 opt))))
-                  cli-options)
-            (System/exit 0))
-        _ (when (and (System/getProperty "aeron.threading.mode") threading-mode)
-            (throw (Exception. "Cannot set both aeron.threading.mode property and threading-mode command-line arg")))
-        threading-mode-obj (cond (or (nil? threading-mode)
-                                     (= threading-mode "shared"))
-                                 ThreadingMode/SHARED
-                                 (= threading-mode "dedicated")
-                                 ThreadingMode/DEDICATED
-                                 (= threading-mode "shared-network")
-                                 ThreadingMode/SHARED_NETWORK)
-        _ (println "Starting media driver with threading mode:" threading-mode ". Use -t to supply an alternative threading mode.")
+        threading-mode-obj (cond
+                             (= threading-mode "dedicated") ThreadingMode/DEDICATED
+                             (= threading-mode "shared-network") ThreadingMode/SHARED_NETWORK
+                             :else ThreadingMode/SHARED)
         ctx (cond-> (MediaDriver$Context.)
               threading-mode (.threadingMode threading-mode-obj)
               delete-dirs (.dirsDeleteOnStart delete-dirs))
         media-driver (try (MediaDriver/launch ctx)
-                       (catch IllegalStateException ise
-                         (throw (Exception. "Error starting media driver. This may be due to a media driver data incompatibility between versions. Check that no other media driver has been started and then use -d to delete the directory on startup" ise))))]
+                          (catch IllegalStateException ise
+                            (throw (Exception. "Error starting media driver. This may be due to a media driver data incompatibility between versions. Check that no other media driver has been started and then use -d to delete the directory on startup" ise))))]
+    (when help
+      (run! (fn [opt]
+              (println (clojure.string/join " " (take 3 opt))))
+            cli-options)
+      (System/exit 0))
+    (when (and (System/getProperty "aeron.threading.mode") threading-mode)
+      (throw (Exception. "Cannot set both aeron.threading.mode property and threading-mode command-line arg")))
+    (println "Starting media driver with threading mode:" threading-mode ". Use -t to supply an alternative threading mode.")
     (println "Launched the Media Driver. Blocking forever...")
     (<!! (chan))))


apply-fn doesn't need intermediate partial

I find this more readable

--- src/onyx/peer/function.clj
+++ src/onyx/peer/function.clj
@@ -44,8 +44,7 @@

 (defmethod p-ext/apply-fn :default
   [{:keys [onyx.core/params] :as event} segment]
-  (let [op (partial operation/apply-fn (:onyx.function/fn event) params)]
-    (op segment)))
+  (operation/apply-fn (:onyx.function/fn event) params segment))

 (defmethod p-ext/compress-batch :default
   [{:keys [onyx.core/results onyx.core/catalog onyx.core/serialized-task]


Changed run-server function to return server thread in meta

--- src/org/httpkit/server.clj
+++ src/org/httpkit/server.clj
@@ -29,7 +29,8 @@
                  ;; 2. wait for existing requests to finish
                  ;; 3. close the server
                  (.stop s timeout))
-      {:local-port (.getPort s)})))
+      {:local-port (.getPort s)
+       :server s})))

 ;;;; Asynchronous extension


Remove redundant let.

Remove redundant let.

--- src/org/httpkit/server.clj
+++ src/org/httpkit/server.clj
@@ -144,10 +144,9 @@

 (defmacro async-response "DEPRECATED"
   [request callback-name & body]
-  `(let [ch# nil]
-     (with-channel ~request ch#
-       (let [~callback-name (fn [data#] (send! ch# data# true))]
-         ~@body))))
+  `(with-channel ~request ch#
+     (let [~callback-name (fn [data#] (send! ch# data# true))]
+       ~@body)))

 (defmacro ws-response "DEPRECATED"
   [request conn-name & then]


Add sample-ready? utility fn to determine whether a given sample has loaded on the server

--- src/overtone/sc/sample.clj
+++ src/overtone/sc/sample.clj
@@ -61,6 +61,12 @@
   [s]
   (isa? (type s) ::sample))

+(defn sample-ready?
+  "Check whether a sample has completed allocating and/or loading data."
+  [sample]
+
+  @(:ready? sample))
+
 ;; Samples are just audio files loaded into a buffer, so buffer
 ;; functions work on samples too.
 (derive ::sample :overtone.sc.core/buffer)


async cljs.js/analyze-deps wip

async cljs.js/analyze-deps wip

--- src/main/cljs/cljs/js.cljs
+++ src/main/cljs/cljs/js.cljs
@@ -33,7 +33,10 @@
 ;; -----------------------------------------------------------------------------
 ;; Analyze

-(defn analyze* [env source cb]
+(defn require [name cb]
+  (*load-fn* name cb))
+
+(defn analyze* [env bound-vars source cb]
   (let [rdr  (rt/string-push-back-reader source)
         eof  (js-obj)
         aenv (ana/empty-env)]
@@ -46,11 +49,40 @@
               (recur))
             (cb)))))))

+(defn analyze-deps
+  "Given a lib, a namespace, deps, its dependencies, env, an analysis environment
+   and opts, compiler options - analyze all of the dependencies. Required to
+   correctly analyze usage of other namespaces."
+  ([lib deps env bound-vars cb] (analyze-deps lib deps env bound-vars nil cb))
+  ([lib deps env bound-vars opts cb]
+   (let [compiler @(:*compiler* bound-vars)]
+     (binding [ana/*cljs-dep-set* (vary-meta (conj (:*cljs-dep-set* bound-vars) lib)
+                                    update-in [:dep-path] conj lib)]
+       (assert (every? #(not (contains? (:*cljs-dep-set* bound-vars) %)) deps)
+         (str "Circular dependency detected "
+           (-> (:*cljs-dep-set* bound-vars) meta :dep-path)))
+       (if (seq deps)
+         (let [dep (first deps)]
+           (when-not (or (not-empty (get-in compiler [::namespaces dep :defs]))
+                       (contains? (:js-dependency-index compiler) (name dep)))
+             (require name
+               (fn [source]
+                 (if-not (nil? source)
+                   (analyze* env bound-vars source
+                     (fn []
+                       (analyze-deps lib (next deps) env bound-vars opts cb)))
+                   (throw
+                     (ana/error env
+                       (ana/error-message :undeclared-ns
+                         {:ns-sym dep :js-provide (name dep)}))))))))
+         (cb))))))
+
 (defn analyze [env source cb]
-  (binding [ana/*cljs-ns*    (or (:ns env) 'cljs.user)
-            *ns*             (create-ns ana/*cljs-ns*)
-            r/*data-readers* tags/*cljs-data-readers*]
-    (analyze* env source cb)))
+  (analyze* env
+    {:*cljs-ns*      (or (:ns env) 'cljs.user)
+     :*ns*           (create-ns ana/*cljs-ns*)
+     :*data-readers* tags/*cljs-data-readers*}
+    source cb))

 ;; -----------------------------------------------------------------------------
 ;; Emit


CLJS-998: Nashorn REPL does not support require special fn

--- src/clj/cljs/repl/nashorn.clj
+++ src/clj/cljs/repl/nashorn.clj
@@ -155,7 +155,20 @@
       (repl/evaluate-form this env repl-filename
         '(do
            (.require js/goog "cljs.core")
-           (cljs.core/enable-console-print!)))))
+           (cljs.core/enable-console-print!)))
+      ;; monkey-patch goog.isProvided_ to suppress useless errors
+      (repl/evaluate-form this env repl-filename
+        '(set! js/goog.isProvided_ (fn [ns] false)))
+      ;; monkey-patch goog.require to be more sensible
+      (repl/evaluate-form this env repl-filename
+        '(do
+           (set! *loaded-libs* #{"cljs.core"})
+           (set! (.-require js/goog)
+             (fn [name reload]
+               (when (or (not (contains? *loaded-libs* name)) reload)
+                 (set! *loaded-libs* (conj (or *loaded-libs* #{}) name))
+                 (js/CLOSURE_IMPORT_SCRIPT
+                   (aget (.. js/goog -dependencies_ -nameToPath) name)))))))))
   (-evaluate [{engine :engine :as this} filename line js]
     (when debug (println "Evaluating: " js))
     (try


fix bug in persistence-str

fix bug in persistence-str

--- src/clj/elephantdb/config.clj
+++ src/clj/elephantdb/config.clj
@@ -80,7 +80,7 @@

 (defn persistence-options [local-config persistence]
   (if-let [local-db-conf (:local-db-conf local-config)]
-    (get local-db-conf (persistence-str persistence {}))
+    (get local-db-conf (persistence-str persistence) {})
     {}
     ))


On create/delete event, send notifications

--- src/clj/herder/web/events.clj
+++ src/clj/herder/web/events.clj
@@ -6,7 +6,8 @@
    [korma.core :as d]
    [herder.web.db :as db]
    [ring.util.response :refer [response status]]
-   [compojure.core :refer [GET POST PATCH DELETE context]))
+   [compojure.core :refer [GET POST PATCH DELETE context]]
+   [herder.web.notifications :as notifications]))

 (defn validate-new-event [params]
   (first
@@ -19,17 +20,19 @@
     (-> (response {:errors errors})
         (status 400))
     (let [id (str (uuid/v1))
+          conv_id (:id params)
           persons (get params :persons [])
           persons (if (vector? persons) persons [persons])]
       (d/insert
        db/events (d/values [{:id id
                              :name (:name params)
-                             :convention_id (:id params)}]))
+                             :convention_id conv_id}]))
       (doseq [person persons]
         (d/insert
-         db/events-persons (d/values [{:convention_id (:id params)
+         db/events-persons (d/values [{:convention_id conv_id
                                        :event_id id
                                        :person_id person}])))
+      (notifications/send-notification [:events conv_id])
       (status (response {:id id}) 201))))

 (defn- retrieve-event [id]
@@ -49,8 +52,13 @@
     (response events)))

 (defn delete-event [{{:keys [id]} :params}]
-  (let [event (d/delete db/events (d/where {:id id}))]
-    (status (response {}) (if (> event 0) 200 404))))
+  (let [event (first (d/select db/events (d/where {:id id})))]
+    (if (nil? event)
+      (status (response {}) 404)
+      (do
+        (d/delete db/events (d/where {:id id}))
+        (notifications/send-notification [:events (str (:convention_id event))])
+        (status (response {}) 200)))))

 (defn delete-event-person [{{:keys [id person_id]} :params}]
   (let [event (d/delete db/events-persons (d/where {:event_id id :person_id person_id}))]


Notifications when changes made to event persons

--- src/clj/herder/web/events.clj
+++ src/clj/herder/web/events.clj
@@ -61,21 +61,28 @@
         (status (response {}) 200)))))

 (defn delete-event-person [{{:keys [id person_id]} :params}]
-  (let [event (d/delete db/events-persons (d/where {:event_id id :person_id person_id}))]
-    (status (response {}) (if (> event 0) 200 404))))
+  (let [event-person (first (d/select db/events-persons (d/where {:event_id id :person_id person_id})))]
+    (if (nil? event-person)
+      (status (response {}) 404)
+      (do
+        (d/delete db/events-persons (d/where {:event_id id :person_id person_id}))
+        (notifications/send-notification [:event (str (:convention_id event-person)) id])
+        (status (response {}) 200)))))

 (defn patch-event [{{:keys [id person]} :params}]
   (let [event (retrieve-event id)]
     (if (nil? event)
       (status (response (str "No such event " id)) 404)
       (let [persons (get-person-ids id)
-            return (assoc event :persons persons)]
+            return (assoc event :persons persons)
+            conv_id (:convention_id event)]
         (if (not (.contains persons person))
           (do
             (d/insert
-             db/events-persons (d/values [{:convention_id (:convention_id event)
+             db/events-persons (d/values [{:convention_id conv_id
                                            :event_id id
                                            :person_id person}]))
+            (notifications/send-notification [:event (str conv_id) id])
             (response (update return :persons #(conj % person))))
           (response return))))))