Add logging namespace

Add logging namespace

error: pathspec 'src/cljc/train_race/log.cljc' did not match any file(s) known to git

--- src/cljc/train_race/log.cljc
+++ src/cljc/train_race/log.cljc
@@ -0,0 +1,60 @@
+(ns train-race.log
+  (:require [clojure.tools.logging :as log]
+            [train-race.config :refer [env]]
+            [mount.core :as mount]))
+
+(defprotocol Logger
+  (log [this msg]))
+
+(defrecord StdOutLogger [] Logger
+  (log [this {:keys [service msg level ex]}]
+    (case level
+      :trace (log/trace service " :: " msg)
+      :debug (log/debug service " :: " msg)
+      :info (log/info service " :: " msg)
+      :warn (log/warn service " :: " msg)
+      :error (if ex (log/error ex service " :: " msg) (log/error service " :: " msg))
+      :fatal (if ex (log/fatal ex service " :: " msg) (log/fatal service " :: " msg)))))
+
+(defrecord NullLogger [] Logger
+  (log [this msg] nil))
+
+(defn trace [logger service {:keys [msg]}]
+  (log logger {:service service :level :trace :msg msg}))
+
+(defn debug [logger service {:keys [msg]}]
+  (log logger {:service service :level :error :msg msg}))
+
+(defn info [logger service {:keys [msg]}]
+  (log logger {:service service :level :info :msg msg}))
+
+(defn warn [logger service {:keys [msg]}]
+  (log logger {:service service :level :warn :msg msg}))
+
+(defn error
+  ([logger service {:keys [msg ex]}]
+   (log logger {:service service :level :error :msg msg
+                :exception ex})))
+
+(defn failure
+  ([logger service {:keys [msg ex]}]
+   (log logger {:service service :level :trace :msg msg
+                :exception ex})))
+
+(defn start-stdoutlogger [config]
+  (let [logger (->StdOutLogger)]
+    (info logger ::system.startup {:msg "StdOutLogger initialising"})
+    logger))
+
+(declare stop-stdoutlogger)
+
+(mount/defstate ^{:on-reload :noop}
+                logger
+                :start
+                (start-stdoutlogger (env :logging))
+                :stop
+                (stop-stdoutlogger))
+
+(defn stop-stdoutlogger []
+  (info logger ::system.shutdown {:msg "Shutting down StdOutLogger; overwriting logger with NullLogger"})
+  (->NullLogger))


improvements on distinct-consecutive

improvements on distinct-consecutive

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/wilkerlucio/youtube-looper.git/'


Added tupelo.forest.xml

Added tupelo.forest.xml

error: pathspec 'test/clj/tst/tupelo/forest/xml.clj' did not match any file(s) known to git

--- test/clj/tst/tupelo/forest/xml.clj
+++ test/clj/tst/tupelo/forest/xml.clj
@@ -0,0 +1,59 @@
+(ns tst.tupelo.forest.xml
+  (:use tupelo.core tupelo.test)
+  (:require
+    [clojure.java.io :as io]
+    [tupelo.string :as ts]
+    [tupelo.forest.xml :as xml]))
+
+(dotest
+  (let [xml-str  "<foo>
+                    <name>John</name>
+                    <address>1 hacker way</address>
+                    <phone></phone>
+                    <school>
+                        <name>Joe</name>
+                        <state>CA</state>
+                        <type>FOOBAR</type>
+                    </school>
+                    <college>
+                        <name>mit</name>
+                        <address></address>
+                        <state>Denial</state>
+                    </college>
+                  </foo> "
+
+        xml-data (xml/parse (ts/string->stream xml-str)) ]
+    (is (= xml-data
+          [{:tag   :foo,
+            :attrs nil,
+            :content
+             [ "\n                    "
+              {:tag :name, :attrs nil, :content ["John"]}
+              "\n                    "
+              {:tag :address, :attrs nil, :content ["1 hacker way"]}
+              "\n                    "
+              {:tag :phone, :attrs nil, :content nil}
+              "\n                    "
+              {:tag   :school,
+               :attrs nil,
+               :content
+                ["\n                        "
+                 {:tag :name, :attrs nil, :content ["Joe"]}
+                 "\n                        "
+                 {:tag :state, :attrs nil, :content ["CA"]}
+                 "\n                        "
+                 {:tag :type, :attrs nil, :content ["FOOBAR"]}
+                 "\n                    "]}
+              "\n                    "
+              {:tag   :college,
+               :attrs nil,
+               :content
+                ["\n                        "
+                 {:tag :name, :attrs nil, :content ["mit"]}
+                 "\n                        "
+                 {:tag :address, :attrs nil, :content nil}
+                 "\n                        "
+                 {:tag :state, :attrs nil, :content ["Denial"]}
+                 "\n                    "]}
+              "\n                  "]}])) ))
+


-0 is nonsensical for bigints

-0 is nonsensical for bigints

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/'


remove autopay namespace

remove autopay namespace

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/'


EquipmentSetup mapping

EquipmentSetup mapping

Well, that was easy

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-v3-migration.git/'


Adds a test for multiconsumption.

Adds a test for multiconsumption.

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

--- test/onyx/peer/multi_peer_test.clj
+++ test/onyx/peer/multi_peer_test.clj
@@ -0,0 +1,122 @@
+(ns onyx.coordinator.multi-peer-test
+  (:require [midje.sweet :refer :all]
+            [onyx.api])
+  (:import [org.hornetq.api.core.client HornetQClient]
+           [org.hornetq.api.core TransportConfiguration HornetQQueueExistsException]
+           [org.hornetq.core.remoting.impl.netty NettyConnectorFactory]))
+
+(def in-queue (str (java.util.UUID/randomUUID)))
+
+(def out-queue (str (java.util.UUID/randomUUID)))
+
+(def tc (TransportConfiguration. (.getName NettyConnectorFactory)))
+
+(def locator (HornetQClient/createServerLocatorWithoutHA (into-array [tc])))
+
+(def session-factory (.createSessionFactory locator))
+
+(def session (.createTransactedSession session-factory))
+
+(.start session)
+
+(.createQueue session in-queue in-queue true)
+
+(.createQueue session out-queue out-queue true)
+
+(def producer (.createProducer session in-queue))
+
+(doseq [n (range 10)]
+  (let [message (.createMessage session true)]
+    (.writeString (.getBodyBuffer message) (pr-str {:n n}))
+    (.send producer message)))
+
+(def sentinel (.createMessage session true))
+(.writeString (.getBodyBuffer sentinel) (pr-str :done))
+(.send producer sentinel)
+
+(.commit session)
+(.close producer)
+(.close session)
+
+(defn my-inc [{:keys [n] :as segment}]
+  (assoc segment :n (inc n)))
+
+(def catalog
+  [{:onyx/name :in
+    :onyx/direction :input
+    :onyx/consumption :concurrent
+    :onyx/type :queue
+    :onyx/medium :hornetq
+    :hornetq/queue-name in-queue
+    :hornetq/host "localhost"
+    :hornetq/port 5445
+    :hornetq/batch-size 2
+    :hornetq/timeout 50}
+   {:onyx/name :inc
+    :onyx/fn :onyx.coordinator.single-peer-test/my-inc
+    :onyx/type :transformer
+    :onyx/consumption :concurrent
+    :onyx/batch-size 2
+    :onyx/timeout 50}
+   {:onyx/name :out
+    :onyx/direction :output
+    :onyx/consumption :concurrent
+    :onyx/type :queue
+    :onyx/medium :hornetq
+    :hornetq/queue-name out-queue
+    :hornetq/host "localhost"
+    :hornetq/port 5445
+    :hornetq/batch-size 2
+    :hornetq/timeout 50}])
+
+(def workflow {:in {:inc :out}})
+
+(def id (str (java.util.UUID/randomUUID)))
+
+(def coord-opts {:datomic-uri (str "datomic:mem://" id)
+                 :hornetq-addr "localhost:5445"
+                 :zk-addr "127.0.0.1:2181"
+                 :onyx-id id
+                 :revoke-delay 2000})
+
+(def conn (onyx.api/connect (str "onyx:mem//localhost/" id) coord-opts))
+
+(def peer-opts {:hornetq-addr "localhost:5445"
+                :zk-addr "127.0.0.1:2181"
+                :onyx-id id})
+
+(def v-peers (onyx.api/start-peers conn 2 peer-opts))
+
+(onyx.api/submit-job conn {:catalog catalog :workflow workflow})
+
+(def session (.createTransactedSession session-factory))
+
+(.start session)
+
+(def consumer (.createConsumer session out-queue))
+
+(def results (atom []))
+
+(doseq [n (range 11)]
+  (let [message (.receive consumer)]
+    (.acknowledge message)
+    (swap! results conj (read-string (.readString (.getBodyBuffer message))))))
+
+(.commit session)
+(.close producer)
+(.close session)
+
+(try
+  ;; (dorun (map deref (map :runner v-peers)))
+  (finally
+   (doseq [v-peer v-peers]
+     (try
+       ((:shutdown-fn v-peer))
+       (catch Exception e (prn e))))
+   (try
+     (onyx.api/shutdown conn)
+     (catch Exception e (prn e)))))
+
+(let [expected-ns (vec (map (fn [x] {:n x}) (range 1 11)))]
+  (fact (into #{} @results) => (into #{} (conj expected-ns :done))))
+


add CSS color values specs

add CSS color values specs

error: pathspec 'src/cljss/css/colors.clj' did not match any file(s) known to git

--- src/cljss/css/colors.clj
+++ src/cljss/css/colors.clj
@@ -0,0 +1,130 @@
+(ns cljss.css.colors
+  (:require [clojure.spec.alpha :as s]))
+
+;;
+;; Keyword colors
+;;
+
+(s/def ::keyword-colors
+  #{:current-color :transparent
+    :aquamarine :lime :deepskyblue :darksalmon :antiquewhite
+    :mediumturquoise :slategrey :slategray :sienna :orange :navajowhite
+    :lavenderblush :firebrick :orangered :palevioletred :lawngreen
+    :seashell :lightpink :darkolivegreen :aliceblue :gray :lightsteelblue
+    :whitesmoke :darkgoldenrod :tan :bisque :white :lightgreen
+    :darkseagreen :crimson :darkslategray :mistyrose :chocolate :yellow
+    :cadetblue :navy :ghostwhite :dimgrey :seagreen :green
+    :mediumseagreen :indigo :olivedrab :cyan :peachpuff :limegreen
+    :mediumslateblue :violet :sandybrown :yellowgreen :mediumspringgreen
+    :steelblue :rosybrown :cornflowerblue :ivory :lightgoldenrodyellow
+    :salmon :darkcyan :peru :cornsilk :lightslategray :blueviolet
+    :forestgreen :lightseagreen :gold :gainsboro :darkorchid :burlywood
+    :lightskyblue :chartreuse :snow :moccasin :honeydew :aqua :darkred
+    :mediumorchid :lightsalmon :saddlebrown :wheat :springgreen
+    :lightslategrey :darkblue :powderblue :turquoise :blanchedalmond
+    :papayawhip :slateblue :lightblue :skyblue :red :lightyellow :blue
+    :palegreen :greenyellow :khaki :maroon :darkgrey :midnightblue
+    :floralwhite :deeppink :paleturquoise :darkkhaki :azure :indianred
+    :darkviolet :mediumpurple :fuchsia :coral :mediumvioletred
+    :lemonchiffon :mediumblue :darkmagenta :goldenrod :darkorange :orchid
+    :plum :pink :teal :magenta :lightgrey :purple :dodgerblue
+    :darkturquoise :mintcream :hotpink :thistle :royalblue :darkgreen
+    :darkslateblue :silver :darkgray :grey :oldlace :mediumaquamarine
+    :brown :lightgray :olive :lightcoral :tomato :lightcyan :linen
+    :darkslategrey :lavender :dimgray :palegoldenrod :beige :black})
+
+;;
+;; RGB(A) colors
+;;
+
+(s/def ::rgb-range
+  (s/cat
+    :value
+    (s/and
+      number?
+      #(s/int-in-range? 0 256 %))))
+
+(s/def ::percentage
+  (s/cat
+    :value (s/and
+             number?
+             #(s/int-in-range? 0 101 %))
+    :unit #{:%}))
+
+(s/def ::numeric-percentage
+  (s/alt
+    :numeric ::rgb-range
+    :percentage (s/spec ::percentage)))
+
+(s/def ::alpha-channel
+  (s/cat
+    :numeric
+    (s/cat
+      :value
+      (s/and
+        number?
+        float?
+        #(>= % 0)
+        #(<= % 1)))))
+
+(s/def ::rgba
+  (s/cat
+    :tag #{:rgb}
+    :red ::numeric-percentage
+    :green ::numeric-percentage
+    :blue ::numeric-percentage
+    :alpha (s/? ::alpha-channel)))
+
+;;
+;; HSL(A) colors
+;;
+
+(s/def ::angle
+  (s/cat
+    :value
+    (s/and
+      number?
+      #(s/int-in-range? 0 361 %))))
+
+(s/def ::angle-percentage
+  (s/alt
+    :numeric ::angle
+    :percentage (s/spec ::percentage)))
+
+(s/def ::hsla
+  (s/cat
+    :tag #{:hsl}
+    :hue ::angle-percentage
+    :saturation ::angle-percentage
+    :lightness ::angle-percentage
+    :alpha (s/? ::alpha-channel)))
+
+;;
+;; HEX colors
+;;
+
+(s/def ::hex-chars
+  #{\a \b \c \d \e \f \0 \1 \2 \3 \4 \5 \6 \7 \8 \9})
+
+(s/def ::hex
+  (s/cat
+    :tag #{:hex}
+    :value
+    (s/and
+      (s/conformer seq)
+      (s/+ ::hex-chars)
+      (s/conformer #(apply str %)))))
+
+;;
+;; Generic CSS Color spec
+;;
+
+(s/def ::color
+  (s/or
+    :keyword ::keyword-colors
+    :rgba ::rgba
+    :hsla ::hsla
+    :hex ::hex))
+
+(comment
+  (s/conform ::color [:hex "242424"]))


fixes for mailing subscribed columne

fixes for mailing subscribed columne

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-mail-works.git/'


backup

backup

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/clojure-ml/cml.git/'


when applying multiple settings, if a value is set to nil treat it as a delete.

--- src/metabase/models/setting.clj
+++ src/metabase/models/setting.clj
@@ -81,6 +81,14 @@
   (swap! cached-setting->value assoc k v)
   v)

+(defn delete
+  "Delete a `Setting`."
+  [k]
+  {:pre [(keyword? k)]}
+  (restore-cache-if-needed)
+  (swap! cached-setting->value dissoc k)
+  (del Setting :key (name k)))
+
 (defn set-all
   "Set the value of a `Setting`.

@@ -88,16 +96,10 @@
   [settings]
   {:pre [(map? settings)]}
   (doseq [k (keys settings)]
-    (set k (clojure.core/get settings k)))
+    (if-let [v (clojure.core/get settings k)]
+      (set k v)
+      (delete k)))
   settings)
-
-(defn delete
-  "Delete a `Setting`."
-  [k]
-  {:pre [(keyword? k)]}
-  (restore-cache-if-needed)
-  (swap! cached-setting->value dissoc k)
-  (del Setting :key (name k)))

 ;; ## DEFSETTING


fix determination of autopay on/off

fix determination of autopay on/off


Moved base data page functions from frxm into dragon.

error: pathspec 'src/dragon/data/page.clj' did not match any file(s) known to git

--- src/dragon/data/page.clj
+++ src/dragon/data/page.clj
@@ -0,0 +1,103 @@
+(ns dragon.data.page
+  (:require
+    [clojure.java.io :as io]
+    [clojure.string :as string]
+    [dragon.blog.content.block :as block]
+    [dragon.blog.core :as blog]
+    [dragon.blog.tags :as blog-tags]
+    [dragon.config.core :as config]
+    [markdown.core :as markdown]
+    [taoensso.timbre :as log]))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;   Constants & Helper Functions   ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defn resource-content
+  [resource-filename]
+  (->> resource-filename
+       (io/resource)
+       (slurp)))
+
+(defn markdown-content
+  [md-filename]
+  (->> md-filename
+       (str "markdown/")
+       (resource-content)
+       (markdown/md-to-html-string)))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;   Base Data Functions   ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defn posts-stats
+  [posts]
+  {:posts (count posts)
+   :authors (->> posts
+                 (map :author)
+                 set
+                 count)
+   :lines (->> posts
+               (map :line-count)
+               (reduce +))
+   :words (->> posts
+               (map :word-count)
+               (reduce +))
+   :chars (->> posts
+               (map :char-count)
+               (reduce +))})
+
+(defn base
+  ([]
+    (base {}))
+  ([opts]
+    {:page-data {
+       :base-path "/blog"
+       :site-title (:site-title opts)
+       :site-description (:site-description opts)
+       :index "index"
+       :about "about"
+       :community "community"
+       :archives "archives"
+       :categories "categories"
+       :tags "tags"
+       :authors "authors"
+       :active (:category-key opts)}}))
+
+(defn default-content-opts
+  []
+  {:title ""
+   :subtitle ""
+   :category-key ""
+   :base-data-fn base
+   :content-filename ""
+   :content-fn (constantly nil)})
+
+(defn default-data-content-opts
+  []
+  (assoc (default-content-opts) :content-fn identity))
+
+(defn default-resource-content-opts
+  []
+  (assoc (default-content-opts) :content-fn resource-content))
+
+(defn default-markdown-content-opts
+  []
+  (assoc (default-content-opts) :content-fn markdown-content))
+
+(defn common
+  [posts additional-opts]
+  (let [opts (merge (default-content-opts) additional-opts)
+        base-data-fn (:base-data-fn opts)
+        content-fn (:content-fn opts)
+        content-filename (:content-filename opts)]
+    (-> opts
+        (base-data-fn)
+        (assoc-in [:page-data :active] (name (:category-key opts)))
+        (dissoc :title :subtitle)
+        (assoc :posts-data posts
+               :posts-stats (posts-stats posts)
+               :content {
+                 :title (:title opts)
+                 :subtitle (:subtitle opts)
+                 :body (content-fn content-filename)}))))


CMR-1022: Added collection platform characteristics and sensor technique to umm.

error: pathspec 'umm-lib/src/cmr/umm/echo10/collection/characteristic.clj' did not match any file(s) known to git

--- umm-lib/src/cmr/umm/echo10/collection/characteristic.clj
+++ umm-lib/src/cmr/umm/echo10/collection/characteristic.clj
@@ -0,0 +1,35 @@
+(ns cmr.umm.echo10.collection.characteristic
+  (:require [clojure.data.xml :as x]
+            [cmr.common.xml :as cx]
+            [cmr.umm.collection :as c]
+            [cmr.umm.echo10.collection.sensor :as sensor]))
+
+(defn xml-elem->Characteristic
+  [char-elem]
+  (let [name (cx/string-at-path char-elem [:Name])
+        description (cx/string-at-path char-elem [:Description])
+        data-type (cx/string-at-path char-elem [:DataType])
+        unit (cx/string-at-path char-elem [:Unit])
+        value (cx/string-at-path char-elem [:Value])]
+    (c/->Characteristic name description data-type unit value)))
+
+(defn xml-elem->Characteristics
+  [platform-element]
+  (seq (map xml-elem->Characteristic
+            (cx/elements-at-path
+              platform-element
+              [:Characteristics :Characteristic]))))
+
+(defn generate-characteristics
+  [characteristics]
+  (when-not (empty? characteristics)
+    (x/element
+      :Characteristics {}
+      (for [characteristic characteristics]
+        (let [{:keys [name description data-type unit value]} characteristic]
+          (x/element :Characteristic {}
+                     (x/element :Name {} name)
+                     (x/element :Description {} description)
+                     (x/element :DataType {} data-type)
+                     (x/element :Unit {} unit)
+                     (x/element :Value {} value)))))))


log GET params when logging API call

log GET params when logging API call

--- src/metabase/middleware/log_api_call.clj
+++ src/metabase/middleware/log_api_call.clj
@@ -56,8 +56,10 @@
   (and (>= (count uri) 4)
        (= (.substring uri 0 4) "/api")))

-(defn- log-request [{:keys [uri request-method body]}]
-  (log/debug (color/blue (format "%s %s " (.toUpperCase (name request-method)) uri)
+(defn- log-request [{:keys [uri request-method body query-string]}]
+  (log/debug (color/blue (format "%s %s " (.toUpperCase (name request-method)) (str uri
+                                                                                (when-not (empty? query-string)
+                                                                                (str "?" query-string))))
                          (when (or (string? body) (coll? body))
                            (str "\n" (with-out-str (pprint (scrub-sensitive-fields body))))))))


Add failing test for latest release when there are multiple.

--- test/clojars/test/unit/routes/api.clj
+++ test/clojars/test/unit/routes/api.clj
@@ -21,6 +21,14 @@
     (is (= 1 (count jars)))
     (is (= "0.1.0" (:latest_release (first jars))))
     (is (= "0.1.0" (:latest_version (first jars))))))
+
+(deftest latest-release
+  (add-jar 0 "0.1.0")
+  (add-jar 1 "0.2.0")
+  (let [jars (api/jars-by-groupname jarname)]
+    (is (= 1 (count jars)))
+    (is (= "0.2.0" (:latest_release (first jars))))
+    (is (= "0.2.0" (:latest_version (first jars))))))

 (deftest only-snapshot
   (add-jar 0 "0.1.0-SNAPSHOT")


Expand webjar resource tests

Expand webjar resource tests

Expanded to handle non-existant paths under webjar path in new-webjar-resource. Also added testing
of webjars-route-pair function.

--- bundles/default/test/yada/webjar_resource_test.clj
+++ bundles/default/test/yada/webjar_resource_test.clj
@@ -4,7 +4,7 @@
   (:require
    [clojure.java.io :as io]
    [clojure.test :refer [deftest is]]
-   [yada.resources.webjar-resource :refer [new-webjar-resource]]
+   [yada.resources.webjar-resource :refer [new-webjar-resource webjars-route-pair]]
    [yada.test :as test]))

 (deftest bootstrap-test
@@ -15,4 +15,13 @@
                                      :get "/less/"))))
     (is (= expected
            (:body (test/response-for ["" (new-webjar-resource "bootstrap")]
-                                     :get "/less/close.less"))))))
+                                     :get "/less/close.less"))))
+    (is (= 404
+           (:status (test/response-for ["" (new-webjar-resource "bootstrap")]
+                                       :get "/non/existant/path"))))
+    (is (= expected
+           (:body (test/response-for (webjars-route-pair)
+                                     :get "/bootstrap/less/close.less"))))
+    (is (= 404
+           (:status (test/response-for (webjars-route-pair)
+                                       :get "/bootstrap/non/existant/path"))))))


Fixes context

Fixes context

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/'


Missing file

Missing file

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

--- src/circle/globals.clj
+++ src/circle/globals.clj
@@ -0,0 +1,5 @@
+(ns circle.globals)
+
+(def ^:dynamic *current-build-url* nil)
+(def ^:dynamic *current-build-number* nil)
+


Add favicon.

Add favicon.

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/jagtalon/what-the-fuck-do-you-want-to-listen-to.git/'


Don't order by version in SQL, UUID is not alphabetic

--- src/main/clojure/pdok/featured/timeline.clj
+++ src/main/clojure/pdok/featured/timeline.clj
@@ -104,7 +104,7 @@
   (str "SELECT DISTINCT ON (feature_id) feature_id, feature"
        " FROM " (qualified-timeline dataset collection)
        " WHERE feature_id in (" (clojure.string/join "," (repeat n "?")) ")"
-       " ORDER BY feature_id ASC, version DESC, valid_from DESC"))
+       " ORDER BY feature_id ASC, valid_from DESC"))

 (defn- load-current-feature-cache [tx dataset collection ids]
   (try


added main card game logic

added main card game logic

error: pathspec 'src/main/clj/clojure_club/stateful_apps/brockturner/labyrinth.clj' did not match any file(s) known to git

--- src/main/clj/clojure_club/stateful_apps/brockturner/labyrinth.clj
+++ src/main/clj/clojure_club/stateful_apps/brockturner/labyrinth.clj
@@ -0,0 +1,228 @@
+(ns clojure-club.stateful-apps.brockturner.labyrinth
+  (:require [clojure.string :as str]))
+
+(def colors [:red :green :blue :tan])
+
+
+(defn make-cards [type number]
+  (reduce (fn [r c]
+            (concat r (repeat number
+                              {:type type :color c})))
+          [] colors))
+
+
+(defn make-base-deck []
+  (concat
+   (make-cards :key 3)
+   (make-cards :moon 4)
+   (repeat 9 {:type :sun :color :red})
+   (repeat 8 {:type :sun :color :blue})
+   (repeat 7 {:type :sun :color :green})
+   (repeat 6 {:type :sun :color :tan})))
+
+
+(defn setup-game []
+  (let [deck (shuffle (make-base-deck))]
+    {:deck (->> deck
+                (drop 5)
+                (concat (repeat 10 {:type :nightmare})
+                        (make-cards :door 2))
+                shuffle)
+     :hand (take 5 deck)
+     :limbo []
+     :discard []
+     :labyrinth []
+     :doors []
+     :resolve nil}))
+
+
+(defn pretty-card [card]
+  (->> (keep card [:color :type])
+       (map name)
+       (str/join " ")))
+
+(defn pick-one [options]
+  (doseq [{:keys [i label]} options]
+    (println "<" i "> -" label))
+  (let [p (str/upper-case (read-line))]
+    (if (= p "EXIT")
+      (constantly nil)
+      (or (first (filter #(= p (:i %)) options))
+          (do (println "Invalid input.")
+            (recur options))))))
+
+
+(defn remove-first [card lst]
+  (concat (take-while #(not= card %) lst)
+          (rest (drop-while #(not= card %) lst))))
+
+
+(defn discard-from-hand [state card]
+  (-> state
+      (update :hand (partial remove-first card))
+      (update :discard conj card)))
+
+(defmulti resolve-card (comp :type :resolve))
+
+(defmethod resolve-card :nightmare [{resolve :resolve :as state}]
+  (some-> state
+          ((:fn (pick-one
+                 (concat
+                  (->> state
+                       :hand
+                       (filter #(= :key (:type %)))
+                       distinct
+                       (map-indexed
+                        (fn [i c]
+                          {:i (str "K" (inc i))
+                           :fn #(discard-from-hand % c)
+                           :label (str "Discard " (pretty-card c) " card from hand")})))
+                  (->> state
+                       :doors
+                       distinct
+                       (map-indexed
+                        (fn [i c]
+                          {:i (str "D" (inc i))
+                           :fn (fn [state]
+                                 (-> state
+                                     (update :doors (partial remove-first c))
+                                     (update :limbo conj c)))
+                           :label (str "Send captured " (pretty-card c) " card to limbo")})))
+                  [{:i "C"
+                    :fn (fn [state]
+                          (let [cards (take 5 (:deck state))]
+                            (-> state
+                                (update :discard concat (remove (comp #{:door :nightmare} :type) cards) [resolve])
+                                (update :limbo concat (filter (comp #{:door :nightmare} :type) cards))
+                                (update :deck (partial drop 5))
+                                (dissoc :resolve))))
+                    :label "Discard 5 cards from deck"}
+                   {:i "H"
+                    :fn (fn [state]
+                          (-> state
+                              (update :discard concat (:hand state))
+                              (assoc :hand [])))
+                    :label "Discard current hand"}]))))
+          (update :discard conj resolve)
+          (dissoc :resolve)))
+
+(defmethod resolve-card :door [{{r-color :color :as resolve} :resolve :as state}]
+  (if-let [key-op (->> state
+                       :hand
+                       (filter #(and (= :key (:type %))
+                                     (= r-color (:color %))))
+                       (some (fn [c]
+                               {:i "K"
+                                :fn (fn [state]
+                                      (-> state
+                                          (update :hand (partial remove-first c))
+                                          (update :discard conj c)
+                                          (update :doors conj resolve)
+                                          (dissoc :resolve)))
+                                :label (str "discard " (-> c :color name) " key card to capture door")})))]
+    ((:fn (pick-one
+           [key-op
+            {:i "I"
+             :fn (fn [state]
+                   (-> state
+                       (update :limbo conj resolve)
+                       (dissoc :resolve)))
+             :label "Ignore door card"}]))
+     state)
+    (-> state
+        (update :limbo conj resolve)
+        (dissoc :resolve))))
+
+
+(defn draw-card [{[card] :deck :as state}]
+  (if card
+    (let [state (update state :deck rest)]
+      (println "You draw a " (pretty-card card) " card")
+      (if (#{:door :nightmare} (:type card))
+        (assoc state :resolve card)
+        (update state :hand conj card)))
+    (println "You lose.")))
+
+
+(defn obtain-door [state color]
+  (let [card {:type :door :color color}]
+    (println "You acquire a " (pretty-card card) " card")
+    (if (->> (concat (:deck state)
+                     (:limbo state))
+             (filter #(= card %))
+             seq)
+      (-> state
+          (update :deck (partial remove-first card))
+          (update :doors conj card))
+      state)))
+
+(defn found-door? [state]
+  (let [color (-> state
+                  :deck
+                  last
+                  :color)]
+    (-> state
+        :deck
+        reverse
+        (->> (take-while #(= color (:color %))))
+        count
+        (mod 3)
+        (= 0))))
+
+(defn add-to-labyrinth [state card]
+  (let [state (-> state
+                  (update :hand (partial remove-first card))
+                  (update :labyrinth conj card))]
+    (if (found-door? state)
+      (obtain-door state)
+      state)))
+
+(defn play-card [state]
+  (println "Labyrinth:")
+  (->> state
+       :labyrinth
+       (map pretty-card)
+       (str/join ", ")
+       println)
+  ((:fn (pick-one
+         (concat
+          (->> state
+               :hand
+               (remove #(-> state :labyrinth last :type (= (:type %))))
+               distinct
+               (map-indexed
+                (fn [i c]
+                  {:i (str "P" (inc i))
+                   :fn #(add-to-labyrinth % c)
+                   :label (str "Play " (pretty-card c) " card from hand")})))
+          (->> state
+               :hand
+               distinct
+               (map-indexed
+                (fn [i c]
+                  {:i (str "D" (inc i))
+                   :fn #(discard-from-hand % c) ;; prophecy
+                   :label (str "Discard " (pretty-card c) " card from hand")}))))))
+   state))
+
+
+(defn shuffle-limbo [state]
+  (println "Shuffling limbo cards back into the deck.")
+  (-> state
+      (update :deck (comp shuffle concat) (:limbo state))
+      (assoc :limbo [])))
+
+
+(defn game-step [state]
+  (cond
+    (-> state :doors count (= 8)) (println "You win!")
+    (:resolve state) (resolve-card state)
+    (-> state :hand count (< 5)) (draw-card state)
+    (-> state :limbo seq) (shuffle-limbo state)
+    :else (play-card state)))
+
+
+(defn play-game []
+  (->> (setup-game)
+       (iterate game-step)
+       (take-while identity)))


try svg

try svg

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/jeelabs/jet.git/'


restlet/status_service_dev.clj: added from v4

error: pathspec 'src/org/altlaw/util/restlet/status_service_dev.clj' did not match any file(s) known to git

--- src/org/altlaw/util/restlet/status_service_dev.clj
+++ src/org/altlaw/util/restlet/status_service_dev.clj
@@ -0,0 +1,18 @@
+(ns org.altlaw.util.restlet.status-service-dev
+  (:gen-class :extends org.restlet.service.StatusService)
+  (:import (org.restlet.data Status MediaType)
+           (org.restlet.resource StringRepresentation)))
+
+(defn -getRepresentation [this status request response]
+  (when (.isError status)
+    (StringRepresentation.
+     (with-out-str
+       (print "HTTP" (.getCode status) (.getName status) "\n\n")
+       (print (.getDescription status) "\n\n")
+       (println "Request Method:  " (.getName (.getMethod request)))
+       (println "Original Request:" (str (.getOriginalRef request)))
+       (println "Target Resource: " (str (.getResourceRef request)))
+       (println "Client Accepted Media Types:" (pr-str (.getAcceptedMediaTypes (.getClientInfo request))))
+       (when-let [t (.getThrowable status)]
+         (.printStackTrace t (java.io.PrintWriter. *out*))))
+     MediaType/TEXT_PLAIN)))


don't sort events in tests; add nested crams test

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/'


Update handler.clj

Update handler.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/yokalona/threen.git/'


[WM] refer all vote-tomorrow symbols in test ns

Now that we no longer have an `update` fn, no need for the alias.

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/'


Fixes to newly added tests; updates to other tests


dropped intermediate datoms -> rel conversion

--- src/datascript/query.cljs
+++ src/datascript/query.cljs
@@ -6,32 +6,27 @@

 (defrecord Context [rels sources])
 ;; attrs:
-;;    [?e ?v ?e2 ?age]
+;;    {?e 0, ?v 1} or {?e2 "a", ?age "v"}
 ;; tuples:
-;;   [ #js [1 "Ivan" 5 14]
-;;     #js [2 "Oleg" 1 55]
-;;     ... ]
+;;    [ #js [1 "Ivan" 5 14] ... ]
+;; or [ (Datom. 2 "Oleg" 1 55) ... ]
 (defrecord Relation [attrs tuples])

-(defn intersect-keys [a1 a2]
-  (set/intersection (set a1)) (set a2))
+(defn intersect-keys [attrs1 attrs2]
+  (set/intersection (set (keys attrs1))
+                    (set (keys attrs2))))

 (defn concatv [& xs]
   (vec (apply concat xs)))

-(defn index [coll]
-  (map vector coll (range)))
-
-(defn index-map [coll]
-  (into {} (index coll)))
-
 (defn tuple-key-fn [idxs]
-  (if (== (alength idxs) 1)
+  (if (== (count idxs) 1)
     (let [idx (first idxs)]
       (fn [tuple]
         (aget tuple idx)))
-    (fn [tuple]
-      (list* (.map idxs #(aget tuple %))))))
+    (let [idxs (to-array idxs)]
+      (fn [tuple]
+        (list* (.map idxs #(aget tuple %))))))) ;; FIXME aget

 (defn hash-attrs [idxs tuples]
   (let [key-fn (tuple-key-fn idxs)]
@@ -43,34 +38,33 @@
                  (assoc! hash-table key (conj (get hash-table key '()) tuple))))
         (persistent! hash-table)))))

-(defn join-tuples [t1 t2 idxs2]
-  (let [l1  (alength t1)
-        l2  (count idxs2)
+(defn join-tuples [t1 idxs1 t2 idxs2]
+  (let [l1  (alength idxs1)
+        l2  (alength idxs2)
         res (js/Array. (+ l1 l2))]
     (dotimes [i l1]
-      (aset res i (aget t1 i)))
+      (aset res i (aget t1 (aget idxs1 i)))) ;; FIXME aget
     (dotimes [i l2]
-      (aset res (+ l1 i) (aget t2 (nth idxs2 i))))
+      (aset res (+ l1 i) (aget t2 (aget idxs2 i)))) ;; FIXME aget
     res))

 (defn hash-join [rel1 rel2]
 ;;  (.time js/console "hash-join")
-  (let [[rel1 rel2]   (if (< (count (:tuples rel1)) (count (:tuples rel2))) [rel1 rel2] [rel2 rel1])
+  (let [;; [rel1 rel2]   (if (< (count (:tuples rel1)) (count (:tuples rel2))) [rel1 rel2] [rel2 rel1])
         tuples1       (:tuples rel1)
         tuples2       (:tuples rel2)
-        attrs1-map    (index-map (:attrs rel1))
-        attrs2-map    (index-map (:attrs rel2))
-        common-attrs  (vec (set/intersection (set (keys attrs1-map)) (set (keys attrs2-map))))
-        common-idxs1  (to-array (map attrs1-map common-attrs))
-        common-idxs2  (to-array (map attrs2-map common-attrs))
-        keep-attrs+idx2 (->> attrs2-map
-                             (remove (fn [[a i]] (contains? attrs1-map a)))
-                             (sort-by second))
-        keep-attrs2   (mapv first keep-attrs+idx2)
-        keep-idxs2    (mapv second keep-attrs+idx2)
+        attrs1        (:attrs rel1)
+        attrs2        (:attrs rel2)
+        common-attrs  (vec (intersect-keys (:attrs rel1) (:attrs rel2)))
+        common-idxs1  (map attrs1 common-attrs)
+        common-idxs2  (map attrs2 common-attrs)
+        keep-attrs1   (keys attrs1)
+        keep-attrs2   (vec (set/difference (set (keys attrs2)) (set (keys attrs1))))
+        keep-idxs1    (to-array (map attrs1 keep-attrs1))
+        keep-idxs2    (to-array (map attrs2 keep-attrs2))

 ;;        _             (.time js/console "hash-attrs")
-        hash          (hash-attrs common-idxs1 (:tuples rel1))
+        hash          (hash-attrs common-idxs1 tuples1)
 ;;        _             (.timeEnd js/console "hash-attrs")

 ;;        _             (.time js/console "new-tuples")
@@ -81,7 +75,7 @@
                                   (let [key (key-fn tuple2)]
                                     (if-let [tuples1 (get hash key)]
                                       (reduce (fn [acc tuple1]
-                                                (conj! acc (join-tuples tuple1 tuple2 keep-idxs2)))
+                                                (conj! acc (join-tuples tuple1 keep-idxs1 tuple2 keep-idxs2)))
                                               acc tuples1)
                                       acc)))
                           (transient []) tuples2)
@@ -89,15 +83,16 @@
 ;;        _             (.timeEnd js/console "new-tuples")
         ]
 ;;    (.timeEnd js/console "hash-join")
-    (Relation. (concatv (:attrs rel1) keep-attrs2)
+    (Relation. (into {}
+                     (map vector (concat keep-attrs1 keep-attrs2) (range)))
                new-tuples)))

-(hash-join (Relation. '[?e ?a ?v]
+#_(hash-join (Relation. '{?e 0 ?a 1 ?v 2}
                       [#js [1 :name "Ivan"]
                        #js [2 :name "Igor"]
                        #js [3 :name "Petr"]])
-           (Relation. '[?e ?a2 ?v2]
+           (Relation. '{?e 0 ?a2 1 ?v2 2}
                       [#js [1 :age 15]
                        #js [3 :age 25]]))

@@ -115,12 +110,11 @@
 (defn build-relation-db [db pattern]
   (let [search-pattern (mapv #(if (symbol? %) nil %) pattern)
         datoms         (d/-search db search-pattern)
-        attr+prop      (->> (map vector pattern ["e" "a" "v" "t"])
+        attr->prop     (->> (map vector pattern ["e" "a" "v" "t"])
                             (filter (fn [[s _]] (and (symbol? s)
-                                                     (not= '_ s)))))
-        props          (to-array (map second attr+prop))]
-    (Relation. (mapv first attr+prop)
-               (mapv (fn [el] (.map props #(aget el %))) datoms))))
+                                                     (not= '_ s))))
+                            (into {}))]
+    (Relation. attr->prop (vec datoms))))

 #_(build-relation-db (-> (d/empty-db)
                        (d/with [[:db/add 1 :name "Ivan"]
@@ -131,12 +125,11 @@

 (defn build-relation-coll [coll pattern]
   (let [data       (filter #(match-pattern pattern %) coll)
-        attr+idx   (->> (map vector pattern (range))
+        attr->idx  (->> (map vector pattern (range))
                         (filter (fn [[s _]] (and (symbol? s)
-                                                 (not= '_ s)))))
-        idxs       (to-array (map second attr+idx))]
-    (Relation. (mapv first attr+idx)
-               (mapv (fn [el] (.map idxs #(nth el %))) data))))
+                                                 (not= '_ s))))
+                        (into {}))]
+    (Relation. attr->idx (map to-array data)))) ;; FIXME to-array

 (defn build-relation [source pattern]
   (cond
@@ -167,24 +160,32 @@
 ;;    (.timeEnd js/console "search/-q")
     res))

-(defn -collect [acc rels symbols]
-;;  (.time js/console "search/-collect")
-  (if-let [rel (first rels)]
-    (let [attr->idx (index-map (:attrs rel))
-          idxs (->> symbols
-                    (map attr->idx)
-                    (remove nil?)
-                    vec)]
-      (if (empty? idxs)
-        (recur acc (next rels) symbols)
-        (recur (for [t1 acc
-                     t2 (:tuples rel)]
-                 (join-tuples t1 t2 idxs))
-               (next rels)
-               symbols)))
-    (do
-;;      (.timeEnd js/console "search/-collect")
-      (set (map vec acc)))))
+(defn -collect
+  ([context symbols]
+    ;;  (.time js/console "search/-collect")
+    (let [symbols-map (into {} (map vector symbols (range)))
+          rels        (:rels context)
+          data        (-collect [(make-array (count symbols))] rels symbols-map)
+          res         (set (map vec data))]
+      ;;      (.timeEnd js/console "search/-collect")
+      res))
+  ([acc rels symbols-map]
+    (if-let [rel (first rels)]
+      (let [keep-attrs (vec (intersect-keys (:attrs rel) symbols-map))]
+        (if (empty? keep-attrs)
+          (recur acc (next rels) symbols-map)
+          (let [idxs-map (mapv #(array ((:attrs rel) %) (symbols-map %)) keep-attrs)]
+            (recur (for [t1 acc
+                         t2 (:tuples rel)]
+                     (let [res (.slice t1 0)] ;; clone
+                       (doseq [idxs idxs-map
+                               :let [from (aget idxs 0)
+                                     to   (aget idxs 1)]]
+                         (aset res to (aget t2 from)))
+                       res))
+                   (next rels)
+                   symbols-map))))
+      acc)))

 #_(-q {'$ [[1 :name "Ivan" 42]
          [1 :age  15 34]
@@ -198,7 +199,7 @@
   (let [context (-q {'$ db}
                     '[[$ ?e :name "Ivan"]
                       [$ ?e :age ?a]])
-        res (-collect [#js[]] (:rels context) '[?e ?a])]
+        res (-collect context '[?e ?a])]
 ;;    (.timeEnd js/console "search")
     res))

@@ -207,31 +208,9 @@
             (d/with [ [:db/add 1 :name "Ivan"]
                       [:db/add 1 :age  15]
                       [:db/add 2 :name "Petr"]
-                      [:db/add 2 :age  34]])))
-
-;; (defn -search2 [db a1 v1 a2]
-;;   (let [rel-e (slice (.-avet db)
-;;                      (Datom. nil a1 v1 nil nil))
-;;         hash1 (hash-attr #(.-e %) rel-e)
-;;         rel-a (slice (.-aevt db)
-;;                      (Datom. (:min hash1) a2 nil nil nil)
-;;                      (Datom. (:max hash1) a2 nil nil nil))]
-;;     (hash-join [#(.-e %)] hash1 rel-a #(.-e %) [#(.-v %)])))
-
-;; (defn search2 [db] (-search2 db :name "Ivan" :age))
-
-;; (defn -search3 [db a1 v1 a2]
-;;   (let [rel-e (slice (.-avet db)
-;;                      (Datom. nil a1 v1 nil nil))
-;;         min   (.-e (first rel-e))
-;;         rel-a (slice (.-aevt db)
-;;                      (Datom. min a2 nil nil nil)
-;;                      (Datom. nil a2 nil nil nil))]
-;;     (sort-join rel-e #(.-e %) [#(.-e %)]
-;;                rel-a #(.-e %) [#(.-v %)])))
-
-;; (defn search3 [db] (-search3 db :name "Ivan" :age))
-
+                      [:db/add 2 :age  34]
+                      [:db/add 3 :name "Ivan"]
+                      [:db/add 3 :age  22]])))

 (defn in? [vector el]
   (>= (.indexOf vector el) 0))
@@ -245,62 +224,3 @@
        (not (in? vars symbol))))

-;; (defn -q-clause [where vars data]
-;;   (let [bound   (filter #(bound? % vars) where)
-;;         unbound (filter #(unbound? % vars) where)
-;;         bound-vals (into {} (for [var bound]
-;;                               [var (build-var var data)]))]
-;;     ...
-
-;; (defn -q [ins->sources where vars data])
-
-
-;; (defn q [query & sources]
-;;   (-q (zipmap (:in query '[$]) sources)
-;;       (:where query)
-;;       [] []))
-
-;; (defn aconj [arr x]
-;;   (datascript.btset/insert arr (alength arr) #js [x]))
-
-
-
-;; (defn get-avet [db a v]
-;;   (->> (slice (.-avet db) (Datom. nil a v nil nil))
-;;        (mapv #(vector (.-e %)))))
-
-;; (defn get-aevt [db a es]
-;;   (let [lookup-hash (hash-attr #(nth % 0) es)
-;;         lookup-map  (:hash-table lookup-hash)
-;; ;;                     {:min (aget (first es) 0)
-;; ;;                      :max (aget (nth es (dec (count es))) 0)}
-;;         datoms      (slice (.-aevt db)
-;;                       (Datom. (:min lookup-hash) a nil nil nil)
-;;                       (Datom. (:max lookup-hash) a nil nil nil))]
-;;     (->>
-;; ;;       (loop [_res (transient [])
-;; ;;              _ds  datoms
-;; ;;              _es  es]
-;; ;;         (let [_fd (first _ds)
-;; ;;               _fe (first _es)]
-;; ;;           (if (and _fd _fe)
-;; ;;             (condp == (cmp-val (.-e _fd) (aget _fe 0))
-;; ;;               0  (recur (conj! _res #js [(aget _fe 0) (.-v _fd)]) (next _ds) (next _es))
-;; ;;               -1 (recur _res (next _ds) _es)
-;; ;;               1  (recur _res _ds (next _es))
-;; ;;               )
-;; ;;             _res)))
-
-;;       (reduce (fn [acc d]
-;;                 (if-let [datas (get lookup-map (.-e d))]
-;;                   (reduce (fn [acc data]
-;;                             (conj! acc (conj data (.-v d))))
-;;                     acc datas)
-;;                   acc))
-;;         (transient []) datoms)
-;;       (persistent!))))
-
-;; (defn search [db]
-;;   (->> (get-avet db :name "Ivan")
-;;        (get-aevt db :age)))
-


Add a dummy page to make clojurecup.com checks happy :)

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/f0086/clojurecup2014-luduverse.git/'


Use transact-async to avoid arbitrary timeouts

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/'


Add user_uuid to TeamMembership schema

Add user_uuid to TeamMembership schema


Initial work on the cljs api.

Initial work on the cljs api.

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

--- src/decimal/core.cljs
+++ src/decimal/core.cljs
@@ -0,0 +1,312 @@
+(ns decimal.core
+  (:require [decimal.extern.decimaljs])
+  (:refer-clojure :exclude [> >= < <= neg? pos? integer? zero? / - + *]))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Constants & Config
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(def ^:static +decimal+ (js/Decimal.noConflict))
+(def ^:dynamic *decimal* +decimal+)
+
+(defn config!
+  "Set the global configuration for the decimal constructor.
+
+  Possible options:
+
+  - `precision`: the maximum number of significant digits of
+    the result of an operation (integer 1 to 1e+9 inclusive,
+    default: 20).
+  - `rounding`: the default rounding mode used when rounding
+    the result of an operation (integer 0 to 8 inclusive,
+  - `modulo`: he modulo mode used when calculating the modulus: `a mod n`.
+    (integer, 0 to 9 inclusive, default 1
+
+  **Rounding modes**
+
+  Rounding modes 0 to 6 (inclusive) are the same as those of Java's
+  BigDecimal class.
+
+  Property         | Value | Description
+  -----------------|-------|------------
+  ROUND_UP         | 0     | Rounds away from zero
+  ROUND_DOWN       | 1     | Rounds towards zero
+  ROUND_CEIL       | 2     | Rounds towards Infinity
+  ROUND_FLOOR      | 3     | Rounds towards -Infinity
+  ROUND_HALF_UP    | 4     | Rounds towards nearest neighbour. If equidistant, rounds away from zero
+  ROUND_HALF_DOWN  | 5     | Rounds towards nearest neighbour. If equidistant, rounds towards zero
+  ROUND_HALF_EVEN  | 6     | Rounds towards nearest neighbour. If equidistant, rounds towards even neighbour
+  ROUND_HALF_CEIL  | 7     | Rounds towards nearest neighbour. If equidistant, rounds towards Infinity
+  ROUND_HALF_FLOOR | 8     | Rounds towards nearest neighbour. If equidistant, rounds towards -Infinity
+  EUCLID           | 9     | Not a rounding mode, see modulo
+
+  **Modulo modes**
+
+  The modes that are most commonly used for the modulus/remainder operation
+  are shown in the following table. Although the other rounding modes can be used,
+  they may not give useful results.
+
+  Property         | Value | Description
+  -----------------|-------|------------
+  ROUND_UP         | 0     | The remainder is positive if the dividend is negative, else is negative
+  ROUND_DOWN       | 1     | The remainder has the same sign as the dividend. This uses truncating division and matches the behaviour of JavaScript's remainder operator %.
+  ROUND_FLOOR      | 3     | The remainder has the same sign as the divisor. (This matches Python's % operator)
+  ROUND_HALF_EVEN  | 6     | The IEEE 754 remainder function
+  EUCLID           | 9     | The remainder is always positive.
+
+  **Other options**
+
+  The underlying library supports more options that and this
+  function also accepts. You can read more about here:
+  http://mikemcl.github.io/decimal.js/#Dconfig"
+  [{:keys [precision rounding modulo] :as options}]
+  (.config +decimal+ (clj->js options))
+  nil)
+
+(defn config
+  "The same as `config` but returns an constructor
+  of decimals that can be used for create new instances
+  with provided configuration."
+  [options]
+  (.clone +decimal+ (clj->js options)))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Protocols & Constructor
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defprotocol IDecimal
+  (-decimal [v] "return a decimal instance."))
+
+(defn decimal
+  "Create a new Decimal instance from `v` value."
+  [v]
+  (-decimal v))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Predicates
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+
+(defn ^boolean decimal?
+  "Return true if `v` is a instance of Decimal."
+  [v]
+  (instance? +decimal+ v))
+
+(defn ^boolean finite?
+  "Returns true if the value of this Decimal is a finite
+  number, otherwise returns false.
+  The only possible non-finite values of a Decimal are
+  NaN, Infinity and -Infinity."
+  [v]
+  (.isFinite v))
+
+(defn ^boolean integer?
+  "Returns true if the value of this Decimal is a whole
+  number, otherwise returns false."
+  [v]
+  (.isInteger v))
+
+(defn ^boolean NaN?
+  "Returns true if the value of this Decimal is NaN,
+  otherwise returns false."
+  [v]
+  (.isNaN v))
+
+(defn ^boolean neg?
+  "Returns true if the value of this Decimal is negative,
+  otherwise returns false."
+  [v]
+  (.isNegative v))
+
+(defn ^boolean pos?
+  "Returns true if the value of this Decimal is negative,
+  otherwise returns false."
+  [v]
+  (.isPositive v))
+
+(defn ^boolean zero?
+  "Returns true if the value of this Decimal is zero or
+  minus zero, otherwise returns false."
+  [v]
+  (.isZero v))
+
+(defn ^boolean <
+  "Returns true if the value of this Decimal is less than
+  the value of x, otherwise returns false."
+  ([v x]
+   (.lt v x))
+  ([v x & more]
+   (if (< v x)
+     (if (next more)
+       (recur x (first more) (next more))
+       (< x (first more)))
+     false)))
+
+(defn ^boolean <=
+  "Returns true if the value of this Decimal is less than
+  or equal to the value of x, otherwise returns false."
+  ([v x]
+   (.lte v x))
+  ([v x & more]
+   (if (<= v x)
+     (if (next more)
+       (recur x (first more) (next more))
+       (<= x (first more)))
+     false)))
+
+(defn ^boolean >
+  "Returns true if the value of this Decimal is greater than
+  the value of x, otherwise returns false."
+  ([v x]
+   (.ge v x))
+  ([v x & more]
+   (if (> v x)
+     (if (next more)
+       (recur x (first more) (next more))
+       (> x (first more)))
+     false)))
+
+(defn ^boolean >=
+  "Returns true if the value of this Decimal is greater than
+  or equal to the value of x, otherwise returns false."
+  ([v x]
+   (.ge v x))
+  ([v x & more]
+   (if (>= v x)
+     (if (next more)
+       (recur x (first more) (next more))
+       (>= x (first more)))
+     false)))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Operations
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defn plus
+  "Returns a new Decimal whose value is the value of this
+  Decimal plus x, rounded to significant digits."
+  [v x]
+  (.plus v x))
+
+(defn minus
+  "Returns a new Decimal whose value is the value of this
+  Decimal minus x, rounded to significant digits."
+  [v x]
+  (.minus v x))
+
+(defn mul
+  "Returns a new Decimal whose value is the value of this
+  Decimal times x, rounded to significant digits using."
+  [v x]
+  (.times v x))
+
+(defn div
+  "Returns a new Decimal whose value is the value of this
+  Decimal divided by x, rounded to significant digits."
+  [v x]
+  (.div v x))
+
+(defn div'
+  "Return a new Decimal whose value is the integer part
+  of dividing this Decimal by x, rounded to significant digits."
+  [v x]
+  (.divToInt v x))
+
+;; Aliases
+
+(def / div)
+(def + plus)
+(def - minus)
+(def * mul)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Math
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defn floor
+  "Returns a new Decimal whose value is the value of this Decimal
+  rounded to a whole number in the direction of negative Infinity."
+  [v]
+  (.floor v))
+
+(defn ceil
+  "Returns a new Decimal whose value is the value of this Decimal
+  rounded to a whole number in the direction of positive Infinity."
+  [v]
+  (.ceil v))
+
+(defn round
+  "Returns a new Decimal whose value is the value of this Decimal
+  rounded to a whole number.
+  To emulate Math.round, set rounding to 7 (or :round/hanf-ceil)."
+  [v]
+  (.round v))
+
+(defn abs
+  "Returns a new Decimal whose value is the absolute value, i.e.
+  the magnitude, of the value of this Decimal."
+  [v]
+  (.absoluteValue v))
+
+(defn sin
+  "Returns a new Decimal whose value is the sine of the value
+  in radians of this Decimal."
+  [v]
+  (.sine v))
+
+(defn cos
+  "Returns a new Decimal whose value is the cosine of the value
+  in radians of this Decimal."
+  [v]
+  (.cosine v))
+
+(defn tan
+  "Returns a new Decimal whose value is the tangent of the value
+  in radians of this Decimal."
+  [v]
+  (.tangent v))
+
+(defn cbrt
+  "Returns a new Decimal whose value is the cube root of this Decimal."
+  [v]
+  (.cubeRoot v))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Protocols
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(extend-type +decimal+
+  cljs.core/IEquiv
+  (-equiv [v other]
+    (.eq v other))
+
+  cljs.core/ICloneable
+  (-clone [v]
+    (let [t *decimal*]
+      (t. v)))
+
+  cljs.core/IPrintWithWriter
+  (-pr-writer [mv writer _]
+    (cljs.core/-write writer "#decimal ")
+    (cljs.core/-write writer (.toString mv)))
+
+  cljs.core/IDeref
+  (-deref [v]
+    (.toNumber v))
+
+  IComparable
+  (-compare [v other]
+    (println "akakkaka")
+    (.comparedTo v other)))
+
+(extend-protocol IDecimal
+  +decimal+
+  (-decimal [v] v)
+
+  string
+  (-decimal [v]
+    (*decimal*. v))
+
+  number
+  (-decimal [v]
+    (*decimal*. v)))


add expose headers

add expose headers

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/fhirbase/fhirplace.git/'


memorie-inca nu e gata

memorie-inca nu e gata

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/kokosro/kokos-crawler.git/'


test fix

test fix

--- lein_tasks/leiningen/webpack.clj
+++ lein_tasks/leiningen/webpack.clj
@@ -5,8 +5,8 @@
 (defn webpack [projects & args]
   ;; TODO - some better validations such as checking that we have webpack available
   (println "Running `webpack -p` to assemble and minify frontend assets")
-  (let [result (sh (str (:root projects) "/node_modules/webpack/bin/webpack.js") (when-not (System/getenv "CI_DISABLE_WEBPACK_MINIFICATION")
-                                                                                "-p"))]
+  (let [result (sh (str (:root projects) "/node_modules/webpack/bin/webpack.js") (if (System/getenv "CI_DISABLE_WEBPACK_MINIFICATION") ""
+                                                                                "-p"))]
     (if (= 0 (:exit result))
       (println (:out result))
       (println (:err result)))))


gogokoak etiketak gehitu

gogokoak etiketak gehitu

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/lnmnd/magnet.zer.git/'


formatting

formatting

--- labs/architecture-examples/om/src/todomvc/app.cljs
+++ labs/architecture-examples/om/src/todomvc/app.cljs
@@ -56,12 +56,12 @@
         (into-array
           (map #(om/build item/todo-item app
                   {:path [:todos %] :opts opts :key :id
-                    :fn (fn [todo]
-                          (cond-> todo
-                            (= (:id todo) (:editing opts))
-                            (assoc :editing true)
-                            (not (visible? todo showing))
-                            (assoc :hidden true)))})
+                   :fn (fn [todo]
+                         (cond-> todo
+                           (= (:id todo) (:editing opts))
+                           (assoc :editing true)
+                           (not (visible? todo showing))
+                           (assoc :hidden true)))})
             (range (count (:todos app)))))))))

 (defn footer [{:keys [showing todos]} opts]


Allow optional body (#151)

Allow optional body (#151)

* allow optional body

looks like schema validation further down the interceptor chain takes care of it, so
we don't need to be so strict here, and allow an empty body to go through in this place.

* approach 2: in the absence of a body, if resource declares a body schema, check if it allows nil

--- src/yada/interceptors.clj
+++ src/yada/interceptors.clj
@@ -11,6 +11,7 @@
    [manifold.stream :as stream]
    ring.util.time
    [schema.utils :refer [error?]]
+   [schema.core :as s]
    [yada.body :as body]
    [yada.charset :as charset]
    [yada.cookies :as cookies]
@@ -182,10 +183,12 @@
             ctx)))

       ;; else
-      (if (get-in ctx [:resource :methods (:method ctx) :parameters :body])
-        (d/error-deferred
-           (ex-info "No body present but body is expected for request."
-                    {:status 400}))
+      (if-let [body-schema (get-in ctx [:resource :methods (:method ctx) :parameters :body])]
+        (if (s/check body-schema nil)
+          (d/error-deferred
+             (ex-info "No body present but body is expected for request."
+                      {:status 400}))
+          ctx)
         ctx))))

 (defn select-representation


Add namespace for macros.

Add namespace for macros.

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

--- src/decimal/core.clj
+++ src/decimal/core.clj
@@ -0,0 +1,7 @@
+(ns decimal.core)
+
+(defmacro with-config
+  [config & body]
+  `(let [type# (decimal.core/config ~config)]
+     (binding [decimal.core/*decimal* type#]
+       ~@body)))


Optimization of db-spec

Optimization of db-spec

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/couragelabs/coachbot.git/'


bidea main-ean hasieratu

bidea main-ean hasieratu

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/lnmnd/magnet.bez.git/'


Update copy in choose date

Update copy in choose date

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/'


ideas for rest

ideas for rest

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

--- src/clj/algorithms_clj/rest_router.clj
+++ src/clj/algorithms_clj/rest_router.clj
@@ -0,0 +1,20 @@
+(ns algorithms-clj.rest-router)
+
+(defn user-by-name
+  [path-params query-params]
+  )
+
+(defn get-all-users
+  [path-params query-params]
+  )
+
+(def route
+  {:path ["user" :name] :get user-by-name})
+
+;; Something like this could be used to make expression template
+#_(comp (path "user") (capture :name) (get user-by-name))
+#_(comp (path "user") (path "all") (get get-all-users))
+#_(comp (path "user") (combine
+                        (comp (path "all") (get get-all-users))
+                        (comp (capture :name) (get user-by-name))
+                        ))


Fixed github url

Fixed github url

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/nidu/whydoyouwannakillme.git/'


palendromic

palendromic

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/tlight/project-euler.git/'


remove unused imports

remove unused imports

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/JetBrains/imperative-nodejs.git/'


update to new api

update to new api

--- labs/architecture-examples/om/src/todomvc/item.cljs
+++ labs/architecture-examples/om/src/todomvc/item.cljs
@@ -13,7 +13,7 @@
 ;; Todo Item

 (defn handle-submit [e todo {:keys [owner comm]}]
-  (let [edit-text (dom/get-state owner :edit-text)
+  (let [edit-text (dom/get-state owner [:edit-text])
         val (.trim edit-text)]
     (if-not (string/blank? val)
       (go
@@ -29,17 +29,17 @@
       (>! comm [:edit todo])
       (.focus node)
       (.setSelectionRange node (.. node -value -length) (.. node -value -length))
-      (dom/set-state! owner :edit-text (:title todo)))))
+      (dom/set-state! owner [:edit-text] (:title todo)))))

 (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))
+      (dom/set-state! owner [:edit-text] (:title todo))
       (if (identical? kc ENTER_KEY)
         (handle-submit e todo opts)))))

 (defn handle-change [e todo owner]
-  (dom/set-state! owner :edit-text (.. e -target -value)))
+  (dom/set-state! owner [:edit-text] (.. e -target -value)))

 (defn todo-item [{:keys [id title editing completed] :as todo} {:keys [comm]}]
   (reify
@@ -61,7 +61,7 @@
             (dom/button #js {:className "destroy"
                              :onClick (fn [_] (put! comm [:destroy todo]))}))
           (dom/input #js {:ref "editField" :className "edit"
-                          :value (dom/get-state owner :edit-text)
+                          :value (dom/get-state owner [:edit-text])
                           :onBlur #(handle-submit % todo m)
                           :onChange #(handle-change % todo owner)
                           :onKeyDown #(handle-key-down % todo m)}))))))


06-candy-factory: A straightforward Clojure solution.

error: pathspec '06-candy-factory/tf-06.clj' did not match any file(s) known to git

--- 06-candy-factory/tf-06.clj
+++ 06-candy-factory/tf-06.clj
@@ -0,0 +1,46 @@
+":";exec java -cp "$HOME/.m2/repository/org/clojure/clojure/1.5.1/clojure-1.5.1.jar" clojure.main $0 $*
+
+; Sort of a hack; Clojure isn't really intended as a scripting language. :-/
+
+(require '[clojure.string :refer [split]]
+         '[clojure.java.io :refer [reader]]
+         '[clojure.pprint :refer [pprint]])
+
+(defn stopwords
+  "Reads a set of comma-separated stopwords from the given filename."
+  [file]
+  (-> file
+      slurp
+      (split #"\s+,\s+")
+      set))
+
+(defn words
+  "Splits a string into a sequence of words."
+  [string]
+  (clojure.string/split string #"[^a-zA-Z]+"))
+
+(defn normalize
+  "Normalizes split words to terms."
+  [word]
+  (.toLowerCase word))
+
+(defn too-short?
+  "Is a word too short for consideration?"
+  [word]
+  (<= (.length word) 2))
+
+; Lazily split the file into lines, explode lines into words, normalize into
+; terms, reject unsuitable candidates, compute frequencies, and take the top
+; 25.
+(with-open [f (reader "../pride-and-prejudice.txt")]
+  (->> f
+       line-seq
+       (mapcat words)
+       (map normalize)
+       (remove too-short?)
+       (remove (stopwords "../stop_words.txt"))
+       frequencies
+       (sort-by second)
+       reverse
+       (take 25)
+       pprint))


refactor promise version of task1

refactor promise version of task1


reprocess->ts only at the td step in the warp factory chain

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/transwarp.git/'


fix handle-edit

fix handle-edit

--- labs/architecture-examples/om/src/todomvc/item.cljs
+++ labs/architecture-examples/om/src/todomvc/item.cljs
@@ -22,10 +22,11 @@
     false))

 (defn handle-edit [e todo {:keys [owner chans]}]
-  (put! (:on-edit chans) todo)
-  (let [node (dom/get-node owner "editField")]
-    (.focus node)
-    (.setSelectionRange (.. node -value -length) (.. node -value -length)))
+  (go
+    (>! (:edit chans) todo)
+    (let [node (dom/get-node owner "editField")]
+      (.focus node)
+      (.setSelectionRange (.. node -value -length) (.. node -value -length))))
   (om/replace! todo :edit-text (:title todo)))

 (defn handle-key-down [e todo opts]


Made app work with latest instaparse.

Made app work with latest instaparse.


lib.zerol.core-tests - engine-side-effects-events tests added

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/artemyarulin/zerol.git/'


Unit namespace added to create a light weight component like schema.

error: pathspec 'src/clj/hellhound/units/core.clj' did not match any file(s) known to git

--- src/clj/hellhound/units/core.clj
+++ src/clj/hellhound/units/core.clj
@@ -0,0 +1,166 @@
+(ns hellhound.units.core
+  "Unit is the same concept as components")
+
+;; Main storage for system data.
+(def ^:private default-system (atom {}))
+
+;; Protocols --------------------------------------
+(defprotocol Structure
+  "This protocol defines the structure of each unit"
+  (start [unit])
+  (stop  [unit]))
+
+;; Private Functions -------------------------------
+(declare get-system-entry start-unit)
+
+(defn- throw-exception
+  [& rest]
+  (throw (Exception. (apply format rest))))
+
+(defn- started?
+  "Returns true if unit already started"
+  [unit-data]
+  (:started? unit-data))
+
+(defn- update-started-system
+  "Update the system with the given started unit data"
+  [system name unit]
+  (let [sys (update-in system [:units name :record] (fn [_] unit))]
+    (update-in sys [:units name :started?] (fn [_] true))))
+
+(defn- update-stopped-system
+  "Update the system with the given sopped unit data"
+  [system name unit]
+  (let [sys (update-in system [:units name :record] (fn [_] unit))]
+    (update-in sys [:units name :started?] (fn [_] false))))
+
+
+(defn- extract-output-of
+  [unit-name]
+  (let [unit (get-system-entry unit-name)]
+
+    (if-not (started? unit)
+      (throw-exception "Unit '%s' is not started yet." unit-name))
+
+    (let [input (:output (:record unit))]
+      (if (nil? input)
+        (throw-exception "Unit '%s' does not provide an :output."
+                         unit-name))
+      input)))
+
+(defn- gather-inputs
+  "Gather all the inputs for the given unit name from the provided list of
+  input units"
+  [name]
+  (let [input-names (:inputs (get-system-entry name))]
+    (if (and (not (nil? input-names))
+             (vector? input-names))
+      (map  extract-output-of input-names)
+      [])))
+
+(defn- start-dependencies
+  [{:keys [name data system] :as all}]
+  (let [requirements (or (:requires data) [])
+        record       (:record   data)]
+
+    (if-not (empty? requirements)
+      ;; In case of any requirement we need to start them first
+      (doseq [req-name requirements]
+        (start-unit req-name (get-system-entry req-name) system)))
+    all))
+
+(defn- inject-inputs
+  [{:keys [name data system] :as all}]
+  (let [inputs (gather-inputs name)]
+    (if-not (empty? inputs)
+      (let [new-record   (assoc (:record data) :inputs inputs)
+            new-data     (update-in data [:record] (fn [_] new-record))]
+        {:name name :data new-data :system system})
+      all)))
+
+(defn- run-the-start-method
+  [{:keys [name data system] :as all}]
+  (let [record       (:record data)
+        started-unit (.start record)]
+    ;; Replace the record value with the started instance
+    (swap! system update-started-system name started-unit)
+    (assoc all :system system)))
+
+(defn- start-unit
+  "Start the given unit"
+  [name data system]
+  (let [bundle {:name name :data data :system system}]
+    (if-not (started? data)
+      (-> bundle
+          (start-dependencies)
+          (inject-inputs)
+          (run-the-start-method))
+      bundle)))
+
+(defn- stop-unit
+  "Stop the given unit"
+  [name data system]
+  (if (started? data)
+    (let [requirements (or (:requires data) [])
+          record       (:record   data)]
+      (let [stopped-unit (.stop record)]
+        (swap! system update-stopped-system name stopped-unit))
+
+      (if-not (empty? requirements)
+        (doseq [req-name requirements]
+          (stop-unit req-name (get (:units @system) req-name) system))))))
+
+(defn- iterate-units
+  "Iterate over system units"
+  [system f]
+  (let [units (:units @system)]
+    (doseq [[unit-name unit-data] units]
+      (if (satisfies? Structure (:record unit-data))
+        (do
+          (f unit-name unit-data system))
+        (throw (Exception. (format "'%s' unit does not satisfy the 'Structure' protocol."
+                                   unit-name)))))))
+
+;; Global Functions ---------------------------
+(defn set-system!
+  "Set the default system"
+  [system]
+  (swap! default-system (fn [_] system)))
+
+(defn system
+  []
+  @default-system)
+
+(defn get-system-entry
+  [unit-name]
+  (get (:units (system)) unit-name))
+
+(defn get-unit
+  [unit-name]
+  (:record (get-system-entry unit-name)))
+
+(defn start-system
+  "Start the given system and call start on all the units"
+  [system]
+  (iterate-units system start-unit))
+
+(defn stop-system
+  "Stop the given system by calling stop on all units"
+  [system]
+  (iterate-units system stop-unit))
+
+(defn start
+  "Start the default system"
+  []
+  (start-system default-system))
+
+(defn stop
+  "Stop the default system"
+  []
+  (stop-system default-system))
+
+(defn restart
+  "Restart the default system"
+  []
+  (stop)
+  (start))


start porting the Ixi Lang synths

start porting the Ixi Lang synths

error: pathspec 'src/overtone/synth/ixi.clj' did not match any file(s) known to git

--- src/overtone/synth/ixi.clj
+++ src/overtone/synth/ixi.clj
@@ -0,0 +1,79 @@
+(ns
+    ^{:doc "A port of the synths found in The Thor's The Ixi Lang"
+      :author "Sam Aaron"}
+  overtone.synth.ixi
+  (:use [overtone.core]))
+
+(defsynth impulser
+  [gate 1
+   pan 0
+   amp 1
+   out-bus 0]
+  (let [kill-env (env-gen:ar (adsr 0.0000001 1 0.2) gate :action FREE)
+        imp      (impulse:ar 1)
+        x        (* (pan2 (* imp (env-gen:ar (perc 0.0000001 0.2))) pan)
+                    amp)]
+    (out out-bus (leak-dc (limiter x)))))
+
+(defsynth kick
+  [mod-freq 2.6
+   mod-index 5
+   sustain 0.4
+   beater-noise-level 0.025
+   pan 0
+   amp 0.3
+   out-bus 0]
+  (let [freq               80
+        pitch-contour      (line:kr (* freq 2) freq 0.02)
+        drum-osc           (pm-osc pitch-contour mod-freq (/ mod-index 1.3))
+        drum-lpf           (lpf drum-osc 1000)
+        drum-env           (* drum-lpf
+                              (env-gen:ar (perc 0.005 sustain) 1 :action FREE))
+        beater-source      (* (white-noise) beater-noise-level)
+        beater-hpf         (hpf beater-source 500)
+        lpf-cutoff-contour (line:kr 6000 500 0.03)
+        beater-lpf         (lpf beater-hpf lpf-cutoff-contour)
+        beater-env         (* beater-lpf
+                              (env-gen:ar (perc 0.000001 1) :action FREE))
+        kick-mix           (* (+ drum-env beater-env) 2 amp)]
+    (out out-bus (pan2 kick-mix pan))))
+
+(defsynth kick2
+  [sustain 0.26
+   pan 0
+   amp 0.3
+   out-bus 0]
+  (let [env0  (env-gen:ar
+               (envelope [0.5 1 0.5 0]
+                         [0.005 0.06 sustain]
+                         [-4 -2 -4])
+               :action FREE)
+        env1  (env-gen:ar
+               (envelope [110 59 29]
+                         [0.005 0.29]
+                         [-4 -5]))
+        env1m (midicps env1)
+        son   (+ (lf-pulse:ar env1m 0 0.5 )
+                 -0.5
+                 (white-noise))
+        son   (* (lpf son (* env1m 1.5)) env0)
+        son   (+ son (* (sin-osc env1m 0.5)
+                        env0))
+        son   (* son 1.2)
+        son   (clip2 son 1)]
+    (out out-bus (pan2 (* son amp) pan))))
+
+(defsynth kick3
+  [high 150
+   low 33
+   phase 1.5
+   dur 0.35
+   sustain 0.4
+   pan 0
+   amp 0.3
+   out-bus 0]
+  (let [signal (* amp (sin-osc (x-line:kr high low dur) (* Math/PI phase)))
+        signal (* signal
+                  (env-gen:ar (perc 0.0001 sustain)
+                              :action FREE))]
+    (out out-bus (pan2 signal pan))))


Added helper.clj containing nice stuff.

Added helper.clj containing nice stuff.

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

--- src/helper.clj
+++ src/helper.clj
@@ -0,0 +1,67 @@
+(ns helper)
+
+;;;
+;;; This file contains stuff which I think are great
+;;;
+
+(defmacro one-by-one
+  "Calls a function on each element of a collection.
+   Parameters:
+   coll    _collection of arguments
+   f       _function body that takes one parameter
+   "
+  [coll & f]
+  `(loop [args# ~coll]
+     (if (empty? args#) nil (do (~@f (first args#))
+                                (recur (rest args#))))))
+
+(defmacro lambda
+  "Takes the free argument as first parameter and the function value as
+    following parameters as function body, i.e.
+
+
+     ( lambda (x y) (do (print x) (* x y)) )
+
+    will produce a function that takes 2 parameters, prints the first one
+    and returns the product of them.
+   "
+  [parameter & body]
+  `(fn [~@parameter] ~@body ))
+
+(defmacro rho
+  "Takes an block that defines a function by omitting its last parameter
+    and turns it into a normal function that takes one parameter"
+  [ & body ]
+  `(fn [x#] (~@body x#)))
+
+(defmacro .*.
+  "Takes two functions and returns the covariant function concatenation
+    of them"
+  [ f g ]
+  `(lambda (x#) (~g (~f x#))))
+
+(defmacro *..
+  "Takes some functions and returns the covariant function concatenation
+    of them (n-ary .*.-Operator)"
+  [ f g & more]
+  (if (empty? more) `(.*. ~f ~g)
+      `(f*g ~f (chain ~g ~@more ))))
+
+(defn do-map-tree
+  "Maps a named list tree using the given functions to a new tree structure,
+   utilizing side effects heavily. (This is Java inspired madness....)
+   (A list tree is a tree which nodes are of the form (name child1 child2)
+    (where the childs are optional) such that the whole tree is represented
+    by its root node.)
+
+   Parameters:
+     mk        _function that maps a node name to the new node data structure
+     add       _function that takes as arguments the root and the child node
+                (as side effect!!)
+     tree      _the tree that is mapped"
+  [mk add tree]
+  (let [root (mk (first tree))
+        childs (rest tree)]
+    (do
+      (one-by-one childs (lambda (x) (add root (do-map-tree mk add x))))
+      root )))


Create github API scraper for boyscouting

error: pathspec 'src/clj/made_merits/service/github/boyscouting/scraper.clj' did not match any file(s) known to git

--- src/clj/made_merits/service/github/boyscouting/scraper.clj
+++ src/clj/made_merits/service/github/boyscouting/scraper.clj
@@ -0,0 +1,19 @@
+(ns made-merits.service.github.boyscouting.scraper
+  (:require [made-merits.service.github.boyscouting.detector :as detector]
+            [clj-http.client :as client]
+            [clojure.string :as string]))
+
+(def ^:private repos ["made-merits" "freestuffly"])
+
+(defn- to-url
+  [repo]
+  (str "https://api.github.com/repos/emileswarts/" repo "/pulls?state=closed"))
+
+(def ^:private urls
+  (map to-url repos))
+
+(defn results [] (map
+    (fn [repo]
+      (println (str "processing " repo))
+      (hash-map :project repo :results (detector/detect (:body (client/get (to-url repo))))))
+    repos))


new responsive layout

new responsive layout

error: pathspec 'src/cljs/dashboard_clj/layouts/grid_layout_responsive.cljs' did not match any file(s) known to git

--- src/cljs/dashboard_clj/layouts/grid_layout_responsive.cljs
+++ src/cljs/dashboard_clj/layouts/grid_layout_responsive.cljs
@@ -0,0 +1,41 @@
+(ns dashboard-clj.layouts.grid-layout-responsive
+  (:require [cljsjs.react-grid-layout]
+            [dashboard-clj.layouts.core :as layout-common]
+            [dashboard-clj.widgets.core :as widget-common]
+            [reagent.core :refer [atom] :as r]))
+
+
+
+(def responsive-grid-layout (.-Responsive js/ReactGridLayout))
+(def width-provider (.-WidthProvider js/ReactGridLayout))
+(def responsive-grid-layout-adapter (r/adapt-react-class (width-provider. responsive-grid-layout)))
+
+
+(defn calculate-layout [{:as dashboard :keys [widgets]}]
+  (into {}
+        (for [brp [:lg :md, :sm :xs :xxs]
+              :let [brp-pos
+                    (into [] (for [widget (:widgets dashboard)
+                                   :let [pos (get-in widget [:layout-opts :position brp])]
+                                   :when (not (nil? pos))]
+                               (merge pos {:i (:name widget )})))]
+              :when (not-empty brp-pos)]
+              {brp brp-pos})))
+
+(def default-layout-opts {:className "layout"})
+
+
+(defn widget-wrapper[w]
+  [:div {:key (:name w) :class "widget" :style (:style w)}
+   (widget-common/setup-widget w)])
+
+
+(defmethod layout-common/create-layout :responsive-grid-layout [{:keys[widgets] :as dashboard}]
+  [responsive-grid-layout-adapter
+   (merge default-layout-opts (:layout-opts dashboard) {:layouts(calculate-layout dashboard)})
+   (doall (for [widget  widgets]
+            (widget-wrapper widget)))])
+
+
+
+


A bit of defensive programming here

A bit of defensive programming here

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/screen6/bigquery-clj.git/'


Make Either satisfy Bifunctor

Make Either satisfy Bifunctor

--- src/cats/monad/either.cljc
+++ src/cats/monad/either.cljc
@@ -159,6 +159,12 @@
         (right (f (.-v s)))
         s))

+    p/Bifunctor
+    (-bimap [_ f g s]
+      (if (left? s)
+        (left  (f (.-v s)))
+        (right (g (.-v s)))))
+
     p/Applicative
     (-pure [_ v]
       (right v))


views: list view for units

views: list view for units

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/'


ffirst

ffirst

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/'


Added module for configuration reading

Added module for configuration reading

It is very similar to the one used in my other projects.

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

--- src/ktra_indexer/config.clj
+++ src/ktra_indexer/config.clj
@@ -0,0 +1,21 @@
+(ns ktra-indexer.config
+  (:require [clojure.edn :as edn]))
+
+(defn load-config
+  "Given a filename, load and return a config file."
+  [filename]
+  (edn/read-string (slurp filename)))
+
+(defn get-conf-value
+  "Return a key value from the configuration."
+  [property & [config-key]]
+  (let [config (load-config
+                (clojure.java.io/resource "config.edn"))]
+    (if config-key
+      (config-key (property config))
+      (property config))))
+
+(defn db-conf
+  "Returns the value of the requested database configuration key"
+  [k]
+  (get-conf-value :database k))


The answer file's expression returns the argument provided

Although the answer's file entry worked, it ignored the provided
argument. With this change it returns what was passed to it.  I branched
from master, I hope it can be merged it in.

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/croeder/clojure-koans-work.git/'


Add test for move-ns

Add test for move-ns

error: pathspec 'src/test/clojure/clojure/tools/namespace/move_test.clj' did not match any file(s) known to git

--- src/test/clojure/clojure/tools/namespace/move_test.clj
+++ src/test/clojure/clojure/tools/namespace/move_test.clj
@@ -0,0 +1,72 @@
+(ns clojure.tools.namespace.move-test
+  (:use [clojure.java.io :as io]
+        [clojure.test :only (deftest is)]
+        [clojure.tools.namespace.move :only (move-ns)])
+  (:import (java.io File)))
+
+(defn- create-temp-dir
+  "Creates and returns a new temporary directory java.io.File."
+  [name]
+  (let [temp-file (File/createTempFile name nil)]
+    (.delete temp-file)
+    (.mkdirs temp-file)
+    temp-file))
+
+(def ^:private file-one-contents "
+ (ns com.example.one
+   (:require [com.example.two :as two]
+             [com.example.three :as three]))
+
+ (defn foo []
+   (com.example.a.four/foo))
+")
+
+(def ^:private file-two-contents "
+ (ns com.example.two
+   (:require [com.example.three :as three]
+             [com.example.a.four :as four]))
+")
+
+(def ^:private file-three-contents "
+ (ns com.example.three
+   (:use com.example.five))
+")
+
+(def ^:private file-four-contents "
+ (ns com.example.a.four)
+ (defn foo [] \"foo\")
+")
+
+(deftest t-move-ns
+  (let [temp-dir (create-temp-dir "tools-namespace-t-move-ns")
+        src-dir (io/file temp-dir "src")
+        example-dir (io/file temp-dir "src" "com" "example")
+        file-one (io/file example-dir "one.clj")
+        file-two (io/file example-dir "two.clj")
+        file-three (io/file example-dir "three.clj")
+        old-file-four (io/file example-dir "a" "four.clj")
+        new-file-four (io/file example-dir "b" "four.clj")]
+
+    (.mkdirs (io/file example-dir "a"))
+    (spit file-one file-one-contents)
+    (spit file-two file-two-contents)
+    (spit file-three file-three-contents)
+    (spit old-file-four file-four-contents)
+    (Thread/sleep 1500) ;; ensure file timestamps are different
+
+    (let [file-three-last-modified (.lastModified file-three)]
+
+      (move-ns 'com.example.a.four 'com.example.b.four src-dir [src-dir])
+
+      (is (.exists new-file-four)
+          "new file should exist")
+      (is (not (.exists old-file-four))
+          "old file should not exist")
+      (is (not (.exists (.getParentFile old-file-four)))
+          "old empty directory should not exist")
+      (is (= file-three-last-modified (.lastModified file-three))
+          "unaffected file should not have been modified")
+      (is (not-any? #(.contains (slurp %) "com.example.a.four")
+                    [file-one file-two file-three new-file-four]))
+      (is (every? #(.contains (slurp %) "com.example.b.four")
+                  [file-one file-two new-file-four])))))


Support ssh url for git repos

Support ssh url for git repos

--- src-clj/acha/git_parser.clj
+++ src-clj/acha/git_parser.clj
@@ -12,8 +12,10 @@
            [org.eclipse.jgit.lib ObjectReader]
            [org.eclipse.jgit.api Git]
            [org.eclipse.jgit.revwalk RevWalk RevCommit RevTree]
-           [org.eclipse.jgit.transport FetchResult]
            [org.eclipse.jgit.lib Constants]
+           [com.jcraft.jsch Session JSch]
+           [org.eclipse.jgit.transport FetchResult JschConfigSessionFactory OpenSshConfig$Host SshSessionFactory]
+           [org.eclipse.jgit.util FS]
            [org.eclipse.jgit.treewalk EmptyTreeIterator CanonicalTreeParser AbstractTreeIterator]))

 (defn- data-dir [url]
@@ -27,6 +29,13 @@
         (jgit.p/git-reset repo (.getName (.getObjectId current)) :hard)))
     (catch Exception e
       (logging/error e "Error occured during force pull"))))
+
+
+(def jsch-factory (proxy [JschConfigSessionFactory] []
+  (configure [^OpenSshConfig$Host hc ^Session session]
+    (.getJSch ^JschConfigSessionFactory this hc FS/DETECTED))))
+
+(SshSessionFactory/setInstance jsch-factory)

 (defn load-repo [url]
   (let [path (str (data-dir url) "/repo")]


Documentation only

Documentation only

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/'


Unused require.

Unused require.

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/couragelabs/crispy-tatertot.git/'


Added exception handling to benchmark script.

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/altamiracorp/honeycomb.git/'


Exclude core/read from voting-methods handlers ns

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/voting-method-works.git/'


refactor: add test newsletter preview definition

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/rodrigo-garcia-leon/semanario-universidad-newsletter.git/'


include account with config

include account with config

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/'


get rid of reference to hosted logo

get rid of reference to hosted logo

--- support/src/figwheel/client/heads_up.cljs
+++ support/src/figwheel/client/heads_up.cljs
@@ -62,7 +62,6 @@
                                 "-o-transition: all 0.2s ease-in-out;"
                                 "transition: all 0.2s ease-in-out;"
                                 "font-size: 13px;"
-                                #_"background: url(https://s3.amazonaws.com/bhauman-blog-images/jira-logo-scaled.png) no-repeat 10px 10px;"
                                 "border-top: 1px solid #f5f5f5;"
                                 "box-shadow: 0px 0px 1px #aaaaaa;"
                                 "line-height: 18px;"


Be slightly less hacky about recovering from bad frames

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/terrancesnyder/engulf.git/'


Reorder functions

Reorder functions

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

--- src/gamma_examples/mvp.cljs
+++ src/gamma_examples/mvp.cljs
@@ -0,0 +1,63 @@
+(ns gamma-examples.mvp
+  (:require
+    [gamma-driver.drivers.basic :as driver]
+    [gamma-driver.protocols :as dp]
+    [gamma.program :as p]
+    [gamma.api :as g]
+    [gamma.webgl :as webgl]
+    [thi.ng.geom.core :as geom]
+    [thi.ng.geom.core.matrix :as mat :refer [M44]]
+    [thi.ng.geom.webgl.arrays :as arrays]
+    [thi.ng.geom.basicmesh :as bm]
+    [thi.ng.geom.cuboid :as cuboid]
+    [thi.ng.geom.webgl.core :as tgl]))
+
+
+(defn ->radians [degrees]
+  (/ (* degrees Math/PI) 180))
+
+
+(def pos-attribute (g/attribute "a_Pos" :vec2))
+
+(def pmatrix (g/uniform "u_PerspectiveMatrix" :mat4))
+
+(def tmatrix (g/uniform "u_TriangleMatrix" :mat4))
+
+
+(defn example-program []
+  (p/program
+    {:vertex-shader {(g/gl-position) (g/* pmatrix
+                                          (g/* tmatrix
+                                               (g/vec4 pos-attribute 0 1)))}
+     :fragment-shader {(g/gl-frag-color) (g/vec4 1 0 0 1)}}
+    ))
+
+
+(defn get-position-matrix [v]
+  (apply geom/translate M44 v))
+
+(defn get-perspective-matrix [width height]
+  (mat/perspective 45 (/ width height) 0.1 100.0))
+
+
+(defn example-data []
+  (let [triangle-matrix (geom/rotate-around-axis
+                          (get-position-matrix [-1.5 0.0 -7.0])
+                          [0 1 0]
+                          (->radians 45))
+        perspective-matrix (get-perspective-matrix 500 500)]
+    (driver/normalize-data
+      {pos-attribute [[0 0.5] [-0.5 -0.5] [0.5 -0.5]]
+       tmatrix       (arrays/float32 triangle-matrix)
+       pmatrix       (arrays/float32 perspective-matrix)})))
+
+(defn example-driver []
+  (driver/basic-driver
+    (.getContext (.getElementById js/document "gl-canvas") "webgl")))
+
+
+(defn draw-example []
+  (let [d (example-driver)
+        p (dp/program d (example-program))]
+    (driver/draw-program d p (example-data))
+    {:program p :driver d}))