71 iframe updates

71 iframe updates

--- src/etaoin/api.clj
+++ src/etaoin/api.clj
@@ -1252,32 +1252,37 @@
 ;; iframes
 ;;

-(defn switch-frame
-  "todo"
+(defn switch-frame*
+  "Switches to an (i)frame by its index or an element reference."
   [driver id]
   (with-resp driver :post
     [:session (:session @driver) :frame]
     {:id id}
     _))

-(defn switch-frame-query
-  "todo"
+(defn switch-frame
+  "Switches to an (i)frame quering the page for it."
   [driver q]
   (let [el (query driver q)]
-    (switch-frame driver (el->ref el))))
-
-(defn switch-parent-frame
-  "todo"
+    (switch-frame* driver (el->ref el))))
+
+(defn switch-frame-first
+  "Switches to the first (i)frame."
+  [driver]
+  (switch-frame* driver 0))
+
+(defn switch-frame-parent
+  "Switches to the parent of the current (i)frame."
   [driver]
   (with-resp driver :post
     [:session (:session @driver) :frame :parent]
     nil
     _))

-(defn switch-top-frame
-  "todo"
-  [driver]
-  (switch-frame driver nil))
+(defn switch-frame-top
+  "Switches to the most top of the page."
+  [driver]
+  (switch-frame* driver nil))

 ;;
 ;; logs


Minor internal renaming.

Minor internal renaming.

--- src/suricatta/dsl.clj
+++ src/suricatta/dsl.clj
@@ -167,24 +167,24 @@
 ;; Protocol Implementations
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

-(defmulti field* (comp class first vector))
-
-(defmethod field* java.lang.String
+(defmulti -field (comp class first vector))
+
+(defmethod -field java.lang.String
   [^String name & [type]]
   (let [type (get *datatypes* type)]
     (if type
       (DSL/field name type)
       (DSL/field name))))

-(defmethod field* clojure.lang.Keyword
+(defmethod -field clojure.lang.Keyword
   [name & args]
-  (apply field* (clojure.core/name name) args))
-
-(defmethod field* org.jooq.Field
+  (apply -field (clojure.core/name name) args))
+
+(defmethod -field org.jooq.Field
   [field & args]
   field)

-(defmethod field* org.jooq.impl.Val
+(defmethod -field org.jooq.impl.Val
   [field & args]
   field)

@@ -206,7 +206,7 @@

   clojure.lang.PersistentVector
   (-sort-field ^org.jooq.SortField [v]
-    (let [^org.jooq.Field field (field* (first v))
+    (let [^org.jooq.Field field (-field (first v))
           ^org.jooq.SortField field (case (second v)
                                       :asc (.asc field)
                                       :desc (.desc field))]
@@ -319,7 +319,7 @@
   "Create a field instance."
   [data & [{:keys [alias] :as opts}]]
   (defer
-    (let [f (field* data)]
+    (let [f (-field data)]
       (if alias
         (.as f (clojure.core/name alias))
         f))))
@@ -345,10 +345,10 @@
       (cond
        (instance? org.jooq.WithStep (first fields))
        (.select (first fields)
-                (->> (map field* (rest fields))
+                (->> (map -field (rest fields))
                      (into-array org.jooq.Field)))
        :else
-       (->> (map field* fields)
+       (->> (map -field fields)
             (into-array org.jooq.Field)
             (DSL/select))))))

@@ -458,7 +458,7 @@
 (defn group-by
   [q & fields]
   (defer
-    (->> (map (comp field* -unwrap) fields)
+    (->> (map (comp -field -unwrap) fields)
          (into-array org.jooq.GroupField)
          (.groupBy @q))))

@@ -484,7 +484,7 @@
   (defer
     (let [q (.forUpdate @q)]
       (if (seq fields)
-        (->> (map field* fields)
+        (->> (map -field fields)
              (into-array org.jooq.Field)
              (.of q))
         q))))
@@ -520,7 +520,7 @@
   (defer
     (if (= (count fields) 0)
       (.returning @t)
-      (.returning @t (->> (map field* fields)
+      (.returning @t (->> (map -field fields)
                           (into-array org.jooq.Field))))))

 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -580,8 +580,8 @@
 (defn values
   [& rows]
   (defer
-    (->> (into-array org.jooq.RowN rows)
-         (DSL/values))))
+    (-> (into-array org.jooq.RowN rows)
+        (DSL/values))))

 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; Insert statement
@@ -596,7 +596,7 @@
   [t values]
   (defer
     (-> (fn [acc [k v]]
-          (.set acc (field* k) (-unwrap v)))
+          (.set acc (-field k) (-unwrap v)))
         (reduce (-unwrap t) values)
         (.newRecord))))

@@ -616,7 +616,7 @@
    (defer
      (let [t (-unwrap t)]
        (reduce (fn [acc [k v]]
-                 (.set t (field* k) v))
+                 (.set t (-field k) v))
                t kv))))
   ([t k v]
    (defer
@@ -624,7 +624,7 @@
            t (-unwrap t)]
        (if (instance? org.jooq.Row k)
          (.set t k v)
-         (.set t (field* k) v))))))
+         (.set t (-field k) v))))))

 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; Delete statement
@@ -672,18 +672,18 @@
   [step name & [{:keys [default] :as opts}]]
   (defer
     (let [step (-unwrap step)
-          name (field* name)
+          name (-field name)
           type (make-datatype opts)
           step (.add step name type)]
         (if default
-           (.setDefault step (field* default))
+           (.setDefault step (-field default))
            step))))

 (defmethod add-column org.jooq.CreateTableAsStep
   [step name & [{:keys [default] :as opts}]]
   (defer
     (let [step (-unwrap step)
-          name (field* name)
+          name (-field name)
           type (make-datatype opts)
           type (.defaulted type true)]
       (.column step name type))))
@@ -692,7 +692,7 @@
   [step name & [{:keys [type default null length] :as opts}]]
   (defer
     (let [step (-> (-unwrap step)
-                   (.alter (field* name)))]
+                   (.alter (-field name)))]
       (when (clojure.core/and (clojure.core/or null length) (clojure.core/not type))
         (throw (IllegalArgumentException.
                 "For change null or length you should specify type.")))
@@ -707,7 +707,7 @@
   [step name & [type]]
   (defer
     (let [step (-> (-unwrap step)
-                   (.drop (field* name)))]
+                   (.drop (-field name)))]
       (case type
         :cascade (.cascade step)
         :restrict (.restrict step)
@@ -719,7 +719,7 @@
   [step table field & extrafields]
   (defer
     (let [fields (->> (concat [field] extrafields)
-                      (map (comp field* -unwrap))
+                      (map (comp -field -unwrap))
                       (into-array org.jooq.Field))]
       (.on (-unwrap step) (-table table) fields))))


When looking at item, if item is player, say what player is carrying as well as describing them.

--- src/isla/story.clj
+++ src/isla/story.clj
@@ -66,10 +66,10 @@
         (if (or (not= "at" (first arguments)) (nil? (second arguments)))
           (creturn this (t/look-instructions (-> player :room :items)))
           (let [name (second arguments)]
-            (if-let [thing (if (> (.indexOf ["myself" "me"] name) -1)
-                             player
-                             (item (:room player) name))]
-              (creturn this (:summary thing))
+            (if-let [description (if (> (.indexOf ["myself" "me"] name) -1)
+                                   (t/player-description player)
+                                   (:summary (item (:room player) name)))]
+              (creturn this description)
               (creturn this (t/look-not-here name))))))))

   (pick [this arguments-str]


don't try to send emails if no recipients

--- src/pc/ses.clj
+++ src/pc/ses.clj
@@ -14,21 +14,22 @@
   (let [re-fragments ["dwwoelfel" "danny.newidea" "@prcrsr.com" "@precursorapp.com"]]
     (re-pattern (str/join "|" re-fragments))))

-(defn filter-to [to-addresses]
+(defn filter-addresses [to-addresses]
   (if (profile/use-email-whitelist?)
     (filter #(re-find dev-whitelist-pattern %) to-addresses)
     to-addresses))

 (defn send-message [{:keys [from to cc bcc subject text html] :as props}]
   (amazonica.core/with-credential [access-key-id secret-access-key "us-west-2"]
-    (ses/send-email :destination (merge {:to-addresses (filter-to [to])
-                                         :bcc-addresses (concat (when (profile/bcc-audit-log?)
-                                                                  ["audit-log@precursorapp.com"])
-                                                                (when bcc [bcc]))}
-                                        (when cc
-                                          {:cc-addresses [cc]}))
-                    :source from
-                    :return-path "bounces@precursorapp.com"
-                    :message {:subject subject
-                              :body {:html html
-                                     :text text}})))
+    (when-let [to-addresses (seq (filter-to [to]))]
+      (ses/send-email :destination (merge {:to-addresses (filter-to [to])
+                                           :bcc-addresses (concat (when (profile/bcc-audit-log?)
+                                                                    ["audit-log@precursorapp.com"])
+                                                                  (when bcc [bcc]))}
+                                          (when cc
+                                            {:cc-addresses [cc]}))
+                      :source from
+                      :return-path "bounces@precursorapp.com"
+                      :message {:subject subject
+                                :body {:html html
+                                       :text text}}))))


wip, placement working

wip, placement working

--- src/qttt/game.cljs
+++ src/qttt/game.cljs
@@ -4,6 +4,8 @@

 (def num-cells 9)
 (def num-players 2)
+
+(def ^:dynamic *speculative* false)

 (comment
   ;; Game Data Structures
@@ -40,7 +42,9 @@
 (defn legal-spooky-mark?
   "Return true if a spooky mark can be placed on the given cell and subcell"
   [game cell subcell]
-  (nil? (get-in game [:board cell :entanglements subcell])))
+  (and
+    (not= cell (first (:pair game)))
+    (nil? (get-in game [:board cell :entanglements subcell]))))

 (defn check-collapses
   "Given a game, check if there are any collapses happening
@@ -59,10 +63,10 @@
         {:player (:player game)
          :turn (:turn game)
          :target pair-cell
-         :focus false})
+         :focus *speculative*})
       ;; update the entangled spooky mark
       (update-in [:board pair-cell :entanglements pair-subcell] assoc
-        :focus false
+        :focus *speculative*
         :target cell)
       ;; remove the pair tracker
       (dissoc :pair)
@@ -103,9 +107,10 @@
 (defn speculate
   "Make a play, but store the previous game state so the 'play' can be easily reverted"
   [game cell subcell]
-  (-> game
-    (play cell subcell)
-    (assoc :base game)))
+  (binding [*speculative* true]
+    (-> game
+      (play cell subcell)
+      (assoc :base game))))

 (defn unspeculate
   "Restore the previous game state (if there was one)."


Set displayName on component from :displayName metadata or js function obj.

--- src/quiescent.cljs
+++ src/quiescent.cljs
@@ -31,6 +31,9 @@
                                     (apply renderer
                                            (aget (.-props this) "value")
                                            (aget (.-props this) "statics")))))}
+                 (or (:displayName m) (not-empty (.-name renderer)))
+                 (q/set-prop! -displayName (or (:displayName m)
+                                               (not-empty (.-name renderer))))
                  (:componentWillMount m)
                  (q/set-prop! -componentWillMount (:componentWillMount m))
                  (:componentDidMount m)


Treat ctrl-c in line, since we can't interrupt jline's readLine

--- src/reply/core.clj
+++ src/reply/core.clj
@@ -31,7 +31,8 @@
       (.clear)))

 (defn handle-ctrl-c [signal]
-  (println "^C")
+  (print "^C")
+  (flush)
   (.interrupt main-thread)
   (clear-jline-buffer))


Write a fn test

Write a fn test

--- test/useful/fn.clj
+++ test/useful/fn.clj
@@ -1,4 +1,26 @@
 (ns useful.fn-test
   (:use clojure.test useful.fn))

+(deftest test-decorate
+  (is (= [[1 2] [2 3] [3 4]] (map (decorate inc) [1 2 3]))))

+(deftest test-annotate
+  (is (= [1 2] (annotate inc 1))))
+
+(deftest test-transform-if
+  (is (= [1 -2 3 -4] (map (transform-if even? -) [1 2 3 4]))))
+
+(deftest test-any
+  (is (= [0 2 3 4 6 8 9 10]
+         (filter (any #(zero? (rem % 2))
+                      #(zero? (rem % 3)))
+                 (range 11)))))
+
+(deftest test-all
+  (is (= [0 6]
+         (filter (all #(zero? (rem % 2))
+                      #(zero? (rem % 3)))
+                 (range 11)))))
+
+(deftest test-thrush
+  (is (= 5 (thrush 1 inc inc inc inc))))


[#531] Don't hardcode Keycloak token endpoint (with @jonase)

--- backend/src/akvo/lumen/import/flow.clj
+++ backend/src/akvo/lumen/import/flow.clj
@@ -35,8 +35,8 @@

 (defn access-token
   "Fetch a new access token using a refresh token"
-  [refresh-token]
-  (-> (http/post "https://kc.akvotest.org/auth/realms/akvo/protocol/openid-connect/token"
+  [token-endpoint refresh-token]
+  (-> (http/post token-endpoint
                  {:form-params {"client_id" "akvo-lumen"
                                 "refresh_token" refresh-token
                                 "grant_type" "refresh_token"}
@@ -45,8 +45,8 @@
       :access_token))

 (defn offline-token
-  [refresh-token]
-  (-> (http/post "https://kc.akvotest.org/auth/realms/akvo/protocol/openid-connect/token"
+  [token-endpoint refresh-token]
+  (-> (http/post token-endpoint
                  {:form-params {"client_id" "akvo-lumen"
                                 "refresh_token" refresh-token
                                 "scope" "offline_access"
@@ -56,52 +56,52 @@
       :refresh_token))

 (defn flow-api-headers
-  [refresh-token]
-  {"Authorization" (format "Bearer %s" (access-token refresh-token))
+  [token-endpoint refresh-token]
+  {"Authorization" (format "Bearer %s" (access-token token-endpoint refresh-token))
    "User-Agent" "lumen"
    "Accept" "application/vnd.akvo.flow.v2+json"
    "X-Akvo-Email" "akvo.flow.user.test2@gmail.com"})

 (defn survey-definition
-  [api-root access-token instance survey-id]
+  [api-root headers-fn instance survey-id]
   (-> (format "%s/orgs/%s/surveys/%s"
               api-root instance survey-id)
-      (http/get {:headers (flow-api-headers access-token)
+      (http/get {:headers (headers-fn)
                  :as :json})
       :body))

-(defn form-instances* [refresh-token url]
+(defn form-instances* [headers-fn url]
   (let [response (-> url
-                     (http/get {:headers (flow-api-headers refresh-token)
+                     (http/get {:headers (headers-fn)
                                 :as :json-string-keys})
                      :body)]
     (lazy-cat (get response "formInstances")
               (when-let [url (get response "cursor")]
-                (form-instances* refresh-token url)))))
+                (form-instances* headers-fn url)))))

 (defn form-instances
   "Returns a lazy sequence of form instances"
-  [refresh-token form]
+  [headers-fn form]
   (let [initial-url (str (:formInstancesUrl form) "?pageSize=300")]
-    (form-instances* refresh-token initial-url)))
+    (form-instances* headers-fn initial-url)))

 (defn data-points*
-  [access-token url]
+  [headers-fn url]
   (-> url
-      (http/get {:headers (flow-api-headers access-token)
+      (http/get {:headers (headers-fn)
                  :as :json-string-keys})
       :body))

 (defn data-points
   "Returns all survey data points"
-  [refresh-token survey]
+  [headers-fn survey]
   (loop [all-data-points []
-         response (data-points* (access-token refresh-token)
+         response (data-points* headers-fn
                                 (str (:dataPointsUrl survey)
                                      "?pageSize=300"))]
     (if-let [url (get response "cursor")]
       (recur (into all-data-points (get response "dataPoints"))
-             (data-points* (access-token refresh-token) url))
+             (data-points* headers-fn url))
       all-data-points)))

 (defn question-type->lumen-type
@@ -214,9 +214,9 @@

 (defn form-data
   "Returns a lazy sequence of form data, ready to be inserted as a lumen dataset"
-  [refresh-token survey form-id]
+  [headers-fn survey form-id]
   (let [form (form survey form-id)
-        data-points (index-by "id" (data-points refresh-token survey))]
+        data-points (index-by "id" (data-points headers-fn survey))]
     (map (fn [form-instance]
            (let [data-point-id (get form-instance "dataPointId")]
              (assoc (response-data form (get form-instance "responses"))
@@ -226,27 +226,31 @@
                     "submitter" (get form-instance "submitter")
                     "submitted_at" (some-> (get form-instance "submissionDate")
                                            sql-timestamp))))
-         (form-instances refresh-token form))))
-
-(defn create-dataset [tenant-conn refresh-token table-name survey form-id]
+         (form-instances headers-fn form))))
+
+(defn create-dataset [tenant-conn headers-fn table-name survey form-id]
   (let [columns (dataset-columns (form survey form-id))
-        data-rows (form-data refresh-token survey form-id)]
+        data-rows (form-data headers-fn survey form-id)]
     (jdbc/execute! tenant-conn [(create-data-table table-name columns)])
     (doseq [data (partition-all 300 data-rows)]
       (jdbc/insert-multi! tenant-conn table-name data))
     columns))

 (defmethod import/make-dataset-data-table "AKVO_FLOW"
-  [tenant-conn {:keys [flow-api-root]} table-name {:strs [instance surveyId formId refreshToken]}]
+  [tenant-conn {:keys [flow-api-root keycloak-realm keycloak-url]} table-name {:strs [instance surveyId formId refreshToken]}]
   (try
-    (let [refresh-token (offline-token refreshToken)]
+    (let [token-endpoint (format "%s/realms/%s/protocol/openid-connect/token"
+                                 keycloak-url
+                                 keycloak-realm)
+          refresh-token (offline-token token-endpoint refreshToken)
+          headers-fn #(flow-api-headers token-endpoint refresh-token)]
       {:success? true
        :columns (let [survey (survey-definition flow-api-root
-                                                (access-token refresh-token)
+                                                headers-fn
                                                 instance
                                                 surveyId)]
                   (create-dataset tenant-conn
-                                  refresh-token
+                                  headers-fn
                                   table-name
                                   survey
                                   formId))})


dont include react

dont include react

--- src/show/core.cljs
+++ src/show/core.cljs
@@ -1,7 +1,6 @@
 (ns show.core
   (:refer-clojure :exclude [reset! update! assoc! dissoc!])
-  (:require react
-            [clojure.string])
+  (:require [clojure.string])
   (:import [goog.ui IdGenerator]))

 (enable-console-print!)


auto retry shouldnt be marked

auto retry shouldnt be marked

--- src/spq/server.clj
+++ src/spq/server.clj
@@ -171,7 +171,7 @@
           (when (seq to-retry)
             (timbre/info "periodic task found" (count to-retry) "tasks to retry")
             (doseq [[id val] to-retry]
-              (lib/retry! queue (:task val))
+              (lib/retry! queue (:task val) :dont-mark-retry)
               (swap! state update-in [:tasks] dissoc id))))
         (time/in (conf :server :period-millis) #(periodic-task stop-periodic-task))
         (catch Throwable ex


whitespace

whitespace

--- figwheel-repl/src/figwheel/repl.cljc
+++ figwheel-repl/src/figwheel/repl.cljc
@@ -393,12 +393,15 @@
 ;; -----------------------------------------------------------

 (defn http-get [url]
-  (Promise. (fn [succ err]
-              (xhrio/send url (fn [e]
-                                (let [xhr (gobj/get e "target")]
-                                  (if (.isSuccess xhr)
-                                    (succ (.getResponseJson xhr))
-                                    (err xhr))))))))
+  (Promise.
+   (fn [succ err]
+     (xhrio/send
+      url
+      (fn [e]
+        (let [xhr (gobj/get e "target")]
+          (if (.isSuccess xhr)
+            (succ (.getResponseJson xhr))
+            (err xhr))))))))

 (declare http-connect http-connect*)


add docstrings for parse-day and parse-month

--- src/tick/core.cljc
+++ src/tick/core.cljc
@@ -119,7 +119,15 @@
   ([^LocalDate date]
    (p/at date cljc.java-time.local-time/noon)))

-(defn parse-day [input]
+(defn parse-day
+  "en locale specific and borderline deprecated.
+  consider writing your own regex or use a formatter. For example:
+
+  (-> (t/formatter \"EEE\")
+      (cljc.java-time.format.date-time-formatter/parse \"Tue\")
+      (cljc.java-time.day-of-week/from))
+  "
+  [input]
   (condp re-matches (str/lower-case input)
     #"^(mon)(day)?$" cljc.java-time.day-of-week/monday
     #"^(tue)(s|sday)?$" cljc.java-time.day-of-week/tuesday
@@ -130,7 +138,15 @@
     #"^(sun)(day)?$" cljc.java-time.day-of-week/sunday
     nil))

-(defn parse-month [input]
+(defn parse-month
+  "en locale specific and borderline deprecated. Consider writing your
+   own regex or use a formatter. For example:
+
+   (-> (t/formatter \"MMM\")
+       (cljc.java-time.format.date-time-formatter/parse \"Jan\")
+       (cljc.java-time.month/from))
+   "
+  [input]
   (condp re-matches (str/lower-case input)
     #"^(jan)(uary)?$" cljc.java-time.month/january
     #"^(feb)(ruary)?$" cljc.java-time.month/february


whitespace

whitespace

--- src-cljs/frontend/components/hud.cljs
+++ src-cljs/frontend/components/hud.cljs
@@ -259,17 +259,17 @@
                      (volume-icon (get-in sub [:recording :media-stream-volume] 0) (name self-color))]])
                  [:div.viewer-toggles
                   [:a.viewer-toggle {:on-click #(do
-                                                (if can-edit?
-                                                  (om/set-state! owner :editing-name? true)
-                                                  (cast! :overlay-username-toggled))
-                                                (.stopPropagation %))
-                                   :role "button"
-                                   :title "Change your display name."}
+                                                  (if can-edit?
+                                                    (om/set-state! owner :editing-name? true)
+                                                    (cast! :overlay-username-toggled))
+                                                  (.stopPropagation %))
+                                     :role "button"
+                                     :title "Change your display name."}
                    (common/icon :pencil)]
                   (when config/subdomain
                     [:a.viewer-toggle {:on-click #(cast! :recording-toggled)
-                                     :role "button"
-                                     :title "Share your audio with everyone in the doc"}
+                                       :role "button"
+                                       :title "Share your audio with everyone in the doc"}
                      (common/icon (if (:recording sub) :mic-off :mic))])]])
               (for [[id {:keys [show-mouse? color cust-name hide-in-list? stream-url] :as sub}] (dissoc (get-in app [:subscribers :info]) client-id)
                     :when (not hide-in-list?)


pings should match target

pings should match target

--- src-cljs/tranjlator/master_view.cljs
+++ src-cljs/tranjlator/master_view.cljs
@@ -114,7 +114,7 @@
                    (= :user-join topic) (om/transact! app :users (fn [col] (conj col (:user-name msg []))))
                    (= :user-part topic) (om/transact! app :users (fn [col] (remove (fn [x] (= x (:user-name msg))) col)))
                    (= (keyword lang) topic) (om/transact! app :translated (fn [col] (conj col msg)))
-                   (= :ping topic) (when (= (:user-name msg) (:user-name @app)) (ping))
+                   (= :ping topic) (when (= (:target msg) (:user-name @app)) (ping))
                    (= :error topic) (do (let [name (:user-name @app)]
                                           (put! socket-ctrl "Doh")
                                           (om/update! app :sender-ch (chan))


use more idiomatic map lookup by keyword

--- clients/clojure/src/samsara/client.clj
+++ clients/clojure/src/samsara/client.clj
@@ -79,7 +79,7 @@
 (defn- enrich-event [event]
   "Enriches the event with default properties etc."
   (conj event (get-event-headers) {:timestamp (System/currentTimeMillis)
-                                   :sourceId (@samsara-config :sourceId)}))
+                                   :sourceId (:sourceId @samsara-config)}))

 (defn- prepare-event [event]
   "Enriches and validates the event and throws an Exception if validation fails."
@@ -89,7 +89,7 @@

 (defn- send-events [events]
   "Send events to samsara api"
-  (let [{:keys [status error] :as resp} @(http/post (str ((get-samsara-config) :url) "/events")
+  (let [{:keys [status error] :as resp} @(http/post (str (:url (get-samsara-config)) "/events")
                                                     {:timeout 500 ;;ms
                                                      :headers {"Content-Type" "application/json"
                                                                "X-Samsara-publishedTimestamp" (str (System/currentTimeMillis))}
@@ -131,9 +131,9 @@
 (defn !init! []
   "Initializes the ring buffer and the timer."
   (let [config (get-samsara-config)
-        max-buffer-size (config :max-buffer-size)
+        max-buffer-size (:max-buffer-size config)
         did-set (compare-and-set! !buffer! nil (ring-buffer max-buffer-size))
-        publish-interval (config :publish-interval)
+        publish-interval (:publish-interval config)
         times (periodic-seq (t/now) (-> publish-interval t/seconds))]

     (when did-set


Remove unneeded call to `format`

Remove unneeded call to `format`

--- src/afrey/boot_asset_fingerprint.clj
+++ src/afrey/boot_asset_fingerprint.clj
@@ -45,7 +45,7 @@
                       output-path (-> (io/file tmp-dir path) .getPath)
                       input-root (path->parent-path path)]]
           (do
-            (util/info (format "Fingerprinting %s...\n" path))
+            (util/info "Fingerprinting %s...\n" path)
             (pod/with-eval-in worker-pod
               (afrey.boot-asset-fingerprint.impl/fingerprint
                 ~{:input-path  input-path


Added comments to all defs in db-spec module

--- src/zg/db_spec.clj
+++ src/zg/db_spec.clj
@@ -7,13 +7,14 @@
 ;  http://www.eclipse.org/legal/epl-v10.html
 ;
 ;  Contributors:
-;      Pavel Tisnovsky
+;      Pavel Tisnovsky
 ;

 (ns zg.db-spec
     "Namespace that contains configuration of all JDBC sources.")

 (def zg-db
+    "Specification for SQLite database used for storing all dictionaries."
     {:classname   "org.sqlite.JDBC"
      :subprotocol "sqlite"
      :subname     "zg.db"


fix indentation

fix indentation

git-svn-id: 03a8048b5ee8463be5048a3801110fb50f378627@8843 d0ab736e-dc22-4aeb-8dc9-08def0aa14fd

--- acqEngine/src/org/micromanager/sequence_generator.clj
+++ acqEngine/src/org/micromanager/sequence_generator.clj
@@ -406,15 +406,15 @@
            (zero? (count runnables))
            (not (first custom-intervals-ms))
            (> default-exposure interval-ms))
-             (let [triggers
-                   {:properties (select-triggerable-sequences property-sequences)}]
-               (if (< 1 num-positions)
-                 (generate-multiposition-bursts
-                   positions numFrames use-autofocus channels
-                   default-exposure triggers)
-               (generate-simple-burst-sequence
-                 numFrames use-autofocus channels
-                 default-exposure triggers 0)))
+      (let [triggers
+            {:properties (select-triggerable-sequences property-sequences)}]
+        (if (< 1 num-positions)
+          (generate-multiposition-bursts
+            positions numFrames use-autofocus channels
+            default-exposure triggers)
+          (generate-simple-burst-sequence
+            numFrames use-autofocus channels
+            default-exposure triggers 0)))
       :else
         (generate-default-acq-sequence settings runnables))))


Refactor `set-document-location-hash` function

And change the steps taken to generate a new url hash, from sorting by
the module info maps to sorting by string representation of the module
info maps.

This patch is done in the hope that we can reuse the newly created
functions, such as `sort-mod-info-url-seq`.

Signed-off-by: Pang Yan Han <22594c345857f664c61cd411f607c4d40a9d4af9@gmail.com>

--- src/cljs/cljs_nusmods/timetable.cljs
+++ src/cljs/cljs_nusmods/timetable.cljs
@@ -74,6 +74,66 @@
   [moduleCode]
   (let [containsModule (contains? ModulesSelected moduleCode)]
     containsModule))
+
+(def ^{:doc     "Converts a short form lesson type string to its long form"
+       :private true}
+  Lesson-Type-Short-To-Long-Form
+  {"DL"  "DESIGN LECTURE",
+   "L"   "LECTURE",
+   "LAB" "LABORATORY",
+   "PL"  "PACKAGED LECTURE",
+   "PT"  "PACKAGED TUTORIAL",
+   "R"   "RECITATION",
+   "SEM" "SEMINAR-STYLE MODULE CLASS",
+   "ST"  "SECTIONAL TEACHING",
+   "T"   "TUTORIAL",
+   "T2"  "TUTORIAL TYPE 2",
+   "T3"  "TUTORIAL TYPE 3"})
+
+(def ^{:doc     "Converts a long form lesson type string to its short form"
+       :private true}
+  Lesson-Type-Long-To-Short-Form
+  {"DESIGN LECTURE"             "DL",
+   "LECTURE"                    "L",
+   "LABORATORY"                 "LAB",
+   "PACKAGED LECTURE"           "PL",
+   "PACKAGED TUTORIAL"          "PT",
+   "RECITATION"                 "R",
+   "SEMINAR-STYLE MODULE CLASS" "SEM",
+   "SECTIONAL TEACHING"         "ST",
+   "TUTORIAL"                   "T",
+   "TUTORIAL TYPE 2"            "T2",
+   "TUTORIAL TYPE 3"            "T3"
+   })
+
+(defn- sort-mod-info-url-seq
+  "Sorts a sequence of mod info url strings, eg. CS1234_L=1"
+  [modInfoUrlSeq]
+  (sort (fn [modInfoUrlA modInfoUrlB]
+          (< modInfoUrlA modInfoUrlB))
+        modInfoUrlSeq))
+
+(defn- mod-info-url-seq-to-url-hash
+  "Converts a sequence of mod info url strings (eg. CS1234_L=1) to a url hash"
+  [modInfoUrlSeq]
+  (clojure.string/join "&" (sort-mod-info-url-seq modInfoUrlSeq)))
+
+(defn- mod-info-to-url-repr
+  "Converts a module info map to a url representation"
+  [modInfo]
+  (str (:moduleCode modInfo) "_"
+       (Lesson-Type-Long-To-Short-Form (:lessonType modInfo))
+       "=" (:lessonGroup modInfo)))
+
+(defn- set-document-location-hash-from-module-info-seq
+  "Sets document.location.hash to a canonical representation.
+
+   NOTE: This function should only be called by the
+         `add-module-lesson-groups-from-url-hash` function"
+  [moduleInfoSeq]
+  (let [moduleInfoUrlSeq (map mod-info-to-url-repr moduleInfoSeq)]
+    (aset (aget js/document "location") "hash"
+          (mod-info-url-seq-to-url-hash moduleInfoUrlSeq))))

 (def ^{:doc "Vector of <tBody> objects representing the days of the timetable
              in the Timetable Builder page"
@@ -325,37 +385,6 @@
                                    bgColorCssClass
                                    ModulesMap)))))

-(def ^{:doc     "Converts a short form lesson type string to its long form"
-       :private true}
-  Lesson-Type-Short-To-Long-Form
-  {"DL"  "DESIGN LECTURE",
-   "L"   "LECTURE",
-   "LAB" "LABORATORY",
-   "PL"  "PACKAGED LECTURE",
-   "PT"  "PACKAGED TUTORIAL",
-   "R"   "RECITATION",
-   "SEM" "SEMINAR-STYLE MODULE CLASS",
-   "ST"  "SECTIONAL TEACHING",
-   "T"   "TUTORIAL",
-   "T2"  "TUTORIAL TYPE 2",
-   "T3"  "TUTORIAL TYPE 3"})
-
-(def ^{:doc     "Converts a long form lesson type string to its short form"
-       :private true}
-  Lesson-Type-Long-To-Short-Form
-  {"DESIGN LECTURE"             "DL",
-   "LECTURE"                    "L",
-   "LABORATORY"                 "LAB",
-   "PACKAGED LECTURE"           "PL",
-   "PACKAGED TUTORIAL"          "PT",
-   "RECITATION"                 "R",
-   "SEMINAR-STYLE MODULE CLASS" "SEM",
-   "SECTIONAL TEACHING"         "ST",
-   "TUTORIAL"                   "T",
-   "TUTORIAL TYPE 2"            "T2",
-   "TUTORIAL TYPE 3"            "T3"
-   })
-
 (defn- get-module-info-from-url-hash-module-info
   "Computes the final module info sequence for modules added via the url hash
    on page initialization.
@@ -436,30 +465,6 @@
                          :lessonGroup lessonGroup}))
                     (keys lessonTypesMap))))
            moduleCodesSeq))))
-
-(defn- set-document-location-hash
-  "Sets document.location.hash to a canonical representation.
-
-   NOTE: This function should only be called by the
-         `add-module-lesson-groups-from-url-hash` function"
-  [moduleInfoSeq]
-  (let [sortedModInfo (sort (fn [modInfoA modInfoB]
-                              (let [moduleCodeA (:moduleCode modInfoA)
-                                    moduleCodeB (:moduleCode modInfoB)]
-                                (if (not= moduleCodeA moduleCodeB)
-                                    (< moduleCodeA moduleCodeB)
-                                    (< (:lessonType modInfoA)
-                                       (:lessonType modInfoB)))))
-                            moduleInfoSeq)]
-    (aset (aget js/document "location") "hash"
-          (clojure.string/join "&"
-            (map (fn [modInfo]
-                   (str (:moduleCode modInfo)
-                        "_"
-                        (Lesson-Type-Long-To-Short-Form (:lessonType modInfo))
-                        "="
-                        (:lessonGroup modInfo)))
-                 sortedModInfo)))))

 (defn add-module-lesson-groups-from-url-hash
   "Adds the module lesson groups available in the url hash. Erroneous lesson
@@ -529,7 +534,7 @@
                                  bgColorCssClass)))

     ; Update url hash
-    (set-document-location-hash moduleInfoFinal)))
+    (set-document-location-hash-from-module-info-seq moduleInfoFinal)))

 (defn remove-module
   "Removes a module from the timetable.


perform pre-save actions before updating affected transaction items

--- src/clj_money/models/transactions.clj
+++ src/clj_money/models/transactions.clj
@@ -161,8 +161,10 @@
                           (let [new-index (+ 1 index)
                                 polarized-amount (accounts/polarize-amount storage-spec item)
                                 new-balance (+ balance polarized-amount)]
-                            (update-item storage-spec (assoc item :index new-index
-                                                             :balance new-balance))
+                            (update-item storage-spec (-> item
+                                                          (assoc :index new-index
+                                                                 :balance new-balance)
+                                                          before-save-item))
                             {:index new-index
                              :balance new-balance}))
                         last-item


show search field to search within stories

--- src/cljs/iwaswhere_web/ui/search.cljs
+++ src/cljs/iwaswhere_web/ui/search.cljs
@@ -52,8 +52,7 @@
             query @query
             starred (:starred query)
             star-fn #(put-fn [:search/update (update-in query [:starred] not)])]
-        (when (and (not (:briefing query))
-                   (not (:story query)))
+        (when-not (:briefing query)
           [:div.search
            [tags-view query]
            [:div.search-row


Small fix

Small fix

--- src/cljs/salava/gallery/ui/block.cljs
+++ src/cljs/salava/gallery/ui/block.cljs
@@ -5,7 +5,8 @@
             [salava.core.i18n :refer [t]]
             [reagent.core :refer [atom cursor]]
             [salava.core.ui.page-grid :refer [page-grid-element]]
-            [salava.user.ui.helper :refer [profile-link-inline-modal]]))
+            [salava.user.ui.helper :refer [profile-link-inline-modal]]
+            [reagent.session :as session]))

 (defn init-grid [kind state]
   (ajax/GET
@@ -101,32 +102,33 @@
   (let [{:keys [gallery_id id data]} params
         state (or (atom data) (atom {}))
         expanded (atom false)]
-    (when (empty? @state)(ajax/GET
-                          (path-for (str "/obpv1/gallery/recipients/" gallery_id))
-                          {;:params {:galleryid gallery_id}
-                           :handler (fn [data]
-                                      (reset! state data))}))
-    (fn []
-     (let [{:keys [public_users private_user_count all_recipients_count]} @state
-            icon-class (if @expanded "fa-chevron-circle-down" "fa-chevron-circle-right")
-            title (if @expanded (t :core/Clicktocollapse) (t :core/Clicktoexpand))]
-      [:div.row
-       [:div.col-md-12
-        [:div.panel.expandable-block ;{:style {:padding "unset"}}
-         [:div.panel-heading {:style {:padding "unset"}}
-          [:h2.uppercase-header (str (t :gallery/recipients) ": " all_recipients_count)]
-          [:a {:href "#" :on-click #(do (.preventDefault %)
-                                        (if @expanded (reset! expanded false) (reset! expanded true)))}
-            ;[:h2.uppercase-header (str (t :gallery/Allrecipients) ": " all_recipients_count)]
-            [:i.fa.fa-lg.panel-status-icon.in-badge {:class icon-class :title title}]]]
-         (when @expanded
-           [:div.panel-body {:style {:padding "unset"}}
-            [:div
-             (into [:div]
-                   (for [user public_users
-                         :let [{:keys [id first_name last_name profile_picture]} user]]
-                     (profile-link-inline-modal id first_name last_name profile_picture)))
-             (when (> private_user_count 0)
-               (if (> (count public_users) 0)
-                 [:span "... " (t :core/and) " " private_user_count " " (t :core/more)]
-                 [:span private_user_count " " (if (> private_user_count 1) (t :gallery/recipients) (t :gallery/recipient))]))]])]]]))))
+    (when (session/get :user)
+      (when (empty? @state)(ajax/GET
+                            (path-for (str "/obpv1/gallery/recipients/" gallery_id))
+                            {;:params {:galleryid gallery_id}
+                             :handler (fn [data]
+                                        (reset! state data))}))
+      (fn []
+       (let [{:keys [public_users private_user_count all_recipients_count]} @state
+              icon-class (if @expanded "fa-chevron-circle-down" "fa-chevron-circle-right")
+              title (if @expanded (t :core/Clicktocollapse) (t :core/Clicktoexpand))]
+        [:div.row
+         [:div.col-md-12
+          [:div.panel.expandable-block ;{:style {:padding "unset"}}
+           [:div.panel-heading {:style {:padding "unset"}}
+            [:h2.uppercase-header (str (t :gallery/recipients) ": " all_recipients_count)]
+            [:a {:href "#" :on-click #(do (.preventDefault %)
+                                          (if @expanded (reset! expanded false) (reset! expanded true)))}
+              ;[:h2.uppercase-header (str (t :gallery/Allrecipients) ": " all_recipients_count)]
+              [:i.fa.fa-lg.panel-status-icon.in-badge {:class icon-class :title title}]]]
+           (when @expanded
+             [:div.panel-body {:style {:padding "unset"}}
+              [:div
+               (into [:div]
+                     (for [user public_users
+                           :let [{:keys [id first_name last_name profile_picture]} user]]
+                       (profile-link-inline-modal id first_name last_name profile_picture)))
+               (when (> private_user_count 0)
+                 (if (> (count public_users) 0)
+                   [:span "... " (t :core/and) " " private_user_count " " (t :core/more)]
+                   [:span private_user_count " " (if (> private_user_count 1) (t :gallery/recipients) (t :gallery/recipient))]))]])]]])))))


Use not-fully-qualified keywords in defmulti and s/multispec

So current db values don't need any adaptation

--- backend/specs/akvo/lumen/specs/transformation.clj
+++ backend/specs/akvo/lumen/specs/transformation.clj
@@ -63,16 +63,15 @@

 (s/def ::type #{:transformation :undo})

-
-(defmulti command-spec ::type)
+(defmulti command-spec :type)

 (defmethod command-spec :undo [_]
-  (s/keys :req [::type]))
+  (s/keys :req-un [::type]))

 (defmethod command-spec :transformation [_]
-  (s/keys :req [::type]))
+  (s/keys :req-un [::type]))

-(s/def ::command (s/multi-spec command-spec ::type))
+(s/def ::command (s/multi-spec command-spec :type))

 (lumen.s/sample ::command)

@@ -98,10 +97,10 @@
 				    :core/trim
 				    :core/trim-doublespace})

-(defmulti op-spec ::transformation.engine/op)
+(defmulti op-spec :op)

 (s/def ::transformation.engine/op-spec
-  (s/multi-spec op-spec ::transformation.engine/op))
+  (s/multi-spec op-spec :op))

 (create-ns  'akvo.lumen.specs.transformation.delete-column)
 (alias 'transformation.delete-column 'akvo.lumen.specs.transformation.delete-column)
@@ -112,6 +111,7 @@
 (defmethod op-spec :core/delete-column  [_]
   (s/keys
    :req-un [::transformation.delete-column/args
-	    ::transformation.engine/onError]))
+	    ::transformation.engine/onError
+            ::transformation.engine/op]))

-(lumen.s/sample ::transformation.engine/op-spec 10)
+(lumen.s/sample ::transformation.engine/op-spec)


[#1949]Auth vis-id with middleware & Auth "DEL /visualisations/:id"

--- backend/src/akvo/lumen/endpoint/visualisation.clj
+++ backend/src/akvo/lumen/endpoint/visualisation.clj
@@ -50,30 +50,36 @@
                                       (let [{:strs [rasterId spec]} body]
                                         (maps/create-raster (p/connection tenant-manager tenant) windshaft-url rasterId)))}}]]
    ;; todo: fix path routing inconsistency here
-   ["/:id" ["" {:get {:parameters {:path-params {:id string?}}
-                      :handler (fn [{tenant :tenant
-                                     auth-service :auth-service
-                                     {:keys [id]} :path-params}]
-                                 (if (p/allow? auth-service (l.auth/ids ::visualisation.s/id id))
-                                   (if-let [res (visualisation/fetch (p/connection tenant-manager tenant) id)]
-                                     (let [ids (l.auth/ids ::visualisation.s/visualisation res)]
-                                       (if (p/allow? auth-service ids)
-                                        (lib/ok res)
-                                        (lib/not-authorized ids)))
-                                     (lib/not-found {:error "Not found"}))
-                                   (lib/not-authorized {:id id})))}
-                  :put {:parameters {:body map?
-                                     :path-params {:id string?}}
-                        :handler (fn [{tenant :tenant
-                                       jwt-claims :jwt-claims
-                                       {:keys [id]} :path-params
-                                       body :body}]
-                                   (let [vis-payload (w/keywordize-keys body)]
-                                     (visualisation/upsert (p/connection tenant-manager tenant) vis-payload jwt-claims)))}
-                  :delete {:parameters {:path-params {:id string?}}
-                           :handler (fn [{tenant :tenant
-                                          {:keys [id]} :path-params}]
-                                      (visualisation/delete (p/connection tenant-manager tenant) id))}}]]])
+   ["/:id"
+    {:middleware [(fn [handler]
+                    (fn [{{:keys [id]} :path-params
+                          auth-service :auth-service
+                          :as req}]
+                      (if (p/allow? auth-service (l.auth/ids ::visualisation.s/id id))
+                        (handler req)
+                        (lib/not-authorized {:id id}))))]}
+    ["" {:get {:parameters {:path-params {:id string?}}
+               :handler (fn [{tenant :tenant
+                              auth-service :auth-service
+                              {:keys [id]} :path-params}]
+                          (if-let [res (visualisation/fetch (p/connection tenant-manager tenant) id)]
+                            (let [ids (l.auth/ids ::visualisation.s/visualisation res)]
+                              (if (p/allow? auth-service ids)
+                                (lib/ok res)
+                                (lib/not-authorized ids)))
+                            (lib/not-found {:error "Not found"})))}
+         :put {:parameters {:body map?
+                            :path-params {:id string?}}
+               :handler (fn [{tenant :tenant
+                              jwt-claims :jwt-claims
+                              {:keys [id]} :path-params
+                              body :body}]
+                          (let [vis-payload (w/keywordize-keys body)]
+                            (visualisation/upsert (p/connection tenant-manager tenant) vis-payload jwt-claims)))}
+         :delete {:parameters {:path-params {:id string?}}
+                  :handler (fn [{tenant :tenant
+                                 {:keys [id]} :path-params}]
+                             (visualisation/delete (p/connection tenant-manager tenant) id))}}]]])

 (defmethod ig/init-key :akvo.lumen.endpoint.visualisation/visualisation  [_ opts]
   (routes opts))


match current state first, then event type.

--- main/clojure/src/org/zproto/hydra_server.clj
+++ main/clojure/src/org/zproto/hydra_server.clj
@@ -6,12 +6,12 @@
 (alter-var-root #'*out* (constantly *out*))

 (defprotocol HydraServer
-  (hello    [this routing-id])
-  (get-tags [this routing-id])
-  (get-tag  [this routing-id tag])
-  (get-post [this routing-id post-id])
-  (goodbye  [this routing-id])
-  (invalid  [this routing-id]))
+  (hello    [this routing-id msg])
+  (get-tags [this routing-id msg])
+  (get-tag  [this routing-id msg])
+  (get-post [this routing-id msg])
+  (goodbye  [this routing-id msg])
+  (invalid  [this routing-id msg]))

 (defprotocol HydraServerBackend
   (get-latest-post [this])
@@ -38,60 +38,56 @@

 (defrecord Server [socket state backend]
   HydraServer
-  (hello [this routing-id]
-    (case (get @state routing-id)
-      :start (let [post-id (get-latest-post backend)]
-               (msg/hello-ok socket routing-id post-id)
-               (next-state state routing-id :start :connected))
+  (hello [this routing-id msg]
+    (let [post-id (get-latest-post backend)]
+      (msg/hello-ok socket routing-id post-id)
+      (next-state state routing-id :start :connected)))

-      (invalid this routing-id)))
+  (get-tags [this routing-id msg]
+    (let [tags (get-all-tags backend)]
+      (msg/get-tags-ok socket routing-id tags)))

-  (get-tags [this routing-id]
-    (case (get @state routing-id)
-      :connected (let [tags (get-all-tags backend)]
-                   (msg/get-tags-ok socket routing-id tags))
+  (get-tag [this routing-id msg]
+    (if-let [post-id (get-single-tag backend (.tag ^HydraMsg msg))]
+      (msg/get-tag-ok socket routing-id (.tag ^HydraMsg msg) post-id)
+      (msg/failed socket routing-id (format "no post for tag %s" (.tag ^HydraMsg msg)))))

-      (invalid this routing-id)))
+  (get-post [this routing-id msg]
+    (if-let [post-data (get-single-post backend (.post_id ^HydraMsg msg))]
+      (apply msg/get-post-ok socket routing-id post-data)
+      (msg/failed socket
+                  routing-id
+                  (format "post not found: %s" (.post_id ^HydraMsg msg)))))

-  (get-tag [this routing-id tag]
-    (case (get @state routing-id)
-      :connected (if-let [post-id (get-single-tag backend tag)]
-                   (msg/get-tag-ok socket routing-id tag post-id)
-                   (msg/failed socket routing-id (format "no post for tag %s" tag)))
-      (invalid this routing-id)))
-
-  (get-post [this routing-id post-id]
-    (case (get @state routing-id)
-      :connected (if-let [post-data (get-single-post backend post-id)]
-                   (apply msg/get-post-ok socket routing-id post-data)
-                   (msg/failed socket
-                               routing-id
-                               (format "post not found: %s" post-id)))
-
-      (invalid this routing-id)))
-
-  (invalid [this routing-id]
+  (invalid [this routing-id msg]
     (msg/invalid socket routing-id))

-  (goodbye [this routing-id]
-    (case (get @state routing-id)
-      :connected  (msg/goodbye-ok socket routing-id)
-      (invalid this routing-id))))
+  (goodbye [this routing-id msg]
+    (msg/goodbye-ok socket routing-id)))

+
+(def state-events
+  {:start {HydraMsg/HELLO hello
+           :*       invalid}
+   :connected {HydraMsg/GET_TAGS get-tags
+               HydraMsg/GET_TAG  get-tag
+               HydraMsg/GET_POST get-post
+               HydraMsg/GOODBYE  goodbye
+               :* invalid}})
+
+(def select-handler
+  (memoize
+   (fn [state event-id]
+     (or (get-in state-events [state event-id])
+         (get-in state-events [state :*])))))

 (defn match-msg
   [{:keys [state] :as server} ^HydraMsg msg]
   (let [id (.id msg)
-        routing-id (.routingId msg)]
-    (swap! state maybe-setup-session routing-id)
-    (cond
-     (= id HydraMsg/HELLO)    (hello    server routing-id)
-     (= id HydraMsg/GET_TAGS) (get-tags server routing-id)
-     (= id HydraMsg/GET_TAG)  (get-tag  server routing-id (.tag msg))
-     (= id HydraMsg/GET_POST) (get-post server routing-id (.post_id msg))
-     (= id HydraMsg/GOODBYE)  (goodbye  server routing-id)
-
-     :default                 (invalid  server routing-id))))
+        routing-id (.routingId msg)
+        initialized-state (swap! state maybe-setup-session routing-id)]
+    (let [handler (select-handler (get initialized-state routing-id) id)]
+      (handler server routing-id msg))))

 (defn server-loop
   [socket backend]


Prepare user-friendly samples #15 - get rid of :use, cleanup

--- src/flatgui/inputchannels/awtbase.clj
+++ src/flatgui/inputchannels/awtbase.clj
@@ -14,5 +14,5 @@

 (defn modifiers [event] (.getModifiersEx event))

-(definputparser with-shift? java.awt.event.InputEvent (> (bit-and (modifiers repaint-reason) InputEvent/SHIFT_DOWN_MASK) 0))
-(definputparser with-ctrl? java.awt.event.InputEvent (> (bit-and (modifiers repaint-reason) InputEvent/CTRL_DOWN_MASK) 0))+(definputparser with-shift? InputEvent (> (bit-and (modifiers repaint-reason) InputEvent/SHIFT_DOWN_MASK) 0))
+(definputparser with-ctrl? InputEvent (> (bit-and (modifiers repaint-reason) InputEvent/CTRL_DOWN_MASK) 0))


#18 fix pagination on post pages and index pages

--- src/kalar_plugins/templates/page.clj
+++ src/kalar_plugins/templates/page.clj
@@ -59,7 +59,7 @@
        (concat (rest urls) '(nil))))

 (defn- compile-serial-mds [dir]
-  (let [files (.listFiles (io/file dir))
+  (let [files (reverse (.listFiles (io/file dir)))
         mds (map #(load-markdown (.getAbsolutePath %)) files)
         neighbor-urls (create-neighbor-url (map #(:url %) mds))
         mds-with-neighbors (map (fn [m n] (merge m n)) mds neighbor-urls)]


Can add a user to the login table

Can add a user to the login table

Not a full user, but at least it is their credentials

--- idecode/myappshare/login_or_join.cljs
+++ idecode/myappshare/login_or_join.cljs
@@ -119,18 +119,23 @@

 (defn-ui-component     join-component-submit-button   [app]  {}
-  (button {:className "btn btn-lg" :style {:backgroundColor "#2B61CC" :fontSize "2em"}
-           :onClick #(go
-                       (let [email      (read-ui app [:email])
-                             password   (read-ui app [:password])
-                             ]
-
-                         (remote !join-go-pressed {:email     email
-                                                   :password  password})
+  (div nil
+       (button {:disabled (not (and (:success (read-ui app [:choose-password-response])) (:success (read-ui app [:confirm-password-response])) (:success (read-ui app [:join-email-response]))))
+                :className "btn btn-lg" :style {:backgroundColor "#2B61CC" :fontSize "2em"}
+                :onClick #(go
+                            (let [email      (read-ui app [:email])
+                                  password   (read-ui app [:password])
+                                  join-response   (remote !join-go-pressed {:email     email
+                                                                            :password  password})
+                                  ]
+                              (write-ui app [:join-response] join-response)

-                         ))
-           } "Go"))
+
+                              ))
+                } "Go")
+
+       (div nil (pr-str (read-ui app [:join-response])))))


fix figwheel :port -> :server-port

fix figwheel :port -> :server-port

--- src/leiningen/new/reagent/project.clj
+++ src/leiningen/new/reagent/project.clj
@@ -44,7 +44,7 @@
                                 (pjstadig.humane-test-output/activate!)]

                    :figwheel {:http-server-root "public"
-                              :port 3449
+                              :server-port 3449
                               :css-dirs ["resources/public/css"]}

                    :env {:dev? true}


the beginnings of a select statement - moving over to implicit metadata drawn from Model rather than explicit, supplied by caller...

--- src/main/java/org/dada/demo/core.clj
+++ src/main/java/org/dada/demo/core.clj
@@ -40,3 +40,226 @@
    (map
     #(Update. % nil)
     (.getData model))))
+
+(import '(clojure.lang DynamicClassLoader))
+
+;; e.g.
+;;(make-class
+;; factory
+;; "org.dada.tmp.Amount"
+;; ["int" "id"] ["int" "version"] ["double" "amount"])
+(defn make-class2 [factory name & properties]
+  (. #^DynamicClassLoader
+     (deref clojure.lang.Compiler/LOADER)
+     (defineClass name
+       (.create
+	factory
+	name
+	(into-array (map #(into-array String %) properties))))))
+
+(defn make-class [factory name & properties]
+  (. #^DynamicClassLoader
+     (deref clojure.lang.Compiler/LOADER)
+     (defineClass name
+       (.create
+	factory
+	name
+	(into-array (map (fn [pair]
+			     (let [array (make-array String 2)]
+			       (aset array 0 (.getCanonicalName (first pair)))
+			       (aset array 1 (first (rest pair)))
+			       array))
+			 properties))))))
+
+;; select t0.f0
+
+;;
+;; fields => [model field]
+
+(import org.dada.core.Getter)
+(import org.dada.core.Transformer)
+(import org.dada.core.Transformer$Transform)
+(import org.dada.core.GetterMetadata)
+(import org.dada.core.VersionedModelView)
+(import org.dada.asm.ClassFactory)
+(import java.beans.PropertyDescriptor)
+
+(defn make-constructor [class & types]
+  (let [ctor (symbol (str (.getCanonicalName class) "."))]
+    (println ctor)
+    (println types)
+    (fn [& args] (apply ctor args))))
+
+(defn make-instance [class & args]
+  (eval (list* 'new class args)))
+
+;; (defn make-instance [class & args]
+;;   "'new' seems to be a macro which does not evaluate its 'class'
+;; argument - so if you want to store the class in a variable and then
+;; instantiate it, use (make-instance)."
+;;   (apply 'new class args))
+
+(require '[clojure.contrib.str-utils2 :as s])
+
+;; TODO: how do we confirm that with-meta is doing the right thing for
+;; both input and output types...
+
+(defn make-getter-name [property-name]
+  (str "get" (s/capitalize property-name)))
+
+;; (defmacro make-lambda-getter [input-type output-type #^String property-name]
+;;   (let [method-name (symbol (make-getter-name property-name))]
+;;     `(fn [bean#] (. bean# ~method-name))))
+
+(defn make-lambda-getter [input-type output-type #^String property-name]
+  (let [method-name (symbol (make-getter-name property-name))]
+    (eval (list 'fn '[bean] (list '. 'bean method-name)))))
+
+;;(with-meta here (:tag output-type))
+
+;; TODO : should this not be a a macro - use proper syntax...
+(defn make-proxy-getter [input-type output-type property-name]
+  (let [method (symbol (make-getter-name property-name))]
+    (eval (list 'proxy '[Getter] '[] (list 'get '[bean] (list '. 'bean method))))
+    ))
+
+;; (defmacro make-proxy-getter [input-type output-type property-name]
+;;   (let [method (symbol (make-getter-name property-name))]
+;;     `(proxy [Getter] [] (get [bean#] (. bean# ~method)))
+;;     ))
+
+;; properties is a vector of property descriptions of the form:
+;; [input-type input-name output-type output-name]
+(defn select2 [input-class input-model output-item-name output-model-name key-type key-name version-type version-name properties]
+  (let [output-properties (map (fn [property] (vector (nth property 2) (nth property 3))) properties)
+   	input-getters (map (fn [property] (make-proxy-getter input-class (nth property 0) (nth property 1))) properties)
+	input-getters (map (fn [property] (make-lambda-getter input-class (nth property 0) (nth property 1))) properties)
+   	output-types (map (fn [property] (nth property 2)) properties)
+   	output-names (map (fn [property] (nth property 3)) properties)
+	class-factory  (new ClassFactory)
+  	output-class (apply make-class class-factory output-item-name output-properties)
+   	key-getter (make-proxy-getter output-class key-type key-name)
+   	version-getter (make-proxy-getter output-class version-type version-name)
+   	output-getters (map (fn [property] (make-proxy-getter output-class (nth property 2) (nth property 3))) properties)
+	output-metadata (new GetterMetadata output-class output-types output-names output-getters)
+	view (new VersionedModelView output-model-name output-metadata key-getter version-getter)
+	transformer (new
+  		     Transformer
+  		     (list view)
+  		     (proxy
+  		      [Transformer$Transform]
+  		      []
+  		      (transform [input]
+				 (print "INPUT ITEM: ")
+				 (println input)
+				 (print "OUTPUT CLASS:")
+				 (println output-class)
+				 (let
+				     [values
+				      (map
+				       ;;(fn [getter] (. getter get input))
+				       (fn [getter] (getter input))
+				       input-getters)]
+				   (print "OUTPUT VALUES:")
+				   (println values)
+				   (apply make-instance output-class values)))
+		      ))]
+    (connect input-model transformer)
+    view)
+  )
+
+;; should [if required] connect a transformer between model and view...
+;; each property should be able to register a converter fn as part of the transformation...
+;; if  properties is null, don't do a transformation etc..
+
+(defn property-map [metadata]
+  )
+
+(defn transform [model names view view-class] ;; lose view class
+  (let [metadata (. model getMetadata)
+	model-class (. metadata getValueClass)
+	types (. metadata getAttributeTypes)
+	getters (map (fn [type name] (make-lambda-getter model-class name type)) names types)
+	transformer (new
+		     Transformer
+		     (list view)
+		     (proxy
+		      [Transformer$Transform]
+		      []
+		      (transform [input]
+				 (let [values (map (fn [getter] (getter input)) getters)]
+				   (apply make-instance view-class values)))
+		      ))]
+    (connect model transformer)
+    ))
+
+(defn select [input-model output-item-name output-model-name key-type key-name version-type version-name properties]
+  (let [output-properties (map (fn [property] (vector (nth property 2) (nth property 3))) properties)
+   	input-names (map (fn [property] (nth property 1)) properties)
+   	output-types (map (fn [property] (nth property 2)) properties)
+   	output-names (map (fn [property] (nth property 3)) properties)
+	class-factory  (new ClassFactory)
+  	output-class (apply make-class class-factory output-item-name output-properties)
+   	key-getter (make-proxy-getter output-class key-type key-name)
+   	version-getter (make-proxy-getter output-class version-type version-name)
+   	output-getters (map (fn [property] (make-proxy-getter output-class (nth property 2) (nth property 3))) properties)
+	output-metadata (new GetterMetadata output-class output-types output-names output-getters)
+	view (new VersionedModelView output-model-name output-metadata key-getter version-getter)
+	transformer (transform input-model input-names view output-class)]
+    view)
+  )
+
+(do
+
+  (def metamodel (start-server "Server0"))
+  (start-client "Server0")
+
+  (import org.dada.asm.ClassFactory)
+  (import org.dada.core.VersionedModelView)
+  (import org.dada.core.GetterMetadata)
+
+  (def factory (new ClassFactory))
+  (def properties (list [(Integer/TYPE) "id"] [(Integer/TYPE) "version"] [(Long/TYPE) "time"] [(Double/TYPE) "amount"]))
+  (def input-class (apply make-class factory "org.dada.tmp.InputItem" properties))
+  (def input-types (map (fn [property] (nth property 0)) properties))
+  (def input-names (map (fn [property] (nth property 1)) properties))
+  (def input-getters (map (fn [property] (make-proxy-getter input-class (nth property 0) (nth property 1))) properties))
+  (def input-key-getter (nth input-getters 0))
+  (def input-version-getter (nth input-getters 1))
+  (def input-metadata (new GetterMetadata input-class input-types input-names input-getters))
+  (def input-model-name "InputModel")
+  (def input-model (new VersionedModelView input-model-name input-metadata input-key-getter input-version-getter))
+  (insert metamodel input-model)
+  (def item (make-instance input-class 0 1 2 3.0))
+  (insert input-model item)
+  (. input-model getData)
+  (. input-model getMetadata)
+
+  (def view (select input-model "org.dada.core.tmp.OutputItem" "OutputModel" (Integer/TYPE) "key" (Integer/TYPE) "version" (list [(Integer/TYPE) "id" (Integer/TYPE) "key"][(Integer/TYPE) "version" (Integer/TYPE) "version"][(Double/TYPE) "amount" (Double/TYPE) "money"])))
+  (insert metamodel view)
+
+  (def item5 (make-instance input-class 3 2 2 6.0))
+  (insert input-model item5)
+
+  (def view2 (select view "org.dada.core.tmp.OutputItem2" "OutputModel2" Integer "key" Integer "version" (list [(Integer/TYPE) "key" Integer "key"][(Integer/TYPE) "version" Integer "version"][(Double/TYPE) "money" Double "amount"])))
+
+  )
+
+;; thoughts about select...
+
+;; outputs: define new column names [and types?], name of new Java type and Model
+;; inputs: define list of (Model, columns, column-mapping, (column-getter), column transform,...
+
+;;where input type and output type differ (column-mappings have been
+;;specified) connect a transformer to input-model, to prrform this.
+
+;; connect input-model/transformer to output-model
+
+;; start by transforming any models that need it
+;; ensure all transforms types concur
+;; connect all to output model
+
+
+
+
+;; retrieve value class from Metadata


Update Jetty dependency to 9.4.36.v20210114

--- ring-jetty-adapter/project.clj
+++ ring-jetty-adapter/project.clj
@@ -7,7 +7,7 @@
   :dependencies [[org.clojure/clojure "1.7.0"]
                  [ring/ring-core "1.9.0"]
                  [ring/ring-servlet "1.9.0"]
-                 [org.eclipse.jetty/jetty-server "9.4.31.v20200723"]]
+                 [org.eclipse.jetty/jetty-server "9.4.36.v20210114"]]
   :aliases {"test-all" ["with-profile" "default:+1.8:+1.9:+1.10" "test"]}
   :profiles
   {:dev  {:dependencies [[clj-http "3.10.0"]


tell about collaboration

tell about collaboration

--- src-cljs/frontend/datascript.cljs
+++ src-cljs/frontend/datascript.cljs
@@ -122,7 +122,7 @@
                         :layer/stroke-color "blue"
                         :layer/name         "Text Layer 2"
                         :document/id        document-id
-                        :layer/text         "Cmd-click to open the Radial menu"
+                        :layer/text         "Cmd-click to open the Radial menu, share the url to collaborate"
                         :layer/font-family  "Helvetica Neue"
                         :layer/font-size    25
                         :entity/type        :layer}


Put some logging for the sake of clarity; also, added an upper limit to the amount of text to generate.

--- src/blutwurst/tuple_generator.clj
+++ src/blutwurst/tuple_generator.clj
@@ -32,7 +32,7 @@
    {
       :name "Random String Generator"
       :determiner #(= (:type %) "VARCHAR")
-      :generator #(random-string (or (:length %) 255))
+      :generator #(random-string (or (min (:length %) 2000) 255))
    }
    {
        :name "Random Integer Generator"
@@ -97,10 +97,13 @@
 (defn- generate-tuples-for-plan* [execution-plan result]
  (if (empty? execution-plan)
   (reverse result)
-  (recur (rest execution-plan)
-         (cons (generate-tuples-for-table (first execution-plan) 100 result) result))
+  (do
+      (trace "Beginning data generation for table " (first execution-plan))
+      (recur (rest execution-plan)
+             (cons (generate-tuples-for-table (first execution-plan) 100 result) result)))
  ))

 (defn generate-tuples-for-plan [execution-plan]
+ (trace "Beginning tuple generation for execution plan.")
  (generate-tuples-for-plan* execution-plan '()))


Simplify calling of pmap-boilerplate and pmap-core

The other changes to pmap-core have made this simplification possible.

--- src/clj/com/climate/claypoole.clj
+++ src/clj/com/climate/claypoole.clj
@@ -305,85 +305,84 @@
 (defn- pmap-core
   "Given functions to customize for pmap or upmap, create a function that does
   the hard work of pmap."
-  [ordered?]
-  (fn [pool f arg-seqs]
-    (let [[shutdown? pool] (impl/->threadpool pool)
-          ;; Use map to handle the argument sequences.
-          args (apply map vector (map impl/unchunk arg-seqs))
-          ;; Pre-declare the canceller because it needs the tasks but the tasks
-          ;; need it too.
-          canceller (promise)
-          ;; Set up queues of tasks and results
-          [task-q tasks] (impl/queue-seq)
-          [unordered-results-q unordered-results] (impl/queue-seq)
-          ;; This is how we'll actually make things go.
-          start-task (fn [i a later-tasks]
-                       ;; We can't directly make a future add itself to a
-                       ;; queue. Instead, we use a promise for indirection.
-                       (let [p (promise)]
-                         (deliver p (future-call
-                                      pool
-                                      (with-meta
-                                        ;; Try to run the task, but definitely
-                                        ;; add the future to the queue.
-                                        #(try
-                                           (let [result (apply f a)]
-                                             (impl/queue-seq-add!
-                                               unordered-results-q @p)
-                                             result)
-                                           ;; Even if we had an error running
-                                           ;; the task, make sure the future
-                                           ;; shows up in the queue.
-                                           (catch Throwable t
-                                             ;; We've still got to send that
-                                             ;; result, even if it was an
-                                             ;; exception, and we have to do it
-                                             ;; before we start the canceller.
-                                             (impl/queue-seq-add!
-                                               unordered-results-q @p)
-                                             ;; If we've had an exception, kill
-                                             ;; future and ongoing processes.
-                                             (@canceller i later-tasks)
-                                             ;; Re-throw that throwable!
-                                             (throw t)))
-                                        ;; Add the args to the function's
-                                        ;; metadata for prioritization.
-                                        {:args a})))
-                         @p))
-          ;; Start all the tasks in a real future, so we don't block.
-          driver (core/future
-                   (try
-                     (doseq [[i a later-tasks _]
-                             (map vector (range) args (impl/subseqs tasks)
-                                  ;; The driver thread reads from this sequence
-                                  ;; and ignores the result, just to get the
-                                  ;; side effect of blocking when the map's
-                                  ;; (imaginary) buffer is full.
-                                  (buffer-blocking-seq pool unordered-results))]
-                       (impl/queue-seq-add! task-q (start-task i a later-tasks)))
-                     (finally
-                       (impl/queue-seq-end! task-q)
-                       (when shutdown? (shutdown pool)))))]
-      (deliver canceller (make-canceller driver))
-      ;; Read results as available.
-      (concat (map deref
-                   (if ordered?
-                     tasks
-                     (map second (impl/lazy-co-read tasks unordered-results))))
-              ;; Deref the read-future to get its exceptions, if it has any.
-              (lazy-seq (try @driver
-                          ;; But if it was cancelled, the user doesn't care.
-                          (catch CancellationException e)))))))
+  [pool ordered? f arg-seqs]
+  (let [[shutdown? pool] (impl/->threadpool pool)
+        ;; Use map to handle the argument sequences.
+        args (apply map vector (map impl/unchunk arg-seqs))
+        ;; Pre-declare the canceller because it needs the tasks but the tasks
+        ;; need it too.
+        canceller (promise)
+        ;; Set up queues of tasks and results
+        [task-q tasks] (impl/queue-seq)
+        [unordered-results-q unordered-results] (impl/queue-seq)
+        ;; This is how we'll actually make things go.
+        start-task (fn [i a later-tasks]
+                     ;; We can't directly make a future add itself to a
+                     ;; queue. Instead, we use a promise for indirection.
+                     (let [p (promise)]
+                       (deliver p (future-call
+                                    pool
+                                    (with-meta
+                                      ;; Try to run the task, but definitely
+                                      ;; add the future to the queue.
+                                      #(try
+                                         (let [result (apply f a)]
+                                           (impl/queue-seq-add!
+                                             unordered-results-q @p)
+                                           result)
+                                         ;; Even if we had an error running
+                                         ;; the task, make sure the future
+                                         ;; shows up in the queue.
+                                         (catch Throwable t
+                                           ;; We've still got to send that
+                                           ;; result, even if it was an
+                                           ;; exception, and we have to do it
+                                           ;; before we start the canceller.
+                                           (impl/queue-seq-add!
+                                             unordered-results-q @p)
+                                           ;; If we've had an exception, kill
+                                           ;; future and ongoing processes.
+                                           (@canceller i later-tasks)
+                                           ;; Re-throw that throwable!
+                                           (throw t)))
+                                      ;; Add the args to the function's
+                                      ;; metadata for prioritization.
+                                      {:args a})))
+                       @p))
+        ;; Start all the tasks in a real future, so we don't block.
+        driver (core/future
+                 (try
+                   (doseq [[i a later-tasks _]
+                           (map vector (range) args (impl/subseqs tasks)
+                                ;; The driver thread reads from this sequence
+                                ;; and ignores the result, just to get the side
+                                ;; effect of blocking when the map's
+                                ;; (imaginary) buffer is full.
+                                (buffer-blocking-seq pool unordered-results))]
+                     (impl/queue-seq-add! task-q (start-task i a later-tasks)))
+                   (finally
+                     (impl/queue-seq-end! task-q)
+                     (when shutdown? (shutdown pool)))))]
+    (deliver canceller (make-canceller driver))
+    ;; Read results as available.
+    (concat (map deref
+                 (if ordered?
+                   tasks
+                   (map second (impl/lazy-co-read tasks unordered-results))))
+            ;; Deref the read-future to get its exceptions, if it has any.
+            (lazy-seq (try @driver
+                        ;; But if it was cancelled, the user doesn't care.
+                        (catch CancellationException e))))))

 (defn- pmap-boilerplate
   "Do boilerplate pmap checks, then call the real pmap function."
-  [pool f arg-seqs pmap-fn]
+  [pool ordered? f arg-seqs]
   (when (empty? arg-seqs)
     (throw (IllegalArgumentException.
              "pmap requires at least one sequence to map over")))
   (if (serial? pool)
     (doall (apply map f arg-seqs))
-    (pmap-fn pool f arg-seqs)))
+    (pmap-core pool ordered? f arg-seqs)))

 (defn pmap
   "Like clojure.core.pmap, except:
@@ -406,13 +405,13 @@
        serial via (doall map). This may be helpful during profiling, for example.
   "
   [pool f & arg-seqs]
-  (pmap-boilerplate pool f arg-seqs (pmap-core true)))
+  (pmap-boilerplate pool true f arg-seqs))

 (defn upmap
   "Like pmap, except that the return value is a sequence of results ordered by
   *completion time*, not by input order."
   [pool f & arg-seqs]
-  (pmap-boilerplate pool f arg-seqs (pmap-core false)))
+  (pmap-boilerplate pool false f arg-seqs))

 (defn pcalls
   "Like clojure.core.pcalls, except it takes a threadpool. For more detail on


extend ALL to PersistentHashSet

extend ALL to PersistentHashSet

--- src/clj/com/rpl/specter/navs.cljc
+++ src/clj/com/rpl/specter/navs.cljc
@@ -102,6 +102,13 @@
   #?(:clj clojure.lang.PersistentVector :cljs cljs.core/PersistentVector)
   (all-transform [structure next-fn]
     (into []
+      (comp (map next-fn)
+            (filter not-NONE?))
+      structure))
+
+  #?(:clj clojure.lang.PersistentHashSet :cljs cljs.core/PersistentHashSet)
+  (all-transform [structure next-fn]
+    (into #{}
       (comp (map next-fn)
             (filter not-NONE?))
       structure))


Fixes Chronos Protocol interaction with I've Had Worse.

--- src/clj/game/cards-identities.clj
+++ src/clj/game/cards-identities.clj
@@ -72,7 +72,7 @@
                                                            (str " and deal "
                                                                 (- (get-defer-damage state side :net nil) 1)
                                                                 " more net damage")))
-                                                  :effect (effect (trash target)
+                                                  :effect (effect (trash target {:cause :net})
                                                                   (damage :net (- (get-defer-damage state side :net nil) 1)
                                                                           {:unpreventable true :card card}))}
                                     :no-ability {:effect (effect (damage :net (get-defer-damage state side :net nil)


change The Greenhouse advancements to :placed true

--- src/clj/game/cards-identities.clj
+++ src/clj/game/cards-identities.clj
@@ -175,7 +175,7 @@
                                          :choices {:req #(or (= (:advanceable %) "always")
                                                              (and (= (:advanceable %) "while-rezzed") (:rezzed %))
                                                              (= (:type %) "Agenda"))}
-                                         :effect (effect (add-prop target :advance-counter 4))} card nil)))))}]}
+                                         :effect (effect (add-prop target :advance-counter 4 {:placed true}))} card nil)))))}]}

    "Kate \"Mac\" McCaffrey: Digital Tinker"
    {:effect (effect (gain :link 1))


refactor Haarpsichord Studios with flag system

--- src/clj/game/cards-identities.clj
+++ src/clj/game/cards-identities.clj
@@ -131,8 +131,14 @@
    {:effect (effect (gain :credit 5 :bad-publicity 1))}

    "Haarpsichord Studios: Entertainment Unleashed"
-   {:events {:pre-steal-cost {:req (req (:stole-agenda runner-reg))
-                              :effect (effect (prevent-steal))}}}
+   {:events {:agenda-stolen
+             {:effect (effect (register-turn-flag!
+                                card :can-steal
+                                (fn [state side card]
+                                  (if (is-type? card "Agenda")
+                                    ((constantly false)
+                                     (toast state :runner "Cannot steal due to Haarpsichord Studios." "warning"))
+                                    true))))}}}

    "Haas-Bioroid: Engineering the Future"
    {:events {:corp-install {:once :per-turn :msg "gain 1 [Credits]"


debug-log some info about the cwd

debug-log some info about the cwd

--- src/clj/runbld/vcs/middleware.clj
+++ src/clj/runbld/vcs/middleware.clj
@@ -4,6 +4,7 @@
             [slingshot.slingshot :refer [throw+]])
   (:require [clojure.java.io :as io]
             [environ.core :as environ]
+            [runbld.util.debug :as debug]
             [runbld.vcs :as vcs]
             [runbld.vcs.subversion :as svn]
             [runbld.vcs.git :as git]))
@@ -26,13 +27,21 @@
                               (get-in opts [:build :project])
                               (get-in opts [:env :SVN_REVISION]))

-      :else (throw+
-             {:error ::unknown-repo
-              :msg (format (str
-                            "%s: unknown repository type "
-                            "(only know about git and svn currently)")
-                           cwd)
-              :opts opts}))))
+      :else
+      (let [msg (str cwd ": unknown repository type "
+                     "(only know about git and svn currently)")
+            f (io/file cwd)
+            exists? (.exists f)]
+        (debug/log msg
+                   "CWD exists?" exists?
+                   "Listing:" (if exists?
+                                (.list f)
+                                "N/A")
+                   "Process opts:" (:process opts))
+        (throw+
+         {:error ::unknown-repo
+          :msg msg
+          :opts opts})))))

 (s/defn add-vcs-info
   [opts :- OptsWithBuild]


refine commodity form fields

refine commodity form fields

--- src/clj_money/web/commodities.clj
+++ src/clj_money/web/commodities.clj
@@ -3,6 +3,7 @@
   (:require [environ.core :refer [env]]
             [ring.util.response :refer :all]
             [hiccup.core :refer :all]
+            [clojure.tools.logging :as log]
             [clj-money.util :refer [format-number]]
             [clj-money.web.shared :refer :all]
             [clj-money.validation :as validation]
@@ -75,14 +76,14 @@
   (html
     [:div.row
      [:div.col-sm-6
-      (select-field commodity :exchange (options-for-select [:currency :stock] name identity))]
+      (select-field commodity :type (options-for-select [:currency :stock] name identity))]
      [:div.col-sm-6
       (select-field commodity :exchange (options-for-select commodities/exchanges name identity))]]
     [:div.row
      [:div.col-sm-6
-      (text-input-field commodity :name)]
+      (text-input-field commodity :name {:autofocus true})]
      [:div.col-sm-6
-      (text-input-field commodity :symbol {:autofocus true})]]
+      (text-input-field commodity :symbol)]]
     [:input.btn.btn-primary {:type :submit
                              :value "Save"
                              :title "Click here to save this commodity"}]
@@ -107,7 +108,7 @@
   [{params :params}]
   (let [commodity (commodities/create
                     (env :db)
-                    (select-keys params [:entity-id :name :symbol :exchange]))]
+                    (select-keys params [:entity-id :name :symbol :exchange :type]))]
     (if (validation/has-error? commodity)
       (new-commodity {} commodity)
       (redirect (format "/entities/%s/commodities" (:entity-id commodity))))))
@@ -133,7 +134,7 @@
   (let [result (commodities/update (env :db)
                                    (select-keys
                                      params
-                                     [:id :name :symbol :exchange]))]
+                                     [:id :name :symbol :exchange :type]))]
     (if (validation/has-error? result)
       (edit {} result)
       (redirect (format "/entities/%s/commodities" (:entity-id result))))))


Add a missing form-2 on symbol-popover. Second part of the renaming.

--- src/cljs/cljs_repl_web/views.cljs
+++ src/cljs/cljs_repl_web/views.cljs
@@ -217,7 +217,7 @@
   [symbol]
   (get-in api/cljs-api-edn [:symbols symbol]))

-(defn build-signatures-ui
+(defn api-signatures
   "Builds a table for the provided signatures of a symbol."
   [signatures]
   [v-box
@@ -228,7 +228,7 @@
                            :label s
                            :class "api-panel-signature"])]])

-(defn build-symbol-description-ui
+(defn api-symbol-description
   "Builds the UI for the symbol's description in the popover. Desc needs
   to be markdown."
   [desc]
@@ -246,7 +246,7 @@
               ;; AR - markdown->react component solves issue #
               [label :label [md/md->react-component desc]]]])

-(defn build-related-symbols-ui
+(defn api-related-symbols
   "Builds the UI for related symbols in the popover."
   [related]
   [v-box
@@ -266,7 +266,7 @@
                             :href (utils/symbol->clojuredocs-url rel)
                             :target "_blank"])]]])

-(defn example-ui
+(defn api-example
   "The (single) example, usually monospaced, html UI. Wants a map {:html ... :strings}."
   [example-map]
   {:pre [(:strings example-map) (:html example-map)]}
@@ -292,9 +292,9 @@
           :src "styles/images/cljs.svg"
           :alt "Load the example in the REPL"}]])

-(defn example-panel
+(defn api-example-panel
   "UI for a single example. Wants a map {:html ... :strings}."
-  [example-index example-map showing?]
+  [showing-atom example-index example-map]
   {:pre [(:strings example-map) (:html example-map)]}
   [v-box
    :size "none"
@@ -317,13 +317,13 @@
                                :children [[example-number-icon example-index]
                                           [example-send-to-repl-button-label example-index example-map]]]
                        :on-click (handler-fn
-                                  (reset! showing? false)
+                                  (reset! showing-atom false)
                                   (dispatch [:send-to-console :cljs-console (:strings example-map)]))]]
-              [example-ui example-map]]])
-
-(defn build-examples-ui
+              [api-example example-map]]])
+
+(defn api-examples
   "Builds the UI for the symbol's examples. Wants a list of {:html ... :strings}."
-  [examples-map showing?]
+  [showing-atom examples-map]
   [v-box
    :size "0 1 auto"
    :children [
@@ -335,11 +335,11 @@
               [v-box
                :size "0 0 auto"
                :gap "2px"
-               :children (map-indexed #(example-panel %1 %2 showing?) examples-map)]]])
+               :children (map-indexed (partial api-example-panel showing-atom) examples-map)]]])

 (defn symbol-popover
   "A popover's body in which details of the given symbol will be shown."
-  [showing? popover-position sym-doc-map]
+  [showing-atom position-atom sym-doc-map]
   (let [{name :name
          full-name :full-name
          desc :description
@@ -348,55 +348,57 @@
          examples-strings :examples-strings
          sign :signature
          related :related} sym-doc-map
-         desc (or desc docstring)       ; some symbols don't have a description so we use
+        desc (or desc docstring) ; some symbols don't have a description so we use
                                         ; the docstring instead; docstring is a regular string,
                                         ; without markdown. Nonetheless, it will be passed to
                                         ; md->react->component function to gain some basic html
                                         ; formatting (like paragraphs)
-         examples (map (fn [html string] {:html html :strings string}) examples-htmls examples-strings)
-         popover-width  400
-         popover-height 400
-         popover-content-width (- popover-width (* 2 14) 15)] ; bootstrap padding + scrollbar width
-    [popover-content-wrapper
-     :showing? showing?
-     :position @popover-position
-     :on-cancel (handler-fn (reset! showing? false))
-     :style {:max-height (str popover-height)
-             :max-width (str popover-width)}
-     :backdrop-opacity 0.1
-     :close-button? false
-     :title [h-box
-             :gap "6px"
-             :align :center
-             :children [[title
-                         :label name
-                         :level :level4]
-                        [md-icon-button
-                         :md-icon-name "zmdi-info"
-                         :tooltip "See online documentation"
-                         :tooltip-position :right-center
-                         :size :smaller
-                         :style {:justify-content :center}
-                         :on-click #(utils/open-new-window (utils/symbol->clojuredocs-url full-name))]]]
-     :body [(fn []
-              [scroller
-               :size "1 1 auto"
-               :max-width (str popover-width)
-               :max-height (str (- popover-height 50))
-               :scroll :auto
-               :child [v-box
-                       :size "1 1 auto"
-                       :gap "8px"
-                       :width (str popover-content-width)
-                       :style {:padding "4px"}
-                       :children [(when (not-empty sign)
-                                    [build-signatures-ui sign])
-                                  (when (not-empty desc)
-                                    [build-symbol-description-ui desc])
-                                  (when (not-empty related)
-                                    [build-related-symbols-ui related])
-                                  (when (not-empty examples)
-                                    [build-examples-ui examples showing?])]]])]]))
+        examples (map (fn [html string] {:html html :strings string}) examples-htmls examples-strings)
+        popover-width  400
+        popover-height 400
+        popover-content-width (- popover-width (* 2 14) 15)] ; bootstrap padding + scrollbar width
+    (fn symbol-popover-form2 [showing-atom position-atom sym-doc-map]
+      [popover-content-wrapper
+       :showing? showing-atom
+       :position @position-atom
+       :on-cancel (handler-fn (reset! showing-atom false))
+       :style {:max-height (str popover-height)
+               :max-width (str popover-width)}
+       :backdrop-opacity 0.1
+       :close-button? false
+       :title [h-box
+               :gap "6px"
+               :align :center
+               :children [[title
+                           :label name
+                           :level :level4]
+                          [md-icon-button
+                           :md-icon-name "zmdi-info"
+                           :tooltip "See online documentation"
+                           :tooltip-position :right-center
+                           :size :smaller
+                           :style {:justify-content :center}
+                           :on-click #(utils/open-new-window (utils/symbol->clojuredocs-url full-name))]]]
+       :body [(fn []
+                [scroller
+                 :size "1 1 auto"
+                 :max-width (str popover-width)
+                 :max-height (str (- popover-height 50))
+                 :scroll :auto
+                 :child [v-box
+                         :size "1 1 auto"
+                         :gap "8px"
+                         :width (str popover-content-width)
+                         :style {:padding "4px"}
+                         :children [(when (not-empty sign)
+                                      [api-signatures sign])
+                                    (when (not-empty desc)
+                                      [api-symbol-description desc])
+                                    (when (not-empty related)
+                                      [api-related-symbols related])
+                                    (when (not-empty examples)
+                                      [api-examples showing-atom examples])]]])]])))
+
 (defn api-symbol
   "Builds the UI for a single symbol. Will be a button."
   [symbol]
@@ -470,8 +472,6 @@
                                                     :style {:flex-flow "wrap"}
                                                     :children (for [symbol (:symbols topic)]
                                                                 [api-symbol symbol])]]])]]]]])
-
-

 (defn api-panel
   "Builds the UI for the api panel."