egoera-espero salbuespenen egoerak egiaztatzeko


Added the set of euclidean orbifold invariants within a clojure namespace.

error: pathspec 'clojure/org/gavrog/clojure/euclideanInvariants.clj' did not match any file(s) known to git


[EN WR] Bind user create events correctly.

I did it wrong before.

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


Add dependency graph library

Add dependency graph library

Adapted from Lazytest by Stuart Sierra. I give my permission to
release this code under the Clojure Contributor Agreement.

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

--- src/main/clojure/clojure/tools/namespace/dependency.clj
+++ src/main/clojure/clojure/tools/namespace/dependency.clj
@@ -0,0 +1,123 @@
+(ns clojure.tools.namespace.dependency
+  "Bidirectional graphs of dependencies and dependent objects."
+  (:require [clojure.set :as set]))
+
+(defprotocol DependencyGraph
+  (immediate-dependencies [graph key]
+    "Returns the set of immediate dependencies of key.")
+  (immediate-dependents [graph key]
+    "Returns the set of immediate dependents of key.")
+  (transitive-dependencies [graph key]
+    "Returns the set of all things which key depends on, directly or
+    transitively.")
+  (transitive-dependents [graph key]
+    "Returns the set of all things which depend upon key, directly or
+    transitively."))
+
+(defprotocol DependencyGraphUpdate
+  (depend [graph key dep]
+    "Returns a new graph with a dependency from key to dep (\"key depends
+    on dep\"). Forbids circular dependencies.")
+  (remove-all [graph key]
+    "Returns a new dependency graph with all references to key removed.")
+  (remove-key [graph key]
+    "Removes the key from the dependency graph without removing it as a
+    dependency of other keys."))
+
+(defn- remove-from-map [amap x]
+  (reduce (fn [m [k vs]]
+	    (assoc m k (disj vs x)))
+	  {} (dissoc amap x)))
+
+(defn- transitive
+  "Recursively expands the set of dependency relationships starting
+  at (get m x)"
+  [m x]
+  (reduce (fn [s k]
+	    (set/union s (transitive m k)))
+	  (get m x) (get m x)))
+
+(declare depends?)
+
+(deftype MapDependencyGraph [dependencies dependents]
+  DependencyGraph
+  (immediate-dependencies [graph key]
+    (get dependencies key #{}))
+  (immediate-dependents [graph key]
+    (get dependents key #{}))
+  (transitive-dependencies [graph key]
+    (transitive dependencies key))
+  (transitive-dependents [graph key]
+    (transitive dependents key))
+  DependencyGraphUpdate
+  (depend [graph key dep]
+    (when (depends? graph dep key)
+      (throw (Exception.
+              (str "Circular dependency between "
+                   (pr-str key) " and " (pr-str dep)))))
+    (MapDependencyGraph.
+     (update-in dependencies [key] set/union #{dep})
+     (update-in dependents [dep] set/union #{key})))
+  (remove-all [graph key]
+    (MapDependencyGraph.
+     (remove-from-map dependencies key)
+     (remove-from-map dependents key)))
+  (remove-key [graph key]
+    (MapDependencyGraph.
+     (dissoc dependencies key)
+     dependents)))
+
+(defn graph "Returns a new, empty, dependency graph." []
+  (->MapDependencyGraph {} {}))
+
+(defn depends?
+  "True if x is directly or transitively dependent on y."
+  [graph x y]
+  (contains? (transitive-dependencies graph x) y))
+
+(defn dependent?
+  "True if y is a dependent of x."
+  [graph x y]
+  (contains? (transitive-dependents graph x) y))
+
+(defn topo-comparator
+  "Returns a comparator which produces a topographical sort based on
+  the dependencies in graph."
+  [graph]
+  (comparator (partial dependent? graph)))
+
+(defn topo-sort
+  "Returns a topographically-sorted sequence of the items in coll
+  using dependencies in graph."
+  [graph coll]
+  (sort (topo-comparator graph) coll))
+
+(defn topo-sort-by
+  "Returns a topographically-sorted sequence of the items in coll by
+  comparing (keyfn item) using dependencies in graph."
+  [graph keyfn coll]
+  (sort-by keyfn (topo-comparator graph) coll))
+
+(comment
+  ;; example usage: building a graph like:
+  ;;
+  ;;       :a
+  ;;      / |
+  ;;    :b  |
+  ;;      \ |
+  ;;       :c
+  ;;        |
+  ;;       :d
+  ;;
+  (def g (-> (graph)
+             (depend :b :a)   ; "B depends on A"
+             (depend :c :b)   ; "C depends on B"
+             (depend :c :a)   ; "C depends on A"
+             (depend :d :c))) ; "D depends on C"
+
+  (transitive-dependencies g :d)
+  ;;=> #{:a :c :b}
+
+  (topo-sort g [:d :a :c :b])
+  ;;=> (:a :b :c :d)
+  )


Add initial data for an om.next parser

Add initial data for an om.next parser

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

--- src/discuss/parser.cljs
+++ src/discuss/parser.cljs
@@ -0,0 +1,26 @@
+(ns discuss.parser
+  (:require [om.next :as om]))
+
+(def init-data {})
+
+;; -----------------------------------------------------------------------------
+;; Parsing
+
+(defmulti read (fn [env key params] key))
+(defmethod read :default
+  [{:keys [state] :as env} key params]
+  (let [st @state]
+    (if-let [[_ value] (find st key)]
+      {:value value}
+      {:value :not-found})))
+
+(defmulti mutate om/dispatch)
+
+
+;; -----------------------------------------------------------------------------
+
+(defonce reconciler
+  (om/reconciler
+   {:state  init-data
+    :parser (om/parser {:read read :mutate mutate})}))
+


when grabbing the admin email, make sure it's an active user.

--- src/metabase/models/setting.clj
+++ src/metabase/models/setting.clj
@@ -165,7 +165,7 @@
                             (or (nil? tracking?) (= "true" tracking?)))
    :site_name             (get :site-name)
    :email_configured      (not (s/blank? (get :email-smtp-host)))
-   :admin_email           (sel :one :field ['User :email] (k/where {:is_superuser true}))})
+   :admin_email           (sel :one :field ['User :email] (k/where {:is_superuser true :is_active true}))})

 ;; # IMPLEMENTATION


Remove channel spec reference on testrunner.

--- test/cats/testrunner.cljx
+++ test/cats/testrunner.cljx
@@ -9,8 +9,7 @@
             [cats.monad.maybe-spec]
             [cats.monad.identity-spec]
             [cats.monad.exception-spec]
-            [cats.monad.continuation-spec]
-            [cats.monad.channel-spec]))
+            [cats.monad.continuation-spec]))

 #+cljs
 (defn main []


Config.boot

Config.boot

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

--- config.boot
+++ config.boot
@@ -0,0 +1,257 @@
+firewall {
+    all-ping enable
+    broadcast-ping disable
+    ipv6-receive-redirects disable
+    ipv6-src-route disable
+    ip-src-route disable
+    log-martians enable
+    options {
+        mss-clamp {
+            mss 1412
+        }
+    }
+    receive-redirects disable
+    send-redirects enable
+    source-validation disable
+    syn-cookies enable
+}
+interfaces {
+    bridge br0 {
+        aging 300
+        hello-time 2
+        max-age 20
+        priority 0
+        promiscuous disable
+        stp false
+    }
+    ethernet eth0 {
+        address 192.168.1.1/24
+        description Local
+        duplex auto
+        speed auto
+    }
+    ethernet eth1 {
+        description "Internet (PPPoE)"
+        duplex auto
+        speed auto
+        vif 835 {
+            address dhcp
+            description FTTH
+            pppoe 0 {
+                default-route auto
+                mtu 1492
+                name-server auto
+                password secret
+                user-id fti/********
+            }
+        }
+        vif 838 {
+            bridge-group {
+                bridge br0
+            }
+            description TV
+        }
+        vif 840 {
+            bridge-group {
+                bridge br0
+            }
+            description TV
+        }
+        vif 851 {
+            address dhcp
+            description TOIP
+        }
+    }
+    ethernet eth2 {
+        address 192.168.2.1/24
+        description "Local 2"
+        duplex auto
+        speed auto
+    }
+    loopback lo {
+    }
+}
+
+protocols {
+    igmp-proxy {
+        interface br0 {
+            alt-subnet 0.0.0.0/0
+            role upstream
+            threshold 1
+        }
+        interface eth0 {
+            alt-subnet 0.0.0.0/0
+            role downstream
+            threshold 1
+        }
+        interface eth2 {
+            alt-subnet 0.0.0.0/0
+            role downstream
+            threshold 1
+        }
+    }
+    static {
+        route 80.10.117.120/31 {
+            next-hop 10.54.56.254 {
+            }
+        }
+        route 81.253.206.0/24 {
+            next-hop 10.54.56.254 {
+            }
+        }
+        route 81.253.210.0/23 {
+            next-hop 10.54.56.254 {
+            }
+        }
+        route 81.253.214.0/23 {
+            next-hop 10.54.56.254 {
+            }
+        }
+        route 172.19.20.0/23 {
+            next-hop 10.54.56.254 {
+            }
+        }
+        route 172.20.224.167/32 {
+            next-hop 10.54.56.254 {
+            }
+        }
+        route 172.23.12.0/22 {
+            next-hop 10.54.56.254 {
+            }
+        }
+        route 193.253.67.88/29 {
+            next-hop 10.54.56.254 {
+            }
+        }
+        route 193.253.153.227/32 {
+            next-hop 10.54.56.254 {
+            }
+        }
+        route 193.253.153.228/32 {
+            next-hop 10.54.56.254 {
+            }
+        }
+    }
+}
+service {
+    dhcp-server {
+        disabled false
+        hostfile-update disable
+        shared-network-name LAN1 {
+            authoritative disable
+            subnet 192.168.1.0/24 {
+                default-router 192.168.1.1
+                dns-server 192.168.1.1
+                lease 86400
+                start 192.168.1.21 {
+                    stop 192.168.1.240
+                }
+            }
+        }
+        shared-network-name LAN2 {
+            authoritative enable
+            subnet 192.168.2.0/24 {
+                default-router 192.168.2.1
+                dns-server 192.168.2.1
+                lease 86400
+                start 192.168.2.21 {
+                    stop 192.168.2.240
+                }
+            }
+        }
+    }
+    dns {
+        forwarding {
+            cache-size 150
+            listen-on eth2
+            listen-on eth0
+        }
+    }
+    gui {
+        https-port 443
+    }
+    nat {
+        rule 5010 {
+            outbound-interface pppoe0
+            type masquerade
+        }
+        rule 5011 {
+            outbound-interface br0
+            type masquerade
+        }
+    }
+    ssh {
+        port 22
+        protocol-version v2
+    }
+    upnp2 {
+        listen-on eth0
+        listen-on eth2
+        nat-pmp enable
+        secure-mode disable
+        wan pppoe0
+    }
+}
+system {
+    config-management {
+        commit-revisions 50
+    }
+    host-name ubnt
+    login {
+        user ubnt {
+            authentication {
+                encrypted-password $1$zKNoUbAo$gomzUbYvgyUMcD436Wo66.
+            }
+            level admin
+        }
+    }
+    ntp {
+        server 0.ubnt.pool.ntp.org {
+        }
+        server 1.ubnt.pool.ntp.org {
+        }
+        server 2.ubnt.pool.ntp.org {
+        }
+        server 3.ubnt.pool.ntp.org {
+        }
+    }
+    offload {
+        ipv4 {
+            forwarding enable
+            pppoe enable
+            vlan disable
+        }
+    }
+    package {
+        repository squeeze {
+            components "main contrib non-free"
+            distribution squeeze
+            password ""
+            url http://http.us.debian.org/debian
+            username ""
+        }
+        repository squeeze-security {
+            components main
+            distribution squeeze/updates
+            password ""
+            url http://security.debian.org
+            username ""
+        }
+    }
+    syslog {
+        global {
+            facility all {
+                level notice
+            }
+            facility protocols {
+                level debug
+            }
+        }
+    }
+    time-zone UTC
+}
+
+
+/* Warning: Do not remove the following line. */
+/* === vyatta-config-version: "config-management@1:conntrack@1:cron@1:dhcp-relay@1:dhcp-server@4:firewall@5:ipsec@3:nat@3:qos@1:quagga@2:system@4:ubnt-pptp@1:ubnt-util@1:vrrp@1:webgui@1:webproxy@1:zone-policy@1" === */
+/* Release version: v1.5.0alpha1.4653508.140328.1720 */


do those primes!

do those primes!

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

--- pcl/chap_08/chap_08.clj
+++ pcl/chap_08/chap_08.clj
@@ -0,0 +1,18 @@
+(clojure/in-ns 'pcl.chap_08)
+(clojure/refer 'clojure)
+
+(defn primep [num]
+  (when (> num 1)
+    (empty? (for [x (range 2 (inc (int (Math/sqrt num)))) :when (zero? (rem num x))] x))))
+
+; why ever do something once, when you can do it infinitely?
+(defn primes-from [number]
+  (filter primep (iterate inc number)))
+
+; new helper function
+(defn primes-in-range [start end]
+  (for [x (primes-from start) :while (<= x end)] x))
+
+; omit the destructuring
+(defmacro do-primes [var start end & body]
+  `(doseq ~var (primes-in-range ~start ~end) ~@body))


java/install options

java/install options

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/jchli/jepsen-aurora.git/'


test fix

test fix

--- test/metabase/test_util.clj
+++ test/metabase/test_util.clj
@@ -33,7 +33,7 @@
 ;;; tests for RPARTIAL

 (expect -3
-  ((rpartial -5) 8))
+  ((rpartial - 5) 8))

 (expect -7
   ((rpartial - 5 10) 8))


Don't need to eval in SQL QP

Don't need to eval in SQL QP

--- src/metabase/driver/generic_sql/query_processor.clj
+++ src/metabase/driver/generic_sql/query_processor.clj
@@ -3,9 +3,10 @@
   (:require [clojure.core.match :refer [match]]
             [clojure.tools.logging :as log]
             [clojure.string :as s]
-            [clojure.walk :as walk]
-            [korma.core :refer :all, :exclude [update]]
-            [korma.sql.utils :as utils]
+            (korma [core :as k]
+                   [db :as kdb])
+            (korma.sql [fns :as kfns]
+                       [utils :as utils])
             [metabase.config :as config]
             [metabase.driver :as driver]
             [metabase.driver.query-processor :as qp]
@@ -21,73 +22,9 @@
                                                       RelativeDateTimeValue
                                                       Value)))

-(declare apply-form
-         log-korma-form)
-
-;; # INTERFACE
-
-
-(def ^:dynamic ^:private *query* nil)
-
-(defn process-structured
-  "Convert QUERY into a korma `select` form, execute it, and annotate the results."
-  [{{:keys [source-table]} :query, database :database, :as query}]
-  (binding [*query* query]
-    (try
-      ;; Process the expanded query and generate a korma form
-      (let [korma-select-form `(select ~'entity ~@(->> (map apply-form (:query query))
-                                                       (filter identity)
-                                                       (mapcat #(if (vector? %) % [%]))))
-            set-timezone-sql  (when-let [timezone (driver/report-timezone)]
-                                (when (seq timezone)
-                                  (let [{:keys [features timezone->set-timezone-sql]} (:driver *query*)]
-                                    (when (contains? features :set-timezone)
-                                      `(exec-raw ~(timezone->set-timezone-sql timezone))))))
-            korma-form        `(let [~'entity (korma-entity ~database ~source-table)]
-                                 ~(if set-timezone-sql `(korma.db/with-db (:db ~'entity)
-                                                          (korma.db/transaction
-                                                           ~set-timezone-sql
-                                                           ~korma-select-form))
-                                      korma-select-form))]
-
-        ;; Log generated korma form
-        (when (config/config-bool :mb-db-logging)
-          (log-korma-form korma-form))
-
-        (eval korma-form))
-
-      (catch java.sql.SQLException e
-        (let [^String message (or (->> (.getMessage e) ; error message comes back like "Error message ... [status-code]" sometimes
-                                       (re-find  #"(?s)(^.*)\s+\[[\d-]+\]$") ; status code isn't useful and makes unit tests hard to write so strip it off
-                                       second) ; (?s) = Pattern.DOTALL - tell regex `.` to match newline characters as well
-                                  (.getMessage e))]
-          (throw (Exception. message)))))))
-
-(defn process-and-run
-  "Process and run a query and return results."
-  [{:keys [type] :as query}]
-  (case (keyword type)
-      :native (native/process-and-run query)
-      :query  (process-structured query)))
-
-
-;; # IMPLEMENTATION
-
-;; ## Query Clause Processors
-
-(defmulti apply-form
-  "Given a Query clause like
-
-    {:aggregation [\"count\"]}
-
-  call the matching implementation which should either return `nil` or translate it into a korma clause like
-
-    (aggregate (count :*) :count)
-
-  An implementation of `apply-form` may optionally return a vector of several forms to insert into the generated korma `select` form."
-  (fn [[clause-name _]] clause-name))
-
-(defmethod apply-form :default [form]) ;; nothing
+(def ^:private ^:dynamic *query* nil)
+
+;;; ## Formatting

 (defprotocol IGenericSQLFormattable
   (formatted [this] [this include-as?]))
@@ -143,48 +80,48 @@
      (formatted this false))
     ([{value :value, {unit :unit} :field} _]
      ;; prevent Clojure from converting this to #inst literal, which is a util.date
-     ((:date (:driver *query*)) unit `(Timestamp/valueOf ~(.toString value)))))
+     ((:date (:driver *query*)) unit value)))

   RelativeDateTimeValue
   (formatted
     ([this]
      (formatted this false))
     ([{:keys [amount unit], {field-unit :unit} :field} _]
-     (let [driver (:driver *query*)]
-       ((:date driver) field-unit (if (zero? amount)
-                                     (sqlfn :NOW)
-                                     ((:date-interval driver) unit amount)))))))
-
-
-(defmethod apply-form :aggregation [[_ {:keys [aggregation-type field]}]]
+     (let [{:keys [date date-interval]} (:driver *query*)]
+       (date field-unit (if (zero? amount)
+                          (k/sqlfn :NOW)
+                          (date-interval unit amount)))))))
+
+
+;;; ## Clause Handlers
+
+(defn- apply-aggregation [korma-query {{:keys [aggregation-type field]} :aggregation}]
   (if-not field
     ;; aggregation clauses w/o a Field
     (case aggregation-type
-      :rows  nil                               ; don't need to do anything special for `rows` - `select` selects all rows by default
-      :count `(aggregate (~'count :*) :count))
+      :rows  korma-query ; don't need to do anything special for `rows` - `select` selects all rows by default
+      :count (k/aggregate korma-query (count :*) :count))
     ;; aggregation clauses with a Field
     (let [field (formatted field)]
       (case aggregation-type
-        :avg      `(aggregate (~'avg ~field) :avg)
-        :count    `(aggregate (~'count ~field) :count)
-        :distinct `(aggregate (~'count (sqlfn :DISTINCT ~field)) :count)
-        :stddev   `(fields [(sqlfn :stddev ~field) :stddev])
-        :sum      `(aggregate (~'sum ~field) :sum)))))
-
-
-(defmethod apply-form :breakout [[_ fields]]
-  `[ ;; Group by all the breakout fields
-    (group  ~@(map formatted fields))
-
-    ;; Add fields form only for fields that weren't specified in :fields clause -- we don't want to include it twice, or korma will barf
-    (fields ~@(->> fields
-                   (filter (partial (complement contains?) (set (:fields (:query *query*)))))
-                   (map (u/rpartial formatted :include-as))))])
-
-
-(defmethod apply-form :fields [[_ fields]]
-  `(fields ~@(map (u/rpartial formatted :include-as) fields)))
-
+        :avg      (k/aggregate korma-query (avg field) :avg)
+        :count    (k/aggregate korma-query (count field) :count)
+        :distinct (k/aggregate korma-query (count (k/sqlfn :DISTINCT field)) :count)
+        :stddev   (k/fields    korma-query [(k/sqlfn :STDDEV field) :stddev])
+        :sum      (k/aggregate korma-query (sum field) :sum)))))
+
+(defn- apply-breakout [korma-query {fields :breakout}]
+  (-> korma-query
+      ;; Group by all the breakout fields
+      ((partial apply k/group) (map formatted fields))
+      ;; Add fields form only for fields that weren't specified in :fields clause -- we don't want to include it twice, or korma will barf
+      ((partial apply k/fields) (->> fields
+                                     (filter (partial (complement contains?) (set (:fields (:query *query*)))))
+                                     (map (u/rpartial formatted :include-as))))))
+
+(defn- apply-fields [korma-query {fields :fields}]
+  (apply k/fields korma-query (for [field fields]
+                                (formatted field :include-as))))

 (defn- filter-subclause->predicate
   "Given a filter SUBCLAUSE, return a Korma filter predicate form for use in korma `where`."
@@ -192,10 +129,8 @@
   (if (= filter-type :inside)
     ;; INSIDE filter subclause
     (let [{:keys [lat lon]} filter]
-      (list 'and {(formatted (:field lat)) ['< (formatted (:max lat))]}
-                 {(formatted (:field lat)) ['> (formatted (:min lat))]}
-                 {(formatted (:field lon)) ['< (formatted (:max lon))]}
-                 {(formatted (:field lon)) ['> (formatted (:min lon))]}))
+      (kfns/pred-and {(formatted (:field lat)) ['between [(formatted (:min lat)) (formatted (:max lat))]]}
+                     {(formatted (:field lon)) ['between [(formatted (:min lon)) (formatted (:max lon))]]}))

     ;; all other filter subclauses
     (let [field (formatted (:field filter))
@@ -216,62 +151,93 @@

 (defn- filter-clause->predicate [{:keys [compound-type subclauses], :as clause}]
   (case compound-type
-    :and `(~'and ~@(map filter-clause->predicate subclauses))
-    :or  `(~'or  ~@(map filter-clause->predicate subclauses))
+    :and (apply kfns/pred-and (map filter-clause->predicate subclauses))
+    :or  (apply kfns/pred-or  (map filter-clause->predicate subclauses))
     nil  (filter-subclause->predicate clause)))

-(defmethod apply-form :filter [[_ clause]]
-  `(where ~(filter-clause->predicate clause)))
-
-
-(defmethod apply-form :join-tables [[_ join-tables]]
-  (vec (for [{:keys [table-name pk-field source-field]} join-tables]
-         `(join ~table-name
-                (~'= ~(keyword (format "%s.%s" (:name (:source-table (:query *query*))) (:field-name source-field)))
-                     ~(keyword (format "%s.%s" table-name                               (:field-name pk-field))))))))
-
-
-(defmethod apply-form :limit [[_ value]]
-  `(limit ~value))
-
-
-(defmethod apply-form :order-by [[_ subclauses]]
-  (vec (for [{:keys [field direction]} subclauses]
-         `(order ~(formatted field)
-                 ~(case direction
-                    :ascending  :ASC
-                    :descending :DESC)))))
-
-;; TODO - page can be preprocessed away -- converted to a :limit clause and an :offset clause
-;; implement this at some point.
-(defmethod apply-form :page [[_ {:keys [items page]}]]
-  {:pre [(integer? items)
-         (> items 0)
-         (integer? page)
-         (> page 0)]}
-  `[(limit ~items)
-    (offset ~(* items (- page 1)))])
-
-
-;; ## Debugging Functions (Internal)
-
+(defn- apply-filter [korma-query {clause :filter}]
+  (k/where korma-query (filter-clause->predicate clause)))
+
+(defn- apply-join-tables [korma-query {join-tables :join-tables, {source-table-name :name} :source-table}]
+  (loop [korma-query korma-query, [{:keys [table-name pk-field source-field]} & more] join-tables]
+    (let [korma-query (k/join korma-query table-name
+                              (= (keyword (format "%s.%s" source-table-name (:field-name source-field)))
+                                 (keyword (format "%s.%s" table-name        (:field-name pk-field)))))]
+      (if (seq more)
+        (recur korma-query more)
+        korma-query))))
+
+(defn- apply-limit [korma-query {value :limit}]
+  (k/limit korma-query value))
+
+(defn- apply-order-by [korma-query {subclauses :order-by}]
+  (loop [korma-query korma-query, [{:keys [field direction]} & more] subclauses]
+    (let [korma-query (k/order korma-query (formatted field) (case direction
+                                                               :ascending  :ASC
+                                                               :descending :DESC))]
+      (if (seq more)
+        (recur korma-query more)
+        korma-query))))
+
+(defn- apply-page [korma-query {{:keys [items page]} :page}]
+  (-> korma-query
+      (k/limit items)
+      (k/offset (* items (dec page)))))
+
+
+;;
 (defn- log-korma-form
   [korma-form]
   (when-not qp/*disable-qp-logging*
     (log/debug
-     (u/format-color 'green "\n\nKORMA FORM: 😏\n%s" (->> (nth korma-form 2)                                    ; korma form is wrapped in a let clause. Discard it
-                                                         (walk/prewalk (fn [form]                               ; strip korma.core/ qualifications from symbols in the form
-                                                                         (cond                                  ; to remove some of the clutter
-                                                                           (symbol? form)  (symbol (name form))
-                                                                           (keyword? form) (keyword (name form))
-                                                                           :else           form)))
-                                                         (u/pprint-to-str)))
-     (u/format-color 'blue  "\nSQL: 😈\n%s\n"        (-> (eval (let [[let-form binding-form & body] korma-form] ; wrap the (select ...) form in a sql-only clause
-                                                                `(~let-form ~binding-form                       ; has to go there to work correctly
-                                                                            (sql-only ~@body))))
-                                                        (s/replace #"\sFROM" "\nFROM")                          ; add newlines to the SQL to make it more readable
-                                                        (s/replace #"\sLEFT JOIN" "\nLEFT JOIN")
-                                                        (s/replace #"\sWHERE" "\nWHERE")
-                                                        (s/replace #"\sGROUP BY" "\nGROUP BY")
-                                                        (s/replace #"\sORDER BY" "\nORDER BY")
-                                                        (s/replace #"\sLIMIT" "\nLIMIT"))))))
+     (u/format-color 'blue "\nSQL: 😈\n%s\n" (-> (k/as-sql korma-form)
+                                                (s/replace #"\sFROM" "\nFROM")           ; add newlines to the SQL to make it more readable
+                                                (s/replace #"\sLEFT JOIN" "\nLEFT JOIN")
+                                                (s/replace #"\sWHERE" "\nWHERE")
+                                                (s/replace #"\sGROUP BY" "\nGROUP BY")
+                                                (s/replace #"\sORDER BY" "\nORDER BY")
+                                                (s/replace #"\sLIMIT" "\nLIMIT"))))))
+
+(defn process-structured
+  "Convert QUERY into a korma `select` form, execute it, and annotate the results."
+  [{{:keys [source-table] :as query} :query, driver :driver, database :database, :as outer-query}]
+  (binding [*query* outer-query]
+    (try
+      (let [entity      (korma-entity database source-table)
+            timezone    (driver/report-timezone)
+            korma-query (cond-> (k/select* entity)
+                          (:aggregation query) (apply-aggregation query)
+                          (:breakout    query) (apply-breakout    query)
+                          (:fields      query) (apply-fields      query)
+                          (:filter      query) (apply-filter      query)
+                          (:join-tables query) (apply-join-tables query)
+                          (:limit       query) (apply-limit       query)
+                          (:order-by    query) (apply-order-by    query)
+                          (:page        query) (apply-page        query))]
+
+        ;; log query
+        (when (config/config-bool :mb-db-logging)
+          (log-korma-form korma-query))
+
+        ;; execute query
+        (kdb/with-db (:db entity)
+          (if (and (seq timezone)
+                   (contains? (:features driver) :set-timezone))
+            (kdb/transaction
+              (k/exec-raw ((:timezone->set-timezone-sql driver) timezone))
+              (k/exec korma-query))
+            (k/exec korma-query))))
+
+      (catch java.sql.SQLException e
+        (let [^String message (or (->> (.getMessage e) ; error message comes back like "Error message ... [status-code]" sometimes
+                                       (re-find  #"(?s)(^.*)\s+\[[\d-]+\]$") ; status code isn't useful and makes unit tests hard to write so strip it off
+                                       second) ; (?s) = Pattern.DOTALL - tell regex `.` to match newline characters as well
+                                  (.getMessage e))]
+          (throw (Exception. message)))))))
+
+(defn process-and-run
+  "Process and run a query and return results."
+  [{:keys [type] :as query}]
+  (case (keyword type)
+    :native (native/process-and-run query)
+    :query  (process-structured query)))


uncomment

uncomment

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


moving reloaded.repl to dev dependencies

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


Make `evaluate` not resolve refs and rename to `evaluate-value`.

* It's basically just a special offshoot of `interpret` for :value nodes.  I separated it to make sure it couldn't be used on :value nodes in contexts other than arrays.

--- src/isla/interpreter.clj
+++ src/isla/interpreter.clj
@@ -6,7 +6,7 @@
   (:require [mrc.utils :as utils]))

 (declare run-sequence resolve- nreturn
-         friendly-class friendly-symbol assign evaluate)
+         friendly-class friendly-symbol assign evaluate-value)

 (defmulti interpret (fn [& args] (:tag (first args))))

@@ -68,25 +68,26 @@
       (nreturn (:ctx env) return-val))))

 (defmethod interpret :value [node env]
-  (evaluate (utils/extract node [:c 0]) env))
+  (evaluate-value (utils/extract node [:c 0]) env))

-(defmulti evaluate (fn [node _] (:tag node)))
+(defmulti evaluate-value (fn [node _] (:tag node)))

-(defmethod evaluate :literal [node env]
+(defmethod evaluate-value :literal [node env]
   {:val (interpret (utils/extract node [:c 0]) env)})

-(defmethod evaluate :variable [node env]
-  (evaluate (utils/extract node [:c 0]) env))
+(defmethod evaluate-value :variable [node env]
+  (evaluate-value (utils/extract node [:c 0]) env))

-(defmethod evaluate :scalar [node env]
-  (let [ref (interpret (utils/extract node [:c 0]) env)]
-    {:ref ref :val (resolve- {:ref ref} env)}))
+(defmethod evaluate-value :scalar [node env]
+  (let [identifier (interpret (utils/extract node [:c 0]) env)]
+    {:ref identifier :val (get (:ctx env) identifier)}))

-(defmethod evaluate :object [node env]
+(defmethod evaluate-value :object [node env]
   (let [object-identifier (utils/extract node [:c 0 :c 0])
         attribute-identifier (keyword (utils/extract node [:c 1 :c 0]))]
-    {:ref [object-identifier attribute-identifier] ;; not used now, but won't work if used
-     :val (get (resolve- {:ref object-identifier} env)
+    {:ref [object-identifier attribute-identifier] ;; not used now,
+                                                   ;; won't work if assign obj-attr to var
+     :val (get (get (:ctx env) object-identifier)
                attribute-identifier)}))

 (defmethod interpret :identifier [node _]


standard middleware

standard middleware

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

--- src/adder/middleware.clj
+++ src/adder/middleware.clj
@@ -0,0 +1,50 @@
+(ns adder.middleware
+  (:require [clj-stacktrace.repl :as strp]))
+
+(defn- log [msg & vals]
+  (let [line (apply format msg vals)]
+    (locking System/out (println line))))
+
+(defn wrap-if [handler pred wrapper & args]
+  (if pred
+    (apply wrapper handler args)
+    handler))
+
+(defn wrap-request-logging [handler]
+  (fn [{:keys [request-method uri] :as req}]
+    (let [start  (System/currentTimeMillis)
+          resp   (handler req)
+          finish (System/currentTimeMillis)
+          total  (- finish start)]
+      (log "request %s %s (%dms)" request-method uri total)
+      resp)))
+
+(defn wrap-exception-logging [handler]
+  (fn [req]
+    (try
+      (handler req)
+      (catch Exception e
+        (log "Exception:\n%s" (strp/pst-str e))
+        (throw e)))))
+
+(defn wrap-failsafe [handler]
+  (fn [req]
+    (try
+      (handler req)
+      (catch Exception e
+        {:status 500
+         :headers {"Content-Type" "text/plain"}
+         :body "We're sorry, something went wrong."}))))
+
+(defn wrap-bounce-favicon [handler]
+  (fn [req]
+    (if (= [:get "/favicon.ico"] [(:request-method req) (:uri req)])
+      {:status 404
+       :headers {}
+       :body ""}
+      (handler req))))
+
+(defn wrap-utf [handler]
+  (fn [req]
+    (let [resp (handler req)]
+      (assoc-in resp [:headers "Content-Type"] "text/html; charset=utf-8"))))


remove extraneous title from wall of text page

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/clojurecup/cc2014-frontend.git/'


update to session handling

update to session handling

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


small fix in document/get-(first-)by-example: prevent an options map from getting passed to ArangoDB

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


Add stub for grains exercise

Add stub for grains exercise

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

--- exercises/grains/src/grains.clj
+++ exercises/grains/src/grains.clj
@@ -0,0 +1,9 @@
+(ns grains)
+
+(defn square [] ;; <- arglist goes here
+    ;; your code goes here
+)
+
+(defn total []  ;; <- arglist goes here
+    ;; your code goes here
+)


Cap execution for e2e tests

Cap execution for e2e tests

--- test/icecap/e2e/common.clj
+++ test/icecap/e2e/common.clj
@@ -22,3 +22,8 @@
   [plan]
   (post (str base-url "/v0/caps")
         {:body (str plan)}))
+
+(defn execute-cap
+  "Executes the capability with the given URL."
+  [cap-url]
+  (get cap-url))


use real applicant name instead of bobloblaw

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


Add mouse event listeners.

Add mouse event listeners.

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

--- src/cljs/quil/applet.clj
+++ src/cljs/quil/applet.clj
@@ -0,0 +1,11 @@
+(ns cljs.quil.applet)
+
+(defmacro with-applet [applet & body]
+  `(binding [cljs.quil.applet/*surface* ~applet]
+     ~@body))
+
+
+(defmacro defsketch
+  [app-name & options]
+  `(defn ^:export ~app-name []
+     (cljs.quil.applet/make-processing ~@options)))


index page layout changed

index page layout changed

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