using os and flavors

using os and flavors

--- src/aws/provider.clj
+++ src/aws/provider.clj
@@ -31,7 +31,7 @@

 (import-logging)

-(defn creds [] (hypervisor :aws))
+(defn creds [] (dissoc (hypervisor :aws) :ostemplates))

 (defn wait-for-status [instance req-stat timeout]
   "Waiting for ec2 machine status timeout is in mili"
@@ -76,15 +76,19 @@
       (s/partial-system (spec :system-id)
         {:machine {:ip (pubdns-to-ip ec2-host)}}))))

-(defn set-hostname [spec endpoint instance-id user]
+(defn set-hostname [{:keys [aws machine] :as spec} endpoint instance-id user]
   "Uses a generic method of setting hostname in Linux (see http://www.debianadmin.com/manpages/sysctlmanpage.txt)
    Note that in ec2 both Centos and Ubuntu use sudo!"
-  (let [{:keys [hostname domain]} (spec :machine)
+  (let [{:keys [hostname domain os]} machine
         remote {:host (pub-dns endpoint instance-id) :user user}]
     (execute (<< "echo kernel.hostname=~{hostname} | sudo tee -a /etc/sysctl.conf") remote )
     (execute (<< "echo kernel.domainname=\"~{hostname}.~{domain}\" | sudo tee -a /etc/sysctl.conf") remote )
     (execute (<< "echo 127.0.1.1 ~{hostname}.~{domain} ~{hostname} | sudo tee -a /etc/hosts") remote )
-    (execute (<< "echo ~{hostname} | sudo tee /etc/hostname") remote )
+    (case (hypervisor :aws :ostemplates os :flavor)
+      :debian  (execute (<< "echo ~{hostname} | sudo tee /etc/hostname") remote )
+      :redhat  (execute (<< "/bin/sed -i 's/HOSTNAME=.*/HOSTNAME=~{hostname}.~{domain}/g") remote )
+      (throw+ ::no-matching-flavor :msg (<< "no os flavor found for ~{os}"))
+      )
     (execute "sudo sysctl -e -p" remote)
     (with-ctx ec2/create-tags [(instance-desc endpoint instance-id :id)] {:Name hostname})
     ))
@@ -99,13 +103,16 @@
     (do ~@body)
     (throw+ {:type ::aws:missing-id :message "Instance id not found"})))

+(defn image-id [machine]
+  (hypervisor :aws :ostemplates (machine :os) :ami))
+
 (defn handle-volumes
    "attached and waits for ebs volumes"
-   [{:keys [image-id volumes]} endpoint instance-id]
-  (when (= (image-desc endpoint image-id :root-device-type) "ebs")
+   [{:keys [aws machine] :as spec} endpoint instance-id]
+  (when (= (image-desc endpoint (image-id machine) :root-device-type) "ebs")
     (wait-for-attach endpoint instance-id [10 :minute]))
   (let [zone (instance-desc endpoint instance-id :placement :availability-zone)]
-    (doseq [{:keys [device size]} volumes]
+    (doseq [{:keys [device size]} (aws :volumes)]
       (let [{:keys [volumeId]} (with-ctx ebs/create-volume size zone)]
         (wait-for {:timeout [10 :minute]} #(= "available" (with-ctx ebs/state volumeId))
            {:type ::aws:ebs-volume-availability :message "Failed to wait for ebs volume to become available"})
@@ -123,15 +130,23 @@
         {:type ::aws:ebs-volume-availability :message "Failed to wait for ebs volume to become available"})
      (with-ctx ebs/delete-volume (ebs :volume-id))))

+(defn create-instance
+   "creates instance from aws"
+   [{:keys [aws machine] :as spec} endpoint]
+   {:pre [(clojure.set/subset? (into #{} (keys aws))
+       #{:volumes :min-count :max-count :instance-type :key-name})]}
+   (let [inst (merge (dissoc aws :volumes) {:image-id (image-id machine)})]
+     (-> (with-ctx ec2/run-instances inst) :instances first :id)))
+
 (defconstrainedrecord Instance [endpoint spec user]
   "An Ec2 instance"
   [(provider-validation spec) (-> endpoint nil? not)]
   Vm
   (create [this]
-    (let [{:keys [aws]} spec instance-id (-> (with-ctx ec2/run-instances (dissoc aws :volumes)) :instances first :id)]
+    (let [instance-id (create-instance spec endpoint)]
        (s/partial-system (spec :system-id) {:aws {:instance-id instance-id}})
        (debug "created" instance-id)
-       (handle-volumes aws endpoint instance-id)
+       (handle-volumes spec endpoint instance-id)
        (when-let [ip (get-in spec [:machine :ip])]
          (debug (<<  "Associating existing ip ~{ip} to instance-id"))
           (with-ctx eip/assoc-pub-ip instance-id ip))


Put workaround under Input interface.

Put workaround under Input interface.

--- src/onyx/peer/function.clj
+++ src/onyx/peer/function.clj
@@ -35,9 +35,10 @@
    {}))

 (defrecord Function [replica peer-replica-view state messenger egress-tasks]
-  p-ext/Pipeline

-  ;;; Start temp fix for: https://github.com/onyx-platform/onyx/issues/344
+  p-ext/PipelineInput
+
+ ;;; Start temp fix for: https://github.com/onyx-platform/onyx/issues/344
   (ack-segment [this event message-id])

   (retry-segment [this event message-id])
@@ -46,6 +47,8 @@

   (drained? [this event])
   ;;; End temp fix.
+
+  p-ext/Pipeline

   (read-batch
     [_ event]


Optimise

Optimise

--- src/onyx/peer/function.clj
+++ src/onyx/peer/function.clj
@@ -28,20 +28,18 @@
   (let [{:keys [task-map id job-id task-id] :as event} (get-event state)
         pipeline (get-pipeline state)
         batch-size (:onyx/batch-size task-map)
-        [next-reader batch]
-        (loop [reader pipeline
-               outgoing []]
-          (assert pipeline)
-          (if (< (count outgoing) batch-size)
-            (let [next-reader (oi/next-state reader state)
-                  segment (oi/segment next-reader)]
-              (if segment
-                (recur next-reader
-                       (conj outgoing (types/input (random-uuid) segment)))
-                [next-reader outgoing]))
-            [reader outgoing]))]
+        [next-reader batch] (loop [reader pipeline
+                                   outgoing (transient [])]
+                              (assert pipeline)
+                              (if (< (count outgoing) batch-size)
+                                (let [next-reader (oi/next-state reader state)
+                                      segment (oi/segment next-reader)]
+                                  (if segment
+                                    (recur next-reader (conj! outgoing (types/input segment)))
+                                    [next-reader outgoing]))
+                                [reader outgoing]))]
     (debug "Reading batch" job-id task-id "peer-id" id batch)
     (-> state
         (set-pipeline! next-reader)
-        (set-event! (assoc event :batch batch))
+        (set-event! (assoc event :batch (persistent! batch)))
         (advance))))


Fix wrong precondition on repeat function.

Thanks to @kennyjwilli for report it.

--- src/beicon/core.cljs
+++ src/beicon/core.cljs
@@ -87,7 +87,7 @@
   ([v]
    (repeat v -1))
   ([v n]
-   {:pre [(number? v)]}
+   {:pre [(number? n)]}
    (js/Rx.Observable.repeat v n)))

 (defn publish


Enable unsubscribe operation just calling the unsub function.

--- src/beicon/core.cljs
+++ src/beicon/core.cljs
@@ -173,27 +173,31 @@
   in the observable sequence."
   [ob f]
   {:pre [(observable? ob) (fn? f)]}
-  (.subscribeOnNext ob f))
+  (let [disposable (.subscribeOnNext ob f)]
+    #(.dispose disposable)))

 (defn on-error
   "Subscribes a function to invoke upon exceptional termination
   of the observable sequence."
   [ob f]
   {:pre [(observable? ob) (fn? f)]}
-  (.subscribeOnError ob f))
+  (let [disposable (.subscribeOnError ob f)]
+    #(.dispose disposable)))

 (defn on-end
   "Subscribes a function to invoke upon graceful termination
   of the observable sequence."
   [ob f]
   {:pre [(observable? ob) (fn? f)]}
-  (.subscribeOnCompleted ob f))
+  (let [disposable (.subscribeOnCompleted ob f)]
+    #(.dispose disposable)))

 (defn subscribe
   "Subscribes an observer to the observable sequence."
   [ob nf ef cf]
   {:pre [(observable? ob)]}
-  (.subscribe ob nf ef cf))
+  (let [disposable (.subscribe ob nf ef cf)]
+    #(.dispose disposable)))

 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; Observable Transformations
@@ -398,7 +402,7 @@
                        (on-end stream #(do (xsink nil)
                                            (sink nil)))
                        (fn []
-                         (.dispose unsub)))))]
+                         (unsub)))))]
     ns))

 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


initial work on templating

initial work on templating

--- src/bløggr/core.clj
+++ src/bløggr/core.clj
@@ -8,6 +8,11 @@
             [clygments.core :as pygments]))

 (def cegdown-ext [:fenced-code-blocks :autolinks])
+
+(html/deftemplate post-template "layouts/post.html" [header body]
+                  [:div#article-content] (html/html-content body)
+                  [:#article-title] (html/content (header :title)))
+

 (defn parse-datestring [date-str]
   (tf/parse (tf/formatter "yyyy-MM-dd HH:mm:ssZ") date-str))
@@ -46,16 +51,20 @@
 (defn render [post]
   (assoc post :body (apply str (html/emit* (post :body)))))

+(defn apply-post-layout [post]
+  (assoc post :body (apply str (post-template (post :header) (post :body)))))
+
 (defn get-posts []
-  (->> (stasis/slurp-directory "posts/" #"test.*\.(md|markdown)$")
-       (vals)
-       (map parse-post)
-       (map markdown)
-       (map enliveify)
-       (map highlight)
-       (map render)
-       (map filename-body-map)
-       (reduce merge)))
+    (->> (stasis/slurp-directory "posts/" #"test.*\.(md|markdown)$")
+         (vals)
+         (map parse-post)
+         (map markdown)
+         (map enliveify)
+         (map highlight)
+         (map render)
+         (map apply-post-layout)
+         (map filename-body-map)
+         (reduce merge)))

 (defn get-css []
   (stasis/slurp-directory "resources/css/" #".*\.css"))


fix lint errors from Eastwood

fix lint errors from Eastwood

--- src/otp_api_proxy/core.clj
+++ src/otp_api_proxy/core.clj
@@ -281,15 +281,6 @@
                    itinernary->add-route-span
                    )))

-(defresource ws-otp-cooked []
-  :available-media-types ["application/json" "text/plain"]
-  :handle-ok (pretty-json
-               (-> (simple-otp-request-cached)
-                   otp-response->itinerary
-                   itinernary->add-text2go
-                   itinernary->add-route-url
-                   itinernary->add-route-span
-                   )))
 (defresource ws-otp-pass-through [otp-instance route-params params request]
   :last-modified  #inst "2015-04-09"
   :available-media-types ["application/json" "text/plain"]
@@ -304,7 +295,7 @@
   :last-modified  #inst "2015-04-09"
   :available-media-types ["application/json" "text/plain"]
   ;; :handle-ok (pretty-json (simple-otp-request)))
-  :handle-ok (let [params (merge params)] (pretty-json { :otp-instance (str (type params)) :params params} )))
+  :handle-ok (pretty-json { :otp-instance (str (type params)) :params params} ))

 (defroutes app


Work on buffers:

Work on buffers:

* create new buffers by merging with the result of #'buffer-info
* add #'buffer-info?
* give buffers created from reading files the type file-buffer

--- src/overtone/sc/buffer.clj
+++ src/overtone/sc/buffer.clj
@@ -38,11 +38,8 @@
                                                      (server-sync uid)))))
            info (buffer-info id)]
        (with-meta
-         {:allocated-on-server (atom true)
-          :size (:size info)
-          :n-channels (:n-channels info)
-          :rate (:rate info)
-          :id (:id info)}
+         (merge info
+                {:allocated-on-server (atom true)})
          {:type ::buffer}))))

 (defn buffer-alloc-read
@@ -62,19 +59,28 @@
          (throw (Exception. (str "Unable to read file - file does not exist: " path))))
        (let [id (alloc-id :audio-buffer)]
          (with-server-sync  #(snd "/b_allocRead" id path start n-frames))
-         (let [{:keys [id size rate n-channels]} (buffer-info id)]
+         (let [info                              (buffer-info id)
+               {:keys [id size rate n-channels]} info]
            (when (every? zero? [size rate n-channels])
              (free-id :audio-buffer id)
-             (throw (Exception. (str "Unable to read file - file does not appear to be a valid audio file: " path))))
+             (throw (Exception. (str "Unable to read file - perhaps path is not a valid audio file: " path))))
            (with-meta
-             {:allocated-on-server (atom true)
-              :size size
-              :n-channels n-channels
-              :rate rate
-              :id id}
-             {:type ::buffer}))))))
-
-(defn buffer? [buf]
+             (merge info
+                    {:allocated-on-server (atom true)})
+             {:type ::file-buffer}))))))
+
+(derive ::buffer ::buffer-info)
+(derive ::file-buffer ::buffer)
+
+(defn buffer-info?
+  "Returns true if b-info is buffer information. This includes buffers
+  themselves in addition to the return value from #'buffer-info"
+  [b-info]
+  (isa? (type b-info) ::buffer-info))
+
+(defn buffer?
+  "Returns true if buf is a buffer."
+  [buf]
   (isa? (type buf) ::buffer))

 (defn buffer-free


modify #'load-sample* to use #'buffer-alloc-read

--- src/overtone/sc/sample.clj
+++ src/overtone/sc/sample.clj
@@ -53,22 +53,14 @@
         f    (file path)]
     (when-not (.exists f)
       (throw (Exception. (str "Unable to load sample - file does not exist: " path))))
-    (let [id       (alloc-id :audio-buffer)
-          arg-map  (apply hash-map args)
+    (let [arg-map  (apply hash-map args)
           f-name   (or (:name args) (.getName f))
           start    (get arg-map :start 0)
-          n-frames (get arg-map :size 0)]
-      (with-server-sync  #(snd "/b_allocRead" id path start n-frames))
-      (let [info   (buffer-info id)
-            _      (when (and (= 0 (:size info))
-                              (= 0.0 (:rate info))
-                              (= 0 (:n-channels info)))
-                     (free-id :audio-buffer id)
-                     (throw (Exception. (str "Unable to load sample - perhaps path is not a valid audio file: " path))))
-            sample (with-meta
-                     (merge info
-                            {:allocated-on-server (atom true)
-                             :path path
+          n-frames (get arg-map :size 0)
+          buf      (buffer-alloc-read path start n-frames)]
+      (let [sample (with-meta
+                     (merge buf
+                            {:path path
                              :args args
                              :name f-name})
                      {:type ::sample})]


comments

comments

--- sample/src/sample/core.clj
+++ sample/src/sample/core.clj
@@ -62,7 +62,8 @@
                          s))
                      {})
              ;;; TODO: this can probably be optimized in terms of memory usage & performance.
-             ;;;   instead of building a new map, can we somehow operate on the existing one?
+             ;;;   instead of building a new map, can we somehow operate on the existing one in
+             ;;;   the appropriate nested places?
              (map (fn [[e am]]
                     [e (reduce (fn [am [k [t v]]]
                                  (assoc am k v))


Docstring adjust

Docstring adjust

--- src/polismath/clusters.clj
+++ src/polismath/clusters.clj
@@ -362,7 +362,7 @@

 (defn unfold-clusters
   "The inverse of `fold-clusters`; takes folded clusters and puts them into standard form.
-  i.e. `(= clusters (comp unfold-clusters fold-clusters))`"
+  i.e. `(= identity (comp unfold-clusters fold-clusters))`"
   [{:keys [members id x y] :as folded-clusters}]
   (map
     (fn [ms id x y]


Update comment for seq-iterator.

Update comment for seq-iterator.

--- src/cavm/h2.clj
+++ src/cavm/h2.clj
@@ -570,15 +570,19 @@
     (.write out (str pid "\t" eid "\t" name "\n"))
     pid))

-; Iterators are not typical of clojure, but it's a quick way to get sequential ids
-; deep in a call stack. A more conventional way might be to return the data up
-; the stack, then zip with the sequence ids.
-(defn- seq-iterator [s]
-    (let [a (atom s)]
+; This is a stateful iterator. It may not be idiomatic in clojure, but it's a
+; quick way to get sequential ids deep in a call stack. Maybe we should instead
+; return a thunk that generates a seq, then zip with the data?
+
+(defn- seq-iterator
+  "Create iterator for a seq"
+  [s]
+  (let [a (atom s)]
     (fn []
-       (let [s @a]
-          (reset! a (next s))
-          (first s)))))
+      (let [s @a]
+        (reset! a (next s))
+        (first s)))))
+

 (defn- sequence-seq [seqname]
   (let [[{val :I}] (exec-raw (format "SELECT CURRVAL('%s') AS I" seqname) :results)]


Add matrix test for all fixed size type specs with all supported buffer types.

--- test/bytebuf/core_tests.clj
+++ test/bytebuf/core_tests.clj
@@ -133,31 +133,26 @@
   )

 (deftest spec-data-types
-  (testing "read/write static string"
-    (let [spec (buf/spec (buf/string 5))
-          buffer (buf/allocate 20)]
-      (buf/write! buffer ["1234567890"] spec)
-      (let [[readed data] (buf/read* buffer spec)]
-        (is (= readed 5))
-        (is (= data ["12345"])))))
-
-  (testing "read/write float and double"
-    (let [spec (buf/spec (buf/float) (buf/double))
-          buffer (buf/allocate (buf/size spec))
-          data [(float 1.2) (double 3.55)]]
-      (buf/write! buffer data spec)
-      (let [[readed data'] (buf/read* buffer spec)]
-        (is (= readed (buf/size spec)))
-        (is (= data data')))))
-
-  (testing "read/write boolean and byte"
-    (let [spec (buf/spec (buf/bool) (buf/byte))
-          buffer (buf/allocate (buf/size spec))
-          data [true (byte 22)]]
-      (buf/write! buffer data spec)
-      (let [[readed data'] (buf/read* buffer spec)]
-        (is (= readed (buf/size spec)))
-        (is (= data data')))))
+  (let [data [(buf/string 5) "12345"
+              (buf/short)    100
+              (buf/long)     1002
+              (buf/integer)  1001
+              (buf/bool)     false
+              (buf/double)   (double 4.3)
+              (buf/float)    (float 3.2)
+              (buf/byte)     (byte 32)]]
+    (doseq [[spec data] (partition 2 data)]
+      (let [buffers [(buf/allocate (buf/size spec) {:type :heap :impl :nio})
+                     (buf/allocate (buf/size spec) {:type :direct :impl :nio})
+                     (buf/allocate (buf/size spec) {:type :heap :impl :netty})
+                     (buf/allocate (buf/size spec) {:type :direct :impl :netty})]]
+        (doseq [buffer buffers]
+          ;; (println buffer spec)
+          (let [written (buf/write! buffer data spec)]
+            (is (= written (buf/size spec)))
+            (let [[readed data'] (buf/read* buffer spec)]
+              (is (= readed (buf/size spec)))
+              (is (= data data'))))))))
   )

 (deftest spec-data-with-dynamic-types


Add DOM test case

Add DOM test case

--- test/om_tools/dom_test.cljs
+++ test/om_tools/dom_test.cljs
@@ -144,5 +144,9 @@
         (is=el (nth c i) (nth om-c i)))))

   (testing "js values still work"
+    (is=el (dom/div #js {} (dom/span #js {}))
+           (om-dom/div #js {} (om-dom/span #js {})))
+    (is=el (dom/div #js {:className "foo"} "bar")
+           (om-dom/div #js {:className "foo"} "bar"))
     (is=el (dom/div #js {:className "foo" :class {:display "block"}})
            (om-dom/div #js {:className "foo" :class {:display "block"}}))))


minor fix

minor fix

--- src/dbquery/core.clj
+++ src/dbquery/core.clj
@@ -80,7 +80,7 @@
         header (if has-header? first (for [i (range  (count first))] (str "Col" i)))
         rows (if has-header? (rest csv) csv)
         ]
-    {:body {:header header :rows (take 4 rows) :file (file :tempfile)}})
+    {:body {:header header :rows (take 4 rows) :file (.getAbsolutePath (file :tempfile))}})
   )

 (defn handle-exec-sql [req ds-id]


more dev setup

more dev setup

--- sidecar/project.clj
+++ sidecar/project.clj
@@ -35,11 +35,11 @@
   :clean-targets ^{:protect false} ["dev-resources/public/js" "target"]

   :profiles {:dev {:dependencies [[com.cemerick/piggieback "0.2.2"]]
-                   :source-paths ["cljs_src" "src"]
+                   :source-paths ["cljs_src" "src" "dev"]
                    :plugins [[lein-cljsbuild "1.1.3" :exclusions [[org.clojure/clojure]]]
                              [lein-ancient "0.6.15"]]}
              :repl {:plugins [[cider/cider-nrepl "0.11.0"]]
-                    :source-paths ["cljs_src" "src" "dev"]
+                    :source-paths ["cljs_src" "src"]
                     :resource-paths ["resources" "dev-resources"]
                     :repl-options {:init-ns figwheel-sidecar.repl-api}}}


Removed trace hack

Removed trace hack

--- src/cljsv/core.clj
+++ src/cljsv/core.clj
@@ -8,10 +8,6 @@
   splatted in as a final argument"
   [f & args]
   (apply (apply partial f (butlast args)) (apply concat (last args))))
-
-(defn trace
-  [thing]
-  (println thing) thing)

 (defn read-csv-row


Make Exploud's application list give back what Onix gives back

--- src/exploud/onix.clj
+++ src/exploud/onix.clj
@@ -38,8 +38,16 @@
   "Gets a particular application. Returns `nil` if the application doesn't
    exist."
   [application-name]
-  (let [{ :keys [body status]} (http/simple-get
+  (let [{:keys [body status]} (http/simple-get
                                 (application-url application-name))]
+    (if (= status 200)
+      (json/parse-string body true))))
+
+(defn applications
+  "Gets all applications Onix knows about."
+  [application-name]
+  (let [{:keys [body status]} (http/simple-get
+                               (applications-url))]
     (if (= status 200)
       (json/parse-string body true))))


bugfix: flow didn't use :name as it should in finding all the markers in a form

--- src/ez_form/flow.clj
+++ src/ez_form/flow.clj
@@ -33,7 +33,7 @@
 (defn get-markers [form]
   (->> form
        :fields
-       (map :type)
+       (map :name)
        (map marker)
        flatten))


Fix class shift ys

Fix class shift ys

A bug; I was attempting to look y-values up by block in a map that
had classes as keys

--- src/fatlip/plot.cljs
+++ src/fatlip/plot.cljs
@@ -50,10 +50,10 @@
 (defn get-shift-ys
   "Calculates the relative y-positions of classes. If compacted upward, we walk
   the classes downward; for downward compaction, upward."
-  [classes class-edges node-sep char-sep rel-ys compacted]
+  [classes block-classes class-edges node-sep char-sep rel-ys compacted]
   (reduce (fn [ys class]
             (let [rel-op ({:up + :down -} compacted)
-                  neighbor-ys (map #(rel-op (- (+ (get ys (:dest %))
+                  neighbor-ys (map #(rel-op (- (+ (get ys (get block-classes (:dest %)))
                                                   (get rel-ys (:dest %)))
                                                (get rel-ys (:src %)))
                                             (* char-sep (dec (:weight %))))
@@ -73,7 +73,7 @@
          positions for each node in the underlying graph."}
   (memoize
    (fn [class-graph node-sep char-sep]
-     (let [{:keys [classes preds succs
+     (let [{:keys [classes block-classes preds succs
                    block-preds block-succs compacted]} class-graph
            [block-edges class-edges] ({:up [block-preds preds]
                                        :down [block-succs succs]} compacted)
@@ -82,8 +82,8 @@
                                                        compacted))
                           {}
                           classes)
-           shift-ys (get-shift-ys classes class-edges node-sep char-sep
-                                  rel-ys compacted)
+           shift-ys (get-shift-ys classes block-classes class-edges node-sep
+                                  char-sep rel-ys compacted)
            block-shift-ys (into {} (mapcat (fn [[class shift]]
                                              (map #(-> [% shift]) class))
                                            shift-ys))]
@@ -96,8 +96,8 @@
             (into {}))))))

-(defrecord ClassGraph [classes succs preds block-succs block-preds sources sinks
-                       aligned compacted]
+(defrecord ClassGraph [classes block-classes succs preds block-succs
+                       block-preds sources sinks aligned compacted]
   YPlottable
   (ys [this node-sep char-sep]
     (memo-ys this node-sep char-sep))
@@ -359,6 +359,7 @@
                                           (into {}))]
                     (topo-sort sinks simple-preds)))]
     (map->ClassGraph {:classes classes
+                      :block-classes block-classes
                       :succs succs :preds preds
                       :sources sources :sinks sinks
                       :block-succs block-succs


fix tg message

fix tg message

--- src/gobanbot/web.clj
+++ src/gobanbot/web.clj
@@ -22,7 +22,7 @@

 (defn send-answer! [chat-id status]
   (log/debug "send-answer!" chat-id status)
-  (comment if (= status :ok)
+  (if (= status :ok)
     (send-photo token
                 chat-id
                 (->> chat-id


More docstring legaleese

More docstring legaleese

--- src/grimoire/api.clj
+++ src/grimoire/api.clj
@@ -39,9 +39,9 @@

 (defmulti list-versions
   "Succeeds with a result Seq[Version] representing all Maven versions in the
-  queried datastore of the specified Artifact. Could succeed with an empty
-  result if there are no known versions. Fails if the specified Artifact does
-  not exist or if another Failure is encountered."
+  queried datastore of the specified Artifact in decending version order. Could
+  succeed with an empty result if there are no known versions. Fails if the
+  specified Artifact does not exist or if another Failure is encountered."

   {:arglists '[[config artifact-thing]]}
   dispatch)


Updating schema for actions

Updating schema for actions

--- src/helda/schema.clj
+++ src/helda/schema.clj
@@ -6,8 +6,7 @@

 (s/defschema Action{
   :source-model s/Str
-  :target-model s/Str
-  :action-ctx {s/Keyword s/Str} ;model per key
+  (s/optional-key :action-ctx) {s/Keyword s/Str} ;model per key
   })

 (s/defschema Model {


use refactored authenticate

use refactored authenticate

--- src/ontrail/core.clj
+++ src/ontrail/core.clj
@@ -1,7 +1,9 @@
 (ns ontrail.core
   (:use
         aleph.http
-        compojure.core)
+        compojure.core
+        ontrail.summary
+        ontrail.auth)
   (:gen-class)
   (:require [compojure.route :as route]))

@@ -12,18 +14,10 @@
 (use '[clojure.data.json :only (read-json json-str)])
 (use '[clojure.string :only (split)])

-(use '[ontrail.summary])
-
 (defn json-response [data & [status]]
   {:status (or status 200)
    :headers {"Content-Type" "application/json"}
    :body (json-str data)})
-
-(defn authenticate [user password]
-  (= user password))
-
-(defn auth-token [user password]
-  (str user ":" password))

 (defn is-authenticated? [cookies action]
   (let [auth-token (:value (cookies "authToken"))


request logging ring handler

request logging ring handler

--- src/ontrail/core.clj
+++ src/ontrail/core.clj
@@ -5,10 +5,11 @@
         ring.middleware.cookies
         [ring.middleware.params :only (wrap-params)]
         [clojure.data.json :only (read-json json-str)])
-  (:use [ontrail summary auth crypto user exercise])
+  (:use [ontrail summary auth crypto user exercise log])
   (:gen-class)
   (:require [compojure.route :as route]
-            [monger.collection :as mc]))
+            [monger.collection :as mc]
+            [ring.util.response :as response]))

 (defn json-response [data & [status]]
   {:status (or status 200)
@@ -22,8 +23,17 @@
       action
       (json-response {"error" "Authentication required"} 401))))

+(defn to-log-entry [req]
+  (str "HTTP " (get req :remote-addr) (get req :uri)))
+
+(defn log-and-wrap-dir-index [handler]
+  (fn [req]
+    (log (to-log-entry req))
+    (handler
+     (update-in req [:uri]
+                #(if (= "/" %) "/index.html" %)))))
+
 (defroutes app-routes
-  "Routes requests to their handler function. Captures dynamic variables."
   (GET "/rest/v1/summary/:user" [user] (json-response (get-overall-summary user)))
   (GET "/rest/v1/ex/:id" [id] (json-response (get-ex id)))
   (GET "/rest/v1/ex-list-all/:page" [page] (json-response (get-latest-ex-list {} page)))
@@ -44,5 +54,6 @@
   (start-http-server (-> app-routes
                        wrap-cookies
                        wrap-params
+                       log-and-wrap-dir-index
                        wrap-ring-handler)
                      {:host "localhost" :port 8080 :websocket true}))


Fix parens in Block type.

Fix parens in Block type.

--- src/blocks/data.clj
+++ src/blocks/data.clj
@@ -34,7 +34,7 @@
                         "realized"
                         (if -reader
                           "deferred"
-                          "empty")))
+                          "empty"))))

   (hashCode
     [this]
@@ -104,7 +104,7 @@
   (cons
     [this element]
     (cond
-      (map-entry? element)
+      (instance? java.util.Map$Entry element)
         (let [^java.util.Map$Entry entry element]
           (.assoc this (.getKey entry) (.getValue entry)))
       (vector? element)
@@ -116,7 +116,7 @@
             (let [^java.util.Map$Entry entry (first entries)]
               (recur (.assoc result (.getKey entry) (.getValue entry))
                      (rest entries)))
-            reult))))
+            result))))

   (equiv
     [this other]
@@ -128,7 +128,7 @@
                           (= -size (. other -size))
                           (= -attributes (. other -attributes))
                           (not (and -content other-content
-                                    (not= -content other-content))))))))
+                                    (not= -content other-content)))))))))

   (containsKey
     [this k]
@@ -138,17 +138,15 @@
     [this k]
     (let [v (.valAt this k this)]
       (when-not (identical? this v)
-        (Tuple/create k v))))
+        [k v])))

   (seq
     [this]
-    (seq (concat [(Tuple/create :id -id)
-                  (Tuple/create :size -size)]
-                 -attributes)))
+    (seq (concat [[:id -id] [:size -size]] -attributes)))

   (iterator
     [this]
-    (seq-iterator (seq this)))
+    (.iterator (seq this)))

   (assoc
     [this k v]
@@ -164,7 +162,7 @@
       (:id :size :content :reader)
         (throw (IllegalArgumentException.
                  (str "Block " k " cannot be changed")))
-      (Block. -id -size -content -reader (not-empty (dissoc -attributes k v)) -meta)))
+      (Block. -id -size -content -reader (not-empty (dissoc -attributes k)) -meta)))

   ; IDeref?


use console/time-start ~ end to find jankiness

--- spinning/src/app/core.cljs
+++ spinning/src/app/core.cljs
@@ -7,14 +7,14 @@
     [clairvoyant.core :as trace :include-macros true]
     [cljs.core.async :as async :refer [<! >! chan close! onto-chan pipe put! take! timeout]]
     [clojure.string :as string]
+    [goog.async.nextTick]
     [goog.dom :as dom]
     [goog.object]
     ;[ion.omni.core :as omni]
     [ion.poly.core :as poly]
     [klang.core :as klang]
     [shodan.console :as console :include-macros true]
-    [shodan.inspection :refer [inspect]]
-    ))
+    [shodan.inspection :refer [inspect]]))

 ;(trace/trace-forms {:tracer trace/default-tracer})

@@ -252,16 +252,25 @@
           cell (update-in cell [:age] inc)]
       [k cell])))

+(defn yield []
+  (let [ch (chan)]
+    (goog.async.nextTick #(close! ch))
+    ch))
+
 (defn step-chan [cells]
   "Returns a channel containing a single map of the next generation of cells."
+  (console/time-start "Build Neighborhood")
   (let [generation   (chan 1 (keep (partial cell-fate cells)))
         neighborhood (mapcat neighbors (keys cells))]
+    (console/time-end "Build Neighborhood")
     (go
-      (<! (timeout 0))
+      (console/time-start "cell-neighbor-freq")
       (let [cell-neighbor-freq (frequencies neighborhood)]
-        (<! (timeout 0))
+        (console/time-end "cell-neighbor-freq")
+        (<! (yield))
+        ;(<! (timeout 0))
         (onto-chan generation cell-neighbor-freq)
-        (<! (timeout 0))
+        ;(<! (timeout 0))
         (<! (async/into {} generation))))))

 (defn setup-gol! []
@@ -273,12 +282,14 @@
   (swap! state assoc-in [:gol :generation] 0))

 (defn swap-gol! [cells]
+  (console/time-end (str "Generation " (get-in @state [:gol :generation])))
   (swap! state assoc-in [:gol :cells] cells)
   (swap! state update-in [:gol :generation] inc)
   (swap! state assoc-in [:gol :busy?] false))

 (defn update-gol! []
   (when-not (get-in @state [:gol :busy?])
+    (console/time-start (str "Generation " (get-in @state [:gol :generation])))
     (swap! state assoc-in [:gol :busy?] true)
     (take! (step-chan (get-in @state [:gol :cells])) swap-gol!)))


smoking gun

smoking gun

--- src/jsx_fun/core.clj
+++ src/jsx_fun/core.clj
@@ -16,7 +16,7 @@
             Config Config$LanguageMode ParserRunner]
            [com.google.javascript.rhino
             Node Token ErrorReporter SimpleErrorReporter]
-           [org.mozilla.javascript Context]))
+           [org.mozilla.javascript Context RhinoException]))

 (defprotocol JSTransformer
   (source-path [this])
@@ -200,6 +200,16 @@
       (.eval "var global = {};")
       (.eval (io/reader (io/resource "META-INF/resources/webjars/lodash/3.10.1/lodash.js")))))

+  (try
+    (let [cx (Context/enter)
+          _ (.setOptimizationLevel cx -1)
+          scope (.initStandardObjects cx)
+          source (slurp (io/resource "babel-core/browser.js"))]
+      (.evaluateString cx scope "var global = {};" "shim.js" 1 nil)
+      (.evaluateString cx scope source "babel.js" 1 nil))
+    (catch RhinoException e
+      (println (.getScriptStackTrace e))))
+
   ;; another attempt
   ;; works with weird fix to browser.js
   ;; line 56607 has a Object.keys(obj).map expression that fails
@@ -228,7 +238,32 @@
         scope  (.initStandardObjects cx)
         source (slurp (io/resource "babel-core/browser.js"))]
     (.evaluateString cx scope
-      "Object.keys({foo: 1}).map(function(n) { return n[0]; })"
-      "<cmd>" 1 nil))
-
+      "(function(){var obj = {foo: 1}; return Object.keys(obj).map(function(name){return obj[name];})})()"
+      "<cmd>" 1 nil))
+
+  (let [cx     (Context/enter)
+        _      (.setOptimizationLevel cx -1)
+        scope  (.initStandardObjects cx)
+        source (slurp (io/resource "babel-core/browser.js"))]
+    (.evaluateString cx scope
+      "function Type() { this.foo = 1 }; Object.keys(new Type());"
+      "<cmd>" 1 nil))
+
+  (let [cx     (Context/enter)
+        _      (.setOptimizationLevel cx -1)
+        scope  (.initStandardObjects cx)
+        source (slurp (io/resource "babel-core/browser.js"))]
+    (.evaluateString cx scope
+      "Object.keys(null)"
+      "<cmd>" 1 nil))
+
+  ;; returns [object Null] in most engines
+  ;; returns [object Object] in Rhino
+  (let [cx     (Context/enter)
+        _      (.setOptimizationLevel cx -1)
+        scope  (.initStandardObjects cx)
+        source (slurp (io/resource "babel-core/browser.js"))]
+    (.evaluateString cx scope
+      "Object.prototype.toString.call(null)"
+      "<cmd>" 1 nil))
   )


remove prcrsr-bot email from auth

remove prcrsr-bot email from auth

--- src/pc/auth.clj
+++ src/pc/auth.clj
@@ -60,13 +60,6 @@
             (throw e)))))))

 ;; Note: this is hardcoded to prcrsr.com for a good reason
-(def prcrsr-bot-email "prcrsr-bot@prcrsr.com")
-(defn prcrsr-bot-uuid [db]
-  (ffirst (d/q '{:find [?u]
-                 :in [$ ?e]
-                 :where [[?t :cust/email ?e]
-                         [?t :cust/uuid ?u]]}
-               db prcrsr-bot-email)))

 (defn cust-permission [db doc cust]
   (when cust


'expected' and 'actual' is the other way around for midje.

--- src/flare/midje.clj
+++ src/flare/midje.clj
@@ -18,7 +18,7 @@
     [failure]
     (default-fail-emissioner failure)
     (when (= (:type failure) :actual-result-did-not-match-expected-value)
-      (some-> (diff (:actual failure) (:expected-result failure))
+      (some-> (diff (:expected-result failure) (:actual failure))
               generate-reports
               emit-reports)))


Changes to grep.  It's now a multi-method and extensible, it dispatches
on the type of its second argument and currently dispatches for:

- fn
- string
- regex

It also now allows you to narrow the grep by column.

--- src/grafter/csv.clj
+++ src/grafter/csv.clj
@@ -5,10 +5,10 @@
 ;; Just experimenting with CSV

 (defn parse-csv [csv-file-or-url]
-  (csv/parse-csv   (io/reader csv-file-or-url)))
+  (csv/parse-csv (io/reader csv-file-or-url)))

 (defn nnth
-  "Same as nth but returns nil (or not-found) if"
+  "Same as nth but returns nil (or not-found) if supplied."
   ([col index] (nnth col index nil))
   ([col index not-found]
      (try
@@ -38,16 +38,25 @@
                 (conj acc (nnth csv r)))
               [] (conj rs r))))

-;; TODO make this extensible
-;; Also don't test for equality of strings but that it contains the string...
-;; also make it work with regexes.
-(defn grep [csv f]
-  (if (instance? String f)
-    (grep csv #(= f %))
+(defmulti grep
+  "Filters rows in the table for matches.  This is multi-method
+  dispatches on the type of its second argument."
+  (fn [table f & cols] (class f)))
+
+(defmethod grep clojure.lang.IFn [csv f & cols]
+  (let [select-cols (if (empty? cols)
+                           identity
+                           (partial select-columns-from-row cols))]
     (filter (fn [row]
-              (some f row)) csv)))
+              (some f (select-cols row))) csv)))

-(defn remove-indices [col & idxs]
+(defmethod grep java.lang.String [csv s & cols]
+  (apply grep csv #(.contains % s) cols))
+
+(defmethod grep java.util.regex.Pattern [csv p & cols]
+  (apply grep csv #(re-find p %) cols))
+
+(defn- remove-indices [col & idxs]
   "Removes the values at the supplied indexes from the given vector."
   (let [pos (map - (sort idxs) (iterate inc 0))
         remove-index (fn [col pos]
@@ -56,16 +65,14 @@
     (reduce remove-index col pos)))

 (defn- fuse-row [columns f row]
-  (let [
-        to-drop (drop 1 (sort columns))
+  (let [to-drop (drop 1 (sort columns))
         merged (assoc row (apply min columns)
                       (apply f (select-columns-from-row columns row)))]
-
     (apply remove-indices merged to-drop)))

 (defn fuse [csv f & cols]
   "Merge columns with the specified function"
-  (map (partial fuse-row cols f) csv ))
+  (map (partial fuse-row cols f) csv))

 (defn join [])

@@ -78,9 +85,7 @@
   (rows earners (range 5 10))

   (-> (parse-csv "./examples/high-earners-pay-2012.csv")
+      (fuse #(str %1 " " %2) 2 1)
       (grep "John")
-      (fuse #(str %1 " " %2) 2 1)
       (columns 2 1)
-      (rows 1 10))
-
-  )
+      (rows 1 10)))


List invoices in a table

List invoices in a table

--- src/invadm/core.clj
+++ src/invadm/core.clj
@@ -4,6 +4,7 @@
             [clojure.java.io :as io]
             [clj-time.core :as t]
             [clj-time.format :as f]
+            [clojure.pprint :as pprint]
             [clojure.string :as string])
   (:gen-class))

@@ -42,19 +43,11 @@
   (map read-json (get-invoice-filenames)))

 (defn pretty-print-invoice [invoice]
-  (format (->> ["\nInvoice #%s"
-                "Client: %s"
-                "Issue date: %s"
-                "Due date: %s (Net %d)"
-                "Amount: %d %s"]
-               (string/join \newline))
-          (get invoice "id")
-          (get invoice "client")
-          (get invoice "issue-date")
-          (get invoice "due-date")
-          (get invoice "net")
-          (get invoice "amount")
-          (get invoice "currency")))
+  {"ID" (get invoice "id")
+   "Client" (get invoice "client")
+   "Issue date" (get invoice "issue-date")
+   "Due date" (get invoice "due-date")
+   "Amount" (format "%d %s" (get invoice "amount") (get invoice "currency"))})

 (defn options-to-filter [options]
   (fn [invoice]
@@ -119,8 +112,9 @@
   (println (json/write-str (filter (options-to-filter options) (read-all-invoices)))))

 (defn list_ [options]
-  (apply println (map pretty-print-invoice (filter (options-to-filter options)
-                                                   (read-all-invoices)))))
+  (pprint/print-table (map pretty-print-invoice
+                           (filter (options-to-filter options)
+                                   (read-all-invoices)))))

 (defn record-payment [options arguments]
   (let [id (get arguments 1)


Make version banner minimal

Make version banner minimal

--- frontend/src/faceboard/views/banner.cljs
+++ frontend/src/faceboard/views/banner.cljs
@@ -10,7 +10,6 @@
         (if-not rev
           "local version"
           (let [url (str "https://github.com/darwin/faceboard/tree/" rev)
-                label (str "darwin/faceboard @ " (subs rev 0 7))]
+                label (subs rev 0 7)]
             (dom/div {:class "github"}
-              "deployed from github: "
               (dom/a {:href url} label))))))))


(TK-130) Test to ensure thread pool size

One more test to esure that our thread pool size algorithm is in parity
with Jetty's.

--- test/clj/puppetlabs/trapperkeeper/services/webserver/jetty9_config_test.clj
+++ test/clj/puppetlabs/trapperkeeper/services/webserver/jetty9_config_test.clj
@@ -286,7 +286,7 @@
                                    {:port 8000 :host "foo.local"} 100)))
       (is (logged? #"Thread pool size not configured so using a size of")))))

-(defn thread-pool-size-test-config
+(defn small-thread-pool-size-test-config
   [raw-config]
   (let [calc-size (calculate-required-threads raw-config (ks/num-cpus))
         low-size  (- calc-size 1)
@@ -296,13 +296,18 @@
     {:config config
      :exp-re exp-re}))

+(defn correct-thread-pool-size-test-config
+  [raw-config]
+  (let [calc-size (calculate-required-threads raw-config (ks/num-cpus))]
+    (assoc raw-config :max-threads calc-size)))
+
 (deftest calculated-thread-pool-size
   (testing "Verify that our thread pool size algorithm matches Jetty's"
     (let [test-1   (merge valid-ssl-pem-config {:port 0, :host "0.0.0.0"
                                                 :ssl-port 0, :ssl-host "0.0.0.0"})
-          config-1 (thread-pool-size-test-config test-1)
+          config-1 (small-thread-pool-size-test-config test-1)
           test-2   {:port 0, :host "0.0.0.0"}
-          config-2 (thread-pool-size-test-config test-2)]
+          config-2 (small-thread-pool-size-test-config test-2)]
       (doseq [{:keys [config exp-re]} [config-1 config-2]]
         (is (thrown-with-msg?
               java.lang.IllegalStateException exp-re
@@ -311,4 +316,16 @@
                  "the minimum size of a thread pool has drifted from how Jetty "
                  "itself calculates the size. This is most likely due to a "
                  "change of the Jetty version being used. The
-                 calculate-required-threads function should be updated."))))))+                 calculate-required-threads function should be updated.")))))
+
+  (testing "Our thread pool size algo still allows Jetty to start"
+    (let [test-1   (merge valid-ssl-pem-config {:port 0, :host "0.0.0.0"
+                                                :ssl-port 0, :ssl-host "0.0.0.0"})
+          config-1 (correct-thread-pool-size-test-config test-1)
+          test-2   {:port 0, :host "0.0.0.0"}
+          config-2 (correct-thread-pool-size-test-config test-2)]
+      (doseq [config [config-1 config-2]]
+        (let [ctxt (jetty9/start-webserver! (jetty9/initialize-context) config)]
+          (is (= (type (:server ctxt)) org.eclipse.jetty.server.Server))
+          (jetty9/shutdown ctxt))))))
+


filter changes list by ids if provided

filter changes list by ids if provided

--- src/adzerk/boot_reload.clj
+++ src/adzerk/boot_reload.clj
@@ -72,6 +72,11 @@
                     #(b/by-ext [".cljs.edn"] %))]
     (-> (b/fileset-diff prev fileset) b/input-files f)))

+(defn- filter-by-ids [ids changes]
+  (let [ids-str (apply str (interpose \| ids))
+        ids-re  (re-pattern (str "(" ids-str ")[.]{1}out/.+"))]
+    (filter #(re-find ids-re %) changes)))
+
 (deftask reload
   "Live reload of page resources in browser via websocket.

@@ -126,6 +131,9 @@
             ; Only send changed files when there are no warnings
             ; As prev is updated only when changes are sent, changes are queued untill they can be sent
             (when (empty? warnings)
-              (send-changed! @pod asset-path (changed @prev fileset))
-              (reset! prev fileset))
+              (let [changes (if ids
+                              (filter-by-ids ids (changed @prev fileset))
+                              (changed @prev fileset))]
+                (send-changed! @pod asset-path changes)
+                (reset! prev fileset)))
             fileset))))))


Removed redundant comment

Removed redundant comment

--- lib/compojure/http/http.clj
+++ lib/compojure/http/http.clj
@@ -85,8 +85,6 @@
         (map hash-map
           (route :keywords)
           (rest (re-groups matcher)))))))
-
-;;;; Cookies

 ;;;; Handler functions ;;;;


server side authentication and setting cookies

--- src/ontrail/core.clj
+++ src/ontrail/core.clj
@@ -44,7 +44,7 @@
        (.error logger (str exception#))
        (stacktrace/print-stack-trace exception# 100)
        {:status 500
-        :headers {"Content-Type" "application/text"}
+        :headers {"Content-Type" "application/json"}
         :body (str exception#)})))

 (defmacro is-authenticated? [cookies action]
@@ -168,10 +168,24 @@
       (json-response {:success true})
       (json-response {:message "wrong-password"} 400)))

+  (POST "/rest/v2/login" [username password location]
+        (if (authenticate username password)
+          (let [case-user (user/get-case-user username)
+                authToken (auth-token case-user)
+                authUser (:username (user/get-case-user username))]
+            {:status 301
+             :headers {"Content-Type" "text/html"
+                       "Location" location}
+             :cookies {"authToken" {:value authToken}
+                       "authUser" {:value authUser}}
+             :body ""
+             })
+          (json-response {:error "Authentication failed"} 401)))
+
   (POST "/rest/v1/login" [username password]
-    (if (authenticate username password)
-      (json-response {:token (auth-token (user/get-case-user username)) :username (:username (user/get-case-user username))} 200)
-      (json-response {:error "Authentication failed"} 401)))
+        (if (authenticate username password)
+          (json-response {:token (auth-token (user/get-case-user username)) :username (:username (user/get-case-user username))} 200)
+          (json-response {:error "Authentication failed"} 401)))

   (POST "/rest/v1/ex/:id/comment" {params :params cookies :cookies}
     (is-authenticated? cookies (json-response (mutate/comment-ex (user-from-cookie cookies) params))))


Java interface follows ack/retry-message name changes

--- src/onyx/interop.clj
+++ src/onyx/interop.clj
@@ -15,8 +15,8 @@

 (gen-interface
   :name onyx.IPipelineInput
-  :methods [[ackMessage [clojure.lang.IPersistentMap java.util.UUID] void]
-            [retryMessage [clojure.lang.IPersistentMap java.util.UUID] Object]
+  :methods [[ackSegment [clojure.lang.IPersistentMap java.util.UUID] void]
+            [retrySegment [clojure.lang.IPersistentMap java.util.UUID] Object]
             [isPending [clojure.lang.IPersistentMap java.util.UUID] Object]
             [isDrained [clojure.lang.IPersistentMap] boolean]])


Add comment based on Miikka's comments

Add comment based on Miikka's comments

--- src/reitit/core.cljc
+++ src/reitit/core.cljc
@@ -61,6 +61,7 @@
   (cond->> (->> (walk data opts) (map-meta merge-meta))
            coerce (into [] (keep #(coerce % opts)))))

+;; This whole function might be more efficient and easier to understand with transducers.
 (defn conflicting-routes [routes]
   (some->>
     (loop [[r & rest] routes, acc {}]


Added frame rate calculation and display.

--- src/sparkle/core.clj
+++ src/sparkle/core.clj
@@ -39,7 +39,7 @@
                                             env
                                             (child-name child-models)
                                             (child-name child-mode-frames))})
-                            (keys child-models)))))})))
+                            (keys child-models))))})))

 (defn setup []
   (let [model (select-model selected-model (edn/read-string (slurp model-file-path)))]
@@ -58,16 +58,25 @@

 (defn render [{:keys [model mode params env]}]
   (let [mode-tree (eval-mode env model {:mode mode :params params})]
-    (pprint [mode-tree])))
+    (pprint [mode-tree])
+    ))

 (defn run []
-  (let [initial-state (setup)]
-    (loop [last-state initial-state]
-      (let [current-state (next-state last-state)]
-        (render (next-state current-state))
-        (recur current-state)))))
+  (loop [last-state (setup)
+         cycle-start-time (System/currentTimeMillis)
+         frame-number 0]
+    (let [current-state (next-state last-state)
+          current-time (System/currentTimeMillis)
+          elapsed-cycle-time (- current-time cycle-start-time)]
+      (render (next-state current-state))
+      (if (> (- current-time cycle-start-time) 100)
+        ; Report frame rate, restart cycle
+        (let [frame-rate (quot 1000 (/ elapsed-cycle-time frame-number))]
+          (println "Frame rate:" frame-rate "Frames this cycle:" frame-number)
+          (recur current-state (System/currentTimeMillis) 0))
+        ; Otherwise, continue
+        (recur current-state cycle-start-time (inc frame-number))))))

 (defn -main
-  "I don't do a whole lot ... yet."
   [& args]
   (run))


make star fade in then out

make star fade in then out

--- src/splash/core.cljs
+++ src/splash/core.cljs
@@ -4,6 +4,8 @@
               [infinitelives.pixi.sprite :as sprite]
               [infinitelives.utils.events :as events]
               [infinitelives.utils.console :refer [log]]
+              [infinitelives.pixi.texture :as texture]
+              [infinitelives.utils.math :as math]
               ;[splash.macros :refer-macros [ignore]]
               [cljs.core.async :refer [<!]])
     (:require-macros [cljs.core.async.macros :refer [go]]
@@ -50,11 +52,18 @@

     (macros/with-sprite canvas :stars
       [spr (sprite/make-sprite
-            (resources/get-texture :stars :nearest)
-            :scale [8 8]
-            :alpha 0.1)]

-      (<! (events/wait-time 2000)))))
+            (texture/sub-texture
+             (resources/get-texture :stars :nearest)
+             [0 0] [8 8]
+             )
+            :scale [4 4]
+            :alpha 0.0)]
+
+      (<! (resources/fadein spr :duration 0.5))
+      (<! (events/wait-time 2000))
+      (<! (resources/fadeout spr :duration 0.5))
+      )))

 (main)


Goddammit

Goddammit

--- src/app/core.cljs
+++ src/app/core.cljs
@@ -369,31 +369,37 @@
      [:h2 "Thank you!"]
      (let [{:keys [guests] :as selection} (om/observe owner (selection))]
        [:ul {:class "summary"}
-        (map (fn [{:keys [id name] :as guest}]
-               [:li (str (or (get-in infos [id :name]) name)
-                         (if (get-in infos [id :attending]) " will " " will not ")
-                         "attend.")])
-             guests)
-        (let [unnamed-guests (filter (comp str/blank? :name)
-                                     (vals plusses))
-              unnamed-attending (count (filter (comp true? :attending)
-                                               unnamed-guests))
-              unnamed-regrets   (count (filter (comp false? :attending)
-                                               unnamed-guests))]
-          (when (pos? unnamed-attending)
-            [:li (str unnamed-attending
-                      " additional "
-                      (if (= 1 unnamed-attending)
-                        "guest"
-                        "guests")
-                      " will attend.")])
-          (when (pos? unnamed-regrets)
-            [:li (str unnamed-regrets
-                      " additional "
-                      (if (= 1 unnamed-regrets)
-                        "guest"
-                        "guests")
-                      " will not attend.")]))])
+        (concat
+         (map (fn [{:keys [id name] :as guest}]
+                [:li (str (or (get-in infos [id :name]) name)
+                          (if (get-in infos [id :attending]) " will " " will not ")
+                          "attend.")])
+              guests)
+         (let [named-guests (remove (comp str/blank? :name)
+                                    (vals plusses))
+               unnamed-guests (filter (comp str/blank? :name)
+                                      (vals plusses))
+               unnamed-attending (count (filter (comp true? :attending)
+                                                unnamed-guests))
+               unnamed-regrets   (count (filter (comp false? :attending)
+                                                unnamed-guests))]
+           [(map (fn [{:keys [name attending]}]
+                   [:li (str name (if attending " will " " will not ") "attend.")])
+                 named-guests)
+            (when (pos? unnamed-attending)
+              [:li (str unnamed-attending
+                        " additional "
+                        (if (= 1 unnamed-attending)
+                          "guest"
+                          "guests")
+                        " will attend.")])
+            (when (pos? unnamed-regrets)
+              [:li (str unnamed-regrets
+                        " additional "
+                        (if (= 1 unnamed-regrets)
+                          "guest"
+                          "guests")
+                        " will not attend.")])]))])
      [:h2 "Doesn't look right?"]
      [:p
       "Please "


Cursors abound

Cursors abound

--- src/app/core.cljs
+++ src/app/core.cljs
@@ -13,14 +13,24 @@
 (defonce app-state
   (atom {:selected [:details]
          :rsvp-search {:name ""
-                       :results nil}
+                       :results nil
+                       :party {}}
+         :party {}
+         :selection {:party nil
+                     :guests nil}
          :response {:contact nil
                     :food-preferences ""
-                    :infos nil
+                    :infos {}
                     :sent false}}))

+(defn search []
+  (om/ref-cursor (:rsvp-search (om/root-cursor app-state))))
+
+(defn selection []
+  (om/ref-cursor (get-in (om/root-cursor app-state) [:selection])))
+
 (defn response []
-  (om/ref-cursor (:response (om/root-cursor app-state))))
+  (om/ref-cursor (get-in (om/root-cursor app-state) [:response])))

 (defonce Response (.extend (.-Object parse/Parse) "Response"))
 (defonce Info (.extend (.-Object parse/Parse) "Info"))
@@ -61,6 +71,39 @@
                     (js->clj result)))
         [])))

+(defn reset-search! [owner]
+  (let [search (om/observe owner (search))]
+    (om/update! search :name "")
+    (om/update! search :results nil)))
+
+(defn reset-selection! [owner]
+  (let [selection (om/observe owner (selection))]
+    (om/update! selection :party nil)
+    (om/update! selection :guests nil)))
+
+(defn select-party! [owner party]
+  (let [selection (om/observe owner (selection))]
+    (go (om/update! selection :party party)
+        (let [guests (mapv #(dissoc % :party)
+                           (<! (guests-in-party (:id party))))]
+          (om/update! selection :guests guests)))))
+
+(defn party-selected? [owner]
+  (let [{:keys [party guests] :as selection} (om/observe owner (selection))]
+    (every? some? [party guests])))
+
+(defn reset-response! [owner]
+  (let [response (om/observe owner (response))]
+    (om/update! response :contact nil)
+    (om/update! response :food-preferences "")
+    (om/update! response :infos {})
+    (om/update! response :sent false)))
+
+(defn reset-all! [owner]
+  (reset-search! owner)
+  (reset-selection! owner)
+  #_(reset-response! owner))
+
 (defn nav-view [{:keys [selected rsvp-search]} owner]
   (reify om/IRender
     (render [_]
@@ -70,9 +113,7 @@
               (map (fn [[key text]]
                      [:li (if (= selected [key]) {:class "selected"} {})
                       [:a {:href "#"
-                           :onClick #(do (om/update! rsvp-search :results nil)
-                                         (om/update! rsvp-search :guests-in-party nil)
-                                         (om/update! rsvp-search :party nil)
+                           :onClick #(do (reset-all! owner)
                                          (om/update! selected 0 key))}
                        text]])
                    (partition 2 [:details       "Details"
@@ -140,7 +181,7 @@
                                (go (let [guests (<! (search-guests name))]
                                      (om/update! data :results guests)
                                      (when (= 1 (count guests))
-                                       (om/update! data :guests-in-party (first guests))))))}
+                                       (select-party! owner (get-in guests [0 :party]))))))}
          [:label {:for "guestsearch"} "Enter the name on your invitation:"]
          [:input {:type "text"
                   :name "guestseearch"
@@ -152,81 +193,98 @@
          [:button {:type "submit"}
           "Find RSVP"]]]))))

-(defn send-rsvps! [{:keys [contact food-preferences infos sent] :as response}]
-  (go (let [[result response-or-error] (<! (parse/save Response {:contact contact
-                                                 :foodPreferences food-preferences}))]
-        (if (= :success result)
-          (doseq [{:keys [id name attending]} infos]
-            (let [[result info-or-error] (<! (parse/save Info {:response response-or-error
-                                                               :guest (let [guest (Guest.)]
-                                                                        (set! (.-id guest) id)
-                                                                        guest)
-                                                               :name name
-                                                               :attending attending}))]
-              (when-not (= result :success)
-                (throw info-or-error))))
-          (throw response-or-error)))))
-
-(defn rsvp-card-view [{:keys [guests] :as party} owner]
+(defn send-rsvps! [{:keys [party guests] :as selection} {:keys [contact food-preferences infos sent] :as response}]
+  (go (try (let [[result response-or-error] (<! (parse/save Response {:party (let [p (Party.)]
+                                                                               (set! (.-id p)
+                                                                                (get-in party [:id]))
+                                                                               p)
+                                                                      :contact contact
+                                                                      :foodPreferences food-preferences}))]
+             (if (= :success result)
+               (doseq [[id {:keys [corrected-name attending]}] infos]
+                 (let [[result info-or-error] (<! (parse/save Info {:response response-or-error
+                                                                    :guest (let [g (Guest.)]
+                                                                             (set! (.-id g)
+                                                                                id)
+                                                                             g)
+                                                                    :correctedName corrected-name
+                                                                    :attending attending}))]
+                   (when-not (= result :success)
+                     (js/console.error "Error! Error! " info-or-error)
+                     (throw info-or-error))))
+               (throw response-or-error)))
+           [:success]
+           (catch :default e
+             [:error e]))))
+
+(defn rsvp-card-view [{:keys [party guests] :as selection} owner]
   (reify
     om/IRender
     (render [_]
       (let [{:keys [contact food-preferences infos] :as response} (om/observe owner (response))]
         (when (nil? contact)
           (om/update! response :contact (:contact party)))
-
+
         (html
-         [:main
-          [:h2 "RSVP"]
-          [:form {:id "rsvpsubmit"
-                  :onSubmit (fn [e]
-                              (.preventDefault e)
-                              (try (send-rsvps! response)
-                                   (om/update! response :sent true)
-                                   (catch js/Error e
-                                     (js/console.error "Error sending response to Parse:" e))))}
-           [:section {:class "guests"}
-            (map-indexed
-             (fn [idx {:keys [id name attending] :as info}]
-               [:div
-                [:input {:type "text"
-                         :class "guestname"
-                         :value name
-                         :ref (str id "name")
-                         :onChange #(om/update! response [:infos idx :name] (.-value (om/get-node owner (str id "name"))))}]
-                [:fieldset
-                 [:div
-                  (let [radio-name (str "guest" idx "rsvp")]
-                    (map (fn [[label for-str val]]
-                           (let [input-id (str "guest" idx for-str)]
-                             [:div
-                              [:input {:type "radio"
-                                       :id input-id
-                                       :name radio-name
-                                       :onChange #(om/update! response [:infos idx :attending] val)}]
-                              [:label {:for input-id}
-                               label]]))
-                         (partition 3 ["Will attend"   "yes" true
-                                       "Sends regrets" "no" false])))]]])
-             infos)
-            [:p {:class "small"}
-             "(If we've gotten anyone's name wrong, we apologize! Please correct it here so that we can stop embarrassing ourselves.)"]]
-           [:section {:class "addendums"}
-            [:label {:for "foodpref", :class "small"}
-             "We are planning on serving a buffet style meal that will be suitable for both meat eaters and vegetarians. Do you have any dietary restrictions or allergies that we should be aware of?"]
-            [:textarea {:name "foodpref"
-                        :ref "food-preferences"
-                        :value food-preferences
-                        :onChange #(om/update! response :food-preferences (.-value (om/get-node owner "food-preferences")))}]
-
-            [:label {:for "contact" :class "small"}
-             "If we need to contact you with any last-minute information, is this a good email address to use?"]
-            [:input {:type "text"
-                     :ref "contact"
-                     :value contact
-                     :onChange #(om/update! response :contact (.-value (om/get-node owner "contact")))}]
-
-            [:button {:type "submit"} "RSVP"]]]])))))
+         [:div
+          [:main
+           [:h1 "Selection"]
+           [:code (with-out-str (cljs.pprint/pprint selection))]
+           [:h1 "Response"]
+           [:code (with-out-str (cljs.pprint/pprint response))]]
+          [:main
+           [:h2 "RSVP"]
+           [:form {:id "rsvpsubmit"
+                   :onSubmit (fn [e]
+                               (.preventDefault e)
+                               (go (let [[result data] (<! (send-rsvps! selection response))]
+                                     (condp = result
+                                       :success (om/update! response :sent true)
+                                       :failure (js/console.error "Error sending response to Parse:" data)))))}
+            [:section {:class "guests"}
+             (map-indexed
+              (fn [idx {id :id, original-name :name :as info}]
+                [:div
+                 [:input {:type "text"
+                          :class "guestname"
+                          :value (or (get-in infos [id :corrected-name]) original-name)
+                          :ref (str id "name")
+                          :onChange #(om/update! response [:infos id :corrected-name] (.-value (om/get-node owner (str id "name"))))}]
+                 [:fieldset
+                  [:div
+                   (let [radio-name (str "guest" idx "rsvp")]
+                     (map (fn [[label for-str val]]
+                            (let [input-id (str "guest" idx for-str)]
+                              [:div
+                               [:input (cond-> {:type "radio"
+                                                :id input-id
+                                                :name radio-name
+                                                :onChange #(om/update! response [:infos id :attending] val)}
+                                         (= val (get-in infos [id :attending]))
+                                         (assoc :checked true))]
+                               [:label {:for input-id}
+                                label]]))
+                          (partition 3 ["Will attend"   "yes" true
+                                        "Sends regrets" "no" false])))]]])
+              guests)
+             [:p {:class "small"}
+              "(If we've gotten anyone's name wrong, we apologize! Please correct it here so that we can stop embarrassing ourselves.)"]]
+            [:section {:class "addendums"}
+             [:label {:for "foodpref", :class "small"}
+              "We are planning on serving a buffet style meal that will be suitable for both meat eaters and vegetarians. Do you have any dietary restrictions or allergies that we should be aware of?"]
+             [:textarea {:name "foodpref"
+                         :ref "food-preferences"
+                         :value food-preferences
+                         :onChange #(om/update! response :food-preferences (.-value (om/get-node owner "food-preferences")))}]
+
+             [:label {:for "contact" :class "small"}
+              "If we need to contact you with any last-minute information, is this a good email address to use?"]
+             [:input {:type "text"
+                      :ref "contact"
+                      :value contact
+                      :onChange #(om/update! response :contact (.-value (om/get-node owner "contact")))}]
+
+             [:button {:type "submit"} "RSVP"]]]]])))))

 (defn rsvp-multiple-results-view [{:keys [name results] :as data} owner]
   (reify
@@ -240,13 +298,14 @@
                         [:li
                          [:span name]
                          [:button
-                          {:onClick (fn [_]
-                                      (go (om/update! data :party (assoc party
-                                                                         :guests (<! (guests-in-party (:id party)))))))}
+                          {:onClick #(select-party! owner party)}
                           "Select"]])
                       results)]
         [:p "Can't find your RSVP? "
-          [:a {:href "???"} "Search again"]]]))))
+         [:a {:onClick #(do (.preventDefault %)
+                            (reset-search! owner)
+                            (reset-selection! owner))}
+          "Search again"]]]))))

 (defn rsvp-confirmation-view [response owner]
   (om/component
@@ -255,24 +314,22 @@
      [:h1 "Confirmed!"]
      [:pre (with-out-str (pp/pprint @response))]])))

-(defn rsvp-search-results-view [{:keys [name results party] :as data} owner]
+(defn rsvp-search-results-view [{:keys [name results] :as data} owner]
   (reify
     om/IRender
     (render [_]
-      (let [{:keys [infos sent] :as response} (om/observe owner (response))]
-        (when (and (some? party)
-                   (nil? infos))
-          (om/update! response :infos (mapv (fn [guest]
-                                              (assoc (select-keys guest [:id :name])
-                                                     :attending nil))
-                                            (:guests party))))
-        (cond (true? sent) (om/build rsvp-confirmation-view response)
-              (some? party) (om/build rsvp-card-view party)
-              (seq results) (om/build rsvp-multiple-results-view data)
-              :else (html [:main
-                            [:h2 (str "Oops! No results found for '" name "'")]
-                            [:p "Can't find your RSVP? "
-                              [:a {:href "???"} "Search again"]]]))))))
+      (let [{:keys [party] :as selection} (om/observe owner (selection))
+            {:keys [infos sent] :as response} (om/observe owner (response))]
+        (cond (true? sent)            (om/build rsvp-confirmation-view response)
+              (party-selected? owner) (om/build rsvp-card-view selection)
+              (seq results)           (om/build rsvp-multiple-results-view data)
+              :else                   (html [:main
+                                             [:h2 (str "Oops! No results found for '" name "'")]
+                                             [:p "Can't find your RSVP? "
+                                              [:a {:onClick #(do (.preventDefault %)
+                                                                 (reset-search! owner)
+                                                                 (reset-selection! owner))}
+                                               "Search again"]]]))))))

 (defn rsvp-view [{:keys [results] :as data} owner]
   (reify om/IRender


Multiline textfield

Multiline textfield

--- flatguiwidgets/src/flatgui/widgets/textfield.clj
+++ flatguiwidgets/src/flatgui/widgets/textfield.clj
@@ -320,7 +320,7 @@
               preferred-h (m/y preferred-size)]
           (m/defpoint (max preferred-w parent-w) (max preferred-h parent-h)))
         (m/defpoint parent-w parent-h)))
-    old-clip-size))
+    ((:clip-size (:evolvers flatgui.widgets.component/component)) component)))

 ;;;
 ;;;TODO listen to timer


More plausible kvs multi-get.

More plausible kvs multi-get.

--- src/cbfg/kvs.cljs
+++ src/cbfg/kvs.cljs
@@ -19,82 +19,88 @@
 ; TODO: Add snapshot ability.
 ; TODO: Readers not blocked by writers.

+(defn make-kc [] ; A kc is a keys / changes map.
+  {:keys (sorted-map)      ; key -> sq
+   :changes (sorted-map)}) ; [sq key] -> {:key k, :sq s, :deleted true | :val v}
+
 (defn make-kvs [name uuid]
   {:name name
    :uuid uuid
-   :keys (sorted-map)    ; key -> sq
-   :changes (sorted-map) ; [sq key] -> {:key k, :sq s, :deleted true | :val v}
+   :clean (make-kc) ; Read-only.
+   :dirty (make-kc) ; Mutations go here, until "persisted / made durable".
    :next-sq 1})

-(defn kvs-sq-by-key [kvs key]
-  (get (:keys kvs) key))
+(defn kc-sq-by-key [kc key]
+  (get (:keys kc) key))

-(defn kvs-entry-by-key-sq [kvs key sq]
-  (get (:changes kvs) [sq key]))
+(defn kc-entry-by-key-sq [kc key sq]
+  (get (:changes kc) [sq key]))

-(defn kvs-entry-by-key [kvs key]
-  (kvs-entry-by-key-sq kvs key (kvs-sq-by-key kvs key)))
+(defn kc-entry-by-key [kc key]
+  (kc-entry-by-key-sq kc key (kc-sq-by-key kc key)))

-(defn kvs-check [kvs-ident work-fn]
+(defn kvs-ident-check [kvs-ident work-fn]
+  ; Wrapper that checks to see if kvs-ident refers to a current kvs.
   (fn [state] ; Meant to be used as work-fn for state-work function.
     (if-let [[name uuid] kvs-ident]
       (if-let [kvs (get-in state [:kvss name])]
         (if (= uuid (:uuid kvs))
           (work-fn state kvs)
-          [state {:status :mismatch :sub-status :wrong-uuid}])
-        [state {:status :not-found :sub-status :no-kvs}])
-      [state {:status :invalid :sub-status :no-kvs-ident}])))
+          [state {:status :mismatch :status-info :wrong-uuid}])
+        [state {:status :not-found :status-info :no-kvs}])
+      [state {:status :invalid :status-info :no-kvs-ident}])))

 (defn state-work [actx state-ch m work-fn & opt-done-ch]
-  (act state-work actx
-       (let [done-ch (or opt-done-ch (achan state-work))]
-         (aput state-work state-ch [work-fn done-ch])
+  (let [done-ch (or opt-done-ch (achan actx))]
+    (act state-work actx
+         (aput state-work state-ch [work-fn done-ch]))
          (aput state-work (:res-ch m)
-               (merge m (or (atake state-work done-ch) {:status :error}))))))
+               (merge m (or (atake state-work done-ch)
+                            {:status :error :status-info :closed-ch})))))

 (def op-handlers
   {:kvs-open
    (fn [actx state-ch m]
      (state-work actx state-ch m
-                 (kvs-check (:kvs-ident m)
-                            #(if-let [name (:name m)]
-                               (if-let [kvs (get-in % [:kvss name])]
-                                 [% {:status :ok :kvs-ident [name (:uuid kvs)]}]
-                                 [(-> %
-                                      (update-in [:kvss name]
-                                                 (make-kvs name (:next-uuid %)))
-                                      (assoc :next-uuid (inc (:next-uuid %))))
-                                  {:status :ok :kvs-ident [name (:next-uuid %)]}])
-                               [% {:status :invalid :sub-status :no-name}]))))
+                 #(if-let [name (:name m)]
+                    (if-let [kvs (get-in % [:kvss name])]
+                      [% {:status :ok :status-info :reopened
+                          :kvs-ident [name (:uuid kvs)]}]
+                      [(-> %
+                           (update-in [:kvss name] (make-kvs name (:next-uuid %)))
+                           (assoc :next-uuid (inc (:next-uuid %))))
+                       {:status :ok :status-info :created
+                        :kvs-ident [name (:next-uuid %)]}])
+                    [% {:status :invalid :status-info :no-name}])))

    :kvs-remove
    (fn [actx state-ch m]
      (state-work actx state-ch m
-                 (kvs-check (:kvs-ident m)
-                            (fn [state kvs]
-                              [(dissoc-in state [:kvss (:name kvs)])
-                               {:status :ok}]))))
+                 (kvs-ident-check (:kvs-ident m)
+                                  (fn [state kvs]
+                                    [(dissoc-in state [:kvss (:name kvs)])
+                                     {:status :ok :status-info :removed}]))))

    :multi-get
    (fn [actx state-ch m]
      (let [keys (:keys m)
            res-m (dissoc m :keys)
            res-ch (:res-ch m)
-           done-ch (achan actx)
            work-fn (fn [state kvs]
-                     [state
-                      (act multi-get actx
-                           (doseq [key (:keys m)]
-                             (if-let [entry (kvs-entry-by-key kvs key)]
-                               (aput multi-get res-ch
-                                     (merge res-m
-                                            {:partial :ok :key key :entry entry}))
-                               (aput multi-get res-ch
-                                     (merge res-m
-                                            {:partial :not-found :key key}))))
-                           (aput multi-get done-ch {:status :ok}))])]
-       (state-work actx state-ch m
-                   (kvs-check (:kvs-ident m) work-fn) done-ch)))
+                     (act multi-get actx
+                          (let [kc-clean (:clean kvs)]
+                            (doseq [key (:keys m)]
+                              (if-let [entry (kc-entry-by-key kc-clean key)]
+                                (aput multi-get res-ch
+                                      (merge res-m
+                                             {:partial :ok :key key :entry entry}))
+                                (aput multi-get res-ch
+                                      (merge res-m
+                                             {:partial :not-found :key key}))))
+                            (aput multi-get res-ch {:status :ok})))
+                     [state nil])]
+       (act multi-get-start actx
+         (aput multi-get-start state-ch [work-fn nil]))))

    :multi-change
    (fn [actx state-ch [res-ch name changes]])
@@ -121,10 +127,10 @@

     ; Using kvs-mgr-state to avoid atoms, which prevent time-travel.
     (act-loop kvs-mgr-state actx [state { :next-uuid 0 :kvss {} }]
-              (if-let [[state-fn res-ch] (atake kvs-mgr-state state-ch)]
-                (if-let [[next-state res] (state-fn state)]
-                  (do (when (and res-ch res)
-                        (aput-close kvs-mgr-state res-ch res))
+              (if-let [[state-fn done-ch] (atake kvs-mgr-state state-ch)]
+                (if-let [[next-state done-res] (state-fn state)]
+                  (do (when (and done-ch done-res)
+                        (aput-close kvs-mgr-state done-ch done-res))
                       (recur next-state))
                   (println :kvs-mgr-state-fn-exit))
                 (println :kvs-mgr-state-ch-exit)))


Added TODO comment.

Added TODO comment.

--- src/cbfg/npr.cljs
+++ src/cbfg/npr.cljs
@@ -1,6 +1,8 @@
 (ns cbfg.npr ; NPR stands for aNother Protocol for Replication, pronounced like UPR.
   (:require-macros [cbfg.act :refer [achan-buf act act-loop
                                      aput aput-close atake]]))
+
+; TODO: What if the underlying bucket / collection is deleted, flushed or DDL modified?

 (defprotocol NPRSnapshot
   (snapshot-rollback? [this])


Refactor: Fix indentation

Refactor: Fix indentation

Acked-by: Juan A. Ruz <fd32a78311daf157576625b0c2bbe145183ae007@gmail.com>

--- backend/test/akvo/lumen/transformation_test.clj
+++ backend/test/akvo/lumen/transformation_test.clj
@@ -144,20 +144,20 @@
     ;;https://github.com/akvo/akvo-lumen/issues/1517
     (testing "Combining columns where one of the columns has empty values"
       (let [[tag _] (apply-transformation {:type :transformation
-                                          :transformation {"op" "core/combine"
-                                                           "args" {"columnNames" ["c2" "c3"]
-                                                                   "newColumnTitle" "issue1517"
-                                                                   "separator" " "}
-                                                           "onError" "fail"}})]
-       (is (= ::lib/ok tag))
-       (let [table-name (:table-name
-                         (latest-dataset-version-by-dataset-id *tenant-conn*
-                                                               {:dataset-id dataset-id}))]
-         (is (= "hope "
-                (:d2 (get-val-from-table *tenant-conn*
-                                         {:rnum 1
-                                          :column-name "d2"
-                                          :table-name table-name})))))))
+                                           :transformation {"op" "core/combine"
+                                                            "args" {"columnNames" ["c2" "c3"]
+                                                                    "newColumnTitle" "issue1517"
+                                                                    "separator" " "}
+                                                            "onError" "fail"}})]
+        (is (= ::lib/ok tag))
+        (let [table-name (:table-name
+                          (latest-dataset-version-by-dataset-id *tenant-conn*
+                                                                {:dataset-id dataset-id}))]
+          (is (= "hope "
+                 (:d2 (get-val-from-table *tenant-conn*
+                                          {:rnum 1
+                                           :column-name "d2"
+                                           :table-name table-name})))))))
     ))

 (defn date-transformation [column-name format]


adding default-fn calling which pushes us to over 500ms

--- src/babel/english/lab.cljc
+++ src/babel/english/lab.cljc
@@ -99,24 +99,26 @@
 (def lexemes
   (flatten (vals (:lexicon model))))

+(def default-fn (:default-fn model))
+
 (defn basecamp []
   (let [tree the-static-tree]
-    (morph (-> tree
-               (basecamp-at [:head :head] (first (take 1 (shuffle ["see"]))))
-               (u/dissoc-paths [[:head :head]])
-               (basecamp-at [:head :comp :head :head] (first (take 1 (shuffle ["game" "word" "book"]))))
-               (u/dissoc-paths [[:head :comp :head :head]])
-               (basecamp-at [:head :comp :head :comp] (first (take 1 (shuffle ["new" "intelligent"]))))
-               (u/dissoc-paths [[:head :comp :head]])
-               (basecamp-at [:head :comp :comp] "the")
-               (u/dissoc-paths [[:head]])
-               (basecamp-at [:comp :head :head] (first (take 1 (shuffle ["professor" "man" "woman" "pupil"]))))
-               (u/dissoc-paths [[:comp :head :head]])
-               (basecamp-at [:comp :head :comp] (first (take 1 (shuffle ["tall" "small" "old"]))))
-               (u/dissoc-paths [[:comp :head]])
-               (basecamp-at [:comp :comp] "the")
-               (u/dissoc-paths [[:comp]])))))
-
+    (-> tree
+        (basecamp-at [:head :head] (first (take 1 (shuffle ["see"]))))
+        (u/dissoc-paths [[:head :head]])
+        (basecamp-at [:head :comp :head :head] (first (take 1 (shuffle ["game" "word" "book"]))))
+        (u/dissoc-paths [[:head :comp :head :head]])
+        (basecamp-at [:head :comp :head :comp] (first (take 1 (shuffle ["new" "intelligent"]))))
+        (u/dissoc-paths [[:head :comp :head]])
+        (basecamp-at [:head :comp :comp] "the")
+        (u/dissoc-paths [[:head]])
+        (basecamp-at [:comp :head :head] (first (take 1 (shuffle ["man" "woman"]))))
+        (u/dissoc-paths [[:comp :head :head]])
+        (basecamp-at [:comp :head :comp] (first (take 1 (shuffle ["tall" "small" "old"]))))
+        (u/dissoc-paths [[:comp :head]])
+        (basecamp-at [:comp :comp] "the")
+        (u/dissoc-paths [[:comp]]))))
+
 (defn basecamp-at [tree path lexeme-surface-form]
 ;;  (println (str "@" path))
   (first (->> (shuffle (filter #(= lexeme-surface-form
@@ -126,7 +128,10 @@
                      (let [tree (u/copy tree)
                            lexeme (u/copy lexeme)]
                         (u/assoc-in! tree path lexeme))))
-              (filter #(not (= :fail %))))))
+              (filter #(not (= :fail %)))
+              (mapcat (fn [tree]
+                        (default-fn tree))))))
+

 (defn nextcamp []
   (let [parse (-> "the small dogs you see" parse first)]


Change text for link.

Change text for link.

--- src/beebster_clj/views.clj
+++ src/beebster_clj/views.clj
@@ -135,7 +135,9 @@
      [:div.iplayerinfo
       [:p (first desc)]]
      [:div.wikilink
-      [:a {:href (wiki-url (first title))} (first title)]])))
+      [:a {:href (wiki-url (first title))} "Look up on wikipedia"]
+      [:br]
+      [:a {:href (imdb-url (first title))} "Look up on IMDB"]])))

 (defn download-page
   [index mode]


Email now reads subject from data

Email now reads subject from data

--- src/cat_facts_v2/email.clj
+++ src/cat_facts_v2/email.clj
@@ -8,7 +8,7 @@
   (postal/send-message {:from "facts@cat-facts.com"
                         :to [recipient-email]
                         :bcc "jonneale@gmail.com"
-                 :subject "Sloth facts - your daily dose of slow moving sustenance"
+                 :subject (:subject data)
                  :body [{:type "text/html"
                          :content (index/render data)}]}))


Removing timing verbiage, start enumerating min/max.

--- src/frmr/dstt.clj
+++ src/frmr/dstt.clj
@@ -47,10 +47,14 @@
   (let [request-indicies (range number-of-requests)
         request-delays (map #(* % pause-between-requests) request-indicies)
         request-futures (map #(issue-timed-request request-invoker % handler) request-delays)
-        result-timings (doall (map deref (doall request-futures)))
-        grouped-result-categories (partition (count result-timings) (apply interleave result-timings))
-        average-timing-per-category (map average grouped-result-categories)]
-    (println (str "Average time per category:\n" (vec average-timing-per-category)))))
+        results (doall (map deref (doall request-futures)))
+        grouped-result-categories (partition (count results) (apply interleave results))
+        average-per-category (mapv average grouped-result-categories)
+        min-per-category (mapv #(apply min %) grouped-result-categories)
+        max-per-category (mapv #(apply max %) grouped-result-categories)]
+    (println (str "Average: " average-per-category))
+    (println (str "Minimum: " min-per-category))
+    (println (str "Maximum: " max-per-category))))

 (defn- parse-header
   "Parse a header string from the command line into a map for the http library."


Monitoring is only in peer group.

Monitoring is only in peer group.

--- src/onyx/system.clj
+++ src/onyx/system.clj
@@ -85,8 +85,7 @@
 (defn onyx-development-env
   [peer-config]
   (map->OnyxDevelopmentEnv
-   {:monitoring (extensions/monitoring-agent ;or (:onyx.monitoring/config peer-config)
-                                                 {:monitoring :no-op})
+   {:monitoring (extensions/monitoring-agent {:monitoring :no-op})
     :logging-config (logging-config/logging-configuration peer-config)
     :log (component/using (zookeeper peer-config) [:monitoring :logging-config])}))

@@ -130,8 +129,7 @@
   [peer-client-config]
   (validator/validate-peer-client-config peer-client-config)
   (map->OnyxClient
-   {:monitoring (extensions/monitoring-agent (or ;(:onyx.monitoring/config peer-client-config)
-                                                 {:monitoring :no-op}))
+   {:monitoring (extensions/monitoring-agent {:monitoring :no-op})
     :log (component/using (zookeeper peer-client-config) [:monitoring])}))

 (defn onyx-task
@@ -159,10 +157,7 @@
   (map->OnyxPeerGroup
    {:config peer-config
     :logging-config (logging-config/logging-configuration peer-config)
-    :monitoring (component/using ;extensions/monitoring-agent
-                                  ;(:onyx.monitoring/config peer-config)
-                                      (metrics-monitoring/new-monitoring)
-                                 [:logging-config])
+    :monitoring (component/using (metrics-monitoring/new-monitoring) [:logging-config])
     :messenger-group (component/using (m/build-messenger-group peer-config) [:logging-config])
     :query-server (component/using (qs/query-server peer-config) [:logging-config])
     :peer-group-manager (component/using (pgm/peer-group-manager peer-config onyx-vpeer-system)


CMR-3184: Wrapped the warning in a do block and return nil explicitly.

--- metadata-db-app/src/cmr/metadata_db/services/concept_constraints.clj
+++ metadata-db-app/src/cmr/metadata_db/services/concept_constraints.clj
@@ -31,11 +31,13 @@
   (let [num-concepts (count concepts)]
     (cond
       (zero? num-concepts)
-      (warn
-        (format "Unable to find saved concept for provider [%s] and %s [%s]"
-                (:provider-id concept)
-                (name field)
-                field-value))
+      (do
+        (warn
+          (format "Unable to find saved concept for provider [%s] and %s [%s]"
+                  (:provider-id concept)
+                  (name field)
+                  field-value))
+        nil)
       (> num-concepts 1)
       [(msg/duplicate-field-msg
          field


privitizing

privitizing

--- src/puny/core.clj
+++ src/puny/core.clj
@@ -15,11 +15,13 @@
   (:use
     [slingshot.slingshot :only  [throw+ try+]]
     [celestial.redis :only (wcar hsetall*)]
+    [celestial.common :only (import-logging)]
     [clojure.core.strint :only (<<)])
   (:require
     [taoensso.carmine :as car])
  )

+(import-logging)
 (defmacro <<<
   "String interpulation into a symbol"
   [s] `(symbol (<< ~s)))
@@ -56,18 +58,18 @@
   (let [{:keys [index-add index-del index-get reindex]} (indices-fn-ids name*)
         indices-ks (into [] (map keyword indices))]
     `(do
-       (defn ~index-add [~'id ~'v]
+       (defn- ~index-add [~'id ~'v]
          (doseq [i# ~indices-ks]
            (car/sadd (str '~name* i# (get ~'v i#)) ~'id )))

        (defn ~index-get [~'k ~'v]
          (wcar (car/smembers (str '~name* ~'k ~'v))))

-       (defn ~index-del [~'id ~'v]
+       (defn- ~index-del [~'id ~'v]
          (doseq [i# ~indices-ks]
            (wcar (car/srem (str '~name* i# (get ~'v i#)) ~'id))))

-        (defn ~reindex [~'id ~'old ~'new]
+        (defn- ~reindex [~'id ~'old ~'new]
           (~index-del ~'id ~'old)
           (~index-add ~'id ~'new)))))

@@ -120,7 +122,8 @@
     `(do
        (declare ~validate-fn)

-       (defn ~gen-fn []
+       (defn- ~gen-fn []
+         "generated ids for entities"
          (wcar (~id-fn (car/incr ~(<< "~{name*}:ids")))))

        (defn ~add-fn [~'v]
@@ -143,7 +146,7 @@
        (defn ~update-fn ~up-args
          (~validate-fn ~'v)
          (~exists! ~up-id)
-         (let [orig# (wcar (car/hgetall* (~id-fn ~up-id) true)) updated# (merge orig#  ~'v)]
+         (let [orig# (wcar (car/hgetall* (~id-fn ~up-id) true)) updated# (merge orig# ~'v)]
            (wcar
              (~reindex ~up-id orig# updated#)
              (hsetall* (~id-fn ~up-id) (assoc updated# :meta ~meta*))))))))


Correct wiki links

Correct wiki links

--- src/re_frame/router.cljs
+++ src/re_frame/router.cljs
@@ -48,7 +48,7 @@
   (if (nil? event-v)
     (warn "re-frame: \"dispatch\" is ignoring a nil event.")     ;; nil would close the channel
     (put! event-chan event-v))
-  nil)   ;; Ensure nil return. See https://github.com/Day8/re-frame/wiki/Returning-False
+  nil)   ;; Ensure nil return. See https://github.com/Day8/re-frame/wiki/Beware-Returning-False

 (defn dispatch-sync
@@ -59,6 +59,6 @@
      (dispatch-sync [:delete-item 42])"
   [event-v]
   (handle event-v)
-  nil)    ;; Ensure nil return. See https://github.com/Day8/re-frame/wiki/Returning-False
+  nil)    ;; Ensure nil return. See https://github.com/Day8/re-frame/wiki/Beware-Returning-False


Add UI related error handling under uxbox.ui ns.

Instead of on uxbox.state.

--- src/uxbox/ui.cljs
+++ src/uxbox/ui.cljs
@@ -8,14 +8,18 @@
 (ns uxbox.ui
   (:require [sablono.core :as html :refer-macros [html]]
             [promesa.core :as p]
+            [beicon.core :as rx]
             [goog.dom :as gdom]
             [rum.core :as rum]
             [lentes.core :as l]
             [uxbox.state :as st]
             [uxbox.router :as r]
             [uxbox.rstore :as rs]
+            [uxbox.locales :refer (tr)]
             [uxbox.data.projects :as dp]
             [uxbox.data.users :as udu]
+            [uxbox.data.auth :as dauth]
+            [uxbox.data.messages :as dmsg]
             [uxbox.ui.icons :as i]
             [uxbox.ui.lightbox :as ui-lightbox]
             [uxbox.ui.auth :as ui-auth]
@@ -33,6 +37,33 @@
 (def route-l
   (as-> (l/key :route) $
     (l/focus-atom $ st/state)))
+
+;; --- Error Handling
+
+(defn- on-error
+  "A default error handler."
+  [error]
+  (cond
+    ;; Unauthorized or Auth timeout
+    (and (:status error)
+         (:payload error)
+         (or (= (:status error) 403)
+             (= (:status error) 419)))
+    (rs/emit! (dauth/logout))
+
+    ;; Network error
+    (= (:status error) 0)
+    (do
+      (dmsg/error! (tr "errors.network"))
+      (js/console.error "Stack:" (.-stack error)))
+
+    ;; Something else
+    :else
+    (do
+      (dmsg/error! (tr "errors.generic"))
+      (js/console.error "Stack:" (.-stack error)))))
+
+(rs/add-error-watcher :ui on-error)

 ;; --- Main App (Component)


Default to 406 rather than application/octet-stream

--- src/yada/core.clj
+++ src/yada/core.clj
@@ -635,7 +635,7 @@
                               (when (not-empty m) [m]))
                             (:representations resource-properties)
                             ;; Default
-                            [{:media-type "application/octet-stream"}])))
+                            [{}])))

          vary (rep/vary representations)