Cosmetic fixes on cats.core ns docstrings.

--- src/cljx/cats/core.cljx
+++ src/cljx/cats/core.cljx
@@ -85,7 +85,7 @@

   This is multiarity function that with arity pure/1
   it uses the dynamic scope to resolve the current
-  context. With pure/2, you can force a specific context
+  context. With `pure/2`, you can force a specific context
   value."
   ([v] (pure (get-current-context) v))
   ([ctx v] (p/pure ctx v)))
@@ -186,21 +186,20 @@
   Let see one example for understand how it works, this is
   a code using bind for compose few number of operations:

-
-    (bind (just 1)
-          (fn [a]
-            (bind (just (inc a))
-                  (fn [b]
-                    (return (* b 2))))))
-    ;=> #<Just [4]>
+      (bind (just 1)
+            (fn [a]
+              (bind (just (inc a))
+                    (fn [b]
+                      (return (* b 2))))))
+      ;=> #<Just [4]>

   Now see how this code can be more clear if you
   are using mlet macro for do it:

-    (mlet [a (just 1)
-           b (just (inc a))]
-      (return (* b 2)))
-    ;=> #<Just [4]>
+      (mlet [a (just 1)
+             b (just (inc a))]
+        (return (* b 2)))
+      ;=> #<Just [4]>
   "
   [bindings & body]
   (when-not (and (vector? bindings)
@@ -240,19 +239,19 @@
   same as mlet but specifying the monadic context.
   So, instead of writing:

-    (with-monad (maybe-transformer vector-monad)
-      (mlet [a [(just 1) (just 2)]
-             b [(just (inc a))]]
-        (return (* b 2))))
-    ;=> [#<Just [4]> #<Just [6]>]
+      (with-monad (maybe-transformer vector-monad)
+        (mlet [a [(just 1) (just 2)]
+               b [(just (inc a))]]
+          (return (* b 2))))
+      ;=> [#<Just [4]> #<Just [6]>]

   You can just write:

-    (mlet-with (maybe-transformer vector-monad)
-      [a [(just 1) (just 2)]
-       b [(just (inc a))]]
-      (return (* b 2)))
-    ;=> [#<Just [4]> #<Just [6]>]
+      (mlet-with (maybe-transformer vector-monad)
+        [a [(just 1) (just 2)]
+         b [(just (inc a))]]
+        (return (* b 2)))
+      ;=> [#<Just [4]> #<Just [6]>]
   "
   [monad bindings & body]
   `(with-monad ~monad
@@ -263,19 +262,19 @@
   "Lifts a function with the given fixed number of arguments to a
   monadic context.

-    (require '[cats.monad.maybe :as maybe])
-    (require '[cats.core :as m])
-
-    (def monad+ (m/lift-m 2 +))
-
-    (monad+ (maybe/just 1) (maybe/just 2))
-    ;=> <Just [3]>
-
-    (monad+ (maybe/just 1) (maybe/nothing))
-    ;=> <Nothing>
-
-    (monad+ [0 2 4] [1 2])
-    ;=> [1 2 3 4 5 6]
+      (require '[cats.monad.maybe :as maybe])
+      (require '[cats.core :as m])
+
+      (def monad+ (m/lift-m 2 +))
+
+      (monad+ (maybe/just 1) (maybe/just 2))
+      ;=> <Just [3]>
+
+      (monad+ (maybe/just 1) (maybe/nothing))
+      ;=> <Nothing>
+
+      (monad+ [0 2 4] [1 2])
+      ;=> [1 2 3 4 5 6]
   "
   [n f]
   (let [val-syms (repeatedly n gensym)
@@ -293,14 +292,14 @@
   "Given a non-empty collection of monadic values, collect
   their values in a vector returned in the monadic context.

-    (require '[cats.monad.maybe :as maybe])
-    (require '[cats.core :as m])
-
-    (m/sequence [(maybe/just 2) (maybe/just 3)])
-    ;=> <Just [[2, 3]]>
-
-    (m/sequence [(maybe/nothing) (maybe/just 3)])
-    ;=> <Nothing>
+      (require '[cats.monad.maybe :as maybe])
+      (require '[cats.core :as m])
+
+      (m/sequence [(maybe/just 2) (maybe/just 3)])
+      ;=> <Just [[2, 3]]>
+
+      (m/sequence [(maybe/nothing) (maybe/just 3)])
+      ;=> <Nothing>
   "
   [mvs]
   {:pre [(not-empty mvs)]}
@@ -318,37 +317,37 @@
    monadic context, map it into the given collection
    calling sequence on the results.

-     (require '[cats.monad.maybe :as maybe])
-     (require '[cats.core :as m])
-
-     (m/mapseq maybe/just [2 3])
-     ;=> <Just [[2 3]]>
-
-     (m/mapseq (fn [v]
+       (require '[cats.monad.maybe :as maybe])
+       (require '[cats.core :as m])
+
+       (m/mapseq maybe/just [2 3])
+       ;=> <Just [[2 3]]>
+
+       (m/mapseq (fn [v]
+                    (if (odd? v)
+                      (maybe/just v)
+                      (maybe/nothing)))
+                   [1 2])
+       ;=> <Nothing>
+  "
+  [mf coll]
+  (sequence (map mf coll)))
+
+(defn forseq
+  "Same as mapseq but with the arguments in reverse order.
+
+      (require '[cats.monad.maybe :as maybe])
+      (require '[cats.core :as m])
+
+      (m/forseq [2 3] maybe/just)
+      ;=> <Just [[2 3]]>
+
+      (m/forseq [1 2]
+                (fn [v]
                   (if (odd? v)
                     (maybe/just v)
-                    (maybe/nothing)))
-                 [1 2])
-     ;=> <Nothing>
-  "
-  [mf coll]
-  (sequence (map mf coll)))
-
-(defn forseq
-  "Same as mapseq but with the arguments in reverse order.
-
-    (require '[cats.monad.maybe :as maybe])
-    (require '[cats.core :as m])
-
-    (m/forseq [2 3] maybe/just)
-    ;=> <Just [[2 3]]>
-
-    (m/forseq [1 2]
-              (fn [v]
-                (if (odd? v)
-                  (maybe/just v)
-                  (maybe/nothing))))
-    ;=> <Nothing>
+                    (maybe/nothing))))
+      ;=> <Nothing>
   "
   [vs mf]
   (mapseq mf vs))
@@ -359,14 +358,14 @@

   Otherwise, returns the instance unchanged.

-    (require '[cats.monad.moaybe :as maybe])
-    (require '[cats.core :as m])
-
-    (m/filter (partial < 2) (maybe/just 3))
-    ;=> <Just [3]>
-
-    (m/filter (partial < 4) (maybe/just 3))
-    ;=> <Nothing>
+      (require '[cats.monad.moaybe :as maybe])
+      (require '[cats.core :as m])
+
+      (m/filter (partial < 2) (maybe/just 3))
+      ;=> <Just [3]>
+
+      (m/filter (partial < 4) (maybe/just 3))
+      ;=> <Nothing>
   "
   [p mv]
   (with-monad (get-current-context mv)


[WM] Quiet test output

[WM] Quiet test output

We don't need to see DEBUG logs for all the generative tests.

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/democracyworks/partner-works.git/'


Update sablono

Update sablono

https://github.com/r0man/sablono/pull/118

--- project.clj
+++ project.clj
@@ -1,4 +1,4 @@
-(defproject rum "0.8.2"
+(defproject rum "0.8.3-SNAPSHOT"
   :description  "ClojureScript wrapper for React"
   :license      { :name "Eclipse"
                   :url  "http://www.eclipse.org/legal/epl-v10.html" }
@@ -9,7 +9,7 @@
    [org.clojure/clojurescript  "1.7.228" :scope "provided"]
    [cljsjs/react               "15.0.1-1"]
    [cljsjs/react-dom           "15.0.1-1"]
-   [sablono                    "0.7.0"]]
+   [sablono                    "0.7.1"]]

   :global-vars
   { *warn-on-reflection* true }


Releasing version 0.9.4

Releasing version 0.9.4

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/hudren/ebook-novel.git/'


Update version to 2.0.0

Update version to 2.0.0

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/Yleisradio/rabid.git/'


rollback project.clj

rollback project.clj

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/runoshun/syncat.git/'


Upgrade ragtime to 0.5.2

Upgrade ragtime to 0.5.2

The previous version had a bug where migration files were not being
loaded in the correct order.

--- project.clj
+++ project.clj
@@ -12,7 +12,7 @@
                  [hikari-cp "1.2.4"]
                  [clj-time "0.11.0"]
                  [com.andrewmcveigh/cljs-time "0.3.13"]
-                 [ragtime "0.5.0"]
+                 [ragtime "0.5.2"]
                  [org.postgresql/postgresql "9.4-1201-jdbc41"]
                  [compojure "1.4.0"]
                  [ring "1.4.0"]


bump korma to 0.4.2 and cider-nrepl to 0.9.0

--- project.clj
+++ project.clj
@@ -33,7 +33,7 @@
                  [compojure "1.3.4"]                                  ; HTTP Routing library built on Ring
                  [environ "1.0.0"]                                    ; easy environment management
                  [hiccup "1.0.5"]                                     ; HTML templating
-                 [korma "0.4.1"]                                      ; SQL lib
+                 [korma "0.4.2"]                                      ; SQL lib
                  [log4j/log4j "1.2.17"
                   :exclusions [javax.mail/mail
                                javax.jms/jms
@@ -64,7 +64,7 @@
                                   [expectations "2.1.1"]              ; unit tests
                                   [marginalia "0.8.0"]                ; for documentation
                                   [ring/ring-mock "0.2.0"]]
-                   :plugins [[cider/cider-nrepl "0.9.0-SNAPSHOT"]     ; Interactive development w/ cider NREPL in Emacs
+                   :plugins [[cider/cider-nrepl "0.9.0"]              ; Interactive development w/ cider NREPL in Emacs
                              [jonase/eastwood "0.2.1"]                ; Linting
                              [lein-ancient "0.6.5"]                   ; Check project for outdated dependencies + plugins w/ 'lein ancient'
                              [lein-bikeshed "0.2.0"]                  ; Linting


Version 1.4.0

Version 1.4.0

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/starcity-properties/odin.git/'


Build java classfiles with debugging symbols, as suggested by the build configuration

--- project.clj
+++ project.clj
@@ -43,7 +43,7 @@
   :repositories {"sonatype"
                  "http://oss.sonatype.org/content/groups/public/"}

-  :javac-options {:debug true}
+  :javac-options ["-g"]
   :jvm-opts ["-Djava.library.path=/usr/local/lib:/opt/local/lib:/usr/lib"]

   :aot :all


bump to 0.1.11-SNAPSHOT

bump to 0.1.11-SNAPSHOT

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/michaelsbradleyjr/shen.clj.git/'


refactor services devcard so form works with new data structure


recording (but not using yet) reagent hack

error: pathspec 'src/cljs/relembra/reagent_hack.cljs' did not match any file(s) known to git

--- src/cljs/relembra/reagent_hack.cljs
+++ src/cljs/relembra/reagent_hack.cljs
@@ -0,0 +1,170 @@
+(ns relembra.reagent-hack
+  (:require
+   reagent.impl.template
+   reagent.impl.component
+   reagent.impl.batching
+   [reagent.interop :refer-macros [$ $!]]))
+
+;; A better but idiosyncratic way for reagent to locate the real
+;; input element of a component. It may be that the component's
+;; top-level (outer) element is an <input> already. Or it may be that
+;; the outer element is a wrapper, and the real <input> is somewhere
+;; within it (as is the case with Material TextFields).
+;; Somehow the `:input` property seems to be pre-populated (in version
+;; 0.6.0 of Reagent) with a reference to the real <input>, so we use
+;; that if available.
+;; At the time of writing, future versions of Reagent will likely
+;; change this behavior, and a totally different patch will be
+;; required for identifying the real <input> element.
+(defn get-input-node [this]
+  (let [outer-node ($ this :cljsInputElement)
+        inner-node (when (and outer-node (.hasOwnProperty outer-node "input"))
+                     ($ outer-node :input))]
+    (if (and inner-node
+             (= "INPUT" ($ inner-node :tagName)))
+      inner-node
+      outer-node)))
+
+;; This is the same as reagent.impl.template/input-set-value except
+;; that the `node` binding uses our `get-input-node` function. Even
+;; the original comments are reproduced below.
+(defn input-set-value
+  [this]
+  (when-some [node (get-input-node this)]
+    ($! this :cljsInputDirty false)
+    (let [rendered-value ($ this :cljsRenderedValue)
+          dom-value      ($ this :cljsDOMValue)]
+      (when (not= rendered-value dom-value)
+        (if-not (and (identical? node ($ js/document :activeElement))
+                  (reagent.impl.template/has-selection-api? ($ node :type))
+                  (string? rendered-value)
+                  (string? dom-value))
+          ;; just set the value, no need to worry about a cursor
+          (do
+            ($! this :cljsDOMValue rendered-value)
+            ($! node :value rendered-value))
+
+          ;; Setting "value" (below) moves the cursor position to the
+          ;; end which gives the user a jarring experience.
+          ;;
+          ;; But repositioning the cursor within the text, turns out to
+          ;; be quite a challenge because changes in the text can be
+          ;; triggered by various events like:
+          ;; - a validation function rejecting a user inputted char
+          ;; - the user enters a lower case char, but is transformed to
+          ;;   upper.
+          ;; - the user selects multiple chars and deletes text
+          ;; - the user pastes in multiple chars, and some of them are
+          ;;   rejected by a validator.
+          ;; - the user selects multiple chars and then types in a
+          ;;   single new char to repalce them all.
+          ;; Coming up with a sane cursor repositioning strategy hasn't
+          ;; been easy ALTHOUGH in the end, it kinda fell out nicely,
+          ;; and it appears to sanely handle all the cases we could
+          ;; think of.
+          ;; So this is just a warning. The code below is simple
+          ;; enough, but if you are tempted to change it, be aware of
+          ;; all the scenarios you have handle.
+          (let [node-value ($ node :value)]
+            (if (not= node-value dom-value)
+              ;; IE has not notified us of the change yet, so check again later
+              (reagent.impl.batching/do-after-render #(input-set-value this))
+              (let [existing-offset-from-end (- (count node-value)
+                                               ($ node :selectionStart))
+                    new-cursor-offset        (- (count rendered-value)
+                                               existing-offset-from-end)]
+                ($! this :cljsDOMValue rendered-value)
+                ($! node :value rendered-value)
+                ($! node :selectionStart new-cursor-offset)
+                ($! node :selectionEnd new-cursor-offset)))))))))
+
+
+;; This is the same as `reagent.impl.template/input-handle-change`
+;; except that the reference to `input-set-value` points to our fn.
+(defn input-handle-change
+  [this on-change e]
+  ($! this :cljsDOMValue (-> e .-target .-value))
+  ;; Make sure the input is re-rendered, in case on-change
+  ;; wants to keep the value unchanged
+  (when-not ($ this :cljsInputDirty)
+    ($! this :cljsInputDirty true)
+    (reagent.impl.batching/do-after-render #(input-set-value this)))
+  (on-change e))
+
+
+;; This is the same as `reagent.impl.template/input-render-setup`
+;; except that the reference to `input-handle-change` points to our fn.
+(defn input-render-setup
+  [this jsprops]
+  ;; Don't rely on React for updating "controlled inputs", since it
+  ;; doesn't play well with async rendering (misses keystrokes).
+  (when (and (some? jsprops)
+          (.hasOwnProperty jsprops "onChange")
+          (.hasOwnProperty jsprops "value"))
+    (let [v         ($ jsprops :value)
+          value     (if (nil? v) "" v)
+          on-change ($ jsprops :onChange)]
+      (when (nil? ($ this :cljsInputElement))
+        ;; set initial value
+        ($! this :cljsDOMValue value))
+      ($! this :cljsRenderedValue value)
+      (js-delete jsprops "value")
+      (doto jsprops
+        ($! :defaultValue value)
+        ($! :onChange #(input-handle-change this on-change %))
+        ($! :ref #($! this :cljsInputElement %1))))))
+
+
+;; This version of `reagent.impl.template/input-component?` is
+;; effectively the same as before except that it also detects Material's
+;; wrapped components as input components. It does this by looking for
+;; a property called "inputStyle" as an indicator. (Perhaps not a
+;; robust test...)
+;;
+;; By identifying input components more liberally, Material textfields
+;; are permitted into the code path that manages caret positioning
+;; and selection state awareness, in reaction to updates. This alone
+;; is necessary but insufficient.
+(defn input-component?
+  [x]
+  (or (= x "input")
+    (= x "textarea")
+    (when-let [prop-types ($ x :propTypes)]
+      ;; Material inputs all have "inputStyle" prop
+      (and (aget prop-types "inputStyle")
+        ;; But we only want text-fields, so let's exclude radio/check inputs
+        (not (aget prop-types "checked"))
+        ;; TODO: ... and other non-text-field inputs?
+        ))))
+
+
+;; This is the same as `reagent.impl.template/input-spec` except that
+;; the reference to `input-render-setup` points to our fn.
+(def input-spec
+  {:display-name "ReagentInput"
+   :component-did-update input-set-value
+   :reagent-render
+   (fn [argv comp jsprops first-child]
+     (let [this reagent.impl.component/*current-component*]
+       (input-render-setup this jsprops)
+       (reagent.impl.template/make-element argv comp jsprops first-child)))})
+
+
+;; This is the same as `reagent.impl.template/reagent-input` except
+;; that the reference to `input-spec` points to our definition.
+(defn reagent-input []
+  (when (nil? reagent.impl.template/reagent-input-class)
+    (set! reagent.impl.template/reagent-input-class (reagent.impl.component/create-class input-spec)))
+  reagent.impl.template/reagent-input-class)
+
+
+;; Now we override the existing functions in `reagent.impl.template`
+;; with our own definitions.
+(defn set-overrides!
+  []
+  (set! reagent.impl.template/input-component? input-component?)
+  (set! reagent.impl.template/input-handle-change input-handle-change)
+  (set! reagent.impl.template/input-set-value input-set-value)
+  (set! reagent.impl.template/input-render-setup input-render-setup)
+  (set! reagent.impl.template/input-spec input-spec)
+  (set! reagent.impl.template/reagent-input reagent-input))


main: simplify workflow

main: simplify workflow

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/pyr/bundes.git/'


Implement group membership adding.

Implement group membership adding.

--- src/clojars/web.clj
+++ src/clojars/web.clj
@@ -241,13 +241,14 @@
     [:h2 "Your groups"]
     (unordered-list (map group-link (find-groups account)))))

-(defn show-group [account group members]
+(defn show-group [account group members & errors]
   (html-doc account (str group " group")
     [:h1 (str group " group")]
     [:h2 "Jars"]
     (unordered-list (map jar-link (jars-by-group group)))
     [:h2 "Members"]
     (unordered-list (map user-link members))
+    (error-list errors)
     (when (some #{account} members)
       [:div {:class :add-member}
        (form-to [:post (str "/groups/" group)]
@@ -307,6 +308,22 @@
        (try-account
         (show-group account group members))
        :next)))
+  (POST #"/groups/([^/]+)"
+    (let [group ((:route-params request) 0)]
+     (if-let [members (with-db (group-members group))]
+       (try-account
+        (cond
+          (some #{(params :user)} members)
+          (show-group account group members "They're already a member!")
+          (and (some #{account} members)
+               (find-user (params :user)))
+          (do (add-member group (params :user))
+              (show-group account group
+                          (conj members (params :user))))
+          :else
+          (show-group account group members (str "No such user: "
+                                                 (h (params :user))))))
+       :next)))
   (GET "/users/:username"
     (if-let [user (find-user (param :username))]
       (try-account


make conn? work with any atom-like entity

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/piranha/datascript.git/'


Start adding abstract group types

Start adding abstract group types

error: pathspec 'src/main/clojure/lazytest/group.clj' did not match any file(s) known to git

--- src/main/clojure/lazytest/group.clj
+++ src/main/clojure/lazytest/group.clj
@@ -0,0 +1,41 @@
+(ns lazytest.group)
+
+(defn RunnableExample [fixtures f]
+  RunnableTest
+  (run-tests [this]
+	     (or (skip-or-pending this)
+		 (try-expectations this
+				   (apply f (map setup fixtures))
+				   (dorun (map teardown fixtures))))))
+
+(defrecord Example [locals fixtures expr]
+  Testable
+  (get-tests [this]
+	     (RunnableExample. fixtures (eval `(fn ~locals ~expr)))))
+
+(defrecord SimpleFixture [value]
+  Fixture
+  (setup [this] value)
+  (teardown [this] nil))
+
+(defrecord Group [children]
+  Testable
+  (get-tests [this] (list this))
+  RunnableTest
+  (run-tests [this] (result-group this (mapcat run-tests children))))
+
+(defrecord BindingFixtureGroup [locals fixtures children]
+  Testable
+  (get-tests [this]
+	     (mapcat (fn [child]
+		       (get-tests
+			(assoc child
+			  :locals (vec (concat (:locals this) (:locals child)))
+			  :fixtures (vec (concat (:locals this) (:locals child))))))
+		     children)))
+
+(defrecord MappingGroup [local sequence expr]
+  (get-tests [this]
+	     (map (fn [value] (Example. [local] [(SimpleFixture. x)] expr))
+		  sequence)))
+


The ultimate debug fn

The ultimate debug fn

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/shaunstanislaus/cljs2go.git/'


Allow PUT TrashedEntity

Allow PUT TrashedEntity

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/physion/ovation-webapi.git/'


Remove unused crapcode

Remove unused crapcode

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/kkroening/jackal.git/'


figured out XFNM nodes have the name of skeleton bones

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/aamedina/swg.git/'


defturtle on the web: ongoing

defturtle on the web: ongoing

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/tiagoantao/turtle.git/'


fix sel `:field` and `:fields` behavior with local bindings

--- src/metabase/db.clj
+++ src/metabase/db.clj
@@ -137,11 +137,13 @@
     `(first (sel :many ~@args (limit 1)))
     (let [[option [entity & forms]] (u/optional keyword? args)]
       (case option
-        :field  `(map ~(second entity)
-                      (sel :many ~entity ~@forms))
-        :id      `(sel :many :field [~entity :id] ~@forms)
-        :fields `(map #(select-keys % [~@(rest entity)])
-                      (sel :many ~entity ~@forms))
+        :field  `(let [[entity# field#] ~entity]
+                   (map field#
+                        (sel :many [entity# field#] ~@forms)))
+        :id     `(sel :many :field [~entity :id] ~@forms)
+        :fields `(let [[~'_ & fields# :as entity#] ~entity]
+                   (map #(select-keys % fields#)
+                        (sel :many entity# ~@forms)))
         nil     `(-sel-select ~entity ~@forms)))))

 (def ^:dynamic *entity-overrides*


add key props for fields and options in service entry


Adding Dan's neighbors namespace

Adding Dan's neighbors namespace

error: pathspec 'src/clj/forma/hadoop/jobs/neighbors.clj' did not match any file(s) known to git

--- src/clj/forma/hadoop/jobs/neighbors.clj
+++ src/clj/forma/hadoop/jobs/neighbors.clj
@@ -0,0 +1,129 @@
+(ns forma.hadoop.jobs.neighbors
+  (:use cascalog.api
+        forma.hoptree)
+  (:require [cascalog.ops :as c]
+            [forma.matrix.utils :as util]
+            [forma.matrix.walk :as walk]
+            [incanter.core :as i]))
+
+(defmapcatop neighbors
+  "Accepts a spatial resolution and a unique, global index for a
+  single pixel. Returns a sequence of indices of the 8 adjacent pixels
+  to the supplied pixel, as well as the own-pixel index."
+  [sres idx]
+  (neighbor-idx sres (GlobalIndex* idx)))
+
+(defn neighbor-src
+  "Accepts a source with the MODIS coordinates and group ID (e.g.,
+  GADM) of a selection of pixels.  Returns a tap with the unique,
+  global pixel IDs of all neighbors that are relevant for neighbor
+  analysis for a selection of pixels."
+  [sres select-src]
+  (<- [?neigh-id]
+      (select-src ?gadm ?h ?v ?s ?l)
+      (TileRowCol* ?h ?v ?s ?l :> ?tile-pixel)
+      (global-index sres ?tile-pixel :> ?idx)
+      (neighbors sres ?idx :> ?neigh-id)
+      (:distinct true)))
+
+(defn window-attribute-src
+  "Accepts two sources (1) coordinates and group ID of a selection of
+  pixels that are to be assigned neighbor values; (2) all pixels in
+  the region that contains the groups, so that all of the pixels
+  in (1) are represented.. Returns the selection of pixels and their
+  values that are relevant for neighbor processing by screening out
+  all unneccessary pixels."
+  [sres select-src full-src]
+  (let [n-src (neighbor-src sres select-src)]
+    (<- [?group ?idx ?val]
+        (n-src ?idx)
+        (full-src ?group ?h ?v ?s ?l ?val)
+        (TileRowCol* ?h ?v ?s ?l :> ?tile-pixel)
+        (global-index sres ?tile-pixel :> ?idx)
+        (:distinct true))))
+
+(defn window-map
+  "Accepts a spatial resolution (as a string) and a collection of
+  global, unique indices.  Returns a defining map of the rectangular
+  window that bounds all pixels in the collection.  The window is
+  fully identified by the topleft corner in the form of [row
+  column], along with the width and height in pixels of the
+  rectangular window."
+  [sres global-idx-coll]
+  (let [rowcol (fn [x] (global-rowcol sres (GlobalIndex* x)))
+        [min-r min-c] (rowcol (reduce min global-idx-coll))
+        [max-r max-c] (rowcol (reduce max global-idx-coll))]
+    {:topleft-rowcol [min-r min-c]
+     :height (inc (- max-r min-r))
+     :width  (inc (- max-c min-c))}))
+
+(defn global-coll->window-coll
+  "Accepts a spatial resolution, a map that identifies a MODIS window,
+  and a sequence of tuples of the form [idx val], where the index is
+  the unique global index.  Returns the same form where the index has
+  been transformed to the relative window index."
+  [sres wmap idx-val]
+  {:pre [(contains? wmap :topleft-rowcol)]}
+  (map (fn [[idx val]] [(window-idx sres wmap (GlobalIndex* idx)) val])
+       idx-val))
+
+(defn create-window
+  "Acceots a sequence of tuples of the form [idx val], where idx is
+  the unique identifier of the pixel within a designated window."
+  [window-coll & {:keys [nrows ncols] :or {nrows 0 ncols 0}}]
+  {:pre  [(> nrows 0) (> ncols 0)
+          (contains? (vec (map first window-coll)) 0)]}
+  (let [len (* nrows ncols)]
+    (partition ncols
+               (util/sparse-expander nil window-coll :length len))))
+
+(defn process-neighbors
+  "Accepts a spatial resolution, a map of window parameters, a
+  function to apply over a 9-pixel square of neighbors, and a
+  rectangular matrix of pixel-level values.  Returns a sequence of
+  tuples of the form [idx val] where the index is the global, unique
+  MODIS index and the value is the transformed values as a result of
+  spatial smoothing."
+  [sres wmap f window-mat]
+  (let [win-col (map-indexed vector
+                             (walk/windowed-function 1 f window-mat))]
+    (map (fn [[idx val]] [(global-index "500" (WindowIndex* idx) wmap) val])
+         win-col)))
+
+(defbufferop [assign-vals [sres]]
+  "Accepts a sequence of tuples within a `?group` field and returns a
+  sequence of tuples with fields for a global-index and
+  smoothed-value; in this case, the sum of all neighboring pixel
+  values."
+  [tuples]
+  (let [wmap (window-map sres (map first tuples))
+        window-coll (global-coll->window-coll sres wmap tuples)
+        window-mat (create-window
+                    (sort-by first window-coll)
+                    :nrows (wmap :height)
+                    :ncols (wmap :width))
+        my-sum (fn [& args] (i/sum args))]
+    (process-neighbors sres wmap my-sum window-mat)))
+
+(defn sample-query
+  "Accepts a spatial resolution; a selection of pixels for which
+  neighborhood attributes are required; and a full selection of
+  indices and values for the region that contains all the group-level
+  pixels.  Returns a tap with the transformed values assigned to the
+  full set of indices."
+  [sres select-src full-src]
+  (let [w-src (window-attribute-src sres select-src full-src)]
+    (<- [?group ?new-idx ?new-val]
+        (w-src ?group ?idx ?val)
+        (assign-vals [sres] ?idx ?val :> ?new-idx ?new-val))))
+
+(defn filtered-sample-query
+  "Filters the `sample-query` return values, so that only the indices
+  that are contained within the selected pixel source are returned."
+  [sres select-src full-src]
+  (let [src (sample-query sres select-src full-src)]
+    (<- [?group ?idx ?val]
+        (src ?group ?idx ?val)
+        (select-src ?group ?h ?v ?s ?l)
+        (TileRowCol* ?h ?v ?s ?l :> ?tile-pixel)
+        (global-index "500" ?tile-pixel :> ?idx))))


add TODO to event dao

add TODO to event dao

--- src/ruuvi_server/database/event_dao.clj
+++ src/ruuvi_server/database/event_dao.clj
@@ -157,6 +157,7 @@
    (let [event-time (or (to-sql-timestamp (:event_time data))
                         (current-sql-timestamp))
          tracker (get-tracker-by-code! (:tracker_code data))
+         ;; TODO trim session_code to length of db field
          session-code (or (:session_code data) "default")
          event-session (get-event-session! (:id tracker) session-code event-time)]


Simple reformat

Simple reformat


test clj

test clj

error: pathspec 'test.clj' did not match any file(s) known to git

--- test.clj
+++ test.clj
@@ -0,0 +1,12 @@
+#(+ %1 %2)
+
+{#js :shirt #{'y 8.7 1/3}}
+
+(def euhs%243!#$%&* true) ;heheh
+
+(defn ❤ [^clojure.core/string s #_ x]
+  (str \a '8 \&)
+    {::foobar\s
+     hard.core/clone!
+     #'user/foo}
+  (str s " is great!"))


cancel on ESC

cancel on ESC

--- labs/architecture-examples/om/src/todomvc/item.cljs
+++ labs/architecture-examples/om/src/todomvc/item.cljs
@@ -34,7 +34,9 @@
 (defn handle-key-down [e todo {:keys [owner] :as opts}]
   (let [kc (.-keyCode e)]
     (if (identical? kc ESCAPE_KEY)
-      (dom/set-state! owner [:edit-text] (:title todo))
+      (do
+        (dom/set-state! owner [:edit-text] (:title todo))
+        (put! (:comm opts) [:cancel todo]))
       (if (identical? kc ENTER_KEY)
         (handle-submit e todo opts)))))


chore(log): add more info to parser error

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/B2W-Digital/pdg-core.git/'


use 32-bit integer for exponent of CLJS bigdec, not any integer string

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/QuiltProject/sedan.git/'


Reduce unnecessary usage of core.async for sending

core.async is only needed when coordination or message passing across
threads is useful. A better fit for managing independent threads as we
do here is to just use the Java executor framework.

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/democracyworks/scheduled-message-works.git/'


Use ordinary pedestal interceptor instead of bifrost

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/democracyworks/turbovote-http-api.git/'


Add aeron heartbeat test

Add aeron heartbeat test

error: pathspec 'test/onyx/messaging/aeron_heartbeat.clj' did not match any file(s) known to git

--- test/onyx/messaging/aeron_heartbeat.clj
+++ test/onyx/messaging/aeron_heartbeat.clj
@@ -0,0 +1,106 @@
+(ns onyx.messaging.aeron-heartbeat
+  (:require [onyx.messaging.aeron.messenger :as am]
+            [onyx.messaging.aeron.embedded-media-driver :as em]
+            [onyx.messaging.protocols.messenger :as m]
+            [onyx.messaging.protocols.publisher :as pub]
+            [onyx.messaging.protocols.subscriber :as sub]
+            [onyx.messaging.common :as mc]
+            [com.stuartsierra.component :as component]
+            [taoensso.timbre :refer [fatal info debug] :as timbre]
+            [clojure.test :refer [deftest is testing]]))
+
+;; Setup an upstream task
+;; Setup two downstream peers on a dst-task-id with same task-id
+;; Publications will now need to know downstream peers as well as dst-task-id so they know what heartbeats to expect.
+;; Subscriptions will need to know upstream peer, but this is already known in src-peer-id
+
+;; Upstream task starts offering barriers.
+   ;; Iterate through all the publications
+        ;; Offer a barrier in each iteration to peers that haven't replied with a ready
+        ;; Send a heartbeat in each iteration to peers that haven't sent a heartbeat. This should include replica-version
+   ;; Poll heartbeat channel, if you receive a heartbeat, set the publication to ready. Upon receiving either a heartbeat or a ready [replica epoch], reset heartbeat count.
+   ;; For
+
+;; Extra peer group subscriber that can look at all the heartbeats and make an overall decision? Would also allow this to be exposed to a health endpoint more easily
+
+(deftest aa-test
+  (let [peer-config {:onyx.messaging.aeron/embedded-driver? true
+                     :onyx.messaging.aeron/embedded-media-driver-threading :shared
+                     :onyx.messaging/peer-port 42000
+                     :onyx.messaging/bind-addr "127.0.0.1"
+                     :onyx.messaging/impl :aeron}
+        media-driver (component/start (em/->EmbeddedMediaDriver peer-config))]
+    (try
+     (let [peer-group (component/start (m/build-messenger-group peer-config))]
+       (try
+        (let [upstream1 (component/start (m/build-messenger peer-config peer-group :p-upstream1))]
+          (try
+           (let [downstream1 (component/start (m/build-messenger peer-config peer-group :p-downstream1))
+                 site {:address (:onyx.messaging/bind-addr peer-config)
+                       :port (:onyx.messaging/peer-port peer-config)}]
+             (try
+              (-> upstream1
+                  (m/set-replica-version! 1)
+                  (m/update-publishers [{:src-peer-id :p-upstream1
+                                         :dst-task-id :downstream1
+                                         :site site
+                                         :dst-peer-ids #{:p-downstream1}
+                                         :slot-id -1}])
+                  (m/next-epoch!))
+              (-> downstream1
+                  (m/set-replica-version! 1)
+                  (m/update-subscribers [{:src-peer-id :p-upstream1
+                                          :dst-task-id :downstream1
+                                          :src-site site
+                                          :site site
+                                          :slot-id -1}]))
+              ;; This will send a ready message
+              ; (while (= -1 (m/offer-barrier upstream1 (first (m/publishers upstream1))
+              ;                               {:recover 33})))
+
+              ;; This will send a ready message
+              (loop []
+                (pub/offer-ready! (first (m/publishers upstream1)))
+                (sub/poll-replica! (first (m/subscribers downstream1)))
+                (pub/poll-heartbeats! (first (m/publishers upstream1)))
+                (when-not (pub/ready? (first (m/publishers upstream1)))
+                  (recur)))
+
+              (dotimes [i 50]
+                (sub/offer-heartbeat! (first (m/subscribers downstream1)))
+                (pub/poll-heartbeats! (first (m/publishers upstream1))))
+
+              (println "Pub and sub both ready")
+
+              ;; We should have sent a ready message now
+
+
+
+
+              ; (println "Pub reg"
+              ;          (.sessionId (:publication (first (m/publishers upstream1))))
+              ;          (mapv (fn [i] (.sessionId i)) (.images (:subscription (first (m/subscriptions downstream1))))))
+              ; (-> upstream1
+              ;     (m/remove-publication {:src-peer-id :p-upstream1
+              ;                            :dst-task-id :downstream1
+              ;                            :site site
+              ;                            :slot-id -1}))
+              ; (-> upstream1
+              ;     (m/add-publication {:src-peer-id :p-upstream1
+              ;                         :dst-task-id :downstream1
+              ;                         :site site
+              ;                         :slot-id -1}))
+
+              ;(while (= -1 (m/offer-barrier upstream1 (first (m/publishers upstream1)))))
+              ; (println "Pub reg"
+              ;          (.sessionId (:publication (first (m/publishers upstream1))))
+              ;          (mapv (fn [i] (.sessionId i)) (.images (:subscription (first (m/subscriptions downstream1))))))
+
+              (finally
+               (component/stop downstream1))))
+           (finally (component/stop upstream1))))
+        (finally
+         (component/stop peer-group))))
+     (finally
+      (component/stop media-driver)))))
+


Add functionality to create rdfs

Add functionality to create rdfs

which are apparently needed for archiving

error: pathspec 'src/mdr2/rdf.clj' did not match any file(s) known to git

--- src/mdr2/rdf.clj
+++ src/mdr2/rdf.clj
@@ -0,0 +1,73 @@
+(ns mdr2.rdf
+  (:require [clojure.data.xml :as xml]))
+
+(defn- depth [production] 0)
+
+(defn- files [production] 0)
+
+(defn- size [production] 0)
+
+(defn- page-front [production] 0)
+(defn- page-normal [production] 0)
+(defn- page-special [production] 0)
+
+(defn- rdf-sexp [production]
+  (let [{:keys [title creator subject description publisher date identifier source language rights
+                sourceDate sourceEdition sourcePublisher sourceRights sourceTitle
+                multimediaType multimediaContent narrator producedDate
+                revision revisionDate revisionDescription
+                totalTime audioFormat type
+                footnotes prodnotes multi-volume sidebars
+                tocItems]} production]
+    [:rdf:DRF {:xmlns:rdf "http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+               :xmlns:dc "http://purl.org/dc/elements/1.1/"
+               :xmlns:ncc "http://www.daisy.org/publications/specifications/"
+               :xmlns:sbs "http://www.sbszh.ch/sbs/namespace"}
+     ;; see also
+     ;; http://www.daisy.org/z3986/specifications/daisy_202.html?q=publications/specifications/daisy_202.html#ncc
+     [:rdf:Description
+      [:dc:creator creator]
+      [:dc:date date]
+      [:dc:format "Daisy 2.02"] ;; this is only for DAISY 2.02
+      [:dc:identifier identifier]
+      [:dc:language language]
+      [:dc:publisher publisher]
+      [:dc:source source]
+      [:dc:title title]
+      [:dc:type type]
+      [:ncc:charset "utf-8"]
+      [:ncc:depth (depth production)]
+      [:ncc:files (files production)]
+      (when footnotes [:ncc:footnotes footnotes])
+      [:ncc:kByteSize (size production)]
+      [:ncc:multimediaType multimediaType]
+      [:ncc:narrator narrator]
+      [:ncc:pageFront (page-front production)]
+      [:ncc:pageNormal (page-normal production)]
+      [:ncc:pageSpecial (page-special production)]
+      (when prodnotes [:ncc:prodNotes prodnotes])
+      [:ncc:producedDate producedDate]
+      [:ncc:revisionDate revisionDate]
+      (when multi-volume
+        [:ncc:setInfo (str (:number multi-volume)) " of " (:total multi-volume)])
+      (when sidebars [:ncc:sidebars sidebars])
+      [:ncc:sourceDate sourceDate]
+      [:ncc:sourcePublisher sourcePublisher]
+      [:ncc:tocItems tocItems]
+      [:ncc:totalTime totalTime]
+      [:sbs:audioFormat "FIXME:"]
+      [:sbs:audioTotalTime "FIXME:"]
+      [:sbs:audioType "FIXME:"]
+      [:sbs:idMaster "FIXME:"]
+      [:sbs:idPrint "FIXME:"]
+      [:sbs:idVorstufe "FIXME:"]
+      [:sbs:kostenstelle "FIXME:"]
+      [:sbs:printPageNumber "FIXME:"]]]))
+
+(defn rdf
+  "Create rdf for a given production"
+  [production]
+  (-> production
+      rdf-sexp
+      xml/sexp-as-element
+      xml/emit-str))


WIP pulse animation

WIP pulse animation

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/dominikzarzecki/meteor-impacts-timelapse.git/'


4clojure:: impl the pairwise brackets parser--first draft -> not done

error: pathspec 'src/clojure_learning/pairwise-brackets-checker.clj' did not match any file(s) known to git

--- src/clojure_learning/pairwise-brackets-checker.clj
+++ src/clojure_learning/pairwise-brackets-checker.clj
@@ -0,0 +1,37 @@
+(ns pairwise
+  (:use [clojure.repl]))
+
+(defn pairwise-checker?
+  [stringified-expr]
+    (let [open-paran? #(re-seq #"\[|\(|\{" %)
+          close-paran? #(re-seq #"\)|\]|\}" %)
+          pair? #(re-seq #"\(\)|\[\]|\{\}" (str % %2))]
+      (loop [[head & tail] (seq stringified-expr)
+             opening-brackets []
+             closing-brackets []]
+        (if (nil? head)
+          (= (count opening-brackets) (count closing-brackets))
+          (if-let [closing (close-paran? (str head))]
+            (if (pair? (last opening-brackets) closing)
+               (recur tail (vec (butlast opening-brackets)) closing-brackets)
+               (recur tail opening-brackets (conj closing-brackets (str head))))
+            (if-let [opening (open-paran? (str head))]
+               (recur tail (conj opening-brackets (str head)) closing-brackets)))))))
+
+(pairwise-checker? "class Test {
+      public static void main(String[] args) {
+        System.out.println(\"Hello world.\");
+      }
+    }")
+
+(doc re-seq)
+(re-seq #"\[|\(" "[")
+
+      (int \{)
+      (int \})
+
+
+(defn pair? [a b]
+  (re-seq #"\(\)|\[\]|\{\}" (str a b)))
+(pair? "(" ")") ;; ("()")
+(pair? "(" "}") ;; nil


Add ability to run aggregation separate from std phase-2 run

error: pathspec 'Jobs/tnseq-phase-2b-job-template.clj' did not match any file(s) known to git

--- Jobs/tnseq-phase-2b-job-template.clj
+++ Jobs/tnseq-phase-2b-job-template.clj
@@ -0,0 +1,10 @@
+
+{:nodes
+ {:ph2
+  {:name "tnseq-phase2b",
+   :type "tool",
+   :args []}
+  :prn1 {:type "func",
+         :name "prn"}},
+ :edges
+ {:ph2 [:prn1]}}


Added database setup utility to unit tests

error: pathspec 'test/ruuvi_server/database/test/database_setup.clj' did not match any file(s) known to git

--- test/ruuvi_server/database/test/database_setup.clj
+++ test/ruuvi_server/database/test/database_setup.clj
@@ -0,0 +1,44 @@
+(ns ruuvi-server.database.test.database-setup
+  (:use midje.sweet)
+  (:require [ruuvi-server.configuration :as conf]
+            [ruuvi-server.database.entities :as entities]
+            [lobos.migrations :as migrations]
+            ))
+
+(defn setup-db-connection [db-name]
+  (let [test-config {:database {:classname "org.h2.Driver"
+                                :subprotocol "h2"
+                                :user "sa"
+                                :password ""
+                                :subname (str "mem:" db-name)
+                                :unsafe true}
+                  }]
+
+    (conf/init-config test-config)
+    (entities/init)
+    ))
+
+(defn create-db-schema []
+  (migrations/do-migration :forward))
+
+(defn drop-db-schema []
+  (migrations/do-migration :rollback))
+
+(fact "Database connection setup works"
+      (setup-db-connection "dummy_internal") => truthy)
+
+(fact "Database migrations apply"
+      (create-db-schema) => nil)
+
+(fact "Database migrations can be applied several times"
+      (create-db-schema)
+      (create-db-schema) => nil)
+
+(fact "Database migrations rollback"
+      (create-db-schema) => nil)
+
+(fact "Database migrations can be re-applied after rollback"
+      (drop-db-schema) => nil)
+
+(fact "Database migrations can be rollbacked after re-applying"
+      (drop-db-schema) => nil)


Add another example show, which was really used.

error: pathspec 'src/afterglow/shows/sallie.clj' did not match any file(s) known to git

--- src/afterglow/shows/sallie.clj
+++ src/afterglow/shows/sallie.clj
@@ -0,0 +1,461 @@
+(ns afterglow.shows.sallie
+  "Cues for Sallie's birthday/housewarming party. Useful as an example
+  of how an actual small show was put together early in Afterglow's
+  development, and also as a source of effects that may want to make
+  there way into a more central place."
+  {:author "James Elliott"}
+  (:require [afterglow.beyond :as beyond]
+            [afterglow.controllers.ableton-push :as push]
+            [afterglow.controllers :as ct]
+            [afterglow.core :as core]
+            [afterglow.effects :as fx]
+            [afterglow.effects.color :refer [color-effect]]
+            [afterglow.effects.cues :as cues]
+            [afterglow.effects.dimmer :refer [dimmer-effect master-set-level]]
+            [afterglow.effects.fun :as fun]
+            [afterglow.effects.movement :as move]
+            [afterglow.effects.oscillators :as oscillators]
+            [afterglow.effects.params :as params]
+            [afterglow.effects.show-variable :as var-fx]
+            [afterglow.fixtures.american-dj :as adj]
+            [afterglow.fixtures.blizzard :as blizzard]
+            [afterglow.fixtures.chauvet :as chauvet]
+            [afterglow.rhythm :as rhythm]
+            [afterglow.show :as show]
+            [afterglow.show-context :refer [*show* with-show set-default-show!]]
+            [afterglow.transform :as tf]
+            [com.evocomputing.colors :refer [color-name create-color hue adjust-hue]]
+            [overtone.osc :as osc]
+            [taoensso.timbre :as timbre]))
+
+(defonce ^{:doc "Holds the show if it has been created,
+  so it can be unregistered if it is being re-created."}
+  sallie-show
+  (atom nil))
+
+(defonce ^{:doc "Allows commands to be sent to the instance of
+  Pangolin Beyond running alongside this light show, in order to
+  affect laser cues."}
+  laser-show
+  (afterglow.beyond/beyond-server "192.168.212.128" 16062))
+
+(defonce ^{:doc "Allows effects to set variables in the running show."}
+  var-binder
+  (atom nil))
+
+(defn use-sallie-show
+  "Set up the show for Sallie's party. By default it will create the
+  show to use universe 1, but if you want to use a different
+  universe (for example, a dummy universe on ID 0, because your DMX
+  interface isn't handy right now), you can override that by supplying
+  a different ID after :universe."
+  [& {:keys [universe] :or {universe 1}}]
+  ;; Since this class is an entry point for interactive REPL usage,
+  ;; make sure a sane logging environment is established.
+  (core/init-logging)
+
+  ;; Create, or re-create the show, on the chosen OLA universe, for demonstration
+  ;; purposes. Make it the default show so we don't need to wrap everything below
+  ;; in a (with-show sallie-show ...) binding
+  (set-default-show! (swap! sallie-show (fn [s]
+                                          (when s
+                                            (show/unregister-show s)
+                                            (with-show s (show/stop!)))
+                                          (show/show :universes [universe] :description "Sallie Show"))))
+
+  (show/patch-fixture! :hex-1 (chauvet/slimpar-hex3-irc) universe 129 :x (tf/inches 14) :y (tf/inches 44)
+                       :z (tf/inches -4.75)
+                       :x-rotation (tf/degrees 90))
+  (show/patch-fixture! :hex-2 (chauvet/slimpar-hex3-irc) universe 145 :x (tf/inches -14) :y (tf/inches 44)
+                       :z (tf/inches -4.75)
+                       :x-rotation (tf/degrees 90))
+  (show/patch-fixture! :ws-1 (blizzard/weather-system) universe 161
+                       :x (tf/inches 55) :y (tf/inches 71) :z (tf/inches 261) :y-rotation (tf/degrees 225))
+  (show/patch-fixture! :snowball (blizzard/snowball) universe 33 :x (tf/inches -76) :y (tf/inches 32)
+                       :z (tf/inches 164.5))
+  (beyond/bind-to-show laser-show *show*)
+  (reset! var-binder (var-fx/create-for-show *show*))
+  '*show*)
+
+
+(defn global-color-effect
+  "Make a color effect which affects all lights in the Sallie show.
+  If the show variable `:also-color-laser` has a value other than `0`,
+  the color will be sent to Beyond to affect laser cues as well. Can
+  include only a specific set of lights by passing them with
+  `:lights`" {:doc/format :markdown}
+  [color & {:keys [include-color-wheels? lights] :or {lights (show/all-fixtures)}}]
+  (try
+    (let [[c desc] (cond (= (type color) :com.evocomputing.colors/color)
+                       [color (color-name color)]
+                       (and (satisfies? params/IParam color)
+                            (= (params/result-type color) :com.evocomputing.colors/color))
+                       [color "variable"]
+                       :else
+                       [(create-color color) color])]
+      (fx/scene (str "Color: " desc)
+                (color-effect (str "Color: " desc) c lights :include-color-wheels? include-color-wheels?)
+                (fx/conditional-effect "Color Laser?" (params/build-variable-param :also-color-laser)
+                                       (beyond/laser-color-effect laser-show c))))
+    (catch Exception e
+      (throw (Exception. (str "Can't figure out how to create color from " color) e)))))
+
+(defn global-dimmer-effect
+  "Return an effect that sets all the dimmers in the sallie rig.
+  Originally this had to be to a static value, but now that dynamic
+  parameters exist, it can vary in response to a MIDI mapped show
+  variable, an oscillator, or the location of the fixture. You can
+  override the default name by passing in a value with :effect-name"
+  [level & {:keys [effect-name]}]
+  (dimmer-effect level (show/all-fixtures) :effect-name effect-name))
+
+(defn global-color-cue
+  "Create a cue-grid entry which establishes a global color effect."
+  [color x y & {:keys [include-color-wheels? held]}]
+  (let [cue (cues/cue :color (fn [_] (global-color-effect color :include-color-wheels? include-color-wheels?))
+                      :held held
+                      :color (create-color color))]
+    (ct/set-cue! (:cue-grid *show*) x y cue)))
+
+(defn make-strobe-cue
+  "Create a cue which strobes a set of fixtures as long as the cue pad
+  is held down, letting the operator adjust the lightness of the
+  strobe color by varying the pressure they are applying to the pad on
+  controllers which support pressure sensitivity."
+  [name fixtures x y]
+  (ct/set-cue! (:cue-grid *show*) x y
+               (cues/cue (keyword (str "strobe-" (clojure.string/replace (clojure.string/lower-case name) " " "-")))
+                         (fn [var-map] (fun/strobe (str "Strobe " name) fixtures
+                                                   (:level var-map 50) (:lightness var-map 100)))
+                         :color :purple
+                         :held true
+                         :priority 100
+                         :variables [{:key "level" :min 0 :max 100 :start 100 :name "Level"}
+                                     {:key "lightness" :min 0 :max 100 :name "Lightness" :velocity true}])))
+
+(defn x-phase
+  "Return a value that ranges from zero for the leftmost fixture in a
+  show to 1 for the rightmost, for staggering the phase of an
+  oscillator in making a can-can chase."
+  [head show]
+  (let [dimensions @(:dimensions *show*)]
+    (/ (- (:x head) (:min-x dimensions)) (- (:max-x dimensions) (:min-x dimensions)))))
+
+(defn try-laser-cues
+  "Create some cues that integrate Pangolin Beyond. Assumes sallie
+  show has been created, and takes the beyond server to work with as
+  an argument."
+  [server]
+  (ct/set-cue! (:cue-grid *show*) 2 7
+               (cues/cue :beyond-cue-1-1 (fn [_] (beyond/cue-effect server 1 1))
+                         :short-name "Beyond 1 1"))
+  (ct/set-cue! (:cue-grid *show*) 3 7
+               (cues/cue :beyond-cue-1-2 (fn [_] (beyond/cue-effect server 1 2))
+                         :short-name "Beyond 1 2")))
+
+
+(defn make-cues
+  "Create the cues for the Sallie show."
+  []
+  {:pre [(some? *show*)]}
+  (let [hue-bar (params/build-oscillated-param  ; Spread a rainbow across a bar of music
+                 (oscillators/sawtooth-bar) :max 360)
+        desat-beat (params/build-oscillated-param  ; Desaturate a color as a beat progresses
+                    (oscillators/sawtooth-beat :down? true) :max 100)
+        hue-gradient (params/build-spatial-param  ; Spread a rainbow across the light grid
+                      (show/all-fixtures)
+                      (fn [head] (- (:x head) (:min-x @(:dimensions *show*)))) :max 360)]
+    (global-color-cue "red" 0 0 :include-color-wheels? true)
+    (global-color-cue "orange" 1 0 :include-color-wheels? true)
+    (global-color-cue "yellow" 2 0 :include-color-wheels? true)
+    (global-color-cue "green" 3 0 :include-color-wheels? true)
+    (global-color-cue "blue" 4 0 :include-color-wheels? true)
+    (global-color-cue "purple" 5 0 :include-color-wheels? true)
+    (global-color-cue "violet" 6 0 :include-color-wheels? true)
+    (global-color-cue "white" 7 0 :include-color-wheels? true)
+    (global-color-cue "pink" 0 1 :include-color-wheels? true)
+    (global-color-cue "salmon" 1 1 :include-color-wheels? true)
+    (global-color-cue "teal" 2 1 :include-color-wheels? true)
+    (global-color-cue "cyan" 3 1 :include-color-wheels? true)
+
+    (ct/set-cue! (:cue-grid *show*) 4 1
+                 (cues/cue :color (fn [_] (global-color-effect
+                                           (params/build-color-param :s :rainbow-saturation :l 50 :h hue-bar)))
+                           :short-name "Rainbow Bar Fade"
+                           :variables [{:key :rainbow-saturation :name "Saturatn" :min 0 :max 100 :start 100
+                                        :type :integer}]))
+    (ct/set-cue! (:cue-grid *show*) 5 1
+                 (cues/cue :color (fn [_] (global-color-effect
+                                           (params/build-color-param :s :rainbow-saturation :l 50 :h hue-gradient)
+                                           :include-color-wheels? true))
+                           :short-name "Rainbow Grid"
+                           :variables [{:key :rainbow-saturation :name "Saturatn" :min 0 :max 100 :start 100
+                                        :type :integer}]))
+    (ct/set-cue! (:cue-grid *show*) 6 1
+                 (cues/cue :color (fn [_] (global-color-effect
+                                           (params/build-color-param :s :rainbow-saturation :l 50 :h hue-gradient
+                                                                     :adjust-hue hue-bar)))
+                           :short-name "Rainbow Grid+Bar"
+                           :variables [{:key :rainbow-saturation :name "Saturatn" :min 0 :max 100 :start 100
+                                        :type :integer}]))
+    ;; TODO: Make this a high-priroity cue which desaturates whatever else is going on.
+    (ct/set-cue! (:cue-grid *show*) 7 1  ; Desaturate the rainbow as each beat progresses
+                 (cues/cue :color (fn [_] (global-color-effect
+                                           (params/build-color-param :s desat-beat :l 50 :h hue-gradient
+                                                                     :adjust-hue hue-bar)))
+                           :short-name "Rainbow Pulse"))
+
+    (ct/set-cue! (:cue-grid *show*) 3 7
+                 (cues/cue :color (fn [var-map]
+                                    (let [hue (fun/random-beat-number-param :max 360 :min-change 60)]
+                                      (global-color-effect
+                                       (params/build-color-param :h hue :l 50 :s (:saturation var-map 100)))))
+                           :short-name "Random Beat Color"))
+
+    (ct/set-cue! (:cue-grid *show*) 0 7
+                 (cues/cue :sparkle (fn [var-map] (fun/sparkle (show/all-fixtures)
+                                                               :chance (:chance var-map 0.05)
+                                                               :fade-time (:fade-time var-map 50)))
+                           :held true
+                           :priority 100
+                           :variables [{:key "chance" :min 0.0 :max 0.4 :start 0.05 :velocity true}
+                                       {:key "fade-time" :name "Fade" :min 1 :max 2000 :start 50 :type :integer}]))
+
+    (ct/set-cue! (:cue-grid *show*) 5 6
+                 (cues/function-cue :strobe-all :strobe (show/all-fixtures) :effect-name "Raw Strobe"))
+
+    (ct/set-cue! (:cue-grid *show*) 5 7
+                 (cues/cue :color-laser (fn [_] (var-fx/variable-effect @var-binder :also-color-laser 1))
+                           :color :red
+                           :short-name "Also color laser"))
+
+    (ct/set-cue! (:cue-grid *show*) 6 7
+                 (cues/function-cue :snowball-sound :sound-active (show/fixtures-named "snowball")
+                                    :color :cyan))
+
+    (ct/set-cue! (:cue-grid *show*) 7 7
+                 (cues/function-cue :hex-uv :uv (show/fixtures-named "snowball")
+                                    :level 255
+                                    :color :blue))
+
+    ;; Dimmer cues to turn on and set brightness of groups of lights
+    (ct/set-cue! (:cue-grid *show*) 0 2
+                 (cues/cue :dimmers (fn [var-map] (global-dimmer-effect
+                                                   (params/bind-keyword-param (:level var-map 255) Number 255)
+                                                   :effect-name "All Dimmers"))
+                           :variables [(merge {:key "level" :min 0 :max 255 :start 255 :name "Level"})]
+                           :color :yellow :end-keys [:torrent-dimmers :blade-dimmers :ws-dimmers
+                                                     :puck-dimmers :hex-dimmers :snowball-dimmers]))
+    (ct/set-cue! (:cue-grid *show*) 1 2
+                 (cues/cue :ws-dimmers (fn [var-map] (dimmer-effect
+                                                      (params/bind-keyword-param (:level var-map 255) Number 255)
+                                                      (show/fixtures-named "ws")
+                                                      :effect-name "Weather System Dimmers"))
+                           :variables [(merge {:key "level" :min 0 :max 255 :start 255 :name "Level"})]
+                           :color :orange :end-keys [:dimmers]))
+
+    (ct/set-cue! (:cue-grid *show*) 2 2
+                 (cues/cue :hex-dimmers (fn [var-map] (dimmer-effect
+                                                       (params/bind-keyword-param (:level var-map 255) Number 255)
+                                                       (show/fixtures-named "hex")
+                                                       :effect-name "Hex Dimmers"))
+                           :variables [(merge {:key "level" :min 0 :max 255 :start 255 :name "Level"})]
+                           :color :orange :end-keys [:dimmers]))
+    (ct/set-cue! (:cue-grid *show*) 3 2
+                 (cues/cue :snowball-dimmers (fn [var-map] (dimmer-effect
+                                                            (params/bind-keyword-param (:level var-map 255) Number 255)
+                                                            (show/fixtures-named "snowball")
+                                                            :effect-name "Snowball Dimmers"))
+                           :variables [(merge {:key "level" :min 0 :max 255 :start 255 :name "Level"})]
+                           :color :orange :end-keys [:dimmers]))
+
+    ;; Dimmer oscillator cues: Sawtooth down each beat
+    (ct/set-cue! (:cue-grid *show*) 0 3
+                 (cues/cue :dimmers (fn [_] (global-dimmer-effect
+                                             (params/build-oscillated-param (oscillators/sawtooth-beat :down? true))
+                                             :effect-name "All Saw Down Beat"))
+                           :color :yellow :end-keys [:ws-dimmers :hex-dimmers :snowball-dimmers]))
+    (ct/set-cue! (:cue-grid *show*) 1 3
+                 (cues/cue :ws-dimmers
+                           (fn [_] (dimmer-effect
+                                    (params/build-oscillated-param (oscillators/sawtooth-beat :down? true))
+                                    (show/fixtures-named "ws") :effect-name "WS Saw Down Beat"))
+                           :color :orange :end-keys [:dimmers]))
+    (ct/set-cue! (:cue-grid *show*) 2 3
+                 (cues/cue :hex-dimmers
+                           (fn [_] (dimmer-effect
+                                    (params/build-oscillated-param (oscillators/sawtooth-beat :down? true))
+                                    (show/fixtures-named "hex") :effect-name "Hex Saw Down Beat"))
+                           :color :orange :end-keys [:dimmers]))
+    (ct/set-cue! (:cue-grid *show*) 3 3
+                 (cues/cue :snowball-dimmers
+                           (fn [_] (dimmer-effect
+                                    (params/build-oscillated-param (oscillators/sawtooth-beat :down? true))
+                                    (show/fixtures-named "snowball") :effect-name "Snowball Saw Down Beat"))
+                           :color :orange :end-keys [:dimmers]))
+
+    ;; Dimmer oscillator cues: Sawtooth up each beat
+    (ct/set-cue! (:cue-grid *show*) 4 3
+                 (cues/cue :dimmers (fn [_] (global-dimmer-effect
+                                             (params/build-oscillated-param (oscillators/sawtooth-beat))
+                                             :effect-name "All Saw Up Beat"))
+                           :color :yellow :end-keys [:ws-dimmers :hex-dimmers :snowball-dimmers]))
+    (ct/set-cue! (:cue-grid *show*) 5 3
+                 (cues/cue :ws-dimmers
+                           (fn [_] (dimmer-effect
+                                    (params/build-oscillated-param (oscillators/sawtooth-beat))
+                                    (show/fixtures-named "ws") :effect-name "WS Saw Up Beat"))
+                           :color :orange :end-keys [:dimmers]))
+    (ct/set-cue! (:cue-grid *show*) 6 3
+                 (cues/cue :hex-dimmers
+                           (fn [_] (dimmer-effect
+                                    (params/build-oscillated-param (oscillators/sawtooth-beat))
+                                    (show/fixtures-named "hex") :effect-name "Hex Saw Up Beat"))
+                           :color :orange :end-keys [:dimmers]))
+    (ct/set-cue! (:cue-grid *show*) 7 3
+                 (cues/cue :snowball-dimmers
+                           (fn [_] (dimmer-effect
+                                    (params/build-oscillated-param (oscillators/sawtooth-beat))
+                                    (show/fixtures-named "snowball") :effect-name "Snowball Saw Up Beat"))
+                           :color :orange :end-keys [:dimmers]))
+
+    ;; Dimmer oscillator cues: Sawtooth down over 2 beat
+    (ct/set-cue! (:cue-grid *show*) 0 4
+                 (cues/cue :dimmers (fn [_] (global-dimmer-effect
+                                             (params/build-oscillated-param (oscillators/sawtooth-beat :beat-ratio 2
+                                                                                :down? true))
+                                             :effect-name "All Saw Down 2 Beat"))
+                           :color :yellow :end-keys [:ws-dimmers :hex-dimmers :snowball-dimmers]))
+    (ct/set-cue! (:cue-grid *show*) 1 4
+                 (cues/cue :ws-dimmers
+                           (fn [_] (dimmer-effect
+                                    (params/build-oscillated-param (oscillators/sawtooth-beat :beat-ratio 2
+                                                                                :down? true))
+                                    (show/fixtures-named "ws") :effect-name "WS Saw Down 2 Beat"))
+                           :color :orange :end-keys [:dimmers]))
+    (ct/set-cue! (:cue-grid *show*) 2 4
+                 (cues/cue :hex-dimmers
+                           (fn [_] (dimmer-effect
+                                    (params/build-oscillated-param (oscillators/sawtooth-beat :beat-ratio 2
+                                                                                :down? true))
+                                    (show/fixtures-named "hex") :effect-name "Hex Saw Down 2 Beat"))
+                           :color :orange :end-keys [:dimmers]))
+    (ct/set-cue! (:cue-grid *show*) 3 4
+                 (cues/cue :snowball-dimmers
+                           (fn [_] (dimmer-effect
+                                    (params/build-oscillated-param (oscillators/sawtooth-beat :beat-ratio 2
+                                                                                :down? true))
+                                    (show/fixtures-named "snowball") :effect-name "Snowball Saw Down 2 Beat"))
+                           :color :orange :end-keys [:dimmers]))
+
+    ;; Dimmer oscillator cues: Sawtooth up over 2 beat
+    (ct/set-cue! (:cue-grid *show*) 4 4
+                 (cues/cue :dimmers (fn [_] (global-dimmer-effect
+                                             (params/build-oscillated-param (oscillators/sawtooth-beat :beat-ratio 2))
+                                             :effect-name "All Saw Up 2 Beat"))
+                           :color :yellow :end-keys [:ws-dimmers :hex-dimmers :snowball-dimmers]))
+    (ct/set-cue! (:cue-grid *show*) 5 4
+                 (cues/cue :ws-dimmers
+                           (fn [_] (dimmer-effect
+                                    (params/build-oscillated-param (oscillators/sawtooth-beat :beat-ratio 2))
+                                    (show/fixtures-named "ws") :effect-name "WS Saw Up 2 Beat"))
+                           :color :orange :end-keys [:dimmers]))
+    (ct/set-cue! (:cue-grid *show*) 6 4
+                 (cues/cue :hex-dimmers
+                           (fn [_] (dimmer-effect
+                                    (params/build-oscillated-param (oscillators/sawtooth-beat :beat-ratio 2))
+                                    (show/fixtures-named "hex") :effect-name "Hex Saw Up 2 Beat"))
+                           :color :orange :end-keys [:dimmers]))
+    (ct/set-cue! (:cue-grid *show*) 7 4
+                 (cues/cue :snowball-dimmers
+                           (fn [_] (dimmer-effect
+                                    (params/build-oscillated-param (oscillators/sawtooth-beat :beat-ratio 2))
+                                    (show/fixtures-named "snowball") :effect-name "Snowball Saw Up 2 Beat"))
+                           :color :orange :end-keys [:dimmers]))
+
+    ;; Dimmer oscillator cues: Sine over a bar
+    (ct/set-cue! (:cue-grid *show*) 0 5
+                 (cues/cue :dimmers (fn [_] (global-dimmer-effect
+                                             (params/build-oscillated-param (oscillators/sine-bar) :min 1)
+                                             :effect-name "All Sine Bar"))
+                           :color :cyan :end-keys [:ws-dimmers :hex-dimmers :snowball-dimmers]))
+    (ct/set-cue! (:cue-grid *show*) 1 5
+                 (cues/cue :ws-dimmers
+                           (fn [_] (dimmer-effect
+                                    (params/build-oscillated-param (oscillators/sine-bar) :min 1)
+                                    (show/fixtures-named "ws") :effect-name "WS Sine Bar"))
+                           :color :blue :end-keys [:dimmers]))
+    (ct/set-cue! (:cue-grid *show*) 2 5
+                 (cues/cue :hex-dimmers
+                           (fn [_] (dimmer-effect
+                                    (params/build-oscillated-param (oscillators/sine-bar) :min 1)
+                                    (show/fixtures-named "hex") :effect-name "Hex Sine Bar"))
+                           :color :blue :end-keys [:dimmers]))
+    (ct/set-cue! (:cue-grid *show*) 3 5
+                 (cues/cue :snowball-dimmers
+                           (fn [_] (dimmer-effect
+                                    (params/build-oscillated-param (oscillators/sine-bar) :min 1)
+                                    (show/fixtures-named "snowball") :effect-name "Snowball Sine Bar"))
+                           :color :blue :end-keys [:dimmers]))
+    (ct/set-cue! (:cue-grid *show*) 4 5
+                 (cues/cue :dimmers
+                           (fn [_] (dimmer-effect
+                                    (params/build-oscillated-param (oscillators/triangle-bar) :min 1)
+                                    (show/all-fixtures) :effect-name "All Triangle Bar"))
+                           :color :purple :end-keys [:ws-dimmers :hex-dimmers :snowball-dimmers]))
+    (ct/set-cue! (:cue-grid *show*) 5 5
+                 (cues/cue :ws-dimmers
+                           (fn [_] (dimmer-effect
+                                    (params/build-oscillated-param (oscillators/triangle-bar) :min 1)
+                                    (show/fixtures-named "ws") :effect-name "WS Triangle Bar"))
+                           :color :violet :end-keys [:dimmers]))
+    (ct/set-cue! (:cue-grid *show*) 6 5
+                 (cues/cue :hex-dimmers
+                           (fn [_] (dimmer-effect
+                                    (params/build-oscillated-param (oscillators/triangle-bar) :min 1)
+                                    (show/fixtures-named "hex") :effect-name "Hex Triangle Bar"))
+                           :color :violet :end-keys [:dimmers]))
+    (ct/set-cue! (:cue-grid *show*) 7 5
+                 (cues/cue :snowball-dimmers
+                           (fn [_] (dimmer-effect
+                                    (params/build-oscillated-param (oscillators/triangle-bar) :min 1)
+                                    (show/fixtures-named "snowball") :effect-name "Snowball Triangle Bar"))
+                           :color :violet :end-keys [:dimmers]))
+
+    ;; Strobe cues
+    (make-strobe-cue "All" (show/all-fixtures) 0 6)
+    (make-strobe-cue "Weather Systems" (show/fixtures-named "ws") 1 6)
+    (make-strobe-cue "Hexes" (show/fixtures-named "hex") 2 6)
+    (make-strobe-cue "Snowball" (show/fixtures-named "snowball") 3 6)
+
+    (ct/set-cue! (:cue-grid *show*) 7 6
+                 (cues/cue :adjust-strobe (fn [_] (fun/adjust-strobe))
+                           :color :purple
+                           :variables [{:key :strobe-hue :min 0 :max 360 :name "Hue" :centered true}
+                                       {:key :strobe-saturation :min 0 :max 100 :name "Saturatn"}]))
+
+    ;; A couple snowball cues
+    (ct/set-cue! (:cue-grid *show*) 0 10 (cues/function-cue :sb-pos :beams-fixed (show/fixtures-named "snowball")
+                                                            :effect-name "Snowball Fixed"))
+    (ct/set-cue! (:cue-grid *show*) 1 10 (cues/function-cue :sb-pos :beams-moving (show/fixtures-named "snowball")
+                                                            :effect-name "Snowball Moving"))
+
+    ;; Some example chases
+    (ct/set-cue! (:cue-grid *show*) 8 1
+                 (cues/cue :color (fn [_] (fun/iris-out-color-cycle-chase (show/all-fixtures)))))
+    (ct/set-cue! (:cue-grid *show*) 9 1
+                 (cues/cue :color (fn [_] (fun/wipe-right-color-cycle-chase
+                                           (show/all-fixtures) :transition-phase-function rhythm/snapshot-bar-phase))))
+    (ct/set-cue! (:cue-grid *show*) 10 1
+                 (cues/cue :color (fn [_] (fun/wipe-right-color-cycle-chase
+                                           (show/all-fixtures)
+                                           :color-index-function rhythm/snapshot-beat-within-phrase
+                                           :transition-phase-function rhythm/snapshot-beat-phase
+                                           :effect-name "Wipe Right Beat"))))))
+
+(defn use-push
+  "A trivial reminder of how to connect the Ableton Push to run the
+  show. But also sets up the cues, if you haven't yet."
+  []
+  (make-cues)
+  (push/bind-to-show *show*))


scheduler: store offers as a seq, not map

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/pyr/bundes.git/'


fix remaining tests

fix remaining tests

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/democracyworks/election-notification-works.git/'


Implemented query zipper.

Implemented query zipper.

error: pathspec 'src/cmr/search/models/query_zipper.clj' did not match any file(s) known to git

--- src/cmr/search/models/query_zipper.clj
+++ src/cmr/search/models/query_zipper.clj
@@ -0,0 +1,106 @@
+(ns cmr.search.models.query-zipper
+  "Implements the clojure.zip API for queries"
+  (:require [cmr.search.models.query :as qm]
+            [clojure.zip :as z])
+  (:import [cmr.search.models.query
+            Query
+            ConditionGroup
+            NegatedCondition
+            CollectionQueryCondition
+            NestedCondition
+            StringCondition]))
+
+
+(defprotocol QueryZipperHelper
+  "Provides implementations of functions that are different for each condition"
+  (branch? [loc])
+  (children [loc])
+  (make-node [loc node-children]))
+
+(defn query-zipper
+  "Constructs a zipper from a query or query condition."
+  [query]
+  (z/zipper branch? children make-node query))
+
+(defn- assert-single-child
+  [node-children]
+  (when (not= (count node-children) 1)
+    (throw (Exception. (str "Expected a single child node"
+                            (pr-str node-children))))))
+
+(extend-protocol QueryZipperHelper
+  Query
+  (branch? [_] true)
+
+  (children
+    [query]
+    [(:condition query)])
+
+  (make-node
+    [query node-children]
+    (assert-single-child node-children)
+    (assoc query :condition (first node-children)))
+
+  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+  ConditionGroup
+  (branch? [_] true)
+
+  (children
+    [group]
+    (:conditions group))
+
+  (make-node
+    [group node-children]
+    (assoc group :conditions node-children))
+
+  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+  NegatedCondition
+  (branch? [_] true)
+
+  (children
+    [c]
+    (:condition c))
+
+  (make-node
+    [c node-children]
+    (assert-single-child node-children)
+    (assoc c :condition (first node-children)))
+
+  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+  CollectionQueryCondition
+  (branch? [_] true)
+
+  (children
+    [c]
+    (:condition c))
+
+  (make-node
+    [c node-children]
+    (assert-single-child node-children)
+    (assoc c :condition (first node-children)))
+
+  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+  NestedCondition
+  (branch? [_] true)
+
+  (children
+    [c]
+    (:condition c))
+
+  (make-node
+    [c node-children]
+    (assert-single-child node-children)
+    (assoc c :condition (first node-children)))
+
+  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+  Object
+  (branch? [_] false)
+
+  (children
+    [loc]
+    (throw (Exception. "This node does not have children.")))
+
+  (make-node
+    [loc node-children]
+    (throw (Exception. "This node can not have children."))))
+


New module: config.clj

New module: config.clj

error: pathspec 'src/emender_jenkins/config.clj' did not match any file(s) known to git

--- src/emender_jenkins/config.clj
+++ src/emender_jenkins/config.clj
@@ -0,0 +1,7 @@
+(ns emender-jenkins.config)
+
+(def default-port
+    "Default port used when no -p or --port CLI option is specified."
+    "3000")
+
+


Add a stupid ideally-failing core test

Add a stupid ideally-failing core test

error: pathspec 'test/desdemona/ui/core_test.cljs' did not match any file(s) known to git

--- test/desdemona/ui/core_test.cljs
+++ test/desdemona/ui/core_test.cljs
@@ -0,0 +1,7 @@
+(ns desdemona.ui.core-test
+  (:require
+   [desdemona.ui.core :as c]
+   [cljs.test :as t :refer-macros [deftest testing is are]]))
+
+(deftest add-tests
+  (is (= (c/add 1 2) 3)))


use lets in subscriptions in the todomvc example

--- examples/todomvc/src/todomvc/core.cljs
+++ examples/todomvc/src/todomvc/core.cljs
@@ -93,16 +93,18 @@
   :done
   (fn
     [db _]
-    (reaction (->> @(subscribe [:items])
-                   (filter :done)
-                   count))))
+    (let [items (subscribe [:items])]
+      (reaction (->> @items
+                     (filter :done)
+                     count)))))

 (register-sub
   :active
   (fn
     [db _]
-    (reaction (- (count @(subscribe [:items]))
-                 @(subscribe [:done])))))
+    (let [items (subscribe [:items])
+          done (subscribe [:done])]
+      (reaction (- (count @items) @done)))))


Add namespace with helpers for work with html5 blobs.

fatal: unable to access 'https://github.com/studiospring/uxbox.git/': The requested URL returned error: 403


Default to local SMTP for the dev profile.

At least that'll be correct *some* of the time.

--- dev-resources/config.clj
+++ dev-resources/config.clj
@@ -4,9 +4,6 @@
  :key-file "data/dev_authorized_keys"
  :repo "data/dev_repo"
  :bcrypt-work-factor 12
- :mail {:hostname "smtp.gmail.com"
+ :mail {:hostname "localhost"
         :from "noreply@clojars.org"
-        :username "clojars@pupeno.com"
-        :password "fuuuuuu"
-        :port 465 ; If you change ssl to false, the port might not be effective, search for .setSSL and .setSslSmtpPort
-        :ssl true}}
+        :ssl false}}


Making pr a multimethod

Making pr a multimethod

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/michaelsbradleyjr/shen.clj.git/'


Create a sample profiles file

Create a sample profiles file

error: pathspec 'profiles.sample.clj' did not match any file(s) known to git

--- profiles.sample.clj
+++ profiles.sample.clj
@@ -0,0 +1,27 @@
+; Rename this file to profiles.clj
+; Run `lein with-profile +braid repl`
+
+{:braid
+  {:env
+   {
+    ; for invite emails:
+    :mailgun-domain "braid.mysite.com"
+    :mailgun-password "my_mailgun_key"
+    :site-url "http://localhost:5555"
+    :hmac-secret "foobar"
+
+    ; for avatar and file uploads
+    :aws-domain "braid.mysite.com"
+    :aws-access-key "my_aws_key"
+    :aws-secret-key "my_aws_secret"
+    :s3-upload-key "key-for-uploading"
+    :s3-upload-secret "secret-for-uploading"
+
+    ; for link info extraction
+    :embedly-key "embedly api key"
+
+    ; for github login
+    :github-client-id "..."
+    :github-client-secret "..."
+    }
+}


init textSNE-x2p - doesnt work

init textSNE-x2p - doesnt work

--- src/conj_2016/core.clj
+++ src/conj_2016/core.clj
@@ -1,9 +1,10 @@
 (ns conj-2016.core
-  (:require [clojure.java.io :as io]
+  (:require [clojure.core.matrix :as m]
+            [clojure.core.matrix.random :as m.rnd]
+            [clojure.java.io :as io]
+            [clojure.spec :as s]
             [clojure.string :as string]
-            [incanter.core :as i.core]
-            [clojure.core.matrix :as m]
-            [clojure.core.matrix.random :as m.rnd])
+            [incanter.core :as i.core])
   (:import [java.util.zip GZIPInputStream]
            [mikera.matrixx Matrix]))

@@ -49,12 +50,12 @@
      (i.core/matrix (map second inp))]))

 (defn rand-matrix
-  [r c]
-  (i.core/matrix (repeatedly r (partial m.rnd/sample-normal c))))
+  [num-rows num-cols]
+  (i.core/matrix (repeatedly num-rows (partial m.rnd/sample-normal num-cols))))

 (defn one-matrix
-  [r c]
-  (i.core/matrix (repeatedly r (constantly 1))))
+  [num-rows num-cols]
+  (m/add (m/zero-matrix num-rows num-cols) 1))

 (defn matrices
   [^Matrix matrix]
@@ -101,8 +102,14 @@
   ;[2 3]
   ;[4 6]
   ;[7 8]
-  (m/select matrix n (remove (partial = n)
-                             (range (m/column-count matrix)))))
+  (let [r (m/get-row matrix n)]
+    (i.core/matrix
+     (concat (subvec r 0 n)
+             (subvec r (inc n) (m/column-count matrix)))))
+  (m/select matrix
+            n
+            (remove (partial = n)
+                    (range (m/column-count matrix)))))

 ;43 def x2p(X = Math.array([]), tol = 1e-5, perplexity = 30.0):
 ;44     """Performs a binary search to get P-values in such a way that each conditional Gaussian has the same perplexity."""
@@ -158,7 +165,8 @@
   ;88             (H, thisP) = Hbeta(Di, beta[i]);
   ;89             Hdiff = H - logU;
   ;90             tries = tries + 1;
-  (loop [h-diff h-diff
+  (loop [d-i nil
+         h-diff h-diff
          this-p (i.core/matrix [] [])
          tries 0]
     ;71         while Math.abs(Hdiff) > tol and tries < 50:
@@ -166,10 +174,10 @@
                  (< tries 50))
       this-p
       (let [[h this-p] (hbeta d-i (calc-beta))]
-        (recur (m/sub h log-u)
+        (recur nil
+               (m/sub h log-u)
                this-p
-               (inc tries)))))
-  )
+               (inc tries))))))

 (defn x2p
   "Performs a binary search to get P-values in such a way that each conditional Gaussian has the same perplexity."
@@ -192,9 +200,7 @@
                  sum-x)
         p (m/zero-matrix nr nr)
         beta (one-matrix nr 1)
-        log-u (i.core/log perplexity)]
-
-    ))
+        log-u (i.core/log perplexity)]))

 (defn p-values
   [^Matrix matrix perplexity]


Update topology.clj

Update topology.clj

fatal: unable to access 'https://github.com/Zintinio/Breeze.git/': The requested URL returned error: 403


Consistent field name in event log

Consistent field name in event log

--- src/clojars/db.clj
+++ src/clojars/db.clj
@@ -228,12 +228,13 @@
                                                       :pgp_key :pgp-key})))
   (write-key-file (:key-file config)))

-(defn add-member [group username added-by]
+(defn add-member [group-id username added-by]
   (insert groups
-          (values {:name group
+          (values {:name group-id
                    :user username
                    :added_by added-by}))
-  (ev/record :membership {:group group :username username :added-by added-by}))
+  (ev/record :membership {:group-id group-id :username username
+                          :added-by added-by}))

 (defn check-and-add-group [account groupname]
   (when-not (re-matches #"^[a-z0-9-_.]+$" groupname)


Redirect maven output to SSH err stream.

--- src/clojars/scp.clj
+++ src/clojars/scp.clj
@@ -91,46 +91,59 @@
     (let [model (maven/make-model jarmap)]
       [model jarmap])))

+(defn jar-name [jarmap]
+  (str (name (:name jarmap)) "-" (:version jarmap) ".jar"))
+
 (defn finish-deploy [#^NGContext ctx, files]
-  (printerr "finish-deploy" files)
   (let [metadata (filter #(#{"xml" "clj"} (:suffix %)) files)
-        jars     (filter #(#{"jar"}       (:suffix %)) files)]
-    (printerr "metadata" (read-metadata (first metadata)))
-    (for [metafile metadata
-          [model jarmap] (read-metadata metafile)]
-      (printerr jarmap))))
+        jars     (filter #(#{"jar"}       (:suffix %)) files)
+        jarfiles (into {} (map (juxt :name :file) jars))]
+
+    (doseq [metafile metadata
+            [model jarmap] (read-metadata metafile)
+            :let [name (jar-name jarmap)]]
+      (if-let [jarfile (jarfiles name)]
+        (do
+          (printerr "\nDeploying" name "as" (:name jarmap) (:version jarmap))
+          (maven/deploy-model jarfile model "file:///tmp/repo"))
+        (throw (Exception. (str "Jar not found: " name))))))
+  (printerr "Success!")
+  (.flush (.err ctx)))

 (defn nail [#^NGContext ctx]
-  (try
-   (let [in (.in ctx)
-         err (.err ctx)
-         out (.out ctx)
-         account (first (.getArgs ctx))]
+  (let [old-out System/out]
+   (try
+    (System/setOut (.err ctx))
+    (let [in (.in ctx)
+          err (.err ctx)
+          out (.out ctx)
+          account (first (.getArgs ctx))]

-     (when-not account
-       (throw (Exception. "I don't know who you are!")))
+      (when-not account
+        (throw (Exception. "I don't know who you are!")))

-     (doto (.err ctx)
-       (.println (str "Welcome to clojars, " account "!"))
-       (.flush))
-
-     (loop [files [], okay true]
-       (when (> (count files) 100)
-         (throw (IOException. "Too many files uploaded at once")))
+      (doto (.err ctx)
+        (.println (str "Welcome to Clojars, " account "!"))
+        (.flush))
+
+      (loop [files [], okay true]
+        (when (> (count files) 100)
+          (throw (IOException. "Too many files uploaded at once")))

-       (when okay
-         (send-okay ctx))
+        (when okay
+          (send-okay ctx))

-       (let [cmd (char (.read in))]
-         (condp = cmd
-           (char 0)      (do (recur files false))
-           \C            (recur (conj files (scp-copy ctx)) true)
-           (char 65535)  (finish-deploy ctx files)
-           ;; TODO: will need other commands for maven support
-           (throw (IOException. (str "Unknown scp command: '" (int cmd) "'")))))))
+        (let [cmd (char (.read in))]
+          (condp = cmd
+            (char 0)      (do (recur files false))
+            \C            (recur (conj files (scp-copy ctx)) true)
+            (char 65535)  (finish-deploy ctx files)
+            ;; TODO: will need other commands for maven support
+            (throw (IOException. (str "Unknown scp command: '" (int cmd) "'")))))))

-   (catch Throwable t
-     (.printStackTrace t))))
+    (catch Throwable t
+      (.printStackTrace t))
+    (finally (System/setOut old-out)))))

 (defn -nailMain [context]
   (nail context))


boxBlur

boxBlur

error: pathspec 'src/codingpuzzle/box_blur.clj' did not match any file(s) known to git

--- src/codingpuzzle/box_blur.clj
+++ src/codingpuzzle/box_blur.clj
@@ -0,0 +1,16 @@
+(ns codingpuzzle.box-blur
+  "https://app.codesignal.com/arcade/intro/level-5/5xPitc3yT3dqS7XkP")
+
+(defn group-x [x]
+  (->> x
+       (partition 3 1)
+       (map #(reduce + %))))
+
+(defn group-y [[a b c]]
+  (map #(quot (+ %1 %2 %3) 9) a b c))
+
+(defn boxBlur [image]
+  (->> image
+       (map group-x)
+       (partition 3 1)
+       (map group-y)))


log form

log form

error: pathspec 'src/cljs/swarmpit/component/service/log.cljs' did not match any file(s) known to git

--- src/cljs/swarmpit/component/service/log.cljs
+++ src/cljs/swarmpit/component/service/log.cljs
@@ -0,0 +1,70 @@
+(ns swarmpit.component.service.log
+  (:require [material.component :as comp]
+            [swarmpit.component.state :as state]
+            [swarmpit.component.mixin :as mixin]
+            [swarmpit.component.handler :as handler]
+            [swarmpit.routes :as routes]
+            [clojure.string :as string]
+            [sablono.core :refer-macros [html]]
+            [rum.core :as rum]))
+
+(def cursor [:page :service :log])
+
+(defn- filter-items
+  [items predicate]
+  (filter #(string/includes? (:line %) predicate) items))
+
+(defn- data-handler
+  [service-id]
+  (handler/get
+    (routes/path-for-backend :service-logs {:id service-id})
+    {:on-success (fn [response]
+                   (state/update-value [:data] response cursor))}))
+
+(defn- init-state
+  [logs]
+  (state/set-value {:filter {:predicate ""}
+                    :data   logs} cursor))
+
+(def refresh-state-mixin
+  (mixin/refresh
+    (fn [data]
+      (data-handler (:service data)))))
+
+(def init-state-mixin
+  (mixin/init
+    (fn [data]
+      (init-state (:logs data)))))
+
+(rum/defc form < rum/reactive
+                 init-state-mixin
+                 refresh-state-mixin [_]
+  (let [{:keys [filter data]} (state/react cursor)
+        filtered-items (filter-items data
+                                     (:predicate filter))]
+    (print filtered-items)
+    [:div
+     [:div.form-panel
+      [:div.form-panel-left
+       (comp/panel-text-field
+         {:hintText "Search in log"
+          :onChange (fn [_ v]
+                      (state/update-value [:filter :serviceName] v cursor))})
+       [:span.form-panel-space]
+       (comp/panel-checkbox
+         {:checked (:unhealthy filter)
+          :label   "Show timestamp"
+          :onCheck (fn [_ v]
+                     (state/update-value [:filter :unhealthy] v cursor))})]
+      [:div.form-panel-right
+       (comp/mui
+         (comp/raised-button
+           {:href    (routes/path-for-frontend :service-create-image)
+            :label   "New service"
+            :primary true}))]]
+     [:div.log
+      (for [item filtered-items]
+        [:span
+         [:span.log-timestamp (:timestamp item)]
+         [:span.log-body (str " " (:line item))]
+         [:br]])]]))


[WM] Bump ext. service timeout to 10s

[WM] Bump ext. service timeout to 10s

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/democracyworks/election-notification-http-api.git/'


try to be slightly more diligent about 80-character line-length

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/jtbeckha/alda.git/'


check in chapter 1

check in chapter 1

fatal: unable to access 'https://github.com/emaphis/learning-clojure.git/': The requested URL returned error: 403


ensure multiple threads won't overlap the console output

fatal: unable to access 'https://github.com/ChallenHB/samsara.git/': The requested URL returned error: 403


enable console.log

enable console.log

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/kenichirow/recipes.git/'


CMR-4238 - Re-added db migration, now that provider-id code is in place.

error: pathspec 'metadata-db-app/src/migrations/059_add_provider_id_to_variables_table.clj' did not match any file(s) known to git

--- metadata-db-app/src/migrations/059_add_provider_id_to_variables_table.clj
+++ metadata-db-app/src/migrations/059_add_provider_id_to_variables_table.clj
@@ -0,0 +1,25 @@
+(ns migrations.059-add-provider-id-to-variables-table
+  "Adds `provider_id` column to variables table."
+  (:require
+   [clojure.java.jdbc :as j]
+   [cmr.metadata-db.services.provider-validation :as provider-validation]
+   [config.mdb-migrate-helper :as h]))
+
+(defn up
+  "Migrates the database up from version 58 to 59."
+  []
+  (println "migrations.059-add-provider-id-to-variables-table up...")
+  ;; At this point in time, UMM-Vars support is still being developed, so we
+  ;; don't care about what's in the database right now, and the new field
+  ;; can't be null, so:
+  (h/sql "TRUNCATE TABLE METADATA_DB.cmr_variables")
+  (h/sql "TRUNCATE TABLE METADATA_DB.cmr_variable_associations")
+  (h/sql (format (str "ALTER TABLE METADATA_DB.cmr_variables "
+                      "ADD provider_id VARCHAR(%s) NOT NULL")
+                 provider-validation/PROVIDER_ID_MAX_LENGTH)))
+
+(defn down
+  "Migrates the database down from version 59 to 58."
+  []
+  (println "migrations.059-add-provider-id-to-variables-table down...")
+  (h/sql "ALTER TABLE METADATA_DB.cmr_variables DROP COLUMN provider_id"))


Added compojure.crypto (again!)

Added compojure.crypto (again!)

error: pathspec 'src/compojure/crypto.clj' did not match any file(s) known to git

--- src/compojure/crypto.clj
+++ src/compojure/crypto.clj
@@ -0,0 +1,26 @@
+;; Copyright (c) James Reeves. All rights reserved.
+;; The use and distribution terms for this software are covered by the Eclipse
+;; Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) which
+;; can be found in the file epl-v10.html at the root of this distribution. By
+;; using this software in any fashion, you are agreeing to be bound by the
+;; terms of this license. You must not remove this notice, or any other, from
+;; this software.
+
+;; compojure.crypto:
+;;
+;; Functions for cryptographically signing, verifying and encrypting data.
+
+(ns compojure.crypto
+  (:use compojure.encodings)
+  (:import javax.crypto.Mac)
+  (:import javax.crypto.spec.SecretKeySpec))
+
+(defn hmac
+  "Generate a hashed message authentication code with the supplied key and
+  algorithm on some string data."
+  [key algorithm data]
+  (let [spec  (SecretKeySpec. (.getBytes key) algorithm)
+        mac   (doto (Mac/getInstance algorithm)
+                (.init spec))
+        bytes (.doFinal mac (.getBytes data))]
+    (base64-encode-bytes bytes)))


filter docstring updates

filter docstring updates

fatal: unable to access 'https://github.com/alesguzik/cats.git/': The requested URL returned error: 403


Version 0.4.1

Version 0.4.1

fatal: unable to access 'https://github.com/modnakasta/weasel.git/': The requested URL returned error: 403


more config woes

more config woes

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/dagda1/i-cal.git/'


Add description & URL to project.clj

Add description & URL to project.clj

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/democracyworks/ballot-notification-works.git/'


project updates

project updates

fatal: unable to access 'https://github.com/ohpauleez/ttt.git/': The requested URL returned error: 403


upgrade schema

upgrade schema

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/vincentstorme/clojureme.git/'