replace (first (filter ...)) with (some ...)

--- src/cljs_api_gen/parse.clj
+++ src/cljs_api_gen/parse.clj
@@ -584,7 +584,7 @@
   "Get derived syntax forms from the given forms."
   [items]
   (let [make-sub-item (fn [info]
-                        (when-let [parent (first (filter #(= (:syntax-form %) (:parent info)) items))]
+                        (when-let [parent (some #(= (:syntax-form %) (:parent info)) items)]
                           (merge parent (base-syntax-item info))))
         sub-items (->> syntax
                        (filter :parent)
@@ -640,7 +640,7 @@
                 (>= *cljs-num* 0)    (parse-clj-core)
                 :else nil)
         match? #(= "destructure" (:name %))
-        item (first (filter match? items))]
+        item (some match? items)]
     (-> item
         (dissoc :signature)
         (merge (base-syntax-item (syntax-map "destructure")))
@@ -658,7 +658,7 @@

 (defn get-non-excluded-macro-api
   [forms macro-api]
-  (let [ns-form (first (filter #(= 'ns (first %)) forms))
+  (let [ns-form (some #(= 'ns (first %)) forms)
         get-excludes #(match % ([:refer-clojure :exclude x] :seq) x :else nil)
         macro-names (->> ns-form (drop 2) (keep get-excludes) first (map str) set)]
     (remove #(macro-names (:name %)) macro-api)))
@@ -858,7 +858,7 @@
                       (>= *cljs-num* 1933) {:ns "special" :name "try"}
                       (>= *cljs-num* 0)    {:ns "cljs.core" :name "try"}
                       :else nil)
-        try-form (first (filter #(= (select-keys % [:ns :name]) try-ns-name) parsed))
+        try-form (some #(= (select-keys % [:ns :name]) try-ns-name) parsed)
         get-sigs (fn [name-]
                    ;; parse docstring for signature of `catch` and `finally`:
                    ;;


Remove 30 day limit wording for audit

Remove 30 day limit wording for audit

We no longer truncate audit logs.

See #812.

--- src/clojars/web/common.clj
+++ src/clojars/web/common.clj
@@ -399,7 +399,7 @@
 (defn audit-table
   [db subject lookup]
   [:div
-   [:h2 (format "Audit Log for %s (for last 30 days)" subject)]
+   [:h2 (format "Audit Log for %s" subject)]
     [:table.audit
      [:tr
       [:th "Tag"]


Document util ns

Document util ns

--- src/caesium/util.clj
+++ src/caesium/util.clj
@@ -1,4 +1,5 @@
 (ns caesium.util
+  "Internal utilities."
   (:import (java.util Arrays)
            (org.abstractj.kalium.encoders Encoder)))


changing to trace

changing to trace

--- src/celestial/jobs.clj
+++ src/celestial/jobs.clj
@@ -72,6 +72,6 @@
 (defn shutdown-workers []
   (doseq [[k ws] @workers]
     (doseq [w ws]
-      (debug "shutting down" k w)
+      (trace "shutting down" k w)
       (mq/stop w))))


Put sql params into Java array in run-sql

--- src/clj/cglossa/db.clj
+++ src/clj/cglossa/db.clj
@@ -42,11 +42,13 @@
     (walk/keywordize-keys $)))

 (defn run-sql
-  ([sql] (run-sql sql []))
+  ([sql]
+   (run-sql sql []))
   ([sql sql-params]
-   (let [graph (get-graph)
-         cmd   (OCommandSQL. sql)]
-     (.. graph (command cmd) (execute sql-params)))))
+   (let [graph  (get-graph)
+         cmd    (OCommandSQL. sql)
+         params (into-array sql-params)]
+     (.. graph (command cmd) (execute params)))))

 (defn sql-query
   "Takes an SQL query and optionally a map of parameters, runs it against the
@@ -84,7 +86,7 @@
                             "String params should be provided in a map")
          _          (doseq [s (vals strings)] (assert (not (re-find #"[\W]" s))
                                                       (str "Invalid string param: " s)))
-         sql-params (into-array (:sql-params params))
+         sql-params (:sql-params params)
          sql*       (-> sql
                         (str/replace #"\&(\w+)" #(get strings (keyword (second %))))
                         (str/replace #"#TARGETS?" (str "[" (str/join ", " targets) "]")))


Formatting

Formatting

--- src/clj/cglossa/db.clj
+++ src/clj/cglossa/db.clj
@@ -17,9 +17,9 @@
   (instance? OIdentifiable o))

 (defn stringify-rid [rid]
-  "When we ask for @rid in an SQL query, the value we get for the 'rid' property is
-  actually the entire record object. This function converts it into the string
-  representation of the record's @rid (e.g. 12:0)"
+  "When we ask for @rid in an SQL query, the value we get for the 'rid'
+  property is actually the entire record object. This function converts it into
+  the string representation of the record's @rid (e.g. 12:0)"
   (.. rid getIdentity toString))

 (defn- xform-val [val]


cleanup

cleanup

--- src/clj/game/cards.clj
+++ src/clj/game/cards.clj
@@ -3505,9 +3505,6 @@
    "Nasir Meidan: Cyber Explorer"
    {:effect (effect (gain :link 1))}

-   "Power Shutdown"
-   {:req (req (:made-run runner-reg))}
-
    "Tallie Perrault"
    {:abilities [{:label "Draw 1 card for each Corp bad publicity" :effect (effect (trash card) (draw (:bad-publicity corp)))
                  :msg (msg "draw " (:bad-publicity corp) " cards")}]


Added Mother Goddess subtype-changing functionality on ICE rez, derez, trash. Fixes interaction with NEXT Gold.

--- src/clj/game/cards.clj
+++ src/clj/game/cards.clj
@@ -2547,7 +2547,55 @@
                  :effect (req (corp-install state side target (:server run)))}]}

    "Mother Goddess"
-   {:abilities [{:msg "end the run" :effect (effect (end-run))}]}
+   {:abilities [{:msg "end the run" :effect (effect (end-run))}]
+    :events {
+      :rez {
+         :req (req (= (:type target) "ICE"))
+         :effect (req (let [allice (->> (flatten (seq (:servers corp))) (map #(:ices %)) (filter #(not (nil? %))) flatten
+                              (filter #(and (:rezzed %) (not= (:cid card) (:cid %)))))
+                            allsubtypes (->> allice
+                              (map #(vec (.split (:subtype %) " - "))) flatten)
+                            newtypes (clojure.string/join " - " (distinct (cons "Mythic" allsubtypes)))]
+            (resolve-ability state side {
+               :msg (msg "gain subtypes " newtypes)
+               :effect (req(let [c (assoc card :subtype newtypes)]
+                  (update! state side c)
+               ))
+            } card nil)
+         ))
+      }
+      :trash {
+         :req (req (= (:type target) "ICE"))
+         :effect (req (let [allice (->> (flatten (seq (:servers corp))) (map #(:ices %)) (filter #(not (nil? %))) flatten
+                              ; the trash event triggers while the ice is still installed, so the filter must rule out the target
+                              (filter #(and (:rezzed %) (not= (:cid card) (:cid %)) (not= (:cid target) (:cid %)))))
+                            allsubtypes (->> allice
+                              (map #(vec (.split (:subtype %) " - "))) flatten)
+                            newtypes (clojure.string/join " - " (distinct (cons "Mythic" allsubtypes)))]
+            (resolve-ability state side {
+               :msg (msg "gain subtypes " newtypes)
+               :effect (req(let [c (assoc card :subtype newtypes)]
+                  (update! state side c)
+               ))
+            } card nil)
+         ))
+      }
+      :derez {
+         :req (req (= (:type target) "ICE"))
+         :effect (req (let [allice (->> (flatten (seq (:servers corp))) (map #(:ices %)) (filter #(not (nil? %))) flatten
+                              (filter #(and (:rezzed %) (not= (:cid card) (:cid %)))))
+                            allsubtypes (->> allice
+                              (map #(vec (.split (:subtype %) " - "))) flatten)
+                            newtypes (clojure.string/join " - " (distinct (cons "Mythic" allsubtypes)))]
+            (resolve-ability state side {
+               :msg (msg "gain subtypes " newtypes)
+               :effect (req(let [c (assoc card :subtype newtypes)]
+                  (update! state side c)
+               ))
+            } card nil)
+         ))
+      }
+      }}

    "Muckraker"
    {:effect (effect (gain :bad-publicity 1))


Fix incorrect sketch hash

Fix incorrect sketch hash


revert date parsing changes

revert date parsing changes

--- src/clj_money/util.clj
+++ src/clj_money/util.clj
@@ -2,9 +2,7 @@
   (:refer-clojure :exclude [update])
   (:require [clojure.pprint :refer [pprint]]
             [clojure.tools.logging :as log]
-            [clj-time.core :as t]
-            [clj-time.format :refer [parse-local
-                                     formatter]])
+            [clj-time.core :as t])
   (:import java.text.DecimalFormat
            org.joda.time.format.DateTimeFormat
            org.joda.time.LocalDate))
@@ -36,12 +34,24 @@
     (catch Exception e
       (log/warn "Unable to format date value \"" value "\""))))

+(def date-patterns
+  [{:pattern #"(\d{1,2})/(\d{1,2})/(\d{4})"
+    :groups [:month :day :year]}
+   {:pattern
+    #"(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})"
+    :groups [:year :month :day]}])
+
 (defn parse-local-date
   "Parses the specified date value"
   [date-string]
   (when date-string
-    (or (parse-local date-string)
-                 (parse-local (formatter "M/d/Y") date-string))))
+    (when-let [parsed (some (fn [{:keys [pattern groups]}]
+                              (when-let [m (re-matches pattern date-string)]
+                                (zipmap groups (->> m
+                                                    rest
+                                                    (map #(Integer. %))))))
+                            date-patterns)]
+      (apply t/local-date ((juxt :year :month :day) parsed)))))

 (defn ensure-local-date
   "Ensures that the specified value is a local date"


docs updated

docs updated

--- src/clojure2d/core.clj
+++ src/clojure2d/core.clj
@@ -95,7 +95,8 @@
   Additional informations:

   * Display refreshment is done by displaying canvas on JFrame. You can set separate quality hints (same as for canvas) for this process with `:hint` parameter.
-  * When you privide drawing function, it's called every refreshment. By default graphical context is created every call - which costs time but is safe in case you want to directly access pixels. The second variant which can be used is to create graphical context once at the moment of window creation. This variant can be forced by setting `:refresher` parameter to `:fast`.
+  * When you privide drawing function, it's called every refreshment. By default graphical context is created every call - which costs time but is safe in case you want to directly access pixels. The second variant which can be used is to create graphical context once at the moment of window creation. This variant can be forced by setting `:refresher` parameter to `:fast`
+  * In case you don't want to refresh window content automatically, set `:refresher` to `:onrepaint`. This will lower CPU consumption.
   * You can replace canvas attached to window with [[replace-canvas]] function.
   * Window itself acts as event object (implements all event protocols)
   * Canvas and window can have different sizes. Display refreshing functions will scale up/down in such case.


Refactored functions.

Refactored functions.

--- src/cmr/common/xml.clj
+++ src/cmr/common/xml.clj
@@ -59,12 +59,8 @@
 (defn contents-at-path
   "This is a helper that will pull the XML content from the xml-struct at the given path."
   [xml-struct path]
-  (let [elements (elements-at-path xml-struct path)]
-    (cond
-      (sequential? elements)
-      (map #(:content %) elements)
-      :else
-      (first elements))))
+  (if-let [elements (elements-at-path xml-struct path)]
+    (map #(:content %) elements)))

 (defn attrs-at-path
   "This is a helper that will pull the XML attributes from the xml-struct at the given path."
@@ -81,12 +77,8 @@
 (defn strings-at-path
   "Extracts a string from the given path in the XML structure."
   [xml-struct path]
-  (let [contents (contents-at-path xml-struct path)]
-    (cond
-      (sequential? contents)
-      (map #(str (first %)) contents)
-      :else
-      (if (not (nil? contents)) (str (first contents))))))
+  (if-let [contents (contents-at-path xml-struct path)]
+    (map #(str (first %)) contents)))

 (defn long-at-path
   "Extracts a long number from the given path in the XML structure."
@@ -115,9 +107,5 @@
 (defn datetimes-at-path
   "Extracts a datetime from the given path in the XML structure."
   [xml-struct path]
-  (let [value (strings-at-path xml-struct path)]
-    (cond
-      (sequential? value)
-      (map #(p/string->datetime %) value)
-      :else
-      (if (not (empty? value)) value))))+  (if-let [value (strings-at-path xml-struct path)]
+    (map #(p/string->datetime %) value)))


[Fix] cover to negative and stego to positive

for general

--- src/clj_elm/core.clj
+++ src/clj_elm/core.clj
@@ -155,10 +155,10 @@
          train (DataSet. (data/remove-list (:classes @dataset) a b)
                          (data/remove-list (:features @dataset) a b))
          exp (atom {:num (str "Data " a " to " b)
-                    :length-train-cover (select-count #(= % -1) (:classes train))
-                    :length-test-cover (select-count #(= % -1) (:classes test))
-                    :length-train-stego (select-count #(= % 1) (:classes train))
-                    :length-test-stego (select-count #(= % 1) (:classes test))
+                    :length-train-negative (select-count #(= % -1) (:classes train))
+                    :length-test-negative (select-count #(= % -1) (:classes test))
+                    :length-train-positive (select-count #(= % 1) (:classes train))
+                    :length-test-positive (select-count #(= % 1) (:classes test))
                     :Accuracy 0.0 :Recall 0.0 :Precision 0.0 :TP 0 :FP 0 :TN 0 :FN 0 :L L})]
      (-> (train-model train L)
          (#(pmap (fn [feature] (predict % feature)) (:features test)))
@@ -166,10 +166,10 @@

 (defn print-exp-data [expdata]
   (print "L: " (:L expdata) "\n"
-         "length(train_cover): " (:length-train-cover expdata) "\n"
-         "length(test_cover): " (:length-test-cover expdata) "\n"
-         "length(train_stego): " (:length-train-stego expdata) "\n"
-         "length(test_stego): " (:length-train-cover expdata) "\n"
+         "length(train_negative): " (:length-train-negative expdata) "\n"
+         "length(test_negative): " (:length-test-negative expdata) "\n"
+         "length(train_positive): " (:length-train-positive expdata) "\n"
+         "length(test_positive): " (:length-test-positive expdata) "\n"
          "TP: " (:TP expdata) ", FP: " (:FP expdata) ", TN: " (:TN expdata) ", FN: " (:FN expdata) "\n"
          "Accracy: " (:Accuracy expdata "\n")
          "Recall: " (:Recall expdata "\n")


Add more visible feedback for beat adjustment.

--- src/afterglow/controllers/ableton_push_2.clj
+++ src/afterglow/controllers/ableton_push_2.clj
@@ -618,6 +618,17 @@
         leader (take (int (/ scaled 2)) (repeat 0))]
     (take width (concat leader [marker] (repeat 0)))))

+(defn draw-null-gauge
+ "Draw a mostly meaningless gauge simply to indicate that the encoder
+ is doing something. Used for beat adjustments, for example, which
+ have no reasonable range or location to show."
+  [controller index encoder-count color]
+  (let [graphics (create-graphics controller)
+        x-center (+ (* index button-cell-width) (* encoder-count 0.5 button-cell-width))
+        arc (java.awt.geom.Arc2D$Double. (- x-center 20.0) 50.0 40.0 40.0 240.0 -300.0 java.awt.geom.Arc2D/OPEN)]
+    (set-graphics-color graphics color)
+    (.draw graphics (java.awt.geom.Ellipse2D$Double. (- x-center 20.0) 50.0 40.0 40.0))))
+
 (defn draw-gauge
   "Draw a graphical gauge with an indicator that fills an arc under a
   variable value. The default range is from zero to a hundred, and the
@@ -791,7 +802,8 @@
                        (inc first-dot) second-dot)
         (.addAttribute label java.awt.font.TextAttribute/FOREGROUND (java.awt.Color/WHITE)
                        (inc second-dot) (count marker)))
-      (draw-attributed-variable-value controller 0 1 label metronome-content))
+      (draw-attributed-variable-value controller 0 1 label metronome-content)
+      (draw-null-gauge controller 0 1 white-color))
   true)

 (defn- adjust-beat-from-encoder


removed unused function

removed unused function

--- src/org/domaindrivenarchitecture/pallet/crate/managed_ide.clj
+++ src/org/domaindrivenarchitecture/pallet/crate/managed_ide.clj
@@ -34,11 +34,6 @@
   {:ide-user s/Keyword
    (s/optional-key :clojure) clojure/LeiningenUserProfileConfig
    (s/optional-key :settings) (hash-set (s/enum :install-atom))}
-  )
-
-(defn default-ide-config
-  "Managed ide crate default configuration"
-  []
   )

 (s/defn install-system


Only emit the editorial if it is not blank

Related to #11

--- src/catalog/layout/dtbook.clj
+++ src/catalog/layout/dtbook.clj
@@ -258,11 +258,12 @@
         [:p {:brl:class (format "jr_%s" year)}]])
       [:bodymatter
        [:level1
-        [:h1 (translations :editorial)]
-        (md-to-dtbook editorial)]
-       [:level1
         [:h1 (translations :recommendations)]
         (md-to-dtbook recommendations)]
+       (when (not (string/blank? editorial))
+         [:level1
+          [:h1 (translations :editorial)]
+          (md-to-dtbook editorial)])
        (when-let [items (not-empty
                          (dissoc items :musiknoten :taktilesbuch))]
          [:level1 [:h1 (translations :braille)]


Don't use defbindings for hash impls

Don't use defbindings for hash impls

--- src/caesium/crypto/hash.clj
+++ src/caesium/crypto/hash.clj
@@ -1,5 +1,24 @@
 (ns caesium.crypto.hash
-  (:require [caesium.binding :refer [sodium defconsts defbindings]]))
+  (:require [caesium.binding :refer [sodium defconsts]]))

 (defconsts [sha256-bytes sha512-bytes])
-(defbindings [sha256 sha512])
+
+(defn sha256-to-buf!
+  [buf msg]
+  (.crypto_hash_sha256 sodium buf msg (alength ^bytes msg)))
+
+(defn sha256
+  [msg]
+  (let [buf (byte-array sha256-bytes)]
+    (sha256-to-buf! buf msg)
+    buf))
+
+(defn sha512-to-buf!
+  [buf msg]
+  (.crypto_hash_sha512 sodium buf msg (alength ^bytes msg)))
+
+(defn sha512
+  [msg]
+  (let [buf (byte-array sha512-bytes)]
+    (sha512-to-buf! buf msg)
+    buf))


Set :template_environment_variables to true by default

--- src/cider_ci/builder/task.clj
+++ src/cider_ci/builder/task.clj
@@ -14,8 +14,7 @@
     [clojure.java.jdbc :as jdbc]

     [clojure.tools.logging :as logging]
-    [logbug.debug :as debug]
-
+    [logbug.debug :as debug :refer [I> I>> identity-with-logging]]
   ))

@@ -66,12 +65,26 @@
                    Math/floor int)))
     (assoc spec :dispatch_storm_delay_seconds (dispatch-storm-delay-default))))

+
+(defn- normalize-template-environment-variables [spec]
+  (if-let [scripts (:scripts spec)]
+    (assoc spec :scripts
+           (->> scripts
+                (into [])
+                (map (fn [[k script]]
+                       [k (if (contains? script :template_environment_variables )
+                            script
+                            (assoc script :template_environment_variables true))]))
+                (into {})))
+    spec))
+
 (defn- normalize-task-spec [raw-spec]
   (-> raw-spec
       clojure.walk/keywordize-keys
       (dissoc :job_id)
       normalize-aggregate-succes
-      normalize-dispatch-storm-delay))
+      normalize-dispatch-storm-delay
+      normalize-template-environment-variables))

 ;##############################################################################
@@ -93,7 +106,6 @@
                         :state (if (empty? errors) "pending" "aborted")
                         :id (util/idid2id job-id (:id db-task-spec))
                         })]
-    (logging/debug task-row)
     (first (jdbc/insert! tx "tasks" task-row))))


changes browser repl server to serve files referenced in source map that are in jars and in project directory

--- src/clj/cljs/repl/browser.clj
+++ src/clj/cljs/repl/browser.clj
@@ -9,11 +9,13 @@
 (ns cljs.repl.browser
   (:refer-clojure :exclude [loaded-libs])
   (:require [clojure.java.io :as io]
+            [clojure.string :as string]
             [cljs.compiler :as comp]
             [cljs.closure :as cljsc]
             [cljs.repl :as repl]
             [cljs.repl.server :as server])
-  (:import cljs.repl.IJavaScriptEnv))
+  (:import cljs.repl.IJavaScriptEnv
+           [java.util.regex Pattern]))

 (defonce browser-state (atom {:return-value-fn nil
                               :client-js nil}))
@@ -63,21 +65,32 @@
   (if (and (:static-dir opts)
            (not= "/favicon.ico" path))
     (let [path   (if (= "/" path) "/index.html" path)
-          st-dir (:static-dir opts)]
-      (if-let [local-path (seq (for [x (if (string? st-dir) [st-dir] st-dir)
-                                     :when (.exists (io/file (str x path)))]
-                                 (str x path)))]
-        (server/send-and-close conn 200 (slurp (first local-path))
-                        (condp #(.endsWith %2 %1) path
-                          ".html" "text/html"
-                          ".css" "text/css"
-                          ".html" "text/html"
-                          ".jpg" "image/jpeg"
-                          ".js" "text/javascript"
-                          ".cljs" "text/clojurescript"
-                          ".map" "application/json"
-                          ".png" "image/png"
-                          "text/plain"))
+          st-dir (:static-dir opts)
+          local-path (cond->
+                       (seq (for [x (if (string? st-dir) [st-dir] st-dir)
+                                  :when (.exists (io/file (str x path)))]
+                              (str x path)))
+                       (complement nil?) first)
+          local-path (if (nil? local-path)
+                       (cond
+                         (re-find #".jar" path)
+                         (io/resource (second (string/split path #".jar!/")))
+                         (re-find (Pattern/compile. (System/getProperty "user.dir")) path)
+                         (io/file (string/replace path (str (System/getProperty "user.dir") "/") ""))
+                         :else nil)
+                       local-path)]
+      (if local-path
+        (server/send-and-close conn 200 (slurp local-path)
+          (condp #(.endsWith %2 %1) path
+            ".html" "text/html"
+            ".css" "text/css"
+            ".html" "text/html"
+            ".jpg" "image/jpeg"
+            ".js" "text/javascript"
+            ".cljs" "text/clojurescript"
+            ".map" "application/json"
+            ".png" "image/png"
+            "text/plain"))
         (server/send-404 conn path)))
     (server/send-404 conn path)))


Reduced weights for rare cards

Reduced weights for rare cards

--- src/clj/funstructor/cards.clj
+++ src/clj/funstructor/cards.clj
@@ -145,7 +145,7 @@
     "remove random terminal from the opponents funstruct"
     :target :self
     :type :mutator
-    :weight 300
+    :weight 50
     :img "mutator_random_shot.svg"}

@@ -257,7 +257,7 @@
     "get a copy of each card played by an opponent. Lasts 5 turns"
     :target :self
     :type :duration
-    :weight 300
+    :weight 40
     :turns-left 5
     :img "duration_duplicate.svg"}

@@ -267,7 +267,7 @@
     "each turn get one more card. Lasts 5 turns"
     :target :self
     :type :duration
-    :weight 300
+    :weight 40
     :turns-left 5
     :img "duration_good_times.svg"}


Client: Add view for adding materials

Client: Add view for adding materials

Submitting doesn't work, but the fields get bound to their scratch area
alright.

--- src/cljs/theatralia/core.cljs
+++ src/cljs/theatralia/core.cljs
@@ -187,6 +187,8 @@

 ;;;; Views

+;;; For the search view
+
 (defn result-item
   "One item of the material search results."
   [[id title _]]
@@ -220,12 +222,28 @@
          (kioo/set-attr :onClick #(dispatch-scratch [:search-submitted
                                                      scratch]))}))))

+;;; View for adding materials
+
+(defn add-material-view []
+  (let [scratch (get-scratch)]
+    (fn add-material-view-infn []
+      (kioo/component "templates/sandbox.html" [:#add-material-form]
+        {[:#newMatSubmit]
+         (kioo/set-attr
+           :onClick (fn [e]
+                      (.preventDefault e)
+                      (dispatch-scratch [:add-material scratch])))
+         [:.form-control] (bind-and-set-attr scratch)}))))
+
+;;; Root view
+
 (defn root-view
   "The application's high-level structure."
   []
   (kioo/component "templates/sandbox.html"
     {[:#search-field] (kioo/substitute [search-view])
-     [:#search-results] (kioo/substitute [result-view])}))
+     [:#search-results] (kioo/substitute [result-view])
+     [:#add-material-form] (kioo/substitute [add-material-view])}))

 ;;;; Entry point


Changed code to allow search with unspecified content-type header.

--- src/cmr/search/api/routes.clj
+++ src/cmr/search/api/routes.clj
@@ -148,20 +148,23 @@
 (defn- find-concepts
   "Invokes query service to find results and returns the response"
   [context path-w-extension params headers query-string]
-  (if (= "application/x-www-form-urlencoded" (get headers (str/lower-case CONTENT_TYPE_HEADER)))
-    (let [concept-type (concept-type-path-w-extension->concept-type path-w-extension)
-          context (-> context
-                      (process-context-info params headers)
-                      (assoc :query-string query-string))
-          params (process-params params path-w-extension headers "application/xml")
-          _ (info (format "Searching for %ss from client %s in format %s with params %s."
-                          (name concept-type) (:client-id context) (:result-format params)
-                          (pr-str params)))
-          search-params (lp/process-legacy-psa params query-string)
-          results (query-svc/find-concepts-by-parameters context concept-type search-params)]
-      (search-response params results))
-    {:status 415
-     :body (str "Unsupported content type [" (get headers (str/lower-case CONTENT_TYPE_HEADER)) "]")}))
+  (let [content-type-header (get headers (str/lower-case CONTENT_TYPE_HEADER))]
+    (if (or (nil? content-type-header)
+            (= "application/x-www-form-urlencoded" content-type-header))
+      (let [concept-type (concept-type-path-w-extension->concept-type path-w-extension)
+            context (-> context
+                        (process-context-info params headers)
+                        (assoc :query-string query-string))
+            params (process-params params path-w-extension headers "application/xml")
+            _ (info (format "Searching for %ss from client %s in format %s with params %s."
+                            (name concept-type) (:client-id context) (:result-format params)
+                            (pr-str params)))
+            search-params (lp/process-legacy-psa params query-string)
+            results (query-svc/find-concepts-by-parameters context concept-type search-params)]
+        (search-response params results))
+      {:status 415
+       :body (str "Unsupported content type ["
+                  (get headers (str/lower-case CONTENT_TYPE_HEADER)) "]")})))

 (defn- find-concepts-by-aql
   "Invokes query service to parse the AQL query, find results and returns the response"


remove unneeded user query

remove unneeded user query

--- src/kixi/hecuba/api/profiles.clj
+++ src/kixi/hecuba/api/profiles.clj
@@ -717,7 +717,7 @@

               (if (not= (:entity_id body) entity_id)
                 true                  ; it's malformed, game over
-                [false {:body body}]))  ; it's not malformed, return the body now we've read it
+                [false {:profile body}]))  ; it's not malformed, return the body now we've read it
       false)))

 (defn index-handle-ok [ctx]
@@ -783,12 +783,10 @@
                            (parse-by-schema body-map profile-schema))
                          decoded-body)
               {:keys [entity_id profile_id]} item
-              username   (sec/session-username (-> ctx :request :session))
-              user_id    (-> (db/execute session (hayt/select :users (hayt/where [[= :username username]]))) first :id)
-              ]
+              username   (sec/session-username (-> ctx :request :session))]
           (db/execute session (hayt/insert :profiles (hayt/values (-> body
                                                                       (assoc :id profile_id)
-                                                                      (assoc :user_id user_id)
+                                                                      (assoc :user_id username)
                                                                       (update-stringified-lists
                                                                         [:airflow_measurements :chps
                                                                          :conservatories :door_sets
@@ -826,15 +824,13 @@
     (let [{:keys [request profile]} ctx
           {:keys [entity_id timestamp]} profile
           username   (sec/session-username (-> ctx :request :session))
-          ;; FIXME: Why user_id?
-          user_id    (-> (db/execute session (hayt/select :users (hayt/where [[= :username username]]))) first :id)
           profile_id (sha1/gen-key :profile profile)]
       (when (and entity_id timestamp)
         (when (seq
                 (first
                   (db/execute session (hayt/select :entities (hayt/where [[= :id entity_id]])))))
           (let [query-profile (-> profile
-                                 (assoc :user_id user_id)
+                                 (assoc :user_id username)
                                  (update-stringified-lists
                                   [:airflow_measurements :chps
                                    :conservatories :door_sets


get POST & PUT csv profiles working

get POST & PUT csv profiles working

--- src/kixi/hecuba/api/profiles.clj
+++ src/kixi/hecuba/api/profiles.clj
@@ -511,13 +511,14 @@
 (def profile-schema
   [ :id
     :entity_id
+    :timestamp
     { :name    :profile_data
       :type    :nested-item
       :schema  profile-data-schema }
     { :name    :window_sets
       :type    :associated-items
       :schema   window-set-schema}
-    { :name    :thermal-images
+    { :name    :thermal_images
       :type    :associated-items
       :schema  thermal-images-schema }
     { :name    :storeys
@@ -618,35 +619,53 @@
                                            (explode-associated-items attr (item (:name attr)))))))))]
     exploded-item))

-(defn extract-attribute [attr input]
-  (println "Attribute: " attr)
-  (println "Input: " input)
-  {attr (input attr)})
+(defn extract-attribute [attr-key input]
+  (let [attr-name (name attr-key)
+        attr-value (input attr-name)]
+  {attr-key attr-value}))

 (defn extract-nested-item [attr input]
   (let [association-name   (:name   attr)
         association-schema (:schema attr)
         nested-item (->> association-schema
                          (reduce
-                           (fn [nested-item attr]
-                             (let [attr-name (name attr)
-                                   exploded-attr-name (str association-name "_" attr-name)]
-                               { (keyword attr-name) (input exploded-attr-name) }))
+                           (fn [nested-item nested-attr]
+                             (let [nested-attr-name (name nested-attr)
+                                   exploded-attr-name (str (name association-name) "_" nested-attr-name)]
+                               (conj nested-item { nested-attr (input exploded-attr-name)})))
                            {}))]
     {association-name nested-item}))

+(defn extract-associated-item [association-name association-schema input index]
+  (->> association-schema
+    (reduce
+      (fn [associated-item associated-item-attr]
+        (let [associated-item-attr-name (name associated-item-attr)
+              exploded-attr-name (str (name association-name) "_" index "_" associated-item-attr-name)]
+          (conj associated-item { associated-item-attr (input exploded-attr-name)})))
+      {})))
+
 (defn extract-associated-items [attr input]
-  {})
+  (let [association-name   (:name attr)
+        association-schema (:schema attr)
+        attribute-names    (doall (keys input))
+        items-id-pattern   (re-pattern (str (name association-name) "_(\\d+)_"))
+        items-ids (reduce conj #{} (->> attribute-names
+                                        (map #(when-some [x (re-find items-id-pattern %)] (last x)))
+                                        (filter #(not (nil? %)))))
+        associated-items (map #(extract-associated-item association-name association-schema input %) items-ids) ]
+    {association-name associated-items}))

 (defn parse-by-schema [input schema]
   (->> schema
        (reduce
          (fn [item attr]
-           (let [t (attribute-type attr)]
-             (case t
-               :attribute               (extract-attribute attr input)
-               :nested-item             (extract-nested-item attr input)
-               :associated-item         (extract-associated-items attr input))))
+           (let [t (attribute-type attr)
+                 imploded-attribute (case t
+                   :attribute               (extract-attribute attr input)
+                   :nested-item             (extract-nested-item attr input)
+                   :associated-items        (extract-associated-items attr input))]
+             (conj item imploded-attribute)))
          {})))

 (defn index-malformed? [ctx]
@@ -655,17 +674,10 @@
         entity_id (:entity_id route-params)]
     (case request-method
       :post (let [decoded-body  (decode-body request)
-                  _ (log/info "BODY SIZE: " (count decoded-body))
-                  _ (log/info "Oh damn, why is it just one vector-in-a-list? Let's see what's in there at least")
-                  raw-body (first decoded-body)
-                  _ (log/info "RAW BODY:\n" raw-body)
-                  _ (log/info "BODY SIZE:\t" (count raw-body))
-                  _ (log/info "doesn't make much sense does it... it's like we got back a vector of strings, joined on \\n")
                   body     (if (= "text/csv" (:content-type request))
-                             (let [body-map (reduce conj {} raw-body)
-                                   _ (println "BODY:\n" body-map)]
+                             (let [body-map (reduce conj {} decoded-body)]
                                (parse-by-schema body-map profile-schema))
-                             raw-body)]
+                             decoded-body)]
               ;; We need to assert a few things
               (if (not= (:entity_id body) entity_id)
                 true                  ; it's malformed, game over
@@ -728,18 +740,31 @@

 (defn resource-put! [store ctx]
   (db/with-session [session (:hecuba-session store)]
-    (let [{request :request} ctx]
+    (let [request (:request ctx)]
       (if-let [item (::item ctx)]
-        (let [body       (decode-body request)
+        (let [decoded-body  (decode-body request)
+              body     (if (= "text/csv" (:content-type request))
+                         (let [body-map (reduce conj {} decoded-body)]
+                           (parse-by-schema body-map profile-schema))
+                         decoded-body)
               entity_id  (-> item :entity_id)
               username   (sec/session-username (-> ctx :request :session))
-              user_id    (:id (users/get-by-username session username))
-              profile_id (-> item :profile-id)]
+              user_id    (-> (db/execute session (hayt/select :users (hayt/where [[= :username username]]))) first :id)
+              profile_id (-> item :profile_id)]
           (db/execute session (hayt/insert :profiles (hayt/values (-> body
                                                                       (assoc :id profile_id)
                                                                       (assoc :user_id user_id)
-                                                                      ;; TODO: add storeys, walls, etc.
-                                                                      stringify-values)))))
+                                                                      (update-stringified-lists
+                                                                        [:airflow_measurements :chps
+                                                                         :conservatories :door_sets
+                                                                         :extensions :floors :heat_pumps
+                                                                         :heating_systems :hot_water_systems
+                                                                         :low_energy_lights :photovoltaics
+                                                                         :roof_rooms :roofs :small_hydros
+                                                                         :solar_thermals :storeys :thermal_images
+                                                                         :ventilation_systems :walls
+                                                                         :wind_turbines :window_sets])
+                                                                       (update-in [:profile_data] json/encode))))))
         (ring-response {:status 404 :body "Please provide valid entity_id and timestamp"})))))

 (defn resource-handle-ok [store ctx]
@@ -763,31 +788,29 @@

 (defn index-post! [store ctx]
   (db/with-session [session (:hecuba-session store)]
-    (let [request    (-> ctx :request)
-          profile    (-> ctx :body)
-          entity_id  (-> profile :entity_id)
-          timestamp  (-> profile :timestamp)
+    (let [{:keys [request profile]} ctx
+          {:keys [entity_id timestamp]} profile
           username   (sec/session-username (-> ctx :request :session))
           ;; FIXME: Why user_id?
           user_id    (-> (db/execute session (hayt/select :users (hayt/where [[= :username username]]))) first :id)
           profile_id (sha1/gen-key :profile profile)]
       (when (and entity_id timestamp)
         (when-not (empty? (-> (db/execute session (hayt/select :entities (hayt/where [[= :id entity_id]]))) first))
-          (db/execute session (hayt/insert :profiles (-> profile
-                                                         (assoc :user_id user_id)
-                                                         (update-stringified-lists
-                                                          [:airflow_measurements :chps
-                                                           :conservatories :door_sets
-                                                           :extensions :floors :heat_pumps
-                                                           :heating_systems :hot_water_systems
-                                                           :low_energy_lights :photovoltaics
-                                                           :roof_rooms :roofs :small_hydros
-                                                           :solar_thermals :storeys :thermal_images
-                                                           :ventilation_systems :walls
-                                                           :wind_turbines :window_sets])
-                                                         (update-in [:profile_data] json/encode)
-                                                         )))
-          {:profile_id profile_id})))))
+          (let [query-profile (-> profile
+                                 (assoc :user_id user_id)
+                                 (update-stringified-lists
+                                  [:airflow_measurements :chps
+                                   :conservatories :door_sets
+                                   :extensions :floors :heat_pumps
+                                   :heating_systems :hot_water_systems
+                                   :low_energy_lights :photovoltaics
+                                   :roof_rooms :roofs :small_hydros
+                                   :solar_thermals :storeys :thermal_images
+                                   :ventilation_systems :walls
+                                   :wind_turbines :window_sets])
+                                 (update-in [:profile_data] json/encode))]
+          (db/execute session (hayt/insert :profiles (hayt/values query-profile)))
+          {:profile_id profile_id}))))))

 (defresource index [store]


Use env port.

Use env port.

--- src/clj/clj_templates/config/main_config.clj
+++ src/clj/clj_templates/config/main_config.clj
@@ -5,7 +5,7 @@
 (def main-config
   {:handler/main        {:es-client (ig/ref :search/elastic)}
    :server/jetty        {:handler (ig/ref :handler/main)
-                         :opts    {:port 3000 :join? false}}
+                         :opts    {:port (or (env :port) 3000) :join? false}}
    :db/postgres         {:jdbc-url          (env :db-url)
                          :driver-class-name "org.postgresql.Driver"}
    :logger/timbre       {:appenders {:println {:stream :auto}}}


generate an initial list of paginations

generate an initial list of paginations

--- src/crawler/corpus.clj
+++ src/crawler/corpus.clj
@@ -2,7 +2,8 @@
   "Tools for processing a downloaded corpus"
   (:require [cheshire.core :as json]
             [clojure.java.io :as io])
-  (:use [clojure.pprint :only [pprint]])
+  (:use [clojure.pprint :only [pprint]]
+        [structural-similarity.xpath-text :only [similar?]])
   (:import [java.io PushbackReader]))

 (defn read-corpus-file
@@ -10,6 +11,56 @@
   (let [rdr (PushbackReader.
              (io/reader a-corpus-file))]
     (read rdr)))
+
+(defn pagination-candidate?
+  "Source page and target page bodies"
+  [src-body target-body]
+  (similar? src-body target-body))
+
+(defn pagination-candidates
+  [corpus]
+  (map
+   #(dissoc % :candidate?)
+   (filter
+    :candidate?
+    (map
+     (fn [[item-url item-details]]
+       (let [src-body (-> item-details :src-url corpus :body)
+             tgt-body (-> item-details :body)
+
+             src-pg-xpath (-> item-details :src-url corpus :src-xpath)
+             tgt-pg-xpath (-> item-details :src-xpath first)
+
+             src-url (-> item-details :src-url)
+             tgt-url item-url]
+         {:src-xpath  src-pg-xpath
+          :action     tgt-pg-xpath
+          :candidate? (pagination-candidate? src-body tgt-body)}))
+     corpus))))
+
+(defn pagination-in-corpus
+  [corpus]
+  (let [candidates (-> corpus pagination-candidates frequencies)
+        sorted-candidates (sort-by #(-> % first :src-xpath count) candidates)
+
+        ;; removes spurious leads with pagination.
+        spurious-candidates-removed
+        (filter
+         (fn [[item freq]]
+           (not
+            (some (fn [[c freq]]
+                    (= (:src-xpath item)
+                       (cons (:action c)
+                             (:src-xpath c))))
+                  sorted-candidates)))
+         sorted-candidates)]
+    (sort-by
+     pagination-candidate-score)))
+
+(defn pagination-in-corpus-file
+  [a-corpus-file]
+  (let [corpus (read-corpus-file a-corpus-file)]
+    (pagination-in-corpus corpus)))

 (defn corpus->json
   "Converts a corpus file which is essentially a pprinted map


Rename args.

Rename args.

--- src/dsbdp/local_data_processing_pipeline.clj
+++ src/dsbdp/local_data_processing_pipeline.clj
@@ -69,12 +69,12 @@
        :out-queue out-queue})))

 (defn interrupt
-  [obj]
-  ((obj :interrupt)))
+  [proc-element]
+  ((proc-element :interrupt)))

 (defn get-out-queue
-  [obj]
-  (obj :out-queue))
+  [proc-element]
+  (proc-element :out-queue))

@@ -109,6 +109,6 @@
               (enqueue in-queue (LocalTransferContainer. in nil)))}))

 (defn get-in-fn
-  [obj]
-  (obj :in-fn))
+  [pipeline]
+  (pipeline :in-fn))


Added error handling

Added error handling

--- src/main/clj/clojure/core/matrix/complex.clj
+++ src/main/clj/clojure/core/matrix/complex.clj
@@ -19,7 +19,7 @@

 (deftype ComplexArray [real imag]
   mp/PImplementation
-  (implementation-key [m]
+  (implementation-key [m]  ;; in this case, 'm' takes the place of the more typical 'this'
     :complex-array)
   (meta-info [m]
     {:doc "Implementation for complex arrays"})
@@ -110,12 +110,12 @@
     (cond
       (number? a) (ComplexArray. (mp/scale (clojure.core.matrix.complex/real m) a)
                                  (mp/scale (clojure.core.matrix.complex/imag m) a))
-      :else (TODO)))
+      :else (error "Unable to multiply " (class a) " with a Complex value")))
   (pre-scale [m a]
     (cond
       (number? a) (ComplexArray. (mp/scale (clojure.core.matrix.complex/real m) a)
                                  (mp/scale (clojure.core.matrix.complex/imag m) a))
-      :else (TODO)))
+      :else (error "Unable to multiply " (class a) " with a Complex value")))

   mp/PMatrixProducts
   (inner-product [m a]


[clojure] make repl helpers more resilient

--- etc/repl.clj
+++ etc/repl.clj
@@ -41,13 +41,17 @@
 (defn find-ns
   "Find namespace vars by a regex"
   [re]
-  (filter #(re-find re (str %)) (list-ns)))
+  (vec (filter #(re-find re (str %)) (list-ns))))

 (defn find-test-ns
   "Find test namespace vars by a regex"
-  [re]
-  (filter #(re-find re (str %)) (list-ns "./test/")))
+  [pattern]
+  (let [re (cond
+             (string? pattern) (re-pattern pattern)
+             (= java.util.regex.Pattern (class pattern)) pattern
+             :else (throw (ex-info "this is not a patternable thing" {:pattern pattern})))]
+  (vec (filter #(re-find re (str %)) (list-ns "./test/")))))

 (def system-status (atom {}))


Improve out of date comment.

Improve out of date comment.

--- src/onyx/log/commands/common.clj
+++ src/onyx/log/commands/common.clj
@@ -129,10 +129,7 @@
 (defn build-stop-task-fn [external-kill-flag started-task-ch]
   (fn [scheduler-event]
     (reset! external-kill-flag true)
-    ;; TODO: consider timeout on blocking read of ending-ch?
-    ;; This way we can't end up with a blocked peer-group
-    ;; Should probably get rid of the future, and deref, and forcefully stop the component after the timeout anyway
-    ;; This is likely better than not stopping the task at all
+    ;; TODO: use timeout on blocking read of ending-ch and eliminate deref below
     (let [started (<!! started-task-ch)]
       (component/stop (assoc-in started [:task-lifecycle :scheduler-event] scheduler-event)))))


utils/simpledb.clj: added docstrings

utils/simpledb.clj: added docstrings

--- src/org/altlaw/util/simpledb.clj
+++ src/org/altlaw/util/simpledb.clj
@@ -5,7 +5,10 @@
 (defn- keystr [x]
   (if (keyword? x) (name x) (str x)))

-(defn- make-attr-list [keyvals]
+(defn- make-attr-list
+  "Given a map of key=>value or key=>[values], return a List of
+  ItemAttribute objects."
+  [keyvals]
   (let [attrs (ArrayList.)]
     (doseq [[k v] keyvals]
       (if (coll? v)
@@ -15,7 +18,10 @@
         (.add attrs (ItemAttribute. (keystr k) (keystr v) true))))
     attrs))

-(defn- parse-attr-list [attrs]
+(defn- parse-attr-list
+  "Given a List of ItemAttribute objects, return a map of name=>value
+  and/or name=>[values]"
+  [attrs]
   (reduce (fn [m attr]
             (let [k (.getName attr), v (.getValue attr)]
               (assoc m k
@@ -51,17 +57,22 @@
     (.putAttributes item (make-attr-list keyvals))))

 (defn get-attrs
-  "Returns attributes (a map of key=>item or key=>collection) in the
-  item under the domain."
+  "Returns attributes (a map of key=>item or key=>collection).
+  Arguments may be either an Item object by itself or strings naming a
+  domain and an item."
   ([item] (parse-attr-list (.getAttributes item)))
   ([domain-name item-name]
      (let [item (get-item domain-name item-name)]
        (parse-attr-list (.getAttributes item)))))

-(defn delete-item [domain-name item-name]
+(defn delete-item
+  "Delete the item from the domain."
+  [domain-name item-name]
   (.deleteItem (get-domain domain-name) (keystr item-name)))

 (defn list-items
+  "Get the list of Item objects, optionally filtered by a Query
+  string."
   ([domain-name]
      (.getItemList (.listItems (get-domain domain-name))))
   ([domain-name query-string]
@@ -69,13 +80,17 @@
                                query-string))))

 (defn select-items
-  ([domain-name query-string]
-     (select-items domain-name query-string nil))
-  ([domain-name query-string next-token]
+  "Perform a Select operation on the domain.  Returns a map from item
+  identifiers to the maps of their attributes."
+  ([domain-name select-string]
+     (select-items domain-name select-string nil))
+  ([domain-name select-string next-token]
      (reduce (fn [m [k v]] (assoc m k (parse-attr-list v)))
              {} (.getItems (.selectItems (get-domain domain-name)
-                                         query-string next-token)))))
+                                         select-string next-token)))))

-(defn delete-where [domain-name query-string]
+(defn delete-where
+  "Deletes items from the domain matching the Query string."
+  [domain-name query-string]
   (doseq [item (list-items domain-name query-string)]
     (delete-item domain-name (.getIdentifier item))))


Unroll current-tx and inline in clj

Unroll current-tx and inline in clj

--- src/datascript/db.cljc
+++ src/datascript/db.cljc
@@ -1037,8 +1037,10 @@
     (raise "Cannot store nil as a value at " at
            {:error :transact/syntax, :value v, :context at})))

-(defn- current-tx [report]
-  (inc (get-in report [:db-before :max-tx])))
+(defn- current-tx
+  #?(:clj {:inline (fn [report] `(-> ~report :db-before :max-tx long inc))})
+  ^long [report]
+  (-> report :db-before :max-tx long inc))

 (defn- next-eid [db]
   (inc (:max-eid db)))


add com.google.datastore.v1.Entity to nippy allowlist

--- src/clj/datasplash/core.clj
+++ src/clj/datasplash/core.clj
@@ -400,7 +400,8 @@

 (alter-var-root #'nippy/*thaw-serializable-allowlist*
                 (fn [_] (into nippy/default-thaw-serializable-allowlist
-                             #{"org.apache.beam.sdk.values.KV"})))
+                             #{"org.apache.beam.sdk.values.KV"
+                               "com.google.datastore.v1.Entity"})))

 (defn make-nippy-coder
   {:doc "Returns an instance of a CustomCoder using nippy for serialization"


remove trashed card :cid from [:per-turn]

allows cards like Imp to be used again in a turn if Scavenged or Clone Chipped

--- src/clj/game/core-rules.clj
+++ src/clj/game/core-rules.clj
@@ -210,7 +210,8 @@
   (let [cdef (card-def card)
         moved-card (move state (to-keyword (:side card)) card :discard {:keep-server-alive keep-server-alive})]
     (when-let [trash-effect (:trash-effect cdef)]
-      (resolve-ability state side trash-effect moved-card (cons cause targets)))))
+      (resolve-ability state side trash-effect moved-card (cons cause targets)))
+    (swap! state update-in [:per-turn] dissoc (:cid moved-card))))

 (defn trash
   "Attempts to trash the given card, allowing for boosting/prevention effects."


Map more controller buttons

Map more controller buttons

dpad left/right/up/down
start button for play/pause

--- src/cljs/kindness/game.cljs
+++ src/cljs/kindness/game.cljs
@@ -26,7 +26,12 @@
    })
 (def gamepad-buttons
   {0 :activate
-   1 :play-pause})
+   1 :play-pause
+   9 :play-pause
+   12 :up
+   13 :down
+   14 :left
+   15 :right})
 (def keyboard-move-speed 20)
 (def gamepad-move-speed 7)


(broken) explore Java SDK using reflection option


Refactor creating peer and orderer

Refactor creating peer and orderer


Add case-inherited-non-zero-errors-meta-error

--- src/clojush/meta_errors.clj
+++ src/clojush/meta_errors.clj
@@ -832,3 +832,15 @@
           (:parent2-errors ind))
     (vec (repeat (count (:errors ind)) 0))))

+(defn case-inherited-non-zero-errors-meta-error
+  [ind evaluated-population argmap]
+  (if (and (:parent1-errors ind)
+           (:parent2-errors ind))
+    (mapv #(if (and (not (zero? %1))
+                    (some #{%1} [%2 %3]))
+             1
+             0)
+          (:errors ind)
+          (:parent1-errors ind)
+          (:parent2-errors ind))
+    (vec (repeat (count (:errors ind)) 0))))


porting more

porting more

Signed-off-by: Yen-Chin Lee <082d453d72dce940e12089a4ad48b97cfe1f3ec4@gmail.com>


Add one-click login button

Add one-click login button

--- src/discuss/debug.cljs
+++ src/discuss/debug.cljs
@@ -11,8 +11,7 @@
              (:is_user bubble) ":user "
              (:is_system bubble) ":info "
              (:is_status bubble) ":status "
-             :else ""
-             )
+             :else "")
            (:message bubble)
            "\n"))
        (range (count bubbles))))
@@ -29,11 +28,18 @@
                        "Debug")
                (dom/div #js {:className "collapse in well"
                              :id "collapse-debug"}
+
                         (dom/h6 nil "Last API call")
                         (dom/pre nil (get-in data [:debug :last-api]))
                         (dom/button #js {:className "btn btn-default"
                                          :onClick   #(discuss.communication/ajax-get (get-in data [:debug :last-api]))}
                                     "Resend API Call")
+
+                        ;; Fast login
+                        " "
+                        (dom/button #js {:className "btn btn-default"
+                                         :onClick   #(discuss.auth/login "christian" "christian")}
+                                    "One-Click Login")

                         (dom/h6 nil "Token")
                         (dom/pre nil (get-in data [:user :token]))


Use callout and panel wrapper

Use callout and panel wrapper

--- src/discuss/views.cljs
+++ src/discuss/views.cljs
@@ -215,8 +215,7 @@
                       (get-in data [:layout :intro])
                       (dom/br nil)
                       (dom/strong nil (get-in data [:issues :info]))))
-           (vlib/panel-wrapper
-             (view-dispatcher data))
+           (bs/panel-wrapper (view-dispatcher data))
            (when (get-in data [:layout :add?])
              (om/build add-element {}))
            (clipboard/view)))


creds/env! -> creds/env

creds/env! -> creds/env

--- src/eulalie/creds.cljc
+++ src/eulalie/creds.cljc
@@ -59,7 +59,7 @@
            (recur))))
      creds)))

-(defn env! []
+(defn env []
   (let [token (util/env! "AWS_SESSION_TOKEN")]
     (cond->
         {:access-key (util/env! "AWS_ACCESS_KEY_ID")


Add swipe behavior

Add swipe behavior

Can now slide the view with some momentum by swiping.

--- src/graphito/core.cljs
+++ src/graphito/core.cljs
@@ -22,6 +22,8 @@

 (def world-width 1280)
 (def world-height 800)
+(def update-interval-ms 15)
+(def swipe-damping-factor 1)

 ;; SVG setup

@@ -101,6 +103,19 @@
   (swap-state! current-state #(-> %
                                   (update :camera-x + dx)
                                   (update :camera-y + dy))))
+
+;; Math
+
+(def sqrt (.-sqrt js/Math))
+
+(defn dist-sq [x y]
+  (+ (* x x) (* y y)))
+
+(def dist (comp sqrt dist-sq))
+
+(defn vector-with-length [l x y]
+  (let [factor (/ l (dist x y))]
+    [(* factor x) (* factor y)]))

 ;; Layout

@@ -157,6 +172,8 @@

 ;; Reactive

+(def tick-observable (js/Rx.Observable.interval update-interval-ms))
+
 ;; Arrow keys

 (def key-down-observable (.fromEvent rx-observable js/document "keydown"))
@@ -181,7 +198,7 @@
   (-> arrow-keys-observable
       (.flatMapLatest (fn [arrows] (if (empty? arrows)
                                      (.empty rx-observable)
-                                     (-> rx-observable (.interval 15) (.map (constantly arrows))))))
+                                     (-> tick-observable (.map (constantly arrows))))))
       (.subscribe
         (fn [arrows]
           (let [dx (+ (if (arrows :left) -10 0) (if (arrows :right) 10 0))
@@ -193,18 +210,22 @@
 (defn hammer-manager [svg]
   (let [manager (js/Hammer.Manager. (.node svg))]
     (.add manager (js/Hammer.Pan.))
+    (-> manager (.add (js/Hammer.Swipe.))
+        (.recognizeWith (.get manager "pan")))
     manager))

-(defn pan-observable [svg]
-  (let [manager (hammer-manager svg)]
-    (.create
-      rx-observable
-      (fn [observer]
-        (.on manager "panstart panmove"
-             (fn [e] (.onNext observer e)))))))
-
-(defn pan-deltas-observable [svg]
-  (-> (pan-observable svg)
+(defn gesture-observable [manager svg gesture]
+  (.create rx-observable
+           (fn [observer] (.on manager gesture #(.onNext observer %)))))
+
+;; Gestures - pan
+
+(defn pan-observable [manager svg]
+  (gesture-observable manager svg "panstart panmove"))
+
+
+(defn pan-deltas-observable [manager svg]
+  (-> (pan-observable manager svg)
       (.bufferWithCount 2 1)
       (.map (fn [es] (let [[e1 e2] es
                            e1-center (.-center e1)
@@ -214,10 +235,53 @@
                          {:dx (- (.-x e1-center) (.-x e2-center))
                           :dy (- (.-y e1-center) (.-y e2-center))}))))))

-(defn move-camera-on-pan! [current-state]
+(defn move-camera-on-pan! [manager current-state]
   (.subscribe
-    (pan-deltas-observable (:svg @current-state))
+    (pan-deltas-observable manager (:svg @current-state))
     (fn [d] (let [{:keys [dx dy]} d] (move-camera! current-state dx dy)))))
+
+;; Gestures - swipe
+
+(defn swipe-observable
+  "A stream of velocity vectors, one per swipe."
+  [manager svg]
+  (.map (gesture-observable manager svg "swipe")
+        (fn [e] {:vx (.-velocityX e), :vy (.-velocityY e)})))
+
+(defn scroll-end-observable [svg]
+  (let [elem (.node svg)]
+    (-> rx-observable (.fromEvent elem "mousedown")
+        (.merge (-> rx-observable (.fromEvent elem "touchstart")))
+        (.map (constantly :scroll-end)))))
+
+(defn dampen [x y]
+  (let [length (dist x y)]
+    (vector-with-length (- length swipe-damping-factor) x y)))
+
+(defn swipe-displacements-observable [manager svg]
+  (let [swipes (swipe-observable manager svg)
+        scroll-ends (scroll-end-observable svg)
+        actions (.merge swipes scroll-ends)]
+    (.flatMapLatest
+      actions
+      (fn [a]
+        (if (= a :scroll-end)
+          (.empty rx-observable)
+          (let [{:keys [vx vy]} a]
+            (.generateWithRelativeTime rx-observable
+              {:dx (* update-interval-ms (or vx 0)), :dy (* update-interval-ms (or vy 0))}
+              (fn [d]
+                (> (dist-sq (:dx d) (:dy d)) 10))
+              (fn [d] (let [[x y] (apply dampen (map d [:dx :dy]))] {:dx x :dy y}))
+              identity
+              (constantly update-interval-ms))))))))
+
+
+(defn move-camera-on-swipe! [manager current-state]
+  (.subscribe
+    (swipe-displacements-observable manager (:svg @current-state))
+    (fn [d]
+      (let [{:keys [dx dy]} d] (move-camera! current-state dx dy)))))

 ;; Exported function to do magic

@@ -226,9 +290,11 @@
         width (.-clientWidth element)
         height (.-clientHeight element)
         svg (setup-svg! selector width height)
-        current-state (atom (initial-state svg width height))]
+        current-state (atom (initial-state svg width height))
+        gesture-manager (hammer-manager svg)]
     (sync-graph! @current-state)
     (load-nodes "miserables.json" (fn [nodes]
                                     (swap-state! current-state assoc :nodes nodes)))
     (move-camera-on-arrow-keys! current-state)
-    (move-camera-on-pan! current-state)))
+    (move-camera-on-pan! gesture-manager current-state)
+    (move-camera-on-swipe! gesture-manager current-state)))


Made mount! convert the mount point into a DOMElement not an UnmanagedDOMNode. Made the more generic element* fn from dom-element. Reworked RAF so it is only called when a render is actually needed - not sure if this optimization is really needed.

--- src/freactive/dom.cljs
+++ src/freactive/dom.cljs
@@ -39,34 +39,44 @@

 (def ^:private ^:dynamic *animating* nil)

-(defonce
-  render-loop
-  (request-animation-frame
-    (fn render[frame-ms]
-      (binding [*animating* true]
-        (reset! frame-time frame-ms)
-        (when enable-fps-instrumentation
-          (if (identical? instrumentation-i 14)
-            (do
-              (reset! fps (* 1000 (/ 15 (- frame-ms last-instrumentation-time))))
-              (set! instrumentation-i 0))
-            (set! instrumentation-i (inc instrumentation-i)))
-          (when (identical? 0 instrumentation-i)
-            (set! last-instrumentation-time frame-ms)))
-        (let [queue render-queue
-              n (alength queue)]
-          (when (> n 0)
-            (set! render-queue #js [])
-            (loop [i 0]
-              (when (< i n)
-                ((aget queue i))
-                (recur (inc i)))))))
-      (request-animation-frame render))))
+(def ^:private animation-requested false)
+
+(declare render-fn)
+
+(defn- request-render []
+  (when-not animation-requested
+    (set! animation-requested true)
+    (request-animation-frame render-fn)))
+
+(defn- render-fn [frame-ms]
+  (binding [*animating* true]
+    (set! animation-requested false)
+    (reset! frame-time frame-ms)
+    (when enable-fps-instrumentation
+      (if (identical? instrumentation-i 14)
+        (do
+          (reset! fps (* 1000 (/ 15 (- frame-ms last-instrumentation-time))))
+          (set! instrumentation-i 0))
+        (set! instrumentation-i (inc instrumentation-i)))
+      (when (identical? 0 instrumentation-i)
+        (set! last-instrumentation-time frame-ms)))
+    (let [queue render-queue
+          n (alength queue)]
+      (when (> n 0)
+        (set! render-queue #js [])
+        (loop [i 0]
+          (when (< i n)
+            ((aget queue i))
+            (recur (inc i)))))))
+  (when (or enable-fps-instrumentation (> (.-watchers frame-time) 0))
+    (request-render)))

 (defn queue-animation [f]
   (if *animating*
     (f)
-    (.push render-queue f)))
+    (do
+      (.push render-queue f)
+      (request-render))))

 ;; ## Attributes, Styles & Events

@@ -497,25 +507,31 @@
       (.push ch* (as-velem ch))))
   ch*)

-(defn- dom-element [ns-uri tag tail]
-  (let [[_ tag-name id class] (re-matches re-tag tag)
-        attrs? (first tail)
-        have-attrs (map? attrs?)
-        attrs (if have-attrs attrs? {})
-        attrs (cond-> attrs
-
-                (and id (not (:id attrs)))
-                (assoc :id id)
-
-                class
-                (update :class
-                        (fn [cls]
-                          (let [class (.replace class re-dot " ")]
-                            (if cls (str class " " cls) class)))))
-
-        children (if have-attrs (rest tail) tail)
-        children* (append-children* #js [] children)]
-    (DOMElement. ns-uri tag-name attrs children* nil nil nil)))
+(defn element* [elem-factory]
+  (fn [ns-uri tag tail]
+    (let [[_ tag-name id class] (re-matches re-tag tag)
+          attrs? (first tail)
+          have-attrs (map? attrs?)
+          attrs (if have-attrs attrs? {})
+          attrs (cond-> attrs
+
+                  (and id (not (:id attrs)))
+                  (assoc :id id)
+
+                  class
+                  (update :class
+                          (fn [cls]
+                            (let [class (.replace class re-dot " ")]
+                              (if cls (str class " " cls) class)))))
+
+          children (if have-attrs (rest tail) tail)
+          children* (append-children* #js [] children)]
+      (elem-factory ns-uri tag-name attrs children*))))
+
+(def dom-element
+  (element*
+   (fn [ns-uri tag-name attrs children*]
+     (DOMElement. ns-uri tag-name attrs children* nil nil nil))))

 (defn- dom-node? [x]
   (and x (> (.-nodeType x) 0)))
@@ -625,15 +641,20 @@
       (.appendChild (.-body js/document) root-node))))

 (defn- configure-root! [vroot vdom]
-  (let [root (ui/velem-insert (as-velem vdom) vroot nil)]
-    (set! (.-root vroot) root)
-    (set! (.-on-dispose vroot) (fn [] (r/dispose root)))))
+  (let [velem (as-velem vdom)]
+    (set! (.-children vroot) [velem])
+    (ui/velem-insert velem vroot nil)))

 (defn- do-unmount! [vroot]
-  (let [root (.-root vroot)]
-    (when-not (keyword-identical? :unmounted root)
-      (ui/velem-remove root)
-      (set! (.-root vroot) :unmounted))))
+  (assert (instance? DOMElement vroot) "Can only unmount from managed elements")
+  (doseq [child (.-children vroot)]
+    (ui/velem-remove child))
+  (set! (.-children vroot) nil)
+  ;; (let [root (.-root vroot)]
+  ;;   (when-not (keyword-identical? :unmounted root)
+  ;;     (ui/velem-remove root)
+  ;;     (set! (.-root vroot) :unmounted)))
+  )

 (defn mount! [mount-point vdom]
   "Makes the specified mount-point the root of a managed element tree, replacing
@@ -650,7 +671,7 @@
           (create-or-find-root-node mount-point))]
     (if-let [vroot (get-element-state root-node)]
       (do
-        (assert (.-root vroot) "Can only remount at a previous mount point")
+        ;; (assert (.-root vroot) "Can only remount at a previous mount point")
         (do-unmount! vroot)
         (configure-root! vroot vdom))
       (do
@@ -659,7 +680,14 @@
             (when last-child
               (ui/velem-remove (as-velem (get-velem-state last-child)))
               (recur))))
-        (let [vroot (wrap-unmanaged-node root-node nil)]
+        (let [vroot (DOMElement.
+                     (.-namespaceURI root-node)
+                     (.-tagName root-node)
+                     {}
+                     nil ;; TODO parent
+                     root-node
+                     nil
+                     (bind-attrs! root-node {}))]
           (configure-root! vroot vdom))))
     root-node))

@@ -672,6 +700,6 @@
           (string? mount-point)
           (find-by-id mount-point))
         vroot (get-element-state root-node)]
-    (assert (and root-node vroot (.-root vroot)) "Can't find mount point")
+    ;; (assert (and root-node vroot (.-root vroot)) "Can't find mount point")
     (do-unmount! vroot)
     root-node))


master: Fleshed out draft-update and draft-send functions.

--- src/gmail_clj/core.clj
+++ src/gmail_clj/core.clj
@@ -179,8 +179,13 @@

 (defn draft-create
   "Create a draft with the DRAFT label."
-  []
-  (throw (Exception. "Not yet implemented.")))
+  [message]
+  (let [message (if (map? message) (map->mime message) message)
+        bytes (with-open [os (java.io.ByteArrayOutputStream.)]
+                (.writeTo message os)
+                (.toByteArray os))
+        b64 (str->b64 bytes)]
+    (api-request :post-json "/users/me/drafts" {:message {:raw (URLEncoder/encode b64 "UTF-8")}} :auth (get-token) :resp :raw)))

 (defn draft-delete
   "Delete a draft by message-id."
@@ -198,10 +203,16 @@
   [& {:keys [maxResults pageToken] :or {maxResults 10}}]
   (api-request :get "/users/me/drafts/" {:maxResults maxResults :pageToken pageToken} :auth (get-token)))

-(defn draft-create
-  "Create a draft with the DRAFT label."
-  []
-  (throw (Exception. "Not yet implemented.")))
+(defn draft-update
+  "Update a draft via a message-id."
+  [message-id]
+  (api-request :put (str "/users/me/drafts/" message-id) {} :auth (get-token)))
+
+(defn draft-send
+  "Send a draft via the message-id."
+  [message-id]
+  (let []
+    (api-request :post-json "/users/me/drafts/send" {:id message-id} :auth (get-token))))

 ; Users.history


Consistently use :version for version specs (instead of sometimes :ver).

--- src/leiningen/voom.clj
+++ src/leiningen/voom.clj
@@ -79,17 +79,17 @@

 (defn format-voom-ver
   [gver]
-  (let [{:keys [ver ctime sha]} gver]
-    (assert ver   (str "format-voom-ver requires :ver " (pr-str gver)))
+  (let [{:keys [version ctime sha]} gver]
+    (assert version   (str "format-voom-ver requires :version " (pr-str gver)))
     (assert ctime (str "format-voom-ver requires :ctime " (pr-str gver)))
     (assert sha   (str "format-voom-ver requires :sha " (pr-str gver)))
-    (str (s/replace ver #"-SNAPSHOT" "")
+    (str (s/replace version #"-SNAPSHOT" "")
          "-" (formatted-timestamp timestamp-fmt ctime) "-g" sha)))

 (defn update-proj-version
   [project long-sha?]
   (let [gver (-> project :root (get-voom-version :long-sha? long-sha?))
-        upfn #(format-voom-ver (assoc gver :ver %))
+        upfn #(format-voom-ver (assoc gver :version %))
         nproj (update-in project [:version] upfn)
         nmeta (update-in (meta project) [:without-profiles :version] upfn)
         nnproj (with-meta nproj nmeta)]
@@ -457,7 +457,7 @@
 (defn parse-tag
   [tag]
   (->
-   (zipmap [:prefix :proj :ver :path :sha :no-parent] (s/split tag #"--"))
+   (zipmap [:prefix :proj :version :path :sha :no-parent] (s/split tag #"--"))
    (update-in [:path] (fnil #(s/replace % #"%" "/") :NOT_FOUND))
    (update-in [:proj] (fnil #(s/replace % #"%" "/") :NOT_FOUND))))

@@ -504,11 +504,11 @@
                                   (= (str proj-name) (:proj t))
                                   (= found-path (:path t))))
                               (:refs next-commit)))
-                (let [ver (-> reflist first :ver)]
+                (let [ver (-> reflist first :version)]
                   (assert (not= nil ver) "Failed to find version for commit.")
                   {:sha (:sha current)
                    :ctime (:ctime current)
-                   :ver ver
+                   :version ver
                    :path found-path
                    :proj proj-name
                    :gitdir gitdir
@@ -524,7 +524,7 @@
                   (assoc :repo (-> (remotes (:gitdir info)) :origin :fetch))
                   (update-in [:sha] #(subs (str % "--------") 0 7)))))
        (sort-by :ctime)
-       (print-table [:repo :proj :ver :branch :path :ctime :sha]))
+       (print-table [:repo :proj :version :branch :path :ctime :sha]))
   (newline))

 (defn fresh-version [[prj ver :as dep]]


Add assert against nil versions in 'newest-voom-ver-by-spec.

--- src/leiningen/voom.clj
+++ src/leiningen/voom.clj
@@ -459,13 +459,15 @@
                                   (= (str proj-name) (:proj t))
                                   (= found-path (:path t))))
                               (:refs next-commit)))
-                {:sha (:sha current)
-                 :ctime (:ctime current)
-                 :ver (-> reflist first :ver)
-                 :path found-path
-                 :proj proj-name
-                 :gitdir gitdir
-                 :branch found-branch}))
+                (let [ver (-> reflist first :ver)]
+                  (assert (not= nil ver) "Failed to find version for commit.")
+                  {:sha (:sha current)
+                   :ctime (:ctime current)
+                   :ver ver
+                   :path found-path
+                   :proj proj-name
+                   :gitdir gitdir
+                   :branch found-branch})))
             (partition 2 1 (concat commits [:end]))))))

 (defn print-repo-infos


lein: cider-nrepl 0.8.1

lein: cider-nrepl 0.8.1

--- lein_profiles.clj
+++ lein_profiles.clj
@@ -2,7 +2,7 @@
                   [lein-ring "0.8.13"]
                   [lein-ancient "0.5.5"]
                   [jonase/eastwood "0.2.0"]
-                  [cider/cider-nrepl "0.8.0"]
+                  [cider/cider-nrepl "0.8.1"]
                   ]}}
 {:dev {:dependencies
        [[com.cemerick/pomegranate "0.3.0"]]


figwheel-start! and stop depend on atom now

--- sidecar/src/figwheel_sidecar/repl_api.clj
+++ sidecar/src/figwheel_sidecar/repl_api.clj
@@ -1,25 +1,36 @@
 (ns figwheel-sidecar.repl-api
-  (:require [figwheel-sidecar.system :as fs]))
+  (:require
+   [figwheel-sidecar.system :as fs]
+   [com.stuartsierra.component :as component]))

-(def ^:dynamic *figwheel-system* nil)
+(defonce ^:dynamic *figwheel-system* (atom nil))
+
+#_(def temp-config
+  {:figwheel-options {:css-dirs ["resources/public/css"]
+                      :nrepl-port 7888}
+   :build-ids  ["example"]
+   :all-builds (fs/get-project-builds)})

 (defn start-figwheel!
   "If you aren't connected to an env where fighweel is running already,
   this method will start the figwheel server with the passed in build info."
-  [{:keys [figwheel-options all-builds build-ids] :as autobuild-options}]
-  (if-not *fighweel-system*
-    (let [env (fs/start-figwheel! autobuild-options)]
-      (alter-var-root (var *figwheel-system*) (fn [_] env))
-      nil)
-    (println "Figwheel system already initialized!")))
+  ([{:keys [figwheel-options all-builds build-ids] :as autobuild-options}]
+   (when @*figwheel-system*
+     (swap! *figwheel-system* component/stop))
+   (reset! *figwheel-system* (fs/start-figwheel! autobuild-options)))
+  ([]
+   ;; TODO automatically pull in config if atom is empty
+   ;; we can check if there is a project.clj
+   ;; and we can pull in the config
+   (swap! *figwheel-system* component/start)))
+
+#_ (start-figwheel! temp-config)

 (defn stop-figwheel!
   "If a figwheel process is running, this will stop all the Figwheel autobuilders and stop the figwheel Websocket/HTTP server."
   []
-  (when *figwheel-system*
-    (fs/stop-figwheel! *figwheel-system*)
-    (alter-var-root (var *figwheel-system*) (fn [_] false))
-    nil))
+  (when @*figwheel-system*
+    (swap! *figwheel-system* component/stop)))

 (comment
   ;; example usage
@@ -92,7 +103,7 @@
 (defn fig-status
   "Display the current status of the running Figwheel system."
   []
-  (ensure-system   (fs/fig-status *figwheel-system*)))
+  (ensure-system (fs/fig-status *figwheel-system*)))

 (defn- doc* [v]
   (let [{:keys [name doc arglists]} (meta v)]


Added more code-checking plugins to the clojure conf file.

--- profiles.clj
+++ profiles.clj
@@ -1 +1,5 @@
-{:user {:plugins [[lein-ancient "0.6.8"]]}}
+{:user {:plugins [[lein-ancient "0.6.8"]
+                  [lein-kibit "0.1.2"]
+                  [jonase/eastwood "0.2.3"]
+                  [venantius/yagni "0.1.4"]
+                  [lein-bikeshed "0.2.0"]]}}


Remove catnip from deps

Remove catnip from deps

--- profiles.clj
+++ profiles.clj
@@ -1,4 +1,2 @@
-{:user {:plugins [[cider/cider-nrepl "0.9.0-SNAPSHOT"]
-                  [lein-catnip "0.5.1" :exclusions [org.clojure/clojure]]
-                  [catnip "0.5.1" :exclusions [org.clojure/clojure]]]
+{:user {:plugins [[cider/cider-nrepl "0.9.0-SNAPSHOT"] ]
         :dependencies [[org.clojure/tools.nrepl "0.2.10"]]}}


oauth in a good place. need to scan video for comments and see how we may report them. or automate other interesting stuff for youtube...

--- src/thehex/youtube_api3/core.clj
+++ src/thehex/youtube_api3/core.clj
@@ -8,7 +8,16 @@
             [taoensso.timbre :as log])
   (:use [slingshot.slingshot :only [try+ throw+]]))

-;; use YOUTUBE_API_KEY environmental variable?
+;; TODO: use YOUTUBE_API_KEY environmental variable
+
+;; - Specific Comment by Id
+;; https://www.googleapis.com/youtube/v3/comments?id=z124jjhzrlfitdvcw23xfzyrdya4ij0kj&part=snippet&key=
+
+;; - Video info (statistics.. change part to get different info)
+;; https://www.googleapis.com/youtube/v3/videos?part=statistics&id=UTXCu1VQDRw&key=
+
+;; - Search all videos of pewdiepie's channel, ordered by date, newest first
+;; https://www.googleapis.com/youtube/v3/search?part=snippet&channelId=UC-lHJZR3Gqxm24_Vd_AJ5Yw&order=date&key=

 ;; With OAUTH and logged in w/ youtube user:
 ;; POST https://www.googleapis.com/youtube/v3/commenThreads?part=snippet&key=
@@ -27,36 +36,33 @@

 (def tokens (oauth/read-persisted-tokens))

+;; TODO: don't store api-key in resources. Allow default location for these configs
+;;       and allow user to specify a different folder for configs.
+;;       then read all json/edn configuration from that folder
 (def api-key (->
               (edn/read-string (slurp (clojure.java.io/resource "config.edn")))
               :api-key))

 (defn get-user-channels
-  "
-  Example...
+  " Example...
   The API supports two ways to specify an access token:
   1. curl -H \"Authorization: Bearer ACCESS_TOKEN\" https://www.googleapis.com/youtube/v3/channels?part=id&mine=true
   2. curl https://www.googleapis.com/youtube/v3/channels?part=id&mine=true&access_token=ACCESS_TOKEN
-
-  try #2 if option #1 doesnt work
-
   TODO: try catch 401. if 401, we nee to refresh the access token
   TODO: this call is not part of the oauth validation file, is an actual api call. move
-
-  Use like: (get-user-channels (:access-token tokens))
-
-  "
-  [access-token]
+  Use like: (get-user-channels) "
+  []
   (try+
    (let [url (str config/api-base "channels?part=id&mine=true")
-         body (-> @(http/get url
-                            {:headers {:Authorization (str "Bearer " access-token)}})
+         body (-> (http/get url
+                            {:headers {:Authorization
+                                       (str "Bearer " (:access-token tokens))}
+                             :as :json})
                   :body ;; body is json
                   ;; TODO: parse response json to actually get info
                   ;; will receive a 401 HTTP unauthorize if the access token expired
                   ;;:user ... old example on getting data...
                   )
-         ;; TODO: this is json at this point:
          as-json (json/read-str body)
          result-count (get (get as-json "pageInfo") "totalResults")]
      (log/debug (str "Got body in get-user-channels: " body))
@@ -67,31 +73,14 @@
    (catch [:status 401] e (log/error e))))

 (defn get-video-commentThreads
-  "
-  https://www.googleapis.com/youtube/v3/commentThreads?part=snippet&videoId=UTXCu1VQDRw&key=
-
-  Use like:
-  "
-  [api-key video-id]
+  " https://www.googleapis.com/youtube/v3/commentThreads?part=snippet&videoId=UTXCu1VQDRw&key=
+  Use like: (get-video-commentThreads 84389473498348) "
+  [video-id]
   (try+
    (let [url (str config/api-base "commentThreads?part=snippet&videoId="
                   video-id "&order=time&key=" api-key)
-         body (-> @(http/get url) :body)]
-     (let [as-json (json/read-str body)
-           items (get as-json "items")]
-       ;; TODO: go through the items, parse and getting info we want
-       (log/trace "Got commentThreads for a video:")
-       items))
-   (catch [:status 401] e (log/error e))))
-
-(defn get-video-comments
-  "Specific Comment by Id
-   https://www.googleapis.com/youtube/v3/comments?id=z124jjhzrlfitdvcw23xfzyrdya4ij0kj&part=snippet&key="
-  [api-key parent-id]
-  (try+
-   (let [url (str config/api-base "comments?part=snippet&parentId="
-                  parent-id "&key=" api-key)
-         body (-> @(http/get url) :body)]
+         body (-> (http/get url {:as :json}) :body)]
+     (log/debug (str "Got videos from search: " body))
      (let [as-json (json/read-str body)
            items (get as-json "items")]
        ;; TODO: go through the items, parse and getting info we want
@@ -99,28 +88,6 @@
        items))
    (catch [:status 401] e (log/error e))))

-(defn mark-comment-as-spam
-  "
-  https://www.googleapis.com/youtube/v3/commentThreads?part=snippet&videoId=UTXCu1VQDRw&key=
-
-  Use like:
-  "
-  [access-token comment-id]
-  (log/warn "Marking comment as spam")
-  (try+
-   (let [url (str config/api-base "comments/markAsSpam?id="
-                  comment-id)]
-     ;; should check for a 204 which is confirmation for marking as spam
-     @(http/post url
-                {:headers {:Authorization (str "Bearer " access-token)}})
-     ;; (log/debug "marked comment as spam...")
-     )
-   (catch [:status 401] e (log/error e))
-   (catch [:status 403] e (log/error e))))
-
-;; repl'ing.. this next call worked!
-(mark-comment-as-spam (:access-token tokens) "z13xvl2ovsqtiz1wj04cfrpxgkmwhvb5zok0k")
-
 (defn get-channel-activity
   "Original Url: https://www.googleapis.com/youtube/v3/activities?part=snippet&channelId=UC-lHJZR3Gqxm24_Vd_AJ5Yw&key=

@@ -128,45 +95,41 @@

   my channel= UC4-vzjcBolmvYWYP6ldbLbA
-  another channel id = UC4u8goEsLgpPvDX2mKD70nQ
-  "
-  [api-key channel-id]
+  another channel id = UC4u8goEsLgpPvDX2mKD70nQ "
+  [channel-id]
   (let [url (str config/api-base "activities?part=snippet&channelId=" channel-id "&key=" api-key)
-        body (-> @(http/get url) :body)]
+        body (-> (http/get url {:as :json}) :body)]
     (log/debug (str "Got activites: " body))
     body))

 (defn search-videos
   "Original Url: https://www.googleapis.com/youtube/v3/search?part=snippet&channelId=UC-lHJZR3Gqxm24_Vd_AJ5Yw&key=

-  Search all videos of pewdiepie's channel, ordered by date, newest first
-  https://www.googleapis.com/youtube/v3/search?part=snippet&channelId=UC-lHJZR3Gqxm24_Vd_AJ5Yw&order=date&key=
-
   Use like: `(search-videos api-key 'UC-lHJZR3Gqxm24_Vd_AJ5Yw')`
   ^ pewds channel

   my channel= UC4-vzjcBolmvYWYP6ldbLbA
-  another channel id = UC4u8goEsLgpPvDX2mKD70nQ
-  "
-  [api-key channel-id]
+  another channel id = UC4u8goEsLgpPvDX2mKD70nQ "
+  [channel-id]
   (let [url (str config/api-base "search?part=snippet&channelId=" channel-id
                  "&key=" api-key "&order=date")
-        body (-> @(http/get url) :body)]
+        body (-> (http/get url {:as :json}) :body)]
     (log/debug (str "Got videos from search: " body))
     (let [as-json (json/read-str body)]
       ;; TODO: go through the items, parse and getting info we want
       (get as-json "items"))))

-;; (defn parse-videos
-;;   "Loop through videos for things that interest us..."
-;;   []
-;;   "")
-
-;; ;; (get-video-commentThreads api-key "d2dNb0wdJF0")
-
-;; ;; (search-videos api-key "UC-lHJZR3Gqxm24_Vd_AJ5Yw")
-
-;; ;; videos for a channel:
+(defn parse-videos
+  "Loop through videos, find all comment threads, scan each,
+  store bad ones on a file..."
+  []
+  "")
+
+;; (get-video-commentThreads api-key "d2dNb0wdJF0")
+
+;; (search-videos api-key "UC-lHJZR3Gqxm24_Vd_AJ5Yw")
+
+;; videos for a channel:
 ;; [{"kind" "youtube#searchResult",
 ;;  "etag" "\"uQc-MPTsstrHkQcRXL3IWLmeNsM/xL2Kk-wHmX7jWjGq4UC1iRNQW00\"",
 ;;  "id" {"kind" "youtube#video",
@@ -282,9 +245,7 @@
 ;;  "publishedAt" "2017-02-18T19:49:34.000Z"}},
 ;;  "canReply" false,
 ;;  "totalReplyCount" 0,
-;;             "isPublic" true}}
-
-;;  {"kind" "youtube#commentThread",
+;;  "isPublic" true}} {"kind" "youtube#commentThread",
 ;;  "etag" "\"uQc-MPTsstrHkQcRXL3IWLmeNsM/Qb8XHO_j4KGnp1v3N1QKPcl6wig\"",
 ;;  "id" "z12shlsrdtz0gjrm023ytpdxypjxdhoni",
 ;;  "snippet" {"videoId" "d2dNb0wdJF0",
@@ -305,9 +266,7 @@
 ;;  "publishedAt" "2017-02-18T19:49:32.000Z"}},
 ;;  "canReply" false,
 ;;  "totalReplyCount" 0,
-;;             "isPublic" true}}
-
-;;  {"kind" "youtube#commentThread",
+;;  "isPublic" true}} {"kind" "youtube#commentThread",
 ;;  "etag" "\"uQc-MPTsstrHkQcRXL3IWLmeNsM/_v5JPAWQbGteqGgPhs1FS3pmVYc\"",
 ;;  "id" "z13jfjqqqyqcsf2qv04cilyhoymutxwaxho",
 ;;  "snippet" {"videoId" "d2dNb0wdJF0",
@@ -328,9 +287,7 @@
 ;;  "publishedAt" "2017-02-18T19:49:27.000Z"}},
 ;;  "canReply" false,
 ;;  "totalReplyCount" 0,
-;;             "isPublic" true}}
-
-;;  {"kind" "youtube#commentThread",
+;;  "isPublic" true}} {"kind" "youtube#commentThread",
 ;;  "etag" "\"uQc-MPTsstrHkQcRXL3IWLmeNsM/JYrx4nX_y60-v8uR48sjh0c-dpk\"",
 ;;  "id" "z13hurtjypejstvra04ci5wwvqubvzxwm24",
 ;;  "snippet" {"videoId" "d2dNb0wdJF0",
@@ -351,9 +308,7 @@
 ;;  "publishedAt" "2017-02-18T19:49:25.000Z"}},
 ;;  "canReply" false,
 ;;  "totalReplyCount" 0,
-;;             "isPublic" true}}
-
-;;  {"kind" "youtube#commentThread",
+;;  "isPublic" true}} {"kind" "youtube#commentThread",
 ;;  "etag" "\"uQc-MPTsstrHkQcRXL3IWLmeNsM/FznlI6Cbcq2bl91OxawulNEmK_0\"",
 ;;  "id" "z13xsdoynkyzhpyzm04ccduivvfss5h5j44",
 ;;  "snippet" {"videoId" "d2dNb0wdJF0",
@@ -647,32 +602,28 @@
 ;;  "publishedAt" "2017-02-18T19:49:00.000Z"}},
 ;;  "canReply" false,
 ;;  "totalReplyCount" 0,
-;;             "isPublic" true}}
-
-;;  {"kind" "youtube#commentThread",
-;;   "etag" "\"uQc-MPTsstrHkQcRXL3IWLmeNsM/6rzPsBSlGgYUbsFdaNT1W8lYb5g\"",
-;;   "id" "z13xvl2ovsqtiz1wj04cfrpxgkmwhvb5zok0k",
-;;   "snippet" {"videoId" "d2dNb0wdJF0",
-;;              "topLevelComment" {"kind" "youtube#comment",
-;;                                 "etag" "\"uQc-MPTsstrHkQcRXL3IWLmeNsM/vO1aAbS4eSd6Z2Swj-6PS4KtZ-c\"",
-;;                                 "id" "z13xvl2ovsqtiz1wj04cfrpxgkmwhvb5zok0k",
-;;                                 "snippet" {"textOriginal" "This is Bob - 🐨\nBob has no penis\n1 like = 1 penis 🍆",
-;;                                            "updatedAt" "2017-02-18T19:48:59.000Z",
-;;                                            "authorProfileImageUrl" "https://yt3.ggpht.com/-1FlFWIb0gFY/AAAAAAAAAAI/AAAAAAAAAAA/mFk1cYFrwxM/s28-c-k-no-mo-rj-c0xffffff/photo.jpg",
-;;                                            "authorDisplayName" "iArvin",
-;;                                            "videoId" "d2dNb0wdJF0",
-;;                                            "textDisplay" "This is Bob - 🐨
Bob has no penis
1 like = 1 penis 🍆",
-;;                                            "authorChannelUrl" "http://www.youtube.com/channel/UC7eXcXvkGEoYpjjYv2hrqxA",
-;;                                            "canRate" false,
-;;                                            "authorChannelId" {"value" "UC7eXcXvkGEoYpjjYv2hrqxA"},
-;;                                            "likeCount" 0,
-;;                                            "viewerRating" "none",
-;;                                            "publishedAt" "2017-02-18T19:48:59.000Z"}},
-;;              "canReply" false,
-;;              "totalReplyCount" 0,
-;;              "isPublic" true}}
-
-;;  {"kind" "youtube#commentThread",
+;;  "isPublic" true}} {"kind" "youtube#commentThread",
+;;  "etag" "\"uQc-MPTsstrHkQcRXL3IWLmeNsM/6rzPsBSlGgYUbsFdaNT1W8lYb5g\"",
+;;  "id" "z13xvl2ovsqtiz1wj04cfrpxgkmwhvb5zok0k",
+;;  "snippet" {"videoId" "d2dNb0wdJF0",
+;;  "topLevelComment" {"kind" "youtube#comment",
+;;  "etag" "\"uQc-MPTsstrHkQcRXL3IWLmeNsM/vO1aAbS4eSd6Z2Swj-6PS4KtZ-c\"",
+;;  "id" "z13xvl2ovsqtiz1wj04cfrpxgkmwhvb5zok0k",
+;;  "snippet" {"textOriginal" "This is Bob - 🐨\nBob has no penis\n1 like = 1 penis 🍆",
+;;  "updatedAt" "2017-02-18T19:48:59.000Z",
+;;  "authorProfileImageUrl" "https://yt3.ggpht.com/-1FlFWIb0gFY/AAAAAAAAAAI/AAAAAAAAAAA/mFk1cYFrwxM/s28-c-k-no-mo-rj-c0xffffff/photo.jpg",
+;;  "authorDisplayName" "iArvin",
+;;  "videoId" "d2dNb0wdJF0",
+;;  "textDisplay" "This is Bob - 🐨
Bob has no penis
1 like = 1 penis 🍆",
+;;  "authorChannelUrl" "http://www.youtube.com/channel/UC7eXcXvkGEoYpjjYv2hrqxA",
+;;  "canRate" false,
+;;  "authorChannelId" {"value" "UC7eXcXvkGEoYpjjYv2hrqxA"},
+;;  "likeCount" 0,
+;;  "viewerRating" "none",
+;;  "publishedAt" "2017-02-18T19:48:59.000Z"}},
+;;  "canReply" false,
+;;  "totalReplyCount" 0,
+;;  "isPublic" true}} {"kind" "youtube#commentThread",
 ;;  "etag" "\"uQc-MPTsstrHkQcRXL3IWLmeNsM/1Dn25Gd_MVoW1IWVobV4AvRgxlo\"",
 ;;  "id" "z12dwv2h2t3bwjznt22zhjliux3dj3ok2",
 ;;  "snippet" {"videoId" "d2dNb0wdJF0",


only render namespace if it has test items

--- src/untangled_spec/renderer.cljs
+++ src/untangled_spec/renderer.cljs
@@ -201,15 +201,16 @@
   (render
     [this]
     (let [{:keys [current-filter] :as tests-by-namespace} (om/props this)]
-      (dom/li #js {:className "test-item"}
-        (dom/div #js {:className "test-namespace"}
-          (dom/h2 #js {:className (test-item-class (:status tests-by-namespace))}
-            (str (:name tests-by-namespace)))
-          (dom/ul #js {:className "test-list"}
-            (sequence (comp (filters current-filter)
-                        (map #(assoc % :current-filter current-filter))
-                        (map ui-test-item))
-              (:test-items tests-by-namespace))))))))
+      (when (seq (:test-items tests-by-namespace))
+        (dom/li #js {:className "test-item"}
+          (dom/div #js {:className "test-namespace"}
+            (dom/h2 #js {:className (test-item-class (:status tests-by-namespace))}
+              (str (:name tests-by-namespace)))
+            (dom/ul #js {:className "test-list"}
+              (sequence (comp (filters current-filter)
+                          (map #(assoc % :current-filter current-filter))
+                          (map ui-test-item))
+                        (:test-items tests-by-namespace)))))))))
 (def ui-test-namespace (om/factory TestNamespace {:keyfn :name}))

 (defn filter-button


Pulling out creation of vbo.

Pulling out creation of vbo.

--- src/opengl_sandbox/antons/hello_triangle.clj
+++ src/opengl_sandbox/antons/hello_triangle.clj
@@ -57,23 +57,26 @@
   (GL11/glDrawArrays GL11/GL_TRIANGLES 0 3)
   (GL30/glBindVertexArray 0))

-(defn populate-vao []
-  (let [vao (GL30/glGenVertexArrays)
-        vbo (GL15/glGenBuffers)
-        points (create-float-buffer triangle-points)]
+(defn create-vbo [points attrib-index]
+  (let [vbo (GL15/glGenBuffers)]
+    (GL15/glBindBuffer GL15/GL_ARRAY_BUFFER vbo)
+    (GL15/glBufferData GL15/GL_ARRAY_BUFFER points GL15/GL_STATIC_DRAW)
+    (GL20/glVertexAttribPointer attrib-index 3 GL11/GL_FLOAT false 0 0)
+    (GL15/glBindBuffer GL15/GL_ARRAY_BUFFER 0)))
+
+(defn populate-vao [all-points]
+  (let [vao (GL30/glGenVertexArrays)]
     (GL30/glBindVertexArray vao)
     (GL20/glEnableVertexAttribArray 0)

-    (GL15/glBindBuffer GL15/GL_ARRAY_BUFFER vbo)
-    (GL15/glBufferData GL15/GL_ARRAY_BUFFER points GL15/GL_STATIC_DRAW)
-    (GL20/glVertexAttribPointer 0 3 GL11/GL_FLOAT false 0 0)
-    (GL15/glBindBuffer GL15/GL_ARRAY_BUFFER 0)
+    (doseq [points all-points]
+      (create-vbo points (.indexOf all-points points)))

     (GL30/glBindVertexArray 0)
     vao))

 (defn render-loop []
-  (let [vao (populate-vao)
+  (let [vao (populate-vao (map create-float-buffer [triangle-points]))
         shader-program (create-shader-program)]
     (while (not (Display/isCloseRequested))
       (Display/update)


added parse-block-time to video.clj

added parse-block-time to video.clj

--- src/elliot/video.clj
+++ src/elliot/video.clj
@@ -16,13 +16,31 @@
 (defn parse-int [s]
    (Integer. (re-find  #"\d+" s )))

-(defn make-video [f]
+(defn parse-block-time [block-time-text]
+  (->> block-time-text
+        (#(clojure.string/split % #" --> "))
+       (map #(clojure.string/split % #"[:,]"))
+       (map (fn [t] (map #(parse-int %) t)))
+       (map #(interleave [:hour :minute :second :millis] %))
+       (map #(apply hash-map %))
+       (interleave [:start :stop])
+       (apply hash-map)))
+
+(deftest test-parse-block-time
+  (let [test-data "00:05:01,670 --> 00:05:06,970"]
+    (is (=
+         (parse-block-time test-data)
+         {:start {:hour 0 :second 1 :millis 670 :minute 5}
+          :stop  {:hour 0 :second 6 :millis 970 :minute 5}}))))
+
+(defn make [f]
   (-> (slurp f)
       (clojure.string/replace #"<[^>]+>" "")
       (clojure.string/split #"\r\n\r\n")
       ((partial map #(clojure.string/split % #"\r\n")))
       ((partial map #(do {:block-id (parse-int (first %))
-                          :words (nlp-utils/tokenize (nth % 2))})))))
+                          :words (nlp-utils/tokenize (nth % 2))
+                          :time (parse-block-time (second %))})))))

 (defn de-blockify [video key]
   (reduce
@@ -58,7 +76,7 @@
   ;;Tests
 (deftest test-blockify
   (let [control
-        (make-video "resources/subs/elliot_hulse/p2zvOJe1Iq4_0_en.srt")]
+        (make "resources/subs/elliot_hulse/p2zvOJe1Iq4_0_en.srt")]

    (is (thrown? Exception
                 (blockify-list


take chat into account when drawing the signin button

--- src-cljs/frontend/components/drawing.cljs
+++ src-cljs/frontend/components/drawing.cljs
@@ -3,6 +3,7 @@
             [frontend.state :as state]
             [frontend.utils :as utils]
             [goog.dom]
+            [goog.style]
             [om.core :as om :include-macros true]
             [om.dom :as dom :include-macros true]))

@@ -221,7 +222,8 @@
   (reify
     om/IDidMount
     (did-mount [_]
-      (let [vw (.-width (goog.dom/getViewportSize))]
+      ;; TODO: would be nice to get this a different way :(
+      (let [vw (.-width (goog.style/getSize (goog.dom/getElement "svg-canvas")))]
         (run-animation owner (signup-animation document vw))))
     om/IWillUnmount
     (will-unmount [_]


add debug

add debug

--- src/fileape/conf.clj
+++ src/fileape/conf.clj
@@ -9,6 +9,8 @@
   (:require [clojure.tools.logging :refer [debug]]))

+(defn parse-topic [{:keys [env-key-parser] :or {env-key-parser identity}} topic]
+  (env-key-parser topic))

 (defn get-conf
   ([conf k]
@@ -16,7 +18,9 @@
   ([topic conf k]
     (get-conf topic conf k nil))
   ([topic conf k default-v]
-    (let [kw-k (keyword (str (name topic) "." (name k)))]
+   (debug "conf " conf)
+
+    (let [kw-k (keyword (str (name (parse-topic conf topic)) "." (name k)))]
       (if-let [v (get conf kw-k)]
         (do
           (debug "get-conf " kw-k " => " v)


Allow to disable currying

Allow to disable currying

--- src/ganjika/core.clj
+++ src/ganjika/core.clj
@@ -21,16 +21,22 @@
 (defn- declare-fn
   "Given a method spec create an unevaluated function form, currying
   over the provided instance"
-  [spec instance]
+  [spec instance no-currying]
   (let [method-name (symbol (:name spec))
         raw-method-name (symbol (str "." (:raw-name spec)))
         params (vec (map gensym (range (:args spec))))
         is-void (:is-void spec)]
-    `(defn ~method-name [~@params]
-       (let [return# (~raw-method-name @~instance ~@params)]
-         (if ~is-void
-           @~instance
-           return#)))))
+    (if no-currying
+      `(defn ~method-name [this# ~@params]
+         (let [return# (~raw-method-name this# ~@params)]
+           (if ~is-void
+             this#
+             return#)))
+      `(defn ~method-name [~@params]
+         (let [return# (~raw-method-name @~instance ~@params)]
+           (if ~is-void
+             @~instance
+             return#))))))

 (defn- define-symbol
   "Creates and return a symbol that resolves to the provided object"
@@ -39,26 +45,31 @@
         obj-symbol (gensym class-name)]
     (eval `(def ~obj-symbol ~object))))

-;; TODO allow to receive instance
 (defmacro def-java-methods
-  "TODO"
-  [target & {:keys [using-ns]}]
-  (let [target (eval target)
-        [clazz instance] (if (class? target)
-                           [target (.newInstance target)]
-                           [(class target) target])
+  "Maps the provided provided Java class or object methods to
+  clojure-like functions (inside using-ns if any or in the current
+  namespace). If target is a class an instance is created (assumes
+  default constructor) unless currying is disabled (via :currying
+  false)."
+  [target & {:keys [using-ns currying]}]
+  (let [no-currying (false? currying)
+        target (eval target)
+        [clazz instance] (cond
+                          (and (class? target) no-currying) [target nil]
+                          no-currying [(class target) nil]
+                          (class? target) [target (.newInstance target)]
+                          :else [(class target) target])
         specs (map method-spec (.getDeclaredMethods clazz))
-        target-sym (define-symbol instance)
+        target-sym (if-not no-currying (define-symbol instance))
         current-ns (.getName *ns*)]
-    (assert (instance? clazz instance))
+    (when-not no-currying (assert (instance? clazz instance)))
     `(do
        (when ~using-ns
          (in-ns ~using-ns))
-       ~@(map #(declare-fn % target-sym) specs)
+       ~@(map #(declare-fn % target-sym no-currying) specs)
        (in-ns (quote ~current-ns)))))

 (comment
-  ;; no currying
   ;; multiple arity
   (refer 'fus.noma.da :only ['mouse-move])
   (to-clj java.awt.Robot :using-ns 'fus.noma.da))


Add FIXME

Add FIXME

--- src/grimoire/doc.clj
+++ src/grimoire/doc.clj
@@ -183,6 +183,7 @@
     (doseq [var ns-vars]
       (write-docs-for-var config var))

+    ;; FIXME: this shouldn't be needed
     (when (= ns 'clojure.core)
       (write-docs-for-specials config)))


Make render use cursor.

Make render use cursor.

--- src/lab_notebook/core.cljs
+++ src/lab_notebook/core.cljs
@@ -8,7 +8,7 @@
   (reify
     om/IRender
     (render [this]
-      (dom/div nil "Hello!"))))
+      (dom/div nil (:message cursor)))))

 (om/root app-container appstate
   {:target (. js/document (getElementById "app"))})


Ditto for dateOf

Ditto for dateOf

--- test/clojurewerkz/cassaforte/cql_test.clj
+++ test/clojurewerkz/cassaforte/cql_test.clj
@@ -9,7 +9,7 @@
             [qbits.hayt.dsl.statement :as hs]
             [qbits.hayt.dsl.clause :as hc]
             [qbits.hayt.fns :as fns]
-            [clj-time.core :refer [seconds ago]]
+            [clj-time.core :refer [seconds ago before?]]
             [clj-time.coerce :as cc]))

 (let [s (client/connect ["127.0.0.1"])]
@@ -393,6 +393,23 @@

     (drop-table s :events))

+  (deftest test-timeuuid-dateof
+    (create-table s :events
+                  (column-definitions {:message      :varchar
+                                       :created_at   :timeuuid
+                                       :primary-key  [:created_at]}))
+
+    (let [dt (-> 2 seconds ago)]
+      (dotimes [i 20]
+        (insert s :events {:created_at (fns/now) :message (format "Message %d" i)}))
+      (let [xs  (select s :events
+                        (columns (fns/date-of :created_at))
+                        (limit 5))
+            dt' (cc/from-date (get (first xs) (keyword "dateOf(created_at)")))]
+        (is (before? dt dt'))))
+
+    (drop-table s :events))
+

   (deftest test-paginate
     (create-table s :tv_series


We no longer use fragments with the v1-run route

--- src-cljs/frontend/routes.cljs
+++ src-cljs/frontend/routes.cljs
@@ -256,16 +256,8 @@
                                                 :repo repo}))))

   (defroute v1-run #"/workflow-run/([^/]+)"
-    [run-id _ maybe-fragment]
-    (let [fragment-args (-> maybe-fragment
-                            :_fragment
-                            parse-build-page-fragment
-                            (select-keys [:tab :action-id :container-id])
-                            (set/rename-keys {:tab :route-params/tab
-                                              :action-id :route-params/action-id
-                                              :container-id :route-params/container-id}))]
-      (open! app :route/run {:route-params (assoc fragment-args
-                                                  :run/id (uuid run-id))})))
+    [run-id]
+    (open! app :route/run {:route-params {:run/id (uuid run-id)}}))

   (defroute v1-job #"/workflow-run/([^/]+)/([^/]+)"
     [run-id job-name _ maybe-fragment]