Improvements on query specs

Improvements on query specs

- ident is a tuple (simplified generator)
- fix join key expression (was allowing for param expr on param expr)
- ensure query doesn't have duplicated keys on the same level

--- src/com/wsscode/pathom/specs/query.cljc
+++ src/com/wsscode/pathom/specs/query.cljc
@@ -2,7 +2,8 @@
   (:require [clojure.spec.alpha :as s]
             [clojure.test.check]
             [clojure.test.check.generators :as gen #?@(:cljs [:include-macros true])]
-            [clojure.test.check.properties]))
+            [clojure.test.check.properties]
+            [fulcro.client.primitives :as fp]))

 (def ^:dynamic *query-gen-max-depth* 4)

@@ -12,10 +13,7 @@
                                                        [10 (gen/return "123")]
                                                        [2 (gen/return [:a "b"])]
                                                        [1 (gen/return '_)]])))
-(s/def ::ident (s/with-gen
-                 (s/and vector? (s/cat :ident ::property :value ::ident-value))
-                 #(gen/let [s (s/gen (s/cat :ident ::property :value ::ident-value))]
-                    (vec s))))
+(s/def ::ident (s/tuple ::property ::ident-value))
 (s/def ::join-key (s/or :prop ::property :ident ::ident :param-exp ::join-key-param-expr))
 (s/def ::join (s/map-of ::join-key ::join-query :count 1 :conform-keys true))
 (s/def ::union (s/map-of ::property ::query :min-count 1 :conform-keys true))
@@ -51,10 +49,12 @@
                p (s/gen ::params)]
        (list q p))))

+(s/def ::join-key-param-key (s/or :prop ::property :ident ::ident))
+
 (s/def ::join-key-param-expr
   (s/with-gen
-    (s/and list? (s/cat :expr ::join-key :params ::params))
-    #(gen/let [q (s/gen ::join-key)
+    (s/and list? (s/cat :expr ::join-key-param-key :params ::params))
+    #(gen/let [q (s/gen ::join-key-param-key)
                p (s/gen ::params)]
        (list q p))))

@@ -65,15 +65,33 @@
         :param-exp ::param-expr
         :special ::special-property))

+(defn unique-keys? [query]
+  (let [ast (fp/query->ast (s/unform ::query query))]
+    (if (reduce
+          (fn [keys {:keys [key]}]
+            (if (contains? keys key)
+              (reduced false)
+              (conj keys key)))
+          #{}
+          (:children ast))
+      query
+      false)))
+
+(s/fdef unique-keys?
+  :args (s/cat :query ::query)
+  :ret (s/or :query ::query :not-unique false?))
+
 (s/def ::query
-  (s/coll-of ::query-expr :kind vector?
-    :gen #(let [g (s/gen (s/coll-of ::query-expr :kind vector? :max-count 5))]
-            (gen/->Generator
-              (fn [rdn size]
-                (if (> *query-gen-max-depth* 0)
-                  (binding [*query-gen-max-depth* (dec *query-gen-max-depth*)]
-                    (gen/call-gen g rdn size))
-                  (gen/call-gen (gen/return []) rdn size)))))))
+  (s/and
+    (s/coll-of ::query-expr :kind vector?
+      :gen #(let [g (s/gen (s/coll-of ::query-expr :kind vector? :max-count 5))]
+              (gen/->Generator
+                (fn [rdn size]
+                  (if (> *query-gen-max-depth* 0)
+                    (binding [*query-gen-max-depth* (dec *query-gen-max-depth*)]
+                      (gen/call-gen g rdn size))
+                    (gen/call-gen (gen/return []) rdn size))))))
+    unique-keys?))

 ; those symbol set examples have to writen outside of the with-gen, otherwise CLJS doesn't compiles
 (def sample-mutations '#{do-something create/this-thing operation.on/space})


Updated call to om/root and used apply in calls to parent elements to get om/build-all working

--- src/main/cljs/emotions_demo/client.cljs
+++ src/main/cljs/emotions_demo/client.cljs
@@ -44,8 +44,8 @@
 (defn bind-state [{:keys [ws] :as data}]
   (go-loop []
     (when-let [{update :message} (<! ws)]
-;      (prn update)
-;      (om/transact! data #(make-new-state % (reader/read-string update)))
+      (prn update)
+      (om/transact! data #(make-new-state % (reader/read-string update)))
       (recur))))

 (defn single-value [{:keys [id name value] :as c} owner opts]
@@ -62,7 +62,7 @@
     om/IRender
     (render [_]
       (prn "valence arousal" va)
-      (dom/div #js {:className "valence_arousal"}
+      (apply dom/div #js {:className "valence_arousal"}
                (om/build-all single-value va {:key :id})))))

@@ -74,8 +74,7 @@
       (prn (if (om/cursor? sv) "cursor" "not cursor"))
       (dom/div #js {:className "satisfaction_vector"}
                (dom/h2 nil "Satisfaction vector")
-               (dom/div #js {:className "contents"}
-
+               (apply dom/div #js {:className "contents"}
                         (om/build-all single-value sv)
                         )))))

@@ -115,5 +114,5 @@
                          :sv [{:id :phys-anger, :name "anger", :value 0} {:id :phys-hunger, :name "hunger", :value 0} {:id :phys-fear, :name "fear", :value 0} {:id :saf-bored, :name "bored", :value 0.098} {:id :saf-delight, :name "delight", :value 0} {:id :saf-playful, :name "playful", :value 0.049} {:id :soc-lonely, :name "lonely", :value 0.04875}]
                          :va [{:id :valence :name "Valence" :value 0.2} {:id :arousal :name "Arousal" :value 0.3}]
                          :percepts [] :sv-history {} :va-history {}})]
-        (om/root app-state emotion-display-app
-         (.getElementById js/document "app"))))
+    (om/root emotion-display-app app-state
+             {:target (.getElementById js/document "app")})))


Stringifying handler symbol doesn't seem necessary

But dynamically-created handlers (those not found in a file on the CP)
don't work.

--- modules/web/src/immutant/web/wunderboss.clj
+++ modules/web/src/immutant/web/wunderboss.clj
@@ -25,7 +25,8 @@
   [context]
   (when-let [container (get @started-containers context)]
     (.stop container)
-    (swap! started-containers dissoc context)))
+    (swap! started-containers dissoc context)
+    true))

 (defn start
   [context handler {:as opts}]
@@ -34,7 +35,6 @@
     (stop context))
   (let [opts (into {} (map (fn [[k v]] [(name k) v]) opts))
         container (.configure (WunderBoss.) "web" opts)
-        h (format "%s/%s" (namespace handler) (name handler))
-        app (.newApplication container "clojure" {"ring-handler" h})]
+        app (.newApplication container "clojure" {"ring-handler" handler})]
     (swap! started-containers assoc context container)
     (.start app "ring" {"context" context})))


fix stray character

fix stray character

--- src-cljs/frontend/rtc.cljs
+++ src-cljs/frontend/rtc.cljs
@@ -271,8 +271,8 @@
                                                  :signal-data signal-data}])
               (do
                 (signal-fn {:sdp (js/JSON.stringify (.-localDescription conn))})
-                (put! (:controls comms) [:remote-media-stream-readyc {:stream (first (.getRemoteStreams conn))
-                                                                      :producer producer}])))
+                (put! (:controls comms) [:remote-media-stream-ready {:stream (first (.getRemoteStreams conn))
+                                                                     :producer producer}])))
             (catch js/Error e
               (put! (:errors comms) [:rtc-error {:error e :type
                                                  :offer-handle-sdp


add stupid ascii diagram showing fn call graph for hydrate internal fns

--- src/metabase/models/hydrate.clj
+++ src/metabase/models/hydrate.clj
@@ -267,6 +267,12 @@
 ;; At a high level, these functions let you aggressively flatten a sequence of maps by a key
 ;; so you can apply some function across it, and then unflatten that sequence.
 ;;
+;;          +-------------------------------------------------------------------------+
+;;          |                                                                         +--> (map merge) --> new seq
+;;     seq -+--> counts-of ------------------------------------+                      |
+;;          |                                                  +--> counts-unflatten -+
+;;          +--> counts-flatten -> (modify the flattened seq) -+
+;;
 ;; 1.  Get a value that can be used to unflatten a sequence later with `counts-of`.
 ;; 2.  Flatten the sequence with `counts-flatten`
 ;; 3.  Modify the flattened sequence as needed


improve channel list ui

improve channel list ui

--- priv/ui/src/cljs/holiday_ping_ui/views.cljs
+++ priv/ui/src/cljs/holiday_ping_ui/views.cljs
@@ -150,29 +150,34 @@
 (defn channel-item-view
   [{:keys [name type] :as channel}]
   [:tr {:key name}
-   [:td [:span.icon.is-small {:title "Slack"} [:i.fa.fa-slack]] "  " name]
-   [:td.has-text-right
-    [:div.field.is-grouped.is-grouped-right
+   [:td
+    [:div.title.is-5 name]
+    [:div.subtitle.is-6 (str type " channel")]]
+   [:td
+    [:div.field.is-pulled-right.has-addons
      [:p.control
-      [:button.button.is-danger.is-small
-       {:on-click #(re-frame/dispatch [:channel-delete name])}
-       [:span.icon.is-small [:i.fa.fa-times]]
-       [:span "Delete"]]]
+      [:button.button.is-danger.is-small.tooltip
+       {:on-click     #(re-frame/dispatch [:channel-delete name])
+        :data-tooltip "Delete"}
+       [:span.icon.is-small [:i.fa.fa-times]]]]
+
      [:p.control
-      [:button.button.is-info.is-small
-       {:on-click #(re-frame/dispatch [:switch-view :channel-edit channel])}
-       [:span.icon.is-small [:i.fa.fa-edit]]
-       [:span "Edit"]]]
+      [:button.button.is-info.is-small.tooltip
+       {:on-click     #(re-frame/dispatch [:switch-view :channel-edit channel])
+        :data-tooltip "Edit"}
+       [:span.icon.is-small [:i.fa.fa-edit]]]]
+
      [:p.control
-      [:button.button.is-small
-       {:on-click #(re-frame/dispatch [:channel-test-start channel])}
-       [:span.icon.is-small [:i.fa.fa-cogs]]
-       [:span "Test"]]]
+      [:button.button.is-small.tooltip
+       {:on-click     #(re-frame/dispatch [:channel-test-start channel])
+        :data-tooltip "Test channel"}
+       [:span.icon.is-small [:i.fa.fa-cogs]]]]
+
      [:p.control
-      [:button.button.is-small
-       {:on-click #(re-frame/dispatch [:switch-view :holidays name])}
-       [:span.icon.is-small [:i.fa.fa-calendar]]
-       [:span "Holidays"]]]]]])
+      [:button.button.is-small.tooltip
+       {:on-click     #(re-frame/dispatch [:switch-view :holidays name])
+        :data-tooltip "Select holidays"}
+       [:span.icon.is-small [:i.fa.fa-calendar]]]]]]])

 (defn add-channel-button
   []
@@ -192,7 +197,7 @@
       [:p.subtitle.has-text-centered
        "Setup the channels to send your holiday reminders."]
       (when-not (empty? channels)
-        [:table.table.is-fullwidth.is-striped
+        [:table.table.is-fullwidth.is-outlined
          [:tbody (map channel-item-view channels)]])
       [add-channel-button]]]))


First implementation of entity groups.

First implementation of entity groups.

--- src/appengine_magic/services/datastore.clj
+++ src/appengine_magic/services/datastore.clj
@@ -23,6 +23,10 @@
                                  last-slash)))))

+(defn- coerce-key-value-type [key-value]
+  (if (integer? key-value) (long key-value) key-value))
+
+
 (defprotocol EntityProtocol
   "Entities are Clojure records which conform to the EntityProtocol. Each Entity
    must have a key. If an entity record field has a :key metadata tag, then that
@@ -30,60 +34,61 @@
    automatically generated for it. In either case, the key becomes part of the
    entity's metadata. Entity retrieval operations must set the :key metadata on
    returned entity records."
-  (get-key-object [this] "Returns nil if no tag is specified in the record
-                          definition, and no :key metadata exists. Otherwise
-                          returns a Key object.")
-  (get-key-value [this]  "Returns the Clojure value of the entity's Key object.")
-  (save! [this]          "Saves the entity to the datastore."))
+  (get-key-object [this] [this parent]
+    "Returns nil if no tag is specified in the record definition, and no :key
+     metadata exists. Otherwise returns a Key object. Specify optional entity
+     group parent.")
+  (save! [this] [this parent]
+    "Writes the given entity to the data store. Specify optional entity group
+    parent."))

-(defn entity-get-key-object-helper [entity-record parent key-property datastore-entity-name]
-  ;; TODO: Handle parent entities.
+(defn get-key-object-helper [entity-record key-property datastore-entity-name &
+                             {:keys [parent]}]
   (let [entity-record-metadata (meta entity-record)
         metadata-key-value (when entity-record-metadata (:key entity-record-metadata))
-        key-property-value (when key-property (key-property entity-record))]
+        key-property-value (coerce-key-value-type
+                            (when key-property (key-property entity-record)))]
     (cond
      ;; neither exists: autogenerate
      (and (nil? key-property-value) (nil? metadata-key-value))
      nil
      ;; key property exists
      (not (nil? key-property-value))
-     (KeyFactory/createKey datastore-entity-name key-property-value)
+     (if parent
+         (KeyFactory/createKey (get-key-object parent) datastore-entity-name key-property-value)
+         (KeyFactory/createKey datastore-entity-name key-property-value))
      ;; metadata key exists
      (and (not (nil? metadata-key-value)) (instance? Key metadata-key-value))
      metadata-key-value
      ;; something's wrong
-     :else (throw (RuntimeException. "entity has no valid :key metadata, and has no fields marked :key")))))
+     :else (throw (RuntimeException.
+                   "entity has no valid :key metadata, and has no fields marked :key")))))

-(defn entity-get-key-value-helper [entity-record]
-  (let [key-object (get-key-object entity-record)]
-    (when key-object
-      (if-let [name (.getName key-object)]
-        name
-        (.getId key-object)))))
-
-
-(defn entity-save-helper [entity-record datastore-entity-name]
-  (let [key-object (get-key-object entity-record)
+(defn save!-helper [entity-record datastore-entity-name &
+                    {:keys [parent]}]
+  (let [key-object (if parent
+                       (get-key-object entity-record parent)
+                       (get-key-object entity-record))
         entity (if key-object
                    (Entity. key-object)
                    (Entity. datastore-entity-name))]
     (doseq [[property-kw value] entity-record]
       (let [property-name (.substring (str property-kw) 1)]
         (.setProperty entity property-name value)))
-    ;; TODO: Allow optional :service argument!
     (.put (get-datastore-service) entity)))

 (defn retrieve [entity-record-type key-value &
                 {:keys [parent datastore-entity-name]
                  :or {datastore-entity-name (unqualified-name (.getName entity-record-type))}}]
-  ;; TODO: Allow optional :service argument!
-  ;; TODO: Deal with parent entities.
-  (let [key-object (KeyFactory/createKey datastore-entity-name (if (integer? key-value)
-                                                                   (long key-value)
-                                                                   key-value))
+  (let [key-object (if parent
+                       (KeyFactory/createKey (get-key-object parent)
+                                             datastore-entity-name
+                                             (coerce-key-value-type key-value))
+                       (KeyFactory/createKey datastore-entity-name
+                                             (coerce-key-value-type key-value)))
         entity (.get (get-datastore-service) key-object)
         properties (into {} (.getProperties entity))
         kw-keys-properties (reduce (fn [m [k v]] (assoc m (keyword k) v)) {} properties)
@@ -96,28 +101,17 @@

 (defmacro defentity [name properties &
-                     {:keys [parent datastore-entity-name]
+                     {:keys [datastore-entity-name]
                       :or {datastore-entity-name (unqualified-name name)}}]
   (let [key-property-name (first (filter #(= (:tag (meta %)) :key) properties))
         key-property (if key-property-name (keyword (str key-property-name)) nil)]
     `(defrecord ~name ~properties
        EntityProtocol
        (get-key-object [this#]
-         (entity-get-key-object-helper this# ~parent ~key-property ~datastore-entity-name))
-       (get-key-value [this#]
-         (entity-get-key-value-helper this#))
+         (get-key-object-helper this# ~key-property ~datastore-entity-name))
+       (get-key-object [this# parent#]
+         (get-key-object-helper this# ~key-property ~datastore-entity-name :parent parent#))
        (save! [this#]
-         (entity-save-helper this# ~datastore-entity-name)))))
-
-
-;; - Is type metadata necessary, or can it be determined at runtime?
-;;   It helps with optional checking, improves error messages.
-;;   Verify type behavior in general, e.g., dates.
-;; - Implement transactions.
-
-
-;; (query
-;;  :filter (filter-operator filter-property filter-value) ; can be a vector of filters
-;;  :sort (property direction)                             ; can specify multiples
-;;  :keys-only true                                        ; default is false
-;;  :kind "Person")
+         (save!-helper this# ~datastore-entity-name))
+       (save! [this# parent#]
+         (save!-helper this# ~datastore-entity-name :parent parent#)))))


1. added thread sleep

1. added thread sleep

--- src/clj/courtauction/component/crawler.clj
+++ src/clj/courtauction/component/crawler.clj
@@ -206,6 +206,7 @@
         )
       (log/log-message "sido=" sido ", sigu=" sigu
                        ", rows.count=" (count @courtauctions))
+      (Thread/sleep 1000)
       )
     )
   )


Separated regular routes and generating routes.

--- src/clj/mx/roads/forgotten/blog/routes.clj
+++ src/clj/mx/roads/forgotten/blog/routes.clj
@@ -17,19 +17,16 @@

 (defn static-routes
   []
-  (log/info "Generating pages for static pages ...")
   {"/blog/about.html" (page/about)})

 (defn design-routes
   []
-  (log/info "Generating pages for design pages ...")
   {"/blog/design/index.html" (page/design)
    "/blog/design/bootstrap-theme.html" (page/bootstrap-theme)
    "/blog/design/example-blog.html" (page/blog-example)})

 (defn post-routes
   [uri-base data]
-  (log/info "Generating pages for blog posts ...")
   (blog/get-indexed-archive-routes
     (map vector (iterate inc 0) data)
     :gen-func page/post
@@ -37,7 +34,6 @@

 (defn index-routes
   [data]
-  (log/info "Generating pages for front page, archives, categories, etc. ...")
   {"/blog/index.html" (page/front-page data)
    "/blog/archives/index.html" (page/archives data)
    "/blog/categories/index.html" (page/categories data)
@@ -46,7 +42,6 @@

 (defn reader-routes
   [uri-base data]
-  (log/info "Generating XML for feeds ...")
   (let [route "/blog/atom.xml"]
     {route (reader/atom-feed
              uri-base route (take (config/feed-count) data))}))
@@ -61,3 +56,51 @@
       (post-routes uri-base data)
       (index-routes data)
       (reader-routes uri-base data))))
+
+;;; Generator routes
+
+(defn gen-route
+  [func msg & args]
+  (log/info msg)
+  (apply func args))
+
+(def gen-static-routes
+  (partial
+    gen-route
+    static-routes
+    "Generating pages for static pages ..."))
+
+(def gen-design-routes
+  (partial
+    gen-route
+    design-routes
+    "Generating pages for design pages ..."))
+
+(def gen-post-routes
+  (partial
+    gen-route
+    post-routes
+    "Generating pages for blog posts ..."))
+
+(def gen-index-routes
+  (partial
+    gen-route
+    index-routes
+    "Generating pages for front page, archives, categories, etc. ..."))
+
+(def gen-reader-routes
+  (partial
+    gen-route
+    reader-routes
+    "Generating XML for feeds ..."))
+
+(defn gen-routes
+  [uri-base]
+  (let [data (blog/process uri-base)]
+    (log/trace "Got data:" (pprint (blog/data-minus-body data)))
+    (merge
+      (gen-static-routes)
+      (gen-design-routes)
+      (gen-post-routes uri-base data)
+      (gen-index-routes data)
+      (gen-reader-routes uri-base data))))


more error messageing

more error messageing

--- src/cljs/infinitelives/pixi/resources.cljs
+++ src/cljs/infinitelives/pixi/resources.cljs
@@ -83,9 +83,13 @@

 (defn get-texture
   ([key scale]
-   (scale (get @!texture-store key)))
+   (scale (or (get @!texture-store key)
+              (throw (js/Error. (str "Texture " key " not loaded"))))))
   ([key]
-   (get-texture key :nearest)))
+   (or
+    (get-texture key :nearest)
+    (throw (js/Error. (str "Texture " key " not loaded")))
+    )))

 ;; setup a pixi texture cache keyed by the tail of its filename
 (defn- register!


task line format

task line format

--- src/cljs/iwaswhere_web/ui/entry/utils.cljs
+++ src/cljs/iwaswhere_web/ui/entry/utils.cljs
@@ -26,7 +26,8 @@
             (text)
             (s/replace "#task" "")
             (s/replace "#habit" "")
-            (s/replace "##" "")
+            (s/replace "#" "")
+            (s/replace "@" "")
             s/trim
             s/split-lines
             first)))


Fix batch network dispatch

Fix batch network dispatch

--- src/com/wsscode/pathom/fulcro/network.cljc
+++ src/com/wsscode/pathom/fulcro/network.cljc
@@ -68,8 +68,8 @@
   interval."
   ([network] (batch-network network 10))
   ([network delay]
-    (let [send-fn (batch-send (fn [reqs]
-                                (doseq [{::keys [query ok err]} reqs]
-                                  (fulcro.network/send network query ok err)))
-                              delay)]
-      (map->BatchNetwork {:send-fn send-fn}))))
+   (let [send-fn (batch-send (fn [reqs]
+                               (doseq [{::keys [query ok err]} reqs]
+                                 (fulcro.network/send network query #(doseq [f ok] (f %)) #(doseq [f err] (f %)))))
+                             delay)]
+     (map->BatchNetwork {:send-fn send-fn}))))


add preconditions on 'bootstrap'

add preconditions on 'bootstrap'

--- src/puppetlabs/trapperkeeper/core.clj
+++ src/puppetlabs/trapperkeeper/core.clj
@@ -258,7 +258,9 @@
   Their must be a `:config` key in this map which defines the .ini file
   (or directory of files) used by the configuration service."
   [cli-data]
-  {:post [(instance? TrapperKeeperApp %)]}
+  {:pre [(map? cli-data)
+         (contains? cli-data :config)]
+  :post [(instance? TrapperKeeperApp %)]}
   (if-let [bootstrap-config (or (bootstrap/config-from-cli! cli-data)
                                   (bootstrap/config-from-cwd)
                                   (bootstrap/config-from-classpath))]


Revert "Fix recur in go-loop"

Revert "Fix recur in go-loop"

This reverts commit bd6adac02b3e45f92a2703858e87ee76ba372933.

--- src/status_im/utils/pre_receiver.cljs
+++ src/status_im/utils/pre_receiver.cljs
@@ -36,6 +36,6 @@
             (do (swap! seen disj [clock-value id])
                 (add-fn msg))
             (async/put! mature-ch msg))
-          (add-fn msg)))
-      (recur))
+          (add-fn msg))
+        (recur)))
     in-ch))


remove leftover debug log

remove leftover debug log

--- src/main/shadow/cljs/ui/db/generic.cljs
+++ src/main/shadow/cljs/ui/db/generic.cljs
@@ -20,7 +20,6 @@
 (defn init-data
   {::ev/handle ::init-data}
   [{:keys [db] :as env} {:keys [result]}]
-  (js/console.log "init-data" result)
   (let [{::m/keys [http-servers build-configs]}
         result


revise/audit new homepage naming scheme

revise/audit new homepage naming scheme

--- frontend/components/landing-b.cljs
+++ frontend/components/landing-b.cljs
@@ -22,33 +22,31 @@
       (let [ab-tests (:ab-tests app)
             controls-ch (om/get-shared owner [:comms :controls])]
         (html [:div.home.page
-               [:section.home-intro
-                [:a.intro-action {:role "button"}
+               [:section.home-prolog
+                [:a.prolog-action {:role "button"}
                  "Sign Up Free"]
-                [:div.intro-cover]
-                [:nav.intro-nav
-                 [:div.wrap
-                  [:a.intro-nav-promote "What is Continuous Integration?"]
-                  [:a.intro-nav-login "Log In"]]]
-                [:div.intro-branding
-                 [:div.wrap
-                  [:div.github-logo
+                [:div.prolog-cover]
+                [:div.prolog-navigation
+                 [:nav
+                  [:a.promo "What is Continuous Integration?"]
+                  [:a.login "Log In"]]]
+                [:div.prolog-logos
+                 [:div.avatars
+                  [:div.avatar-github
                    (common/ico :github)]
-                  [:div.circle-logo
+                  [:div.avatar-circle
                    (common/ico :logo)]]]
-                [:div.intro-slogan
-                 [:h1.slogan-tagline {:title "Your org needs a hero."
+                [:div.prolog-slogans
+                 [:h1.slogan.proverb {:title "Your org needs a hero."
                                       :alt "We just need authorization first."}
                   "Your org needs a hero."]
-                 [:h3.slogan-subline {:title "You have a product to focus on, let Circle handle your"
+                 [:h3.slogan.context {:title "You have a product to focus on, let Circle handle your"
                                       :alt "Why? Because signing up with your GitHub account lets Circle start your tests really fast."}
                   "You have a product to focus on, let Circle handle your"]
-                 [:h3.slogan-subline {:title "Continuous Integration & Deployment."
+                 [:h3.slogan.context {:title "Continuous Integration & Deployment."
                                       :alt "Note, without fine-grained scopes, GitHub requires us to request them in bulk."}
                   "Continuous Integration & Deployment."]]
-                ; [:a.intro-action-btn "Sign Up Free"]
-                ; [:div.intro-action-overlay]
-                [:div.intro-learn
+                [:div.prolog-learn
                  [:a
                   "Learn more"
                   (common/ico :chevron-down)]]]


better link for docker info in promo link

--- frontend/components/landing_b.cljs
+++ frontend/components/landing_b.cljs
@@ -166,7 +166,7 @@
                                  (when (:header-bkg-visible data) ["bkg-visible"])
                                  (when (:header-bkg-invisible data) ["bkg-invisible"])
                                  (when (:header-cta-invisible data) ["cta-invisible"]))}
-          [:a.promo {:href "http://blog.circleci.com/continuous-delivery-with-docker-containers/"}
+          [:a.promo {:href "integrations/docker"}
                                         ; "What is Continuous Integration?"
            "Learn how we support Docker."]
           [:a.login {:href (auth-url)


change headline to old one for now

change headline to old one for now

--- frontend/components/landing_b.cljs
+++ frontend/components/landing_b.cljs
@@ -230,9 +230,9 @@
                 [:div.home-cover]
                 [:div.home-top-shelf]
                 [:div.home-slogans
-                 [:h1.slogan.proverb {:title "Your org needs a hero."
+                 [:h1.slogan.proverb {:title "Ship better code, faster."
                                       :alt   "Let's just authorize first."}
-                  "Your org needs a hero."]
+                  "Ship better code, faster."]
                  [:h3.slogan.context {:title "You have a product to focus on, let Circle handle your"
                                       :alt   "Signing up using your GitHub login lets us start really fast."}
                   "You have a product to focus on, let Circle handle your"]
@@ -354,9 +354,9 @@
                 [:div.home-cover]
                 [:div.home-top-shelf]
                 [:div.home-slogans
-                 [:h1.slogan.proverb {:title "So, ready to be a hero?"
+                 [:h1.slogan.proverb {:title "So, ready to ship faster?"
                                       :alt   "Let's just authorize first."}
-                  "So, ready to be a hero?"]
+                  "So, ready to ship faster?"]
                  [:h3.slogan.context {:title "Next you'll just need to sign in using your GitHub account."
                                       :alt   "Signing up using your GitHub login lets us start really fast."}
                   "Next you'll just need to sign in using your GitHub account."]


Added exists? function to the Datastore API.

--- src/appengine_magic/services/datastore.clj
+++ src/appengine_magic/services/datastore.clj
@@ -2,6 +2,7 @@
   (:use appengine-magic.utils)
   (:import [com.google.appengine.api.datastore DatastoreService DatastoreServiceFactory
             DatastoreServiceConfig DatastoreServiceConfig$Builder
+            EntityNotFoundException
             ReadPolicy ReadPolicy$Consistency ImplicitTransactionManagementPolicy
             Key KeyFactory
             Entity
@@ -334,6 +335,15 @@
          (with-meta entity# {:key (get-key-object entity# parent#)}))))

+(defn exists? [entity-record-type key-value-or-values &
+               {:keys [parent kind]
+                :or {kind (unqualified-name (.getName entity-record-type))}}]
+  (try
+    (retrieve entity-record-type key-value-or-values :parent parent :kind kind)
+    true
+    (catch EntityNotFoundException _ false)))
+
+
 ;;; Note that the code relies on the API's implicit transaction tracking
 ;;; wherever possible, but the *current-transaction* value is still used for
 ;;; query construction.


Limit count & scroll to actual element counts.

--- src-cljs/pepa/workflows/dashboard.cljs
+++ src-cljs/pepa/workflows/dashboard.cljs
@@ -113,12 +113,14 @@
         outer-height (.-clientHeight container)
         bottom-distance (Math/abs (- scroll-height
                                      (+ scroll-top outer-height)))
-        progress (/ scroll-top scroll-height)]
+        progress (/ scroll-top scroll-height)
+        elements (document-ids state)]
     (let [[num scroll] (parse-count-scroll state)
           scroll (Math/ceil (* progress num))
           num (if (< bottom-distance +scroll-margin+)
                 (+ num +to-load+)
-                num)]
+                num)
+          num (min num (count elements))]
       (-> (:navigation state)
           (assoc-in [:query-params :count] (str num))
           (assoc-in [:query-params :scroll] (str scroll))
@@ -129,10 +131,11 @@
 (defn scroll-to-offset! [state owner]
   (let [el (om/get-node owner "documents")
         scroll-height (.-scrollHeight el)
-        [num scroll] (parse-count-scroll state)]
+        [num scroll] (parse-count-scroll state)
+        elements (page-ids state)]
     (when (= 0 (.-scrollTop el))
       (set! (.-scrollTop el) (* scroll-height
-                                (/ scroll num))))))
+                                (/ scroll (count elements)))))))

 (defn dashboard [state owner]
   (reify


Uncomment background in Spaceship example.

--- src/cljs/quil_site/examples/spaceship.cljs
+++ src/cljs/quil_site/examples/spaceship.cljs
@@ -75,7 +75,7 @@
       (q/background 255)

       ; Draw background and back stars
-;      (draw-image state :bg [0 0])
+      (draw-image state :bg [0 0])
       (draw-stars state (:stars2 state))

       ; Slightly move and rotate spaceship


add func on modal close

add func on modal close

--- src/cljs/salava/social/ui/connections.cljs
+++ src/cljs/salava/social/ui/connections.cljs
@@ -68,7 +68,7 @@
                                          :alt name}]]
                   [:td.name [:a {:href "#"
                                  :on-click #(do
-                                              (mo/open-modal [:gallery :badges] {:badge-id id})
+                                              (mo/open-modal [:gallery :badges] {:badge-id id} {:hide (fn [] (init-data state))})
                                               ;(b/open-modal id false init-data state)
                                               (.preventDefault %)) } name]]
                    [:td.action (unfollow id state)]


Add backlog feature

Add backlog feature

--- org-mode/src/com/gfredericks/org_agenda.clj
+++ org-mode/src/com/gfredericks/org_agenda.clj
@@ -160,6 +160,7 @@
                                                 (* 60 (Long/parseLong hours))))))
               scheduled (get-timestamp scheduled-finder true)
               deadline  (get-timestamp deadline-finder true)
+              tags (reduce into #{} tags-with-ancestors)
               base (with-meta
                      {:todo               (if (contains? DONE-states todo) nil todo)
                       :done               (if (contains? DONE-states todo) todo)
@@ -181,8 +182,9 @@
                       :priority-cookie    priority-cookie
                       :parent-is-ordered? (-> props-with-ancestors second (get "ORDERED") (= "t"))
                       :properties         (first props-with-ancestors)
-                      :tags               (reduce into #{} tags-with-ancestors)
-                      :effort             effort}
+                      :tags               tags
+                      :effort             effort
+                      :backlog?           (contains? tags "backlog")}
                      {:raw-section section})
               date-range (->> prelude
                               (keep (fn [line]
@@ -306,37 +308,38 @@
           all-items (->> (all-sections file)
                          (mapcat #(parse-section-for-agenda % file-str today)))
           calendar-events (->> all-items
-                               (filter calendar-event?))]
-      {:todos (->> all-items
-                   (filter :todo)
-                   (map (fn [todo]
-                          (let [search (conj (:ancestor-headers todo) (:raw-header todo))]
-                            (assoc todo
-                                   :descendent-TODOs?
-                                   (->> all-items
-                                        (filter :todo)
-                                        (some (fn [todo]
-                                                (= search (take (count search)
-                                                                (:ancestor-headers todo)))))
-                                        (boolean))
-                                   :shadowed-by-sibling?
-                                   ;; figure out if its parent has "ORDERED" set and
-                                   ;; a prior sibling has "TODO"
-                                   (boolean
-                                    (and (:parent-is-ordered? todo)
-                                         (->> all-items
-                                              (filter :todo)
-                                              (some (fn [todo2]
-                                                      (and (= (:ancestor-headers todo)
-                                                              (:ancestor-headers todo2))
-                                                           (< (:line-number todo2)
-                                                              (:line-number todo)))))))))))))
+                               (filter calendar-event?))
+          todos (->> all-items
+                     (filter :todo)
+                     (map (fn [todo]
+                            (let [search (conj (:ancestor-headers todo) (:raw-header todo))]
+                              (assoc todo
+                                     :descendent-TODOs?
+                                     (->> all-items
+                                          (filter :todo)
+                                          (some (fn [todo]
+                                                  (= search (take (count search)
+                                                                  (:ancestor-headers todo)))))
+                                          (boolean))
+                                     :shadowed-by-sibling?
+                                     ;; figure out if its parent has "ORDERED" set and
+                                     ;; a prior sibling has "TODO"
+                                     (boolean
+                                      (and (:parent-is-ordered? todo)
+                                           (->> all-items
+                                                (filter :todo)
+                                                (some (fn [todo2]
+                                                        (and (= (:ancestor-headers todo)
+                                                                (:ancestor-headers todo2))
+                                                             (< (:line-number todo2)
+                                                                (:line-number todo)))))))))))))]
+      {:todos   todos
        :todones (->> all-items
                      (filter :done))
        :calendar-events calendar-events})
     (catch FileNotFoundException e
       (log/warn "FileNotFoundException")
-      {:todos [] :todones []  :calendar-events []})))
+      {:todos [] :todones [] :calendar-events []})))

 (defn synthesize-agenda
@@ -352,13 +355,15 @@
                                    :priority-cookie
                                    (re-find #"\d")))
                  (remove #(contains? (:tags %) "slow"))
-                 (keep (fn [{:keys [todo header deadline] :as item}]
-                         (if (and deadline (compare/<= (to-local-date deadline) today))
-                           {:deadlines #{item}}
-                           (if-let [d (relevant-date item)]
-                             (if-not (compare/< today+10 d)
-                               {(compare/max today d) #{item}})
-                             {:triage #{item}}))))
+                 (keep (fn [{:keys [todo header deadline backlog?] :as item}]
+                         (if backlog?
+                           {:backlog #{item}}
+                           (if (and deadline (compare/<= (to-local-date deadline) today))
+                             {:deadlines #{item}}
+                             (if-let [d (relevant-date item)]
+                               (if-not (compare/< today+10 d)
+                                 {(compare/max today d) #{item}})
+                               {:triage #{item}})))))
                  (apply merge-with into))
           calendar-events (->> deets-by-file
                                vals
@@ -393,7 +398,8 @@
                            [day {:todos (get m day [])
                                  :calendar-events (get calendar-events day [])
                                  :past-log (get past-log day [])}]))
-                    (into {}))})))
+                    (into {}))
+       :backlog (:backlog m)})))

 (let [p (re-pattern (format (str #"(?:%s )?(.*)")
                             (str TODO-state-pattern)))]
@@ -530,7 +536,7 @@
                                                 ;; once we figure out enough elisp to stop using links this
                                                 ;; can just be implicit
                                                 (make-org-link item "(link)")))))))
-        {:keys [deadlines triage today future past]} agenda]
+        {:keys [deadlines triage today future past backlog]} agenda]
     (with-atomic-write-to cfg
       (when-let [preamble (:preamble cfg)]
         (println (cond (string? preamble)
@@ -599,12 +605,18 @@
         (println (format "== LOG: %s ==" (format-org-local-date date)))
         (print-calendar calendar-events)
         (doseq [item past-log]
-          (print-todo-line item {:omit-effort? true}))))))
+          (print-todo-line item {:omit-effort? true})))
+      (when (seq backlog)
+        (println "\n\n--------------------------------------------------------------------------------")
+        (println "|                                   backlog                                    |")
+        (println "--------------------------------------------------------------------------------")
+        (doseq [item backlog]
+          (print-todo-line item {}))))))

 (defn calculate-agenda
   [deets-by-file cfg now]
   (let [today (.toLocalDate now)
-        {:keys [triage deadlines by-day past-log]} (synthesize-agenda deets-by-file today)
+        {:keys [triage deadlines by-day past-log backlog]} (synthesize-agenda deets-by-file today)
         custom-prefix (:custom-prefix cfg (constantly nil))
         stats-by-date (into {}
                             (for [[date {:keys [todos calendar-events]}] (sort by-day)
@@ -646,9 +658,11 @@
                                                              t2 (some-> t2 .toLocalTime)]
                                                          (assoc item
                                                                 :timetable-slot [t1 t2]
-                                                                :past? past?)))))}])]
-    {:deadlines (sort-by (juxt (comp - priority) :created-at :file :line-number) deadlines)
-     :triage    (sort-by (juxt (comp - priority) :created-at :file :line-number) triage)
+                                                                :past? past?)))))}])
+        sort-key (juxt (comp - priority) :created-at :file :line-number)]
+    {:deadlines (sort-by sort-key deadlines)
+     :triage    (sort-by sort-key triage)
+     :backlog   (sort-by sort-key backlog)
      :today     (second (first not-past))
      :future    (rest not-past)
      :past      (for [[date :as date+item] (reverse (sort by-day))


More on EL-gfp lcs computation

More on EL-gfp lcs computation

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

--- src/conexp/contrib/dl/languages/EL_gfp.clj
+++ src/conexp/contrib/dl/languages/EL_gfp.clj
@@ -76,28 +76,37 @@
   [tbox concepts]
   (when (empty? concepts)
     (illegal-argument "EL-gfp-lcs called with no concepts."))
-  (let [G_T-tbox (tbox->description-graph tbox)]
-    (loop [new-tbox tbox,
-           concepts (sort-by #(let [dl-expr (definition-expression (find-definition tbox %))]
-                                (count (filter compound? (arguments dl-expr))))
-                             concepts)]
-      (if (= 1 (count concepts))
-        (let [new-tbox (description-graph->tbox (tbox->description-graph new-tbox))]
-          (println (find-definition new-tbox (first concepts)))
-          (clarify-ttp [new-tbox (first concepts)]))
-        (let [A     (first concepts),
-              B     (second concepts),
-              G_T_A (description-graph-component (tbox->description-graph new-tbox) A),
-              G_T_B (description-graph-component G_T-tbox B)
-              G-x-G (graph-product G_T_A G_T-tbox [A,B]),
-              _ (println "CHECK 1" (count concepts))_(flush)
-              T_2   (description-graph->tbox G-x-G),
-              _ (println "CHECK 2")_(flush)
-              [new-tbox new-target] (uniquify-ttp (clarify-ttp (tidy-up-ttp [T_2, [A,B]])))]
-          (if (empty? (arguments (definition-expression (find-definition new-tbox new-target))))
-            [new-tbox new-target]
-            (recur new-tbox
-                   (conj (nthnext concepts 2) new-target))))))))
+  (if (= 1 (count concepts))
+    [tbox (first concepts)]
+    (let [G_T-tbox (tbox->description-graph tbox),
+          concepts (sort-by #(let [dl-expr (definition-expression (find-definition tbox %))]
+                               (count (filter compound? (arguments dl-expr))))
+                            concepts)]
+      (loop [G_T      (description-graph-component G_T-tbox (first concepts))
+             concepts concepts]
+        (if (= 1 (count concepts))
+          (let [new-tbox              (description-graph->tbox G_T),
+                new-target            (first concepts)
+                [new-tbox new-target] (clarify-ttp (uniquify-ttp [new-tbox new-target]))]
+            (println "LCS CHECK 2")
+            (println (find-definition new-tbox new-target))
+            [new-tbox new-target])
+          (let [A     (first concepts),
+                B     (second concepts),
+                G_T_A G_T,
+                G_T_B (description-graph-component G_T-tbox B)
+                _ (println "LCS CHECK 3" (count concepts))_(flush)
+                _ (if (>= 4 (count concepts)) (println concepts))
+                G-x-G (graph-product G_T_A G_T_B [A,B]),
+
+                [tbox target] (tidy-up-ttp (uniquify-ttp [(description-graph->tbox G-x-G) [A,B]]))]
+            (println "LCS CHECK 1")
+            (flush)
+            (if (and (singleton? (vertices G-x-G))
+                     (empty? ((vertex-labels G-x-G) [A,B])))
+              [(conexp.contrib.dl.framework.boxes/tbox (tbox-language tbox) A (and)) 'A]
+              (recur (tbox->description-graph tbox)
+                     (conj (nthnext concepts 2) target)))))))))

 (defn EL-gfp-msc
   "Returns the model based most specific concept of objects in model."
@@ -119,7 +128,6 @@
                           tidy-up-ttp
                           reduce-ttp
                           normalize-EL-gfp-term)]
-    (println "CHECK 3")(flush)
     (if (acyclic? tbox)
       (definition-expression (first (tbox-definitions tbox)))
       (make-dl-expression-nc (interpretation-language model) [tbox target]))))


Format dictionary interface by zprint

Format dictionary interface by zprint

--- src/zg/dictionary_interface.clj
+++ src/zg/dictionary_interface.clj
@@ -11,59 +11,77 @@
 ;

 (ns zg.dictionary-interface
-    "Functions providing dictionary interface.")
+  "Functions providing dictionary interface.")

 (require '[clojure.tools.logging   :as log])

 (require '[zg.db-interface         :as db-interface])

 (defn proper-word-for-blacklist?
-    [word]
-    (re-matches #"[A-Za-z0-9.'\-\s_/]+" word))
+  [word]
+  (re-matches #"[A-Za-z0-9.'\-\s_/]+" word))

 (defn proper-word-for-whitelist?
-    [word]
-    (re-matches #"[A-Za-z0-9.'\-\s_]+" word))
+  [word]
+  (re-matches #"[A-Za-z0-9.'\-\s_]+" word))

 (defn process-use-it
-    [use-it]
-    (condp = use-it
-        "Yes" 1
-        "No"  0
-              2))
+  [use-it]
+  (condp = use-it
+      "Yes" 1
+      "No"  0
+            2))

 (defn process-class
-    [class]
-    (condp = (.toLowerCase class)
-        "N/A" nil
-        "n/a" nil
-        "verb" 1
-        "noun" 2
-        "adverb" 3
-        "adjective" 4
-        "pronoun" 5
-        "conjunction"  6
-        "preposition"  7
-        "interjection" 8
-        "article"      9
-        "numeral"      10
-        "determiner"  11
-        "exclamation" 12))
+  [class]
+  (condp = (.toLowerCase class)
+    "N/A" nil
+    "n/a" nil
+    "verb" 1
+    "noun" 2
+    "adverb" 3
+    "adjective" 4
+    "pronoun" 5
+    "conjunction" 6
+    "preposition" 7
+    "interjection" 8
+    "article" 9
+    "numeral" 10
+    "determiner" 11
+    "exclamation" 12))

 (defn store-word
-    "Store one word into the dictionary."
-    ([word correct-form description user-name dictionary-type]
-    (log/info "About to store following word:" word " with description: " description " and/or correct form: " correct-form
+  "Store one word into the dictionary."
+  ([word correct-form description user-name dictionary-type]
+   (log/info "About to store following word:" word
+             " with description: " description
+             " and/or correct form: " correct-form
              " into dictionary: " (str dictionary-type))
-    (db-interface/add-new-word-into-dictionary word correct-form description (or user-name "(*unknown*)") dictionary-type))
-    ([word description class use-it internal copyright source correct-forms incorrect-forms user-name dictionary-type]
-    (log/info "About to store following word:" word " with description: " description " into dictionary: " (str dictionary-type))
-    (db-interface/add-new-word-into-dictionary word description (process-class class) (process-use-it use-it) internal copyright (inc source) correct-forms incorrect-forms (or user-name "(*unknown*)") dictionary-type)))
+   (db-interface/add-new-word-into-dictionary word
+                                              correct-form
+                                              description
+                                              (or user-name "(*unknown*)")
+                                              dictionary-type))
+  ([word description class use-it internal copyright source correct-forms incorrect-forms user-name dictionary-type]
+   (log/info "About to store following word:" word
+             " with description: " description
+             " into dictionary: " (str dictionary-type))
+   (db-interface/add-new-word-into-dictionary word
+                                              description
+                                              (process-class class)
+                                              (process-use-it use-it)
+                                              internal
+                                              copyright
+                                              (inc source)
+                                              correct-forms
+                                              incorrect-forms
+                                              (or user-name "(*unknown*)")
+                                              dictionary-type)))

 (defn store-words
-    "Store sequence of words into the dictionary."
-    [words user-name dictionary-type]
-    (log/info "About to store following words:" words)
-    (doseq [word words]
-        (db-interface/add-new-word-into-dictionary word user-name dictionary-type)))
+  "Store sequence of words into the dictionary."
+  [words user-name dictionary-type]
+  (log/info "About to store following words:" words)
+  (doseq [word words]
+    (db-interface/add-new-word-into-dictionary word user-name dictionary-type)))


Add util/def-

Add util/def-

--- cortex/src/cortex/util.cljc
+++ cortex/src/cortex/util.cljc
@@ -13,6 +13,13 @@

 #?(:clj (do (set! *warn-on-reflection* true)
             (set! *unchecked-math* :warn-on-boxed)))
+
+;;;; Vars
+
+(defmacro def-
+  "same as def, yielding non-public def"
+  [name & decls]
+  (list* `def (with-meta name (assoc (meta name) :private true)) decls))

 ;;;; Mathematics


Tests for functions: render-edn-data, add-new-results, and store-results

--- test/emender_jenkins/results_test.clj
+++ test/emender_jenkins/results_test.clj
@@ -23,3 +23,22 @@
     [function-name]
     (clojure.test/function? function-name))

+
+(deftest test-render-edn-data-existence
+    "Check that the emender-jenkins.results/render-edn-data definition exists."
+    (testing "if the emender-jenkins.results/render-edn-data definition exists."
+        (is (callable? 'emender-jenkins.results/render-edn-data))))
+
+
+(deftest test-add-new-results-existence
+    "Check that the emender-jenkins.results/add-new-results definition exists."
+    (testing "if the emender-jenkins.results/add-new-results definition exists."
+        (is (callable? 'emender-jenkins.results/add-new-results))))
+
+
+(deftest test-store-results-existence
+    "Check that the emender-jenkins.results/store-results definition exists."
+    (testing "if the emender-jenkins.results/store-results definition exists."
+        (is (callable? 'emender-jenkins.results/store-results))))
+
+


Adapt colors nav tabs to be consistent with the rest of the pages.

--- src/uxbox/main/ui/dashboard/colors.cljs
+++ src/uxbox/main/ui/dashboard/colors.cljs
@@ -239,12 +239,12 @@
       [:div.library-bar
        [:div.library-bar-inside
         [:ul.library-tabs
+         [:li {:class-name (when own? "current")
+               :on-click (partial select-tab :own)}
+          "YOUR COLORS"]
          [:li {:class-name (when builtin? "current")
                :on-click (partial select-tab :builtin)}
-          "STANDARD"]
-         [:li {:class-name (when own? "current")
-               :on-click (partial select-tab :own)}
-          "YOUR LIBRARIES"]]
+          "COLORS STORE"]]
         (nav-collections type selected)]])))

 ;; --- Colors Page


Remove unused whitespaces.

Remove unused whitespaces.

--- src/uxbox/main/ui/workspace/canvas.cljs
+++ src/uxbox/main/ui/workspace/canvas.cljs
@@ -140,11 +140,9 @@
         zoom (or (:zoom workspace) 1)]
     (letfn [(on-mouse-down [event]
               (dom/stop-propagation event)
-
               (let [opts {:shift? (kbd/shift? event)
                           :ctrl? (kbd/ctrl? event)}]
                 (rx/push! wb/events-b [:mouse/down opts]))
-
               (if (:drawing workspace)
                 (rlocks/acquire! :ui/draw)
                 (do


Use mapcat to neaten the repeats in the time.

--- src/overtunes/songs/canone_alla_quarta.clj
+++ src/overtunes/songs/canone_alla_quarta.clj
@@ -46,13 +46,13 @@

 (def leader
   (let [call
-          {:time (concat (repeat 2 1/4) [1/2] (repeat 14 1/4) [3/2])
+          {:time (mapcat repeat [2 1 14 1] [1/4 1/2 1/4 3/2])
            :pitch (concat [0] (run -1 3) (run 2 0) [4] (run 1 8))}
         response
-          {:time (concat (repeat 10 1/4) [1/2] (repeat 2 1/4) [9/4])
+          {:time (mapcat repeat [10 1 2 1]  [1/4 1/2 1/4 9/4])
            :pitch (concat (run 7 -1) [0] (run 0 -3))}
         development
-          {:time (concat [3/4] (repeat 12 1/4) [1/2 1 1/2] (repeat 12 1/4) [3])
+          {:time (mapcat repeat [1 12 1 1 1 12 1] [3/4 1/4 1/2 1 1/2 1/4 3])
            :pitch (concat [4 4] (run 2 -3) [-1 -2 0] (run 3 5) (repeat 3 1) [2] (run -1 1) [0 -1] (run 5 0))}
         line
           (merge-with concat call response development)]


Specify flats and sharps inline.

Specify flats and sharps inline.

--- src/overtunes/songs/canone_alla_quarta.clj
+++ src/overtunes/songs/canone_alla_quarta.clj
@@ -85,12 +85,11 @@
   (let [from-now #(translate % 0 (now))
         with-beat (update :time (partial connect (from-now (bpm 90))))
         in #(update :pitch (partial connect %))
-        with-bass-accidentals (update :pitch (partial sharps [8]))
-        with-leader-accidentals (connect (update :pitch (partial sharps [22 32])) (update :pitch (partial flats [37])))
-        after-a-half (after 1/2)]
-    (=> bass (in g-major) with-bass-accidentals with-beat melody#)
+        with-sharps #(update :pitch (partial sharps %))
+        with-flats #(update :pitch (partial flats %))]
+    (=> bass (in g-major) (with-sharps [8]) with-beat melody#)
     (=> leader (after 1/2) canone-alla-quarta (in g-major) with-beat melody#)
-    (=> leader (after 1/2) (in g-major) with-leader-accidentals with-beat melody#)
+    (=> leader (after 1/2) (in g-major) (with-sharps [22 32]) (with-flats [37]) with-beat melody#)
     ))

 (play#)


Add cue to tie rainbow to just main rig.

--- src/afterglow/examples.clj
+++ src/afterglow/examples.clj
@@ -785,6 +785,9 @@
   [page-x page-y]
   (let [x-base (* page-x 8)
         y-base (* page-y 8)
+        rig-left (:x (first (show/fixtures-named :hex-2)))
+        rig-right (:x (first (show/fixtures-named :hex-1)))
+        rig-width (- rig-right rig-left)
         hue-bar (oscillators/build-oscillated-param  ; Spread a rainbow across a bar of music
                  (oscillators/sawtooth :interval :bar) :max 360)
         desat-beat (oscillators/build-oscillated-param  ; Desaturate a color as a beat progresses
@@ -792,6 +795,9 @@
         hue-gradient (params/build-spatial-param  ; Spread a rainbow across the light grid
                       (show/all-fixtures)
                       (fn [head] (- (:x head) (:min-x @(:dimensions *show*)))) :max 360)
+        rig-hue-gradient (params/build-spatial-param  ; Spread a rainbow across just the main rig, repeating
+                          (show/all-fixtures)         ; beyond that, irrespective of other lights' positions.
+                          (fn [head] (colors/clamp-hue (* 360 (/ (- (:x head) rig-left) rig-width)))))
         hue-z-gradient (params/build-spatial-param  ; Spread a rainbow across the light grid front to back
                         (show/all-fixtures)
                         (fn [head] (- (:z head) (:min-z @(:dimensions *show*)))) :max 360)]
@@ -819,9 +825,10 @@
                                             :type :integer}])))
     (show/set-cue! (+ x-base 1) (+ y-base 1)
                    (cues/cue :all-color (fn [_] (global-color-effect
-                                                 (params/build-color-param :s :rainbow-saturation :l 50 :h hue-gradient)
+                                                 (params/build-color-param :s :rainbow-saturation :l 50
+                                                                           :h rig-hue-gradient)
                                                  :include-color-wheels? true))
-                             :short-name "Rainbow Grid"
+                             :short-name "Rainbow Rig"
                              :variables [{:key :rainbow-saturation :name "Saturatn" :min 0 :max 100 :start 100
                                           :type :integer}]))
     (show/set-cue! (+ x-base 2) (+ y-base 1)


Use semantic HTML.

Use semantic HTML.

--- src/airhead_cljs/core.cljs
+++ src/airhead_cljs/core.cljs
@@ -70,27 +70,27 @@
     (let [title   (get-in @state [:info "name"])
           message (get-in @state [:info "greet_message"])
           url     (get-in @state [:info "stream_url"])]
-      [:div.info
+      [:section#info
        [:h1 title]
-       [:div.greet-message message]
-       [:div.player [:audio {:src url
-                             :controls "controls"}]]])))
+       [:p message]
+       [:audio {:src url
+                :controls "controls"}]])))

 (defn upload-component []
-  [:div.upload
+  [:section#upload
    [:h2 "Upload"]
-   [:form {:id "upload-form"}
+   [:form {:id "upload"}
     [:input {:type "file" :name "track"}]
-    [:input {:type "button" :value "Upload" :on-click upload!}]]
-   [:div.upload-status (@state :upload-status)]])
+    [:input {:type "button" :value "Upload" :on-submit upload!}]]
+   [:p (@state :upload-status)]])

 (defn playlist-add-component [track]
-  [:input.add-button
+  [:input.add
    {:type "button" :value "+"
     :on-click #(playlist-add (track "uuid"))}])

 (defn playlist-remove-component [track]
-  [:input.add-button
+  [:input.remove
    {:type "button" :value "-"
     :on-click #(playlist-remove (track "uuid"))}])

@@ -101,12 +101,12 @@
      "-")])

 (defn now-playing-component []
-  [:div.now-playing
+  [:p
    [:span "Now playing:"]
    [track-component (get-in @state [:playlist "current"])]])

 (defn next-component []
-  [:div.next
+  [:section
    [:span "Next:"]
    [:ul
     (for [track (get-in @state [:playlist "next"])]
@@ -115,7 +115,7 @@
        [track-component track]])]])

 (defn playlist-component []
-  [:div.playlist
+  [:section#playlist
    [:h2 "Playlist"]
    [now-playing-component]
    [next-component]])
@@ -125,14 +125,16 @@
   (swap! state assoc :query (-> e .-target .-value)))

 (defn search-component []
-  [:div.search
-   [:span "Serach:"]
-   [:input {:type "text"
-            :value (@state :query)
-            :on-change on-query-change}]])
+  [:section#search
+   [:form
+    [:label {:for "query"} "Search:"]
+    [:input {:type "text"
+             :id "query"
+             :value (@state :query)
+             :on-change on-query-change}]]])

 (defn library-component []
-  [:div.library
+  [:section#library
    [:h2 "Library"]
    [search-component]
    [:ul (for [track (@state :library)]
@@ -141,7 +143,7 @@
            [track-component track]])]])

 (defn page-component []
-  [:div.page
+  [:main
    [info-component]
    [upload-component]
    [playlist-component]


added metrics for state events

added metrics for state events

--- core/src/samsara_core/kernel.clj
+++ core/src/samsara_core/kernel.clj
@@ -181,12 +181,13 @@
   [stream ^String event]
   ;; this ugly stuff works because *stores* is thread-local
   (printf-stream "STATE[%s] : %s\n" stream event)
-  (let [kv-store (get *stores* stream)]
-    (var-set kv-store
-             (->> event
-                  from-json
-                  vector
-                  (kv/restore (var-get kv-store))))))
+  (track-time (str "pipeline.stores.local." stream ".restore.time")
+    (let [kv-store (get *stores* stream)]
+      (var-set kv-store
+               (->> event
+                    from-json
+                    vector
+                    (kv/restore (var-get kv-store)))))))

@@ -195,13 +196,14 @@
    it pushes the change to the running *global-stores*"
   [stream ^String event]
   (printf-stream "GLOBAL[%s] : %s\n" stream event)
-  (let [txlog (->> event from-json vector)]
-    (swap! *global-stores*
-           update
-           stream
-           (fn [kvstore]
-             (kv/restore (or kvstore (kv/make-in-memory-kvstore))
-                         txlog)))))
+  (track-time (str "pipeline.stores.global." stream ".restore.time")
+   (let [txlog (->> event from-json vector)]
+     (swap! *global-stores*
+            update
+            stream
+            (fn [kvstore]
+              (kv/restore (or kvstore (kv/make-in-memory-kvstore))
+                          txlog))))))

 (defn process-dispatch


Fix display-results to check for old recordings.

--- src/beebster_clj/views.clj
+++ src/beebster_clj/views.clj
@@ -78,7 +78,7 @@
    (nil? resultlist)
    (html
     [:p "No matches foudn."])
-   (old-recordings? (first resultlist))
+   (some #(re-find #"These programmes should" %) resultlist)
    (html
     (for [i resultlist]
       [:p (str i)]))
@@ -92,10 +92,10 @@
           [:div.table
            [:div.tablecell
             [:div.t1
-             [:a {:href (get-url (nth ind a))}
-              [:img.img {:src (first i)}]]]
+             [:a {:href (get-url (nth ind a)) :alt (nth desc a)}
+              [:img.img {:src i}]]]
             [:div.t1
-             (str (first (nth desc a)))]]]))
+             (str (nth desc a))]]]))
       [:div.clear " "]))))

 (defn category-page


Add header to download page.

Add header to download page.

--- src/beebster_clj/views.clj
+++ src/beebster_clj/views.clj
@@ -150,4 +150,7 @@
   [index mode]
   (let [prog (future (apply sh  (iplayer-download-command index mode)))]
     (html
-     [:p (apply str "Downloading " index mode)])))
+     (base-template "Download")
+     (header '(("/" "search") ("/about" "about")))
+     [:div.download
+      [:p (apply str "Downloading programme with index: " index )]])))


[scamp] Add new MessageTypes to schema; drop MessageBodySchema

--- modules/scamp/src/scamp/core.clj
+++ modules/scamp/src/scamp/core.clj
@@ -48,9 +48,13 @@
    :downstream NodeNeighborsSchema
    :messages-seen {MessageEnvelopeIdSchema s/Int}})

-(def MessageTypeSchema
+(def MessageTypesSchema
   (s/enum :forwarded-subscription
-          :new-upstream-node))
+          :new-upstream-node
+          :node-unsubscription ;; currently only for self-unsubscription
+          :node-replacement
+          :node-removal
+          ))

 (def SubscriptionSchema
   NodeContactAddressSchema)
@@ -71,15 +75,12 @@
     (println :preds preds)
     (s/pred #(some nil? preds))))

-(def MessageBodySchema
-  (s/pred #(some nil?
-                 [(s/check SubscriptionSchema %)])))

 (def MessageEnvelopeSchema
   [(s/one (s/eq :message-envelope) "envelope variant type")
    (s/one NodeContactAddressSchema "envelope destination")
-   (s/one MessageTypeSchema "envelope message type")
-   (s/one MessageBodySchema "envelope body")
+   (s/one MessageTypesSchema "envelope message type")
+   (s/one s/Any "envelope body")
    (s/one MessageEnvelopeIdSchema "envelope id")])

 (def WorldConfigSchema


Fix monitoring tags for non namespaced tasks.

--- src/onyx/monitoring/metrics_monitoring.clj
+++ src/onyx/monitoring/metrics_monitoring.clj
@@ -233,7 +233,9 @@
     (.set ^AtomicLong epoch (task/epoch state))))

 (defn cleanup-keyword [k]
-  (str (namespace k) "/" (name k)))
+  (if-let [n (namespace k)]
+    (str n "/" (name k))
+    (name k)))

 (defn normalize-tag [tag]
   (-> tag


Better tests for the static files

Better tests for the static files

--- test/cljc/reitit/ring_test.cljc
+++ test/cljc/reitit/ring_test.cljc
@@ -3,7 +3,8 @@
             [clojure.set :as set]
             [reitit.middleware :as middleware]
             [reitit.ring :as ring]
-            [reitit.core :as r])
+            [reitit.core :as r]
+            [clojure.string :as str])
   #?(:clj
      (:import (clojure.lang ExceptionInfo))))

@@ -267,56 +268,154 @@

 #?(:clj
    (deftest resource-handler-test
-     (doseq [[test app] [["inside a router"
-                          (ring/ring-handler
-                            (ring/router
-                              [["/ping" (constantly {:status 200, :body "pong"})]
-                               ["/files/*" (ring/create-resource-handler)]
-                               ["/*" (ring/create-resource-handler)]]
-                              {:conflicts (constantly nil)})
-                            (ring/create-default-handler))]
-
-                         ["outside of a router"
-                          (ring/ring-handler
-                            (ring/router
-                              ["/ping" (constantly {:status 200, :body "pong"})])
-                            (ring/routes
-                              (ring/create-resource-handler {:path "/files"})
-                              (ring/create-resource-handler {:path "/"})
-                              (ring/create-default-handler)))]]
-             prefix ["" "/" "/files" "/files/"]
-             :let [request (fn [uri] {:uri (str prefix uri), :request-method :get})]]
-
-       (testing test
-         (testing "different file-types"
-           (let [response (app (request "/hello.json"))]
-             (is (= "application/json" (get-in response [:headers "Content-Type"])))
-             (is (get-in response [:headers "Last-Modified"]))
-             (is (= "{\"hello\": \"file\"}" (slurp (:body response)))))
-           (let [response (app (request "/hello.xml"))]
-             (is (= "text/xml" (get-in response [:headers "Content-Type"])))
-             (is (get-in response [:headers "Last-Modified"]))
-             (is (= "<xml><hello>file</hello></xml>\n" (slurp (:body response))))))
-
-         (testing "index-files"
-           (let [response (app (request "/docs"))]
-             (is (= "text/html" (get-in response [:headers "Content-Type"])))
-             (is (get-in response [:headers "Last-Modified"]))
-             (is (= "
hello
\n" (slurp (:body response)))))
-           (let [response (app (request "/docs/"))]
-             (is (= "text/html" (get-in response [:headers "Content-Type"])))
-             (is (get-in response [:headers "Last-Modified"]))
-             (is (= "
hello
\n" (slurp (:body response))))))
-
-         (testing "not found"
-           (let [response (app (request "/not-found"))]
-             (is (= 404 (:status response)))))
-
-         (testing "3-arity"
-           (let [result (atom nil)
-                 respond (partial reset! result)
-                 raise ::not-called]
-             (app (request "/hello.xml") respond raise)
-             (is (= "text/xml" (get-in @result [:headers "Content-Type"])))
-             (is (get-in @result [:headers "Last-Modified"]))
-             (is (= "<xml><hello>file</hello></xml>\n" (slurp (:body @result))))))))))
+     (let [redirect (fn [uri] {:status 302 :headers {"Location" uri}})
+           request (fn [uri] {:uri uri, :request-method :get})]
+       (testing "inside a router"
+
+         (testing "from root"
+           (let [app (ring/ring-handler
+                       (ring/router
+                         ["/*" (ring/create-resource-handler)])
+                       (ring/create-default-handler))]
+             (testing test
+               (testing "different file-types"
+                 (let [response (app (request "/hello.json"))]
+                   (is (= "application/json" (get-in response [:headers "Content-Type"])))
+                   (is (get-in response [:headers "Last-Modified"]))
+                   (is (= "{\"hello\": \"file\"}" (slurp (:body response)))))
+                 (let [response (app (request "/hello.xml"))]
+                   (is (= "text/xml" (get-in response [:headers "Content-Type"])))
+                   (is (get-in response [:headers "Last-Modified"]))
+                   (is (= "<xml><hello>file</hello></xml>\n" (slurp (:body response))))))
+
+               (testing "index-files"
+                 (let [response (app (request "/docs"))]
+                   (is (= (redirect "/docs/index.html") response)))
+                 (let [response (app (request "/docs/"))]
+                   (is (= (redirect "/docs/index.html") response))))
+
+               (testing "not found"
+                 (let [response (app (request "/not-found"))]
+                   (is (= 404 (:status response)))))
+
+               (testing "3-arity"
+                 (let [result (atom nil)
+                       respond (partial reset! result)
+                       raise ::not-called]
+                   (app (request "/hello.xml") respond raise)
+                   (is (= "text/xml" (get-in @result [:headers "Content-Type"])))
+                   (is (get-in @result [:headers "Last-Modified"]))
+                   (is (= "<xml><hello>file</hello></xml>\n" (slurp (:body @result)))))))))
+
+         (testing "from path"
+           (let [app (ring/ring-handler
+                       (ring/router
+                         ["/files/*" (ring/create-resource-handler)])
+                       (ring/create-default-handler))
+                 request #(request (str "/files" %))
+                 redirect #(redirect (str "/files" %))]
+             (testing test
+               (testing "different file-types"
+                 (let [response (app (request "/hello.json"))]
+                   (is (= "application/json" (get-in response [:headers "Content-Type"])))
+                   (is (get-in response [:headers "Last-Modified"]))
+                   (is (= "{\"hello\": \"file\"}" (slurp (:body response)))))
+                 (let [response (app (request "/hello.xml"))]
+                   (is (= "text/xml" (get-in response [:headers "Content-Type"])))
+                   (is (get-in response [:headers "Last-Modified"]))
+                   (is (= "<xml><hello>file</hello></xml>\n" (slurp (:body response))))))
+
+               (testing "index-files"
+                 (let [response (app (request "/docs"))]
+                   (is (= (redirect "/docs/index.html") response)))
+                 (let [response (app (request "/docs/"))]
+                   (is (= (redirect "/docs/index.html") response))))
+
+               (testing "not found"
+                 (let [response (app (request "/not-found"))]
+                   (is (= 404 (:status response)))))
+
+               (testing "3-arity"
+                 (let [result (atom nil)
+                       respond (partial reset! result)
+                       raise ::not-called]
+                   (app (request "/hello.xml") respond raise)
+                   (is (= "text/xml" (get-in @result [:headers "Content-Type"])))
+                   (is (get-in @result [:headers "Last-Modified"]))
+                   (is (= "<xml><hello>file</hello></xml>\n" (slurp (:body @result))))))))))
+
+       (testing "outside a router"
+
+         (testing "from root"
+           (let [app (ring/ring-handler
+                       (ring/router [])
+                       (ring/routes
+                         (ring/create-resource-handler {:path "/"})
+                         (ring/create-default-handler)))]
+             (testing test
+               (testing "different file-types"
+                 (let [response (app (request "/hello.json"))]
+                   (is (= "application/json" (get-in response [:headers "Content-Type"])))
+                   (is (get-in response [:headers "Last-Modified"]))
+                   (is (= "{\"hello\": \"file\"}" (slurp (:body response)))))
+                 (let [response (app (request "/hello.xml"))]
+                   (is (= "text/xml" (get-in response [:headers "Content-Type"])))
+                   (is (get-in response [:headers "Last-Modified"]))
+                   (is (= "<xml><hello>file</hello></xml>\n" (slurp (:body response))))))
+
+               (testing "index-files"
+                 (let [response (app (request "/docs"))]
+                   (is (= (redirect "/docs/index.html") response)))
+                 (let [response (app (request "/docs/"))]
+                   (is (= (redirect "/docs/index.html") response))))
+
+               (testing "not found"
+                 (let [response (app (request "/not-found"))]
+                   (is (= 404 (:status response)))))
+
+               (testing "3-arity"
+                 (let [result (atom nil)
+                       respond (partial reset! result)
+                       raise ::not-called]
+                   (app (request "/hello.xml") respond raise)
+                   (is (= "text/xml" (get-in @result [:headers "Content-Type"])))
+                   (is (get-in @result [:headers "Last-Modified"]))
+                   (is (= "<xml><hello>file</hello></xml>\n" (slurp (:body @result)))))))))
+
+         (testing "from path"
+           (let [app (ring/ring-handler
+                       (ring/router [])
+                       (ring/routes
+                         (ring/create-resource-handler {:path "/files"})
+                         (ring/create-default-handler)))
+                 request #(request (str "/files" %))
+                 redirect #(redirect (str "/files" %))]
+             (testing test
+               (testing "different file-types"
+                 (let [response (app (request "/hello.json"))]
+                   (is (= "application/json" (get-in response [:headers "Content-Type"])))
+                   (is (get-in response [:headers "Last-Modified"]))
+                   (is (= "{\"hello\": \"file\"}" (slurp (:body response)))))
+                 (let [response (app (request "/hello.xml"))]
+                   (is (= "text/xml" (get-in response [:headers "Content-Type"])))
+                   (is (get-in response [:headers "Last-Modified"]))
+                   (is (= "<xml><hello>file</hello></xml>\n" (slurp (:body response))))))
+
+               (testing "index-files"
+                 (let [response (app (request "/docs"))]
+                   (is (= (redirect "/docs/index.html") response)))
+                 (let [response (app (request "/docs/"))]
+                   (is (= (redirect "/docs/index.html") response))))
+
+               (testing "not found"
+                 (let [response (app (request "/not-found"))]
+                   (is (= 404 (:status response)))))
+
+               (testing "3-arity"
+                 (let [result (atom nil)
+                       respond (partial reset! result)
+                       raise ::not-called]
+                   (app (request "/hello.xml") respond raise)
+                   (is (= "text/xml" (get-in @result [:headers "Content-Type"])))
+                   (is (get-in @result [:headers "Last-Modified"]))
+                   (is (= "<xml><hello>file</hello></xml>\n" (slurp (:body @result)))))))))))))


Get rid of empty blocks

Get rid of empty blocks

--- src/catalog/layout/fop.clj
+++ src/catalog/layout/fop.clj
@@ -189,7 +189,7 @@
                  ;; if the toc has a heading we assume that it is the
                  ;; first toc. The following content should start on
                  ;; an odd page
-                 {:role "NonStruct" :break-after "odd-page"}
+                 {:role "NonStruct" :break-after "odd-page" :break-before "odd-page"}
                  {:role "NonStruct"})
      (when heading? (heading :h1 [:inhalt] opts))
      [:fo:block {:line-height "1.5"
@@ -559,9 +559,7 @@
        ;; Cover page
        [:fo:block (style :h1)
         (format "Neu als Hörbuch Nr. %s/%s" (layout/volume-number date) (layout/year date))]
-       (block {:break-before "odd-page"}) ;; toc should start on recto
        (toc subitems [] 3 {:path-to-numbers path-to-numbers :heading? true})
-       (block {:break-before "odd-page"}) ;; the very first format should start on recto
        (mapcat #(format-sexp (get subitems %) % 1 {:path-to-numbers path-to-numbers :with-toc? false}) (keys subitems))])]])

 (defn- logo []
@@ -613,9 +611,7 @@
        (cover-page ["Hörfilme in der SBS"
                     "Filme mit Audiodeskription"]
                    date)
-       (block {:break-before "odd-page"}) ;; toc should start on recto
        (toc subitems [fmt] 1 {:heading? true})
-       (block {:break-before "odd-page"}) ;; the very first format should start on recto
        (mapcat #(genre-sexp (get subitems %) fmt % 1 {:show-genre? false}) (keys subitems))])]])

 (defmethod document-sexp :ludo
@@ -634,9 +630,7 @@
       [:fo:flow {:flow-name "xsl-region-body"}
        (cover-page ["Spiele in der SBS"]
                    date)
-       (block {:break-before "odd-page"}) ;; toc should start on recto
        (toc subitems [fmt] 1 {:heading? true})
-       (block {:break-before "odd-page"}) ;; the very first format should start on recto
        (mapcat #(genre-sexp (get subitems %) fmt % 1 {:show-genre? false}) (keys subitems))])]])

 (defmethod document-sexp :taktilesbuch
@@ -655,9 +649,7 @@
       [:fo:flow {:flow-name "xsl-region-body"}
        (cover-page ["Taktile Kinderbücher in der SBS"]
                    date)
-       (block {:break-before "odd-page"}) ;; toc should start on recto
        (toc subitems [fmt] 1 {:heading? true})
-       (block {:break-before "odd-page"}) ;; the very first format should start on recto
        (mapcat #(genre-sexp (get subitems %) fmt % 1 {}) (keys subitems))])]])

 (defmethod document-sexp :all-formats
@@ -673,7 +665,6 @@

     [:fo:flow {:flow-name "xsl-region-body"}
      (toc items [] 1 {:heading? true})
-     (block {:break-before "odd-page"}) ;; the very first format should start on recto
      (mapcat #(format-sexp (get items %) % 1 {}) (keys items))]]])

 (defn document [items fmt editorial recommendations & args]


Rename the brand to "Kati"

Rename the brand to "Kati"

--- src/catalog/web/layout.clj
+++ src/catalog/web/layout.clj
@@ -57,7 +57,7 @@
       [:span.icon-bar]
       [:span.icon-bar]
       [:span.icon-bar]]
-     [:a.navbar-brand {:href (format "/%s/%s" year issue)} (format "Catalog %s/%s" year issue)]]
+     [:a.navbar-brand {:href (format "/%s/%s" year issue)} "Kati"]]
     [:div.collapse.navbar-collapse
      {:id "navbar-collapse-target"}
      [:ul.nav.navbar-nav


make update thread last read independent of browser time

--- src/chat/client/store.cljs
+++ src/chat/client/store.cljs
@@ -121,7 +121,11 @@
   (transact! [:new-thread-id] (fn [_] (uuid/make-random-squuid))))

 (defn update-thread-last-open-at [thread-id]
-  (transact! [:threads thread-id :last-open-at] (constantly (js/Date.))))
+  (let [latest-message (->> (get-in @app-state [:threads thread-id :messages])
+                            (map :created-at)
+                            (reduce max (js/Date. 0)))
+        new-last-open (js/Date. (inc (.getTime latest-message)))]
+    (transact! [:threads thread-id :last-open-at] (constantly new-last-open))))

 (defn set-open-threads! [threads]
   (transact! [:threads] (constantly (key-by-id threads)))


make sure transact! doesn't recursively throw

--- src/chat/client/store.cljs
+++ src/chat/client/store.cljs
@@ -63,7 +63,9 @@
         (errorf "State consistency error updating %s to %s: %s"
                 ks (get-in @app-state ks) (ex-data e))
         (reset! app-state old-state)
-        (display-error! :internal-consistency "Something has gone wrong")))))
+        ; Not just calling display-error! to avoid possibility of infinite loop
+        (swap! app-state update-in [:errors] conj
+               [:internal-consistency "Something has gone wrong"])))))

 ; login state


bit by the fence

bit by the fence

--- src/clj/owl/modularity.clj
+++ src/clj/owl/modularity.clj
@@ -316,8 +316,9 @@
         remain (rest ids)
         fiction-community (apply set/union (vals (select-keys full ids)))
         trim-community (apply dissoc communities remain)
-        trim-full (apply dissoc full ids)]
-    (assoc unity :communities trim-community :full-communities (merge trim-full {fiction-key fiction-community}))))
+        trim-full (apply dissoc full ids)
+        fiction (when ids {fiction-key fiction-community})]
+    (assoc unity :communities trim-community :full-communities (merge trim-full fiction))))

 (defn seek-unity
   ([network]


node hostnames in timeseries

node hostnames in timeseries

--- src/clj/swarmpit/stats.clj
+++ src/clj/swarmpit/stats.clj
@@ -82,7 +82,11 @@
 (defn hosts-timeseries
   "Get hosts timeseries data for last 24 hours"
   []
-  (map #(m/->host-ts %)
-       (-> (influx/read-host-stats)
-           (first)
-           (get "series"))))+  (let [nodes (->> (docker/nodes)
+                   (group-by :ID))
+        node-name #(or (-> (get nodes %) first :Description :Hostname) %)]
+    (->> (-> (influx/read-host-stats)
+             (first)
+             (get "series"))
+         (map #(m/->host-ts %))
+         (map #(update % :name node-name)))))


Implemented memory edit front end

Implemented memory edit front end

--- src/cljs/memento/core.cljs
+++ src/cljs/memento/core.cljs
@@ -10,7 +10,7 @@
             [jayq.core :refer [$]]
             [markdown.core :refer [md->html]]
             [markdown.transformers :as transformers]
-            [ajax.core :refer [GET POST]])
+            [ajax.core :refer [GET POST PUT]])
   (:require-macros [reagent.ratom :refer [reaction]]
                    [memento.misc.cljs-macros :refer [adapt-bootstrap]])
   (:import goog.History))
@@ -103,6 +103,53 @@

 (register-handler
+  :edit-memory-set
+  (fn [app-state [_ thought]]
+    (if (empty? thought)
+      (dispatch [:update-note nil]))
+    (assoc-in app-state [:note :edit-memory] thought)
+    ))
+
+
+(register-handler
+  :edit-memory-save
+  (fn [app-state _]
+    (let [note   (get-in app-state [:note :current-note])
+          memory (get-in app-state [:note :edit-memory])
+          url    (str "/api/memory/" (:id memory) "/thought")]
+      (PUT url {:params        {:thought note :refine_id (get-in app-state [:note :focus :id])}
+                :headers       {:authorization (str "Token " (get-in app-state [:credentials :token]))}
+                :handler       #(dispatch [:edit-memory-success note])
+                :error-handler #(dispatch [:edit-memory-error %])})
+      )
+    (assoc-in app-state [:ui-state :is-busy?] true)
+    ))
+
+
+(register-handler
+  :edit-memory-success
+  (fn [app-state [_ msg]]
+    (dispatch [:set-message (str "Updated memory to: " msg) "alert-success"])
+    (if (= :remember (get-in app-state [:ui-state :section]))         ; Just in case we allow editing from elsewhere...
+      (dispatch [:load-memories]))
+    (-> app-state
+        (assoc-in [:ui-state :is-busy?] false)
+        (assoc-in [:note :edit-memory] nil)
+        (assoc-in [:note :current-note] "")
+        (assoc-in [:note :focus] nil)
+        )))
+
+
+(register-handler
+  :edit-memory-error
+  (fn [app-state [_ result]]
+    (dispatch [:set-message (str "Error editing note: " result) "alert-danger"])
+    (clear-token-on-unauth result)
+    (assoc-in app-state [:ui-state :is-busy?] false)
+    ))
+
+
+(register-handler
   :initialize
   (fn [app-state _]
     (dispatch [:set-token (cookies/get :token nil)])
@@ -114,6 +161,7 @@
                                  :results-page  0
                                  :memories      {:pages 0}
                                  :is-searching? false}
+                      :note     {:edit-memory nil}
                       })))

 (register-handler
@@ -384,8 +432,26 @@
         [:div {:class "panel-body"}
          [:p {:dangerouslySetInnerHTML {:__html (md->html (:thought @focus) :replacement-transformers md-transformers)}}]
          ]]])
-
-    ))
+    ))
+
+
+(defn thought-edit-box []
+  (let [note (subscribe [:note :current-note])]
+    (fn []
+      [:div {:class "form-group"}
+       [focused-thought]
+       [:div {:class "col-sm-12"}
+        [initial-focus-wrapper
+         [:textarea {:class       "form-control"
+                     :id          "thought-area"
+                     :placeholder "I was thinking..."
+                     :rows        12
+                     :style       {:font-size "18px"}
+                     :on-change   #(dispatch-sync [:update-note (-> % .-target .-value)])
+                     :value       @note
+                     }]]
+        ]]))
+  )

 (defn write-section []
   (let [note     (subscribe [:note :current-note])
@@ -393,20 +459,7 @@
     (fn []
       [:fielset
        [:div {:class "form-horizontal"}
-        [:div {:class "form-group"}
-         [focused-thought]
-
-         [:div {:class "col-sm-12"}
-          [initial-focus-wrapper
-           [:textarea {:class       "form-control"
-                       :id          "thought-area"
-                       :placeholder "I was thinking..."
-                       :rows        12
-                       :style       {:font-size "18px"}
-                       :on-change   #(dispatch-sync [:update-note (-> % .-target .-value)])
-                       :value       @note
-                       }]]
-          ]]
+        [thought-edit-box]
         [:div {:class "form-group"}
          [:div {:class "col-sm-12"}
           [:button {:type     "reset"
@@ -476,6 +529,12 @@
       ]
      [:div
       [:div {:class "col-sm-4"}
+       (if (= :open (:status memory))
+         [:a {:class    "btn btn-primary btn-xs"
+              :on-click #(do
+                          (dispatch [:update-note (:thought memory)])
+                          (dispatch [:edit-memory-set memory]))}
+          "Edit" [:i {:class "fa fa-pencil fa-space"}]])
        [:a {:class    "btn btn-primary btn-xs"
             :on-click #(do
                         (.scrollIntoView top-div-target)
@@ -490,6 +549,30 @@
       [:div {:class "col-sm-4 col-sm-offset-4" :style {:text-align "right"}}
        [:i [:small (:created memory)]]
        ]]]))
+
+
+(defn edit-memory []
+  (let [edit-memory (subscribe [:note :edit-memory])
+        note        (subscribe [:note :current-note])
+        is-busy?    (subscribe [:ui-state :is-busy?])
+        ;; On the next one, we can't use not-empty because (= nil (not-empty nil)), and :show expects true/false,
+        ;; not a truth-ish value.
+        show?       (reaction (not (empty? @edit-memory)))]
+    (fn []
+      [Modal {:show @show? :onHide #(dispatch [:edit-memory-set nil])}
+       [ModalBody
+        [:div {:class "col-sm-12 thought"}
+         [thought-edit-box]]]
+       [ModalFooter
+        [:button {:type     "reset"
+                  :class    "btn btn-default"
+                  :on-click #(dispatch [:edit-memory-set nil])} "Discard"]
+        [:button {:type     "submit"
+                  :class    "btn btn-primary"
+                  :disabled (or @is-busy? (empty? @note))
+                  :on-click #(dispatch [:edit-memory-save])} "Save"]
+        ]])))
+

 (defn memory-thread []
   (let [show?  (subscribe [:ui-state :show-thread?])
@@ -524,6 +607,7 @@
 (defn memory-list []
   (fn []
     [:span
+     [edit-memory]
      [memory-thread]
      [memory-query]
      [memory-results]]))
@@ -641,6 +725,4 @@
 (defn init! []
   (dispatch-sync [:initialize])
   (hook-browser-navigation!)
-  (mount-components))
-
-
+  (mount-components))


add dispatch assertions

add dispatch assertions

--- src/citrus/reconciler.cljs
+++ src/citrus/reconciler.cljs
@@ -58,6 +58,10 @@

   IReconciler
   (dispatch! [this cname event args]
+    (assert (contains? controllers cname) (str "Controller " cname " is not found"))
+    (assert (-> (get controllers cname) methods (contains? event))
+            (str "Controller " cname " doesn't declare " event " method"))
+
     (queue-effects!
       queue
       [cname event #((get controllers cname) event args (get %1 cname) %2)])
@@ -91,6 +95,10 @@
           (reset! state next-state)))))

   (dispatch-sync! [this cname event args]
+    (assert (contains? controllers cname) (str "Controller " cname " is not found"))
+    (assert (-> (get controllers cname) methods (contains? event))
+            (str "Controller " cname " doesn't declare " event " method"))
+
     (let [ctrl (get controllers cname)
           cofx (get-in (.-meta ctrl) [:citrus event :cofx])
           cofx (reduce


remove console logs

remove console logs

--- src/cljs/re_form/core.cljs
+++ src/cljs/re_form/core.cljs
@@ -161,8 +161,6 @@
      {:display-name :binded-field
       :component-will-mount
       (fn [this]
-        (.log js/console "This" this)
-        (.log js/console "Props" (clj->js (get-props this)))
         (update-binding (get-props this)))

       :component-will-unmount


ghetto paragraph and add instructions

ghetto paragraph and add instructions

--- src/cljs/unfolds/core.cljs
+++ src/cljs/unfolds/core.cljs
@@ -88,7 +88,8 @@
                (dom/h2 nil (:item/title item))
                (dom/br nil "")
                (link (str "#/" (:item/id item)) (:item/id item))
-               ;; prepare-item
+               (dom/br nil "") ;; XXX: ghetto paragraph
+               (dom/br nil "")
                (apply dom/div nil
                       (prepare-item (:item/text item)))))))

@@ -100,7 +101,12 @@
                   :sync sync}]
         (dom/div #js {:id "item-add-view"}
         (dom/div #js {:id "item-info"}
-          (dom/div #js {:className "item-name editable"}
+                 (dom/div #js {:className "item-name editable"}
+                          (dom/p nil "If you want to link to, say, the
+                          start page,
+                          write [[ea72343d-89dc-4dfc-85af-25e1113b0948|Unfolds]].
+                          Unfortunately the link text can only be one
+                          word for now (no spaces).")
             (dom/input #js
                        {:value (:title state)
                         :ref "new-item-title"


Change order for :states in :move-attack-twice (again)

--- src/cljs/zetawar/data.cljs
+++ src/cljs/zetawar/data.cljs
@@ -135,11 +135,11 @@
                              :attack-unit  :moved-0-attacked-1
                              :repair-unit  :done
                              :capture-base :done}}
+       :moved-0-attacked-1 {:transitions
+                            {:attack-unit  :done
+                             :capture-base :done}}
        :moved-1-attacked-0 {:transitions
                             {:attack-unit  :moved-1-attacked-1
-                             :capture-base :done}}
-       :moved-0-attacked-1 {:transitions
-                            {:attack-unit  :done
                              :capture-base :done}}
        :moved-1-attacked-1 {:transitions
                             {:attack-unit  :done


Correct attribution on Weewar maps

Correct attribution on Weewar maps

I created these based on old Weewar screen captures. They may have been created
by Weewar players originally. I'll try to track down actual names for them at
some point.

--- src/cljs/zetawar/data.cljs
+++ src/cljs/zetawar/data.cljs
@@ -792,7 +792,7 @@
   {:sterlings-aruba
    {:id :sterlings-aruba
     :description "Sterling's Aruba"
-    :created-by "David Whittington"
+    :created-by "Weewar"
     :terrains
     [;; Row 1
      {:q 1 :r 0 :terrain-type :plains}
@@ -881,7 +881,7 @@
    :city-sprawl
    {:id :city-sprawl
     :description "City Sprawl"
-    :created-by "David Whittington"
+    :created-by "Weewar"
     :terrains
     [;; Row 1
      {:q 2 :r 0 :terrain-type :woods}
@@ -1655,7 +1655,7 @@
   {:sterlings-aruba-multiplayer
    {:id :sterlings-aruba-multiplayer
     :description "Sterling's Aruba Multiplayer"
-    :created-by "David Whittington"
+    :created-by "Weewar"
     :ruleset-id :zetawar
     :map-id :sterlings-aruba
     :max-count-per-unit 10
@@ -1685,7 +1685,7 @@
    :city-sprawl-multiplayer
    {:id :city-sprawl-multiplayer
     :description "City Sprawl Multiplayer"
-    :created-by "David Whittington"
+    :created-by "Weewar"
     :ruleset-id :zetawar
     :map-id :city-sprawl
     :max-count-per-unit 10


Move unit-terrain-effects out of "Selection and target" section

--- src/cljs/zetawar/subs.cljs
+++ src/cljs/zetawar/subs.cljs
@@ -361,6 +361,11 @@
 (deftrack in-range-of-friend-at? [conn unit-q unit-r friend-q friend-r]
   (contains? @(friend-locations-in-range-of conn unit-q unit-r) [friend-q friend-r]))

+(deftrack unit-terrain-effects [conn unit-q unit-r terrain-q terrain-r]
+  (when-let [unit @(unit-at conn unit-q unit-r)]
+    (let [terrain @(terrain-at conn terrain-q terrain-r)]
+      (game/unit-terrain-effects @conn unit terrain))))
+
 (deftrack repairable? [conn q r]
   (when-let [unit @(unit-at conn q r)]
     (game/repairable? @conn @(game conn) unit)))
@@ -453,11 +458,6 @@
   (when-let [[q r] @(selected-hex conn)]
     @(unit-at conn q r)))

-(deftrack unit-terrain-effects [conn unit-q unit-r terrain-q terrain-r]
-  (when-let [unit @(unit-at conn unit-q unit-r)]
-    (let [terrain @(terrain-at conn terrain-q terrain-r)]
-      (game/unit-terrain-effects @conn unit terrain))))
-
 (deftrack selected-terrain-effects [conn]
   (when-let [[q r] @(selected-hex conn)]
     @(unit-terrain-effects conn q r q r)))


CMR-387: Fixed typo.

CMR-387: Fixed typo.

--- src/cmr/umm/collection.clj
+++ src/cmr/umm/collection.clj
@@ -158,7 +158,7 @@
    ;; The number of orbits per granule (may be fractional)
    number-of-orbits

-   ;; The starting circular latitude in degress
+   ;; The starting circular latitude in degrees
    start-circular-latitude
    ])


Fix minelayer message

Fix minelayer message

fixes #1476

--- src/clj/game/cards-ice.clj
+++ src/clj/game/cards-ice.clj
@@ -665,7 +665,7 @@
                  :choices {:req #(and (ice? %)
                                       (in-hand? %))}
                  :prompt "Choose an ICE to install from HQ"
-                 :effect (req (corp-install state side target (:server run) {:no-install-cost true}))}]}
+                 :effect (req (corp-install state side target (zone->name (first (:server run))) {:no-install-cost true}))}]}

    "Mother Goddess"
    (let [ab {:req (req (ice? target))