Add some utilities to update the ui in-place

--- frontend/core.cljs
+++ frontend/core.cljs
@@ -174,9 +174,25 @@
     (js/setInterval #(reset! mya (time/now)) 1000)
     mya))

+
+(defn install-om [state container]
+  (om/root
+     app/app
+     state
+     {:target container
+      :shared {:comms (:comms @state)
+               :timer-atom (setup-timer-atom)
+               :_app-state-do-not-use state}}))
+
+(defn find-top-level-node []
+  (sel1 :body))
+
+(defn find-app-container [top-level-node]
+  (sel1 top-level-node "#om-app"))
+
 (defn main [state top-level-node history-imp]
   (let [comms       (:comms @state)
-        container   (sel1 top-level-node "#om-app")
+        container   (find-app-container top-level-node)
         uri-path    (.getPath utils/parsed-uri)
         history-path "/"
         pusher-imp (pusher/new-pusher-instance)
@@ -186,13 +202,7 @@
         ws-tap (chan)
         errors-tap (chan)]
     (routes/define-routes! state)
-    (om/root
-     app/app
-     state
-     {:target container
-      :shared {:comms comms
-               :timer-atom (setup-timer-atom)
-               :_app-state-do-not-use state}})
+    (install-om state container)

     (async/tap (:controls-mult comms) controls-tap)
     (async/tap (:nav-mult comms) nav-tap)
@@ -233,7 +243,7 @@
 (defn ^:export setup! []
   (apply-app-id-hack)
   (let [state (app-state)
-        top-level-node (sel1 :body)
+        top-level-node (find-top-level-node)
         history-imp (history/new-history-imp top-level-node)]
     ;; globally define the state so that we can get to it for debugging
     (def debug-state state)
@@ -256,3 +266,16 @@

 (defn ^:export toggle-admin []
   (swap! debug-state update-in [:current-user :admin] not))
+
+(defn reinstall-om! []
+  (install-om debug-state (find-app-container (find-top-level-node))))
+
+(defn refresh-css! []
+  (let [link (.createElement js/document "link")]
+    (.setAttribute link "rel" "stylesheet")
+    (.setAttribute link "href" "/assets/css/app.css.less")
+    (.appendChild (.-head js/document) link)))
+
+(defn update-ui! []
+  (reinstall-om!)
+  (refresh-css!))


Add a little macro to reduce some of the om component boilerplate.

--- frontend/utils.clj
+++ frontend/utils.clj
@@ -33,3 +33,12 @@
           (when (:rethrow-errors? initial-query-map)
             (js* "debugger;")
             (throw e#)))))
+
+(defmacro defrender
+  "Reifies an IRender component that only has a render function and
+   splices the body into the render function"
+  [name args & body]
+  `(defn ~name ~args
+     (reify
+       om.core/IRender
+       (~'render [~'_] ~@body))))


Make sure the most recent comment is selected when calculating the last-activity-at value for each entry. Replace field names with keywords.

--- src/oc/storage/db/common.clj
+++ src/oc/storage/db/common.clj
@@ -36,21 +36,18 @@
                                        (r/get-all [(r/get-field post-row :uuid)] {:index :resource-uuid})
                                        (r/filter (r/fn [interaction-row]
                                         ;; Filter out reactions
-                                        (r/ge (r/get-field interaction-row "body") "")))
+                                        (r/ge (r/get-field interaction-row :body) "")))
                                        (r/coerce-to :array)
-                                       (r/reduce (r/fn [left right]
-                                         (if (r/ge (r/get-field left "created-at") (r/get-field right "created-at"))
-                                           left
-                                           right)))
+                                       (r/order-by (r/desc :created-at))
                                        (r/default (r/fn [_err]
-                                        {"created-at" (r/default
-                                                       (r/get-field post-row "published-at")
-                                                       (r/get-field post-row "created-at"))}))
-                                       (r/do (r/fn [interaction-row]
-                                         (r/get-field interaction-row "created-at"))))}
+                                        {:created-at (r/default
+                                                       (r/get-field post-row :published-at)
+                                                       (r/get-field post-row :created-at))}))
+                                       (r/do (r/fn [activity-row]
+                                         (r/get-field activity-row :created-at))))}
                 {:last-activity-at (r/default
-                                    (r/get-field post-row "published-at")
-                                    (r/get-field post-row "created-at"))})))
+                                    (r/get-field post-row :published-at)
+                                    (r/get-field post-row :created-at))})))
             (if (sequential? allowed-boards)
               ;; Filter out:
               (r/filter query (r/fn [post-row]
@@ -114,18 +111,16 @@
                                      (r/filter (r/fn [interaction-row]
                                       ;; Filter out reactions and comments from the current user
                                       (r/and
-                                       (r/ge (r/get-field interaction-row "body") "")
-                                       (r/ne (r/get-field (r/get-field interaction-row "author") "user-id") user-id))))
+                                       (r/ge (r/get-field interaction-row :body) "")
+                                       (r/ne (r/get-field (r/get-field interaction-row :author) :user-id) user-id))))
                                      (r/coerce-to :array)
-                                     (r/reduce (r/fn [left right]
-                                       (if (r/ge (r/get-field left "created-at") (r/get-field right "created-at"))
-                                         left
-                                         right)))
-                                     (r/default {"created-at" (r/default
-                                                               (r/get-field post-row "published-at")
-                                                               (r/get-field post-row "created-at"))})
-                                     (r/do (r/fn [interaction-row]
-                                       (r/get-field interaction-row "created-at"))))}))
+                                     (r/order-by (r/desc :created-at))
+                                     (r/nth 0)
+                                     (r/default {:created-at (r/default
+                                                               (r/get-field post-row :published-at)
+                                                               (r/get-field post-row :created-at))})
+                                     (r/do (r/fn [activity-row]
+                                       (r/get-field activity-row :created-at))))}))
             ;; Filter out:
             (r/filter query (r/fn [post-row]
               (r/and ;; All records in boards the user has no access


fix tags

fix tags

--- src/ontrail/sportsummary.clj
+++ src/ontrail/sportsummary.clj
@@ -64,7 +64,7 @@
   (.trace logger (str "Getting summary: " user " condition " condition))
   (let [cond-with-user (assoc condition :user user)
         all-distinct-tags (filter (partial not= "") (get-distinct-tags cond-with-user))
-        summary-tags (sort-by :numericalDuration >
+        summary-tags (sort-by :nduration >
           (map #(get-summary (assoc cond-with-user :tags %) :tag %) all-distinct-tags))]
     {:user user :sports summary-tags}))


Don't continue to attempt to write to closed publication

--- src/onyx/messaging/aeron.clj
+++ src/onyx/messaging/aeron.clj
@@ -450,7 +450,10 @@
 (defn write [^Publication pub ^UnsafeBuffer buf]
   ;; Needs an escape mechanism so it can break if a peer is shutdown
   ;; Needs an idle mechanism to prevent cpu burn
-  (while (neg? (.offer pub buf 0 (.capacity buf)))
+  (while (let [ret (.offer pub buf 0 (.capacity buf))]
+           (when (= ret Publication/CLOSED)
+             (throw (Execption. "Wrote to closed publication.")))
+           (neg? ret))
     (debug "Re-offering message, session-id" (.sessionId pub))))

 (defmethod extensions/send-messages AeronMessenger


Fix for bot trigger when JWT user has no name property.

--- src/open_company/lib/bot.clj
+++ src/open_company/lib/bot.clj
@@ -11,7 +11,7 @@

 (def BotTrigger
   {:api-token s/Str
-   :script   {:id KnownScripts :params {s/Keyword s/Str}}
+   :script   {:id KnownScripts :params {s/Keyword (s/maybe s/Str)}}
    :receiver {:type (s/enum :all-members :user :channel) (s/optional-key :id) s/Str}
    :bot      {:token s/Str :id s/Str}})


Add os specific shortcut for loading synthdefs by keyword

--- src/overtone/sc/synthdef.clj
+++ src/overtone/sc/synthdef.clj
@@ -122,6 +122,12 @@

 (defn synthdef? [obj] (= ::synthdef (type obj)))

+(defn- supercollider-synthdef-path
+  "Returns a constructed path to a named synthdef on the current platform"
+  [synth-name]
+  (case (get-os)
+        :mac   (str "/Users/" (user-name) "/Library/Application Support/SuperCollider/synthdefs/" synth-name ".scsyndef")))
+
 ; TODO: byte array shouldn't really be the default here, but I don't
 ; know how to test for one correctly... (byte-array? data) please?
 (defn synthdef-read
@@ -129,13 +135,12 @@
   a URL, or a byte array."
   [data]
   (first (:synths
-    (cond
-      (string? data)
-      (spec-read-url synthdef-file-spec (java.net.URL. (str "file:" data)))
-      (instance? java.net.URL data)
-      (spec-read-url synthdef-file-spec data)
-      (byte-array? data) (spec-read-bytes synthdef-file-spec data)
-      :default (throw (IllegalArgumentException. (str "synthdef-read expects either a string, a URL, or a byte-array argument.")))))))
+          (cond
+           (keyword? data) (spec-read-url synthdef-file-spec (java.net.URL. (str "file:" (supercollider-synthdef-path (to-str data)))) )
+           (string? data) (spec-read-url synthdef-file-spec (java.net.URL. (str "file:" data)))
+           (instance? java.net.URL data) (spec-read-url synthdef-file-spec data)
+           (byte-array? data) (spec-read-bytes synthdef-file-spec data)
+           :default (throw (IllegalArgumentException. (str "synthdef-read expects either a string, a URL, or a byte-array argument.")))))))

 (defn synthdef-write
   "Write a synth definition to a new file at the given path, which includes
@@ -224,4 +229,3 @@
   "Load a synth definition file onto the audio server."
   [path]
   (snd "/d_recv" (synthdef-bytes (synthdef-read path))))
-


s/debug/info/

s/debug/info/

--- src/babel/generate.cljc
+++ src/babel/generate.cljc
@@ -108,13 +108,13 @@
       (add-all-comps-with-paths
        (lazy-mapcat
         (fn [bolt]
-          (log/debug (str "add-all-comps-with-paths: " (show-bolt bolt path language-model)
+          (log/info (str "add-all-comps-with-paths: " (show-bolt bolt path language-model)
                           "@[" (string/join " " path) "]" "^" total-depth))
           (add-complement-to-bolt bolt path
                                   language-model (+ total-depth (count path))
                                   :max-total-depth max-total-depth
                                   :truncate-children truncate-children))
-        bolts)
+        (take 1 bolts))
        language-model
        total-depth
        (rest comp-paths)


s/truncate-children?/truncate-children/

s/truncate-children?/truncate-children/

--- src/babel/generate.cljc
+++ src/babel/generate.cljc
@@ -79,7 +79,7 @@
 (defn generate
   "Return one (by default) or _n_ (using :take _n_) expressions matching spec _spec_ given the model _model_."
   [spec language-model
-   & {:keys [max-total-depth truncate-children lexicon take-n]
+   & {:keys [max-total-depth truncate-children? lexicon take-n]
       :or {max-total-depth max-total-depth
            lexicon nil
            shuffle? nil


+(defn truncate-expressions)

+(defn truncate-expressions)

--- src/babel/generate.cljc
+++ src/babel/generate.cljc
@@ -33,6 +33,7 @@
 (declare path-to-map)
 (declare show-bolt)
 (declare truncate)
+(declare truncate-expressions)

 (defn generate [spec language-model
                 & {:keys [max-total-depth truncate-children]
@@ -300,6 +301,10 @@
                       path-vals))]
     (deserialize truncated-serialized)))

+(defn truncate-expressions [expressions truncate-paths]
+  (map #(truncate % truncate-paths)
+       expressions))
+
 ;; Thanks to http://clojurian.blogspot.com.br/2012/11/beware-of-mapcat.html
 (defn lazy-mapcat  [f coll]
   (lazy-seq


+comments & TODO

+comments & TODO

--- src/babel/italiano.cljc
+++ src/babel/italiano.cljc
@@ -18,6 +18,8 @@
   (parse/fo-ps expr fo))

 (defn analyze
+  "analyze a word: as opposed to parsing which is multi-word."
+  ;; TODO: should take a language model, not a lexicon
   ([surface-form]
    (analyze surface-form (:lexicon (medium))))
   ([surface-form lexicon]


Fix bugs in monitor route from change to poll ns.

--- src/ranked_choice/routes.clj
+++ src/ranked_choice/routes.clj
@@ -51,9 +51,9 @@
               poll (poll/new-poll (irv/->InstantRunoff) candidates-coll)
               poll-id (poll/conj-poll poll-mgr poll)]
           (redirect (str "/poll/" poll-id "/vote"))))
-  (GET "/poll/monitor" {poll-mgr :voting/poll-mgr}
+  (GET "/poll/monitor" {poll-mgr :poll/poll-mgr}
        (let [polls @(:polls poll-mgr)
-             polls-by-id (->> polls (map-indexed vector) (filter (comp :candidates last)))]
+             polls-by-id (->> polls (map-indexed vector) (filter last))]
          (monitor polls-by-id)))
   (context "/poll/:id" [id :as {poll-mgr :poll/poll-mgr}]
            (if-let [poll (poll/get-poll poll-mgr (Integer/parseInt id))]


Use string specifier

Use string specifier

--- src/runbld/publish/email.clj
+++ src/runbld/publish/email.clj
@@ -15,7 +15,7 @@
   (send* (-> opts :opts :email)
          (ctx :mail-from)
          (ctx :rcpt-to)
-         (format "%s %d"
+         (format "%s %s"
                  (ctx :github-name)
                  (ctx :jenkins-number))
          (mustache/render-string


LES Mode: Fix config so that node starts properly.

Signed-off-by: Igor Mandrigin <042dc4512fa3d391c5170cf3aa61e6a638f84342@mandrigin.ru>

--- src/status_im/constants.cljs
+++ src/status_im/constants.cljs
@@ -37,8 +37,9 @@
 (def mainnet-networks
   {"mainnet"     {:id     "mainnet",
                   :name   "Mainnet",
-                  :config {:NetworkId (ethereum/chain-keyword->chain-id :mainnet)
-                           :DataDir   "/ethereum/mainnet"}}
+                  :config {:NetworkId      (ethereum/chain-keyword->chain-id :mainnet)
+                           :DataDir        "/ethereum/mainnet"
+                           :LightEthConfig {:Enabled true}}}
    "mainnet_rpc" {:id     "mainnet_rpc",
                   :name   "Mainnet with upstream RPC",
                   :config {:NetworkId      (ethereum/chain-keyword->chain-id :mainnet)
@@ -49,8 +50,9 @@
 (def testnet-networks
   {"testnet"     {:id     "testnet",
                   :name   "Ropsten",
-                  :config {:NetworkId (ethereum/chain-keyword->chain-id :testnet)
-                           :DataDir   "/ethereum/testnet"}}
+                  :config {:NetworkId      (ethereum/chain-keyword->chain-id :testnet)
+                           :DataDir        "/ethereum/testnet"
+                           :LightEthConfig {:Enabled true}}}
    "testnet_rpc" {:id     "testnet_rpc",
                   :name   "Ropsten with upstream RPC",
                   :config {:NetworkId      (ethereum/chain-keyword->chain-id :testnet)
@@ -59,8 +61,9 @@
                                             :URL     "https://ropsten.infura.io/z6GCTmjdP3FETEJmMBI4"}}}
    "rinkeby"     {:id     "rinkeby",
                   :name   "Rinkeby",
-                  :config {:NetworkId (ethereum/chain-keyword->chain-id :rinkeby)
-                           :DataDir   "/ethereum/rinkeby"}}
+                  :config {:NetworkId      (ethereum/chain-keyword->chain-id :rinkeby)
+                           :DataDir        "/ethereum/rinkeby"
+                           :LightEthConfig {:Enabled true}}}
    "rinkeby_rpc" {:id     "rinkeby_rpc",
                   :name   "Rinkeby with upstream RPC",
                   :config {:NetworkId      (ethereum/chain-keyword->chain-id :rinkeby)


Set datalog as the home page.

Set datalog as the home page.

--- src/stuttaford/web/routes.clj
+++ src/stuttaford/web/routes.clj
@@ -61,7 +61,7 @@
   {:title   "Dive into Datomic"
    :layout  "bare"
    :css     ["bootstrap/css/bootstrap.min.css" "css/dive-into-datomic.css"]
-   :content (list (om-app "dive-into-datomic" true {:view :datom}))})
+   :content (list (om-app "dive-into-datomic" true {:view :datalog}))})

 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; Routes


Clean up gclosure warnings

Clean up gclosure warnings

--- src/cljs/cljs/core.cljs
+++ src/cljs/cljs/core.cljs
@@ -118,6 +118,9 @@

 (defn nil? [x]
   (identical? x nil))
+
+(defn undefined? [x]
+  (js* "(void 0 === ~{x})"))

 (defn instance? [t o]
   (js* "(~{o} instanceof ~{t})"))
@@ -440,7 +443,7 @@
 (defn not-every?
   "Returns false if (pred x) is logical true for every x in
   coll, else true."
-  [pred coll] (not (every pred coll)))
+  [pred coll] (not (every? pred coll)))

 (defn some
   "Returns the first logical true value of (pred x) for any x in coll,
@@ -736,7 +739,7 @@

   IStack
   (-peek [coll] first)
-  (-pop [coll] (irest coll))
+  (-pop [coll] (-rest coll))

   ICollection
   (-conj [coll o] (List. meta o coll (inc count)))
@@ -846,7 +849,7 @@
        (if (< n (-count string)) (.charAt string n)))
     ([string n not-found]
        (if (< n (-count string)) (.charAt string n)
-           not_found)))
+           not-found)))

   goog.global.Array
   (-nth
@@ -1378,7 +1381,7 @@

 (defn bit-xor
   "Bitwise exclusive or"
-  [x y] (js* "(~{x} ^ ~{n})"))
+  [x y] (js* "(~{x} ^ ~{y})"))

 (defn bit-shift-left
   "Bitwise shift left"
@@ -1671,7 +1674,7 @@
 (defn- pr-seq [obj opts]
   (cond
     (nil? obj) (list "nil")
-    (identical? undefined obj) (list "#<undefined>")
+    (undefined? obj) (list "#<undefined>")
     :else (concat
             (when (and (get opts :meta)
                        (satisfies? IMeta obj)


INext docstring typo

INext docstring typo

--- src/cljs/cljs/core.cljs
+++ src/cljs/cljs/core.cljs
@@ -381,7 +381,7 @@
 (defprotocol INext
   "Protocol for accessing the next items of a collection."
   (^clj-or-nil -next [coll]
-    "Returns a new collection of coll without the first item. In contract to
+    "Returns a new collection of coll without the first item. In contrast to
      rest, it should return nil if there are no more items, e.g.
      (next []) => nil
      (next nil) => nil"))


fix subtle problem when skipping loading js in dev

--- src/cljs/lumo/repl.cljs
+++ src/cljs/lumo/repl.cljs
@@ -229,11 +229,15 @@
   [name path file-path macros? cb]
   (let [bundled-src-prefix (cond-> path
                              macros? (str MACROS_SUFFIX))
-        bundled-source (js/LUMO_LOAD (str bundled-src-prefix JS_EXT))]
+        bundled-source (js/LUMO_LOAD (str bundled-src-prefix JS_EXT))
+        skip-load-js? (skip-load-js? name macros?)]
     (cond
-      (or bundled-source (skip-load-js? name macros?))
+      skip-load-js?
+      (load-bundled file-path "" cb)
+
+      bundled-source
       ;; bundled source are AOTed macros which don't have the `.clj[sc]*` extension
-      (load-bundled (if bundled-source bundled-src-prefix file-path) (or bundled-source "") cb)
+      (load-bundled bundled-src-prefix bundled-source cb)

       :else
       (load-external path file-path macros? cb))))


Add metadata to new ClojureScript functions in quil.core.

--- src/cljx/quil/core.cljx
+++ src/cljx/quil/core.cljx
@@ -250,17 +250,34 @@
 ;; ------------------ end PConstants section ---------------------

 #+cljs
-(defn get-key []
+(defn
+  ^{:requires-bindings true
+    :processing-name "key"
+    :category "Input"
+    :subcategory "Keyboard"
+    :added "1.0"}
+  get-key []
   (.-key (current-graphics)))

 #+cljs
-(defn get-sketch-by-id [id]
+(defn
+  ^{:requires-bindings true
+    :processing-name "getSketchById()"
+    :category nil
+    :subcategory nil
+    :added "1.0"}
+  get-sketch-by-id [id]
   (.getInstanceById js/Processing id))

 #+cljs
 (defn size
+  ^{:requires-bindings true
+    :processing-name "size()"
+    :category "Structure"
+    :subcategory nil
+    :added "1.0"}
   ([width height]
     (.size (current-graphics) (int width) (int height)))


Fixed issue #25: Add page with listings of all changes sorted by user.

--- src/clouseau/server.clj
+++ src/clouseau/server.clj
@@ -207,7 +207,7 @@
                         [:a {:href "/" :class "navbar-brand"} "Clouseau"]
                     ] ; ./navbar-header
                 ] ; col ends
-                [:div {:class "col-md-5"}
+                [:div {:class "col-md-4"}
                     (render-search-field package)
                 ] ; col ends
                 [:div {:class "col-md-2"}
@@ -217,7 +217,12 @@
                 ] ; col ends
                 [:div {:class "col-md-3"}
                     (render-name-field user-name)
-                    ]
+                ]
+                [:div {:class "col-md-1"}
+                    [:div {:class "navbar-header"}
+                        [:a {:href "/users" :class "navbar-brand"} "Users"]
+                    ] ; ./navbar-header
+                ] ; col ends
             ] ; row ends
         ] ; /.container-fluid
 ]); </nav>
@@ -317,6 +322,40 @@
         ] ; </body>
     ))

+(defn html-renderer-users
+    [statistic changes user-name]
+    (page/xhtml
+        (render-html-header nil)
+        [:body
+            [:div {:class "container"}
+                (render-navigation-bar-section nil user-name)
+                [:table {:class "table table-stripped table-hover" :style "width:auto"}
+                    [:tr [:th "User name"]
+                         [:th "Changes made"]]
+                    (for [stat statistic]
+                        [:tr [:td (:user_name stat)]
+                             [:td (:cnt stat)]]
+                    )
+                ]
+                [:br]
+                [:table {:class "table table-stripped table-hover" :style "width:auto"}
+                    [:tr [:th "ID"]
+                         [:th "Date"]
+                         [:th "Package"]
+                         [:th "User"]
+                         [:th "Description"]]
+                    (for [change changes]
+                        [:tr [:td (:id change)]
+                             [:td (:date_time change)]
+                             [:td (:package change)]
+                             [:td (:user_name change)]
+                             [:td (:description change)]])
+                ]
+                (render-footer)
+            ] ; </div class="container">
+        ] ; </body>
+    ))
+
 (defn log-request-information
     [request]
     (println-and-flush "time:        " (.toString (new java.util.Date)))
@@ -422,6 +461,15 @@
         (-> (http-response/response (html-renderer-descriptions descriptions user-name))
             (http-response/content-type "text/html"))))

+(defn render-users-info
+    "Create page containing user info(s)."
+    [request]
+    (let [changes-statistic (read-changes-statistic)
+          changes           (read-changes)
+          user-name    (get (get (request :cookies) "user-name") :value)]
+        (-> (http-response/response (html-renderer-users changes-statistic changes user-name))
+            (http-response/content-type "text/html"))))
+
 (defn return-file
     [file-name content-type]
     (let [file (new java.io.File "www" file-name)]
@@ -442,5 +490,6 @@
             "/smearch.css"       (return-file "smearch.css" "text/css")
             "/bootstrap.min.js"  (return-file "bootstrap.min.js" "application/javascript")
             "/"                  (perform-normal-processing request)
-            "/descriptions"      (render-all-descriptions request))))
-
+            "/descriptions"      (render-all-descriptions request)
+            "/users"             (render-users-info request))))
+


Adding type hints during validation to avoid reflection and warning messages.

--- src/cmr/spatial/mbr.clj
+++ src/cmr/spatial/mbr.clj
@@ -287,6 +287,6 @@
 (extend-protocol v/SpatialValidation
   cmr.spatial.mbr.Mbr
   (validate
-    [{:keys [north south]}]
+    [{:keys [^double north ^double south]}]
       (when (< north south)
         [(msg/br-north-less-than-south north south)])))


reorder stream tewmplate

reorder stream tewmplate

--- src/text_stream/templates.clj
+++ src/text_stream/templates.clj
@@ -45,8 +45,9 @@
     (css-resource "view-stream.css")
     [:title "Streaming..."]]
    [:body
+    [:a#share]
+    [:br]
     [:small#status "connecting..."]
-    [:a#share]
     [:pre#stream
      [:span.cursor ""]]
     (js-resource "make-stream.js")]))


Converting players from Brazil

Converting players from Brazil

--- raw_data/convert_players.clj
+++ raw_data/convert_players.clj
@@ -5,7 +5,7 @@
 (def position { "GK" "Goalkeeper", "DF" "Defender", "MF" "Midfielder", "FW" "Forward" })

 (def country-by-code {
-  "ITA" "Italy"
+  "BRA" "Brazil", "ENG" "England", "ESP" "Spain", "FRA" "France", "GER" "Germany", "GRE" "Greece", "ITA" "Italy", "POR" "Portugal", "TUR" "Turkey"
 })

 (def number read-string)


Check for error items in SMLXLexer test.

The SMLXLexer doesn't throw any exceptions, but return error items.

--- test/com/hypirion/smallex/test/lexer.clj
+++ test/com/hypirion/smallex/test/lexer.clj
@@ -6,7 +6,4 @@

 (deftest test-read
   (with-open [rdr (io/reader (io/resource "clojure.smlx"))]
-    (is (try
-          (doall (iterator-seq (SMLXLexer. rdr)))
-          true
-          (catch Exception _ false)))))
+    (is (not-any? #(= :error (:type %)) (iterator-seq (SMLXLexer. rdr))))))


Test for self-requiring cljc namespace. Closes #102

--- test/node/replumb/require_node_test.cljs
+++ test/node/replumb/require_node_test.cljs
@@ -479,7 +479,7 @@
     (let [res (do (read-eval-call "(ns my.namespace (:require [foo.bar.baz :refer-macros [mul-baz]]))")
                   (read-eval-call "(mul-baz 10 12)"))
           error (unwrap-result res)]
-      (is (not (success? error)) "(ns my.namespace (:require ...:refer-macros...)) and (mul-baz 10 12) should not succeed")
+      (is (not (success? res)) "(ns my.namespace (:require ...:refer-macros...)) and (mul-baz 10 12) should not succeed")
       (is (valid-eval-error? error) "(ns my.namespace (:require ...:refer-macros..)) and (mul-baz 10 12) should be an instance of js/Error")
       (is (re-find #"ERROR" (extract-message error)) "(ns my.namespace (:require ...:refer-macros...)) and (mul-baz 10 12) should have correct error message")
       (reset-env! '[my.namespace foo.bar.baz]))
@@ -495,7 +495,7 @@
     (let [res (do (read-eval-call "(ns my.namespace (:require [foo.bar.core :refer-macros [mul-core]]))")
                   (read-eval-call "(mul-core 10 20)"))
           error (unwrap-result res)]
-      (is (not (success? error)) "(ns my.namespace (:require ...:refer-macros...)) and (mul-core 10 20) should not succeed")
+      (is (not (success? res)) "(ns my.namespace (:require ...:refer-macros...)) and (mul-core 10 20) should not succeed")
       (is (valid-eval-error? error) "(ns my.namespace (:require ...:refer-macros...)) and (mul-core 10 20) should be an instance of js/Error")
       (is (re-find #"ERROR" (extract-message error))
           "(ns my.namespace (:require ...:refer-macros...)) and (mul-core 10 20) should have correct error message")
@@ -509,6 +509,16 @@
     ;;   (is (= "200" out ) "(mul-core 10 20) should produce 200")
     ;;   (reset-env! '[my.namespace foo.bar.core foo.bar.macros]))
 )
+
+  (deftest ns-macro-self-requiring-namespace
+    ;; see "loop" section here: http://blog.fikesfarm.com/posts/2015-12-18-clojurescript-macro-tower-and-loop.html
+    ;; but it does not work in JS ClojureScript
+    (let [res (read-eval-call "(ns my.namespace (:require [foo.bar.self]))")
+          error (unwrap-result res)]
+      (is (not (success? res)) "(ns my.namespace (:require [foo.bar.self])) should not succeed")
+      (is (valid-eval-error? error) "(ns my.namespace (:require [foo.bar.self])) should be an instance of js/Error")
+      (is (re-find #"Maximum call stack size exceeded" (extract-message error)) "(ns my.namespace (:require [foo.bar.self])) should have correct error message")
+      (reset-env!)))

   (deftest process-reload
     (let [alterable-core-path "dev-resources/private/test/src/cljs/alterable/core.cljs"
@@ -597,6 +607,7 @@
     (ns-macro-use-macros)
     (ns-macro-require)
     (ns-macro-require-macros-as)
+    (ns-macro-self-requiring-namespace)

     (process-reload)
     (process-reload-all)))


Optimize execute-sgr

Optimize execute-sgr

--- src/asciinema/player/vt.cljc
+++ src/asciinema/player/vt.cljc
@@ -570,30 +570,37 @@
 (defn execute-sgr [vt]
   (let [params (or (seq (get-params vt)) [0])]
     (loop [vt vt
-           [p1 p2 p3 & _ :as params] params]
-      (if p1
-        (match [p1 p2 p3]
-               [0  _ _] (recur (reset-attrs vt) (rest params))
-               [1  _ _] (recur (set-attr vt :bold true) (rest params))
-               [3  _ _] (recur (set-attr vt :italic true) (rest params))
-               [4  _ _] (recur (set-attr vt :underline true) (rest params))
-               [5  _ _] (recur (set-attr vt :blink true) (rest params))
-               [7  _ _] (recur (set-attr vt :inverse true) (rest params))
-               [21 _ _] (recur (unset-attr vt :bold) (rest params))
-               [22 _ _] (recur (unset-attr vt :bold) (rest params))
-               [23 _ _] (recur (unset-attr vt :italic) (rest params))
-               [24 _ _] (recur (unset-attr vt :underline) (rest params))
-               [25 _ _] (recur (unset-attr vt :blink) (rest params))
-               [27 _ _] (recur (unset-attr vt :inverse) (rest params))
-               [(fg :guard #(<= 30 % 37)) _ _] (recur (set-attr vt :fg (- fg 30)) (rest params))
-               [38 5 (fg :guard some?)] (recur (set-attr vt :fg fg) (drop 3 params))
-               [39 _ _] (recur (unset-attr vt :fg) (rest params))
-               [(bg :guard #(<= 40 % 47)) _ _] (recur (set-attr vt :bg (- bg 40)) (rest params))
-               [48 5 (bg :guard some?)] (recur (set-attr vt :bg bg) (drop 3 params))
-               [49 _ _] (recur (unset-attr vt :bg) (rest params))
-               [(fg :guard #(<= 90 % 97)) _ _] (recur (set-attr vt :fg (- fg 82)) (rest params))
-               [(bg :guard #(<= 100 % 107)) _ _] (recur (set-attr vt :bg (- bg 92)) (rest params))
-               :else (recur vt (rest params)))
+           params params]
+      (if (seq params)
+        (let [x (first params)]
+          (case x
+            0  (recur (reset-attrs vt) (rest params))
+            1  (recur (set-attr vt :bold true) (rest params))
+            3  (recur (set-attr vt :italic true) (rest params))
+            4  (recur (set-attr vt :underline true) (rest params))
+            5  (recur (set-attr vt :blink true) (rest params))
+            7  (recur (set-attr vt :inverse true) (rest params))
+            21 (recur (unset-attr vt :bold) (rest params))
+            22 (recur (unset-attr vt :bold) (rest params))
+            23 (recur (unset-attr vt :italic) (rest params))
+            24 (recur (unset-attr vt :underline) (rest params))
+            25 (recur (unset-attr vt :blink) (rest params))
+            27 (recur (unset-attr vt :inverse) (rest params))
+            (30 31 32 33 34 35 36 37) (recur (set-attr vt :fg (- x 30)) (rest params))
+            38 (let [[y fg] (take 2 (rest params))]
+                 (if (and (= y 5) fg)
+                   (recur (set-attr vt :fg fg) (drop 3 params))
+                   (recur vt (rest params))))
+            39 (recur (unset-attr vt :fg) (rest params))
+            (40 41 42 43 44 45 46 47) (recur (set-attr vt :bg (- x 40)) (rest params))
+            48 (let [[y bg] (take 2 (rest params))]
+                 (if (and (= y 5) bg)
+                   (recur (set-attr vt :bg bg) (drop 3 params))
+                   (recur vt (rest params))))
+            49 (recur (unset-attr vt :bg) (rest params))
+            (90 91 92 93 94 95 96 97) (recur (set-attr vt :fg (- x 82)) (rest params))
+            (100 101 102 103 104 105 106 107) (recur (set-attr vt :bg (- x 92)) (rest params))
+            (recur vt (rest params))))
         vt))))

 (defn execute-vpa [vt]


Adds training page link to nav and removes Home.

--- src/cadence/views/common.clj
+++ src/cadence/views/common.clj
@@ -54,8 +54,9 @@
        [:a.brand.dropdown-toggle {:href "#"} "Cadence"]
        [:div.nav-collapse
         [:ul.nav
-         [:li [:a {:href "/"}
-               [:i.icon-home.icon-white] " Home"]]
+         (when (not (friend/anonymous?))
+           [:li
+            [:a {:href "/user/training"} "Training"]])
          [:li [:a {:href "/about"} "About"]]]
         [:ul.nav.pull-right
          [:li.divider-vertical]
@@ -66,7 +67,7 @@
       (when-let [{:keys [type message]} (flash/get)]
         (let [type (name type)]
           [:div {:id "flash" :class (str "alert alert-" type)}
-           [:a.close {:data-dismiss "alert"} "x"]
+           [:a.close {:data-dismiss "alert"} "×"]
            [:strong (string/capitalize type) ": "] message]))
       content]]))

@@ -92,11 +93,11 @@
     [:div.form-actions
      (map form-button buttons)]]])

-(defpartial input [{:keys [eclass type name placeholder]}]
+(defpartial input [{:keys [eclass type name placeholder params]}]
   [(keyword (str "input" (as-css-id eclass)))
-   {:type type
+   (merge params {:type type
     :name (string/lower-case name)
-    :placeholder (or placeholder name)}])
+    :placeholder (or placeholder name)})])

 (defpartial default-form [id+class params items buttons]
   [(keyword (str "form" (as-css-id id+class))) params


run-query returns n possible tuples

run-query returns n possible tuples


build-lookup-table tests

build-lookup-table tests

--- test/grafter/tabular_test.clj
+++ test/grafter/tabular_test.clj
@@ -277,65 +277,30 @@
       (is (thrown? java.lang.Exception
              (swap ordered-ds "A" "B" "C"))))))

-(comment

 (deftest build-lookup-table-test
-  (let [ds (make-dataset [[1 2 3 4]
-                          [5 6 7 8]
-                          [9 10 11 12]])
-
-        row {"D" 8, "C" 7, "B" 6, "A" 5}]
+  (let [ds (make-dataset ["name" "age" "debt"]
+                         [["rick" 30 30]
+                          ["rick" 25 33]
+                          ["john" 9 12]
+                          ["bob" 48 20]
+                          ["kevin" 43 10]])
+
+        key-cell "bob"]
+    (testing "1 key column"
+      (is (= 20
+             ((build-lookup-table debts ["name"] "debt") key-cell)))
+      (is (= nil
+             ((build-lookup-table debts ["name"] "debt") "foo"))))
     (testing "several key columns"
-      (testing "1 value column"
-        (is (= {"B" 6}
-               ((build-lookup-table ds ["A" "C"] "B") row))))
-      (testing "several value columns"
-        (is (= {"D" 8, "B" 6}
-               ((build-lookup-table ds ["A" "C"] ["B" "D"]) row))))
-      (testing "0 value columns"
-        (is (= {"D" 8, "B" 6}
-               ((build-lookup-table ds ["A" "C"]) row))))
-
-      (testing "value column id"
-        (is (= {"B" 6}
-               ((build-lookup-table ds ["A" "C"] 1) row)))))
-    (testing "1 key column"
-      (testing "1 value column"
-        (is (= {"B" 6}
-               ((build-lookup-table ds ["A"] "B") row))))
-      (testing "several value columns"
-        (is (= {"C" 7, "B" 6}
-               ((build-lookup-table ds ["A"] ["B" "C"]) row))))
-      (testing "key column id"
-        (is (= {"B" 6}
-               ((build-lookup-table ds 0 "B") row))))
-      (testing "key column name"
-        (is (= {"B" 6}
-               ((build-lookup-table ds "A" "B") row)))))
+      (is (= 33
+             ((build-lookup-table debts ["name" "age"] "debt") ["rick" 25])))
+      (is (= nil
+             ((build-lookup-table debts ["name" "age"] "debt") ["foo" 99]))))
     (testing "errors"
       (testing "no key column"
         (is (thrown? IndexOutOfBoundsException
-                     ((build-lookup-table ds [] "B") row))))
+                     ((build-lookup-table debts [] "debt") key-cell))))
       (testing "key column not existing"
         (is (thrown? IndexOutOfBoundsException
-                     ((build-lookup-table ds ["foo"] "B") row)))))))
-
-
-
-  ;; TODO: Make build-lookup-table work like this:
-
-  (let [friends (make-dataset [["rick"] ["bob"] ["john"] ["kevin"]])
-        debtor-table (make-dataset [["bob" 10] ["john" 20] ["rick" 30]])
-
-        debtor-lookup (build-lookup-table debtor-table :A :B)]
-
-    (-> friends
-        (derive-column :A debtor-lookup :money-owed-by-friend)))
-
-  ;; =>
-  ;; |   :A | :money-owed-by-friend |
-  ;; |------+-----------------------|
-  ;; |  bob |                    10 |
-  ;; | john |                    20 |
-  ;; | rick |                    30 |
-)
+                     ((build-lookup-table debts "foo" "debt") key-cell)))))))


Don't generate zero records in data-context.

--- test/merkle_db/generators.clj
+++ test/merkle_db/generators.clj
@@ -114,5 +114,5 @@
   (gen/bind
     (gen/tuple
       (gen/not-empty (gen/set field-key))
-      gen/nat)
+      (gen/such-that pos? gen/nat))
     (partial apply data-context*)))


Updated ns-tracker dependency

Updated ns-tracker dependency

--- ring-devel/project.clj
+++ ring-devel/project.clj
@@ -4,4 +4,4 @@
   :dependencies [[ring/ring-core "1.1.7"]
                  [hiccup "1.0.0"]
                  [clj-stacktrace "0.2.4"]
-                 [ns-tracker "0.2.0"]])
+                 [ns-tracker "0.2.1"]])


hide align button

hide align button

--- frontend/src/uxbox/main/ui/workspace/header.cljs
+++ frontend/src/uxbox/main/ui/workspace/header.cljs
@@ -126,10 +126,10 @@
         {:alt "Grid (Ctrl + G)"
          :class (when (contains? flags :grid) "selected")
          :on-click (partial toggle :grid)}
-        i/grid]
-       [:li.tooltip.tooltip-bottom
-        {:alt "Align (Ctrl + A)"}
-        i/alignment]]
+        i/grid]]
+       ;; [:li.tooltip.tooltip-bottom
+        ;; {:alt "Align (Ctrl + A)"}
+        ;; i/alignment]]
       [:ul.options-btn
        [:li.tooltip.tooltip-bottom.view-mode
         {:alt "View mode (Ctrl + P)"


Add gif to a list of webp-compatible types

--- src/vignette/media_types.clj
+++ src/vignette/media_types.clj
@@ -10,7 +10,7 @@

 (def archive-dir "archive")

-(def webp-compatible-mime-types #{"image/jpeg" "image/png"})
+(def webp-compatible-mime-types #{"image/jpeg" "image/png" "image/gif"})
 (def webp-mime-type "image/webp")
 (def webp-format "webp")


Handle mouse up anywhere

Handle mouse up anywhere

--- src/web_audio_cljs/core.cljs
+++ src/web_audio_cljs/core.cljs
@@ -20,11 +20,17 @@
                           :recorded-buffers []
                           :audio-context audio-context}))

-(defn listen [el type]
-  (let [out (chan)]
-    (events/listen el type
-      (fn [e] (put! out e)))
-    out))
+(defn listen
+  ([el type]
+   (let [out (chan)]
+     (events/listen el type
+       (fn [e] (put! out e)))
+     out))
+  ([el type tx]
+   (let [out (chan 1 tx)]
+     (events/listen el type
+       (fn [e] (put! out e)))
+     out)))

 (defn lin-interp [x0 x1 y0 y1]
   (fn [x]
@@ -33,23 +39,20 @@
              (- x1 x0))
           (- y1 y0)))))

-(defn min-arr-val [arr]
+(defn superlative-of [arr compar]
   (loop [i 0 min-val (aget arr 0)]
     (if (= i (.-length arr))
       min-val
       (let [cur-val (aget arr i)]
-        (if (< cur-val min-val)
+        (if (apply compar [cur-val min-val])
           (recur (inc i) cur-val)
           (recur (inc i) min-val))))))

+(defn min-arr-val [arr]
+  (superlative-of arr <))
+
 (defn max-arr-val [arr]
-  (loop [i 0 max-val (aget arr 0)]
-    (if (= i (.-length arr))
-      max-val
-      (let [cur-val (aget arr i)]
-        (if (> cur-val max-val)
-          (recur (inc i) cur-val)
-          (recur (inc i) max-val))))))
+  (superlative-of arr >))

 (defn draw-select-rect! [canvas-width canvas-height canvas-context mouse-down? mouse-over?]
   (.clearRect canvas-context 0 0 canvas-width canvas-height)
@@ -59,7 +62,7 @@
     (do
       (aset canvas-context "strokeStyle" "aliceblue")
       (aset canvas-context "lineWidth" 6)
-      (.strokeRect canvas-context 0 2 100 96))
+      (.strokeRect canvas-context 2 2 96 96))
     mouse-over?
     (do
       (aset canvas-context "strokeStyle" "aliceblue")
@@ -101,16 +104,24 @@
     om/IRender
     (render [_]
       (dom/div nil
-               (dom/button #js {:className "toggle-recording"
-                                :onClick (fn [e]
-                                           (if is-recording
-                                             (do
-                                               (save-recording! data audio-recorder audio-context analyser-node)
-                                               (om/transact! data :is-recording not))
-                                             (do
-                                               (.record audio-recorder)
-                                               (om/transact! data :is-recording not))))}
-                           (if is-recording "Stop" "Record"))))))
+        (dom/button #js {:className "toggle-recording"
+                         :onClick (fn [e]
+                                    (if is-recording
+                                      (do
+                                        (save-recording! data audio-recorder audio-context analyser-node)
+                                        (om/transact! data :is-recording not))
+                                      (do
+                                        (.record audio-recorder)
+                                        (om/transact! data :is-recording not))))}
+                    (if is-recording "Stop" "Record"))))))
+
+(defn clamped-rel-mouse-pos [e min-x max-x {:keys [x-offset mouse-down-pos mouse-down]}]
+  (if mouse-down
+    (let [x (.-clientX e)
+          [old-x old-y] mouse-down-pos
+          new-x (+ x-offset (- x old-x))]
+      [(.clamp goog.math new-x min-x max-x) old-x old-y])
+    nil))

 (defn wave-selector-view [data owner]
   (reify
@@ -133,18 +144,14 @@
             canvas-context (.getContext canvas "2d")
             mouse-move-chan (listen js/document (.-MOUSEMOVE EventType))
             mouse-up-chan (listen js/document (.-MOUSEUP EventType))]
-        ;;;
-        ;;; On any mouse up on the document, set mouse-down to false.
         (go
           (while true
-            (let [e (<! mouse-move-chan)
-                  x (.-clientX e)
-                  {:keys [mouse-down x-offset mouse-down-pos]} (om/get-state owner)
-                  [old-x old-y] mouse-down-pos
-                  new-x (+ x-offset (- x old-x))
-                  clamp-x (.clamp goog.math new-x 0 (- 400 canvas-width))]
-              (when mouse-down
-                (om/update-state! owner #(assoc % :x-offset clamp-x :mouse-down-pos [x old-y]))))))
+            (alt!
+              mouse-move-chan
+              ([v] (when-let [[clamp-x _ old-y] (clamped-rel-mouse-pos v 0 (- 400 canvas-width) (om/get-state owner))]
+                     (om/update-state! owner #(assoc % :x-offset clamp-x :mouse-down-pos [(.-clientX v) old-y]))))
+              mouse-up-chan
+              ([_] (om/set-state! owner :mouse-down false)))))
         (om/update-state! owner #(assoc % :canvas-context canvas-context :canvas canvas))))

     om/IDidUpdate
@@ -161,8 +168,8 @@
                        :height      canvas-height
                        :style       #js {:opacity 0.3 :position "absolute" :left x-offset}
                        :ref         "canvas-ref"
-                       :onMouseDown (fn [e] (om/set-state! owner :mouse-down true) (om/set-state! owner :mouse-down-pos [(.-clientX e) (.-clientY e)]))
-                       :onMouseUp   #(om/set-state! owner :mouse-down false)
+                       :onMouseDown (fn [e] (om/update-state! owner
+                                              #(assoc % :mouse-down true :mouse-down-pos [(.-clientX e) (.-clientY e)])))
                        :onMouseOver #(om/set-state! owner :mouse-over true)
                        :onMouseOut  #(om/set-state! owner :mouse-over false)}
                   "no canvas"))))
@@ -186,7 +193,7 @@

     om/IRenderState
     (render-state [_ {:keys [canvas-width canvas-height]}]
-      (dom/div #js {:style  #js {:position "relative"}}
+      (dom/div #js {:style #js {:position "relative"}}
         (dom/canvas #js {:width  canvas-width
                          :height canvas-height
                          :ref    "canvas-ref"}


added "olvidar"

added "olvidar"

--- src/babel/espanol/lexicon.clj
+++ src/babel/espanol/lexicon.clj
@@ -866,11 +866,17 @@
                   :sem {:subj {:animate true}
                         :pred :hear}}}

-   "olvidar" {}
+   "olvidar" {:synsem {:cat :verb
+                      :sem {:pred :forget}}}
+
    "organizar" {}
+
    "pagar" {}
+
    "parar" {}
+
    "pedir" {}
+
    "peinarse" {}

    "os"


added negar

added negar

--- src/babel/espanol/lexicon.clj
+++ src/babel/espanol/lexicon.clj
@@ -383,6 +383,11 @@
                     :subcat {:1 {:cat :det
                                  :number :sing
                                  :def :def}}}})
+
+   "negar" {:espanol {:boot-stem "nieg"}
+                :synsem {:cat :verb
+                         :sem {:pred :deny}}}
+
    "nos" {:synsem {:cat :noun
                    :pronoun true
                    :reflexive true


filter out transitive non-reflexive verbs for purposes of generation

--- src/babel/italiano/writer.clj
+++ src/babel/italiano/writer.clj
@@ -45,7 +45,9 @@
                            (= (get-in lexeme [:synsem :cat]) :verb)
                            (= (get-in lexeme [:synsem :infl]) :top)
                            (= (get-in lexeme [:synsem :aux] false) false)
-                           (not (= :top (get-in lexeme [:synsem :sem :pred] :top)))))
+                           (not (= :top (get-in lexeme [:synsem :sem :pred] :top)))
+                           (or (= :unspec (get-in lexeme [:synsem :sem :obj]))
+                               (= true (get-in lexeme [:synsem :sem :reflexive])))))
                         lexeme-set))
               lexemes))


Don't use flatten

Don't use flatten

The recursive nature of flatten is not needed here, and it precludes
having arguments to quick-check that have sequential literals.

If clojure.core had mapply this wouldn't be so awkward.

Signed-off-by: Reid Draper <1f4d9895740d1b07c3b2f21f4b03e23d1086f158@gmail.com>

--- src/main/clojure/clojure/test/check/clojure_test.clj
+++ src/main/clojure/clojure/test/check/clojure_test.clj
@@ -44,7 +44,7 @@
            clojure.test.check/quick-check
            times#
            (vary-meta ~property assoc :name (str '~property))
-           (flatten (seq quick-check-opts#))))))))
+           (apply concat quick-check-opts#)))))))

 (def ^:dynamic *report-trials*
   "Controls whether property trials should be reported via clojure.test/report.


CMR-1246: Remove OBE code since reset is not a valid action type on the message queue

--- system-int-test/src/cmr/system_int_test/utils/index_util.clj
+++ system-int-test/src/cmr/system_int_test/utils/index_util.clj
@@ -43,7 +43,6 @@
   "Returns a map of concept id revision id tuples to the sequence of states for each one."
   [message-states]
   (let [int-states (for [mq message-states
-                         :when (not= (get-in mq [:action :action-type]) :reset)
                          :let [{{:keys [action-type]
                                  {:keys [concept-id revision-id id]} :message} :action} mq
                                result-state (:state (messages+id->message (:messages mq) id))]]


[#532] Clean up some sql generation

[#532] Clean up some sql generation

--- backend/src/akvo/lumen/lib/pivot_impl.clj
+++ backend/src/akvo/lumen/lib/pivot_impl.clj
@@ -26,25 +26,20 @@
                           value-column
                           aggregation]}
                   filter-str]
-  (str
-   (format "SELECT %s, %s, %s(%s) FROM %s WHERE %s\n"
-           (get row-column "columnName")
-           (get category-column "columnName")
-           aggregation
-           (get value-column "columnName")
-           table-name
-           filter-str)
-   "GROUP BY 1,2 ORDER BY 1,2\n"))
+  (format "SELECT %s, %s, %s(%s) FROM %s WHERE %s GROUP BY 1,2 ORDER BY 1,2"
+          (get row-column "columnName")
+          (get category-column "columnName")
+          aggregation
+          (get value-column "columnName")
+          table-name
+          filter-str))

 (defn pivot-sql [table-name query filter-str categories-count]
-  (str "SELECT * FROM crosstab ($$\n"
-       (source-sql table-name query filter-str)
-       "$$,$$\n"
-       (unique-values-sql table-name (:category-column query) filter-str)
-       "$$) AS ct (c1 text, \n"
-       (str/join "," (map #(format "c%s double precision" (+ % 2))
-                          (range categories-count)))
-       ");"))
+  (format "SELECT * FROM crosstab ($$ %s $$, $$ %s $$) AS ct (c1 text, %s);"
+          (source-sql table-name query filter-str)
+          (unique-values-sql table-name (:category-column query) filter-str)
+          (str/join "," (map #(format "c%s double precision" (+ % 2))
+                             (range categories-count)))))

 (defn apply-pivot [conn dataset query filter-str]
   (let [categories (unique-values conn
@@ -75,12 +70,13 @@
      :rows count}))

 (defn apply-empty-category-query [conn dataset query filter-str]
-  (let [rows (rest (jdbc/query conn
-                               [(format "SELECT %s, count(rnum) FROM %s WHERE %s GROUP BY 1 ORDER BY 1"
-                                        (get (:row-column query) "columnName")
-                                        (:table-name dataset)
-                                        filter-str)]
-                               {:as-arrays? true}))]
+  (let [rows (rest
+              (jdbc/query conn
+                          [(format "SELECT %s, count(rnum) FROM %s WHERE %s GROUP BY 1 ORDER BY 1"
+                                   (get (:row-column query) "columnName")
+                                   (:table-name dataset)
+                                   filter-str)]
+                          {:as-arrays? true}))]
     {:columns [{"type" "text"
                 "title" (get (:row-column query) "title")}
                {"type" "number"
@@ -88,13 +84,15 @@
      :rows rows}))

 (defn apply-empty-row-query [conn dataset query filter-str]
-  (let [counts (map second
-                    (rest (jdbc/query conn
-                                      [(format "SELECT %s, count(rnum) FROM %s WHERE %s GROUP BY 1 ORDER BY 1"
-                                               (get (:category-column query) "columnName")
-                                               (:table-name dataset)
-                                               filter-str)]
-                                      {:as-arrays? true})))
+  (let [counts (->> (jdbc/query
+                     conn
+                     [(format "SELECT %s, count(rnum) FROM %s WHERE %s GROUP BY 1 ORDER BY 1"
+                              (get (:category-column query) "columnName")
+                              (:table-name dataset)
+                              filter-str)]
+                     {:as-arrays? true})
+                    rest
+                    (map second))
         categories (unique-values conn (:table-name dataset) (:category-column query) filter-str)]
     {:columns (cons {"title" ""
                      "type" "text"}


Added stafett

Added stafett

--- src/clj/skidskytte/namer.clj
+++ src/clj/skidskytte/namer.clj
@@ -152,6 +152,7 @@
                 "skateboard"
                 "skytte"
                 "slalom"
+                "stafett"
                 "styrkelyft"
                 "störtlopp"
                 "snowboard"


multy arrity engine method

multy arrity engine method

--- src/clj/trottoirs/engine.clj
+++ src/clj/trottoirs/engine.clj
@@ -104,7 +104,9 @@

 ;;; Main function ;;;;;;;;;;;
-(defn draw-perps [lat lng rad]
+(defn draw-perps
+  ( [] (draw-perps nil nil nil)) ; that's ugly yeah
+  ( [lat lng rad]
   (let [;; trottoirs will be computed around this central point with a given diameter
         nearQuery (if (every? some? [lat lng rad])
                     { :geometry
@@ -163,5 +165,5 @@
       out
       )

-    ))
+    )))


forward to filter after auth

forward to filter after auth

--- src/cljs/uberblick/core.cljs
+++ src/cljs/uberblick/core.cljs
@@ -346,8 +346,8 @@
   ([token]
    (prn 'token token)
    (genome/set-auth-token token)
-   (set! (.-location js/window) "/") ;hide the token!
-   (secretary/dispatch! "/")
+   (set! (.-location js/window) "#filters") ;hide the token!
+   (secretary/dispatch! "#filters")
    ))

 (defn current-page []


Don't need to track the upstream here

Don't need to track the upstream here

--- src/clojure/picard/proxy.clj
+++ src/clojure/picard/proxy.clj
@@ -35,29 +35,27 @@
          (defupstream
            ;; Handling the initial request
            (request [req]
-             (with
-              (client/request
-               pool (addr-from-req req) req
-               (fn [upstream evt val]
-                 (cond
-                  (bad-gateway? @state evt val)
-                  (downstream :response [502 {"content-length" "0"} nil])
+             (client/request
+              pool (addr-from-req req) req
+              (fn [upstream evt val]
+                (cond
+                 (bad-gateway? @state evt val)
+                 (downstream :response [502 {"content-length" "0"} nil])

-                  (= :connected evt)
-                  (locking req
-                    (let [current-state @state]
-                      (when (= :pending current-state)
-                        (downstream :resume nil))
-                      (reset! state upstream)))
+                 (= :connected evt)
+                 (locking req
+                   (let [current-state @state]
+                     (when (= :pending current-state)
+                       (downstream :resume nil))
+                     (reset! state upstream)))

-                  :else
-                  (downstream evt val))))
-              :as upstream
-              (when (chunked? req)
-                (locking req
-                  (when-not @state
-                    (reset! state :pending)
-                    (downstream :pause nil))))))
+                 :else
+                 (downstream evt val))))
+             (when (chunked? req)
+               (locking req
+                 (when-not @state
+                   (reset! state :pending)
+                   (downstream :pause nil)))))
            ;; Handling all other events
            (:else [evt val]
              (if-let [upstream @state]


Remove reference to unused function

Remove reference to unused function

--- src/com/puppetlabs/utils.clj
+++ src/com/puppetlabs/utils.clj
@@ -16,7 +16,7 @@
         [clojure.java.io :only (reader)]
         [clojure.set :only (difference union)]
         [clj-time.core :only [now]]
-        [clj-time.format :only [formatters unparse parse]]
+        [clj-time.format :only [formatters unparse]]
         [slingshot.slingshot :only (try+ throw+)]))

 ;; ## Math


Still show 'x of n' event count when x is 0

--- src/day8/re_frame/trace.cljs
+++ src/day8/re_frame/trace.cljs
@@ -213,7 +213,7 @@
           [:thead>tr
            [:th "operations"]
            [:th
-             (when (pos? (count showing-traces))
+             (when (pos? (count @filter-items))
                (str (count showing-traces) " of "))
              (when (pos? (count @traces))
                (str (count @traces)))


improved HTML generator for paragraph to support CSS class as optional argument

--- src/distillery/view/html.clj
+++ src/distillery/view/html.clj
@@ -45,8 +45,10 @@

 (defn paragraph
   "Wrappes the given content into a paragraph."
-  [content]
+  ([content]
   {:tag :p :content (safe-content content)})
+  ([css-class content]
+  {:tag :p :attrs {:class css-class} :content (safe-content content)}))

 (defn headline
   "Wrappes the given content into a headline. Headline levels from 1 to 8 are supported."


Problem added - "Reimplement Trampoline"

--- src/foreclojure/data_set.clj
+++ src/foreclojure/data_set.clj
@@ -888,6 +888,17 @@

       (insert! :problems
            {:_id 78
+            :title "Reimplement Trampoline"
+            :times-solved 0
+            :restricted ["trampoline"]
+            :description ""
+            :approved true
+            :tags ["medium" "core-functions"]
+            :tests ["(= (letfn [(triple [x] #(sub-two (* 3 x)))\n          (sub-two [x] #(stop?(- x 2)))\n          (stop? [x] (if (> x 50) x #(triple x)))]\n    (__ triple 2))\n  82)"
+                    "(= (letfn [(my-even? [x] (if (zero? x) true #(my-odd? (dec x))))\n          (my-odd? [x] (if (zero? x) false #(my-even? (dec x))))]\n    (map #(__ my-even? %) (range 6)))\n  [true false true false true false])"]})
+
+      (insert! :problems
+           {:_id 79
             :title "Power Set"
             :times-solved 0
             :description "A power set is the set of all subsets of a given set. Given a list, produce a set of sublists while preserving the order of elements."
@@ -897,6 +908,7 @@
                     "(= (__ '()) '#{()})"
                     "(= (__ '(1 2 3)) '#{() (1) (2) (3) (1 2) (1 3) (2 3) (1 2 3)})"
                     "(= (count (__ (range 10))) 1024)"]})
+
       ))

 (load-problems)


Kill url helper fn

Kill url helper fn

--- src/icecap/handlers/http.clj
+++ src/icecap/handlers/http.clj
@@ -10,9 +10,9 @@

 (defn scheme
-  "Get the scheme of a URL."
-  [^String url]
-  (.getScheme (URI. url)))
+  "Get the scheme of a (string) URL."
+  [^String s]
+  (.getScheme (URI. s)))

 (defn valid-scheme?
   "Checks if the given URL has a valid scheme."


Implement `derivative` operation

Implement `derivative` operation

--- src/io/cyanite/query/ast.clj
+++ src/io/cyanite/query/ast.clj
@@ -110,6 +110,23 @@
      nil
      (resolve! series 1 1))))

+(defrecord DerivativeOperation [series]
+  SeriesTransform
+  (transform! [this]
+    (traverse!
+     "derivative($0)"
+     (let [st (volatile! ::none)]
+       (fn [i]
+         (if-not (nil? i)
+           (let [prev @st]
+             (vreset! st i)
+             (if (= ::none prev)
+               i
+               (- i prev))))))
+
+     nil
+     (resolve! series 1 1))))
+
 (defrecord AbsoluteOperation [series]
   SeriesTransform
   (transform! [this]
@@ -141,6 +158,10 @@
   [[_ series]]
   (AbsoluteOperation. (tokens->ast series)))

+(defmethod tokens->ast :derivative
+  [[_ series]]
+  (DerivativeOperation. (tokens->ast series)))
+
 (defmethod tokens->ast :default
   [x]
   (throw (ex-info "unsupported function in cyanite" {:arg x})))


rm metadata forwarding

rm metadata forwarding

--- src/java_time/impl/load.cljc
+++ src/java_time/impl/load.cljc
@@ -35,11 +35,8 @@
 (def ^Runnable async-load-fast-path
   (bound-fn []
     (load-java-time)
-    (run! (fn [sym]
-            (let [api (resolve (symbol "java-time" (name sym)))
-                  impl (resolve sym)]
-              (alter-var-root api (constantly @impl))
-              (alter-meta! api vary-meta (fnil into {}) (select-keys (meta impl) [:doc :arglists :deprecated]))))
+    (run! #(alter-var-root (resolve (symbol "java-time" (name %)))
+                           (constantly @(resolve %)))
           @slow-path-vars)))

 (defmacro when-class [clstr & body]


Improvements to DTBook catalog entries

Improvements to DTBook catalog entries

- show genre-text
- add classes

--- src/catalog/layout/dtbook.clj
+++ src/catalog/layout/dtbook.clj
@@ -8,16 +8,17 @@

 (def wrap (layout/wrapper ""))

-(defn catalog-entry [{:keys [creator record-id title subtitle name-of-part source-publisher source-date
-                        genre description producer-brief rucksackbuch? rucksackbuch-number
-                        library-signature product-number price]}]
-  [:div {:class "catalog-item"}
-   [:p (wrap creator "" ": " false) (wrap title) (wrap subtitle) (wrap name-of-part) " - "
+(defn catalog-entry [{:keys [creator record-id title subtitles name-of-part source-publisher
+                             source-date genre-text description producer-brief rucksackbuch?
+                             rucksackbuch-number library-signature product-number price]}]
+  [:div {:class "ps"}
+   [:p {:class "tit"} (wrap creator "" ": " false)
+    (wrap title) (for [s subtitles] (wrap s)) (wrap name-of-part) " - "
     (wrap source-publisher "" ", " false) (wrap (layout/year source-date))]
-   [:p (wrap (layout/translations genre) "Genre: ")]
-   [:p (wrap description)]
+   [:p {:class "gen"} (wrap genre-text "Genre: ")]
+   [:p {:class "ann"} (wrap description)]
    (if rucksackbuch?
-     [:p (wrap producer-brief "" ", " false) (wrap rucksackbuch-number "Rucksackbuch Nr. ")]
+     [:p {:class "pro"} (wrap producer-brief "" ", " false) (wrap rucksackbuch-number "Rucksackbuch Nr. ")]
      [:p (wrap producer-brief)])
    (when library-signature
      [:p {:class "aus"} "Ausleihe: " (layout/braille-signatures library-signature)])


export some obviously useful utilities to cljs.analyzer.api

--- src/clj/cljs/analyzer/api.clj
+++ src/clj/cljs/analyzer/api.clj
@@ -11,6 +11,59 @@
                             ns-publics remove-ns])
   (:require [cljs.env :as env]
             [cljs.analyzer :as ana]))
+
+;; =============================================================================
+
+(defn empty-env
+  "Creates an empty analysis environment."
+  []
+  (ana/empty-env))
+
+(defn analyze
+  "Given an environment, a map containing {:locals (mapping of names to bindings), :context
+  (one of :statement, :expr, :return), :ns (a symbol naming the
+  compilation ns)}, and form, returns an expression object (a map
+  containing at least :form, :op and :env keys). If expr has any (immediately)
+  nested exprs, must have :children [exprs...] entry. This will
+  facilitate code walking without knowing the details of the op set."
+  ([env form] (ana/analyze env form nil))
+  ([env form name] (ana/analyze env form name nil))
+  ([env form name opts] (ana/analyze env form name opts)))
+
+(defn forms-seq
+  "Seq of Clojure/ClojureScript forms from rdr, a java.io.Reader. Optionally
+  accepts a filename argument which will be used in any emitted errors."
+  ([rdr] (ana/forms-seq* rdr nil))
+  ([rdr filename] (ana/forms-seq* rdr filename)))
+
+(defn parse-ns
+  "Helper for parsing only the essential namespace information from a
+   ClojureScript source file and returning a cljs.closure/IJavaScript compatible
+   map _not_ a namespace AST node.
+
+   By default does not load macros or perform any analysis of dependencies. If
+   opts parameter provided :analyze-deps and :load-macros keys their values will
+   be used for *analyze-deps* and *load-macros* bindings respectively. This
+   function does _not_ side-effect the ambient compilation environment unless
+   requested via opts where :restore is false."
+  ([src] (ana/parse-ns src nil nil))
+  ([src opts] (ana/parse-ns src nil opts))
+  ([src dest opts] (ana/parse-ns src dest opts)))
+
+(defn analyze-file
+  "Given a java.io.File, java.net.URL or a string identifying a resource on the
+   classpath attempt to analyze it.
+
+   This function side-effects the ambient compilation environment
+   `cljs.env/*compiler*` to aggregate analysis information. opts argument is
+   compiler options, if :cache-analysis true will cache analysis to
+   \":output-dir/some/ns/foo.cljs.cache.edn\". This function does not return a
+   meaningful value."
+  ([f] (ana/analyze-file f nil))
+  ([f opts] (ana/analyze-file f opts)))
+
+;; =============================================================================
+;; Main API

 (defn resolve
   "Given an analysis environment resolve a var. Analogous to


Small fixes to loader.clj

Small fixes to loader.clj

--- src/clj/elephantdb/loader.clj
+++ src/clj/elephantdb/loader.clj
@@ -88,15 +88,15 @@
     ))

-(defn supervise-shard [domain shard-id max-kbs-per-shard ^ShardState shard-state]
+(defn supervise-shard [domain shard-id max-kbs total-kb ^ShardState shard-state]
   (let [downloaded-kb (:downloaded-kb shard-state)
         do-download (:do-download shard-state)
         sleep-interval (:sleep-interval shard-state)]
     (let [dl-kb @downloaded-kb
           sleep-ms (rand 1000)] ;; sleep random amount of time up to 1s
-      (if (>= dl-kb max-kbs-per-shard)
+      (swap! total-kb + dl-kb)
+      (if (>= @total-kb max-kbs)
         (do
-          (log-message "Download throttle exceeded (" domain " / " shard-id "): " dl-kb " (" max-kbs-per-shard " allowed) - Sleeping: " sleep-ms "ms")
           (reset! do-download false)
           (reset! sleep-interval sleep-ms)
           (reset! downloaded-kb 0))
@@ -107,13 +107,14 @@
 (defn supervise-downloads [amount-shards max-kbs interval-ms ^DownloadState state]
   (let [domain-to-shard-states (:shard-states state)
         finished-loaders (:finished-loaders state)
-        max-kbs-per-shard (/ max-kbs amount-shards)]
+        total-kb (atom 0)]
     (loop []
+      (reset! total-kb 0)
       (Thread/sleep interval-ms)
       (when (< @finished-loaders amount-shards)
         (doseq [[domain shard-states] domain-to-shard-states]
           (doseq [[s-id ^ShardState s-state] shard-states]
-            (supervise-shard domain s-id max-kbs-per-shard s-state)))
+            (supervise-shard domain s-id max-kbs total-kb s-state)))
         (recur)))))

 (defn start-download-supervisor [amount-shards max-kbs ^DownloadState state]


implement Exploratory Romp

implement Exploratory Romp

--- src/clj/game/cards-events.clj
+++ src/clj/game/cards-events.clj
@@ -136,6 +136,24 @@
    "Executive Wiretaps"
    {:msg (msg "reveal cards in HQ: " (map :title (:hand corp)))}

+   "Exploratory Romp"
+   {:prompt "Choose a server" :choices (req servers)
+    :effect (effect (run target
+                       {:replace-access
+                        {:prompt "Advancements to remove from a card in or protecting this server?"
+                         :choices ["0", "1", "2", "3"]
+                         :effect (req (let [c (Integer/parseInt target)]
+                                        (resolve-ability
+                                          state side
+                                          {:choices {:req #(and (contains? % :advance-counter)
+                                                                (= (:server run) (vec (rest (butlast (:zone %))))))}
+                                          :msg (msg "remove " c " advancements from "
+                                                (if (:rezzed target) (:title target) "a card"))
+                                          :effect (req (add-prop state :corp target :advance-counter (- c))
+                                                       (swap! state update-in [:runner :prompt] rest)
+                                                       (handle-end-run state side))}
+                                         card nil)))}} card))}
+
    "Express Delivery"
    {:prompt "Choose a card to add to your Grip" :choices (req (take 4 (:deck runner)))
     :effect (effect (move target :hand) (shuffle! :deck))}


bug fix

bug fix

--- src/cljs/closerve/client.cljs
+++ src/cljs/closerve/client.cljs
@@ -88,7 +88,7 @@
                 (go (loop [matched-form (jq/$ form-id)]
                       (if (= 0 (.size matched-form))
                         (do (<! (timeout 500))
-                            (.log "wait form element to arrive")
+                            (log "wait form element to arrive")
                             (recur (jq/$ form-id)))
                         (.submit matched-form
                          (fn [e]


Add schedule layout, fixes #9

Add schedule layout, fixes #9

--- src/cljs/herder/schedule.cljs
+++ src/cljs/herder/schedule.cljs
@@ -12,19 +12,44 @@
    4 "Fourth"
    5 "Fifth"})

+(defn make-link [item]
+  (let [event (get-data [:event (:id @state) (:event_id item)])
+        event_day (:event_day item)
+        day-name (if (= 1 event_day) "" (gstring/format "(%s) " (get count-map (js/parseInt event_day))))]
+    [[:a {:href (str "#/events/" (:id event))} (:name event)] " " day-name]))
+
 (defn ^:export component []
   (let [schedule (get-data [:schedule (:id @state)])
         slots (get-mapped-data [:slots (:id @state)])
-        schedule-issues (get-data [:schedule-issues (:id @state)])]
+        schedule-issues (get-data [:schedule-issues (:id @state)])
+        slot-width (quot 11 (count slots))
+        days (distinct (map :date schedule))]
     [:div {:class "container-fluid"}
      [convention-header :schedule]
      [:h2 "Schedule"]
-     (into [:ul]
-           (for [{:keys [id date event_id slot_id event_day]} (sort-by :date schedule)
-                 :let [event (get-data [:event (:id @state) event_id])
-                       slot (get slots slot_id)
-                       day-name (if (= 1 event_day) "" (gstring/format "(%s) " (get count-map (js/parseInt event_day))))]]
-             ^{:key id} [:li [:a {:href (str "#/events/" event_id)} (:name event)] " " day-name (to-date date) " " (:start slot) "-" (:end slot)]))
+     [:table.table
+      [:thead
+       [:tr
+        (cons
+         (with-meta [:th ""] {:key "corner-slot"})
+         (for [slot (sort-by :start (vals slots))]
+           (with-meta [:th (:start slot) "-" (:end slot)] {:key (:id slot)})))]]
+      (into [:tbody]
+            (for [day days]
+              [:tr
+               (cons
+                (with-meta [:td (to-date day)] {:key day})
+                (doall (for [slot_id (map :id (sort-by :start (vals slots)))
+                             :let [items (filter #(and
+                                                   (= (:date %) day)
+                                                   (= (:slot_id %) slot_id))
+                                                 schedule)
+                                   links (mapv make-link items)
+                                   links (cons (first links) (map #(cons "/ " %) (rest links)))
+                                   link (into [:td] (apply concat links))]]
+                         (do
+                           (js/console.log "link" (pr-str link))
+                           (with-meta link {:key (str slot_id "-" day)})))))]))]
      (if (-> schedule-issues empty? not)
        [:div
         [:h3 "Issues"]


use consultant for data generation (superjob does not contains 2012)

--- src/cljs_workcalendar/app.clj
+++ src/cljs_workcalendar/app.clj
@@ -1,9 +1,7 @@
 (ns cljs-workcalendar.app
   (:require [cljs-workcalendar.datasource.workcalendarsource :as source])
-
-  (:require [cljs-workcalendar.datasource.superjobru])
-  (:import  [cljs_workcalendar.datasource.superjobru SuperjobRuWorkCalendarSource])
-
+  (:require [cljs-workcalendar.datasource.consultantru])
+  (:import  [cljs_workcalendar.datasource.consultantru ConsultantRuWorkCalendarSource])
   (:require [cljs-workcalendar.format.formatinterface :as fmt])
   (:require [cljs-workcalendar.format.plaintextformatter])
   (:require [cljs-workcalendar.format.cljsformatter])
@@ -25,7 +23,7 @@
                                     (:month item)
                                     (:day item)))
                           (source/get-work-calendar
-                           (SuperjobRuWorkCalendarSource.)))]
+                           (ConsultantRuWorkCalendarSource.)))]
     (do
       (serialize-calendar calendar
                           (PlainTextWorkCalendarFormatter.)


Removed extra space indent from routes file header

--- src/compojure/http/routes.clj
+++ src/compojure/http/routes.clj
@@ -1,15 +1,15 @@
-;;  Copyright (c) James Reeves. All rights reserved.
-;;  The use and distribution terms for this software are covered by the Eclipse
-;;  Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) which
-;;  can be found in the file epl-v10.html at the root of this distribution. By
-;;  using this software in any fashion, you are agreeing to be bound by the
-;;  terms of this license. You must not remove this notice, or any other, from
-;;  this software.
+;; Copyright (c) James Reeves. All rights reserved.
+;; The use and distribution terms for this software are covered by the Eclipse
+;; Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) which
+;; can be found in the file epl-v10.html at the root of this distribution. By
+;; using this software in any fashion, you are agreeing to be bound by the
+;; terms of this license. You must not remove this notice, or any other, from
+;; this software.

-;;  compojure.http.routes:
+;; compojure.http.routes:
 ;;
-;;  Functions compiling and matching routes contructed using the Rails routing
-;;  syntax.
+;; Functions compiling and matching routes contructed using the Rails routing
+;; syntax.

 (ns compojure.http.routes
   (:use compojure.str-utils))


Change name and position of buttons to select control type

--- src/re_natal_esp32control_app/views/ble_control.cljs
+++ src/re_natal_esp32control_app/views/ble_control.cljs
@@ -10,9 +10,9 @@

 (def control-modes
   [{:id :single-joystick
-    :name "A Joystick"}
+    :name "Joystick"}
    {:id :toggle-bars
-    :name "Toggle"}
+    :name "Toggle Bars"}
    {:id :tile-buttons
     :name "Tile Buttons"}])

@@ -21,7 +21,8 @@
     (fn []
       [v.common/view
        [v.common/view {:style {:flex-direction "row"
-                               :margin-bottom 40}}
+                               :margin-bottom 20
+                               :align-self "center"}}
         (doall
          (for [{:keys [id name]} control-modes
                :let [selected? (= @control-mode id)]]


The missing close! fn has been added to stream ns

--- core/src/cljc/hellhound/streams.cljc
+++ core/src/cljc/hellhound/streams.cljc
@@ -33,4 +33,5 @@
 (def description s/description)
 (def downstream s/downstream)

+(def close! s/close!)
 ;; ----------------------------------------------------------------------------


Pretty format the xml

Pretty format the xml

--- test/cljs_xml/core_test.cljs
+++ test/cljs_xml/core_test.cljs
@@ -7,7 +7,6 @@

 (deftest ^:async parser-case1
   (testing "Case 1 - Empty element"
-    (print "== case 1")
     (go
       (let [xml "<element/>"
             result (-> xml core/xml->clj <!)]
@@ -16,7 +15,6 @@

 (deftest ^:async parser-case2
   (testing "Case 2 - Empty element with attributes"
-    (print "== case 2")
     (go
       (let [xml "<element att1='a' att2='b'/>"
             result (-> xml core/xml->clj <!)]
@@ -25,7 +23,6 @@

 (deftest ^:async parser-case3
   (testing "Case 3 - Text element"
-    (print "== case 3")
     (go
       (let [xml "<element>value</element>"
             result (-> xml core/xml->clj <!)]
@@ -34,7 +31,6 @@

 (deftest ^:async parser-case4
   (testing "Case 4 - Text + attributes element"
-    (print "== case 4")
     (go
       (let [xml "<element att1='a' att2='b'>value</element>"
             result (-> xml core/xml->clj <!)]
@@ -43,36 +39,55 @@

 (deftest ^:async parser-case5
   (testing "Case 5 - Subtree elements (no repetition)"
-    (print "== recursive 1")
     (go
-      (let [xml "<element><elem-a>1</elem-a><elem-b>2</elem-b><elem-c>3</elem-c></element>"
+      (let [xml "<element>
+                   <elem-a>1</elem-a>
+                   <elem-b>2</elem-b>
+                   <elem-c>3</elem-c>
+                 </element>"
             result (-> xml core/xml->clj <!)]
         (is (= result [:element {} [[:elem-a {} ["1"]] [:elem-b {} ["2"]] [:elem-c {} ["3"]]]]))
         (done)))))

 (deftest ^:async parser-case6
   (testing "Case 6 - Subtree elements (repetition)"
-    (print "== recursive 2")
     (go
-      (let [xml "<element><elem-a>1</elem-a><elem-a>2</elem-a><elem-b>3</elem-b></element>"
+      (let [xml "<element>
+                   <elem-a>1</elem-a>
+                   <elem-a>2</elem-a>
+                   <elem-b>3</elem-b>
+                 </element>"
             result (-> xml core/xml->clj <!)]
         (is (= result [:element {} [[:elem-a {} ["1"]] [:elem-a {} ["2"]] [:elem-b {} ["3"]]]]))
         (done)))))

 (deftest ^:async parser-case7
   (testing "Case 7 - Nested tree"
-    (print "== recursive 3")
     (go
-      (let [xml "<element><elem-a><elem-b><elem-c>test</elem-c></elem-b></elem-a></element>"
+      (let [xml "<element>
+                   <elem-a>
+                     <elem-b>
+                       <elem-c>test</elem-c>
+                     </elem-b>
+                   </elem-a>
+                 </element>"
             result (-> xml core/xml->clj <!)]
         (is (= result [:element {} [[:elem-a {} [[:elem-b {} [[:elem-c {} ["test"]]]]]]  ]]))
         (done)))))

 (deftest ^:async parser-case8
   (testing "Case 8 - Nested tree with children"
-    (print "== recursive 4")
     (go
-      (let [xml "<element><elem-a><elem-b><elem-c>test1</elem-c><elem-c>test2</elem-c><elem-c>test3</elem-c></elem-b></elem-a><elem-a>other</elem-a></element>"
+      (let [xml "<element>
+                   <elem-a>
+                     <elem-b>
+                       <elem-c>test1</elem-c>
+                       <elem-c>test2</elem-c>
+                       <elem-c>test3</elem-c>
+                     </elem-b>
+                   </elem-a>
+                   <elem-a>other</elem-a>
+                 </element>"
             result (-> xml core/xml->clj <!)]
         (is (= result
                [:element {}
@@ -84,39 +99,34 @@
                  [:elem-a {} ["other"]]]]))
         (done)))))

-(def xml-parser-full "
- <rss version=\"2.0\">
-   <channel>
-     <title>RSS Title</title>
-     <description>This is an example of an RSS feed</description>
-     <link>http://www.example.com/main.html</link>
-     <lastBuildDate>Mon, 06 Sep 2010 00:01:00 +0000 </lastBuildDate>
-     <pubDate>Sun, 06 Sep 2009 16:20:00 +0000</pubDate>
-     <ttl>1800</ttl>
-
-     <item>
-       <title>Example entry</title>
-       <description>Here is some text containing an interesting description.</description>
-       <link>http://www.example.com/blog/post/1</link>
-       <guid isPermaLink=\"false\">7bd204c6-1655-4c27-aeee-53f933c5395f</guid>
-       <pubDate>Sun, 06 Sep 2009 16:20:00 +0000</pubDate>
-     </item>
-     <item>
-       <title>Example entry2</title>
-       <description>Here is some text containing an interesting description.</description>
-       <link>http://www.example.com/blog/post/1</link>
-       <guid isPermaLink=\"false\">7bd204c6-1655-4c27-aeee-53f933c5395f</guid>
-       <pubDate>Sun, 06 Sep 2009 16:20:00 +0000</pubDate>
-     </item>
-   </channel>
- </rss>
-")

 (deftest ^:async parser-full
   (testing "Full parser"
-    (print "== Full parser")
     (go
-      (let [xml xml-parser-full
+      (let [xml "<rss version=\"2.0\">
+                   <channel>
+                     <title>RSS Title</title>
+                     <description>This is an example of an RSS feed</description>
+                     <link>http://www.example.com/main.html</link>
+                     <lastBuildDate>Mon, 06 Sep 2010 00:01:00 +0000 </lastBuildDate>
+                     <pubDate>Sun, 06 Sep 2009 16:20:00 +0000</pubDate>
+                     <ttl>1800</ttl>
+                     <item>
+                       <title>Example entry</title>
+                       <description>Here is some text containing an interesting description.</description>
+                       <link>http://www.example.com/blog/post/1</link>
+                       <guid isPermaLink=\"false\">7bd204c6-1655-4c27-aeee-53f933c5395f</guid>
+                       <pubDate>Sun, 06 Sep 2009 16:20:00 +0000</pubDate>
+                     </item>
+                     <item>
+                       <title>Example entry2</title>
+                       <description>Here is some text containing an interesting description.</description>
+                       <link>http://www.example.com/blog/post/1</link>
+                       <guid isPermaLink=\"false\">7bd204c6-1655-4c27-aeee-53f933c5395f</guid>
+                       <pubDate>Sun, 06 Sep 2009 16:20:00 +0000</pubDate>
+                     </item>
+                   </channel>
+                 </rss>"
             result (-> xml core/xml->clj <!)]
         (is (= result
                [:rss {:version "2.0"}


[test/wiring] Fix includes.

[test/wiring] Fix includes.

--- test/cortex/wiring_test.cljc
+++ test/cortex/wiring_test.cljc
@@ -1,9 +1,10 @@
 (ns cortex.wiring-test
-  (:require [cortex.core :refer [calc function-module stack-module parameters output]]
+  (:require [cortex.core :refer [calc stack-module parameters output forward
+                                 backward input-gradient calc-output]]
             #?(:cljs
-                [cljs.test :refer-macros [deftest is]]
+                [cljs.test :refer-macros [deftest is testing]]
                 :clj
-                [clojure.test :refer [deftest is]])
+                [clojure.test :refer [deftest is testing]])
             [clojure.core.matrix :as m]
             [cortex.layers :as layers]))


fix hardcoded testdata to match/id

fix hardcoded testdata to match/id

--- test/foosball/test/stats.clj
+++ test/foosball/test/stats.clj
@@ -23,16 +23,16 @@
                                                                                [expected-losers -9]]})))

 (def example-matches
-  [{:id 333, :matchdate #inst "2013-04-11",
+  [{:match/id 333, :matchdate #inst "2013-04-11",
     :team1 {:score 10, :player2 "Knud Erik", :player1 "Lisse", :id 5555},
     :team2 {:score 7, :player2 "Thomas", :player1 "Anders", :id 6666}}
-   {:id 222, :matchdate #inst "2013-04-12",
+   {:match/id 222, :matchdate #inst "2013-04-12",
     :team1 {:score 10, :player2 "Thomas", :player1 "Maria", :id 3333},
     :team2 {:score 2, :player2 "Lisse", :player1 "Anders", :id 4444}}
-   {:id 111, :matchdate #inst "2013-04-13",
+   {:match/id 111, :matchdate #inst "2013-04-13",
     :team1 {:score 10, :player2 "Lisse", :player1 "Thomas", :id 1111},
     :team2 {:score 8, :player2 "Maria", :player1 "Anders", :id 2222}}
-   {:id 444, :matchdate #inst "2013-04-15",
+   {:match/id 444, :matchdate #inst "2013-04-15",
     :team1 {:score 10, :player2 "Anders", :player1 "Knud Erik", :id 7777},
     :team2 {:score 6, :player2 "Lisse", :player1 "Maria", :id 8888}}])


Développements en cours sur CSB (Silver League à ce stade)

--- clojure/codingame/competition/coders-strike-back/src/coders_strike_back/core.clj
+++ clojure/codingame/competition/coders-strike-back/src/coders_strike_back/core.clj
@@ -1,10 +1,10 @@
 (ns coders-strike-back.core
   (:gen-class))

-(defn rand-boolean [] (= (rem (rand-int 10) 2) 0))
+;(defn rand-boolean [] (= (rem (rand-int 10) 2) 0))

 ;; Random boost using
-(defn rand-boost [boost-used?] (if (not @boost-used?) (if (rand-boolean) (do (reset! boost-used? true) "BOOST") "100") "100"))
+;(defn rand-boost [boost-used?] (if (not @boost-used?) (if (rand-boolean) (do (reset! boost-used? true) "BOOST") "100") "100"))

 ;; Distance entre 2 points ou norme du vecteur Norme = ||(x, y) || = sqrt(x*x+y*y)
 (defn distance [x y] (Math/sqrt (+ (* x x) (* y y))))
@@ -14,28 +14,40 @@
   (* degree (/ Math/PI 180) )
   )

-(defn calculate-thrust-from-angle [angle] (str (Integer/valueOf (Math/round (* 100 (Math/cos (convert-degree-to-radian angle)))))))
+(defn calculate-thrust-from-angle [angle] (str (Integer/valueOf (Math/round (* 100 (Math/abs (Math/cos (convert-degree-to-radian angle))))))))

 ;; Ajouter le boost quand l’angle est bon et la distance assez grande
 ;; Si il reste un boost
 ;; Si l’angle est < 10
 ;; Si la distance à la cible est > 4000
 ;;Alors « BOOST »
-(defn use-boost [next-checkpoint-angle next-checkpoint-x next-checkpoint-y boost-used?]
-      (if (and (not @boost-used?) (or (< next-checkpoint-angle 10) (> next-checkpoint-angle -10)) (> (distance next-checkpoint-x next-checkpoint-y) 4000))
+;;(defn use-boost [next-checkpoint-angle next-checkpoint-x next-checkpoint-y boost-used?]
+;;      (if (and (not @boost-used?) (or (< next-checkpoint-angle 10) (> next-checkpoint-angle -10)) (> (distance next-checkpoint-x next-checkpoint-y) 4000))
+;;          (do (reset! boost-used? true)
+;;              "BOOST"
+;;              (calculate-thrust-from-angle next-checkpoint-angle)) (calculate-thrust-from-angle next-checkpoint-angle)))
+
+;;(defn compute-action [next-checkpoint-angle next-checkpoint-x next-checkpoint-y boost-used?]
+;;      (cond
+;;        (>= (Math/abs next-checkpoint-angle) 90) "0"
+;;        (<= 90 (Math/abs next-checkpoint-angle)  60) "25"
+;;        (<= 60 (Math/abs next-checkpoint-angle)  45) "50"
+;;        (<= 45 (Math/abs next-checkpoint-angle)  30) "75"
+;;         true (use-boost next-checkpoint-angle next-checkpoint-x next-checkpoint-y boost-used?)))
+
+(def boost-used? (atom false))
+
+(defn compute-action [next-checkpoint-angle next-checkpoint-x next-checkpoint-y boost-used?]
+      (binding [*out* *err*]
+          (println (str
+                     "distance next-checkpoint-x next-checkpoint-y : " (str (distance next-checkpoint-x next-checkpoint-y))
+                     " ; pod angle with checkpoint : " (str next-checkpoint-angle))))
+      (binding [*out* *err*]
+                    (println (str "Boost used ? (in compute-action) : " @boost-used? )))
+      (if (and (not @boost-used?) (< (Math/abs next-checkpoint-angle) 10) (> (distance next-checkpoint-x next-checkpoint-y) 4000))
           (do (reset! boost-used? true)
               "BOOST"
               (calculate-thrust-from-angle next-checkpoint-angle)) (calculate-thrust-from-angle next-checkpoint-angle)))
-
-(defn compute-action [next-checkpoint-angle next-checkpoint-x next-checkpoint-y boost-used?]
-      (cond
-        (>= (Math/abs next-checkpoint-angle) 90) "0"
-        (<= 90 (Math/abs next-checkpoint-angle)  60) "25"
-        (<= 60 (Math/abs next-checkpoint-angle)  45) "50"
-        (<= 45 (Math/abs next-checkpoint-angle)  30) "75"
-         true (use-boost next-checkpoint-angle next-checkpoint-x next-checkpoint-y boost-used?)))
-
-(def boost-used? (atom false))

 (defn -main [& args]
       (while true
@@ -47,7 +59,8 @@

                   ; (binding [*out* *err*]
                   ;   (println "Debug messages..."))
-
+                  (binding [*out* *err*]
+                    (println (str "Boost used ?" @boost-used? )))
                   ; You have to output the target position
                   ; followed by the power (0 <= thrust <= 100)
                   ; i.e.: "x y thrust"


More concise error logging :warning:

More concise error logging :warning:

--- src/metabase/models/card.clj
+++ src/metabase/models/card.clj
@@ -49,7 +49,7 @@
        ;; if for some reason we can't expand the Card (i.e. it's an invalid legacy card)
        ;; just return a set of permissions that means no one will ever get to see it
        (catch Throwable e
-         (log/warn "Error getting permissions for card:" e)
+         (log/warn "Error getting permissions for card:" (.getMessage e) "\n" (u/pprint-to-str (u/filtered-stacktrace e)))
          #{"/db/0/"}))) ; DB 0 will never exist

 (defn- permissions-path-set:native [read-or-write {database-id :database}]


added sse for future auto-reloading

added sse for future auto-reloading

--- booking-service/src/booking_service/service.clj
+++ booking-service/src/booking_service/service.clj
@@ -6,14 +6,18 @@
             [io.pedestal.service.log :as log]
             ;; the impl dependencies will go away
             ;; these next two will collapse to one
-            [io.pedestal.service.interceptor :as interceptor :refer [definterceptorfn defon-response defon-request defafter defbefore]]
+            [io.pedestal.service.interceptor :as interceptor :refer [definterceptor definterceptorfn defon-response defon-request defafter defbefore]]
             [io.pedestal.service.http :as bootstrap]
             [io.pedestal.service.http.impl.servlet-interceptor :as servlet-interceptor]
             [io.pedestal.service.interceptor :as interceptor]
             [io.pedestal.service.http.route.definition :refer [expand-routes]]
             [io.pedestal.service.http.ring-middlewares :as middlewares]
             [io.pedestal.service.http.route :as route]
+            ;
+            [io.pedestal.service.http.sse :refer :all]
+            ;
             [ring.util.response :as ring-resp]
+            [ring.middleware.session.cookie :as cookie]
             [clojure.data.codec.base64 :as base64]))

@@ -38,9 +42,9 @@
   (byte-transform base64/decode string))

-(defn about-page
-  [request]
-  (ring-resp/response (format "%s" (pr-str request))))
+;(defn about-page
+;  [request]
+;  (ring-resp/response (format "%s" (pr-str request))))

 (defn home-page
@@ -58,7 +62,7 @@
 (defn auth-page []
   {:status 401
    :headers {"Content-Type" "text/html; charset=utf-8"
-             "WWW-Authenticate" (authentication-text "ПАРОЛЬ!")}
+             "WWW-Authenticate" (authentication-text "Please authorize yourself")}
    :body "Restricted!"})

@@ -88,7 +92,13 @@

 (def auth-map {
-  "odmin" "odmin"})
+  "odmin" "0dmin"})
+
+
+(defn- session-id [] (.toString (java.util.UUID/randomUUID)))
+
+(definterceptor session-interceptor
+  (middlewares/session {:store (cookie/cookie-store)}))

 (defbefore basic-auth [context]
@@ -112,17 +122,98 @@
            {:response (auth-page)})))

+;;; sse stuff
+
+(def ^{:doc "Map of subscriber IDs to SSE contexts"}
+  subscribers (atom {}))
+
+(defn context-key
+  "Return key for given `context`."
+  [cookie-name sse-context]
+  (get-in sse-context [:request :cookies cookie-name :value]))
+
+
+(defn add-subscriber
+  "Add `context` to subscribers map."
+  [cookie-name sse-context]
+  (swap! subscribers assoc (context-key cookie-name sse-context) sse-context))
+
+(defn remove-subscriber
+  [cookie-name context]
+  ;(log/info :msg "removing subscriber")
+  (swap! subscribers dissoc (context-key cookie-name context))
+  (end-event-stream context))
+
+
+
+(declare url-for)
+
+(defn subscribe-for
+  [queue-id redirect-to request]
+     (let [session-id (or (get-in request [:cookies queue-id :value])
+                          (session-id))
+           cookie {(keyword queue-id) {:value session-id :path "/"}}]
+       (-> (ring-resp/redirect (url-for redirect-to))
+           (update-in [:cookies] merge cookie))))
+
+
+(def admin-subscribe (partial subscribe-for "admin-session" ::wait-for-events))
+
+(def wait-for-events (sse-setup (partial add-subscriber "admin-session")))
+
+
+(defn remove-subscriber
+  "Remove `context` from subscribers map and end the event stream."
+  [cookie-name context]
+  ; (log/info :msg "removing subscriber")
+  (swap! subscribers dissoc (context-key cookie-name context))
+  (end-event-stream context))
+
+
+
+(defn send-to-subscriber
+  "Send `msg` as event to event stream represented by `context`. If
+  send fails, removes `context` from subscribers map."
+  [cookie-name context msg]
+  (try
+    ;(log/info :msg "calling event sending fn")
+    (send-event context "msg" msg)
+    (catch java.io.IOException ioe
+      (log/error :msg "Exception from event send"
+                 :exception ioe)
+      (remove-subscriber cookie-name context))))
+
+
+(defn send-to-subscribers
+  "Send `msg` to all event streams in subscribers map."
+  [cookie-name msg]
+  ;(log/info :msg "sending to all subscribers")
+  (doseq [sse-context (vals @subscribers)]
+    (send-to-subscriber cookie-name sse-context msg)))
+
+
+
+(defn admin-publish [req]
+  (let [msg-data [:updated [:1_1 :1_2] ]]
+    ;; pr-str won't be needed in the future
+    (send-to-subscribers "admin-session"
+                         (pr-str msg-data)))
+    (ring-resp/response ""))
+
 (defroutes routes
   [[["/"
-     ^:interceptors [dummy-interceptor] ; add data for request
-     {:get about-page}]
-    ["/odmin"
-     ^:interceptors [basic-auth]
-     {:get admin-page}]]])
+     {:get home-page}]
+    ["/booking"
+     ^:interceptors [dummy-interceptor session-interceptor] ; add data for request
+      ["/test-add" {:get admin-publish}]
+      ["/odmin" ^:interceptors [basic-auth ] {:get admin-subscribe}
+          ["/all" {:get wait-for-events}]
+     ]]]])

 ;; You can use this fn or a per-request fn via io.pedestal.service.http.route/url-for
 (def url-for (route/url-for-routes routes))
+

 (defon-response default-cache-control-to-no-cache
@@ -160,6 +251,13 @@
     context))

+
+;;; TBD:
+; 0. init web app
+; 1. session for admins (storing current user)
+; 2. sse for seat updating
+
+
 ;; Consumed by booking-service.server/create-server
 (def service {:env :prod
               ;; You can bring your own non-default interceptors. Make
@@ -170,20 +268,21 @@
               ::bootstrap/routes routes

               ::bootstrap/interceptors [
+                  bootstrap/log-request
+                  ; tbd: remove this
                   log-request
-
                   log-response

                   not-found
-
                   (route/router routes)

-                  (middlewares/file-info)
-                  (middlewares/file "public" {:index-files? false})
+                  (middlewares/resource "public")
+;                  (middlewares/file-info)
+;                  (middlewares/file "public" {:index-files? false})

                   ]
                   ;default-cache-control-to-no-cache
-                  ;bootstrap/log-request
+                  ;
                   ;servlet-interceptor/exception-debug
                   ;middlewares/cookies
                   ;(middlewares/params)


added support for user specific matrix color

--- src/distillery/view/match.clj
+++ src/distillery/view/match.clj
@@ -46,33 +46,40 @@
                   (map render-match-matrix-head-cell categories)))})

 (defn- render-match-matrix-row
-  [matrix max-score category-ids {:keys [id name] :as medium}]
-  {:tag :tr
-   :content
-   (vec (cons {:tag :th
-               :content [{:tag :a
-                          :attrs {:href (str "media/" id "/index.html")
-                                  :title name}
-                          :content name}]}
-              (map
-               (fn [category-id]
-                 (let [match (get-in matrix [category-id id])
-                       score (:score match)
-                       medium-max-score (:max-score medium)
-                       normalized-score (if (> max-score 0) (/ score max-score) 0)
-                       medium-normalized-score (if (> medium-max-score 0) (/ score medium-max-score) 0)]
-                   (if match
-                     {:tag :td
-                      :attrs {:data-medium-id id
-                              :data-category-id category-id
-                              :style (str "background-color: rgba(234,30,106," medium-normalized-score ")")}
-                      :content [(link (str "categories/" category-id "/index.html?match=" id)
-                                      (format "%.1f%%" (* 100 normalized-score)))]}
-                     {:tag :td :content []})))
-               category-ids)))})
+  [configuration matrix max-score category-ids {:keys [id name] :as medium}]
+  (let [[r g b a] (get-in configuration [:matrix :color])
+        cell-color (fn [v] (java.lang.String/format nil
+                                                    "rgba(%d, %d, %d, %.3f)"
+                                                    (to-array [(int (* 255 r))
+                                                               (int (* 255 g))
+                                                               (int (* 255 b))
+                                                               v])))]
+    {:tag :tr
+     :content
+     (vec (cons {:tag :th
+                 :content [{:tag :a
+                            :attrs {:href (str "media/" id "/index.html")
+                                    :title name}
+                            :content name}]}
+                (map
+                 (fn [category-id]
+                   (let [match (get-in matrix [category-id id])
+                         score (:score match)
+                         medium-max-score (:max-score medium)
+                         normalized-score (if (> max-score 0) (/ score max-score) 0)
+                         medium-normalized-score (if (> medium-max-score 0) (/ score medium-max-score) 0)]
+                     (if match
+                       {:tag :td
+                        :attrs {:data-medium-id id
+                                :data-category-id category-id
+                                :style (str "background-color: " (cell-color medium-normalized-score))}
+                        :content [(link (str "categories/" category-id "/index.html?match=" id)
+                                        (format "%.1f%%" (* 100 normalized-score)))]}
+                       {:tag :td :content []})))
+                 category-ids)))}))

 (defn render-match-matrix
-  [{:keys [media categories max-score] :as args}]
+  [{:keys [media categories max-score configuration] :as args}]
   (let [matrix (->> categories
                     (map
                      (fn [category]
@@ -100,4 +107,4 @@
          [(render-match-matrix-head-row categories)]}
         {:tag :tbody
          :content
-         (vec (map (partial render-match-matrix-row matrix max-score category-ids) media))}]}]}))
+         (vec (map (partial render-match-matrix-row configuration matrix max-score category-ids) media))}]}]}))


Add missing update slug to update SQS trigger.

--- src/oc/storage/lib/email.clj
+++ src/oc/storage/lib/email.clj
@@ -10,6 +10,7 @@
    :subject schema/Str
    :note schema/Str
    :reply-to (schema/maybe schema/Str)
+   :slug schema/Str
    :org-slug schema/Str
    :org-name schema/Str
    :logo-url (schema/maybe schema/Str)
@@ -22,6 +23,7 @@
    :subject (:subject update)
    :note (:note update)
    :reply-to (:email user)
+   :slug (:slug update)
    :org-slug org-slug
    :origin-url origin-url
    :org-name (:org-name update)