Return an empty map when all.edn stats not found

--- src/clojars/stats.clj
+++ src/clojars/stats.clj
@@ -1,10 +1,14 @@
 (ns clojars.stats
-  (:require [clojars.config :as config]))
+  (:require [clojars.config :as config]
+            [clojure.java.io :as io]))

 (defn all []
-  (read (java.io.PushbackReader. (java.io.FileReader.
-                                  (str (config/config :stats-dir)
-                                       "/all.edn")))))
+  (let [path (str (config/config :stats-dir) "/all.edn")]
+    (if (.exists (io/as-file path))
+      (read (java.io.PushbackReader. (java.io.FileReader.
+                                      (str (config/config :stats-dir)
+                                           "/all.edn"))))
+      {})))

 (defn download-count [dls group-id artifact-id & [version]]
   (let [ds (dls [group-id artifact-id])]


timeout increased

timeout increased

--- src/etaoin/client.clj
+++ src/etaoin/client.clj
@@ -9,7 +9,12 @@
 ;; defaults
 ;;

-(def timeout 20)
+(def timeout
+  "HTTP timeout in seconds. The current value may seems to high,
+  but according to my experience with SPA application full of React
+  modules even 20 seconds could not be enough for a driver to process
+  your request."
+  60)

 (def default-api-params
   {:as :json


Update server.clj

Update server.clj

--- src/falkor/server.clj
+++ src/falkor/server.clj
@@ -9,7 +9,7 @@
             [compojure.route :as route]))

 (defn allow-cross-origin
-  "middleware function to allow crosss origin"
+  "Middleware function to allow crosss origin"
   [handler]
   (fn [request]
    (let [response (handler request)]


Fix `peak?`

Fix `peak?`

--- src/get_here/core.clj
+++ src/get_here/core.clj
@@ -3,10 +3,9 @@
             [clojure.core.memoize :as memo]
             [compojure.core :refer [GET POST defroutes]]
             [ring.adapter.jetty :as jetty]
-            [ring.middleware.file-info :as file-info]
+            [ring.middleware.file-info :refer [wrap-file-info]]
             [ring.middleware.format-params :refer [wrap-restful-params]]
             [ring.middleware.format-response :refer [wrap-restful-response]]
-            [ring.middleware.keyword-params :as keyword-params]
             [ring.middleware.params :as params]
             [ring.middleware.reload :as reload]
             [ring.middleware.resource :as resource]
@@ -56,14 +55,16 @@

 (def nyc-terminal? (partial contains? #{"Penn Station"}))

-(defn peak?
-  [step]
-  {:pre [(transit-step? step)]}
-  #_
-  (or (and (nyc-terminal? departure-stop)
-           (<= 6 arrival-hour 10))
-      (and (nyc-terminal? arrival-stop)
-           (<= 16 departure-hour 20))))
+(defn peak? [{:keys [origin destination departure arrival] :as directions}]
+  {:pre [(instance? Date departure)
+         (instance? Date arrival)]}
+  (let [ny (ZoneId/of "America/New_York")
+        departure-instant (ZonedDateTime/ofInstant (.toInstant departure) ny)
+        arrival-instant (ZonedDateTime/ofInstant (.toInstant arrival) ny)]
+    (or (and (nyc-terminal? origin)
+             (<= 6 (.getHour departure-instant) 10))
+        (and (nyc-terminal? arrival)
+             (<= (.getHour arrival-instant) 20)))))

 (defn reformat-directions [body]
   (let [directions (get-in body [:routes 0 :legs 0])]
@@ -82,9 +83,9 @@
                   :towards     (get-in step [:transit_details :headsign])
                   :route       (get-in step [:transit_details :line :name])
                   :departure   (epoch-seconds->date (get-in step [:transit_details :departure_time :value]))
-                  :arrival     (epoch-seconds->date (get-in step [:transit_details :arrival_time :value]))
-                  ;; :peak        (peak? step)
-                  })))}))
+                  :arrival     (epoch-seconds->date (get-in step [:transit_details :arrival_time :value]))}))
+          (map (fn [step]
+                 (assoc step :peak (peak? step)))))}))

 #_ ;; example response
 {:summary
@@ -152,10 +153,9 @@
   (-> routes
       (wrap-restful-params)
       (wrap-restful-response)
-      #_(keyword-params/wrap-keyword-params)
       (params/wrap-params)
       (resource/wrap-resource "static")
-      (file-info/wrap-file-info)))
+      (wrap-file-info)))

 #_(defn -main
   [port]


Add logging

Add logging

--- src/gobanbot/flow.clj
+++ src/gobanbot/flow.clj
@@ -1,6 +1,7 @@
 (ns gobanbot.flow
   (:require [clojure.string :as s]
             [clojure.set :as ss]
+            [clojure.tools.logging :as log]
             [gobanbot.storage :as storage]))

 (defn moves-to-mvc [moves] (zipmap (map :mv moves) (map :color moves)))
@@ -11,11 +12,11 @@
 (defn is-move? [size value]
   (let [max-letter (-> size (+ 96) char str)]
   (if-not (empty? value)
-    (re-find (re-pattern
-               (str
-                 "^[a-"
-                 max-letter
-                 "]{2}$|^pass$|^resigni$"))
+    (re-find (re-pattern
+               (str
+                 "^[a-"
+                 max-letter
+                 "]{2}$|^pass$|^resigni$"))
              value))))

 (defn next-bwid [{:keys [bid wid handicap]} uid]
@@ -28,14 +29,14 @@
             (cond (not wid) :wid
                   (not bid) :bid))))

-(defn decide-move
+(defn decide-move
   [{:keys [moves bid wid ended started] :as game} uid mv]
   (let [bwid (next-bwid game uid)
         color (cond (= bwid :bid) "b" (= bwid :wid) "w")]
     {:bwid bwid
      :color color
      :status
-     (cond
+     (cond
        (not game) :no-game
        (not color) :not-a-player
        (= started 0) :not-started
@@ -46,22 +47,22 @@

 (defn should-end? [game]
   (or (->> game :moves (some #(= "resign" (:mv %))))
-      (->> game
+      (->> game
            :moves
-           (filter (comp (partial = "pass") :mv))
-           count
+           (filter (comp (partial = "pass") :mv))
+           count
            (= 2))))

 (defn show [{:keys [size moves]}]
   (let [mvc (moves-to-mvc moves)]
-    (str
+    (str
       (apply str (repeat (+ 2 size) "-")) "\n"
       (apply str (for [v (range size)]
         (str "|"
-           (apply str (for [h (range size)]
-                        (case (mvc (str (-> h (+ 97) char) (-> v (+ 97) char)))
-                          "b" "x"
-                          "w" "o"
+           (apply str (for [h (range size)]
+                        (case (mvc (str (-> h (+ 97) char) (-> v (+ 97) char)))
+                          "b" "x"
+                          "w" "o"
                           nil "+")))
            "|\n")))
       (apply str (repeat (+ 2 size) "-")))))
@@ -76,27 +77,27 @@

 (defn get-group-at
   ([{:keys [size moves]} color mv]
-    (get-group-at size
-                  (moves-to-mvc moves)
-                  color
-                  #{}
+    (get-group-at size
+                  (moves-to-mvc moves)
+                  color
+                  #{}
                   mv))

   ([size mvc color found mv]
   (if (= (mvc mv) color)
-    (conj
-      (apply ss/union (map
+    (conj
+      (apply ss/union (map
         #(get-group-at
-           size
+           size
            mvc
-           color
-           (conj found mv)
+           color
+           (conj found mv)
            %)
         (-> mv (get-near-cells size) set (ss/difference found))))
       mv)
     found)))

-(defn get-dame [{:keys [size moves]} group]
+(defn get-dame [{:keys [size moves]} group]
   (let [mvc (moves-to-mvc moves)]
   (->> group
       (map #(get-near-cells % size))
@@ -105,7 +106,7 @@
       (filter (comp not (partial get mvc)))
       count)))

-(defn find-to-eat [{:keys [size moves] :as game} color mv]
+(defn find-to-eat [{:keys [size moves] :as game} color mv]
   (let [op-color (if (= color "b") "w" "b")]
     (->> mv
          (#(get-near-cells % size))
@@ -119,15 +120,15 @@
   (storage/insert-move! game color mv)
   (let [gid (:gid game)
         updated (storage/get-game gid)]
-    (if (should-end? updated)
+    (if (should-end? updated)
       (storage/end-game! gid)
       (doall (map storage/mark-eaten! (find-to-eat updated color mv))))))

 (defn move! [game uid mv]
-  (println "move gid" (:gid game) uid mv)
+  (log/debug "move gid" (:gid game) uid mv)
   (let [gid (:gid game)
         {:keys [status color bwid] :as stat} (decide-move game uid mv)]
-    (println "move status" stat)
+    (log/debug "move status" stat)
     (if bwid (storage/set-player! gid bwid uid))
     (if (= status :ok) (add-move! game color mv))
     status))


CMR-612: Added an explict test that combines multiple collection query conditions to test the collection query resolver.

--- test/cmr/system_int_test/search/granule_platform_instrument_sensor_search_test.clj
+++ test/cmr/system_int_test/search/granule_platform_instrument_sensor_search_test.clj
@@ -117,72 +117,91 @@
         pr6 (dg/platform-ref "platform-6" i5)
         pr7 (dg/platform-ref "platform-7" i6)
         pr8 (dg/platform-ref "platform-8" i7)
-        coll1 (d/ingest "CMR_PROV1" (dc/collection {}))
+        coll1 (d/ingest "CMR_PROV1" (dc/collection {:short-name "SHORT1"}))
         coll2 (d/ingest "CMR_PROV1" (dc/collection {:platforms [p0]}))
-        gran1 (d/ingest "CMR_PROV1" (dg/granule coll1 {:platform-refs [pr1]}))
-        gran2 (d/ingest "CMR_PROV1" (dg/granule coll1 {:platform-refs [pr1 pr2]}))
-        gran3 (d/ingest "CMR_PROV1" (dg/granule coll1 {:platform-refs [pr2]}))
-        gran4 (d/ingest "CMR_PROV1" (dg/granule coll1 {:platform-refs [pr3]}))
-        gran5 (d/ingest "CMR_PROV1" (dg/granule coll1 {:platform-refs [pr4]}))
-        gran6 (d/ingest "CMR_PROV1" (dg/granule coll1 {:platform-refs [pr5]}))
-        gran7 (d/ingest "CMR_PROV1" (dg/granule coll2 {}))
-        gran8 (d/ingest "CMR_PROV1" (dg/granule coll2 {:platform-refs [pr6]}))
-        gran9 (d/ingest "CMR_PROV1" (dg/granule coll2 {:platform-refs [pr7]}))
-        gran10 (d/ingest "CMR_PROV1" (dg/granule coll2 {:platform-refs [pr8]}))]
+        gran1 (d/ingest "CMR_PROV1" (dg/granule coll1 {:granule-ur "gran1" :platform-refs [pr1]}))
+        gran2 (d/ingest "CMR_PROV1" (dg/granule coll1 {:granule-ur "gran2" :platform-refs [pr1 pr2]}))
+        gran3 (d/ingest "CMR_PROV1" (dg/granule coll1 {:granule-ur "gran3" :platform-refs [pr2]}))
+        gran4 (d/ingest "CMR_PROV1" (dg/granule coll1 {:granule-ur "gran4" :platform-refs [pr3]}))
+        gran5 (d/ingest "CMR_PROV1" (dg/granule coll1 {:granule-ur "gran5" :platform-refs [pr4]}))
+        gran6 (d/ingest "CMR_PROV1" (dg/granule coll1 {:granule-ur "gran6" :platform-refs [pr5]}))
+        gran7 (d/ingest "CMR_PROV1" (dg/granule coll2 {:granule-ur "gran7" }))
+        gran8 (d/ingest "CMR_PROV1" (dg/granule coll2 {:granule-ur "gran8" :platform-refs [pr6]}))
+        gran9 (d/ingest "CMR_PROV1" (dg/granule coll2 {:granule-ur "gran9" :platform-refs [pr7]}))
+        gran10 (d/ingest "CMR_PROV1" (dg/granule coll2 {:granule-ur "gran10" :platform-refs [pr8]}))]

     (index/refresh-elastic-index)

+    (testing "collection resolving query simplifications"
+      ;; This is necessary to test some simplifications the collection query resolver is doing to pass collection ids found
+      ;; in top level collection id queries down to subconditions executing collection queries
+      (are [items params]
+           (d/refs-match? items
+                          (search/find-refs :granule params))
+           [gran1 gran2] {:instrument "instrument-Sn A"
+                          :platform "platform-1"
+                          :echo_collection_id (:concept-id coll1)}
+           [gran1 gran2] {:instrument "instrument-Sn A"
+                          :platform "platform-1"
+                          :provider "CMR_PROV1"
+                          :short-name "SHORT1"}
+           [] {:instrument "instrument-Sn A"
+               :provider "CMR_PROV2"}
+           [] {:instrument "instrument-Sn A"
+               :provider "CMR_PROV1"
+               :short-name "SHORT2"}))
+
     (testing "search by instrument"
-      (are [items instrument-sn options]
-           (let [params (merge {:instrument instrument-sn}
-                               (when options
-                                 {"options[instrument]" options}))]
-             (d/refs-match? items (search/find-refs :granule params)))
-
-           [gran1 gran2 gran6] "instrument-Sn A" {}
-           [gran4] "instrument-SnA" {}
-           [gran9 gran10] "instrument-x" {}
-           [] "BLAH" {}
-
-           ;; search by instrument, multiple values
-           [gran1 gran2 gran4 gran6] ["instrument-SnA" "instrument-Sn A"] {}
-           ;; search by instrument, inheritance
-           [gran7] ["instrument-Inherit"] {}
-           ;; search by instrument, ignore case
-           [gran9 gran10] ["instrument-x"] {:ignore-case true}
-           [gran9] ["instrument-x"] {:ignore-case false}
-           ;; search by instrument, wildcards
-           [gran1 gran2 gran3 gran6] ["instrument-Sn *"] {:pattern true}
-           [gran4 gran5] ["instrument-Sn?"] {:pattern true}
-           ;; search by instrument, options :or
-           [gran1 gran2 gran3 gran6] ["instrument-Sn b" "instrument-Sn A"] {:or true}
-           ;; search by instrument, options :and
-           [gran2 gran6] ["instrument-Sn b" "instrument-Sn A"] {:and true}))
+        (are [items instrument-sn options]
+             (let [params (merge {:instrument instrument-sn}
+                                 (when options
+                                   {"options[instrument]" options}))]
+               (d/refs-match? items (search/find-refs :granule params)))
+
+             [gran1 gran2 gran6] "instrument-Sn A" {}
+             [gran4] "instrument-SnA" {}
+             [gran9 gran10] "instrument-x" {}
+             [] "BLAH" {}
+
+             ;; search by instrument, multiple values
+             [gran1 gran2 gran4 gran6] ["instrument-SnA" "instrument-Sn A"] {}
+             ;; search by instrument, inheritance
+             [gran7] ["instrument-Inherit"] {}
+             ;; search by instrument, ignore case
+             [gran9 gran10] ["instrument-x"] {:ignore-case true}
+             [gran9] ["instrument-x"] {:ignore-case false}
+             ;; search by instrument, wildcards
+             [gran1 gran2 gran3 gran6] ["instrument-Sn *"] {:pattern true}
+             [gran4 gran5] ["instrument-Sn?"] {:pattern true}
+             ;; search by instrument, options :or
+             [gran1 gran2 gran3 gran6] ["instrument-Sn b" "instrument-Sn A"] {:or true}
+             ;; search by instrument, options :and
+             [gran2 gran6] ["instrument-Sn b" "instrument-Sn A"] {:and true}))

     (testing "search granules by instrument with aql"
-      (are [items instruments options]
-           (let [condition (merge {:instrumentShortName instruments} options)]
-             (d/refs-match? items (search/find-refs-with-aql :granule [condition])))
-
-           [gran1 gran2 gran6] "instrument-Sn A" {}
-           [gran4] "instrument-SnA" {}
-           [gran9 gran10] "instrument-x" {}
-           [] "BLAH" {}
-
-           ;; search by instrument, multiple values
-           [gran1 gran2 gran4 gran6] ["instrument-SnA" "instrument-Sn A"] {}
-           ;; search by instrument, inheritance
-           [gran7] ["instrument-Inherit"] {}
-           ;; search by instrument, ignore case
-           [gran9 gran10] ["instrument-x"] {:ignore-case true}
-           [gran9] ["instrument-x"] {:ignore-case false}
-           ;; search by instrument, wildcards
-           [gran1 gran2 gran3 gran6] "instrument-Sn %" {:pattern true}
-           [gran4 gran5] "instrument-Sn_" {:pattern true}
-           ;; search by instrument, options :or
-           [gran1 gran2 gran3 gran6] ["instrument-Sn b" "instrument-Sn A"] {:or true}
-           ;; search by instrument, options :and
-           [gran2 gran6] ["instrument-Sn b" "instrument-Sn A"] {:and true}))))
+        (are [items instruments options]
+             (let [condition (merge {:instrumentShortName instruments} options)]
+               (d/refs-match? items (search/find-refs-with-aql :granule [condition])))
+
+             [gran1 gran2 gran6] "instrument-Sn A" {}
+             [gran4] "instrument-SnA" {}
+             [gran9 gran10] "instrument-x" {}
+             [] "BLAH" {}
+
+             ;; search by instrument, multiple values
+             [gran1 gran2 gran4 gran6] ["instrument-SnA" "instrument-Sn A"] {}
+             ;; search by instrument, inheritance
+             [gran7] ["instrument-Inherit"] {}
+             ;; search by instrument, ignore case
+             [gran9 gran10] ["instrument-x"] {:ignore-case true}
+             [gran9] ["instrument-x"] {:ignore-case false}
+             ;; search by instrument, wildcards
+             [gran1 gran2 gran3 gran6] "instrument-Sn %" {:pattern true}
+             [gran4 gran5] "instrument-Sn_" {:pattern true}
+             ;; search by instrument, options :or
+             [gran1 gran2 gran3 gran6] ["instrument-Sn b" "instrument-Sn A"] {:or true}
+             ;; search by instrument, options :and
+             [gran2 gran6] ["instrument-Sn b" "instrument-Sn A"] {:and true}))))

 (deftest search-by-sensor-short-names
   (let [s0 (dc/sensor "sensor-Inherit")


prelim pagination + prelim above avg score extracted

--- src/crawler/crawl.clj
+++ src/crawler/crawl.clj
@@ -24,65 +24,104 @@
                       :paginated?}
                       .
                       .
-                      .]"
-  [queue visited num-decisions sum-score limit]
+                      .]
+   misc: {:num-pages-to-max ..}. Number of pages to follow overall.
+   what is the base idea."
+  [queue visited num-decisions sum-score limit options]
   (Thread/sleep 2000)
   (if (and (not (zero? limit))
            (seq queue))
     (let [url        (-> queue first :url)
           body       (-> url client/get :body)
-          decision   (extractor/extract-richest body url visited)
+          paginated? (-> queue first :pagination?)
+          p-thus-far (-> options :pagination)
+          decision   (extractor/extract-above-average-richest
+                      body url (clojure.set/union visited queue))
           xpaths     (:xpaths decision)
           links      (:links decision)
           score      (:action-score decision)]
       (do
+        (println :total-score (/ sum-score num-decisions))
+        (println :cur-page-score score)
         (if (< (* 0.75 (/ sum-score num-decisions)) score)
           (let [paging-decis (extractor/weak-pagination-detector
                               body
                               (first queue)
-                              (concat visited queue))
+                              (clojure.set/union visited queue))
                 pagination-l (second paging-decis)

-                new-queue    (do
-                               (println :links links)
-                               (println :pagination paging-decis)
-                               (println)
-                               (concat (map (fn [a-link]
-                                              {:url a-link
-                                               :pagination? true
-                                               :content-xpaths xpaths
-                                               :paging-xpaths (first paging-decis)}) ; xpaths are what we picked on this page. no need to re-learn anything
-                                            pagination-l)
-                                       (rest queue)
-                                       (map
-                                        (fn [x] {:url x})
-                                        (filter
-                                         (fn [a-link]
-                                           (and (not (some #{a-link} visited))
-                                                (not (some #{a-link} (set
-                                                                      (map #(-> % :url) queue))))))
-                                         links))))
+                new-queue    (if (<= (-> options :pagination) 10) ; switch order of insertion at 10 urls
+                               (do
+                                 (println :links links)
+                                 (println :pagination paging-decis)
+                                 (println)
+                                 (concat (map
+                                          (fn [a-link]
+                                            {:url a-link
+                                             :pagination? true
+                                             :content-xpaths xpaths
+                                             :paging-xpaths (first paging-decis)}) ; xpaths are what we picked on this page. no need to re-learn anything
+                                          pagination-l)
+                                         (rest queue)
+                                         (map
+                                          (fn [x] {:url x})
+                                          (filter
+                                           (fn [a-link]
+                                             (and (not (some #{a-link} visited))
+                                                  (not (some #{a-link} (set
+                                                                        (map #(-> % :url) queue))))))
+                                           links))))
+                               (do
+                                 (println :links links)
+                                 (println :pagination paging-decis)
+                                 (println)
+                                 (concat
+                                  (rest queue)
+                                  (map
+                                   (fn [x] {:url x})
+                                   (filter
+                                    (fn [a-link]
+                                      (and (not (some #{a-link}
+                                                      visited))
+                                           (not (some #{a-link}
+                                                      (set
+                                                       (map #(-> % :url) queue))))))
+                                           links))
+                                  (map (fn [a-link]
+                                         {:url a-link
+                                          :pagination? true
+                                          :content-xpaths xpaths
+                                          :paging-xpaths (first paging-decis)}) ; xpaths are what we picked on this page. no need to re-learn anything
+                                       pagination-l))))
                 new-visited  (conj visited url)
                 new-num-dec  (inc num-decisions)
                 new-scr      (+ score sum-score)
-                new-lim      (dec limit)]
+                new-lim      (dec limit)
+                new-opt      (if paginated?
+                               (merge
+                                options
+                                {:pagination (+ (-> options :pagination) 1)})
+                               (merge options {:pagination 0}))]
             (recur new-queue
                    new-visited
                    new-num-dec
                    new-scr
-                   new-lim))
+                   new-lim
+                   new-opt))
           (do
             (println :no-links-chosen)
             (println)
-            ; pagination must still be chosen though
+                                        ; pagination must still be chosen though
             (let [new-queue   (rest queue)
                   new-visited (conj visited url)
                   new-num-dec num-decisions
                   new-scr     sum-score
-                  new-lim     (dec limit)]
+                  new-lim     (dec limit)
+                  new-opt     options]
               (recur new-queue
                      new-visited
                      new-num-dec
                      new-scr
-                     new-lim))))))
+                     new-lim
+                     new-opt))))))
     {:visited visited}))


Clamp RGB components outside 0..255

Clamp RGB components outside 0..255

--- src/inkspot/color.clj
+++ src/inkspot/color.clj
@@ -13,14 +13,20 @@
   (alpha [c])
   (coerce [c]))

+(defn- clamp [n]
+  (cond
+    (< n 0) 0
+    (> n 255) 255
+    :else (int n)))
+
 (defn rgba
   "Convert an IColor to rgba(...) format"
   [color]
   (str
     "rgba("
-    (int (red   color)) ","
-    (int (green color)) ","
-    (int (blue  color)) ","
+    (clamp (red   color)) ","
+    (clamp (green color)) ","
+    (clamp (blue  color)) ","
     (alpha color) ")"))

 (defn to-color
@@ -30,10 +36,10 @@
   [color]
   ^{:cljs '(rgba color)}
   (Color.
-    (int (red color))
-    (int (green color))
-    (int (blue color))
-    (int (* (alpha color) 255))))
+    (clamp (red color))
+    (clamp (green color))
+    (clamp (blue color))
+    (clamp (* (alpha color) 255))))

 (defn rgb
   "Construct a tuple of RGB (or RGBA) elements from xs, expected values
@@ -46,9 +52,9 @@
    expected values (double) in range 0.0-1.0"
   [{:keys [red green blue scale]
     :or   {red 0.0 green 0.0 blue 0.0 scale 1.0}}]
-  [(int (* 255 red scale))
-   (int (* 255 green scale))
-   (int (* 255 blue scale))])
+  [(clamp (* 255 red scale))
+   (clamp (* 255 green scale))
+   (clamp (* 255 blue scale))])

 (defn- color-vec [[_ & xs]]
   (vec


Fix fat-fingered pom generation from jar task.

--- src/leiningen/jar.clj
+++ src/leiningen/jar.clj
@@ -17,7 +17,7 @@
 as the main-class for an executable jar."
   ([project jar-name]
      (compile/compile project)
-     (pom "pom-generated.xml" true)
+     (pom project "pom-generated.xml" true)
      (let [jar-file (str (:root project) "/" jar-name)
            filesets [{:dir *compile-path*}
                      {:dir (str (:root project) "/src")}


put Manifest.txt in classes/ instead of toplevel project directory

--- src/leiningen/jar.clj
+++ src/leiningen/jar.clj
@@ -7,7 +7,7 @@
         [clojure.contrib.str-utils :only [str-join]]))

 (defn make-manifest [project]
-  (doto (str (:root project) "/Manifest.txt")
+  (doto (str (:root project) "/classes/Manifest.txt")
     (spit (str-join "\n"
                     ["Created-By: Leiningen"
                      (str "Built-By: " (System/getProperty "user.name"))


actually still against polluting cljs.reader by default

setting

  :compiler-options {:data-readers true}

will lead to cljs.reader/*tag-table* being populated with the
readers listed in data_readers.clj(c) on the classpath during
compilation.

Not doing this by default since there is no way to tell
if those readers are actually required. Just putting an unresolved
symbol reference in the build makes closure unhappy if the
namespace is not part of the actual build otherwise.

cljs does this by default. I don't like breaking that behavior
but I really don't like this default. Adding a data reader
should be part of user code, not due to some random artifact
being on the classpath.

Does not affect how data readers are handled for compilation or
REPL purposes.

--- src/main/shadow/build.clj
+++ src/main/shadow/build.clj
@@ -463,7 +463,7 @@
 ;; delaying loading via shadow.build.data/maybe-loading-data-readers for regular compilation
 (defn maybe-prepare-data-readers
   [state]
-  (let [cfg (get-in state [:compiler-options :data-readers])]
+  (let [cfg (get-in state [:compiler-options :data-readers] false)]
     (if (or (false? cfg) (::data-readers-loaded state))
       state
       (let [data-readers (ana/get-data-readers)


Modify as-coach to take many arguments and to compose them.

--- src/manners/victorian.clj
+++ src/manners/victorian.clj
@@ -18,9 +18,9 @@

 (defn as-coach
   "Memoize and mark the given function as a coach with the meta {:coach true}."
-  [coach-fn]
+  [& coaching-fns]
   (with-meta
-    (memoize coach-fn)
+    (memoize (apply comp coaching-fns))
     {:coach true}))

 (defn- pred-msg->coach


errors not automatically caught

errors not automatically caught

--- src/mediakeys/hotkeys.clj
+++ src/mediakeys/hotkeys.clj
@@ -17,15 +17,13 @@
 (defn register-keys! [provider keys]
     (observable
         (fn [s]
-            (try
-                (doseq [[action hotkey] keys
-                        n [(println hotkey)]
-                        keystroke [(make-keystroke hotkey)]]
-                    (.register provider keystroke
-                        (proxy [HotKeyListener] []
-                            (onHotKey [event]
-                                (next! s action)))))
-            (catch ))))
+            (doseq [[action hotkey] keys
+                    n [(println hotkey)]
+                    keystroke [(make-keystroke hotkey)]]
+                (.register provider keystroke
+                    (proxy [HotKeyListener] []
+                        (onHotKey [event]
+                            (next! s action))))))))

 (def prstr (comp println str))

@@ -34,8 +32,10 @@
 (defn keypress-events! [key-changes]
     (mapcat key-changes
         (fn [key-update]
-            (let [new-keys (swap! current-keys #(merge % key-update))]
+            (let [new-keys (swap! current-keys #(merge % key-update))
+                  new-provider (Provider/getCurrentProvider false)
+                  result (register-keys! new-provider new-keys)]
                 (.reset @provider)
                 (.stop @provider)
-                (reset! provider (Provider/getCurrentProvider false))
-                (register-keys! @provider new-keys)))))
+                (reset! provider)
+                result))))


Don't use error-kit any more.

Don't use error-kit any more.

--- src/midje/unprocessed.clj
+++ src/midje/unprocessed.clj
@@ -8,7 +8,6 @@
         [midje.checkers.chatty :only [chatty-checker?]]
         [midje.checkers.util]
         [midje.error-handling :only [broken-fake? report-broken-fakes]]
-        clojure.contrib.error-kit
         [clojure.contrib.ns-utils :only [immigrate]]))
 (immigrate 'midje.checkers)


fix response to actually return application/json

--- src/mimic/handler.clj
+++ src/mimic/handler.clj
@@ -1,5 +1,5 @@
 (ns mimic.handler
-  (:require [compojure.core :refer [GET defroutes]]
+  (:require [compojure.core :refer [GET defroutes context]]
             [compojure.route :as route]
             [ring.util.response :as resp]
             [ring.middleware.json :as json-middleware]
@@ -21,7 +21,8 @@

 (defroutes app-routes
   (GET "/" [] (resp/content-type (resp/resource-response "index.html" {:root "public"}) "text/html"))
-  (GET "/champions-by-name" [] (champions-by-name champions-db))
+  (context "/api" []
+           (GET "/champions-by-name" [] (resp/response (champions-by-name champions-db))))
   (route/resources "/")
   (route/not-found "Not Found"))


stop replaying transactions back to people who generated them

--- src/pc/http/sente.clj
+++ src/pc/http/sente.clj
@@ -60,12 +60,12 @@

 (defn notify-transaction [data]
   (let [doc-id (:db/id (:transaction/document data))]
-    (doseq [[uid _] (dissoc (get @document-subs doc-id) (str (:session/uuid data)))]
+    (doseq [[uid _] (dissoc (get @document-subs doc-id) (:session/client-id data))]
       (log/infof "notifying %s about new transactions for %s" uid doc-id)
       ((:send-fn @sente-state) uid [:datomic/transaction data]))
     (when-let [server-timestamps (seq (filter #(= :server/timestamp (:a %)) (:tx-data data)))]
       (log/infof "notifying %s about new server timestamp for %s" (:session/uuid data) doc-id)
-      ((:send-fn @sente-state) (str (:session/uuid data)) [:datomic/transaction (assoc data :tx-data server-timestamps)]))))
+      ((:send-fn @sente-state) (str (:session/client-id data)) [:datomic/transaction (assoc data :tx-data server-timestamps)]))))

 (defn ws-handler-dispatch-fn [req]
   (-> req :event first))


be less verbose

be less verbose

--- src/pc/http/sente.clj
+++ src/pc/http/sente.clj
@@ -106,12 +106,10 @@
     (log/infof "transacting %s on %s for %s" datoms document-id client-uuid)
     (datomic/transact! datoms document-id (UUID/fromString (client-uuid->uuid client-uuid)))))

-(defmethod ws-handler :frontend/mouse-position  [{:keys [client-uuid ?data] :as req}]
+(defmethod ws-handler :frontend/mouse-position [{:keys [client-uuid ?data] :as req}]
   (let [document-id (-> ?data :document/id)
         mouse-position (-> ?data :mouse-position)
         cid (client-uuid->uuid client-uuid)]
-    (log/infof "sending mouse-move on %s for %s" document-id cid)
-    (log/info (get @document-subs document-id))
     (doseq [[uid _] (dissoc (get @document-subs document-id) cid)]
       ((:send-fn @sente-state) uid [:frontend/mouse-move {:client-uuid cid
                                                           :mouse-position mouse-position}]))))


Revert that ungodly cond atrocity into a condp

--- src/constraint/core.cljs
+++ src/constraint/core.cljs
@@ -131,18 +131,14 @@

 (defn handle-button-click
   [clicked-what world-state]
-  (let [clicked-edit?  (re-matches #"edit" clicked-what)
-        clicked-auto?  (re-matches #"auto" clicked-what)
-        clicked-save?  (re-matches #"save" clicked-what)
-        clicked-reset? (re-matches #"manualreset" clicked-what)
-        clicked-flips? (re-matches #"flips" clicked-what)]
-      (cond
-        clicked-edit?  (toggle-editing world-state)
-        clicked-auto?  (toggle-random world-state)
-        clicked-flips? (toggle-flips world-state)
-        clicked-reset? (reset-to-initial world-state)
-        clicked-save?  (remember-initial-state world-state)
-        :else          world-state)))
+  (let [what-to-do (condp re-matches clicked-what
+                     #"edit"        toggle-editing
+                     #"auto"        toggle-random
+                     #"save"        remember-initial-state
+                     #"manualreset" reset-to-initial
+                     #"flips"       toggle-flips
+                     identity)]
+    (what-to-do world-state)))

 (defn clicked-button?


Way more robust scrolling

Way more robust scrolling

* Notes left on (less (!))  frequently after scroll.
* Fixed stupid bug where playing a second simultaneous notes cancelled the first

--- src/playmary/one.cljs
+++ src/playmary/one.cljs
@@ -185,14 +185,15 @@
         (assoc :notes (map (fn [n] (if (note-off? n) (assoc n :off playhead) n)) notes))
         (->> (reduce-val->> stop-piano-key (->> notes (filter note-off?) (map :freq)))))))

-(defn max-scroll-distance
+(defn distance
+  [t instrument]
+  (- (get-in instrument [:cur-touches (t :touch-id) :position :y])
+     (-> t :position :y)))
+
+(defn filter-scroll-touches
   [touches instrument]
-  (let [distances (map (fn [t]
-                         (- (get-in instrument [:cur-touches (t :touch-id) :position :y])
-                            (-> t :position :y)))
-                       (filter-type "touchmove" touches))]
-    (or (first (sort (fn [a b] (max (.abs js/Math a) (.abs js/Math b))) distances))
-        0)))
+  (filter (fn [t] (> (.abs js/Math (distance t instrument)) 10))
+          (filter-type "touchmove" touches)))

 (defn record-touches
   [touches instrument]
@@ -205,18 +206,18 @@
         (update-in [:cur-touches] (fn [c] (apply dissoc c (map :touch-id ends)))))))

 (defn scroll
-  [touches {playhead :playhead :as instrument}]
-  (let [delta-ms (/ (max-scroll-distance touches instrument)
-                    (instrument :px-per-ms))]
-    (if (> (.abs js/Math delta-ms) 20)
-      (-> instrument
-          (assoc :scrolling? true)
-          (assoc :playhead (+ playhead delta-ms)))
-      (assoc instrument :scrolling? false))))
+  [scroll-touches {playhead :playhead px-per-ms :px-per-ms :as instrument}]
+  (if-let [scroll-touch (first (sort (fn [a b] (max (.abs js/Math (distance a instrument))
+                                                    (.abs js/Math (distance b instrument))))
+                                     scroll-touches))]
+    (-> instrument
+        (assoc :scrolling? true)
+        (assoc :playhead (+ playhead (/ (distance scroll-touch instrument) px-per-ms))))
+    (assoc instrument :scrolling? false)))

 (defn delete-scrolled-notes
-  [touches {notes :notes :as instrument}]
-  (let [scroll-touch-ids (set (map :touch-id (filter-type "touchmove" touches)))
+  [scroll-touches {notes :notes :as instrument}]
+  (let [scroll-touch-ids (set (map :touch-id scroll-touches))
         delete-notes (group-by (fn [t] (and (nil? (t :off))
                                             (contains? scroll-touch-ids (t :touch-id))))
                                notes)]
@@ -226,10 +227,11 @@

 (defn handle-scrolling
   [touches instrument]
-  (->> instrument
-       (scroll touches)
-       (record-touches touches)
-       (delete-scrolled-notes touches)))
+  (let [scroll-touches (filter-scroll-touches touches instrument)]
+    (->> instrument
+         (scroll scroll-touches)
+         (delete-scrolled-notes scroll-touches)
+         (record-touches touches))))

 (defn fire-touch-data-on-instrument
   [instrument data]


adding system id and creation is working

--- src/digital/provider.clj
+++ src/digital/provider.clj
@@ -12,6 +12,7 @@
 (ns digital.provider
    "Digital ocean provider"
    (:require
+     [slingshot.slingshot :refer (throw+)]
      [clojure.tools.trace :as tr]
      [digital.validations :refer (provider-validation)]
      [clojure.core.strint :refer (<<)]
@@ -27,14 +28,21 @@

 (defn run-action [type* id]
   (let [post-action (do/generic :post (<< "droplets/~{id}/actions"))]
-    (post-action (hypervisor* :digital-ocean :token) nil  {:type (name type*)}))
+    (post-action (hypervisor* :digital-ocean :token) nil  {:type (name type*)})))
+
+(defn ip [droplet]
+  (get-in droplet [:networks :v4 :ip_address])
   )

-(defrecord Droplet [token spec]
+(defrecord Droplet [token spec ext]
   Vm
   (create [this]
-     (let [{:keys [droplet]} (do/create-droplet token nil spec) {:keys [id]} droplet]
-       (s/partial-system (spec :system-id) {:digital-ocean {:id id}})))
+     (let [{:keys [droplet message] :as result} (do/create-droplet token nil spec) {:keys [id]} droplet]
+       (when-not droplet
+         (throw+ {:type ::droplet-fail} message))
+       (s/partial-system (ext :system-id) {:digital-ocean {:id id}})
+       this
+       ))

   (delete [this])

@@ -64,14 +72,14 @@
      (mappings {:os :image :hostname :name})
      (transform (machine-ts machine))
      (assoc :ssh_keys [(hypervisor* :digital-ocean :ssh-key)])
-     (select-keys drop-ks)
+     (selections [drop-ks [:system-id]] )
      )
   )

 (defmethod vconstruct :digital-ocean [{:keys [digital-ocean machine] :as spec}]
-  (let [translated (translate spec)]
+  (let [[translated ext] (translate spec)]
      (provider-validation translated)
-     (->Droplet (hypervisor* :digital-ocean :token) translated)
+     (->Droplet (hypervisor* :digital-ocean :token) translated ext)
    )
   )

@@ -80,3 +88,4 @@

+; (clojure.pprint/pprint (do/regions (get* :hypervisor :dev :digital-ocean :token)))


clean up code a bit

clean up code a bit

--- src/dot_utility/core.clj
+++ src/dot_utility/core.clj
@@ -2,10 +2,8 @@
   (:require (clojure [string :as str]))
   (:gen-class))

-(def id-sequence (atom 0))
-(defn get-id! [] (str "node" (dosync (swap! id-sequence inc))))
-
-(defn make-node [t l] {:id (get-id!) :level t :label l})
+(let [id-sequence (atom 0)]
+  (defn make-node [t l] {:id (str "node" (dosync (swap! id-sequence inc))) :level t :label l}))

 (defn add-node [g n] (if (g n) g (assoc g n {:next #{} :prev #{}})))

@@ -16,20 +14,16 @@
      (update-in [n1 :next] conj n2)
      (update-in [n2 :prev] conj n1)))

-(defn contains-node? [g n] (g n))
-(defn contains-edge? [g n1 n2] (get-in g [n1 :next n2]))
 (defn next-nodes [g n] (get-in g [n :next]))
 (defn prev-nodes [g n] (get-in g [n :prev]))
 (defn nodes [g] (keys g))

-(defn split-lines [str]
-  (filter (comp not empty?) (str/split str #"\n")))
+(defn split-lines [str] (filter (comp not empty?) (str/split str #"\n")))

 (defn nodify
   [line]
-  (let [stars (count (take-while #(= \* %) line))
-        label (clojure.string/trim (subs line stars))]
-    (if (> stars 0) (make-node stars label))))
+  (let [stars (count (take-while #(= \* %) line))]
+    (if (> stars 0) (make-node stars (clojure.string/trim (subs line stars))))))

 (defn insert-root [nodes] (conj nodes (make-node 0 "Utility")))

@@ -43,39 +37,28 @@
           {}
           (partition 2 1 nodeseq)))

-(defn prolog
-  [g]
-  (println "digraph {
-     rankdir=LR;
-     node[shape=\"plaintext\"];
-     edge[arrowhead=\"none\"];"))
-
-(defn rank
-  [nodes]
+(defn emit-rank
+  [[r nodes]]
   (println "subgraph {\nrank=same;")
   (doseq [n nodes]
     (println (str (:id n) " [label=\"" (:label n) "\"];")))
   (println "}"))

-(defn dependencies
+(defn emit-dependencies
   [g]
   (doseq [n (nodes g)
-        trg (next-nodes g n)]
+          trg (next-nodes g n)]
     (println (str (:id n) "->" (:id trg) ";"))))
-
-(defn epilog
-  [g]
-  (println "}"))
-
-(defn ranks-in [g] (set (map :level (nodes g))))

 (defn emit-dot
   [g]
-  (prolog g)
-  (doseq [r (ranks-in g)]
-    (rank (filter #(= r (:level %)) (nodes g))))
-  (dependencies g)
-  (epilog g))
+  (println "digraph {
+     rankdir=LR;
+     node[shape=\"plaintext\"];
+     edge[arrowhead=\"none\"];")
+  (doall (map emit-rank (sort (group-by :level (keys g)))))
+  (emit-dependencies g)
+  (println "}"))

 (defn -main [& args]
   (doseq [f args]


first implementation.

first implementation.

--- src/fogus/me/trammel.clj
+++ src/fogus/me/trammel.clj
@@ -1,5 +1,28 @@
 (ns fogus.me.trammel
   (:require '[clojure.test :as test]))

-(defmacro defcontract [& specs]
-  nil)
+(defn- build-contract [c]
+  (let [args (first c)]
+    (list
+     (into '[f] args)
+     (apply merge
+            (for [con (rest c)]
+              (cond (= (first con) 'require)
+                    (assoc {} :pre (vec (rest con)))
+                    (= (first con) 'ensure)
+                    (assoc {} :post (vec (rest con)))
+                    :else (throw (Exception. (str "Unknown tag " (first con)))))))
+     (list* 'f args))))
+
+(defn- collect-bodies [forms]
+  (for [form (partition 3 forms)]
+    (build-contract form)))
+
+(defmacro defcontract [& forms]
+  (let [name (if (symbol? (first forms))
+               (first forms)
+               nil)
+        body (collect-bodies (if name
+                               (rest forms)
+                               forms))]
+    (list* 'fn name body)))


Improve local-time and offset-time, including documentation.

--- src/guangyin/core.clj
+++ src/guangyin/core.clj
@@ -99,11 +99,25 @@
   [x] (instance? DayOfWeek x))

 (defn zone-id?
-  "Returns true if the given value is a time zone."
+  "Returns true if the given value is a time zone.
+   Examples:
+
+     => (zone-id? (zone-id \"Europe/Helsinki\"))
+     true
+     => (zone-id? (zone-offset :utc))
+     true
+     => (zone-id? (hours 1))
+     false"
   [x] (instance? ZoneId x))

 (defn zone-offset?
-  "Returns true if the given value is a zone offset."
+  "Returns true if the given value is a zone offset.
+   Examples:
+
+     => (zone-offset? (zone-offset :utc))
+     true
+     => (zone-offset? (zone-id \"Europe/Helsinki\"))
+     false"
   [x] (instance? ZoneOffset x))

 (defn clock?
@@ -274,6 +288,33 @@
    (LocalDate/of year month day-of-month)))

 (defn local-time
+  "Coerce to local time.
+   Can also be used to parse a local time using a custom formatter, or to create
+   a time from hours, minutes, seconds and nanoseconds.
+   Examples:
+
+     => (local-time) ; Current time
+     #<LocalTime 12:15:00.123>
+     => (local-time (clock))
+     #<LocalTime 12:15:00.123>
+     => (local-time (zone-id \"Asia/Shanghai\")) ; Current time in Shanghai
+     #<LocalTime 17:15:00.123>
+     => (local-time \"12:15\")
+     #<LocalTime 12:15>
+     => (local-time \"12:15:00.123\")
+     #<LocalTime 12:15:00.123>
+     => (local-time :noon)
+     #<LocalTime 12:00>
+     => (local-time (local-date-time)) ; Time part of local date-time
+     #<LocalTime 12:15:00.123>
+     => (local-time \"12.15\" (date-time-formatter \"HH.mm\"))
+     #<LocalTime 12:15>
+     => (local-time 12 15)
+     #<LocalTime 12:15>
+     => (local-time 12 15 0)
+     #<LocalTime 12:15>
+     => (local-time 12 15 0 123000000)
+     #<LocalTime 12:15:00.123>"
   ([]
    (LocalTime/now))
   ([x]
@@ -284,10 +325,41 @@
      string? (LocalTime/parse x)
      keyword? (local-time-keywords x)
      :else (LocalTime/from x)))
-  ([text formatter]
-   (LocalTime/parse text formatter)))
+  ([hour-or-text minute-or-formatter]
+   (pred-cond hour-or-text
+     integer? (LocalTime/of hour-or-text minute-or-formatter)
+     :else (LocalTime/parse hour-or-text minute-or-formatter)))
+  ([hour minute second]
+   (LocalTime/of hour minute second))
+  ([hour minute second nano-of-second]
+   (LocalTime/of hour minute second nano-of-second)))

 (defn offset-time
+  "Coerce to time with offset.
+   Can also be used to parse a time with offset using a custom formatter, or to
+   create a time with offset from hours, minutes, seconds and nanoseconds.
+   Examples:
+
+     => (offset-time) ; Current time with offset
+     #<OffsetTime 12:15:00.123+03:00>
+     => (offset-time (clock))
+     #<OffsetTime 12:15:00.123+03:00>
+     => (offset-time (zone-id \"Asia/Shanghai\"))
+     #<OffsetTime 17:15:00.123+08:00>
+     => (offset-time \"12:15:00.123+03:00\")
+     #<OffsetTime 12:15:00.123+03:00>
+     => (offset-time :max)
+     #<OffsetTime 23:59:59.999999999-18:00>
+     => (offset-time (offset-date-time))
+     #<OffsetTime 12:15:00.123+03:00>
+     => (offset-time (local-time 12 15) (zone-offset (hours 3)))
+     #<OffsetTime 12:15+03:00>
+     => (offset-time (instant) (zone-id \"Europe/Helsinki\"))
+     #<OffsetTime 12:15:00.123+03:00>
+     => (offset-time \"12.15+0300\" (date-time-formatter \"HH.mmx\"))
+     #<OffsetTime 12:15+03:00>
+     => (offset-time 12 15 0 123000000 (zone-offset (hours 3)))
+     #<OffsetTime 12:15:00.123+03:00>"
   ([]
    (OffsetTime/now))
   ([x]
@@ -310,7 +382,7 @@
              time-or-instant-or-text
              offset-or-zone-or-formatter)))
   ([hour minute second nano-of-second offset]
-   (OffsetTime/of hour minute second nano-of-second offset)))
+   (OffsetTime/of hour minute second nano-of-second (zone-offset offset))))

 (defn local-date-time
   ([]


Don't rely on buffer? sample? in synth trigger fn as sample? is defined in a namespace that uses synth - so we get recursive nastiness.

--- src/overtone/sc/synth.clj
+++ src/overtone/sc/synth.clj
@@ -296,7 +296,10 @@
           [tgt-fn args] (if (= :ctl (first args))
                           [controller (rest args)]
                           [player args])
-          args (map #(if (buffer? %) (:id %) %) args)
+          args (map #(if (or (isa? (type %) :overtone.sc.core/buffer)
+                             (isa? (type %) :overtone.sc.core/sample))
+                       (:id %) %) args)
+
           named-args (if (keyword? (first args))
                        args
                        (name-synth-args args arg-names))]


Close editor when stop db editing

Close editor when stop db editing

Done by setting the UI state [:ui :editing-database] to false

--- idecode/myappshare/mainapp.cljs
+++ idecode/myappshare/mainapp.cljs
@@ -470,12 +470,14 @@
                  :className (str "btn-lg btn-default" )
                  :aria-hidden "true"
                  :onClick     (fn [x]
-                                  (js/setAllBlocksToEditable nil))
+                                (do
+                                  (js/setAllBlocksToEditable nil)
+                                  (set_edit_database_mode  false)
+                                  ))
                 } "Stop Editing")
          )

     :else
-    (div nil (str "edit: " (get-in @app-state [:ui :editing-database]))
     (iframe {:id "appframe" :frameBorder "0"
              :style {:display "inline-block"}
              :src
@@ -485,7 +487,7 @@

                     :else
                     "http://appshare.co/appshare")
-                  "/devclient.html") :width "600" :height "800"}))))
+                  "/devclient.html") :width "600" :height "800"})))


Analyze text, beginning.

Analyze text, beginning.

--- src/shokunin/word.clj
+++ src/shokunin/word.clj
@@ -1,6 +1,7 @@
 (ns shokunin.word
   (:require [clojure.string :refer [lower-case split-lines]]))

+(def tokenize (partial re-seq #"(?:\w[\w\-\']*)"))

 (defn term-frequency
   "Count occurrences of terms in a sequence of string."
@@ -29,3 +30,25 @@
                                 "resources/01/stop.txt")]
     (println (take 10 (sort-by last > tf)))
     (println (take 10 (sort-by first compare tf)))))
+
+
+(defn n-gram
+  "Um. Create n-gram from a word seq."
+  [n word-seq]
+  (partition-all n 1 word-seq))
+
+
+(defn word-link
+  "Turn a tri-gram into a word-chain entry."
+  [[t1 t2 t3]]
+  {[t1 t2] (if t3 #{t3} #{})})
+
+
+(defn word-chain
+  "Use everything but the last word in an n-gram as a key to the set of words that follow them."
+  [n word-seq]
+  (let [tri-grams (n-gram 3 word-seq)]
+    (apply merge-with clojure.set/union (map word-link tri-grams))))
+
+(word-chain 3 (tokenize (slurp "resources/01/declaration.txt")))
+


Successfully compiling state machine in Clojure

It doesn't do a whole lot yet, but this is just a proof of concept.

--- src/state-machine.clj
+++ src/state-machine.clj
@@ -1,5 +1,6 @@
 (ns state-machine
-  (:use computer-build.vhdl clojure.contrib.pprint))
+  (:use computer-build.vhdl clojure.contrib.pprint)
+  (:refer-clojure :rename {:name :keyword-to-str}))

 (defn state-machine [name inputs outputs states transitions]
 	"Create a state machine that operates from the given inputs, triggering
@@ -10,12 +11,18 @@
 	`(entity ~(gensym name)
           ; Ports
           ~(concat ['(:clock :in "std_logic")] inports outports)
+          ; Definitions
+          ((deftype "STATE_TYPE" ~(map #(str "state_" (keyword-to-str %)) (keys states)))
+          (signal "state" "STATE_TYPE"))
           ; Behavior
-          (process ~(conj inputs :clock) ()))))
+          (process ~(conj inputs :clock)
+                   (if (and (event :clock) (= :clock "'1'"))
+                     (case :state
+                           "state_on" (<= :bulb "1")))))))

 (def my-sm (state-machine "pushbutton" [:push] [:bulb]
-               {:on '(<= :bulb "1") :off '(<= :bulb "0")}
-               [
+               {:on '(<= :bulb "1") :off '(<= :bulb "0")} ; states
+               [ ; transitions
                 '(:on (= :push "1") :off)
                 '(:off (= :push "0") :on)
                 ]))


Use :reload instead of :reload-all in test skeleton.

--- src/leiningen/new.clj
+++ src/leiningen/new.clj
@@ -24,7 +24,7 @@
   (.mkdirs (.getParentFile (file project-dir "test" (ns->path test-ns))))
   (spit (file project-dir "test" (ns->path test-ns))
         (str "(ns " (str test-ns)
-             "\n  (:use [" project-ns "] :reload-all)"
+             "\n  (:use [" project-ns "] :reload)"
              "\n  (:use [clojure.test]))\n\n"
              "(deftest replace-me ;; FIXME: write\n  (is false "
              "\"No tests have been written.\"))\n")))


Don't create single-segment namespaces in the "lein new" skeleton.

--- src/leiningen/new.clj
+++ src/leiningen/new.clj
@@ -18,7 +18,7 @@
                   "  :description \"FIXME: write\"\n"
                   "  :dependencies [[org.clojure/clojure \"1.1.0\"]\n"
                   "                 [org.clojure/clojure-contrib \"1.1.0\"]])"))
-       (let [project-ns  (.replace (str project-name) "/" ".")
+       (let [project-ns  (str (.replace (str project-name) "/" ".") ".core")
              project-clj (str (apply str (replace {\- \_, \. \/} project-ns))
                               ".clj")
              test-clj (.replace project-clj ".clj" "_test.clj")]


test request sooner for prerenderer

test request sooner for prerenderer

--- src/name_bazaar/ui/core.cljs
+++ src/name_bazaar/ui/core.cljs
@@ -55,5 +55,6 @@
                                      :dispatch-to [:active-page-changed]}
                     :dispatch-n [[:setup-update-now-interval]
                                  [:district0x/load-conversion-rates [:USD]]
-                                  [:district0x.config/load]]}}])
+                                 [:district0x.config/load]
+                                 [:offerings.total-count/load]]}}])
   (mount-root))


fix loading errors

fix loading errors


Use the fromArray method for read speed up

--- src/longshi/core.cljs
+++ src/longshi/core.cljs
@@ -159,13 +159,13 @@
      (read-object reader))
    "map"
    (fn [reader tag component-count]
-     (apply hash-map (read-object reader)))
+     (cljs.core/PersistentArrayMap.fromArray (read-object reader)))
    "set"
    (fn [reader tag component-count]
-     (into #{} (read-object reader)))
+     (cljs.core/PersistentHashSet.fromArray (read-object reader)))
    "vector"
    (fn [reader tag component-count]
-     (into [] (read-object reader)))})
+     (cljs.core/PersistentVector.fromArray (read-object reader)))})
 (defn create-reader [input-stream & {:keys [handlers checksum?]}]
   "Creates a fressian reader


defonce app-state

defonce app-state

--- src/chat/client/store.cljs
+++ src/chat/client/store.cljs
@@ -1,21 +1,22 @@
 (ns chat.client.store
   (:require [cljs-utils.core :refer [flip]]))

-(def app-state (atom {:threads {}
-                      :users {}
-                      :tags {}
-                      :groups {}
-                      :session nil
-                      :error-msg nil
-                      :invitations []
-                      :notifications {:window-visible? true
-                                      :unread-count 0}
-                      :user {:open-thread-ids #{}
-                             :subscribed-tag-ids #{}
-                             :user-id nil
-                             :nickname nil}
-                      :open-thread-ids #{}
-                      :search-results {}}))
+(defonce app-state
+  (atom {:threads {}
+         :users {}
+         :tags {}
+         :groups {}
+         :session nil
+         :error-msg nil
+         :invitations []
+         :notifications {:window-visible? true
+                         :unread-count 0}
+         :user {:open-thread-ids #{}
+                :subscribed-tag-ids #{}
+                :user-id nil
+                :nickname nil}
+         :open-thread-ids #{}
+         :search-results {}}))

 (defn- key-by-id [coll]
   (reduce (fn [memo x]


rewrite sourceMappingURL with full path so source maps can be found for 3rd party plugins

--- src/lt/util/load.cljs
+++ src/lt/util/load.cljs
@@ -8,14 +8,30 @@

 (def ^:dynamic *force-reload* false)

+(def fpath (js/require "path"))
+
+(def separator (.-sep fpath))
+
 (defn absolute? [path]
   (boolean (re-seq #"^\s*[\\\/]|([\w]+:[\\\/])" path)))

 (defn node-module [path]
   (js/require (str pwd "/core/node_modules/" path)))

+(defn- abs-source-mapping-url [code file]
+  (if-let [path-to-source-map (second (re-find #"\n//# sourceMappingURL=(.*)" code))]
+    (if-not (absolute? path-to-source-map)
+      (let [abs-path-to-source-map (->> path-to-source-map
+                          (string/replace-first file (re-pattern (str "[^" separator "]*$")))
+                          js/encodeURI)]
+        (string/replace-first code #"\n//# sourceMappingURL=.*" (str "\n//# sourceMappingURL=" abs-path-to-source-map)))
+      code)
+    code))
+
 (defn- prep [code file]
-  (str code "\n\n//# sourceURL=" file))
+  (-> code
+      (abs-source-mapping-url file)
+      (str "\n\n//# sourceURL=" file)))

 (defn js
   ([file] (js file false))


Parameter not renamed in group-societ? Correcting

--- src/civs/model/society.clj
+++ src/civs/model/society.clj
@@ -42,7 +42,7 @@
 (defn band-society? [group]
   (= :band (.society group)))

-(defn group-society? [tribe]
+(defn group-society? [group]
   (= :tribe (.society group)))

 (defn chiefdom-society? [group]


build protos before compiling

build protos before compiling

--- src/clj/protobuf/tasks.clj
+++ src/clj/protobuf/tasks.clj
@@ -84,6 +84,7 @@
   (for [file (rest (file-seq dir)) :when (.endsWith (.getName file) ".proto")]
     (.substring (.getPath file) (inc (count (.getPath dir))))))

+(deftask compile #{proto})
 (deftask proto
   (if (= "clojure-protobuf" (:artifact-id project))
     (do (run-task 'fetch-protoc)


custom diff impl, we don't want to diff seqs

--- src/cljc/commos/delta.cljc
+++ src/cljc/commos/delta.cljc
@@ -1,6 +1,5 @@
 (ns commos.delta
   (:require [clojure.set :as set]
-            [clojure.data :as data]
             [commos.shared.core :refer [flatten-keys]]))

 (def ^:private kw-identical?
@@ -67,12 +66,52 @@
                        [[:is full-ks v]])))]
     (mapcat (partial step []) (flatten-keys m))))

+(defn- diff
+  [a b]
+  (if (= a b)
+    [nil nil]
+    (cond (and (map? a)
+               (map? b))
+          (reduce
+           (fn [[in-a in-b :as acc] k]
+             (let [v-in-a (get a k :sentinel)
+                   v-in-b (get b k :sentinel)]
+               (cond
+                 (kw-identical? v-in-a :sentinel)
+                 (assoc-in acc [1 k] v-in-b)
+
+                 (kw-identical? v-in-b :sentinel)
+                 (assoc-in acc [0 k] v-in-a)
+
+                 (not= v-in-a v-in-b)
+                 (if (or (nil? v-in-a)
+                         (nil? v-in-b))
+                   (-> acc
+                       (assoc-in [0 k] v-in-a)
+                       (assoc-in [1 k] v-in-b))
+
+                   (let [[v-in-a v-in-b] (diff v-in-a v-in-b)]
+                     (cond-> acc
+                       v-in-a (assoc-in [0 k] v-in-a)
+                       v-in-b (assoc-in [1 k] v-in-b))))
+
+                 true
+                 acc)))
+           [nil nil]
+           (eduction (distinct) (concat (keys a) (keys b))))
+          (and (set? a)
+               (set? b))
+          [(not-empty (set/difference a b))
+           (not-empty (set/difference b a))]
+          :else
+          [a b])))
+
 (defn difference
   "Returns difference between x and y in raw deltas.  Adding the
   returned deltas to x gives y."
   [x y]
   (cond (and (map x) (map? y))
-        (let [[neg pos _] (data/diff x y)]
+        (let [[neg pos] (diff x y)]
           (concat (subtractive-deltas neg)
                   (additive-deltas pos)))


Moving TODO comment to more appropriate location

--- src/cljs/zetawar/data.cljs
+++ src/cljs/zetawar/data.cljs
@@ -282,7 +282,6 @@
             :zoc
             [:personnel :armored]}}}})

-;; TODO: add support for :allowed-unit-types
 ;; TODO: remove redundant id keys (?)
 (def maps
   {:sterlings-aruba
@@ -1185,6 +1184,7 @@
     }
    })

+;; TODO: add support for :allowed-unit-types
 (def scenarios
   {:sterlings-aruba-multiplayer
    {:id :sterlings-aruba-multiplayer


rename bottom section of parser

rename bottom section of parser


Forgot to add common.clj - oops.

Forgot to add common.clj - oops.

--- src/clojars/web/common.clj
+++ src/clojars/web/common.clj
@@ -14,6 +14,9 @@
   (html5
    [:html {:lang :en}
     [:head
+     [:link {:type "application/opensearchdescription+xml"
+	      :href (resolve-uri "opensearch.xml")
+	      :rel "search"}]
      [:meta {:charset "utf-8"}]
      [:title
       (when title


Force typekit to use https

Force typekit to use https

closes clojars/clojars-web#496

--- src/clojars/web/common.clj
+++ src/clojars/web/common.clj
@@ -103,7 +103,7 @@
          ;; (then the default colors were removed)
          ;; more info: http://getbootstrap.com/css/#grid
          ["reset.css" "vendor/bootstrap/bootstrap.css" "screen.css"])
-    (include-js "//use.typekit.net/zhw0tse.js")
+    (include-js "https://use.typekit.net/zhw0tse.js")
     (typekit-js)
     (google-analytics-js)
     (raw (when-ie (include-js "/js/html5.js")))]
@@ -174,7 +174,7 @@
          ;; (then the default colors were removed)
          ;; more info: http://getbootstrap.com/css/#grid
          ["reset.css" "vendor/bootstrap/bootstrap.css" "screen.css"])
-    (include-js "//use.typekit.net/zhw0tse.js")
+    (include-js "https://use.typekit.net/zhw0tse.js")
     (typekit-js)
     (google-analytics-js)
     (raw (when-ie (include-js "/js/html5.js")))]


Revert "redirect fix"

Revert "redirect fix"

This reverts commit 4cd5174c7961efbb0b0f9abf3d6b31e184850827.

--- src/clojure/nossal/app.clj
+++ src/clojure/nossal/app.clj
@@ -43,8 +43,6 @@
     (route/not-found (slurp (io/resource "404.html")))))

-(assoc secure-site-defaults :proxy true)
-
 (def app
   (routes (-> app-routes (wrap-routes wrap-defaults secure-site-defaults))))


Tweak Path coercion.

Tweak Path coercion.

--- src/clojure/parkour/fs.clj
+++ src/clojure/parkour/fs.clj
@@ -23,40 +23,40 @@
   (let [w (vary-meta w assoc :tag `Writer)]
     `(do ~@(map (fn [x] `(. ~w write ~(if (string? x) x `(str ~x)))) forms))))

+(defn path?
+  "True iff `x` is a Path."
+  [x] (instance? Path x))
+
 (defn path
   "Coerce argument(s) to a Path, resolving successive arguments against base."
   {:tag `Path}
-  ([x] (-path x))
-  ([x y] (Path. (-path x) (str y)))
+  ([x] (if (path? x) x (-path x)))
+  ([x y] (Path. (path x) (str y)))
   ([x y & more] (apply path (path x y) more)))

 (defn path-array
   "Array of `Path`s for each entry in seq `ps`."
-  {:tag `"[Lorg.apache.hadoop.fs.Path;"}
+  {:tag "[Lorg.apache.hadoop.fs.Path;"}
   [ps] (into-array Path (map path ps)))

 (defmethod print-method Path [x w] (write-all w "#hadoop.fs/path \"" x "\""))
 (defmethod print-dup Path [x w] (write-all w "#hadoop.fs/path \"" x "\""))

-(defn path?
-  "True iff `x` is a Path."
-  [x] (instance? Path x))
+(defn uri?
+  "True iff `x` is a URI."
+  [x] (instance? URI x))

 (defn uri
   "Coerce argument(s) to a URI, resolving successive arguments against base."
   {:tag `URI}
-  ([x] (-uri x))
+  ([x] (if (uri? x) x (-uri x)))
   ([x y]
-     (let [x (-uri x)]
+     (let [x (uri x)]
        (-> x (.resolve (str (.getPath x) "/")) (.resolve (str y)))))
   ([x y & more] (apply uri (uri x y) more)))

 (defmethod print-method URI [x w] (write-all w "#java.net/uri \"" x "\""))
 (defmethod print-dup URI [x w] (write-all w "#java.net/uri \"" x "\""))
-
-(defn uri?
-  "True iff `x` is a URI."
-  [x] (instance? URI x))

 (defn path-fs
   "Hadoop filesystem for the path `p`."
@@ -102,21 +102,21 @@

 (defn path-glob
   "Expand path glob `p` to set of matching paths."
-  ([p] (path-glob (path-fs p) p))
+  ([p] (let [p (path p)] (path-glob (path-fs p) p)))
   ([fs p]
      (->> (.globStatus ^FileSystem fs (path p))
           (map #(.getPath ^FileStatus %)))))

 (defn path-list
   "List the entries in the directory at path `p`."
-  ([p] (path-list (path-fs p) p))
+  ([p] (let [p (path p)] (path-list (path-fs p) p)))
   ([fs p]
      (->> (.listStatus ^FileSystem fs (path p))
           (map #(.getPath ^FileStatus %) ))))

 (defn path-delete
   "Recursively delete files at path `p`."
-  ([p] (path-delete (path-fs p) p))
+  ([p] (let [p (path p)] (path-delete (path-fs p) p)))
   ([fs p] (.delete ^FileSystem fs (path p) true)))

 (defn path-exists?
@@ -129,7 +129,7 @@

 (defn path-map
   "Return map of file basename to full path for all files in `dir`."
-  ([dir] (path-map (path-fs dir) dir))
+  ([dir] (let [dir (path dir)] (path-map (path-fs dir) dir)))
   ([fs dir]
      (let [dir (path dir)]
        (->> (.listStatus ^FileSystem fs dir)
@@ -156,7 +156,7 @@

 (defn path-create
   "Create an output stream on `p` for `fs`, or default `fs` if not provided."
-  ([p] (path-create (path-fs p) p))
+  ([p] (let [p (path p)] (path-create (path-fs p) p)))
   ([fs p] (.create ^FileSystem fs (path p))))

 (extend Path


performed some simple smoke tests; fixed obvious errors

--- src/clojure/ronin/core.clj
+++ src/clojure/ronin/core.clj
@@ -74,44 +74,47 @@
       [:create :write])

 When finished, be sure to `.close` it."
-  [db specs modes]
+  [^DB db specs modes]
   (let [needs-filename #{:file-hash
                          :file-tree
                          :directory-hash
                          :directory-tree
                          :plain-text}

-        db-type (do (assert (keyword? (:type specs))
-                            ":type needs to be a keyword")
-                    (assert (not (nil? (get db-specs (:type specs))))
+        db-type (do (println "checking DB type")
+                  (assert (not (nil? (get db-specs (:type specs))))
                             ":type needs to be found in db-specs")
                     (:type specs))

-        db-file (if (some needs-filename db-type)
-                  (do (assert (string? (:filename specs))
-                              ":filename needs to be a string")
-                      (assert (not= "" (:filename specs))
-                              ":filename cannot be an empty string")
-                      (str (:filename specs) (get db-specs db-type)))
-                  (get db-specs db-type))
-
-        tuned-db-file (if (and (map? (:tuning specs))
-                               (not (empty? (:tuning specs))))
-                        (-> (:tuning specs)
-                            (map (fn [[k v]] (str k "=" v)))
-                            (reduce #(str %1 "#" %2))
-                            (str db-file "#"))
-                        db-file)
+        db-file (do (println "checking db file")
+                    (if (some needs-filename [(:type specs)])
+                      (do (assert (string? (:filename specs))
+                                  ":filename needs to be a string")
+                          (assert (not= "" (:filename specs))
+                                  ":filename cannot be an empty string")
+                          (str (:filename specs) (get db-specs db-type)))
+                      (get db-specs db-type)))
+
+        tuned-db-file (do (println "checking tuning")
+                          (if (and (map? (:tuning specs))
+                                   (not (empty? (:tuning specs))))
+                            (->> (:tuning specs)
+                                 (map (fn [[k v]] (str k "=" v)))
+                                 (reduce #(str %1 "#" %2))
+                                 (str db-file "#"))
+                            db-file))

-        db-modes (do (assert (vector? modes)
-                             ":modes must be a vector")
-                     (assert (-> (map #(get open-options %) modes)
-                                 (map number?)
-                                 (reduce #(and %1 %2)))
+        db-modes (do (println "checking modes")
+                     (assert (vector? modes)
+                             "modes must be a vector")
+                     (assert (->> (map #(get open-options %) modes)
+                                  (map number?)
+                                  (reduce #(and %1 %2)))
                              "every specified mode must be in `open-options`")
-                     (-> (map #(get open-options %) modes)
-                         (apply bit-or 0)))]
-
+                     (->> (map #(get open-options %) modes)
+                          (apply bit-or 0)))]
+
+    (println "done checking stuff")
     (.open db tuned-db-file db-modes)
     db))

@@ -151,9 +154,10 @@
 initial parameters, with simlar syntax to `let`.

 An example would be merging hashes of people and animals together to see
-who owns which pet, assuming that Ronin is being used as a graph database:
-
-    (with-dbs [merged {:type :cache-hash :modes [:create :write :read]
+who owns which pet, assuming that Ronin is being used to drive a graph
+database:
+
+    (with-dbs [merged {:type :cache-hash :modes [:create :write :read]}
                people (assoc people-spec :modes [:read])
                animals (assoc animal-spec :modes [:read])]
       (merge-dbs! :add merged people animals)
@@ -164,7 +168,7 @@
           "dbs-and-specs must not be empty.")
   (assert (even? (count dbs-and-specs))
           "dbs-and-specs must be of even length")
-  (if (= 2 (length dbs-and-specs))
+  (if (= 2 (count dbs-and-specs))
     `(with-db ~(vec dbs-and-specs) ~@body)
     `(with-db ~(vec (take 2 dbs-and-specs))
        (with-dbs ~(drop 2 dbs-and-specs)
@@ -183,3 +187,36 @@
             "must be expressable as EDN")
     cand))

+(defn add-bin!
+  "Adds a binary key and value to an open DB.  If the key exists, then
+there is no change to the DB.
+
+Returns `true` if it succeeds, `false` on an error."
+  [^DB db ^bytes key ^bytes value]
+  (.add db key value))
+
+(defn add-edn!
+  "Adds a string key and a Clojure data structure to an open DB.  It
+uses `add-bin!` to do the heavy-lifting (which there isn't any).  If
+the key already exists in the database, then there is no change.
+
+Returns `true` on success, `false` on an error."
+  [^DB db ^String key value]
+  (add-bin! db (.getBytes key)
+            (bytes (.getBytes (edn-str value)))))
+
+(defn get-bin!
+  "Gets binary data from an open DB using a binary key.
+
+Returns a byte array on success, 'nil' if it errors."
+  [^DB db ^bytes key]
+  (.get db key))
+
+(defn get-edn!
+  "Gets parsed Clojure data from an open DB using a string key.
+
+Returns Clojure on success, 'nil' if it errors."
+  [^DB db ^String key]
+  (if-let [^bytes result (get-bin! db (.getBytes key))]
+    (-> (String. result)
+        edn/read-string)))


Attempt to introduce some pseudo-random object sizes to be less nice to CMS.

--- src/org/scode/httpgctest.clj
+++ src/org/scode/httpgctest.clj
@@ -33,7 +33,8 @@
                " a fairly long semi-unique string that is hopefully not very small in"
                " comparison to the set structure itself, thus making this test a bit"
                " more useful in testing gc behavior. this string plus the map we are"
-               " returning should hopefully be enough")}))
+               " returning should hopefully be enough")
+     :frag-grendade (apply str r (repeat (* (rand) 25) "kaboom"))}))

 (defn serve-gendata [request]
   (let [amount (let [amstr (:amount (:query-params request))]


re-encode csv source with edn

re-encode csv source with edn

--- src/quark/tree_tokenizer.clj
+++ src/quark/tree_tokenizer.clj
@@ -7,6 +7,8 @@
             [schema.core :as s]
             [clojure.pprint :refer [pprint]]
             [clojure.string :as str]
+            [clojure.data.csv :as csv]
+            [clojure.java.io :as io]
             [swiss.arrows :refer :all]
             )
   (:import
@@ -62,8 +64,17 @@
     (clojure.java.io/make-parents out-filename)
     (->> src-filename parse-file to-edn (spit out-filename))))

-'((time-mins (src-dir-to-edn linux-path "tmp/src-to-edn/linux3")))
-
 '((time-mins (src-dir-to-edn linux-path "tmp/src-to-edn/linux4")))

+(defn src-csv-to-edn
+  [csv-path column-name]
+  (with-open [reader (io/reader csv-path)
+              writer (io/writer (str csv-path ".edn"))]
+    (let [[header & csv-data] (csv/read-csv reader)
+          code-idx (.indexOf header column-name)
+          edn-data (map #(update-in % [code-idx] (comp to-edn parse-source)) csv-data)]
+     (csv/write-csv writer (cons header edn-data))
+      )))

+
+'((time-mins (src-csv-to-edn "tmp/context_study_code.csv" "Code")))


profile -> profiler

profile -> profiler

--- src/riemann/jvm_profiler.clj
+++ src/riemann/jvm_profiler.clj
@@ -18,7 +18,7 @@
          stack/hotspots
          (map (fn [[^StackTraceElement frame
                     {:keys [self-time top-trace top-trace-time]}]]
-                {:service     (str prefix "profile fn "
+                {:service     (str prefix "profiler fn "
                                    (.getClassName frame) " "
                                    (.getMethodName frame))
                  :file        (.getFileName frame)
@@ -28,7 +28,7 @@
                  :metric      self-time
                  :ttl         (* 2 dt)
                  :tags        tags}))
-         (concat [{:service (str prefix "profile rate")
+         (concat [{:service (str prefix "profiler rate")
                    :state   "ok"
                    :metric  rate
                    :ttl     (* 2 dt)


remove

remove

--- src/simple/combinatorics.clj
+++ src/simple/combinatorics.clj
@@ -1,2 +0,0 @@
-(ns simple.combinatorics
-  (:use [maths.cartesian]))


Started at -> Started

Started at -> Started

--- src-cljs/frontend/components/builds_table.cljs
+++ src-cljs/frontend/components/builds_table.cljs
@@ -92,7 +92,7 @@
             [:th "Branch"])
           [:th "Triggered by"]
           [:th "Log"]
-          [:th.condense "Started at"]
+          [:th.condense "Started"]
           [:th.condense "Length"]
           [:th.condense "Status"]
           (when show-actions?


Fix uninstall causing extra missing popup

Since the user plugin has all dependencies, uninstalling anything triggers
the missing? popup before we've had a chance to remove the dependency from
the plugin.edn. Added a flag to available-plugins to bypass the popup for
just this case.

--- src/lt/objs/plugins.cljs
+++ src/lt/objs/plugins.cljs
@@ -143,7 +143,8 @@
     (doseq [dep missing]
       (discover-deps dep count-down))))

-(defn available-plugins []
+(defn available-plugins
+  [& {:keys [ignore-missing]}]
   (let [ds (concat (files/dirs user-plugins-dir)
                    (files/dirs plugins-dir)
                    [settings/user-plugin-dir])
@@ -161,12 +162,12 @@
                           plugins)
                   (persistent!))
         missing? (missing-deps final)]
-    (when missing?
+    (when (and missing? (not ignore-missing))
       (popup/popup! {:header "Some plugin dependencies are missing."
                      :body [:div
                             [:span "We found that the following plugin dependencies are missing: "]
-                             (for [{:keys [name version]} missing?]
-                               [:div name " " version " "])
+                            (for [{:keys [name version]} missing?]
+                              [:div name " " version " "])
                             [:span "Would you like us to install them?"]]
                      :buttons [{:label "Cancel"}
                                {:label "Install all"
@@ -538,7 +539,8 @@
           :desc "Saves dependencies to user's plugin.edn"
           :reaction (fn [this]
                       ;; Use available-plugins b/c ::plugins aren't always up to date e.g. uninstall
-                      (save-plugins (available-plugins))))
+                      ;; :ignore-missing to avoid missing popup on uninstall
+                      (save-plugins (available-plugins :ignore-missing true))))

 (behavior ::render-installed-plugins
           :triggers #{:refresh!}


Add popover to function to avoid dupe code

--- src-cljs/frontend/components/builds_table.cljs
+++ src-cljs/frontend/components/builds_table.cljs
@@ -85,6 +85,25 @@
                                                                       :links-to links-to}})}
      "Learn more →"]]])

+(defn build-engine-popover
+  [platform owner]
+  (popover/popover {:title nil
+                    :body (if (= "1.0" platform)
+                            (platform-link {:body-text "2.0 is coming soon!\n"
+                                            :link "https://circleci.com/beta-access/"
+                                            :links-to "beta-access"
+                                            :owner owner})
+                            (platform-link {:body-text "This build ran on 2.0.\n"
+                                            :link "https://circleci.com/docs/2.0/"
+                                            :links-to "beta-docs"
+                                            :owner owner}))
+                    :placement :left
+                    :trigger-mode :click
+                    :on-show #((om/get-shared owner :track-event) {:event-type :platform-number-popover-impression
+                                                                   :properties {:component "builds-table"
+                                                                                :platform-number platform}})}
+                   [:span.platform platform]))
+
 (defn build-row [{:keys [build project]} owner {:keys [show-actions? show-branch? show-project?]}]
   (let [url (build-model/path-for (select-keys build [:vcs_url]) build)
         build-args (merge (build-model/build-args build) {:component "build-row" :no-cache? false})
@@ -155,23 +174,7 @@
          [:span.recent-log
           {:title (:body build)}
           (:subject build)]]]
-      [:div.build-engine
-        (popover/popover {:title nil
-                          :body (if (= "1.0" platform)
-                                  (platform-link {:body-text "2.0 is coming soon!\n"
-                                                  :link "https://circleci.com/beta-access/"
-                                                  :links-to "beta-access"
-                                                  :owner owner})
-                                  (platform-link {:body-text "This build ran on 2.0.\n"
-                                                  :link "https://circleci.com/docs/2.0/"
-                                                  :links-to "beta-docs"
-                                                  :owner owner}))
-                          :placement :left
-                          :trigger-mode :click
-                          :on-show #((om/get-shared owner :track-event) {:event-type :platform-number-popover-impression
-                                                                         :properties {:component "builds-table"
-                                                                                :platform-number platform}})}
-                         [:span.platform platform])]]
+      [:div.build-engine.screen-md-down (build-engine-popover platform owner)]]

      [:div.metadata
       [:div.metadata-row.timing
@@ -199,23 +202,7 @@
       [:div.metadata-row.pull-revision
        (om/build pull-requests {:build build})
        (om/build commits {:build build})]]
-     [:div.build-engine
-      (popover/popover {:title nil
-                        :body (if (= "1.0" platform)
-                                (platform-link {:body-text "2.0 is coming soon!\n"
-                                                :link "https://circleci.com/beta-access/"
-                                                :links-to "beta-access"
-                                                :owner owner})
-                                (platform-link {:body-text "This build ran on 2.0.\n"
-                                                :link "https://circleci.com/docs/2.0/"
-                                                :links-to "beta-docs"
-                                                :owner owner}))
-                        :placement :left
-                        :trigger-mode :click
-                        :on-show #((om/get-shared owner :track-event) {:event-type :platform-number-popover-impression
-                                                                       :properties {:component "builds-table"
-                                                                                :platform-number platform}})}
-        [:span.platform platform])]]))
+     [:div.build-engine.screen-md-up (build-engine-popover platform owner)]]))

 (defn job-waiting-badge
   "badge for waiting job."


First draft for plan overview page.

First draft for plan overview page.

Conflicts:
	src-cljs/frontend/components/org_settings.cljs

--- src-cljs/frontend/components/org_settings.cljs
+++ src-cljs/frontend/components/org_settings.cljs
@@ -871,11 +871,27 @@
                   "Cancel Plan"])))]]])))))

 (defn overview [app owner]
-  (reify
-    om/IRender
-    (render [_]
-      (html
-       [:div "hello world"]))))
+  (om/component
+   (html
+    (let [org-name (get-in app state/org-name-path)
+          plan (get-in app state/org-plan-path)
+          plan-total (pm/stripe-cost plan)
+          container-cost (pm/per-container-cost plan)
+          price (-> plan :paid :template :price)]
+      [:div
+       [:fieldset [:legend (str org-name "'s plan")]]
+       [:div.explanation
+        [:p
+         (str "Your builds will be distributed across " (pm/usable-containers plan) " containers.")]
+        (when (pm/paid? plan)
+          [:p
+           (str (pm/paid-containers plan) " of these are paid, at $" (pm/stripe-cost plan) "/month. ")
+           "You can "
+           [:a {:href "#containers"} "add more"]
+           " at $" container-cost " per container  for more parallelism and shorter queue times."])
+        (when  (pm/freemium? plan)
+          [:p (str (pm/freemium-containers plan) " container is free, forever.")])
+        [:p "Additionally, projects that are public on GitHub will build with " pm/oss-containers " extra containers -- our gift to free and open source software."]]]))))

 (def main-component
   {:overview overview


More docstring

More docstring

--- src/sparql_to_csv/sparql.clj
+++ src/sparql_to_csv/sparql.clj
@@ -23,6 +23,8 @@
 (defn sparql-results->clj
   "Convert SPARQL `results` into Clojure data structures.
   `header?` indicates if header should be output.
+  `base-line` is a row (a vector) of values to which to append newly fetched columns.
+  `base-header` is a header row for the `base-line`.
   Returns an empty sequence when the query has no results."
   [results & {:keys [base-line base-header header?]}]
   (let [zipper (-> results xml/parse-str zip/xml-zip)


Documentation tweak

Documentation tweak

--- src/such/function_makers.clj
+++ src/such/function_makers.clj
@@ -25,7 +25,11 @@
         (has-favs? [1 6]) => true

    Stops checking after the first success. A predicate created from
-   no arguments always returns `true`."
+   no arguments always returns `true`.
+
+   Note: this predates [[some-fn]]. It differs in that it always returns
+   `true` or `false`, and that it allows zero arguments (which produces a
+   function that always returns `true`).
   [& preds]
   (if (empty? preds)
     (constantly true)


Expontential backoff for Metabot reconnection :back:

--- src/metabase/metabot.clj
+++ src/metabase/metabot.clj
@@ -9,6 +9,7 @@
             (manifold [bus :as bus]
                       [deferred :as d]
                       [stream :as s])
+            [throttle.core :as throttle]
             [metabase.db :as db]
             [metabase.integrations.slack :as slack]
             [metabase.models.setting :refer [defsetting], :as setting]
@@ -227,21 +228,44 @@

 ;;; Websocket monitor

-;; Keep track of the Thread ID of the current monitor thread. Monitor threads should check this ID and if it is no longer equal to
-;; theirs they should die
+;; Keep track of the Thread ID of the current monitor thread. Monitor threads should check this ID
+;; and if it is no longer equal to theirs they should die
 (defonce ^:private websocket-monitor-thread-id (atom nil))
+
+;; we'll use a THROTTLER to implement exponential backoff for recconenction attempts, since THROTTLERS are designed with for this sort of thing
+;; e.g. after the first failed connection we'll wait 2 seconds, then each that amount increases by the `:delay-exponent` of 1.3
+;; so our reconnection schedule will look something like:
+;; number of consecutive failed attempts | seconds before next try (rounded up to nearest multiple of 2 seconds)
+;; --------------------------------------+----------------------------------------------------------------------
+;;                                    0  |   2
+;;                                    1  |   4
+;;                                    2  |   4
+;;                                    3  |   6
+;;                                    4  |   8
+;;                                    5  |  14
+;;                                    6  |  30
+;; we'll throttle this based on values of the `slack-token` setting; that way if someone changes its value they won't have to wait
+;; whatever the exponential delay is before the connection is retried
+(def ^:private reconnection-attempt-throttler
+  (throttle/make-throttler nil :attempts-threshold 1, :initial-delay-ms 2000, :delay-exponent 1.3))
+
+(defn- should-attempt-to-reconnect? ^Boolean []
+  (boolean (u/ignore-exceptions
+             (throttle/check reconnection-attempt-throttler (slack/slack-token))
+             true)))

 (defn- start-websocket-monitor! []
   (future
     (reset! websocket-monitor-thread-id (.getId (Thread/currentThread)))
     ;; Every 2 seconds check to see if websocket connection is [still] open, [re-]open it if not
     (loop []
-      (Thread/sleep 500)
+      (while (not (should-attempt-to-reconnect?))
+        (Thread/sleep 2000))
       (when (= (.getId (Thread/currentThread)) @websocket-monitor-thread-id)
         (try
           (when (or (not  @websocket)
                     (s/closed? @websocket))
-            (log/debug "MetaBot WebSocket is closed.  Reconnecting now.")
+            (log/debug "MetaBot WebSocket is closed. Reconnecting now.")
             (connect-websocket!))
           (catch Throwable e
             (log/error "Error connecting websocket:" (.getMessage e))))
@@ -252,7 +276,7 @@

    This will spin up a background thread that opens and maintains a Slack WebSocket connection."
   []
-  (when (and (setting/get :slack-token)
+  (when (and (slack/slack-token)
              (metabot-enabled))
     (log/info "Starting MetaBot WebSocket monitor thread...")
     (start-websocket-monitor!)))


Change copyright email on dsl ns.

Change copyright email on dsl ns.

--- src/suricatta/dsl.clj
+++ src/suricatta/dsl.clj
@@ -1,4 +1,4 @@
-;; Copyright (c) 2014-2015, Andrey Antukh <niwi@niwi.be>
+;; Copyright (c) 2014-2015, Andrey Antukh <niwi@niwi.nz>
 ;; All rights reserved.
 ;;
 ;; Redistribution and use in source and binary forms, with or without


Better name

Better name

--- src/wishlistd/cljs/main.cljs
+++ src/wishlistd/cljs/main.cljs
@@ -165,7 +165,7 @@
     (letrem [neu (delete-wish id)]
       (fn [e] nil))))

-; DELEGATES
+; EVENT LISTENERS

 (on $body :click "#create-wishlist" nil
   (fn [e]


support destructoring in augmented fn-params

--- src/minreact/core.clj
+++ src/minreact/core.clj
@@ -17,9 +17,9 @@
                  :or {this-sym (gensym "this")}} fn-form]
   (let [raw? (= 'raw (second fn-form))
         [fn-name fn-bindings & fn-body] (nthrest fn-form (if raw? 2 1))
-        fn-params (mapv (fn [param]
-                          (gensym (name param)))
-                        fn-bindings)]
+        fn-params (mapv (fn [i]
+                          (gensym (str fn-name "_arg_" i)))
+                        (range (count fn-bindings)))]
     [(name fn-name)
      `(fn ~fn-name
         ~fn-params


Reducing time-interval for heroku

Reducing time-interval for heroku

--- src/engine_server/game.clj
+++ src/engine_server/game.clj
@@ -2,7 +2,7 @@
   (:require [engine-server.engine :refer [next-frame]]
     [engine-server.body-builder :refer :all]))

-(def time-interval 1000)
+(def time-interval 100)
 (def base-planet (with-mass 1e6 body))
 (def base-player (with-mass 1.0 body))
 (def base-positions [[-1000.0 0.0]


Actually use the rolling log appender

Actually use the rolling log appender

--- src/yetibot/core/logging.clj
+++ src/yetibot/core/logging.clj
@@ -14,9 +14,10 @@
 ; (timbre/set-config! [:shared-appender-config :spit-filename] "/var/log/yetibot/yetibot.log")

 ;; rolling log files
-(make-rolling-appender {:enabled? true}
-                       {:path "/var/log/yetibot/yetibot.log"
-                        :pattern :daily})
+(timbre/set-config! [:appenders :rolling]
+                    (make-rolling-appender {:enabled? true}
+                                           {:path "/var/log/yetibot/yetibot.log"
+                                            :pattern :daily}))

 (defn log-to-db
   [{:keys [ap-config level prefix throwable message] :as args}]


Update the app's model according to incoming events.

--- src/fm/simrunner/input.clj
+++ src/fm/simrunner/input.clj
@@ -8,10 +8,29 @@
   (:require
     [fm.simrunner.config :as cfg]))

-(defmulti on-input {:private true} (fn [id & _] id))
+(defn- value->param [id value]
+  (if (= :calc-err id)
+    (if value "1" "0")
+    (str value)))

-(defmethod on-input :default [id app & args]
-  (println (format "on-input{id: %s args: %s}" id args)))
+(defn- update-values [app-state id value]
+  (assoc-in app-state [:ui :model :values id] value))
+
+(defn- update-config [app-state id value]
+  (let [config (-> (get-in app-state [:model :config])
+                   (cfg/with-value id (value->param id value)))]
+    (-> app-state
+        (assoc-in [:model :config] config)
+        (assoc-in [:model :changed?] true)
+        (assoc-in [:model :valid?] (cfg/complete? config)))))
+
+(defn- on-input [id {app-state :state} & [widget value :as args]]
+  (println (format "on-input{id: %s value: %s}" id value))
+  (swap! app-state
+         (fn [app-state]
+           (-> app-state
+               (update-values id value)
+               (update-config id value)))))

 (defn- handle-input? [{app-state :state}]
   (let [{ui :ui} @app-state]


More card implementations

More card implementations

--- src/node/game/cards.cljs
+++ src/node/game/cards.cljs
@@ -9,6 +9,10 @@

    "Akamatsu Mem Chip"
    {:effect (effect (gain :memory 1)) :leave-play (effect (lose :memory 1))}
+
+   "All-nighter"
+   {:abilities [{:cost [:click 1] :effect (effect (trash card) (gain :click 2))
+                 :msg "gain [Click][Click]"}]}

    "Armitage Codebusting"
    {:data {:counter 12}
@@ -89,6 +93,16 @@

    "Easy Mark"
    {:effect (effect (gain :credit 3))}
+
+   "Executive Retreat"
+   {:data {:counter 1}
+    :abilities [{:cost [:click 1] :counter-cost 1
+                 :effect (effect (shuffle-into-deck :hand) (draw 5))}]}
+
+   "Geothermal Fracking"
+   {:data {:counter 2}
+    :abilities [{:cost [:click 1] :counter-cost 1
+                 :effect (effect (gain :credit 7 :bad-publicity 1))}]}

    "Gila Hands Arcology"
    {:abilities [{:cost [:click 2] :effect (effect (gain :credit 3)) :msg "gain 3 [Credits]"}]}
@@ -208,12 +222,24 @@
    {:effect (effect (lose :bad-publicity 2))}

    ;; partial implementation
+   "Adonis Campaign"
+   {:data {:counter 12}}
+
+   "AstroScript Pilot Program"
+   {:data {:counter 1}}
+
    "Astrolabe"
    {:effect (effect (gain :memory 1)) :leave-play (effect (lose :memory 1))}

    "Bad Times"
    {:req (req tagged)}

+   "D4v1d"
+   {:data {:counter 3}}
+
+   "Daily Casts"
+   {:data {:counter 8}}
+
    "Exile: Streethawk"
    {:effect (effect (gain :link 1))}

@@ -229,14 +255,43 @@
    "Early Bird"
    {:req (req (not (:spent-click register)))}

+   "Eden Shard"
+   {:abilities [{:effect (effect (trash card) (draw :corp 2))
+                 :msg "force the Corp to draw 2 cards"}]}
+
+   "Efficiency Committee"
+   {:data {:counter 3}
+    :abilities [{:cost [:click 1] :counter-cost 1 :effect (effect (gain :click 2))
+                 :msg "gain [Click][Click]"}]}
+
    "Emergency Shutdown"
    {:req (req (some :hq (:successful-run register)))}

+   "Eve Campaign"
+   {:data {:counter 16}}
+
+   "Fall Guy"
+   {:abilities [{:effect (effect (trash card) (gain :credit 2)) :msg "gain 2 [Credits]"}]}
+
+
+   "Gorman Drip v1"
+   {:abilities [:effect (effect (gain :credit (:counter card)) (trash card))]}
+
+   "House of Knives"
+   {:data {:counter 3}
+    :abilities [{:cost [:click 1] :counter-cost 1 :effect (effect (damage :net 1))
+                 :msg "do 1 Net damage"}]}
+
    "Iain Stirling: Retired Spook"
    {:effect (effect (gain :link 1))}
+
+   "Imp"
+   {:data {:counter 2}}

    "Freelancer"
    {:req (req tagged)}
+   "Jackson Howard"
+   {:abilities [{:cost [:click 1] :effect (effect (draw 2)) :msg "draw 2 cards"}]}

    "Kate \"Mac\" McCaffrey: Digital Tinker"
    {:effect (effect (gain :link 1))}
@@ -248,6 +303,9 @@
    {:effect (effect (gain :memory 1 :max-hand-size 1))
     :leave-play (effect (lose :memory 1 :max-hand-size 1))}

+   "Mental Health Clinic"
+   {:effect (effect (gain :runner :max-hand-size 1))}
+
    "Midseason Replacements"
    {:req (req (:stole-agenda register))}

@@ -257,6 +315,9 @@
    "Nasir Meidan: Cyber Explorer"
    {:effect (effect (gain :link 1))}

+   "Networking"
+   {:effect (effect (lose :tag 1))}
+
    "Power Shutdown"
    {:req (req (:made-run register))}