ML + DM | 150 | Minor test cleanup

ML + DM | 150 | Minor test cleanup

--- test/stonecutter/test/controller/user.clj
+++ test/stonecutter/test/controller/user.clj
@@ -374,34 +374,42 @@
          nil empty?))

 (facts "about resending confirmation emails"
-       (fact "redirects to profile page with flash message indicating email has been sent"
-             (let [test-email-sender (test-email/create-test-email-sender)
-                   user-store (m/create-memory-store)
-                   user (user/store-user! user-store default-email default-password)
-                   confirmation-store (m/create-memory-store)
-                   _confirmation (confirmation/store! confirmation-store (:login user) confirmation-id)
-                   request (th/create-request :post (routes/path :resend-confirmation-email)
-                                              {}
-                                              {:user-login default-email})]
-               (u/resend-confirmation-email user-store confirmation-store test-email-sender request)
-               => (every-checker (th/check-redirects-to "/profile")
-                                 (contains {:flash :confirmation-email-sent}))
-               (:email (test-email/last-sent-email test-email-sender)) => default-email
-               (:body (test-email/last-sent-email test-email-sender)) => (contains {:confirmation-id confirmation-id})))
-
-       (fact "redirects to profile page with flash message indicating email is already confirmed"
-             (let [test-email-sender (test-email/create-test-email-sender)
-                   user-store (m/create-memory-store)
-                   _user (->> (user/store-user! user-store default-email default-password)
-                              (user/confirm-email! user-store))
-                   confirmation-store (m/create-memory-store)
-                   request (th/create-request :post (routes/path :resend-confirmation-email)
-                                              {}
-                                              {:user-login default-email})]
-               (u/resend-confirmation-email user-store confirmation-store test-email-sender request)
-               => (every-checker (th/check-redirects-to "/profile")
-                                 (contains {:flash :email-already-confirmed}))
-               (test-email/last-sent-email test-email-sender) => nil?)))
+       (facts "when the user's email address has not yet been confirmed"
+              (let [test-email-sender (test-email/create-test-email-sender)
+                    user-store (m/create-memory-store)
+                    confirmation-store (m/create-memory-store)
+                    user (user/store-user! user-store default-email default-password)
+                    _confirmation (confirmation/store! confirmation-store (:login user) confirmation-id)
+                    request (th/create-request :post (routes/path :resend-confirmation-email)
+                                               {}
+                                               {:user-login default-email})
+                    response (u/resend-confirmation-email user-store confirmation-store test-email-sender request)]
+
+                (fact "redirects to profile page with flash message indicating email has been sent"
+                      response => (th/check-redirects-to "/profile")
+                      response => (contains {:flash :confirmation-email-sent}))
+
+                (fact "sends another confirmation email"
+                      (:email (test-email/last-sent-email test-email-sender)) => default-email
+                      (:body (test-email/last-sent-email test-email-sender)) => (contains {:confirmation-id confirmation-id}))))
+
+       (facts "when the user's email has already been confirmed"
+              (let [test-email-sender (test-email/create-test-email-sender)
+                    user-store (m/create-memory-store)
+                    confirmation-store (m/create-memory-store)
+                    _user-with-confirmed-email (->> (user/store-user! user-store default-email default-password)
+                                                    (user/confirm-email! user-store))
+                    request (th/create-request :post (routes/path :resend-confirmation-email)
+                                               {}
+                                               {:user-login default-email})
+                    response (u/resend-confirmation-email user-store confirmation-store test-email-sender request)]
+
+                (fact "redirects to profile page with flash message indicating address is already confirmed"
+                      response => (th/check-redirects-to "/profile")
+                      response => (contains {:flash :email-already-confirmed}))
+
+                (fact "does not send another confirmation email"
+                      (test-email/last-sent-email test-email-sender)) => nil?)))

 (facts "about unsharing profile cards"
        (facts "about get requests to /unshare-profile-card"


comment out some tests

comment out some tests

--- test/cljam/t_core.clj
+++ test/cljam/t_core.clj
@@ -17,9 +17,9 @@
                      (after  :facts (clean-cache!))]
   (fact "about view"
         (with-out-file temp-out (core/view [test-sam-file])) => anything
-        (slurp temp-out) => (slurp "test/resources/t_core.view")
+        ;(slurp temp-out) => (slurp "test/resources/t_core.view")
         (with-out-file temp-out (core/view [test-bam-file])) => anything
-        (slurp temp-out) => (slurp "test/resources/t_core.view")
+        ;(slurp temp-out) => (slurp "test/resources/t_core.view")
         ))

 (with-state-changes [(before :facts (prepare-cache!))
@@ -69,7 +69,7 @@
                      (after  :facts (clean-cache!))]
   (fact "about pileup"
         (with-out-file temp-out (core/pileup [test-sorted-bam-file])) => anything
-        (slurp temp-out) => (slurp "test/resources/t_core.pileup")
+        ;(slurp temp-out) => (slurp "test/resources/t_core.pileup")
         ))

 (with-state-changes [(before :facts (do (prepare-cache!)


Added multipart options to handler/site function

--- src/compojure/handler.clj
+++ src/compojure/handler.clj
@@ -35,8 +35,9 @@
     - wrap-keyword-params

   A map of options may also be provided. These keys are provided:
-    :session - a map of session middleware options"
+    :session   - a map of session middleware options
+    :multipart - a map of multipart-params middleware options"
   [routes & [opts]]
   (-> (api routes)
-      (wrap-multipart-params)
+      (with-opts wrap-multipart-params (:multipart opts))
       (with-opts wrap-session (:session opts))))


take off voice=true param

take off voice=true param

--- src-cljs/frontend/components/outer.cljs
+++ src-cljs/frontend/components/outer.cljs
@@ -357,7 +357,7 @@
                [:span.content-copy
                 "Sometimes speaking out loud is simply easier than typing messages back and forth. "
                 "Teammates on your domain will get unlimited access to voice chat in every document. "]]
-              [:a.feature-link {:href "https://precursor.precursorapp.com/document/17592197569418?voice=true" :target "_blank"}
+              [:a.feature-link {:href "https://precursor.precursorapp.com/document/17592197569418" :target "_blank"}
                [:span.content-copy "Try a voice chat."]]]
              [:div.feature-media.reverse
               [:div.art-frame


Remove unused code from data/shapes.

Remove unused code from data/shapes.

--- frontend/src/uxbox/main/data/shapes.cljs
+++ frontend/src/uxbox/main/data/shapes.cljs
@@ -126,22 +126,12 @@

 ;; --- Apply Temporal Displacement

-(defn rotate
-  [{:keys [x1 y1 x2 y2 rotation] :as shape}]
-  (let [x-center (+ x1 (/ (- x2 x1) 2))
-        y-center (+ y1 (/ (- y2 y1) 2))]
-    (-> (gmt/matrix)
-        #_(gmt/translate  x-center y-center)
-        (gmt/rotate 15)
-        #_(gmt/translate (- x-center) (- y-center)))))
-
 (deftype ApplyTemporalDisplacement [id delta]
   udp/IPageUpdate
   ptk/UpdateEvent
   (update [_ state]
     (let [shape (get-in state [:shapes id])
           displ (:tmp-displacement shape (gpt/point 0 0))
-          ;; delta (gpt/transform delta (rotate shape))
           delta (gpt/add displ delta)]
       (assoc-in state [:shapes id :tmp-displacement] delta))))


Add better docstrings

Add better docstrings

--- src/oxcart/util.clj
+++ src/oxcart/util.clj
@@ -42,8 +42,10 @@

 (defn take-when
-  "When pred is true of the head of seq, return [head tail]. Otherwise
-  [nil seq]. Used as a helper for parsing optinal typed elements out
+  "λ (λ T → Bool) → (Seq T) → [(Option T) (Seq T)]
+
+  When pred is true of the head of seq, return [head tail]. Otherwise
+  [nil seq]. Used as a helper for parsing optional typed elements out
   of sequences. Say docstrings out of argument seqs."
   [pred seq]
   (if (pred (first seq))
@@ -52,20 +54,35 @@

 (defn map-vals
+  "λ {A → B} → (λ B → more* → C) → more* → {A → C}
+
+  Computes a new map from m preserving the keys of m, but mapping the
+  keys of m to (apply f (get m k) args)."
   [m f & args]
   (->> (for [[k v] m]
          [k (apply f v args)])
        (into {})))

-(defn fix [f dat]
+(defn fix
+  "λ (fn T → T) → T → T
+
+  Eagerly computes the fixed point combinator of the input function
+  and value. As this computation is eager, it will terminate only when
+  a fixed point is reached which may be never."
+  [f dat]
   (let [dat' (f dat)]
     (if (= dat dat')
       dat
       (recur f dat'))))

-(defn update [map key f & args]
+(defn update
+  "λ {A → B} → A → (λ B → args* → C) → args* → {A → C}
+
+  Updates a key in the map by applying f to the value at that key more
+  arguments, returning the resulting map."
+  [map key f & args]
   (assoc map key
          (apply f (get map key) args)))


Remove obsolete bulk functions.

Remove obsolete bulk functions.

--- src/pjstadig/es.clj
+++ src/pjstadig/es.clj
@@ -367,59 +367,6 @@
                                                       :_id id})]
     (http-delete (url es index-name type-name id) body)))

-(defn op-action
-  "Returns the action from op (its first and only key)."
-  [op]
-  (first (keys op)))
-
-(defn op-source
-  "Returns the source from op."
-  [op]
-  (get-in op [(op-action op) :source]))
-
-(defn op-source-meta
-  "Returns the meta from the source of the op (the _index, _type, and _id
-  keys)."
-  [op]
-  (select-keys (op-source op) [:_index "_index" :_type "_type" :_id "_id"]))
-
-(defn op-prep
-  "Prep op to be sent to ES.  It merges the meta from the source of the op into
-  the op, and merges in the index-name if it is specified."
-  ([op]
-     (let [action (op-action op)]
-       (update-in op [action] #(merge (op-source-meta op)
-                                      %))))
-  ([index-name op]
-     (let [action (op-action op)]
-       (update-in op [action] #(merge (when index-name
-                                        {:_index index-name})
-                                      (op-source-meta op)
-                                      %)))))
-
-(defn op-write!
-  "Writes JSON encoded op to writer."
-  [op wos]
-  (let [action (op-action op)
-        source (op-source op)
-        op (update-in op [action] dissoc :source)
-        s (json/encode-stream op wos)]
-    (.write wos "\n")
-    (when source
-      (json/encode-stream source wos)
-      (.write wos "\n"))))
-
-(defn doc-bulk
-  "Performs bulk index operations."
-  ([es ops]
-     (http-post (url es "_bulk")
-                (piped-body #(doseq [op ops]
-                               (op-write! (op-prep op) %)))))
-  ([es index-name ops]
-     (http-post (url es "_bulk")
-                (piped-body #(doseq [op ops]
-                               (op-write! (op-prep index-name op) %))))))
-
 (defn bulk-write! [metas&sources writer]
   (doseq [doc metas&sources]
     (json/encode-stream doc writer)


Compute parameters of exponential distribution, split by limiting angles

--- src/db_quiz_prep/prepare.clj
+++ src/db_quiz_prep/prepare.clj
@@ -1,18 +1,42 @@
 (ns db-quiz-prep.prepare
   (:require [db-quiz-prep.sparql :as sparql]
             [clojure.java.io :as io]
-            [clojure.edn :as edn]))
+            [clojure.edn :as edn]
+            [stencil.core :refer [render-string]]))
+
+; ----- Private functions -----
+
+(def ^:private degrees->radians
+  "Convert angle in degrees to radians"
+  (partial * (/ Math/PI 180)))
+
+(defn- round
+  "Round a `number` to a given `precision` decimal places."
+  [precision number]
+  (let [rounding-factor (Math/pow 10 precision)]
+    (/ (Math/round (* number rounding-factor))
+       rounding-factor)))
+
+(def ^:private round-2
+  "Round to 2 decimal places"
+  (partial round 2))

 (defn- sign
+  "Tell the sign of the `number`."
   [number]
   (if (neg? number) - +))

+; ----- Public functions -----
+
 (defn bisection
+  "Use bisection method to find the root of function `f` in the interval [a, b].
+  `tolerance` the maximum deviation from 0.
+  `nmax` is the maximum number of iteration of the bisection before it fails."
   ([n f a b tolerance nmax]
    (if (<= n nmax)
      (let [c (/ (+ a b) 2)
            fc (f c)]
-       (if (< (/ (- b a) 2) tolerance)
+       (if (< (Math/abs (float (/ (- b a) 2))) tolerance)
          c
          (if (= (sign fc) (sign (f a)))
            (recur (inc n) f c b tolerance nmax)
@@ -22,12 +46,28 @@
    (bisection 1 f a b tolerance nmax)))

 (defn estimate-b
+  "Estimates parameter b of an exponential function based on `indegree-histogram`."
   [indegree-histogram b]
   (letfn [(sum-map [f] (reduce + (map f indegree-histogram)))]
     (- (* (sum-map (fn [[x _]] (* x (Math/exp (* 2 b x)))))
           (/ (sum-map (fn [[x y]] (* y (Math/exp (* b x)))))
              (sum-map (fn [[x _]] (Math/exp (* 2 b x))))))
        (sum-map (fn [[x y]] (* y x (Math/exp (* b x))))))))
+
+(defn compute-a
+  "Computes parameter a of an exponential function with parameter `b`
+  based on `indegree-histogram`."
+  [indegree-histogram b]
+  (letfn [(sum-map [f] (reduce + (map f indegree-histogram)))]
+    (/ (sum-map (fn [[x y]] (* y (Math/exp (* b x)))))
+       (sum-map (fn [[x _]] (Math/exp (* 2 b x)))))))
+
+(defn get-indegree-limit
+  "Get limiting indegree for exponential function parameterized with `a` and `b` at `angle` in degrees."
+  [a b angle]
+  (round-2 (/ (Math/log (/ (Math/tan (degrees->radians angle))
+                           (* a b)))
+              b)))

 (defn get-indegree-histogram
   "Compute indegree histogram based on the provided configuration.
@@ -39,33 +79,48 @@
            (mapv parse-int [indegree frequency]))
          (sparql/execute-unlimited-select-query config query))))

-(defn materialize-difficulty
+(defn materialize-difficulties
+  "Precompute difficulties of questions based on their indegree."
   [config]
-  (let [indegree-histogram (get-indegree-histogram config)]
-    indegree-histogram))
+  (let [{{:keys [easy normal]} :split-angles} config
+        indegree-histogram (get-indegree-histogram config)
+        b (float (bisection (partial estimate-b indegree-histogram) -10 0 0.001 100))
+        a (float (compute-a indegree-histogram b))
+        maximum-indegree (get-indegree-limit a b easy)
+        minimum-indegree (get-indegree-limit a b normal)
+        update-template (slurp (io/resource "materialize_difficulties.mustache"))]
+    (sparql/execute-unlimited-update config
+                                     update-template
+                                     :data {:maximum-indegree maximum-indegree
+                                            :minimum-indegree minimum-indegree})))
+
+(defn delete-difficulties
+  "Delete materialized difficulties for given class.
+  Used for testing."
+  [{:keys [data params]
+    :as config}]
+  (let [update-template (slurp (io/resource "delete_difficulties.mustache"))
+        update-string (render-string update-template (merge params data))]
+    (sparql/execute-update config update-string)))

 (defn materialize-questions
   "Materialize questions based on provided configuration"
   [config]
   (let [update-template (slurp (io/resource "materialize_questions.mustache"))]
-    (sparql/execute-unlimited-update config materialize-questions)))
+    (sparql/execute-unlimited-update config update-template)))

 (defn execute
-  ""
+  "Execute `task` given configuration in `config`."
   [{{:keys [page-size]
       :or {page-size 10000}} :sparql-endpoint
      :keys [data start-from]
      :or {start-from 0}
-     :as config}]
+     :as config}
+   task]
   (let [config' (merge config {:page-size page-size
-                               :start-from start-from
-                               :params data})]
-    ;(materialize-questions config')
-    (materialize-difficulty config')))
-
-(comment
-  (def config (edn/read-string (slurp "config.edn")))
-  (def indegrees (execute config))
-  (def f (partial estimate-b indegrees))
-  (float (bisection f -10 0 0.00001 100))
-  )
+                               :params data
+                               :start-from start-from})]
+    (case task
+          "questions" (materialize-questions config')
+          "difficulties" (materialize-difficulties config')
+          "delete-difficulties" (delete-difficulties config'))))


Replace no-fn-applet-param to fn-applet-param.

--- src/quil/applet.clj
+++ src/quil/applet.clj
@@ -359,8 +359,11 @@
       (attach-applet-listeners))))

 (def ^{:private true}
-  non-fn-applet-params
-  #{:size :renderer :output-file :title :target})
+  fn-applet-params
+  #{:setup :draw :focus-gained :focus-lost :mouse-entered
+    :mouse-exited :mouse-pressed :mouse-released :mouse-clicked
+    :mouse-moved :mouse-dragged :mouse-wheel :key-pressed
+    :key-typed :safe-draw-fn :on-close})

 (defmacro defapplet
   "Define and start an applet and bind it to a var with the symbol
@@ -369,7 +372,7 @@
   inlined and that redefinitions to the original fns are reflected in
   the visualisation. See applet for the available options."
   [app-name & opts]
-  (let [fn-param? #(not (contains? non-fn-applet-params %))
+  (let [fn-param? #(contains? fn-applet-params %)
         opts  (mapcat (fn [[k v]]
                         [k (if (and (symbol? v)
                                     (fn-param? k))


Add the option to pass either a topic or a subscription to read-from-pubsub

--- src/datasplash/pubsub.clj
+++ src/datasplash/pubsub.clj
@@ -6,10 +6,11 @@

 (defn read-from-pubsub
   "Create an unbounded PCollection from a pubsub stream"
-  [subscription options p]
-  (-> p
-      (cond-> (instance? Pipeline p) (PBegin/in))
-      (apply-transform (PubsubIO$Read/subscription subscription) {} options)))
+  [subscription-or-topic options p]
+  (cond-> p
+          (instance? Pipeline p) (PBegin/in)
+          (re-find #"subscriptions" subscription-or-topic) (apply-transform (PubsubIO$Read/subscription subscription-or-topic) {} options)
+          (re-find #"topics" subscription-or-topic) (apply-transform (PubsubIO$Read/topic subscription-or-topic) {} options)))

 (defn write-to-pubsub
   "Write the contents of an unbounded PCollection to to a pubsub stream"


docker-compose DNS

docker-compose DNS

--- src/leiningen/new/onyx_app/src/onyx_app/catalogs/sample_catalog.clj
+++ src/leiningen/new/onyx_app/src/onyx_app/catalogs/sample_catalog.clj
@@ -95,7 +95,7 @@
       :onyx/medium :sql
       :sql/classname "com.mysql.jdbc.Driver"
       :sql/subprotocol "mysql"
-      :sql/subname "//192.168.99.100:3306/meetup"
+      :sql/subname "//db:3306/meetup"
       :sql/user "onyx"
       :sql/password "onyx"
       :sql/table :recentMeetups


refactoring

refactoring

--- iwaswhere-web/src/cljs/iwaswhere_web/new_entry.cljs
+++ iwaswhere-web/src/cljs/iwaswhere_web/new_entry.cljs
@@ -5,21 +5,17 @@
             [cljsjs.leaflet]
             [cljs.pprint :as pp]))

-(defn w-geolocation
-  [data pos]
-  (let [coords (.-coords pos)
-        latitude (.-latitude coords)
-        longitude (.-longitude coords)]
-    (merge data {:latitude  latitude
-                 :longitude longitude})))
-
 (defn send-w-geolocation
+  "Calls geolocation, sends entry enriched by geo information inside the
+  callback function"
   [data put-fn]
-  (let [geo (.-geolocation js/navigator)]
-    (.getCurrentPosition geo (fn [pos]
-                               (let [w-geoloc (w-geolocation data pos)]
-                                 (pp/pprint w-geoloc)
-                                 (put-fn [:geo-entry/persist w-geoloc]))))))
+  (.getCurrentPosition
+    (.-geolocation js/navigator)
+    (fn [pos]
+      (let [coords (.-coords pos)]
+        (put-fn [:geo-entry/persist
+                 (merge data {:latitude  (.-latitude coords)
+                              :longitude (.-longitude coords)})])))))

 (defn parse-entry
   "Parses entry for hastags and mentions."
@@ -44,9 +40,10 @@
                          (put-fn [:text-entry/save @local]))}]]
     #_(h/pp-div @local)
     [:div.entry-footer
-     [:button {:on-click (fn [_ev] (let [entry @local]
-                                     (send-w-geolocation entry put-fn)
-                                     (put-fn [:text-entry/persist entry])))} "save"]
+     [:button {:on-click #(let [entry @local]
+                           (put-fn [:text-entry/persist entry])
+                           (send-w-geolocation entry put-fn))}
+      "save"]
      (for [hashtag (:tags @local)]
        ^{:key (str "tag-" hashtag)}
        [:span.hashtag hashtag])]]])


Allow matching on +ed and -ed facts

Allow matching on +ed and -ed facts

--- src/aurora/compiler/datalog.cljs
+++ src/aurora/compiler/datalog.cljs
@@ -57,7 +57,7 @@
         facts))
     (meta query)))

-(defn project [pattern]
+(defn project [pattern kn-f]
   (let [return-syms (into [] (match/vars pattern))
         return-keys (map keyword return-syms)
         shape (into #{} return-keys)
@@ -65,7 +65,7 @@
     (with-meta
       (fn [kn]
         (into #{}
-              (for [fact (to-be kn)
+              (for [fact (kn-f kn)
                     :let [vals (f fact)]
                     :when vals]
                 (zipmap return-keys vals))))
@@ -99,6 +99,12 @@
 (defn project? [clause]
   (not (seq? clause)))

+(defn project-asserted? [clause]
+  (and (seq? clause) (= '+ed (first clause))))
+
+(defn project-retracted? [clause]
+  (and (seq? clause) (= '-ed (first clause))))
+
 (defn filter? [clause]
   (and (seq? clause) (= '? (first clause))))

@@ -115,7 +121,9 @@
                (fn [query clause]
                  (debug-q
                   (cond
-                   (project? clause) (join query (project clause))
+                   (project? clause) (join query (project clause to-be))
+                   (project-asserted? clause) (join query (project clause :asserted))
+                   (project-retracted? clause) (join query (project clause :retracted))
                    (filter? clause) (filter-q query (second clause))
                    :else query)))
                empty-q
@@ -187,4 +195,11 @@
          (- [b b b]))
    (Knowledge. #{[1 2 3] [2 3 4] [:a :b :c] [:b :c :d]} #{} #{}))

+  ((rule [a b _]
+         (+ed [_ a b])
+         (? (integer? a))
+         (+ [a a a])
+         (- [b b b]))
+   (Knowledge. #{[2 3 4] [:a :b :c] [:b :c :d]} #{[1 2 3]} #{}))
+
   )


Track which predicates each rule queries/updates

--- src/aurora/compiler/datalog.cljs
+++ src/aurora/compiler/datalog.cljs
@@ -66,6 +66,30 @@
     (if (seq? clause)
       #{}
       (match/vars clause))))
+
+(defn preds-in [clause]
+  ;; TODO check not nil
+  (condp op? clause
+    '+ed #{(:name (second clause))}
+    '-ed #{(:name (second clause))}
+    'set (apply clojure.set/union (map preds-in (nthnext clause 3)))
+    (if (seq? clause)
+      #{}
+      #{(:name clause)})))
+
+(defn preds-out [clause]
+  ;; TODO check not nil
+  (condp op? clause
+        '+ #{(:name (second clause))}
+        '- #{(:name (second clause))}
+        '+s #{:any}
+        '-s #{:any}
+        '> (let [from-name (:name (nth clause 1))
+                 to-name (:name (nth clause 2))]
+             (check from-name)
+             (check (or (nil? to-name) (= from-name to-name)))
+             #{(:name (nth clause 1))})
+        #{}))

 (def empty-q
   (with-meta
@@ -211,9 +235,12 @@

 (defn rule* [clauses]
   (let [asserts+retracts (asserts+retracts* clauses)]
-    (fn [kn]
-      (let [[asserts retracts] (asserts+retracts kn)]
-        (reduce retract (reduce assert kn asserts) retracts)))))
+    (with-meta
+      (fn [kn]
+        (let [[asserts retracts] (asserts+retracts kn)]
+          (reduce retract (reduce assert kn asserts) retracts)))
+      {::preds-in (apply union (map preds-in clauses))
+       ::preds-out (apply union (map preds-out clauses))})))

 (defn chain [rules]
   (fn [kn]
@@ -242,6 +269,7 @@
          (+ [a a a])
          (- [b b b]))
    (Knowledge. #{[1 2 3] [2 3 4] [:a :b :c] [:b :c :d]} #{} #{}))
+
   ((rule [a b _]
          (+ed [_ a b])
          (? (integer? a))
@@ -259,8 +287,6 @@
   ((query (+ed [a b])
           (+ [a b]))
    (Knowledge. #{} #{[1 2]} #{}))
-
-  ((set-q 'x '[b c] '[[a b c] [b c d]]) (Knowledge. #{[1 2 3] [2 3 4] [3 4 5] [2 8 9] [8 9 5]} #{} #{}))

   ((query (set x [b c]
                [a b c]
@@ -300,4 +326,7 @@
          (+ [c c c])
          (- [d d d]))
    (Knowledge. #{[2 3 4] [:a :b :c] [:b :c :d]} #{[1 2 3]} #{}))
+
+  (rule {:name :quux :quux x}
+        (> {:name :the :foo x} {:bar x}))
   )


Problem added - "A Half-Truth"

Problem added - "A Half-Truth"

--- src/foreclojure/data_set.clj
+++ src/foreclojure/data_set.clj
@@ -940,9 +940,23 @@
                     "(= true (__ #{\"spout\" \"do\" \"pot\" \"pout\" \"spot\" \"dot\"}))"
                     "(= true (__ #{\"share\" \"hares\" \"shares\" \"hare\" \"are\"}))"
                     "(= false (__ #{\"share\" \"hares\" \"hare\" \"are\"}))"]})
+
+(insert! :problems
+           {:_id 83
+            :title "A Half-Truth"
+            :times-solved 0
+            :description "Write a function which takes a variable number of booleans.  Your function should return true if some of the parameters are true, but not all of the parameters are true.  Otherwise your function should return false."
+            :approved true
+            :tags ["easy"]
+            :tests ["(= false (__ false false))"
+                    "(= true (__ true false))"
+                    "(= false (__ true))"
+                    "(= true (__ false true false))"
+                    "(= false (__ true true true))"
+                    "(= true (__ true true true false))"]})

       (insert! :problems
-          {:_id 83
+          {:_id 84
            :title "Create an Equation"
            :times-solved 0
            :description "Write a function which takes three or more integers.  Using these integers, your function should generate clojure code representing an equation.  The following rules for the equation must be satisfied:\n\n    1. All integers must be used once and only once.\n    2. The order of the integers must be maintained when reading the equation left-to-right.\n    3. The only functions you may use are +, *, or =.\n    4. The equation must use the minimum number of parentheses.\n    5. If no satisfying equation exists, return nil."
@@ -961,7 +975,7 @@

       (insert! :problems
-           {:_id 84
+           {:_id 85
             :title "Power Set"
             :times-solved 0
             :description "A power set is the set of all subsets of a given set. Given a list, produce a set of sublists while preserving the order of elements."


turned tap dispatch into multimethod

turned tap dispatch into multimethod

--- pigpen-cascading/src/main/clojure/pigpen/cascading.clj
+++ pigpen-cascading/src/main/clojure/pigpen/cascading.clj
@@ -14,13 +14,14 @@
             [pigpen.oven :as oven]
             [taoensso.nippy :refer [freeze thaw]]))

-;; TODO: there must be a better way to pass a Tap to a storage definition.
-(defn- get-tap-fn [name]
-  (let [tap ({:string (fn [location] (Hfs. (TextLine.) location))}
-             name)]
-    (if (nil? tap)
-      (throw (Exception. (str "Unrecognized tap type: " name)))
-      tap)))
+(defmulti get-tap-fn
+          identity)
+
+(defmethod get-tap-fn :string [_]
+           (fn [location] (Hfs. (TextLine.) location)))
+
+(defmethod get-tap-fn :default [_]
+           (throw (Exception. (str "Unrecognized tap type: " name))))

 (defn load-text [location]
   (-> (raw/load$ location '[offset line] :string {})))
@@ -60,10 +61,6 @@
 (defmulti command->flowdef
           "Converts an individual command into the equivalent Cascading flow definition."
           (fn [{:keys [type]} flowdef] type))
-
-(defmethod command->flowdef :register
-           [command flowdef]
-  flowdef)

 (defmethod command->flowdef :load
            [{:keys [id location storage fields opts]} flowdef]


delete seqs

delete seqs

--- src/functions/sequences.cljc
+++ src/functions/sequences.cljc
@@ -1,165 +0,0 @@
-(ns functions.sequences
-  (:require [clojure.zip :as z]))
-
-(def data
-  {:headers {"Content-Type" "text/html"}
-   :body {:text {:html "markup"}
-          :images "/img/path-to-img.jpg"}})
-
-(assoc-in data [:body :text] "Hello Planet" )
-
-(def matrix [[1 2 3 4 5]
-             ["a" "b" "c" "d" "e"]
-             ["hello" "thanks" "hola" "namaste" "hi"]])
-
-;; reverse
-
-(reverse [1 2 3])
-
-;; remove (opp of filter)
-
-(remove #(if (odd? %) %) (range 10))
-
-;; comp
-
-(defn reverse-and-take-rest [numbers]
-  (rest (reverse numbers)))
-
-(reverse-and-take-rest [1 2 3 4 5])
-
-;; ((comp rest reverse) [1 2 3 4])
-
-(defn square [x]
-  (* x x))
-
-(def compai (comp square first rest reverse))
-
-(compai [1 2 3 4 5])
-
-(map
- (comp - (partial + 3) (partial * 2))
- [1 2 3 4])
-
-;; credit: http://commandercoriander.net/blog/2015/02/21/writing-clojures-comp-function-from-scratch/
-
-;; first: try a recursive function
-(defn recur-comp [& all-fns]
-  (loop [fns all-fns
-         acc-fn identity]
-    (if (empty? fns) acc-fn
-        (recur
-         (butlast fns)
-         (fn [a]
-           ((last fns) (acc-fn a)))))))
-
-(def recur-comp (comp rest reverse))
-(recur-comp [1 2 3 4 5])
-
-;; second: try a reducing fn
-(defn red-comp [& all-fns]
-  (reduce
-   (fn [acc-fn curr-fn]
-     (fn [a]
-       (acc-fn (curr-fn a)))
-     identity
-     all-fns)))
-
-(def red-comp (comp rest reverse))
-(red-comp [1 2 3 4 5])
-
-
-;; Playing with Maps
-
-(defn map-over-map
-  "Given a function like (fn [k v] ...) returns a new map with each entry mapped
-   by it."
-  [f m]
-  (when m
-    (persistent! (reduce-kv (fn [out-m k v]
-                              (apply assoc! out-m (f k v)))
-                            (transient (empty m))
-                            m))))
-
-(defn map-values
-  "Apply a function on all values of a map and return the corresponding map (all
-   keys untouched)"
-  [f m]
-  (when m
-    (persistent! (reduce-kv (fn [out-m k v]
-                              (assoc! out-m k (f v)))
-                            (transient (empty m))
-                            m))))
-
-(defn map-keys
-  "Apply a function on all keys of a map and return the corresponding map (all
-   values untouched)"
-  [f m]
-  (when m
-    (persistent! (reduce-kv (fn [out-m k v]
-                              (assoc! out-m (f k) v))
-                            (transient (empty m))
-                            m))))
-
-(defn map-values
-  "Apply a function on all values of a map and return the corresponding map (all
-   keys untouched)"
-  [f m]
-  (when m
-    (persistent! (reduce-kv (fn [out-m k v]
-                              (assoc! out-m k (f v)))
-                            (transient (empty m))
-                            m))))
-
-(defn invert-map
-  "Inverts a map: key becomes value, value becomes key"
-  [m]
-  (zipmap (vals m) (keys m)))
-
-;;; Zips
-
-;; example from clojure source: zip.clj
-
-(def zip1 [1 '(a b c) 2])
-
-(def root-loc (z/seq-zip (seq zip1)))
-
-(def data '[[a * b] + [c * d]])
-(def dz (z/vector-zip data))
-
-(z/lefts (z/right (z/down (z/right (z/right (z/down dz))))))
-(z/rights (z/right (z/down (z/right (z/right (z/down dz))))))
-(z/up (z/up (z/right (z/down (z/right (z/right (z/down dz)))))))
-(z/path (z/right (z/down (z/right (z/right (z/down dz))))))
-
-(-> dz z/down z/right z/right z/down z/right (z/replace '/) z/root)
-(-> dz z/next z/next (z/edit str) z/next z/next z/next (z/replace '/) z/root)
-(-> dz z/next z/next z/next z/next z/next z/next z/next z/next z/next z/remove
-    (z/insert-right 'e) z/root)
-(-> dz z/next z/next z/next z/next z/next z/next z/next z/next z/next z/remove z/up
-    (z/append-child 'e) z/root)
-
-(z/end? (-> dz z/next z/next z/next z/next z/next z/next z/next z/next z/next z/remove z/next))
-
-(-> dz z/next z/remove z/next z/remove z/root)
-
-(loop [loc dz]
-  (if (z/end? loc)
-    (z/root loc)
-    (recur (z/next (if (= '* (z/node loc))
-                   (z/replace loc '/)
-                   loc)))))
-
-(loop [loc dz]
-  (if (z/end? loc)
-    (z/root loc)
-    (recur (z/next (if (= '* (z/node loc))
-                   (z/remove loc)
-                   loc)))))
-
-(defn print-tree [original]
-  (loop [loc (z/seq-zip (seq original))]
-    (if (z/end? loc)
-      (z/root loc)
-      (recur (z/next
-                (do (println (z/node loc))
-                    loc))))))


Split up main function in problem61.clj

Split up main function in problem61.clj

--- euler_clojure/src/euler/problem61.clj
+++ euler_clojure/src/euler/problem61.clj
@@ -1,8 +1,9 @@
 (ns euler.problem61
   "https://projecteuler.net/problem=61

-  Triangle, square, pentagonal, hexagonal, heptagonal, and octagonal numbers are
-  all figurate (polygonal) numbers and are generated by the following formulae:
+  Triangle, square, pentagonal, hexagonal, heptagonal, and octagonal numbers
+  are all figurate (polygonal) numbers and are generated by the following
+  formulae:

       Triangle   P[3,n]=n(n+1)/2  --> 1, 3, 6, 10, 15, ...
       Square     P[4,n]=n2        --> 1, 4, 9, 16, 25, ...
@@ -11,15 +12,15 @@
       Heptagonal P[7,n]=n(5n−3)/2 --> 1, 7, 18, 34, 55, ...
       Octagonal  P[8,n]=n(3n−2)   --> 1, 8, 21, 40, 65, ...

-  The ordered set of three 4-digit numbers: 8128, 2882, 8281, has
-  three interesting properties.
+  The ordered set of three 4-digit numbers: 8128, 2882, 8281, has three
+  interesting properties.

       1. The set is cyclic, in that the last two digits of each number is the
       first two digits of the next number (including the last number with the
       first).
       2. Each polygonal type: triangle (P[3,127]=8128), square (P[4,91]=8281),
-      and pentagonal (P[5,44]=2882), is represented by a different number in the
-      set.
+      and pentagonal (P[5,44]=2882), is represented by a different number in
+      the set.
       3. This is the only set of 4-digit numbers with this property.

   Find the sum of the only ordered set of six cyclic 4-digit numbers for which
@@ -61,28 +62,33 @@
                           (map func (iterate inc 0)))]
        (take-while fourdigit? dw)))))

+(defn search-permutation
+  "Given a permutation of functions representing polygonal types, search for a
+  solution, or return nil if not found."
+  [poly-funcs]
+  ;; We will build up candidate solutions incrementally. The starting
+  ;; frontier is therefore full of one-length vectors of all the four
+  ;; digit numbers for the first polygonal type of this permutation.
+  (loop [frontier (vec (for [x (fourdigit-polys (first poly-funcs))] [x]))]
+    (let [node (peek frontier)
+          z (count node)]
+      (cond
+        ;; This permutation failed.
+        (empty? frontier)
+        nil
+        ;; Success: evaluate to the sum of the values in this node.
+        (and (= z 6) (all-cyclic? node))
+        (reduce + node)
+        ;; Append child nodes to the frontier and continue the search.
+        (< z 6)
+        (let [children (for [y (fourdigit-polys (nth poly-funcs z))
+                             :when (cyclic? (last node) y)]
+                         (conj node y))]
+          (recur (into (pop frontier) (reverse children))))))))
+
 (defn problem61 []
   ;; For every way to order the polygonal types, perform depth-first search.
-  (let [polys [triangle, square, pentagonal, hexagonal, heptagonal, octagonal]
+  (let [polys [octagonal heptagonal hexagonal pentagonal square triangle]
         perms (comb/permutations polys)]
-    (some identity ; Returns the first 'truthy' result found.
-      (for [perm perms]
-        ;; We will build up candidate solutions incrementally. The starting
-        ;; frontier is therefore full of one-length vectors of all the four
-        ;; digit numbers for the first polygonal type of this permutation.
-        (loop [frontier (vec (for [x (fourdigit-polys (nth perm 0))] [x]))]
-          (let [node (peek frontier)
-                z (count node)]
-            (cond
-              ;; This permutation failed.
-              (empty? frontier)
-              nil
-              ;; Success: evaluate to the sum of the values in this node.
-              (and (= z 6) (all-cyclic? node))
-              (reduce + node)
-              ;; Append child nodes to the frontier and continue the search.
-              (< z 6)
-              (let [children (for [y (fourdigit-polys (nth perm z))
-                                   :when (cyclic? (last node) y)]
-                               (conj node y))]
-                (recur (into (pop frontier) (reverse children)))))))))))
+    ;; Return the first non-nil result.
+    (first (remove nil? (map search-permutation perms)))))


Fix warning

Fix warning

--- src/expound/problems.cljc
+++ src/expound/problems.cljc
@@ -104,12 +104,8 @@
               ;; and the unform function could throw any type of
               ;; exception (it's provided by user)
               (catch #?(:cljs :default
-                        :clj java.lang.Exception) _e
-                nil)
-              (catch #?(:cljs :default
-                        :clj java.lang.Error) _e
+                        :clj java.lang.Throwable) _e
                 nil))
-
         new-in (cond in1
                      in1


Remove unneeded require

Remove unneeded require

--- src/braid/core/server/invite.clj
+++ src/braid/core/server/invite.clj
@@ -13,7 +13,6 @@
    [image-resizer.core :as img]
    [image-resizer.format :as img-format]
    [org.httpkit.client :as http]
-   [taoensso.carmine :as car]
    [taoensso.timbre :as timbre]))

 (when (and (= (env :environment) "prod") (empty? (env :hmac-secret)))


[uploads] Guard against nil group id

[uploads] Guard against nil group id

--- src/braid/page_uploads/core.cljc
+++ src/braid/page_uploads/core.cljc
@@ -47,7 +47,7 @@

           :braid.uploads-page/get-group-uploads!
           (fn [{state :db} _]
-            (let [group-id (state :open-group-id)]
+            (when-let [group-id (state :open-group-id)]
               {:websocket-send
                (list
                  [:braid.server/uploads-in-group group-id]


limit to 100 users

limit to 100 users

--- src/foreclojure/users.clj
+++ src/foreclojure/users.clj
@@ -36,7 +36,7 @@
     (first
      (filter #(= username (% :user)) users-with-rankings))))

- (defn golfer? [user]
+(defn golfer? [user]
   (some user golfer-tags))

 (defn disable-codebox? [user]
@@ -49,9 +49,12 @@
   (link-to (str "mailto:" (email-address username))
            username))

-(defn format-user-ranking [{:keys [rank, user, solved]}]
+(defn format-user-ranking [{:keys [rank user contributor solved]}]
   [:div
    [:h2 "Your Ranking"]
+   [:div.ranking (str "Username: ")
+     (when contributor [:span.contributor "* "])
+                      [:a.user-profile-link {:href (str "/user/" user)} user]]
    [:div.ranking (str "Rank: " rank)]
    [:div.ranking (str "Problems Solved: " (count solved))]
    [:br]
@@ -81,11 +84,10 @@
      (map-indexed (fn [rownum {:keys [user contributor solved]}]
                     [:tr (row-class rownum)
                      [:td (inc rownum)]
-                         [:td
-                          (when (:contributor %2)
-                            [:span.contributor "* "])
-                          (:user %2)]
-                         [:td {:class "centered"} (count (:solved %2))]])
+                     [:td
+                      (when contributor [:span.contributor "* "])
+                      [:a.user-profile-link {:href (str "/user/" user)} user]]
+                     [:td.centered (count solved)]])
                   (take 100 (get-users)))])})

 ;; TODO: this is snagged from problems.clj but can't be imported due to cyclic dependency, must refactor this out.


CMR-1580: Addressing pull review comments.

--- umm-spec-lib/test/cmr/umm_spec/test/generate_and_parse.clj
+++ umm-spec-lib/test/cmr/umm_spec/test/generate_and_parse.clj
@@ -12,8 +12,7 @@
             [cmr.umm-spec.models.common :as umm-cmn]
             [cmr.umm-spec.json-schema :as js]
             [clj-time.core :as t]
-            [cmr.common.util :as u :refer [are2]]
-            [cmr.umm-spec.umm-json :as umm-json]))
+            [cmr.common.util :as u :refer [are2]]))

 (def example-record-echo10-supported
   "This contains an example record will all the fields supported by ECHO10. It supported
@@ -47,10 +46,7 @@
                                                    :DurationUnit "YEAR"
                                                    :DurationValue 4
                                                    :PeriodCycleDurationUnit "DAY"
-                                                   :PeriodCycleDurationValue 3}])
-                         })]}))
-
-
+                                                   :PeriodCycleDurationValue 3}])})]}))

 (def example-record
   "This contains an example record with fields supported by all formats"
@@ -68,21 +64,6 @@
                                            ;; TODO put version here once it's added to UMM.
                                            )))

-(comment
-
-
-  ;; Take a UMM record, convert to UMM JSON, parse UMM JSON, and then convert to ECHO10 XML
-  (->>  example-record-echo10-supported
-       umm-json/umm->json
-       umm-json/json->umm
-       (xg/generate-xml xm-echo10/umm-c-to-echo10-xml)
-       cmr.common.xml/pretty-print-xml
-       println)
-
-
-  )
-
-
 (deftest roundtrip-gen-parse
   (are2 [to-xml to-umm expected-manip-fn]
         (let [xml (xg/generate-xml to-xml example-record)
@@ -93,8 +74,7 @@
         xm-echo10/umm-c-to-echo10-xml um-echo10/echo10-xml-to-umm-c expected-echo10

         "ISO19115-2"
-        xm-iso2/umm-c-to-iso19115-2-xml um-iso2/iso19115-2-xml-to-umm-c identity
-        )
+        xm-iso2/umm-c-to-iso19115-2-xml um-iso2/iso19115-2-xml-to-umm-c identity)

   ;; This is here because echo10 supported additional fields
   (testing "echo10 supported fields"


Database Explorer can now add tables

Database Explorer can now add tables

Still a bit buggy but can name a table and add it

--- resources/public/init/dbexplorer.cljs
+++ resources/public/init/dbexplorer.cljs
@@ -1,8 +1,11 @@
+
+(defn get-tables []
 (remote "!get-list-of-tables"
         {:session-id  (:session-id @webapp.framework.client.system-globals.client-session-atom)}
         (fn [result2]
             (reset! webapp.framework.client.system-globals/app-state (assoc-in @webapp.framework.client.system-globals/app-state [:ui :table-list] result2))))
-
+)
+(get-tables)

 (comment sql "select * from newtable" [] (fn [rr] (js/alert (pr-str rr))))
@@ -16,6 +19,26 @@
          (fn [table-name]
            (div nil table-name))
          (get-in @webapp.framework.client.system-globals/app-state [:ui :table-list])
+         )
+
+       (div {:className "input-group"}
+            (input {:id          "tablename"
+                    :type        "text"
+                    :className   "form-control"
+                    :placeholder "New table name" } )
+
+            (span {:className "input-group-btn"}
+                  (button {:className "btn btn-default" :type "button"
+                           :onClick #(let [table-name    (.. (js/document.getElementById "tablename") -value  )]
+                                       (sql  (str "create table " table-name " (did     integer)") {}
+                                             (fn [ss]
+                                               (do
+                                                 (set! (js/document.getElementById "tablename") -value  "")
+                                                 (get-tables))))
+
+                                       )
+                           } "Add!")
+                  )
+            )
        )
-   )
   )


fix issuer banner

fix issuer banner

--- src/clj/salava/extra/application/db.clj
+++ src/clj/salava/extra/application/db.clj
@@ -205,7 +205,9 @@
 (defn publish-badge [ctx data]
   (try
     (let [advert_id (:generated_key (replace-badge-advert<!
-                                      (merge data (advert-content ctx data))
+                                      (merge (assoc data :remote_issuer_banner
+                                               (if-not (string/blank? (:remote_issuer_banner data))
+                                                 (u/file-from-url ctx (:remote_issuer_banner data)))) (advert-content ctx data))
                                       (u/get-db ctx)))]
       (when (and advert_id (= "pro" (:remote_issuer_tier data))) (do-publish ctx advert_id data)) ;;publish events only when issuer is pro
       {:success true})


Unpublish adverts, return value

Unpublish adverts, return value

--- src/clj/salava/extra/application/db.clj
+++ src/clj/salava/extra/application/db.clj
@@ -161,7 +161,8 @@

 (defn unpublish-badge [ctx data]
   (try
-    {:success (= 1 (unpublish-badge-advert-by-remote! data (u/get-db ctx)))}
+    (unpublish-badge-advert-by-remote! data (u/get-db ctx))
+    {:success true}
     (catch Exception ex
       (log/error "unpublish-badge: failed to remove badge advert")
       (log/error (.toString ex))


fixed loading

fixed loading

--- src/cljs/daveconservatoire/site/ui.cljs
+++ src/cljs/daveconservatoire/site/ui.cljs
@@ -1248,11 +1248,11 @@
     (remove-watch (some-> (om/get-reconciler this) :config :state) :auth-state-detector))

   (render [this]
-    (let [{:keys [app/route app/me route/data ui/react-key ui/fetch-state]} (om/props this)]
+    (let [{:keys [app/route app/me route/data ui/react-key]} (om/props this)]
       (dom/div #js {:key react-key}
         (desktop-menu (assoc me :react-key "desktop-menu"))
         (u/transition-group #js {:transitionName "loading" :transitionEnterTimeout 200 :transitionLeaveTimeout 200}
-          (if (df/loading? fetch-state)
+          (if (df/loading? (get data :ui/fetch-state))
             (loading nil)))
         ((u/route->factory route) data)
         (footer {:react-key "footer"})))))


transitions refactoring

transitions refactoring

--- src/cljs/triboard/logic/transition.cljs
+++ src/cljs/triboard/logic/transition.cljs
@@ -31,38 +31,37 @@
   [cell]
   (or (= cell :empty) (= cell :wall)))

-(defn- is-source?
+(defn- ^boolean is-source?
   [looser cell]
   (and looser (not= looser cell)))

-(defn- aboard-cell-at
-  [board x y]
-  (if (and (< -1 x board/width) (< -1 y board/height))
-    (aget board x y)
-    :wall))
+(defn- ^boolean? in-board?
+  [x y]
+  (and (< -1 x board/width) (< -1 y board/height)))

 (defn- seek-jump-source-toward
   "Starting from the destination of a jump (an empty cell):
-   * search for valid source for the jump
-   * collect the jumped cells along the way"                ;; TODO - Separate this? (could be faster)
+   * Search for valid source for the jump
+   * Collect the jumped cells along the way"                ;; TODO - Separate this? (could be faster)
   [board [x-init y-init :as destination] [dx dy]]
   (loop [x (+ x-init dx)
          y (+ y-init dy)
          looser nil
          taken []]
-    (let [cell (aboard-cell-at board x y)]
-      (cond
-        (block-jump? cell) nil
-        (is-source? looser cell) {:winner cell
-                                  :looser looser
-                                  :destination destination
-                                  :taken taken}
-        :else (recur
-                (+ x dx)
-                (+ y dy)
-                cell
-                (conj taken [x y])))
-      )))
+    (if (in-board? x y)
+      (let [owner (aget board x y)]
+        (cond
+          (block-jump? owner) nil
+          (is-source? looser owner) {:winner owner
+                                     :looser looser
+                                     :destination destination
+                                     :taken taken}
+          :else (recur
+                  (+ x dx)
+                  (+ y dy)
+                  owner
+                  (conj taken [x y])))
+        ))))

 (defn- available-jumps-at
   "Provides the list of moves that can be done from a cell"


Add some cosmetic improvements to handlers.clj file.


more logging

more logging

--- src/clojure/zensols/actioncli/parse.clj
+++ src/clojure/zensols/actioncli/parse.clj
@@ -145,6 +145,7 @@
 (defn handle-exception
   "Handle exceptions thrown from CLI actions."
   [e]
+  (log/debugf "handle exception: <%s>" e)
   (let [msg (.getMessage e)]
     (if *log-error* (log/error e "action line parse error"))
     (if (instance? java.io.FileNotFoundException e)
@@ -156,6 +157,8 @@
                          (if ex-data
                            (.getMessage e)
                            (.toString e)))))))
+  (log/debugf "dumping JVM: %s, rethrow: %s"
+              *dump-jvm-on-error* *rethrow-error*)
   (if *dump-jvm-on-error*
     (System/exit 1)
     (if *rethrow-error* (throw e))))


(maint) Add validate-schemas fixture to master-service-test

--- test/integration/puppetlabs/services/master/master_service_test.clj
+++ test/integration/puppetlabs/services/master/master_service_test.clj
@@ -22,7 +22,8 @@
     [puppetlabs.trapperkeeper.services.metrics.metrics-testutils :as metrics-testutils]
     [puppetlabs.trapperkeeper.services :as tk]
     [clojure.string :as str]
-    [puppetlabs.services.jruby.jruby-puppet-testutils :as jruby-testutils]))
+    [puppetlabs.services.jruby.jruby-puppet-testutils :as jruby-testutils]
+    [schema.test :as schema-test]))

 (def test-resources-path "./dev-resources/puppetlabs/services/master/master_service_test")
 (def test-resources-code-dir (str test-resources-path "/codedir"))
@@ -31,6 +32,7 @@
 (def master-service-test-runtime-dir "target/master-service-test")

 (use-fixtures :once
+              schema-test/validate-schemas
               (fn [f]
                 (testutils/with-config-dirs
                  {test-resources-conf-dir


Allow ip binding configuration.

Allow ip binding configuration.

--- src/gorilla_repl/core.clj
+++ src/gorilla_repl/core.clj
@@ -97,6 +97,7 @@
   ;; get configuration information from parameters
   (let [version (or (:version conf) "develop")
         webapp-port (or (:port conf) 8990)
+        ip (or (:ip conf) "127.0.0.1")
         nrepl-requested-port (or (:nrepl-port conf) 0)  ;; auto-select port if none requested
         project (or (:project conf) "no project")
         keymap (or (:keymap (:gorilla-options conf)) {})
@@ -111,7 +112,7 @@
     ;; first startup nREPL
     (nrepl/start-and-connect nrepl-requested-port)
     ;; and then the webserver
-    (server/run-server app-routes {:port webapp-port :join? false :ip "127.0.0.1"})
+    (server/run-server app-routes {:port webapp-port :join? false :ip ip})
     (println (str "Running at http://localhost:" webapp-port "/worksheet.html ."))
     (println "Ctrl+C to exit.")))


feature: Add delete-datastore-raw to datastore features

--- src/clj/datasplash/datastore.clj
+++ src/clj/datasplash/datastore.clj
@@ -28,6 +28,15 @@
                    (cond-> query (.withQuery query))
                    (cond-> namespace (.withNamespace namespace))
                    (cond-> num-query-split (.withNumQuerySplits num-query-split)))]
+    (apply-transform pcoll ptrans named-schema opts)))
+
+(defn delete-datastore-raw
+  "delete a pcoll of already generated datastore entity from datastore"
+  [{:keys [project-id] :as options} pcoll]
+  (let [opts (assoc options :label :delete-datastore-raw)
+        ptrans (-> (DatastoreIO/v1)
+                   (.deleteEntity)
+                   (.withProjectId project-id))]
     (apply-transform pcoll ptrans named-schema opts)))

 (declare value->clj)


implement Councilman

implement Councilman

--- src/clj/game/cards-resources.clj
+++ src/clj/game/cards-resources.clj
@@ -104,6 +104,24 @@
     :events {:rez {:req (req (ice? target))
                    :msg "gain 1 [Credits]"
                    :effect (effect (gain :runner :credit 1))}}}
+
+   "Councilman"
+   {:events {:rez {:req (req (and (#{"Asset" "Upgrade"} (:type target))
+                                  (can-pay? state :runner nil [:credit (rez-cost state :corp target)])))
+                   :effect (req (toast state :runner "Click Councilman to derez the asset or upgrade that was just rezzed" "info"))}}
+    :abilities [{:prompt "Choose an asset or upgrade that was just rezzed"
+                 :choices {:req #(and (rezzed? %)
+                                      (or (is-type? % "Asset") (is-type? % "Upgrade")))}
+                 :effect (req (let [c target
+                                    creds (rez-cost state :corp c)]
+                                (when (can-pay? state side nil [:credit creds])
+                                  (resolve-ability
+                                    state :runner
+                                    {:msg (msg "pay " creds " [Credit] and derez " (:title c) ". Councilman is trashed")
+                                     :effect (req (lose state :runner :credit creds)
+                                                  (derez state :corp c)
+                                                  (trash state side card {:unpreventable true}))}
+                                   card nil))))}]}

    "Crash Space"
    {:prevent {:damage [:meat]}


refine model helpers

refine model helpers

only match db url at the start for protocol
correct coercion matcher ref

--- src/clj_money/models/helpers.clj
+++ src/clj_money/models/helpers.clj
@@ -9,7 +9,7 @@
 ;; Storage
 ; TODO should this be dynamic to support extension?
 (def handlers
-  [{:can-handle-fn #(re-find #"postgresql" %)
+  [{:can-handle-fn #(re-find #"\Apostgresql" %)
     :create-fn #(SqlStorage. %)}])

 (defn- process-handler
@@ -54,7 +54,8 @@
   "Coerces and validates the specified model using the specified schema"
   [model schema model-name]
   (let [coercer (coerce/coercer schema
-                                (coerce/first-matcher json-matcher nil-matcher))
+                                (coerce/first-matcher [coerce/json-coercion-matcher
+                                                       nil-matcher]))
         result (coercer model)]
     (if (sutils/error? result)
      (throw-validation-exception (:error result) model schema model-name)


filters widget

filters widget

--- src/cljs/dbquery/data_table.cljs
+++ src/cljs/dbquery/data_table.cljs
@@ -2,7 +2,8 @@
   (:require [dbquery.commons :as c :refer [button input]]
             [dbquery.sql-utils :refer [sort-icons]]
             [re-frame.core :refer [dispatch subscribe]]
-            [reagent.core :as r :refer [atom]]))
+            [reagent.core :as r :refer [atom]]
+            [clojure.string :as str]))

 (defn toggle [x y]
   (if-not (= x y) y))
@@ -29,7 +30,7 @@
   (let [active-box (atom nil)]
     (fn [model i col]
       [:div.my-popover
-       [c/button-group {:bsSize "xsmall" :style {:display "flex"}}
+       [c/button-group {:bsSize "small" :style {:display "flex"}}
         [c/button {:on-click (fn[](swap! active-box #(case % :filter nil :filter)))}
          [:i.fa.fa-filter]]
         [c/button {:on-click (fn[]
@@ -46,16 +47,29 @@
          "")])))

 (defn filters [model]
-  [:div
-   [:ul.list-unstyled
-    (for [[col pred] (get-in model [:query :conditions])]
-                       ^{:key col} [:li (str col pred) [:button.btn.btn-xs "x"]])]
-   ])
+  (r/with-let [pred (atom nil)]
+    [:div.panel.panel-default
+     [:div.panel-heading "Filters"]
+     [:ul.list-group
+      (for [[col pred] (get-in model [:query :conditions])]
+        ^{:key col} [:li.list-group-item (str col " " pred)
+                     [:span.badge {:on-click #(dispatch [:set-filter col nil])} "x"]])
+      [:li.list-group-item
+       [:form.form-inline
+        {:on-submit #(do (.preventDefault %)
+                         (dispatch [:set-filter (:col @pred)
+                                    (str/replace-first (:value @pred) (:col @pred) "")])
+                         (reset! pred nil))}
+        [input {:type "typeahead" :model [pred :value] :data-source #(-> model :data :columns)
+                :choice-fn #(swap! pred assoc :col %)
+                :placeholder "more filters..."}]
+        [button {:bs-style "default" :type "submit"} "+"]]]]
+     ]))

 (defn more-toolbar [model]
   (r/with-let [active (atom nil)]
     [:div.my-popover
-     [c/button-group {:bsSize "xsmall" :style {:display "flex"}}
+     [c/button-group {:bsSize "small" :style {:display "flex"}}
       [c/button {:title "Filters:" :on-click #(reset! active :filters)} [:i.fa.fa-filter]]
       [c/button {:title "SQL"} [:i.fa.fa-paste]]]
      (case @active
@@ -101,7 +115,7 @@
                 [c/button-group {:bsSize "xsmall" :style {:display "flex"}}
                  [c/button {:title "refresh" :on-click #(dispatch [:reload])} [:i.fa.fa-refresh]]
                  [c/button {:title "more options"
-                            :on-click #(swap! col-toolbar-on toggle -1)} "..."]]
+                            :on-mouse-over #(swap! col-toolbar-on toggle -1)} "..."]]
                 (if (= @col-toolbar-on -1)
                   [more-toolbar model])]
            (doall


Make the values of the spelling select more clear

--- src/cljs/hyphen_keeper/core.cljs
+++ src/cljs/hyphen_keeper/core.cljs
@@ -114,8 +114,8 @@
             :on-change (fn [e]
                          (reset! spelling (-> e .-target .-value))
                          (load-hyphenation-patterns! @spelling @search))}
-   [:option {:value 0} "Old"]
-   [:option {:value 1} "New"]])
+   [:option {:value 0} "Old Spelling"]
+   [:option {:value 1} "New Spelling"]])

 (defn hyphenation-list []
   [:div.container


Respond to PR comments

Respond to PR comments

- add a `test-all` alias

--- src/clojure/contrib/inflect.cljc
+++ src/clojure/contrib/inflect.cljc
@@ -13,6 +13,7 @@
 (defn pluralize-noun [count noun]
   "Return the pluralized noun if the `count' is
    not 1."
+  {:pre [(<= 0 count)]}
   (let [singular? (== count 1)]
     (if singular? noun ;; If singular, return noun
         (some (fn [[cond? result-fn]]


Changing reset status code.

Changing reset status code.

--- src/cmr/mock_echo/api/routes.clj
+++ src/cmr/mock_echo/api/routes.clj
@@ -24,7 +24,7 @@
       (token-db/reset context)
       (provider-db/reset context)
       (acl-db/reset context)
-      {:status 200})
+      {:status 204})

     ;; Add routes
     (token-api/build-routes system)


Add dedupe-by and index-by helpers

Add dedupe-by and index-by helpers

--- src/com/wsscode/pathom/misc.cljc
+++ src/com/wsscode/pathom/misc.cljc
@@ -7,3 +7,31 @@
 (defn pathom-random-uuid []
   #?(:clj  (UUID/randomUUID)
      :cljs (random-uuid)))
+
+(defn dedupe-by
+  "Returns a lazy sequence removing consecutive duplicates in coll when passed to a function f.
+  Returns a transducer when no collection is provided."
+  {:added "1.7"}
+  ([f]
+   (fn [rf]
+     (let [pv (volatile! ::none)]
+       (fn
+         ([] (rf))
+         ([result] (rf result))
+         ([result x]
+          (let [prior @pv
+                fx    (f x)]
+            (vreset! pv fx)
+            (if (= prior fx)
+              result
+              (rf result x))))))))
+  ([f coll] (sequence (dedupe-by f) coll)))
+
+(defn index-by
+  "Like group by, but will keep only the last result."
+  [f coll]
+  (reduce
+    (fn [m x]
+      (assoc m (f x) x))
+    {}
+    coll))


Fix a bug reading set attributes from models.

--- src/shale/redis.clj
+++ src/shale/redis.clj
@@ -103,7 +103,7 @@
   "A session, as represented in redis."
   :model-name "sessions"
   {(s/optional-key :webdriver-id) s/Str
-   (s/optional-key :tags)        [s/Str]
+   (s/optional-key :tags)       #{s/Str}
    (s/optional-key :reserved)     s/Bool
    (s/optional-key :current-url)  s/Str
    (s/optional-key :browser-name) s/Str
@@ -148,17 +148,17 @@
   [model-schema id]
   (let [set-keys (->> model-schema
                       (keys-with-vals-matching-pred set?)
-                      (map :k))
+                      (map (comp name :k)))
         list-keys (->> model-schema
                        (keys-with-vals-matching-pred sequential?)
-                       (map :k))
+                       (map (comp name :k)))
         map-keys (->> model-schema
                       (keys-with-vals-matching-pred map?)
-                      (map :k))
+                      (map (comp name :k)))
         regular-keys (->> model-schema
                           (keys-with-vals-matching-pred
                             #(not-any? identity (juxt sequential? map? set?)))
-                          (map :k))
+                          (map (comp name :k)))
         k (model-key model-schema id)]
     (last
       (with-car*
@@ -174,9 +174,10 @@
                 lists (for [list-k list-keys]
                        {list-k (list (with-car* (car/lrange list-k 0 -1)))})
                 maps (for [map-k map-keys]
-                       {map-k (hash-map (with-car* (car/smembers map-k)))})]
-            (if-not (= base {})
-              (reduce merge (list* base (concat sets []))))))))))
+                       {map-k (with-car* (car/hgetall map-k))})]
+            (->> (concat sets lists maps)
+                 (list* base)
+                 (reduce merge))))))))

 (defn delete-model!
   "Delete a model from Redis."


Close thumb shapes

Close thumb shapes

--- src/dactyl_keyboard/dactyl-manuform.clj
+++ src/dactyl_keyboard/dactyl-manuform.clj
@@ -214,69 +214,69 @@
 ;;;;;;;;;;;;
 ;; Thumbs ;;
 ;;;;;;;;;;;;
-(def thumborigin [-25 -35 40])
+(def thumborigin [-23 -34 35])

 (defn deg2rad [degrees]
   (* (/ degrees 180) pi))

-(defn thumb-a1-place [shape]
+(defn thumb-tr-place [shape]
   (->> shape
        (rotate (deg2rad  10) [1 0 0])
        (rotate (deg2rad -23) [0 1 0])
        (rotate (deg2rad  -3) [0 0 1])
        (translate thumborigin)
-       (translate [-16 -23 -3])
+       (translate [-10 -16 0])
        ))
-(defn thumb-a2-place [shape]
-  (->> shape
-       (rotate (deg2rad  15) [1 0 0])
-       (rotate (deg2rad -35) [0 1 0])
-       (rotate (deg2rad  54) [0 0 1])
-       (translate thumborigin)
-       (translate [-28 -50 -16])
-       ))
-(defn thumb-a3-place [shape]
-  (->> shape
-       (rotate (deg2rad   6) [1 0 0])
-       (rotate (deg2rad -34) [0 1 0])
-       (rotate (deg2rad  74) [0 0 1])
-       (translate thumborigin)
-       (translate [-35 -65 -27])))
-(defn thumb-b1-place [shape]
+(defn thumb-tl-place [shape]
   (->> shape
        (rotate (deg2rad  10) [1 0 0])
        (rotate (deg2rad -23) [0 1 0])
        (rotate (deg2rad  -3) [0 0 1])
        (translate thumborigin)
-       (translate [-36 -21 -5])))
-(defn thumb-b2-place [shape]
+       (translate [-30 -15 -2])))
+(defn thumb-mr-place [shape]
+  (->> shape
+       (rotate (deg2rad  -6) [1 0 0])
+       (rotate (deg2rad -34) [0 1 0])
+       (rotate (deg2rad  48) [0 0 1])
+       (translate thumborigin)
+       (translate [-29 -40 -13])
+       ))
+(defn thumb-ml-place [shape]
   (->> shape
        (rotate (deg2rad   6) [1 0 0])
        (rotate (deg2rad -34) [0 1 0])
-       (rotate (deg2rad  70) [0 0 1])
-       (translate thumborigin)
-       (translate [-51 -34 -16])
+       (rotate (deg2rad  40) [0 0 1])
+       (translate thumborigin)
+       (translate [-51 -25 -12])))
+(defn thumb-br-place [shape]
+  (->> shape
+       (rotate (deg2rad -16) [1 0 0])
+       (rotate (deg2rad -33) [0 1 0])
+       (rotate (deg2rad  54) [0 0 1])
+       (translate thumborigin)
+       (translate [-37.8 -55.3 -25.3])
        ))
-(defn thumb-b3-place [shape]
-  (->> shape
-       (rotate (deg2rad   3) [1 0 0])
+(defn thumb-bl-place [shape]
+  (->> shape
+       (rotate (deg2rad  -4) [1 0 0])
        (rotate (deg2rad -35) [0 1 0])
        (rotate (deg2rad  52) [0 0 1])
        (translate thumborigin)
-       (translate [-55 -52 -28])
+       (translate [-56.3 -43.3 -23.5])
        ))

 (defn thumb-1x-layout [shape]
   (union
-   (thumb-a2-place shape)
-   (thumb-a3-place shape)
-   (thumb-b2-place shape)
-   (thumb-b3-place shape)))
+   (thumb-mr-place shape)
+   (thumb-ml-place shape)
+   (thumb-br-place shape)
+   (thumb-bl-place shape)))

 (defn thumb-15x-layout [shape]
   (union
-   (thumb-a1-place shape)
-   (thumb-b1-place shape)))
+   (thumb-tr-place shape)
+   (thumb-tl-place shape)))

 (def larger-plate
   (let [plate-height (/ (- sa-double-length mount-height) 3)
@@ -291,89 +291,10 @@
    (thumb-1x-layout (sa-cap 1))
    (thumb-15x-layout (rotate (/ π 2) [0 0 1] (sa-cap 1.5)))))

-(def thumb-connectors
-  (union
-   (apply union
-          (concat
-           (for [column [2] row [1]]
-             (triangle-hulls (thumb-place column row web-post-br)
-                             (thumb-place column row web-post-tr)
-                             (thumb-place (dec column) row web-post-bl)
-                             (thumb-place (dec column) row web-post-tl)))
-           (for [column [2] row [0 1]]
-             (triangle-hulls
-              (thumb-place column row web-post-bl)
-              (thumb-place column row web-post-br)
-              (thumb-place column (dec row) web-post-tl)
-              (thumb-place column (dec row) web-post-tr)))))
-   (let [plate-height (/ (- sa-double-length mount-height) 2)
-         thumb-tl (->> web-post-tl
-                       (translate [0 plate-height 0]))
-         thumb-bl (->> web-post-bl
-                       (translate [0 (- plate-height) 0]))
-         thumb-tr (->> web-post-tr
-                       (translate [0 plate-height 0]))
-         thumb-br (->> web-post-br
-                       (translate [0 (- plate-height) 0]))]
-     (union
-
-      ;;Connecting the two doubles
-      (triangle-hulls (thumb-place 0 -1/2 thumb-tl)
-                      (thumb-place 0 -1/2 thumb-bl)
-                      (thumb-place 1 -1/2 thumb-tr)
-                      (thumb-place 1 -1/2 thumb-br))
-
-      ;;Connecting the double to the one above it
-      (triangle-hulls (thumb-place 1 -1/2 thumb-tr)
-                      (thumb-place 1 -1/2 thumb-tl)
-                      (thumb-place 1 1 web-post-br)
-                      (thumb-place 1 1 web-post-bl))
-
-      ;;Connecting the 4 with the double in the bottom left
-      (triangle-hulls (thumb-place 1 1 web-post-bl)
-                      (thumb-place 1 -1/2 thumb-tl)
-                      (thumb-place 2 1 web-post-br)
-                      (thumb-place 2 0 web-post-tr))
-
-      ;;Connecting the two singles with the middle double
-      (hull (thumb-place 1 -1/2 thumb-tl)
-            (thumb-place 1 -1/2 thumb-bl)
-            (thumb-place 2 0 web-post-br)
-            (thumb-place 2 -1 web-post-tr))
-      (hull (thumb-place 1 -1/2 thumb-tl)
-            (thumb-place 2 0 web-post-tr)
-            (thumb-place 2 0 web-post-br))
-      (hull (thumb-place 1 -1/2 thumb-bl)
-            (thumb-place 2 -1 web-post-tr)
-            (thumb-place 2 -1 web-post-br))
-
-      ;;Connecting the thumb to everything
-      (triangle-hulls (thumb-place 0 -1/2 thumb-br)
-                      (key-place 1 4 web-post-bl)
-                      (thumb-place 0 -1/2 thumb-tr)
-                      (key-place 1 4 web-post-tl)
-                      (key-place 1 3 web-post-bl)
-                      (thumb-place 0 -1/2 thumb-tr)
-                      (key-place 0 3 web-post-br)
-                      (key-place 0 3 web-post-bl)
-                      (thumb-place 0 -1/2 thumb-tr)
-                      (thumb-place 0 -1/2 thumb-tl)
-                      (key-place 0 3 web-post-bl)
-                      (thumb-place 1 -1/2 thumb-tr)
-                      (thumb-place 1 1 web-post-br)
-                      (key-place 0 3 web-post-bl)
-                      (key-place 0 3 web-post-tl)
-                      (thumb-place 1 1 web-post-br)
-                      (thumb-place 1 1 web-post-tr))
-      (hull (thumb-place 0 -1/2 web-post-tr)
-            (thumb-place 0 -1/2 thumb-tr)
-            (key-place 1 4 web-post-bl)
-            (key-place 1 4 web-post-tl))))))

 (def thumb
   (union
 ;    thumb-connectors
-   thumbcaps
    (thumb-1x-layout single-plate)
    (thumb-15x-layout single-plate)
    (thumb-15x-layout larger-plate)
@@ -383,9 +304,9 @@
       (write-scad (union
                    key-holes
                    connectors
+                   thumb
+                   thumbcaps
                    caps
-                   thumb
-                  ;  thumbcaps
                   ;  front-wall
                   ;  right-wall
                   ;  new-case


Correction code typo

Correction code typo

--- src/dda/pallet/dda_backup_crate/app.clj
+++ src/dda/pallet/dda_backup_crate/app.clj
@@ -37,7 +37,7 @@
   {:group-specific-config
    {s/Keyword InfraResult}})

-(s/defn ^:allways-validate app-configuration :- BackupAppConfig
+(s/defn ^:always-validate app-configuration :- BackupAppConfig
   [domain-config :- domain/BackupConfig
    & options]
   (let [{:keys [group-key]


cleaner & faster merge-with-meta

cleaner & faster merge-with-meta

--- src/skream/core.clj
+++ src/skream/core.clj
@@ -51,14 +51,8 @@
 ;; Utility Functions (e.g. hashing)
 ;;
 (defn merge-with-meta [& maps]
-  (loop [current-maps maps
-         current-result {}]
-    (if (empty? current-maps)
-      current-result
-      (recur (rest current-maps)
-             (with-meta
-               (merge current-result (first current-maps))
-               (merge (meta current-result) (meta (first current-maps))))))))
+  (let [meta-maps (map meta maps)]
+    (with-meta (apply merge maps) (apply merge meta-maps))))

 (defn get-time [] (/ (System/currentTimeMillis) 1000))

@@ -115,7 +109,7 @@
   ([sk] sk)
   ([sk x]
     (let [added-sk (apply merge-with-meta (pmap (fn [add-fn] (add-fn sk x))
-                                      (vals (:add-fn-map (meta sk)))))
+                                                (vals (:add-fn-map (meta sk)))))
           alias-map (:alias-map (meta sk))
           aliased-sk (apply merge (pmap (fn [alias-target]
                                           (let [alias-src (get alias-map alias-target)


CMR-1335: Removed spurious capture-reveals

--- search-app/src/cmr/search/data/keywords_to_elastic.clj
+++ search-app/src/cmr/search/data/keywords_to_elastic.clj
@@ -155,13 +155,11 @@
                    (merge default-boosts specified-boosts)
                    specified-boosts)
                  default-boosts)]
-    (cmr.common.dev.capture-reveal/capture-all)
     (get boosts field 1.0)))

 (defn keywords->boosted-elastic-filters
   "Create filters with boosting for the function score query used with keyword search"
   [keywords specified-boosts]
-  (cmr.common.dev.capture-reveal/capture-all)
   (let [get-boost-fn #(get-boost specified-boosts %)]
     [;; long-name, short-name
      (keywords->name-filter :long-name.lowercase


Show usage

Show usage

--- src/spark/core.cljs
+++ src/spark/core.cljs
@@ -1,6 +1,16 @@
 (ns spark.core)

 (defn start [& _]
-  (println "YOLO"))
+  (println "
+      USAGE:
+        spark [-h] VALUE,...
+
+      EXAMPLES:
+        spark 1 5 22 13 53
+        ▁▁▃▂█
+        spark 0,30,55,80,33,150
+        ▁▂▃▄▂█
+        echo 9 13 5 17 1 | spark
+        ▄▆▂█▁"))

 (set! *main-cli-fn* start)


Move rows of the table into separate components

--- src/lolitemsets/core.cljs
+++ src/lolitemsets/core.cljs
@@ -203,22 +203,28 @@
     :optimizable true
     :troll true}])

+(defn stat-row [recommended props champ champ-level {:keys [name calc pretty] :as stat}]
+  (let [stat-optimized? (contains? props name)]
+    [(if stat-optimized?
+       :tr.info
+       :tr)
+     [:td (cond-> name
+            stat-optimized? (as-> el [:b el]))]
+     [:td (cond-> (calc champ champ-level recommended)
+            (not pretty) int
+            pretty pretty
+            stat-optimized? (as-> el [:b el]))]]))
+
 (defn build-stats [recommended champ champ-level props]
   [:div.panel.panel-primary
    [:div.panel-heading "Build statistics"]
-   (into [:table.table
-          [:tr [:th "Stat"] [:th "Value"]]]
-         (for [{:keys [name calc pretty] :as stat} stats
-               :let [stat-optimized? (contains? props name)]]
-           [(if stat-optimized?
-              :tr.info
-              :tr)
-            [:td (cond-> name
-                   stat-optimized? (as-> el [:b el]))]
-            [:td (cond-> (calc champ champ-level recommended)
-                   (not pretty) int
-                   pretty pretty
-                   stat-optimized? (as-> el [:b el]))]]))])
+   [:table.table
+    [:tr [:th "Stat"] [:th "Value"]]
+    [:div
+     (map (fn [idx stat]
+            ^{:key idx}
+            [stat-row recommended props champ champ-level stat])
+          (range) stats)]]])

 (defn item-block [id block]
   (let [items (mapv #(get @items (int (:id %))) (:items block))]
@@ -229,8 +235,8 @@
        :on-change #(swap! app assoc-in [:itemset :blocks id :type] (-> % .-target .-value))
        :value (:type block)}]]
     [:div.panel-body
-     (for [item items]
-       [:span {:key (:id item)}
+     (for [[idx item] (map vector (range) items)]
+       [:span {:key idx}
         [item-image item]])]]))

 (defn item-set [itemset]


Re-instated proper exit of program

Re-instated proper exit of program

--- src/lonelyplanet/core.clj
+++ src/lonelyplanet/core.clj
@@ -70,12 +70,6 @@
                      ]
            (let [output (second arguments)]
              (process-files {:taxonomy taxonomy :destinations destinations :output-dir output})
-             ;(exit 0
-                   (str "Files processed & saved to " output)
-                   ;)
-             ))
+             (exit 0 (str "Files processed & saved to " output))))
          (catch Exception e
-           ;(exit 1
-                 (str "Exception: " (.getMessage e))
-                 ;)
-           ))))
+           (exit 1 (str "Exception: " (.getMessage e)))))))


Adds valid-keys for limiting output

Adds valid-keys for limiting output

--- src/yuubin/mail.clj
+++ src/yuubin/mail.clj
@@ -9,6 +9,10 @@
 ;; Identify as coming from the postmaster unless otherwise provided.
 (defn- from [mailbox]
   {"from" (str "Mailgun Sandbox <postmaster@" mailbox ">")})
+
+;; The valid keys currently supported (not all of Mailgun's keys)
+(def valid-keys
+  ["from" "to" "cc" "bcc" "subject" "text" "html"])

 ;; Pre-load the known templates.
 (def templates
@@ -24,11 +28,11 @@
   (let [{body "body" template "template"} json]
     (cond
       body (assoc
-             (select-keys json ["to" "from" "subject"])
+             (select-keys json valid-keys)
              "html" body)
       (and template (contains? templates template))
         (assoc
-          (select-keys json ["to" "from" "subject"])
+          (select-keys json valid-keys)
           "html" (load-template template))
       :else json)))


More time for log files to appear in S3 for test (#948)

* More time for log files to appear in S3 for test

* Remove debug logging from S3 logs test

--- waiter/integration/waiter/kubernetes_scheduler_integration_test.clj
+++ waiter/integration/waiter/kubernetes_scheduler_integration_test.clj
@@ -143,12 +143,10 @@
                       (is (wait-for
                             #(let [{:keys [body] :as logs-response} (make-request-fn log-url)]
                                (string/includes? body log-bucket-url))
-                            :interval 1 :timeout 60)
+                            :interval 5 :timeout 300)
                           (str "Log URL never pointed to S3 bucket " log-bucket-url)))
-                  _ (log/debug "Log Url Killed:" log-url)
                   {:keys [body] :as logs-response} (make-request-fn log-url)
                   _ (assert-response-status logs-response 200)
-                  _ (log/debug "Response body:" body)
                   log-files-list (walk/keywordize-keys (json/read-str body))
                   stdout-file-link (:url (first (filter #(= (:name %) "stdout") log-files-list)))
                   stderr-file-link (:url (first (filter #(= (:name %) "stderr") log-files-list)))]


Turn off footer for inner pages.

Turn off footer for inner pages.

--- src-cljs/frontend/components/app.cljs
+++ src-cljs/frontend/components/app.cljs
@@ -126,7 +126,6 @@
               ;; simple optimzation for real-time updates when the build is running
               app-without-container-data (dissoc-in app state/container-data-path)
               dom-com (dominant-component app owner)
-              show-header-and-footer? (not= :signup (:navigation-point app))
               project (get-in app state/project-path)]
           (reset! keymap {["ctrl+s"] persist-state!
                           ["ctrl+r"] restore-state!})
@@ -173,11 +172,11 @@

                 [:div.main-body
                  (when (and (not (feature/enabled? :ui-v2))
-                            show-header-and-footer?)
+                            (not inner?))
                    (om/build header/header app-without-container-data))
                  (om/build dom-com app)

-                 (when (and show-header-and-footer? (config/footer-enabled?))
+                 (when (and (not inner?) (config/footer-enabled?))
                    [:footer.main-foot
                     (footer/footer)])]]


Sort macro results by line number

Sort macro results by line number

--- src/refactor_nrepl/find/find_macros.clj
+++ src/refactor_nrepl/find/find_macros.clj
@@ -189,4 +189,5 @@
                (conj dependents)
                (mapcat (partial find-usages-in-file macro-def))
                (into #{})
-               (remove nil?)))))
+               (remove nil?)
+               (sort-by :line-beg)))))


add tty support (#1468)

add tty support (#1468)

--- scheduler/src/cook/kubernetes/api.clj
+++ scheduler/src/cook/kubernetes/api.clj
@@ -13,7 +13,7 @@
   (:import
     (com.google.gson JsonSyntaxException)
     (com.twosigma.cook.kubernetes WatchHelper)
-    (io.kubernetes.client ApiClient ApiException)
+    (io.kubernetes.client ApiClient ApiException JSON)
     (io.kubernetes.client.apis CoreV1Api)
     (io.kubernetes.client.custom Quantity Quantity$Format IntOrString)
     (io.kubernetes.client.models V1Affinity V1Container V1ContainerPort V1ContainerState V1DeleteOptions
@@ -22,7 +22,7 @@
                                  V1NodeSelectorRequirement V1NodeSelectorTerm V1ObjectMeta V1Pod V1PodCondition
                                  V1PodSecurityContext V1PodSpec V1PodStatus V1Probe V1ResourceRequirements
                                  V1Toleration V1VolumeBuilder V1Volume V1VolumeMount)
-    (io.kubernetes.client.util Watch Yaml)
+    (io.kubernetes.client.util Watch)
     (java.util.concurrent Executors ExecutorService)))

@@ -585,6 +585,10 @@
     (.setCommand container (conj (or (when use-cook-init? custom-shell) ["/bin/sh" "-c"]) (:value command)))
     (.setEnv container main-env-vars)
     (.setImage container image)
+
+    ; allocate a TTY to support tools that need to read from stdin
+    (.setTty container true)
+    (.setStdin container true)

     (.putRequestsItem resources "memory" (double->quantity (* memory-multiplier mem)))
     (.putLimitsItem resources "memory" (double->quantity (* memory-multiplier mem)))
@@ -844,45 +848,46 @@
   [api namespace pod]
   (.createNamespacedPod api namespace pod nil nil nil))

-(defn launch-pod
-  "Attempts to submit the given pod to k8s. If pod submission fails, we inspect the
-  response code to determine whether or not this is a bad pod spec (e.g. the
-  namespace doesn't exist on the cluster or there is an invalid environment
-  variable name), or whether the failure is something less offensive (like a 409
-  conflict error because we've attempted to re-submit a pod that the watch has not
-  yet notified us exists). The function returns false if we should consider the
-  launch operation failed."
-  [api-client compute-cluster-name {:keys [launch-pod]} pod-name]
-  (if launch-pod
-    (let [{:keys [pod]} launch-pod
-          pod-name-from-pod (-> pod .getMetadata .getName)
-          namespace (-> pod .getMetadata .getNamespace)
-          api (CoreV1Api. api-client)]
-      (assert (= pod-name-from-pod pod-name)
-              (str "Pod name from pod (" pod-name-from-pod ") "
-                   "does not match pod name argument (" pod-name ")"))
-      (log/info "In" compute-cluster-name "compute cluster, launching pod with name" pod-name "in namespace" namespace ":" (Yaml/dump pod))
-      (try
-        (timers/time! (metrics/timer "launch-pod" compute-cluster-name)
-          (create-namespaced-pod api namespace pod))
-        true
-        (catch ApiException e
-          (let [code (.getCode e)
-                bad-pod-spec? (contains? #{400 404 422} code)]
-            (log/info e "In" compute-cluster-name "compute cluster, error submitting pod with name" pod-name "in namespace" namespace
-                      ", code:" code ", response body:" (.getResponseBody e))
-            (if bad-pod-spec?
-              (meters/mark! (metrics/meter "launch-pod-bad-spec-errors" compute-cluster-name))
-              (meters/mark! (metrics/meter "launch-pod-good-spec-errors" compute-cluster-name)))
-            (not bad-pod-spec?)))))
-    (do
-      ; Because of the complicated nature of task-metadata-seq, we can't easily run the pod
-      ; creation code for launching a pod on a server restart. Thus, if we create an instance,
-      ; store into datomic, but then the Cook Scheduler exits --- before k8s creates a pod (either
-      ; the message isn't sent, or there's a k8s problem) --- we will be unable to create a new
-      ; pod and we can't retry this at the kubernetes level.
-      (log/info "Unable to launch pod because we do not reconstruct the pod on startup:" pod-name)
-      false)))
+(let [json (JSON.)]
+  (defn launch-pod
+    "Attempts to submit the given pod to k8s. If pod submission fails, we inspect the
+    response code to determine whether or not this is a bad pod spec (e.g. the
+    namespace doesn't exist on the cluster or there is an invalid environment
+    variable name), or whether the failure is something less offensive (like a 409
+    conflict error because we've attempted to re-submit a pod that the watch has not
+    yet notified us exists). The function returns false if we should consider the
+    launch operation failed."
+    [api-client compute-cluster-name {:keys [launch-pod]} pod-name]
+    (if launch-pod
+      (let [{:keys [pod]} launch-pod
+            pod-name-from-pod (-> pod .getMetadata .getName)
+            namespace (-> pod .getMetadata .getNamespace)
+            api (CoreV1Api. api-client)]
+        (assert (= pod-name-from-pod pod-name)
+                (str "Pod name from pod (" pod-name-from-pod ") "
+                     "does not match pod name argument (" pod-name ")"))
+        (log/info "In" compute-cluster-name "compute cluster, launching pod with name" pod-name "in namespace" namespace ":" (.serialize json pod))
+        (try
+          (timers/time! (metrics/timer "launch-pod" compute-cluster-name)
+                        (create-namespaced-pod api namespace pod))
+          true
+          (catch ApiException e
+            (let [code (.getCode e)
+                  bad-pod-spec? (contains? #{400 404 422} code)]
+              (log/info e "In" compute-cluster-name "compute cluster, error submitting pod with name" pod-name "in namespace" namespace
+                        ", code:" code ", response body:" (.getResponseBody e))
+              (if bad-pod-spec?
+                (meters/mark! (metrics/meter "launch-pod-bad-spec-errors" compute-cluster-name))
+                (meters/mark! (metrics/meter "launch-pod-good-spec-errors" compute-cluster-name)))
+              (not bad-pod-spec?)))))
+      (do
+        ; Because of the complicated nature of task-metadata-seq, we can't easily run the pod
+        ; creation code for launching a pod on a server restart. Thus, if we create an instance,
+        ; store into datomic, but then the Cook Scheduler exits --- before k8s creates a pod (either
+        ; the message isn't sent, or there's a k8s problem) --- we will be unable to create a new
+        ; pod and we can't retry this at the kubernetes level.
+        (log/info "Unable to launch pod because we do not reconstruct the pod on startup:" pod-name)
+        false))))

 ;; TODO: Need the 'stuck pod scanner' to detect stuck states and move them into killed.


Fix formatting on special forms

Fix formatting on special forms

--- src/clj/clojuredocs/search/static.clj
+++ src/clj/clojuredocs/search/static.clj
@@ -27,34 +27,85 @@
 (def special-forms
   (->> [{:name 'def
          :ns "clojure.core"
-         :doc "Creates and interns or locates a global var with the name of symbol and a namespace of the value of the current namespace (*ns*). See http://clojure.org/special_forms for more information."}
+         :doc "Creates and interns or locates a global var with the name of symbol and a
+namespace of the value of the current namespace (*ns*). See
+http://clojure.org/special_forms for more information."}
         {:name 'if
          :ns "clojure.core"
          :doc "Evaluates test."}
         {:name 'do
          :ns "clojure.core"
-         :doc "Evaluates the expressions in order and returns the value of the last. If no expressions are supplied, returns nil. See http://clojure.org/special_forms for more information."}
+         :doc "Evaluates the expressions in order and returns the value of the last. If no
+expressions are supplied, returns nil. See http://clojure.org/special_forms
+for more information."}
         {:name 'quote
          :ns "clojure.core"
-         :doc "Yields the unevaluated form. See http://clojure.org/special_forms for more information."}
+         :doc "Yields the unevaluated form. See http://clojure.org/special_forms for more
+information."}
         {:name 'var
          :ns "clojure.core"
-         :doc "The symbol must resolve to a var, and the Var object itself (not its value) is returned. The reader macro #'x expands to (var x). See http://clojure.org/special_forms for more information."}
+         :doc "The symbol must resolve to a var, and the Var object itself (not its value)
+is returned. The reader macro #'x expands to (var x). See
+http://clojure.org/special_forms for more information."}
         {:name 'recur
          :ns "clojure.core"
-         :doc "Evaluates the exprs in order, then, in parallel, rebinds the bindings of the recursion point to the values of the exprs. See http://clojure.org/special_forms for more information."}
+         :doc "Evaluates the exprs in order, then, in parallel, rebinds the bindings of
+the recursion point to the values of the exprs. See
+http://clojure.org/special_forms for more information."}
         {:name 'throw
          :ns "clojure.core"
-         :doc "Evaluates the exprs in order, then, in parallel, rebinds the bindings of the recursion point to the values of the exprs. See http://clojure.org/special_forms for more information."}
+         :doc "Evaluates the exprs in order, then, in parallel, rebinds the bindings of the
+recursion point to the values of the exprs. See
+http://clojure.org/special_forms for more information."}
         {:name 'try
          :ns "clojure.core"
-         :doc "The exprs are evaluated and, if no exceptions occur, the value of the last is returned. If an exception occurs and catch clauses are provided, each is examined in turn and the first for which the thrown exception is an instance of the named class is considered a matching catch clause. If there is a matching catch clause, its exprs are evaluated in a context in which name is bound to the thrown exception, and the value of the last is the return value of the function. If there is no matching catch clause, the exception propagates out of the function. Before returning, normally or abnormally, any finally exprs will be evaluated for their side effects. See http://clojure.org/special_forms for more information."}
+         :doc "The exprs are evaluated and, if no exceptions occur, the value of the last
+is returned. If an exception occurs and catch clauses are provided, each is
+examined in turn and the first for which the thrown exception is an instance
+of the named class is considered a matching catch clause. If there is a
+matching catch clause, its exprs are evaluated in a context in which name is
+bound to the thrown exception, and the value of the last is the return value
+of the function. If there is no matching catch clause, the exception
+propagates out of the function. Before returning, normally or abnormally,
+any finally exprs will be evaluated for their side effects. See
+http://clojure.org/special_forms for more information."}
+        {:name 'catch
+         :ns "clojure.core"
+         :doc "The exprs are evaluated and, if no exceptions occur, the value of the last
+is returned. If an exception occurs and catch clauses are provided, each is
+examined in turn and the first for which the thrown exception is an instance
+of the named class is considered a matching catch clause. If there is a
+matching catch clause, its exprs are evaluated in a context in which name is
+bound to the thrown exception, and the value of the last is the return value
+of the function. If there is no matching catch clause, the exception
+propagates out of the function. Before returning, normally or abnormally,
+any finally exprs will be evaluated for their side effects. See
+http://clojure.org/special_forms for more information."}
+        {:name 'finally
+         :ns "clojure.core"
+         :doc "The exprs are evaluated and, if no exceptions occur, the value of the last
+is returned. If an exception occurs and catch clauses are provided, each is
+examined in turn and the first for which the thrown exception is an instance
+of the named class is considered a matching catch clause. If there is a
+matching catch clause, its exprs are evaluated in a context in which name is
+bound to the thrown exception, and the value of the last is the return value
+of the function. If there is no matching catch clause, the exception
+propagates out of the function. Before returning, normally or abnormally,
+any finally exprs will be evaluated for their side effects. See
+http://clojure.org/special_forms for more information."}
         {:name '.
          :ns "clojure.core"
-         :doc "The '.' special form is the basis for access to Java. It can be considered a member-access operator, and/or read as 'in the scope of'. See http://clojure.org/special_forms for more information."}
+         :doc "The '.' special form is the basis for access to Java. It can be considered
+a member-access operator, and/or read as 'in the scope of'. See
+http://clojure.org/special_forms for more information."}
         {:name 'set!
          :ns "clojure.core"
-         :doc "Assignment special form. When the first operand is a field member access form, the assignment is to the corresponding field. If it is an instance field, the instance expr will be evaluated, then the expr. In all cases the value of expr is returned. Note - you cannot assign to function params or local bindings. Only Java fields, Vars, Refs and Agents are mutable in Clojure. See http://clojure.org/special_forms for more information."}]
+         :doc "Assignment special form. When the first operand is a field member access
+form, the assignment is to the corresponding field. If it is an instance
+field, the instance expr will be evaluated, then the expr. In all cases
+the value of expr is returned. Note - you cannot assign to function params
+or local bindings. Only Java fields, Vars, Refs and Agents are mutable in
+Clojure. See http://clojure.org/special_forms for more information."}]
        (map #(assoc % :type "special-form"))))

 (def concept-pages


caching-mult works when source is drained

--- src/cljc/commos/delta/compscribe.cljc
+++ src/cljc/commos/delta/compscribe.cljc
@@ -361,24 +361,33 @@
             (untap* [_ ch]
               (swap! chs disj ch))
             (untap-all* [_] (throw (throw (UnsupportedOperationException.)))))]
-    (go-loop [cache nil]
-      (let [[v port] (alts! [tap-ch ch] :priority true)]
+    (go-loop [cache nil
+              receiving? true]
+      (let [[v port] (alts! (cond-> [tap-ch]
+                              receiving? (conj ch)) :priority true)]
         (condp identical? port
           tap-ch
-          (do (when (or (nil? cache)
-                        (put! v cache))
-                (swap! chs conj v))
-              (recur cache))
+          (do (when (and (or (nil? cache)
+                             (>! v cache)))
+                (if receiving?
+                  (swap! chs conj v)
+                  (close! v)))
+              (recur cache
+                     receiving?))
           ch
           (if (nil? v)
-            (run! close! @chs)
+            (do
+              (run! close! @chs)
+              (recur cache
+                     false))
             (do (when-let [chs (seq @chs)]
                   (reset! dctr (count chs))
                   (doseq [ch chs]
                     (when-not (put! ch v done)
                       (a/untap* m ch)))
                   (<! dchan))
-                (recur (accumulate cache v)))))))
+                (recur (accumulate cache v)
+                       true))))))
     m))

 (defn- cached-service


Flushing stdout prior to exiting

Flushing stdout prior to exiting

--- jvm-runner/src/clojure/codewars/core.clj
+++ jvm-runner/src/clojure/codewars/core.clj
@@ -7,6 +7,10 @@
             [codewars.runner.clojure])
   (:import [java.util.concurrent TimeoutException])
   (:gen-class))
+
+(defn- flush-out [val]
+  (flush)
+  val)

 (defn- fail [e]
   (binding [*out* *err*]
@@ -19,5 +23,5 @@
   (let [ms (-> env :timeout Integer/parseInt)
         input (json/parse-stream *in* true)]
     (try
-      (with-timeout ms (run input))
+      (flush-out (with-timeout ms (run input)))
       (catch Exception e (fail e)))))


Don't try to use console log on old versions of IE.

--- src/coming_soon/cljs/coming_soon.cljs
+++ src/coming_soon/cljs/coming_soon.cljs
@@ -1,8 +1,9 @@
 (ns coming-soon
   (:require [goog.net.XhrIo :as xhr]
             [cljs.reader :as reader]
+            [clojure.string :refer [join]]
             [jayq.core :refer [$ document-ready bind val css attr remove-attr add-class remove-class]]
-            [jayq.util :refer [log]]
+            [jayq.util :as util]
             [coming-soon.models.email :refer [valid?]]))

 (def subscribe-url "/subscribe")
@@ -17,6 +18,12 @@
 (def $subscribe ($ :#subscribe))
 (def $referrer ($ :#referrer))
 (def $spam-msg ($ :#spam-msg))
+
+(defn log
+  "log to the console only if we have a console (so not in old versions of IE)"
+  [& msg]
+  (if-not (= js/console js/undefined)
+    (util/log (join msg))))

 (defn disable-submission []
   ;; disable the submit button


Add print and factory methods for BlobRefs.

--- src/mvxcvi/vault/blob.clj
+++ src/mvxcvi/vault/blob.clj
@@ -28,7 +28,12 @@
     (str (name algorithm) ":" digest)))

-(defn content-address
+(defmethod print-method BlobRef
+  [value ^java.io.Writer w]
+  (.write w (str "#vault/blobref " \" value \")))
+
+
+(defn hash-content
   "Calculates the blob reference for the given content."
   [algorithm content]
   (let [hashfn (digest-functions algorithm)]
@@ -43,7 +48,16 @@
   "Parses an address string into a blobref. Accepts either a hash URI or the
   shorter \"algo:address\" format."
   [address]
-  (let [address (str address)
-        address (if (re-find #"^urn:" address) (subs address 4) address)
+  (let [address (if (re-find #"^urn:" address) (subs address 4) address)
         [algorithm digest] (string/split address #":" 2)]
     (BlobRef. (keyword algorithm) digest)))
+
+
+(defn blob-ref
+  "Constructs a blobref out of the arguments."
+  ([x]
+   (if (instance? BlobRef x)
+     x
+     (parse-address (str x))))
+  ([algorithm digest]
+   (BlobRef. algorithm digest)))


Fix reflection.

Fix reflection.

--- src/onyx/plugin/kafka.clj
+++ src/onyx/plugin/kafka.clj
@@ -228,8 +228,8 @@
           (ProducerRecord. message-topic (int 0) k (serializer-fn message)))))

 (defn clear-write-futures! [fs]
-  (doall (remove (fn [f]
-                   (assert (not (.isCancelled ^java.util.concurrent.Future f)))
+  (doall (remove (fn [^java.util.concurrent.Future f]
+                   (assert (not (.isCancelled f)))
                    (.isDone f))
                  fs)))