Ensure the stack trace button reflects status correctly

--- src/clojure/nightmod/screens.clj
+++ src/clojure/nightmod/screens.clj
@@ -371,7 +371,8 @@
              (scroll-pane (style :scroll-pane nil nil nil nil nil))
              (assoc :id :text :x pad-small :y (+ text-height (* 2 pad-small))))
          (-> [(check-box (nc-utils/get-string :stack-trace) ui-skin
-                         :set-name "stack-trace")
+                         :set-name "stack-trace"
+                         :set-checked @u/stack-trace?)
               (text-button (nc-utils/get-string :copy) ui-skin
                            :set-name "copy")]
              (horizontal :space (* 2 pad-small) :pack)


Fix wrap-parser-exception to have one atom per parser full call

--- src/com/wsscode/pathom/core.cljc
+++ src/com/wsscode/pathom/core.cljc
@@ -225,8 +225,8 @@
         ::reader-error))))

 (defn wrap-parser-exception [parser]
-  (let [errors (atom {})]
-    (fn [env tx]
+  (fn [env tx]
+    (let [errors (atom {})]
       (cond-> (parser (assoc env ::errors* errors) tx)
         (seq @errors) (assoc ::errors @errors)))))

@@ -272,8 +272,6 @@
       (apply-plugins plugins ::wrap-parser)
       wrap-normalize-env))

-
-
 (defn pathom-read [{::keys [reader process-reader] :as env} _ _]
   "DEPRECATED: use p/parser to create your parser"
   {:value


Use idiomatic clojure for str/starts-with?

--- src/com/wsscode/pathom/test.cljc
+++ src/com/wsscode/pathom/test.cljc
@@ -1,5 +1,6 @@
 (ns com.wsscode.pathom.test
-  (:require [com.wsscode.pathom.core :as p]))
+  (:require [com.wsscode.pathom.core :as p]
+            [clojure.string :as str]))

 (defn self-reader [{:keys [ast query] :as env}]
   (if query
@@ -18,7 +19,7 @@

 (defn repeat-reader [env]
   (if-let [key (p/ident-key env)]
-    (if (some-> (name key) (.startsWith "repeat."))
+    (if (some-> (name key) (str/starts-with? "repeat."))
       (p/join-seq env (map (constantly {}) (range (p/ident-value env))))
       ::p/continue)
     ::p/continue))


Workaround codox markdown formatting issues

--- src/re_frame/core.cljc
+++ src/re_frame/core.cljc
@@ -22,14 +22,14 @@
 (defn dispatch
   "Queue `event` for processing by the event handling machinery.

-   `event` is a vector and the first element is typically a keyword which
+   `event` is a vector and the first element is typically a keyword which
    identifies the kind of event.

-   The event will be added to the end of a FIFO processing queue. So,
-   event handling does not happen immediately. It will likely happen
-   'very soon', bit not now. And if the queue already contains events,
-   they will be processed first.
-
+   The event will be added to the end of a FIFO processing queue. So,
+   event handling does not happen immediately. It will likely happen
+   'very soon', bit not now. And if the queue already contains events,
+   they will be processed first.
+
    Usage:
    ```clj
    (dispatch [:order-pizza \"me\" {:supreme 2 :meatlovers 1 :veg 1}])
@@ -39,15 +39,15 @@
   (router/dispatch event))

 (defn dispatch-sync
-  "Synchronously (immediately) process `event`. Does not queue the event
+  "Synchronously (immediately) process `event`. Does not queue the event
    for handling later as `dispatch` does.

    Generally, don't use this and, instead, use `dispatch`. It is an error
-   to use `dispatch-sync` within an event handler because you can't immediately
+   to use `dispatch-sync` within an event handler because you can't immediately
    process an new event when one is already being processed.

    Useful when any delay in processing will be a problem:
-
+
      1. the `:on-change` handler of a text field where we are expecting fast typing.
      2  when initialising your app - see 'main' in examples/todomvc/src/core.cljs
      3. in a unit test where immediate, synchronous processing is useful.
@@ -74,9 +74,9 @@
   from which nodes can be created later.

   `reg-sub` arguments are:
-    - a `query-id` (typically a namespaced keyword)
-    - a function which returns the inputs required by this kind of node (can be supplied  in one of three ways)
-    - a function which computes the value of this kind of node
+  - a `query-id` (typically a namespaced keyword)
+  - a function which returns the inputs required by this kind of node (can be supplied  in one of three ways)
+  - a function which computes the value of this kind of node

   The `computation function` is always the last argument supplied and it is expected to have the signature:
     `(input-values, query-vector) -> a-value`
@@ -93,104 +93,96 @@
   But note, the 2nd method, in which a `signal-fn` is explicitly supplied, is the most canonical and instructive. The other
   two are really just sugary variations.

-  1. No input signals given:
-     ```clj
-     (reg-sub
-       :query-id
-       a-computation-fn)   ;; has signature:  (fn [db query-vec]  ... ret-value)
-     ```
+  First, No input signals given:
+
+      (reg-sub
+        :query-id
+        a-computation-fn)   ;; has signature:  (fn [db query-vec]  ... ret-value)

      In the absence of an explicit `input-fn`, the node's input signal defaults to `app-db`
      and, as a result, the value within `app-db` (a map) is
      is given as the 1st argument when `a-computation-fn` is called.

-  2. A signal function is explicitly supplied:
-     ```clj
-     (reg-sub
-       :query-id
-       signal-fn     ;; <-- here
-       computation-fn)
-     ```
-
-     This is the most canonical and instructive of the three variations.
-
-     When a node is created from the template, the `signal-fn` will be called and it
-     is expected to return the input signal(s) as either a singleton, if there is only
-     one, or a sequence if there are many, or a map with the signals as the values.
-
-     The values from returned nominated signals will be supplied as the 1st argument to
-     the `a-computation-fn` when it is called - and subject to what this `signal-fn` returns,
-     this value will be either a singleton, sequence or map of them (paralleling
-     the structure returned by the `signal-fn`).
-
-     This example `signal-fn` returns a vector of input signals.
-     ```clj
-       (fn [query-vec dynamic-vec]
+  Second, A signal function is explicitly supplied:
+
+      (reg-sub
+        :query-id
+        signal-fn     ;; <-- here
+        computation-fn)
+
+  This is the most canonical and instructive of the three variations.
+
+  When a node is created from the template, the `signal-fn` will be called and it
+  is expected to return the input signal(s) as either a singleton, if there is only
+  one, or a sequence if there are many, or a map with the signals as the values.
+
+  The values from returned nominated signals will be supplied as the 1st argument to
+  the `a-computation-fn` when it is called - and subject to what this `signal-fn` returns,
+  this value will be either a singleton, sequence or map of them (paralleling
+  the structure returned by the `signal-fn`).
+
+  This example `signal-fn` returns a vector of input signals.
+
+      (fn [query-vec dynamic-vec]
          [(subscribe [:a-sub])
           (subscribe [:b-sub])])
-      ```
-
-     The associated computation function must be written
-     to expect a vector of values for its first argument:
-     ```clj
-     (fn [[a b] query-vec]     ;; 1st argument is a seq of two values
-       ....)
-     ```
-
-     If, on the other hand, the signal function was simpler and returned a singleton, like this:
-     ```clj
+
+  The associated computation function must be written
+  to expect a vector of values for its first argument:
+
+      (fn [[a b] query-vec]     ;; 1st argument is a seq of two values
+        ....)
+
+  If, on the other hand, the signal function was simpler and returned a singleton, like this:
+
      (fn [query-vec dynamic-vec]
        (subscribe [:a-sub]))
-     ```
-     then the associated computation function must be written to expect a single value
-     as the 1st argument:
-     ```clj
-       (fn [a query-vec]       ;; 1st argument is a single value
+
+  then the associated computation function must be written to expect a single value
+  as the 1st argument:
+
+      (fn [a query-vec]       ;; 1st argument is a single value
          ...)
-      ```
-
-     Further Note: variation #1 above, in which an `input-fn` was not supplied, like this:
-     ```clj
-     (reg-sub
-       :query-id
-       a-computation-fn)   ;; has signature:  (fn [db query-vec]  ... ret-value)
-     ```
-     is the equivalent of using this
-     2nd variation and explicitly suppling a `signal-fn` which returns `app-db`:
-     ```clj
-     (reg-sub
-       :query-id
-       (fn [_ _]  re-frame/app-db)   ;; <--- explicit input-fn
-       a-computation-fn)             ;; has signature:  (fn [db query-vec]  ... ret-value)
-     ```
-
-  3. Syntax Sugar
-     ```clj
-     (reg-sub
-       :a-b-sub
-       :<- [:a-sub]
-       :<- [:b-sub]
-       (fn [[a b] query-vec]    ;; 1st argument is a seq of two values
-         {:a a :b b}))
-     ```
-
-     This 3rd variation is just syntactic sugar for the 2nd.  Instead of providing an
-     `signals-fn` you provide one or more pairs of `:<-` and a subscription vector.
-
-     If you supply only one pair a singleton will be supplied to the computation function,
-     as if you had supplied a `signal-fn` returning only a single value:
-
-     ```clj
-     (reg-sub
-       :a-sub
-       :<- [:a-sub]
-       (fn [a query-vec]      ;; only one pair, so 1st argument is a single value
-         ...))
-     ```
-
-    For further understanding, read the tutorials, and look at the detailed comments in
-    /examples/todomvc/src/subs.cljs
+
+  Further Note: variation #1 above, in which an `input-fn` was not supplied, like this:
+
+      (reg-sub
+        :query-id
+        a-computation-fn)   ;; has signature:  (fn [db query-vec]  ... ret-value)
+
+  is the equivalent of using this
+  2nd variation and explicitly suppling a `signal-fn` which returns `app-db`:
+
+      (reg-sub
+        :query-id
+        (fn [_ _]  re-frame/app-db)   ;; <--- explicit input-fn
+        a-computation-fn)             ;; has signature:  (fn [db query-vec]  ... ret-value)
+
+  Third, Syntax Sugar
+
+      (reg-sub
+        :a-b-sub
+        :<- [:a-sub]
+        :<- [:b-sub]
+        (fn [[a b] query-vec]    ;; 1st argument is a seq of two values
+          {:a a :b b}))
+
+  This 3rd variation is just syntactic sugar for the 2nd.  Instead of providing an
+  `signals-fn` you provide one or more pairs of `:<-` and a subscription vector.
+
+  If you supply only one pair a singleton will be supplied to the computation function,
+  as if you had supplied a `signal-fn` returning only a single value:
+
+
+      (reg-sub
+        :a-sub
+        :<- [:a-sub]
+        (fn [a query-vec]      ;; only one pair, so 1st argument is a single value
+          ...))
+
+  For further understanding, read the tutorials, and look at the detailed comments in
+  /examples/todomvc/src/subs.cljs
   "
   [query-id & args]
   (apply subs/reg-sub (into [query-id] args)))
@@ -217,7 +209,7 @@
   (subscribe [:items \"blue\" :small])
   (subscribe [:items {:colour \"blue\"  :size :small}])
   ```
-
+
   Note: for any given call to `subscribe` there must have been a previous call
   to `reg-sub`, registering the query handler (function) for the `query-id` given.

@@ -247,7 +239,7 @@
    one arg, assumed to be a `query-id` of a registered subscription handler,
    unregisters the associated handler.

-   NOTE: Depending on the usecase it may also be necessary to call
+   NOTE: Depending on the usecase it may also be necessary to call
          `clear-subscription-cache!`."
   ([]
    (registrar/clear-handlers subs/kind))
@@ -257,12 +249,12 @@
 (defn clear-subscription-cache!
   "Removes all subscriptions from the cache.

-  This is for development time use. Useful when hot realoding reloading
+  This is for development time use. Useful when hot realoding reloading
   to subscription code or after a React/render exception, because React components won't have been
   cleaned up properly. And this, in turn, means the subscriptions within those
   components won't have been cleaned up correctly. So this forces the issue.
-
-   Implementation note: it calls `on-dispose` for each cached item,
+
+   Implementation note: it calls `on-dispose` for each cached item,
    and it is that fucntion which actually performs the cache removal.
    "
   []
@@ -271,7 +263,7 @@
 (defn reg-sub-raw
   "This is a low level, advanced function.  You should probably be
   using `reg-sub` instead.
-
+
   Some docs are available in
   http://day8.github.io/re-frame/flow-mechanics/"
   [query-id handler-fn]
@@ -282,20 +274,18 @@
 (defn reg-fx
   "Register the given effect `handler` for the given `id`:

-    - `id` is keyword, often namespaced.
-    - `handler` is a side-effecting function which takes a single argument and whose return
-      value is ignored.
+  - `id` is keyword, often namespaced.
+  - `handler` is a side-effecting function which takes a single argument and whose return
+    value is ignored.

   Example Use
   First, registration ... associate `:effect2` with a handler.
-
-  ```clj
+
   (reg-fx
      :effect2
      (fn [value]
         ... do something side-effect-y))
-  ```
-
+
   Then, later, if an event handler were to return this effects map ...

   {...
@@ -309,8 +299,8 @@

 (defn clear-fx ;; think unreg-fx
   "When called with no args, unregisters all effect handlers. When given one arg,
-   assumed to be the `id` of a registered effect handler, unregisters the
-   associated handler."
+  assumed to be the `id` of a registered effect handler, unregisters the
+  associated handler."
   ([]
    (registrar/clear-handlers fx/kind))
   ([id]
@@ -319,37 +309,37 @@
 ;; -- coeffects ---------------------------------------------------------------
 (defn reg-cofx
   "Register the given coeffect `handler` for the given `id`, for later use
-   within `inject-cofx`:
+  within `inject-cofx`:

     - `id` is keyword, often namespaced.
     - `handler` is a function which takes either one or two arguements, the first of which is
        always `coeffects` and which returns an updated `coeffects`.

-   See the docs for `inject-cofx` for example use.
+  See the docs for `inject-cofx` for example use.
    "
   [id handler]
   (cofx/reg-cofx id handler))

 (defn inject-cofx
   "Given an `id`, and an optional, arbitrary `value`, returns an interceptor
-   whose `:before` adds to the `:coeffects` (map) by calling a pre-registered
-   'coeffect handler' identified by the `id`.
-
-   The previous association of a `coeffect handler` with an `id` will have
-   happened via a call to `re-frame.core/reg-cofx` - generally on program startup.
-
-   Within the created interceptor, this 'looked up' `coeffect handler` will
-   be called (within the `:before`) with two arguments:
-
-     - the current value of `:coeffects`
-     - optionally, the originally supplied arbitrary `value`
-
-   This `coeffect handler` is expected to modify and return its first, `coeffects` argument.
-
-   ##### Example of `inject-cofx` and `reg-cofx` working together
-
-
-   1. Early in app startup, you register a `coeffect handler` for `:datetime`:
+  whose `:before` adds to the `:coeffects` (map) by calling a pre-registered
+  'coeffect handler' identified by the `id`.
+
+  The previous association of a `coeffect handler` with an `id` will have
+  happened via a call to `re-frame.core/reg-cofx` - generally on program startup.
+
+  Within the created interceptor, this 'looked up' `coeffect handler` will
+  be called (within the `:before`) with two arguments:
+
+  - the current value of `:coeffects`
+  - optionally, the originally supplied arbitrary `value`
+
+  This `coeffect handler` is expected to modify and return its first, `coeffects` argument.
+
+  ##### Example of `inject-cofx` and `reg-cofx` working together
+
+
+  First - Early in app startup, you register a `coeffect handler` for `:datetime`:

       (re-frame.core/reg-cofx
         :datetime                        ;; usage  (inject-cofx :datetime)
@@ -357,7 +347,7 @@
           [coeffect]
           (assoc coeffect :now (js/Date.))))   ;; modify and return first arg

-   2. Later, add an interceptor to an -fx event handler, using `inject-cofx`:
+  Second - Later, add an interceptor to an -fx event handler, using `inject-cofx`:

       (re-frame.core/reg-event-fx        ;; we are registering an event handler
          :event-id
@@ -366,22 +356,22 @@
            [coeffect event]
            ... in here can access (:now coeffect) to obtain current datetime ... )))

-   ##### Background
-
-   `coeffects` are the input resources required by an event handler
-   to perform its job. The two most obvious ones are `db` and `event`.
-   But sometimes an event handler might need other resources.
-
-   Perhaps an event handler needs a random number or a GUID or the current
-   datetime. Perhaps it needs access to a DataScript database connection.
-
-   If an event handler directly accesses these resources, it stops being
-   pure and, consequently, it becomes harder to test, etc. So we don't
-   want that.
-
-   Instead, the interceptor created by this function is a way to 'inject'
-   'necessary resources' into the `:coeffects` (map) subsequently given
-   to the event handler at call time."
+  ##### Background
+
+  `coeffects` are the input resources required by an event handler
+  to perform its job. The two most obvious ones are `db` and `event`.
+  But sometimes an event handler might need other resources.
+
+  Perhaps an event handler needs a random number or a GUID or the current
+  datetime. Perhaps it needs access to a DataScript database connection.
+
+  If an event handler directly accesses these resources, it stops being
+  pure and, consequently, it becomes harder to test, etc. So we don't
+  want that.
+
+  Instead, the interceptor created by this function is a way to 'inject'
+  'necessary resources' into the `:coeffects` (map) subsequently given
+  to the event handler at call time."
   ([id]
    (cofx/inject-cofx id))
   ([id value]
@@ -389,8 +379,8 @@

 (defn clear-cofx ;; think unreg-cofx
   "When called with no args, unregisters all coeffect handlers. When given one arg,
-   assumed to be the `id` of a registered coeffect handler, unregisters the
-   associated handler."
+   assumed to be the `id` of a registered coeffect handler, unregisters the
+   associated handler."
   ([]
    (registrar/clear-handlers cofx/kind))
   ([id]
@@ -401,11 +391,11 @@
 (defn reg-event-db
   "Register the given event `handler` (function) for the given `id`. Optionally, provide
   an `interceptors` chain:
-
+
     - `id` is typically a namespaced keyword  (but can be anything)
     - `handler` is a function: (db event) -> db
     - `interceptors` is a collection of interceptors. Will be flattened and nils removed.
-
+
    Note: `handler` is wrapped in its own interceptor and added to the end of the interceptor
        chain, so that, in the end, only a chain is registered.
   "
@@ -418,11 +408,11 @@
 (defn reg-event-fx
   "Register the given event `handler` (function) for the given `id`. Optionally, provide
   an `interceptors` chain:
-
+
     - `id` is typically a namespaced keyword  (but can be anything)
     - `handler` is a function: (coeffects-map event-vector) -> effects-map
     - `interceptors` is a collection of interceptors. Will be flattened and nils removed.
-
+
    Note: `handler` is wrapped in its own interceptor and added to the end of the interceptor
        chain, so that, in the end, only a chain is registered.
    "
@@ -446,8 +436,8 @@

 (defn clear-event ;; think unreg-event-*
   "When called with no args, unregisters all event handlers. When given one arg,
-   assumed to be the `id` of a registered event handler, unregisters the
-   associated handler."
+   assumed to be the `id` of a registered event handler, unregisters the
+   associated handler."
   ([]
    (registrar/clear-handlers events/kind))
   ([id]
@@ -460,7 +450,7 @@
   `js/console.debug`. See examples/todomvc/src/events.cljs for use.

   Output includes:
-
+
   1. the event vector
   2. a `clojure.data/diff` of db, before vs after, which shows
      the changes caused by the event handler. To understand the output,
@@ -561,22 +551,22 @@

 (def trim-v
   "An interceptor which removes the first element of the event vector,
-  before it is supplied to the event handler, allowing you to write more
+  before it is supplied to the event handler, allowing you to write more
    aesthetically pleasing event handlers. No leading underscore on the event-v!
-
+
   Your event handlers will look like this:

       (reg-event-db
-        :event-id
-        [... trim-v ...]    ;; <-- added to the interceptors
+        :event-id
+        [... trim-v ...]    ;; <-- added to the interceptors
         (fn [db [x y z]]    ;; <-- instead of [_ x y z]
           ...)
     "
   std-interceptors/trim-v)

 (def after
-  "An interceptor factory, which is to say, a function which will return an interceptor.
-
+  "An interceptor factory, which is to say, a function which will return an interceptor.
+
   Returns an interceptor which runs a given function `f` in the `:after`
   position, presumably for side effects.

@@ -585,18 +575,18 @@
   Its return value is ignored, so `f` can only side-effect.

   An examples of use can be seen in /examples/todomvc/events.cljs:
-
+
      - `f` runs schema validation (reporting any errors found).
      - `f` writes to localstorage."
   std-interceptors/after)

 (def on-changes
-  "An interceptor factory, which is to say, a function which will return an interceptor.
-
-   Returns an interceptor which will observe N paths within `db`, and if any of them
-   test not identical? to their previous value  (as a result of a event handler
-   being run), then it runs `f` to compute a new value, which is then assoc-ed
-   into the given `out-path` within `db`.
+  "An interceptor factory, which is to say, a function which will return an interceptor.
+
+  Returns an interceptor which will observe N paths within `db`, and if any of them
+  test not identical? to their previous value  (as a result of a event handler
+  being run), then it runs `f` to compute a new value, which is then assoc-ed
+  into the given `out-path` within `db`.

   Example Usage:

@@ -607,16 +597,16 @@
       ;; use it
       (def my-interceptor (on-changes my-f [:c] [:a] [:b]))

-      (reg-event-db
-        :event-id
+      (reg-event-db
+        :event-id
         [... my-interceptor ...]  ;; <-- ultimately used here
         (fn [db v]
            ...))

-
+
     Put this Interceptor on handlers which might change paths :a or :b
-    and it will:
-
+    and it will:
+
      - call `f` each time the value at path [:a] or [:b] changes
      - call `f` with the values extracted from [:a] [:b]
      - assoc the return value from `f` into the path  [:c]
@@ -631,14 +621,14 @@
    When you register an event handler you have the option of supplying an
    interceptor chain. Any global interceptors you register are effectively
    prepending to this chain.
-
+
    Global interceptors are run in the order that they are registered."
   [interceptor]
   (settings/reg-global-interceptor interceptor))

 (defn clear-global-interceptor ;; think unreg-global-interceptor
-  "Unregisters (removes) global interceptors.
-
+  "Unregisters (removes) global interceptors.
+
    When called with no arguments, it unregisters all global interceptors. When given
    one argument, assumed to be the `id` of a currently registered global
    interceptor, it unregisters the associated interceptor."
@@ -649,19 +639,19 @@

 (defn ->interceptor
-  "A utility function for creating interceptors.
-
-   Accepts three optional, named arguments:
-
+  "A utility function for creating interceptors.
+
+  Accepts three optional, named arguments:
+
      - `:id` - an id for the interceptor (decorative only)
-     - `:before` - the interceptor's before function
-     - `:after`  - the interceptor's after function
-
-   Example use:
+     - `:before` - the interceptor's before function
+     - `:after`  - the interceptor's after function
+
+  Example use:

       (def my-interceptor
-        (->interceptor
-         :id     :my-interceptor
+        (->interceptor
+         :id     :my-interceptor
          :before (fn [context]            ;; you normally want to change :coeffects
                    ... in here use get-coeffect  and assoc-coeffect)
          :after  (fn [context]                         ;; you normally want to change :effects
@@ -672,10 +662,10 @@
   (utils/apply-kw interceptor/->interceptor m))

 (defn get-coeffect
-  "A utility function, typically used when writing an interceptor's `:before` function.
-
+  "A utility function, typically used when writing an interceptor's `:before` function.
+
    When called with one argument, it returns the `:coeffects` map from with that `context`.
-
+
    When called with two or three arguments, behaves like `clojure.core/get` and
    returns the value mapped to `key` in the `:coeffects` map within `context`, `not-found` or
    `nil` if `key` is not present."
@@ -687,18 +677,18 @@
    (interceptor/get-coeffect context key not-found)))

 (defn assoc-coeffect
-  "A utility function, typically used when writing an interceptor's `:before` function.
-
+  "A utility function, typically used when writing an interceptor's `:before` function.
+
    Adds or updates a key/value pair in the `:coeffects` map within `context`. "
   [context key value]
   (interceptor/assoc-coeffect context key value))

 (defn get-effect
-  "A utility function, used when writing interceptors, typically within an `:after` function.
-
+  "A utility function, used when writing interceptors, typically within an `:after` function.
+
    When called with one argument, returns the `:effects` map from the `context`.
-
-   When called with two or three arguments, behaves like `clojure.core/get` and
+
+   When called with two or three arguments, behaves like `clojure.core/get` and
    returns the value mapped to `key` in the effects map, `not-found` or
    `nil` if `key` is not present."
   ([context]
@@ -709,15 +699,15 @@
    (interceptor/get-effect context key not-found)))

 (defn assoc-effect
-   "A utility function, typically used when writing an interceptor's `:after` function.
-
+   "A utility function, typically used when writing an interceptor's `:after` function.
+
    Adds or updates a key/value pair in the `:effects` map within `context`. "
   [context key value]
   (interceptor/assoc-effect context key value))

 (defn enqueue
-  "An advanced utility function, typically used when writing an interceptor's `:before` function.
-
+  "An advanced utility function, typically used when writing an interceptor's `:before` function.
+
   Adds a collection of `interceptors` to the end of `context's` execution `:queue`, and then
   returns the updated `context`."
   [context interceptors]
@@ -729,32 +719,32 @@
 (defn set-loggers!
   "Internally, re-frame uses the logging functions: `warn`, `log`, `error`, `group` and `groupEnd`

-   By default, these functions map directly to the default `js/console` implementations,
-   but you can override with your own fns (set or subset) if you wish to handle the logging yourself.
-
-   `new-loggers` should be a map containing a subset of they keys for the standard `loggers`.
+  By default, these functions map directly to the default `js/console` implementations,
+  but you can override with your own fns (set or subset) if you wish to handle the logging yourself.
+
+  `new-loggers` should be a map containing a subset of they keys for the standard `loggers`.

   Example Usage:
-
+
       (defn my-logger      ;; here is my alternative logging function
-        [& args]
-        (post-it-somewhere (apply str args)))
-
-      ;; now install my alternative loggers
-      (re-frame.core/set-loggers!  {:warn my-logger :log my-logger})
+        [& args]
+        (post-it-somewhere (apply str args)))
+
+      ;; now install my alternative loggers
+      (re-frame.core/set-loggers!  {:warn my-logger :log my-logger})
    "
   [new-loggers]
   (loggers/set-loggers! new-loggers))

 (defn console
-  "A utility function for use in libraries which extend re-frame, like
-   perhaps an effect handler, when they want to produce log output.
-
-   It will write the given `args` to js/console at the given `level`.
-
-   `level` can be one of `:log` `:error` `:warn` `:debug` `:group` `:groupEnd`.
-
+  "A utility function for use in libraries which extend re-frame, like
+  perhaps an effect handler, when they want to produce log output.
+
+  It will write the given `args` to js/console at the given `level`.
+
+  `level` can be one of `:log` `:error` `:warn` `:debug` `:group` `:groupEnd`.
+
   Example usage:

       (console :error \"Oh, dear God, it happened:\" a-var \"and\" another)
@@ -766,12 +756,12 @@
 ;; -- unit testing ------------------------------------------------------------

 (defn make-restore-fn
-  "A utility function, typically used in testing.
-
-   Checkpoints the state of re-frame and returns a function which, when
-   later called, will restore re-frame to that checkpointed state.
-
-   Checkpoint includes app-db, all registered handlers and all subscriptions.
+  "A utility function, typically used in testing.
+
+  Checkpoints the state of re-frame and returns a function which, when
+  later called, will restore re-frame to that checkpointed state.
+
+  Checkpoint includes app-db, all registered handlers and all subscriptions.
   "
   []
   (let [handlers @registrar/kind->id->handler
@@ -803,12 +793,12 @@
 (defn add-post-event-callback
   "Registers a function `f` to be called after each event is processed
    `f` will be called with two arguments:
-
+
     - `event`: a vector. The event just processed.
     - `queue`: a PersistentQueue, possibly empty, of events yet to be processed.

    This is useful in advanced cases like:
-
+
      - you are implementing a complex bootstrap pipeline
      - you want to create your own handling infrastructure, with perhaps multiple
        handlers for the one event, etc.  Hook in here.
@@ -824,8 +814,8 @@

 (defn remove-post-event-callback
-  "Unregisters a post event callback function, identified by `id`. Such a
-   function would  have been registered in the first place via `add-post-event-callback`"
+  "Unregisters a post event callback function, identified by `id`. Such a
+  function would  have been registered in the first place via `add-post-event-callback`"
   [id]
   (router/remove-post-event-callback re-frame.router/event-queue id))


Add console to core.

Add console to core.

--- src/re_frame/core.cljs
+++ src/re_frame/core.cljs
@@ -71,7 +71,7 @@
 ;;   (defn my-fn [& args]  (post-it-somewhere (apply str args)))
 ;;   (re-frame.core/set-loggers!  {:warn my-fn :log my-fn})    ;; I should override the rest of them too.
 (def set-loggers! loggers/set-loggers!)
-
+(def console loggers/console)

 ;; -- Event Procssing Callbacks


fix the scrolling and zoom (has nothing to do with inverted from device!)

--- src-cljs/frontend/components/canvas.cljs
+++ src-cljs/frontend/components/canvas.cljs
@@ -283,16 +283,13 @@
                                  (.preventDefault event)
                                  (.stopPropagation event)
                                  (let [dx     (- (aget event "deltaX"))
-                                       dy     (if (aget event "nativeEvent" "webkitDirectionInvertedFromDevice")
-                                                ;; Detect inverted scroll (natural scroll)
-                                                (aget event "deltaY")
-                                                (- (aget event "deltaY")))]
+                                       dy     (aget event "deltaY")]
                                    (om/transact! payload (fn [state]
                                                            (let [camera (cameras/camera state)
                                                                  mode   (cameras/camera-mouse-mode state)]
                                                              (if (= mode :zoom)
                                                                (cameras/set-zoom state (partial + (* -0.002 dy)))
-                                                               (cameras/move-camera state dx dy)))))))}
+                                                               (cameras/move-camera state dx (- dy))))))))}
                  (dom/defs nil
                    (dom/pattern #js {:id           "small-grid"
                                      :width        (str (cameras/grid-width camera))


Implement a better memoize for parallel use cases

Implement an alternate memoize which performs better than clojure.core/memoize when the memoized function is invoked in parallel by ensuring that memoized values cannot be recalculated even by retry behavior on clojure.core/swap!

--- src/flatland/useful/parallel.clj
+++ src/flatland/useful/parallel.clj
@@ -17,3 +17,34 @@
                       (let [body (wrap-fn #(doall (map f slice)))]
                         (future-call body)))
                     (slice *pcollect-thread-num* coll))))))
+
+
+(defn- assoc-noclobber
+  "An assoc wrapper which ensures that existing keys will not be
+  clobbered by subsequent assoc invocations.
+
+  Used as a helper for locking-memoize to ensure that (delay) refs
+  cannot be lost by swap! retry behavior."
+
+  [m k v]
+  (if (contains? m k) m
+      (assoc m k v)))
+
+(defn pmemoize
+  "Memoizes the function f, using the same approach as
+  clojure.core/memoize. The practical difference is that this function
+  provides the gurantee that in spite of parallel invocations of the
+  memoized function each input to f will only ever be memoized
+  once. This resolves an implementation detail in clojure.core/memoize
+  which allows f to be applied to args without locking the cache to
+  prevent other threads duplicating the work."
+
+  [f]
+  (let [mem (atom {})]
+    (fn [ & args ]
+      (if-let [e (find @mem args)]
+        (deref (val e))
+        (-> (swap! mem assoc-noclobber
+                   args (delay (apply f args)))
+            (get args)
+            (deref))))))


remove errant println!

remove errant println!

--- src/pronouns/pages.clj
+++ src/pronouns/pages.clj
@@ -133,7 +133,6 @@
         alternates (map #(lookup-pronouns (escape-html %)
                                           pronouns-table)
                         ors)]
-    (println pronoun-declension)
     (if pronoun-declension
       (format-pronoun-examples pronoun-declension alternates)
       (not-found))))


Simplify the intermediate data used when building the dispatch handler

--- src/io/aviso/rook/dispatcher.clj
+++ src/io/aviso/rook/dispatcher.clj
@@ -56,7 +56,7 @@
   provided by the values."
   {'show    [:get [:id]]
    'modify  [:put [:id]]
-   ;; change will be removed in 0.1.17
+   ;; change will be removed at some point
    'change  [:put [:id]]
    'patch   [:patch [:id]]
    'destroy [:delete [:id]]
@@ -219,14 +219,13 @@
   (cons :function (-> #'map meta keys)))

 (defn- analyze*
-  [[routes handlers middleware namespaces-metadata] arg-resolvers dispatch-table-entry]
-  (if-let [[method pathvec verb-fn-sym mw-spec] dispatch-table-entry]
+  [[routes handlers namespaces-metadata] arg-resolvers dispatch-table-entry]
+  (if-let [[method pathvec verb-fn-sym endpoint-middleware] dispatch-table-entry]
     (t/track
       (format "Analyzing endpoint function `%s'." verb-fn-sym)
       (let [handler-key (gensym "handler-key__")
             routes' (assoc routes
                            [method (keywords->symbols pathvec)] handler-key)
-            [middleware' middleware-key] (caching-get middleware mw-spec #(gensym "middleware-key__"))

             ns-symbol (-> verb-fn-sym namespace symbol)

@@ -253,16 +252,16 @@
             ;; and metadata is merged onto that.
             arg-resolvers (merge arg-resolvers (:arg-resolvers metadata))
             handler (cond->
-                      {:middleware-key middleware-key
-                       :route-params   route-params
-                       :verb-fn-sym    verb-fn-sym
-                       :arglist        arglist
-                       :arg-resolvers  arg-resolvers
-                       :metadata       metadata}
+                      {:middleware    endpoint-middleware
+                       :route-params  route-params
+                       :verb-fn-sym   verb-fn-sym
+                       :arglist       arglist
+                       :arg-resolvers arg-resolvers
+                       :metadata      metadata}
                       context
                       (assoc :context (string/join "/" (cons "" context))))
             handlers' (assoc handlers handler-key handler)]
-        [routes' handlers' middleware' namespaces-metadata']))))
+        [routes' handlers' namespaces-metadata']))))

 (declare default-arg-resolver-factories default-arg-resolvers)

@@ -304,10 +303,9 @@
            entries (seq (unnest-dispatch-table dispatch-table))]
       (if-let [analyze-state' (analyze* analyze-state arg-resolvers (first entries))]
         (recur analyze-state' (next entries))
-        (let [[routes handlers middleware] analyze-state]
-          {:routes     (sorted-routes routes)
-           :handlers   handlers
-           :middleware (set/map-invert middleware)})))))
+        (let [[routes handlers] analyze-state]
+          {:routes   (sorted-routes routes)
+           :handlers handlers})))))

 (defn- map-traversal-dispatcher
   "Returns a Ring handler using the given dispatch-map to guide
@@ -508,12 +506,12 @@

 (defn- build-dispatch-map
   "Returns a dispatch-map for use with map-traversal-dispatcher."
-  [{:keys [routes handlers middleware]}
+  [{:keys [routes handlers]}
    {:keys [async? arg-resolvers sync-wrapper]}]
   (reduce (fn [dispatch-map [[method pathvec] handler-key]]
             (t/track #(format "Compiling handler for `%s'."
                               (get-in handlers [handler-key :verb-fn-sym]))
-                     (let [{:keys           [middleware-key route-params
+                     (let [{:keys           [middleware route-params
                                              verb-fn-sym arglist
                                              metadata context]
                             extra-resolvers :arg-resolvers}
@@ -527,8 +525,6 @@
                                                   extra-resolvers))
                                               (set route-params)
                                               arglist)
-
-                           middleware (get middleware middleware-key)

                            ;; middleware may return nil, so:


cleanup

cleanup

--- src/babel/francais/morphology/verbs.cljc
+++ src/babel/francais/morphology/verbs.cljc
@@ -9,9 +9,6 @@
    [dag_unify.core :refer (copy dissoc-paths fail? get-in ref? strip-refs unify)]))

 ;; TODO: convert to (babel.morphology/conjugation) (see babel.latin.morphology for an example of how to use conjugation)
-
-(def agr :top)
-
 (def present-nonreflexive-er-verb
   (map
    #(merge %


simplifying irregular conjugations

simplifying irregular conjugations

--- src/babel/italiano/morphology/verbs.cljc
+++ src/babel/italiano/morphology/verbs.cljc
@@ -410,90 +410,76 @@
                         :person :3rd}}})}])

 (defn irregular-future [word]
-  (let [person (get-in word '(:agr :person))
-        number (get-in word '(:agr :number))]
+  (let [person (get-in word [:agr :person])
+        number (get-in word [:agr :number])
+        exception-map (get-in word [:future])]
     (cond
       (and (= person :1st) (= number :sing))
-      (get-in word '(:future :1sing))
+      (get-in exception-map [:1sing])
       (and (= person :2nd) (= number :sing))
-      (get-in word '(:future :2sing))
+      (get-in exception-map [:2sing])
       (and (= person :3rd) (= number :sing))
-      (get-in word '(:future :3sing))
+      (get-in exception-map [:3sing])
       (and (= person :1st) (= number :plur))
-      (get-in word '(:future :1plur))
+      (get-in exception-map [:1plur])
       (and (= person :2nd) (= number :plur))
-      (get-in word '(:future :2plur))
+      (get-in exception-map [:2plur])
       (and (= person :3rd) (= number :plur))
-      (get-in word '(:future :3plur))
-
-      (and (= (get-in word '(:infl)) :future)
-           (string? (get-in word '(:italiano))))
-      (str (get-in word '(:italiano)) " (future)")
+      (get-in exception-map [:3plur])

       true ;; failthrough: should usually not get here:
       ;; TODO: describe when it might be ok, i.e. why log/warn not log/error.
-      (do (log/warn (str "get-string-1 could not match: " word))
-          word))))
-
-(defn irregular-imperfect-1sing? [word]
-  (and
-   (= (get-in word '(:infl)) :imperfect)
-   (= :sing (get-in word '(:agr :number)))
-   (= :1st (get-in word '(:agr :person)))
-   (string? (get-in word '(:imperfect :1sing)))))
-
-(defn irregular-imperfect-1sing [word]
-  (get-in word [:imperfect :1sing]))
-
-(defn irregular-imperfect-2sing? [word]
-  (and
-   (= (get-in word '(:infl)) :imperfect)
-   (= :sing (get-in word '(:agr :number)))
-   (= :2nd (get-in word '(:agr :person)))
-   (string? (get-in word '(:imperfect :2sing)))))
-
-(defn irregular-imperfect-2sing [word]
-  (get-in word [:imperfect :2sing]))
-
-(defn irregular-imperfect-3sing? [word]
-  (and
-   (= (get-in word '(:infl)) :imperfect)
-   (= :sing (get-in word '(:agr :number)))
-   (= :3rd (get-in word '(:agr :person)))
-   (string? (get-in word '(:imperfect :3sing)))))
-
-(defn irregular-imperfect-3sing [word]
-  (get-in word [:imperfect :3sing]))
-
-(defn irregular-imperfect-1plur? [word]
-  (and
-   (= (get-in word '(:infl)) :imperfect)
-   (= :plur (get-in word '(:agr :number)))
-   (= :1st (get-in word '(:agr :person)))
-   (string? (get-in word '(:imperfect :1plur)))))
-
-(defn irregular-imperfect-1plur [word]
-  (get-in word [:imperfect :1plur]))
-
-(defn irregular-imperfect-2plur? [word]
-  (and
-   (= (get-in word '(:infl)) :imperfect)
-   (= :plur (get-in word '(:agr :number)))
-   (= :2nd (get-in word '(:agr :person)))
-   (string? (get-in word '(:imperfect :2plur)))))
-
-(defn irregular-imperfect-2plur [word]
-  (get-in word [:imperfect :2plur]))
-
-(defn irregular-imperfect-3plur? [word]
-  (and
-   (= (get-in word '(:infl)) :imperfect)
-   (= :plur (get-in word '(:agr :number)))
-   (= :3rd (get-in word '(:agr :person)))
-   (string? (get-in word '(:imperfect :3plur)))))
-
-(defn irregular-imperfect-3plur [word]
-  (get-in word [:imperfect :3plur]))
+      (throw (Exception. (str "irregular-future could not match: " word))))))
+
+;; TODO: convert to (defn irregular-imperfect [word])
+;; as above with (defn irregular-future [word])
+(defn irregular-imperfect [word]
+  (let [person (get-in word [:agr :person])
+        number (get-in word [:agr :number])
+        exception-map (get-in word [:imperfect])]
+    (cond
+      (and (= person :1st) (= number :sing))
+      (get-in exception-map [:1sing])
+      (and (= person :2nd) (= number :sing))
+      (get-in exception-map [:2sing])
+      (and (= person :3rd) (= number :sing))
+      (get-in exception-map [:3sing])
+      (and (= person :1st) (= number :plur))
+      (get-in exception-map [:1plur])
+      (and (= person :2nd) (= number :plur))
+      (get-in exception-map [:2plur])
+      (and (= person :3rd) (= number :plur))
+      (get-in exception-map [:3plur])
+
+      true ;; failthrough: should usually not get here:
+      ;; TODO: describe when it might be ok, i.e. why log/warn not log/error.
+      (throw (Exception. (str "irregular-imperfect could not match: " word))))))
+
+(defn irregular-present [word]
+  (let [person (get-in word [:agr :person])
+        number (get-in word [:agr :number])
+        exception-map (get-in word [:present])]
+    (cond
+      (and (= person :1st) (= number :sing)
+           (get-in exception-map [:1sing]))
+      (get-in exception-map [:1sing])
+      (and (= person :2nd) (= number :sing)
+           (get-in exception-map [:2sing]))
+      (get-in exception-map [:2sing])
+      (and (= person :3rd) (= number :sing)
+           (get-in exception-map [:3sing]))
+      (get-in exception-map [:3sing])
+      (and (= person :1st) (= number :plur)
+           (get-in exception-map [:1plur]))
+      (get-in exception-map [:1plur])
+      (and (= person :2nd) (= number :plur)
+           (get-in exception-map [:2plur]))
+      (get-in exception-map [:2plur])
+      (and (= person :3rd) (= number :plur)
+           (get-in exception-map [:3plur]))
+      (get-in exception-map [:3plur])
+
+      true nil)))

 (defn passato-as-head? [word]
   ;; "fare [past]" + "bene" => "fatto bene"
@@ -506,10 +492,6 @@
        (get-in word '(:b))))

 (defn irregular-passato? [word]
-  ;; TODO: do not use brackets: if there's an error about there being
-  ;; not enough information, throw an exception explicitly.
-  ;; return the irregular form in square brackets, indicating that there's
-  ;; not enough information to conjugate the verb.
   (and (= :past (get-in word '(:infl)))
        (get-in word '(:passato))
        (get-in word '(:essere) true)
@@ -529,6 +511,7 @@

 (defn suffix-of [word]
   "compute the final character given a lexical entry and agreement info in :agr."
+  ;; TODO: convert to .edn
   (let [suffix (cond

                  (and (= (get-in word '(:obj-agr :gender)) :fem)
@@ -567,72 +550,6 @@
         butlast (nth (re-find #"(.*).$" irregular-passato) 1)]
     (str butlast (suffix-of word))))

-(defn irregular-present-1sing? [word]
-  ;; <irregular present tense>
-  (let [person (get-in word '(:agr :person))
-        number (get-in word '(:agr :number))]
-    (and (= (get-in word '(:infl)) :present)
-         (= person :1st) (= number :sing)
-         (string? (get-in word '(:present :1sing))))))
-
-(defn irregular-present-1sing [word]
-  (get-in word '(:present :1sing)))
-
-(defn irregular-present-2sing? [word]
-  ;; <irregular present tense>
-  (let [person (get-in word '(:agr :person))
-        number (get-in word '(:agr :number))]
-    (and (= (get-in word '(:infl)) :present)
-         (= person :2nd) (= number :sing)
-         (string? (get-in word '(:present :2sing))))))
-
-(defn irregular-present-2sing [word]
-  (get-in word '(:present :2sing)))
-
-(defn irregular-present-3sing? [word]
-  ;; <irregular present tense>
-  (let [person (get-in word '(:agr :person))
-        number (get-in word '(:agr :number))]
-    (and (= (get-in word '(:infl)) :present)
-         (= person :3rd) (= number :sing)
-         (string? (get-in word '(:present :3sing))))))
-
-(defn irregular-present-3sing [word]
-  (get-in word '(:present :3sing)))
-
-(defn irregular-present-1plur? [word]
-  ;; <irregular present tense>
-  (let [person (get-in word '(:agr :person))
-        number (get-in word '(:agr :number))]
-    (and (= (get-in word '(:infl)) :present)
-         (= person :1st) (= number :plur)
-         (string? (get-in word '(:present :1plur))))))
-
-(defn irregular-present-1plur [word]
-  (get-in word '(:present :1plur)))
-
-(defn irregular-present-2plur? [word]
-  ;; <irregular present tense>
-  (let [person (get-in word '(:agr :person))
-        number (get-in word '(:agr :number))]
-    (and (= (get-in word '(:infl)) :present)
-         (= person :2nd) (= number :plur)
-         (string? (get-in word '(:present :2plur))))))
-
-(defn irregular-present-2plur [word]
-  (get-in word '(:present :2plur)))
-
-(defn irregular-present-3plur? [word]
-  ;; <irregular present tense>
-  (let [person (get-in word '(:agr :person))
-        number (get-in word '(:agr :number))]
-    (and (= (get-in word '(:infl)) :present)
-         (= person :3rd) (= number :plur)
-         (string? (get-in word '(:present :3plur))))))
-
-(defn irregular-present-3plur [word]
-  (get-in word '(:present :3plur)))
-
 (defn regular-present [word]
   (log/debug (str "(regular-present " (dag_unify.core/strip-refs word) ")"))
   (let [unifying-patterns
@@ -675,23 +592,10 @@
     (= (get-in word [:infl]) :conditional)
     (regular-conditional word)

-    (irregular-imperfect-1sing? word)
-    (irregular-imperfect-1sing word)
-
-    (irregular-imperfect-2sing? word)
-    (irregular-imperfect-2sing word)
-
-    (irregular-imperfect-3sing? word)
-    (irregular-imperfect-3sing word)
-
-    (irregular-imperfect-1plur? word)
-    (irregular-imperfect-1plur word)
-
-    (irregular-imperfect-2plur? word)
-    (irregular-imperfect-2plur word)
-
-    (irregular-imperfect-3plur? word)
-    (irregular-imperfect-3plur word)
+    (and
+     (= (get-in word '(:infl)) :imperfect)
+     (map? (get-in word '(:imperfect))))
+    (irregular-imperfect word)

     (= (get-in word [:infl]) :imperfect)
     (regular-imperfect word)
@@ -708,23 +612,11 @@
     (= :past (get-in word '(:infl)))
     (regular-passato word)

-    (irregular-present-1sing? word)
-    (irregular-present-1sing word)
-
-    (irregular-present-2sing? word)
-    (irregular-present-2sing word)
-
-    (irregular-present-3sing? word)
-    (irregular-present-3sing word)
-
-    (irregular-present-1plur? word)
-    (irregular-present-1plur word)
-
-    (irregular-present-2plur? word)
-    (irregular-present-2plur word)
-
-    (irregular-present-3plur? word)
-    (irregular-present-3plur word)
+    (and
+     (= (get-in word '(:infl)) :present)
+     (map? (get-in word '(:present)))
+     (not (nil? (irregular-present word))))
+    (irregular-present word)

     (= (get-in word '(:infl)) :present)
     (regular-present word)
@@ -732,8 +624,8 @@
     (irregular-gerund? word)
     (irregular-gerund word)

-   (= (get-in word [:infl]) :participle)
+    (= (get-in word [:infl]) :participle)
     (regular-gerund word)
-
     ))

+


code-ids fixed (list is now returns only names)

--- src/clj/backtype/storm/daemon/nimbus.clj
+++ src/clj/backtype/storm/daemon/nimbus.clj
@@ -725,7 +725,7 @@
     ))

 (defn code-ids [storage]
-  (set (.list storage (nimbus-storage-stormdist-root))))
+  (set (.list storage (nimbus-storage-stormdist-root) false)))

 (defn cleanup-storm-ids [storage storm-cluster-state]
   (let [heartbeat-ids (set (.heartbeat-storms storm-cluster-state))


More refactors

More refactors

--- src/cljs/load_test_client/histogram.cljs
+++ src/cljs/load_test_client/histogram.cljs
@@ -36,15 +36,20 @@
                    :d (str "M0" (aget rng 0) ",6V0H" (aget rng 1) "V6")})))

 (defn render-x-axis-ticks [x-scale]
-  (let [tick-arguments (array 10)
-        ticks (if (.-ticks x-scale)
-                (.apply (.-ticks x-scale) x-scale tick-arguments)
-                (.domain x-scale))]
+  (let [ticks (.apply (.-ticks x-scale) x-scale)]
     (apply dom/g nil (map (fn [tick]
                             (dom/g #js {:className "tick" :transform (str "translate(" (x-scale tick) ",0)")}
                                    (dom/line #js {:x2 0 :y2 6})
                                    (dom/text #js {:dy ".71em" :y 9 :x 0 :style #js {:textAnchor "middle"}} tick)))
                           ticks))))
+
+(defn x-axis-component [{:keys [chart-height scale]} owner]
+  (reify
+    om/IRender
+    (render [_]
+      (dom/g #js {:className "x axis" :transform (str "translate(0," chart-height ")")}
+             (render-x-axis-path scale)
+             (render-x-axis-ticks scale)))))

 (defn component [{:keys [data-points]} owner]
   (reify
@@ -61,13 +66,12 @@
             data ((-> (.. js/d3 -layout histogram)
                       (.bins (.ticks x-scale 20)))
                   (apply array response-times))
+
             y-scale (get-y-scale data)]

         (dom/div #js {:className "chart response-time-histogram"}
                  (dom/svg #js {:width (+ chart-width left right)
                                :height (+ chart-height top bottom)}
                           (apply dom/g #js {:transform (str "translate(" left "," top ")")}
-                                 (dom/g #js {:className "x axis" :transform (str "translate(0," chart-height ")")}
-                                        (render-x-axis-path x-scale)
-                                        (render-x-axis-ticks x-scale))
+                                 (om/build x-axis-component {:chart-height chart-height :scale x-scale})
                                  (map #(render-bar x-scale y-scale %) data))))))))


webcam turns off now

webcam turns off now

--- src/cljs/re_form/inputs/webcam_impl.cljs
+++ src/cljs/re_form/inputs/webcam_impl.cljs
@@ -18,11 +18,21 @@
               -mediaDevices
               (getUserMedia (clj->js {:video true}))
               (then (fn [stream]
+                      (swap! widget-state assoc-in [photo-name :video-tracks] (js->clj (.getVideoTracks stream)))
                       (set! (.-src video) (.. js/window
                                               -URL
                                               (createObjectURL stream)))
                       (.play video)))))))
-    :component-will-unmount #(reset! widget-state {})
+
+    :component-will-unmount
+    (fn [_]
+      ;; FIXME here we deinit all widgets at once
+      ;; assumption is they are all the part of one page
+      (let [tracks (mapcat :video-tracks (vals @widget-state))]
+        (doseq [t tracks]
+          (when t (.stop t)))
+        (reset! widget-state {})))
+
     :reagent-render
     (fn [{:keys [photo-name width height]}]
       [:div.re-webcam {:style {:padding "10px"}}


Accessibility Improvements

Accessibility Improvements

--- src/cljs/salava/location/ui/explore.cljs
+++ src/cljs/salava/location/ui/explore.cljs
@@ -9,7 +9,8 @@
             [salava.core.ui.helper :refer [js-navigate-to path-for private? plugin-fun]]
             [salava.core.ui.layout :as layout]
             [salava.core.i18n :refer [t translate-text]]
-            [salava.location.ui.util :as lu]))
+            [salava.location.ui.util :as lu]
+            [dommy.core :as dommy :refer-macros [sel1 sel]]))

 (defn icon [kind num]
   (get (if (= num 1)
@@ -58,22 +59,47 @@
                  (js/L.marker. (clj->js {:icon icon :title title}))
                  (.on "click" (click-cb item unique-count)))))))})))

+#_(defn filter-autocomplete [kind state]
+    (let [filter (cursor state [kind])
+          class-name (str (name kind) "-filter")
+          placeholder (keyword "location" (str (name kind) "FilterField"))]
+      (fn []
+        [autocomplete/autocomplete
+         {:value (:value @filter)
+          :on-change (fn [item]
+                       (swap! filter assoc :value (:key item))
+                       (.trigger (js/jQuery (str "div.badges-filter ." class-name " input")) "change"))
+          :search-fields   [:value]
+          :items           (:autocomplete @filter)
+          :no-results-text " "
+          :placeholder     (t placeholder)
+          :control-class   (str "form-control " class-name)
+          :max-results     100}])))
+
 (defn filter-autocomplete [kind state]
   (let [filter (cursor state [kind])
         class-name (str (name kind) "-filter")
         placeholder (keyword "location" (str (name kind) "FilterField"))]
-    (fn []
-      [autocomplete/autocomplete
-       {:value (:value @filter)
-        :on-change (fn [item]
-                     (swap! filter assoc :value (:key item))
-                     (.trigger (js/jQuery (str "div.badges-filter ." class-name " input")) "change"))
-        :search-fields   [:value]
-        :items           (:autocomplete @filter)
-        :no-results-text " "
-        :placeholder     (t placeholder)
-        :control-class   (str "form-control " class-name)
-        :max-results     100}])))
+    (create-class
+     {:reagent-render
+      (fn []
+        [autocomplete/autocomplete
+         {:value (:value @filter)
+          :on-change (fn [item]
+                       (swap! filter assoc :value (:key item))
+                       (.trigger (js/jQuery (str "div.badges-filter ." class-name " input")) "change"))
+          :search-fields   [:value]
+          :items           (:autocomplete @filter)
+          :no-results-text " "
+          :placeholder     (t placeholder)
+          :control-class   (str "form-control " class-name)
+          :max-results     100}])
+      :component-did-mount
+      (fn []
+        (-> (sel1 ".autocomplete__input")
+            (dommy/set-attr! :aria-label (t placeholder)))
+        (-> (sel1 ".autocomplete__clear-button")
+            (dommy/set-attr! :aria-hidden true)))})))

 (defn map-view [state]
   (create-class


fixed mapchan

fixed mapchan

--- src/cljs/swannodette/utils/reactive.cljs
+++ src/cljs/swannodette/utils/reactive.cljs
@@ -51,7 +51,8 @@
     (let [out (chan)]
       (go (loop []
             (if-let [x (<! in)]
-              (do (>! out (<! (if f (f x) x)))
+              (do
+                (dochan [v (if f (f x) x)] (>! out v))
                 (recur))
               (close! out))))
       out)))


remove 404 from handler -> we're using that internally so 404 can't happen

--- src/cljs/swarmpit/component/handler.cljs
+++ src/cljs/swarmpit/component/handler.cljs
@@ -18,8 +18,7 @@
   (case resp-status
     401 (router/set-location {:handler :login})
     403 (router/set-location {:handler :unauthorized})
-    404 (router/set-route {:handler :not-found})
-    (dispatch! (routes/path-for-frontend :error {} {:stacktrace resp-body}))))
+    500 (dispatch! (routes/path-for-frontend :error {} {:stacktrace resp-body}))))

 (defn- command
   [request]


Tests: test-get-word-class, test-get-word-class-exception-handling, test-get-source, and test-get-source-exception-handling

--- test/clj_mrazik/importer_test.clj
+++ test/clj_mrazik/importer_test.clj
@@ -81,6 +81,32 @@
         (is (= 0 (parse-use-it "No")))
         (is (= 2 (parse-use-it "with caution")))))

+(deftest test-get-word-class
+    "Check the function get-word-class"
+    (testing "Function get-word-class"
+        (with-redefs [db-interface/select-word-class-id (fn [input] "verb")]
+            (is (nil? (get-word-class nil)))
+            (is (= "verb" (get-word-class 1))))))
+
+(deftest test-get-word-class-exception-handling
+    "Check the function get-word-class"
+    (testing "Function get-word-class"
+        (with-redefs [db-interface/select-word-class-id (fn [input] (throw (new Exception "exception")))]
+            (is (nil? (get-word-class 42))))))
+
+(deftest test-get-source
+    "Check the function get-source"
+    (testing "Function get-source"
+        (with-redefs [db-interface/select-source-id (fn [input] "Glossary")]
+            (is (nil? (get-source nil)))
+            (is (= "Glossary" (get-source 1))))))
+
+(deftest test-get-source-exception-handling
+    "Check the function get-source"
+    (testing "Function get-source"
+        (with-redefs [db-interface/select-source-id (fn [input] (throw (new Exception "exception")))]
+            (is (nil? (get-source 42))))))
+
 (deftest test-read-csv
     "Check the function read-cvs"
     (testing "read-csv"


Description to svg helpers

Description to svg helpers

--- src/export_server/utils/rasterizator.clj
+++ src/export_server/utils/rasterizator.clj
@@ -15,9 +15,11 @@
 ;====================================================================================
 ; SVG string helpers
 ;====================================================================================
+;; remove empty images - cause of error during pdf processing
 (defn- remove-empty-img [svg]
   (clojure.string/replace svg #"<image[^>]*xlink:href=\"data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\"[^\<]*" ""))

+;; remove paths with 0.00001 opacity - cause of some other labels invisibility
 (defn- remove-opacity [svg]
   (clojure.string/replace svg #"<path[^>]*fill-opacity=\"0\.0+1\"[^<]*" ""))


Re-implement core to gain performance and simplify code #44 - text size measurements

--- src/flatgui/samples/forms/textwindow.clj
+++ src/flatgui/samples/forms/textwindow.clj
@@ -48,7 +48,9 @@
       textfield/textfield
       :textfield2
       {:clip-size (m/defpoint 4.875 0.375)
-       :position-matrix (m/translation 0.125 5.0)})))
+       :position-matrix (m/translation 0.125 5.0)
+       :font "8px sans-serif"
+       :evolvers {:font nil}})))

 (def root-panel
   (fg/defcomponent
@@ -62,5 +64,7 @@
      ;; TODO this should be a part defroot probably
      :closed-focus-root true
      :focus-state {:mode :has-focus
-                   :focused-child nil}}
+                   :focused-child nil}
+
+     :evolvers {:font nil}}
     text-window))


use an async channel for slide! updates over an agent

--- src/tile_game/core.clj
+++ src/tile_game/core.clj
@@ -1,5 +1,6 @@
 (ns tile-game.core
   (:use [tile-game board])
+  (:require [clojure.core.async :as a])
   (:import [javax.swing JFrame JPanel]
            [java.awt Color Graphics Graphics2D Dimension Font]
            [java.awt.event KeyAdapter KeyEvent]))
@@ -28,6 +29,15 @@

 (def board (ref (create-board 2)))

+(defn slide!
+  [render & moves]
+  (prn :slide! moves)
+  (a/go
+    (doseq [piece moves]
+      (dosync (alter board slide piece))
+      (a/>! render :render)
+      (Thread/sleep 150))))
+
 (defn start-gui [dim]
   (let [size (* dim scale)
         #^JFrame frame (JFrame.)
@@ -35,15 +45,7 @@
                          (paint [g]
                            (doseq [x (range dim) y (range dim)]
                              (render-tile g @board [x y]))))
-        slide!
-        (fn [& moves]
-          (prn :slide! moves)
-          (send (agent moves)
-                (fn [moves]
-                  (doseq [piece moves]
-                    (dosync (alter board slide piece))
-                    (.repaint panel)
-                    (Thread/sleep 150)))))
+        render (a/chan)
         shuffle-board!
         (fn [dim] (dosync (ref-set board
                                    (create-board dim :shuffle))))]
@@ -55,16 +57,19 @@
        (proxy [KeyAdapter] []
          (keyPressed [#^KeyEvent e]
            (condp = (.getKeyCode e)
-             KeyEvent/VK_LEFT  (slide! :left)
-             KeyEvent/VK_RIGHT (slide! :right)
-             KeyEvent/VK_UP    (slide! :up)
-             KeyEvent/VK_DOWN  (slide! :down)
+             KeyEvent/VK_LEFT  (slide! render :left)
+             KeyEvent/VK_RIGHT (slide! render :right)
+             KeyEvent/VK_UP    (slide! render :up)
+             KeyEvent/VK_DOWN  (slide! render :down)
              KeyEvent/VK_Q     (.dispose #^JFrame frame)
              KeyEvent/VK_R     (do (shuffle-board! dim) (.repaint panel))
-             KeyEvent/VK_S     (apply slide! (solve-next @board))
+             KeyEvent/VK_S     (apply slide! (cons render (solve-next @board)))
              true)))))
     (doto frame (.setContentPane panel) .pack .show)
-    slide!))
+    (a/go (while true
+            (a/<! render)
+            (.repaint panel)))
+    render))

 (defn -main [& [num]]
   (if num (start-gui (Integer/parseInt num))
@@ -72,4 +77,3 @@
   nil)

 ;(def slide! (main 5))
-


Todo tuples -> maps

Todo tuples -> maps

--- src/todomvc/rules.cljs
+++ src/todomvc/rules.cljs
@@ -12,14 +12,14 @@
         temp-id (random-uuid)]
     (conj
       (mapv (fn [[a v]] [eid a v]) (dissoc m :db/id)))))
-      ;[temp-id :db/id eid])))
+;[temp-id :db/id eid])))

 ;(defrecord Todo [id title done])
 ;
 (defn todo-tx [id title done]
   (merge
-    {:db/id      id
-     :todo/title title
+    {:db/id        id
+     :todo/title   title
      :todo/visible false}
     (when-not (nil? done)
       {:todo/status done})))
@@ -27,15 +27,15 @@
 ;(defrecord Showing [key])
 ;
 (defn showing-tx [id kw]
+  {:db/id                id
+   :ui/visibility-filter kw})
+
+;(defrecord VisibleTodos [todos])
+;
+;(defrecord ToggleComplete [])
+;
+(defn toggle-tx [id bool]
   {:db/id              id
-   :ui/visibility-filter kw})
-
-;(defrecord VisibleTodos [todos])
-;
-;(defrecord ToggleComplete [])
-;
-(defn toggle-tx [id bool]
-  {:db/id id
    :ui/toggle-complete bool})

 ;(defrule show-all
@@ -112,7 +112,7 @@
   =>
   (println "Mark done via toggle complete:" ?e)
   (insert-unconditional! [?e :todo/status :done]))
- ; and todos/status :done count === num of todos
+; and todos/status :done count === num of todos

 (defrule remove-toggle
   [?toggle <- :ui/toggle-complete [[e a v]] (= v true)]
@@ -153,13 +153,16 @@
 ;  [?todos <- (acc/all) :from [Todo (= done true)]])
 ;
 (defquery find-all-done []
-  [?todos <- (acc/all) :from [:todo/status [[e a v]] (= v :done)]])
+  ;[:all [[e a v]] (= e ?e) (= a ?a) (= v ?v)]
+  [:all [[e a v]] (= e ?e) (= a ?a) (= v ?v)]
+  [:test (= (attr-ns ?a) "todo")])
+
 ;(defquery find-done-count
 ;  []
 ;  [?count <- (acc/count) :from [Todo (= done true)]])
 ;
 (defquery find-done-count []
-  [?count <- (acc/count) from [:todo/status [[e a v]] (= v :done)]])
+  [?count <- (acc/count) :from [:todo/status [[e a v]] (= v :done)]])

 (defsession todos 'todomvc.rules
@@ -175,8 +178,24 @@

 @(def session (fire-rules (insert-all todos facts)))

-
-(println "Done count: "(query session find-done-count))
+@(def all-done (query session find-all-done))
+
+(defn clara-tups->maps
+  [tups]
+  (->> (group-by :?e tups)
+    (mapv (fn [[id ent]]
+           (into {:db/id id}
+             (reduce (fn [m tup] (assoc m  (:?a tup) (:?v tup)))
+               {} ent))))))
+
+
+(defn attr-ns [attr]
+  (subs (first (clojure.string/split attr "/")) 1))
+
+(cljs.pprint/pprint (clara-tups->maps all-done))
+
+
+(println "Done count: " (query session find-done-count))

 (println facts)


Renaming for consistency

Renaming for consistency

--- src/wishlistd/json.clj
+++ src/wishlistd/json.clj
@@ -5,7 +5,7 @@
   "Wraps the response in the json content type and generates JSON from the content. Uses Chesire for date support."
   [content]
   {:headers {"Content-Type" "application/json"}
-   :body (cheshire/generate-string content)})
+   :body (cheshire/encode content)})

 (defn encode [v]
   "Cheshire encode."


Fixed failing test.

Fixed failing test.

--- test/blutwurst/tuple_formatter_test.clj
+++ test/blutwurst/tuple_formatter_test.clj
@@ -11,34 +11,34 @@
   (testing "Generating a CSV from rows."
     (let [spec {:format :csv}
           table {:name "Example" :schema "foo" :properties '({:name "A" :type :integer} {:name "B" :type :integer})}
-          rows `({:table ~table :tuples ({:A 1 :B 2})})]
-      (is (= `[{:table ~table :tuples ["A,B\n1,2\n"]}]
+          rows `({:entity ~table :tuples ({:A 1 :B 2})})]
+      (is (= `[{:entity ~table :tuples ["A,B\n1,2\n"]}]
              (format-rows spec rows)))))

   (testing "Flattens out embedded objects."
     (let [spec {:format :csv}
           person-table {:name "Person" :schema nil :properties [{:name "Address" :type :complex} {:name "Name" :type :string}]
                         :dependencies [{:target-schema nil :target-name "Address" :dependency-name nil :links {"Address" :embedded}}]}
-          data `({:table ~person-table :tuples ~(list {:name "John Doe" :Address {:Address1 "123 Main" :City "Springfield"}})})]
-      (is (= [{:table person-table :tuples ["name,Address.Address1,Address.City\nJohn Doe,123 Main,Springfield\n"]}]
+          data `({:entity ~person-table :tuples ~(list {:name "John Doe" :Address {:Address1 "123 Main" :City "Springfield"}})})]
+      (is (= [{:entity person-table :tuples ["name,Address.Address1,Address.City\nJohn Doe,123 Main,Springfield\n"]}]
              (format-rows spec data))))))

 (deftest sql-formatter-test
   (testing "Basic SQL generation with integer-only values."
     (let [spec {:format :sql}
           table {:name "Example" :schema "foo" :properties '({:name "A" :type :integer} {:name "B" :type :integer})}
-          rows `({:table ~table
+          rows `({:entity ~table
                   :tuples ({:A 1 :B 2})})]
-      (is (= '({:table {:name "Example" :schema "foo" :properties ({:name "A" :type :integer} {:name "B" :type :integer})}
+      (is (= '({:entity {:name "Example" :schema "foo" :properties ({:name "A" :type :integer} {:name "B" :type :integer})}
                 :tuples ["INSERT INTO \"foo\".\"Example\" (\"A\",\"B\") VALUES (1,2);\n"]})
              (format-rows spec rows)))))

   (testing "SQL generation quotes and escapes string values."
     (let [spec {:format :sql}
           table {:name "Example" :schema "foo" :properties '({:name "A" :type :integer} {:name "B" :type :string})}
-          rows `({:table ~table
+          rows `({:entity ~table
                   :tuples ({:A 1 :B  "Then O'Kelly came in with the \t hatchett."})})]
-      (is (= `({:table ~table
+      (is (= `({:entity ~table
                 :tuples ["INSERT INTO \"foo\".\"Example\" (\"A\",\"B\") VALUES (1,'Then O''Kelly came in with the \t hatchett.');\n"]})
              (format-rows spec rows)))))

@@ -46,16 +46,16 @@
     (let [spec {:format :sql}
           person-table {:name "Person" :schema nil :properties [{:name "Address" :type :complex} {:name "Name" :type :string}]
                         :dependencies [{:target-schema nil :target-name "Address" :dependency-name nil :links {"Address" :embedded}}]}
-          data `({:table ~person-table :tuples ~(list {:Name "John Doe" :Address {:Address1 "123 Main" :City "Springfield"}})})]
-      (is (= [{:table person-table :tuples ["INSERT INTO \"Person\" (\"Name\",\"Address.Address1\",\"Address.City\") VALUES ('John Doe','123 Main','Springfield');\n"]}]
+          data `({:entity ~person-table :tuples ~(list {:Name "John Doe" :Address {:Address1 "123 Main" :City "Springfield"}})})]
+      (is (= [{:entity person-table :tuples ["INSERT INTO \"Person\" (\"Name\",\"Address.Address1\",\"Address.City\") VALUES ('John Doe','123 Main','Springfield');\n"]}]
              (format-rows spec data)))))

   (testing "SQL generation formats DATE values."
     (let [spec {:format :sql}
           table {:name "Example" :schema "foo" :properties '({:name "A" :type :integer} {:name "B" :type :datetime})}
-          rows `({:table ~table
+          rows `({:entity ~table
                   :tuples ({:A 1 :B ~(Date. 1109741401000)})})]
-      (is (= `({:table ~table
+      (is (= `({:entity ~table
                 :tuples ["INSERT INTO \"foo\".\"Example\" (\"A\",\"B\") VALUES (1,'2005-03-01T23:30:01.000-06:00');\n"]})
                   ; TODO: handle timezone in test
              (format-rows spec rows))))))
@@ -64,8 +64,8 @@
   (testing "Basic JSON generation."
     (let [spec {:format :json}
           table {:name "Example" :schema "foo" :properties '({:name "A" :type :integer} {:name "B" :type :string})}
-          rows `({:table ~table
+          rows `({:entity ~table
                   :tuples ({:A 1 :B  "\"Thus sayeth...\""})})]
-      (is (= `[{:table ~table
+      (is (= `[{:entity ~table
                 :tuples ["[{\"A\":1,\"B\":\"\\\"Thus sayeth...\\\"\"}]"]}]
              (format-rows spec rows))))))


Added refresh-session functions.

Added refresh-session functions.

--- src/shale/sessions.clj
+++ src/shale/sessions.clj
@@ -90,7 +90,24 @@
       (car/del sess-tags-key)))
   true)

+(defn refresh-session [session-id]
+   (with-car*
+     (car/watch session-set-key)
+     (let [sess-key (format session-key-template session-id)]
+       (car/watch sess-key)
+       (let [wd (resume-webdriver-from-id session-id)]
+         (try
+           (car/hset sess-key :current-url (current-url wd))
+           (catch WebDriverException e
+             (destroy-session session-id))))))
+   true)

+(defn refresh-sessions [session-ids]
+  (with-car*
+    (car/watch session-set-key)
+    (doseq [session-id (or session-ids (with-car* (car/smembers session-set-key)))]
+      (refresh-session session-id)))
+  true)

 (defn view-model [session-id]
   (let [[contents tags]


Fix authentication unit test

Fix authentication unit test

--- test/env_logger/authentication_test.clj
+++ test/env_logger/authentication_test.clj
@@ -114,7 +114,10 @@
     (let [resp (wa-prepare-register {:params {:username test-user}})
           body (parse-string (:body resp) true)]
       (is (= 200 (:status resp)))
-      (is (= "localhost" (get-in body [:rp :id])))
+      (if (:ci env)
+        ;; Use value from CircleCI machine when running in CircleCI
+        (is (= (:hostname env) (get-in body [:rp :id])))
+        (is (= "localhost" (get-in body [:rp :id]))))
       (is (= "dGVzdC11c2Vy" (get-in body [:user :id]))))))

 (deftest login-preparation


fix in server certificate resource identifier

--- src/terraboot/core.clj
+++ src/terraboot/core.clj
@@ -210,7 +210,7 @@

 (defn account-elb-listener[account-number]
   (fn [{:keys [port lb-port protocol lb-protocol cert-name]}]
-    (let [cert-id (str "arn:aws:iam:" account-number ":server-certificate/" cert-name)
+    (let [cert-id (str "arn:aws:iam::" account-number ":server-certificate/" cert-name)
           add-cert-if-present #(if cert-name (assoc % :ssl_certificate_id cert-id) %)]
       (add-cert-if-present {:instance_port port
                             :instance_protocol protocol


always include secure-uuid

always include secure-uuid

--- src/oc/storage/representations/entry.clj
+++ src/oc/storage/representations/entry.clj
@@ -83,9 +83,7 @@
 (defn- include-secure-uuid
   "Include secure UUID property for authors."
   [entry secure-uuid access-level]
-  (if (= access-level :author)
-    (assoc entry :secure-uuid secure-uuid)
-    entry))
+  (assoc entry :secure-uuid secure-uuid))

 (defn- include-interactions
   "Include interactions only if we have some."


Connect back to the URL we came from

Connect back to the URL we came from

--- src/tttclj/render.cljs
+++ src/tttclj/render.cljs
@@ -1,6 +1,7 @@
 (ns tttclj.render
   (:require [chord.client :refer [ws-ch]]
             [cljs.core.async :refer [chan <! >! put! close! timeout]]
+            [clojure.string :refer [replace-first]]
             [quiescent :as q :include-macros true]
             [quiescent.dom :as d])
   (:require-macros [cljs.core.async.macros :refer [go go-loop]]))
@@ -45,7 +46,10 @@
 (enable-console-print!)

 (go
-  (let [{:keys [ws-channel error]} (<! (ws-ch "ws://localhost:8080/ws"))
+  (let [url (-> (aget js/window "location" "href")
+                (replace-first #"http" "ws")
+                (replace-first #"index.html" "ws"))
+        {:keys [ws-channel error]} (<! (ws-ch url))
         container (.getElementById js/document "main")]
     (if error
       (prn "Couldn't open websocket connection:" error)


Finished some on parsing and scraping band members

--- src/metallumapi/scrape/bands.clj
+++ src/metallumapi/scrape/bands.clj
@@ -47,6 +47,11 @@
 (defn band-content []
   (html/select (fetch-url *band-url*) *band-content*))

+(defn band-bio []
+  (let [bio (html/select (fetch-url *band-bio-url*)
+                              *bio*)]
+    bio))
+
 (defn band-stats [content]
   (let [stats (reduce-kv (fn [m k v]
                            (assoc m (pretty-key k) v))
@@ -87,7 +92,32 @@
      :demos (fn [] (disco "demos"))
      :misc (fn [] (disco "misc"))}))

-(defn band-bio []
-  (let [bio (html/select (fetch-url *band-bio-url*)
-                              *bio*)]
-    bio))
+(defn band-members [content]
+  (letfn [(lineup [l]
+            (let [cnt (first (html/select content
+                                          [(keyword (str "div#band_tab_members_" l))
+                                           :table.lineupTable]))]
+              (map (fn [mem band]
+                     (let [[name instruments] (html/select mem [:td])
+                           bands (remove #{", ex-"}
+                                        (-> band (html/select [:td])
+                                            first :content rest))]
+                       {:member (let [mem-info (first (html/select name [:a]))]
+                                  {:name (-> mem-info :content first)
+                                   :link (-> mem-info :attrs :href)})
+                        :instruments (-> instruments
+                                         :content first
+                                         strip-whitespace)
+                        :bands (map (fn [row]
+                                      (if (:attrs row)
+                                        {:name (-> row :content first)
+                                         :link (-> row :attrs :href)}
+                                        {:name (-> row strip-whitespace
+                                                   (str/replace-first #"[,]ex-" ""))}))
+                                    bands)}))
+                   (html/select cnt [:tr.lineupRow])
+                   (html/select cnt [:tr.lineupBandsRow]))))]
+    {:complete (fn [] (lineup "complete"))
+     :current (fn [] (lineup "current"))
+     :past (fn [] (lineup "past"))
+     :live (fn [] (lineup "live"))}))


fix bad url for og:image tags

fix bad url for og:image tags

--- src/norman_sicily_static/web.clj
+++ src/norman_sicily_static/web.clj
@@ -66,8 +66,8 @@
        [:meta {:property "og:type" :content "website"}]
        [:meta {:property "og:url" :content web-url}]
        [:meta {:property "og:description" :content site-description}]
-       [:meta {:property "og:image" :content "/images/favicon-196.png"}]
-       [:meta {:property "og:image:url" :content "/images/favicon-196.png"}]
+       [:meta {:property "og:image" :content (str web-url "images/favicon-196.png")}]
+       [:meta {:property "og:image:url" :content (str web-url "images/favicon-196.png")}]
        [:meta {:property "og:image:type" :content "image/png"}]
        [:meta {:property "og:image:width" :content "196"}]
        [:meta {:property "og:image:height" :content "196"}]


Schmuck am Nachthemd

Schmuck am Nachthemd

--- src/euler/helper.clj
+++ src/euler/helper.clj
@@ -4,7 +4,8 @@
 (def & "function composition" comp)
 (def p "partial application" partial)

-;; factorisation
+;; == factorisation ===========================================================
+
 (def factor?
   "**factor? :: dividend:Int, divisor:Int -> Bool**:
   Predicate that tests whether the divisor evenly divides the dividend."
@@ -54,6 +55,9 @@
   "**triangle :: [Int]** Lazy seq of all triangle numbers. A triangle number is
   generated by adding the natural numbers up to n."
   (lazy-cat [1] (map + triangles (iterate inc 2))))
+
+
+;; == Fibonacci Sequence ======================================================

 (def fibs
   "**fibs :: [Int]**


Refactor plotting

Refactor plotting

Under some circumstances, character paths could intersect in a way
that wasn't necessary, and was only due to the plotting algorithm.
To fix this, I refactored the arc-radius algorithm to calculate
the appropriate value with respect to a character's entire layer,
rather than just its node.

--- src/fatlip/plot.cljs
+++ src/fatlip/plot.cljs
@@ -419,17 +419,26 @@
   (let [class-graphs (FlatGraph->ClassGraphs flat-graph)
         narrowest (apply min-key #(width % node-sep char-sep) class-graphs)
         narrow-min-y (min-y narrowest node-sep char-sep)
-        narrow-max-y (max-y narrowest node-sep char-sep)]
-    (->> class-graphs
-         (map #(let [delta (if (:aligned-down (meta %))
-                             (- narrow-max-y (max-y % node-sep char-sep))
-                             (- narrow-min-y (min-y % node-sep char-sep)))]
-                 (ys % node-sep char-sep delta)))
-         (apply merge-with #(if (vector? %1) (conj %1 %2) [%1 %2]))
-         (map (fn [[node ys]]
-                (let [sort-ys (sort ys)]
-                  [node (/ (+ (nth sort-ys 1) (nth sort-ys 2)) 2)])))
-         (into {}))))
+        narrow-max-y (max-y narrowest node-sep char-sep)
+        y-map (->> class-graphs
+                   (map #(let [delta (if (:aligned-down (meta %))
+                                       (- narrow-max-y (max-y % node-sep
+                                                              char-sep))
+                                       (- narrow-min-y (min-y % node-sep
+                                                              char-sep)))]
+                           (ys % node-sep char-sep delta)))
+                   (apply merge-with #(if (vector? %1) (conj %1 %2) [%1 %2]))
+                   (map (fn [[node ys]]
+                          (let [sort-ys (sort ys)]
+                            [node (/ (+ (nth sort-ys 1) (nth sort-ys 2)) 2)])))
+                   (into {}))]
+    (map (fn [node]
+           (let [top-y (get y-map node)
+                 bot-y (+ top-y
+                            (* char-sep
+                               (dec (:weight node))))]
+             [node [top-y bot-y]]))
+         (nodes flat-graph))))

 (defn arc-distance
@@ -545,124 +554,93 @@
     (+ arcs-x-dist tangent-x-dist)))

-(defn arc-center-up
-  "Given node info map (must have :node-y) and a min-arc-radius, returns the
-  center for the upward arcs on that node"
-  [{:keys [node-y]} min-arc-radius]
-  {:pre [(vector? node-y) (number? min-arc-radius)]}
-  (- (node-y 0) min-arc-radius))
-
-
-(defn arc-center-down
-  "Given node info map (must have :node-y) and a min-arc-radius, returns the
-  center for the downward arcs on that node"
-  [{:keys [node-y]} min-arc-radius]
-  {:pre [(vector? node-y) (number? min-arc-radius)]}
-  (+ (node-y 1) min-arc-radius))
-
-
-(defn arc-radius-up
+(defn arc-radius
   "Given node info map (must have :order) a min-arc-radius and the number of
   pixels characters should be separated by, and returns the radius of the arc
   for that node for that character"
   [{:keys [order]} min-arc-radius char-sep]
   {:pre [(integer? order) (every? number? [min-arc-radius char-sep])]}
-  (+ min-arc-radius
-     (* order char-sep)))
-
-
-(defn arc-radius-down
-  "Given node info map (must have :order and :node, which in turn must
-  have :weight) a min-arc-radius and the number of pixels characters should be
-  separated by, and returns the radius of the arc for that node for that
-  character"
-  [{:keys [order] {weight :weight} :node} min-arc-radius char-sep]
-  {:pre [(every? integer? [order weight])
-         (every? number? [min-arc-radius char-sep])]}
-  (+ min-arc-radius
-     (* (- (dec weight) order)
-        char-sep)))
+  (+ min-arc-radius (* order char-sep)))

 (defn arc-y-info
   "Returns the y values of the arc centers, as well as the radii for each arc
-  for a pair of character nodes on adjacent layers"
+  for a character segment with endpoints on adjacent layers"
   [src dest dir min-arc-radius char-sep]
   {:pre [(contains? #{:up :down} dir)]}
-  (if (= dir :up)
-    {:src-arc-y (arc-center-up src min-arc-radius)
-     :src-arc-radius (arc-radius-up src min-arc-radius char-sep)
-     :dest-arc-y (arc-center-down dest min-arc-radius)
-     :dest-arc-radius (arc-radius-down dest min-arc-radius char-sep)}
-    {:src-arc-y (arc-center-down src min-arc-radius)
-     :src-arc-radius (arc-radius-down src min-arc-radius char-sep)
-     :dest-arc-y (arc-center-up dest min-arc-radius)
-     :dest-arc-radius (arc-radius-up dest min-arc-radius char-sep)}))
+  (let [src-arc-r (arc-radius src min-arc-radius char-sep)
+        dest-arc-r (arc-radius dest min-arc-radius char-sep)
+        [src-op dest-op] ({:up [- +] :down [+ -]} dir)]
+    {:src-arc-radius src-arc-r
+     :dest-arc-radius dest-arc-r
+     :src-arc-y (src-op (:y src) src-arc-r)
+     :dest-arc-y (dest-op (:y dest) dest-arc-r)}))

 (defn add-y-info
-  "Adds :arc-y and :arc-radius information to character path pairs, plus
+  "Adds :arc-y and :arc-radius information to character segments, plus
   :total-arc-radius, for convenience"
-  [pair-maps min-arc-radius char-sep]
-  (map (fn [{:keys [dir], [src dest] :pair, :as info}]
+  [char-segs min-arc-radius char-sep]
+  (map (fn [{:keys [dir src dest], :as seg}]
          (if (= dir :level)
-           info
+           seg
            (let [{:keys [src-arc-y dest-arc-y
                          src-arc-radius dest-arc-radius]}
                  (arc-y-info src dest dir min-arc-radius char-sep)]
-             (-> info
+             (-> seg
                  (assoc :total-arc-radius (+ src-arc-radius dest-arc-radius))
-                 (assoc-in [:pair 0 :arc-y] src-arc-y)
-                 (assoc-in [:pair 0 :arc-radius] src-arc-radius)
-                 (assoc-in [:pair 1 :arc-y] dest-arc-y)
-                 (assoc-in [:pair 1 :arc-radius] dest-arc-radius)))))
-       pair-maps))
+                 (assoc-in [:src :arc-y] src-arc-y)
+                 (assoc-in [:src :arc-radius] src-arc-radius)
+                 (assoc-in [:dest :arc-y] dest-arc-y)
+                 (assoc-in [:dest :arc-radius] dest-arc-radius)))))
+       char-segs))

 (defn add-x-info
-  "Adds :xs to character path pairs, and if the pairs are not :level, also
-  adds :arc-x for each pair"
-  [pair-maps layer-xs]
-  (map (fn [{:keys [dir], [src dest] :pair, :as info}]
+  "Adds :xs to character segments, and if the segment is not :level, also
+  adds :arc-x for each segment"
+  [char-segs layer-xs]
+  (map (fn [{:keys [dir src dest], :as seg}]
          (let [src-xs (-> src :node :layer-id layer-xs)
                dest-xs (-> dest :node :layer-id layer-xs)
-               info' (-> info
-                         (assoc-in [:pair 0 :xs] src-xs)
-                         (assoc-in [:pair 1 :xs] dest-xs))]
+               seg' (-> seg
+                        (assoc-in [:src :xs] src-xs)
+                        (assoc-in [:dest :xs] dest-xs))]
            (if (= dir :level)
-             info'
-             (-> info'
-                 (assoc-in [:pair 0 :arc-x] (src-xs 1))
-                 (assoc-in [:pair 1 :arc-x] (dest-xs 0))))))
-       pair-maps))
+             seg'
+             (-> seg'
+                 (assoc-in [:src :arc-x] (src-xs 1))
+                 (assoc-in [:dest :arc-x] (dest-xs 0))))))
+       char-segs))

 (defn pair-up
   "Given a list of character positions, pairs each with the one following for a
   representation of transistions between layers. Also adds information about
-  the direction this transition goes."
+  the direction this segment goes."
   [infos]
   (->> (map vector infos (drop 1 infos))
-       (reduce (fn [pairs [src dest]]
+       (reduce (fn [segments [src dest]]
                  (let [src-y (:y src)
                        dest-y (:y dest)]
-                   (conj pairs
+                   (conj segments
                          {:dir (if (= src-y dest-y)
                                  :level
                                  (if (> src-y dest-y)
                                    :up
                                    :down))
-                          :pair [src dest]})))
+                          :src src
+                          :dest dest
+                          :character (:character src)})))
                [])))

 (defn relative-layer-xs
   "Generates a map of layers to the pixel distance to the preceding layer"
   [path-info layers max-slope layer-sep]
-  (->> (map second path-info)
+  (->> (vals path-info)
        (mapcat #(remove (fn [{:keys [dir]}] (= dir :level)) %))
-       (reduce (fn [min-seps {:keys [dir total-arc-radius],
-                              [src dest] :pair}]
+       (reduce (fn [min-seps {:keys [dir total-arc-radius src dest]}]
                  (let [layer (get layers (-> dest
                                              :node
                                              :layer-id))
@@ -694,13 +672,12 @@

 (defn arcs-and-tangent
-  "Given a pair of character positions that are not :level, generates plotting
-  information for the arcs and the line tangent to them required to draw the
-  transition"
+  "Given a segment that is not :level, generates plotting information for the
+  arcs and the line tangent to them required to draw the transition"
   [{:keys [dir total-arc-radius],
-    [{src-x :arc-x, src-y :arc-y, src-radius :arc-radius}
-     {dest-x :arc-x, dest-y :arc-y, dest-radius :arc-radius
-      dest-path-y :y}] :pair}]
+    {src-x :arc-x, src-y :arc-y, src-radius :arc-radius} :src
+    {dest-x :arc-x, dest-y :arc-y, dest-radius :arc-radius
+     dest-path-y :y} :dest}]
   {:pre [(every? number? [total-arc-radius src-x src-y src-radius
                           dest-x dest-y dest-radius])
          (contains? #{:up :down} dir)]}
@@ -793,7 +770,7 @@

 (defn char-plots
   "Generates coordinates a single character's path"
-  [plots {:keys [dir pair], [src dest] :pair, :as pair-map}]
+  [plots {:keys [dir src dest], :as segment}]
   ;; TODO checking empty? on every step seems silly; once we have
   ;; multipart paths, potentially with mid-path M's, we should just
   ;; use (move-to src) as the seed value in the reduce
@@ -805,7 +782,7 @@
     (match [last-type dir]
            [:h :level] (extend-h plots' dest-end-x)
            [_ :level] (conj plots' (h-to dest-end-x))
-           :else (plot-duration (into plots' (arcs-and-tangent pair-map))
+           :else (plot-duration (into plots' (arcs-and-tangent segment))
                                 dest-start-x dest-end-x))))

@@ -815,47 +792,104 @@
   [paths-y layers max-slope layer-sep]
   (let [layer-xs (absolute-layer-xs paths-y layers max-slope layer-sep)]
     (->> paths-y
-         (map (fn [[character pair-maps]]
-                [character (add-x-info pair-maps layer-xs)]))
-         (map (fn [[character pair-maps]]
+         (map (fn [[character segments]]
+                [character (add-x-info segments layer-xs)]))
+         (map (fn [[character segments]]
                 {:character character
-                 :plots (reduce char-plots [] pair-maps)})))))
-
-
-(defn pathify
-  "Given node-level y information, generate paths with character-level y info
-  for each character"
-  [node-ys nodes characters min-arc-radius char-sep]
-  (->> nodes
-       (mapcat (fn [node]
-                 (map-indexed (fn [i c]
-                                {:node node
-                                 :character c
-                                 :order i})
-                              (get characters node))))
-       (map (fn [info]
-              (let [node (:node info)
-                    node-top-y (get node-ys node)]
-                (assoc info
-                       :node-y [node-top-y
-                                (+ node-top-y
-                                   (* char-sep
-                                      (dec (:weight node))))]
-                       :y (+ node-top-y (* (:order info)
-                                           char-sep))))))
+                 :plots (reduce char-plots [] segments)})))))
+
+
+(defn character-ys
+  "Given node-level ys, generate y info for each character"
+  [node-ys characters char-sep]
+  (mapcat (fn [[node [top-y _ :as node-y]]]
+            (map-indexed (fn [i c]
+                           {:node node
+                            :character c
+                            :node-y node-y
+                            :y (+ top-y (* i char-sep))})
+                         (get characters node)))
+          node-ys))
+
+
+(defn character-segments
+  [char-ys]
+  (->> char-ys
        (group-by :character)
-       (map (fn [[character infos]]
-              [character (pair-up infos)]))
-       (map (fn [[character pair-maps]]
-              [character (add-y-info pair-maps min-arc-radius
-                                     char-sep)]))))
+       vals
+       (mapcat pair-up)))
+
+
+(defn get-segments-by-layer-character
+  [char-segs layers]
+  (let [layer-map (group-by #(-> % :dest :node :layer-id) char-segs)]
+    (->> (drop 1 layers)
+         (map (fn [layer]
+                (get layer-map (:id layer))))
+         (map (fn [seg-layer]
+                (into {} (map (fn [seg]
+                                [(:character seg) seg])
+                              seg-layer)))))))
+
+
+(defn get-character-layer-pairs
+  [layers characters]
+  (let [char-layers (map (fn [layer]
+                           (map (fn [item]
+                                  (if (instance? Node item)
+                                    (get characters item)
+                                    (get characters (first (:endpoints item)))))
+                                (:items layer)))
+                         layers)]
+    (map vector char-layers (drop 1 char-layers))))
+
+
+(defn order-groups
+  [groups order-attr char-segs]
+  (first
+   (reduce (fn [[segs order] group]
+             [(first (reduce (fn [[p i] char]
+                              [(assoc-in p [char order-attr :order] (+ order i))
+                               (inc i)])
+                            [segs 0]
+                            group))
+              (+ order (dec (count group)))])
+           [char-segs 0]
+           groups)))

 (defn plot
   "Generates coordinates for all paths in a FlatGraph"
   [flat-graph max-slope min-arc-radius layer-sep node-sep char-sep]
-  (let [{:keys [layers characters]} flat-graph]
-    (-> flat-graph
-        (plot-ys node-sep char-sep)
-        (pathify (nodes flat-graph) characters min-arc-radius char-sep)
-        (plot-xs layers max-slope layer-sep))))
+  (let [{:keys [layers characters]} flat-graph
+        character-layer-pairs (get-character-layer-pairs layers characters)
+        char-segs (-> flat-graph
+                      (plot-ys node-sep char-sep)
+                      (character-ys characters char-sep)
+                      character-segments)
+        segs-by-layer-character (get-segments-by-layer-character char-segs layers)
+        segs-by-char (->> (map (fn [layer-pair char-segs]
+                                 (let [char-dir #(:dir (get char-segs %))
+                                       [src-dirs dest-dirs] (map (fn [layer]
+                                                                   (->> layer
+                                                                        (mapcat (fn [node]
+                                                                                (partition-by char-dir node)))
+                                                                        (group-by #(char-dir (first %)))))
+                                                                 layer-pair)]
+                                   (->> char-segs
+                                        (order-groups (:up src-dirs) :src)
+                                        (order-groups (reverse (map reverse (:down src-dirs))) :src)
+                                        (order-groups (reverse (map reverse (:up dest-dirs))) :dest)
+                                        (order-groups (:down dest-dirs) :dest))))
+                               character-layer-pairs
+                               segs-by-layer-character)
+                          (reduce (fn [by-char layer-map]
+                                    (reduce (fn [bc [char seg]]
+                                              (update-in bc [char] (fnil conj []) seg))
+                                            by-char
+                                            layer-map))
+                                  {}))]
+    (plot-xs (map (fn [[character segs]]
+                    [character (add-y-info segs min-arc-radius char-sep)])
+                  segs-by-char)
+             layers max-slope layer-sep)))


Add `paginate` tests

Add `paginate` tests

--- test/io/perun_test.clj
+++ test/io/perun_test.clj
@@ -181,6 +181,11 @@
   (let [{:keys [entry entries]} data]
     (str "
collection " (count entries) "
")))

+(defn render-paginate
+  [data]
+  (let [{:keys [entry entries]} data]
+    (str "
paginate " (count entries) "
")))
+
 (deftesttask default-tests []
   (comp (add-txt-file :path "2017-01-01-test.md" :content (nth input-strings 0))
         (boot/with-pre-wrap fileset
@@ -275,6 +280,11 @@
         (testing "collection"
           (content-check :path "public/index.html"
                          :content "collection 7"))
+
+        (p/paginate :renderer 'io.perun-test/render-paginate)
+        (testing "paginate"
+          (content-check :path "public/page-1.html"
+                         :content "paginate 7"))

         (p/render :renderer 'io.perun-test/render)

@@ -452,6 +462,23 @@
           (value-check :path "bar/its-a-collection.html"
                        :value-fn #(meta= %1 %2 :collected "uh huh")))

+        (p/paginate :renderer 'io.perun-test/render-paginate
+                    :out-dir "baz"
+                    :prefix "decomplect-"
+                    :page-size 2
+                    :filterer :assorting
+                    :extensions [".htm"]
+                    :sortby :prder
+                    :comparator #(compare %1 %2)
+                    :meta {:paginated "mmhmm"})
+        (testing "paginate"
+          (content-check :path "baz/decomplect-1.html"
+                         :content "paginate 2")
+          (content-check :path "baz/decomplect-2.html"
+                         :content "paginate 2")
+          (content-check :path "baz/decomplect-3.html"
+                         :content "paginate 1"))
+
         (p/render :renderer 'io.perun-test/render
                   :filterer :markdown-set
                   :extensions [".htm"]


Because handled things don't cross versions

--- src/grimoire/api.clj
+++ src/grimoire/api.clj
@@ -255,7 +255,8 @@
   Fails if a nested Failure is encountered."

   [config thing]
-  {:pre [(t/versioned? thing)]}
+  {:pre [(t/versioned? thing)
+         (not (:handle thing))]}
   (let [thing    (t/ensure-thing thing)
         currentv (t/thing->version thing)               ; version handle
         current  (-> currentv :name util/normalize-version)


Add a warning about possible future work

--- src/grimoire/api.clj
+++ src/grimoire/api.clj
@@ -84,11 +84,15 @@
   {:arglists '[[config thing]]}
   dispatch)

+;; FIXME: Examples on Namespaces? Artifacts?
 (defmulti read-examples
   "Succeeds with a result Seq[Tuple[version, example-text]] for all examples on
   prior or equal versions of the given thing sorted in decending version
   order. Will Fail if the given Def does not exist, or if a nested Failure is
-  encountered."
+  encountered.
+
+  Note that future versions of this API may extend examples to Namespaces and
+  Artifacts."

   {:arglists '[[config def-thing]]}
   dispatch)