[l.d.manifest] Manifest cleanup

[l.d.manifest] Manifest cleanup

--- src/leiningen/droid/manifest.clj
+++ src/leiningen/droid/manifest.clj
@@ -3,9 +3,10 @@
   (:require [clojure.data.zip.xml :refer :all]
             [clojure.xml :as xml]
             [clojure.java.io :as jio]
+            [clojure.string :as str]
             [clojure.zip :refer [up xml-zip]]
             [clostache.parser :as clostache]
-            [leiningen.core.main :refer [info debug]]
+            [leiningen.core.main :refer [info debug abort]]
             [leiningen.droid.aar :refer [get-aar-files]]
             [leiningen.droid.utils :refer [dev-build?]]
             [leiningen.release :refer [parse-semantic-version]])
@@ -25,9 +26,6 @@
 ;; Attribute name for minimal SDK version.
 (def ^:private min-sdk-attribute (keyword :android:minSdkVersion))

-;; Attribute name for project version name.
-(def ^:private version-name-attribute (keyword :android:versionName))
-
 ;; ### Local functions

 (defn- load-manifest
@@ -42,7 +40,7 @@
   (xml-> manifest :application :activity :intent-filter :category
          (attr= :android:name launcher-category)))

-;; ### Public functions
+;; ### Manifest parsing and data extraction

 (defn get-package-name
   "Returns the name of the application's package."
@@ -70,31 +68,30 @@
   "Extracts the target SDK version from the provided manifest file. If
   target SDK is not specified returns minimal SDK."
   [manifest-path]
-  (let [[uses-sdk] (xml-> (load-manifest manifest-path) :uses-sdk)
-        [target-sdk] (xml-> uses-sdk (attr target-sdk-attribute))]
-    (or target-sdk
+  (let [[uses-sdk] (xml-> (load-manifest manifest-path) :uses-sdk)]
+    (or (first (xml-> uses-sdk (attr target-sdk-attribute)))
         (first (xml-> uses-sdk (attr min-sdk-attribute))))))

-(defn get-project-version
-  "Extracts the project version name from the provided manifest file."
-  [manifest-path]
-  (first (xml-> (load-manifest manifest-path) (attr version-name-attribute))))
-
-(def ^:private version-bit-sizes [9 9 9 5])
+;; ### Manifest templating

 (def ^:private version-maximums
-  (mapv (partial bit-shift-left 1) version-bit-sizes))
+  "Maximum values per each version bucket."
+  (mapv (partial bit-shift-left 1) [9 9 9 5]))

 (def ^:private version-coefficients
-  (mapv (fn [offset] (bit-shift-left 1 (- 32 offset)))
-        (reductions + version-bit-sizes)))
+  "Each part of the version number will be multiplied by the respective
+  coefficient, all of which are calculated here."
+  (->> version-maximums
+       (reductions +)
+       (mapv (fn [offset] (bit-shift-left 1 (- 32 offset))))))

 (defn- assert>
   "Asserts that a>b in version segments"
   [a b]
-  (assert (> a b) (str "Version number segment too large to fit in the
-  version-code scheme " b ">" a ", maximum version in each segment
-  is " (clojure.string/join "." version-maximums)))
+  (when-not (> a b)
+    (abort (format "Version number segment too large to fit in the
+ version-code scheme: %s > %s, maximum version in each segment is %s"
+                   b a (str/join "." version-maximums))))
   b)

 (defn version-code


cli: use nil? instead of not

cli: use nil? instead of not

--- src/com/okl/tokenmgr/cli.clj
+++ src/com/okl/tokenmgr/cli.clj
@@ -163,7 +163,7 @@
         cli-tokens (:token (:options parsed-opts))
         tokens (process-token-values (get-token-values app envt cli-tokens))]
     (let [num-unexpanded (process-dir dir tokens)]
-      (if (or (not num-unexpanded) (> num-unexpanded 0))
+      (if (or (nil? num-unexpanded) (> num-unexpanded 0))
         1
         0))))


add multimethod docset type

add multimethod docset type

--- src/main/cljs_api_gen/docset.clj
+++ src/main/cljs_api_gen/docset.clj
@@ -56,6 +56,7 @@
    "binding"             "Builtin"
    "convention"          "Builtin"
    "special character"   "Builtin"
+   "multimethod"         "Method"
    })

 (defn dash-name


make duplicating shapes increment layer names and actions (view-1 -> view-2)

--- src-cljs/frontend/controllers/controls.cljs
+++ src-cljs/frontend/controllers/controls.cljs
@@ -188,6 +188,12 @@
                 (update-in [:entity-ids] disj entity-id))]
             r)))

+(defn inc-str-id [str-id]
+  (str/replace str-id #"(.+?)(-{0,1})(\d+)?$" (fn [match base dash num]
+                                            (str base
+                                                 "-"
+                                                 (inc (js/parseInt (or num "0")))))))
+
 (defmethod control-event :layer-duplicated
   [browser-state message {:keys [layer x y]} state]
   (let [[rx ry] (cameras/screen->point (:camera state) x y)
@@ -201,7 +207,11 @@
                                         :layer/start-x (:layer/start-x layer)
                                         :layer/end-x (:layer/end-x layer)
                                         :layer/current-x (:layer/end-x layer)
-                                        :layer/current-y (:layer/end-y layer))])
+                                        :layer/current-y (:layer/end-y layer)
+                                        :layer/ui-id (when (:layer/ui-id layer)
+                                                       (inc-str-id (:layer/ui-id layer)))
+                                        :layer/ui-action (when (:layer/ui-action layer)
+                                                           (inc-str-id (:layer/ui-action layer))))])
         (assoc-in [:drawing :moving?] true)
         (assoc-in [:drawing :starting-mouse-position] [rx ry])
         (update-in [:entity-ids] disj entity-id))))
@@ -226,7 +236,11 @@
                                                      :layer/start-x (:layer/start-x layer)
                                                      :layer/end-x (:layer/end-x layer)
                                                      :layer/current-x (:layer/end-x layer)
-                                                     :layer/current-y (:layer/end-y layer)))
+                                                     :layer/current-y (:layer/end-y layer)
+                                                     :layer/ui-id (when (:layer/ui-id layer)
+                                                                    (inc-str-id (:layer/ui-id layer)))
+                                                     :layer/ui-action (when (:layer/ui-action layer)
+                                                                        (inc-str-id (:layer/ui-action layer)))))
                                                  layers entity-ids)
                                            group-layer))
         (assoc-in [:drawing :moving?] true)


Fetch all lazy data

Fetch all lazy data

--- src/cyanite_fetcher/core.clj
+++ src/cyanite_fetcher/core.clj
@@ -96,14 +96,14 @@
   "Fetch data in parallel fashion."
   (let [futures
         (doall (map #(future
-                       (->> (alia/execute
-                             session fetch!
-                             {:values [% tenant (int rollup)
-                                       (int period)
-                                       from to]
-                              :fetch-size Integer/MAX_VALUE})
-                            (map detect-aggregate)
-                            (seq)))
+                       (let [data (alia/execute
+                                   session fetch!
+                                   {:values [% tenant (int rollup)
+                                             (int period)
+                                             from to]
+                                    :fetch-size Integer/MAX_VALUE})]
+                         (->> (doall (map detect-aggregate data))
+                              (seq))))
                     paths))]
     (map deref futures)))

@@ -349,8 +349,7 @@
     (newline)
     (let [paths (es-get-paths eshost path tenant)
           data (c-get-data chost paths tenant rollup period from to)
-          fdata (flatter data (fn [data] (r/reduce into [] data)) "warming r/reduce")]
-      (flatter data (fn [data] (r/reduce into [] data)) "r/reduce")
+          fdata (flatter data (fn [data] (r/reduce into [] data)) "r/reduce")]
       (flatter data (fn [data] (reduce into data)) "reduce")
       (cleaner fdata (fn [data] (into [] (r/remove nil? data))) "r/remove")
       (cleaner fdata (fn [data] (remove nil? data))  "remove")


added nested entity support in datastore

--- src/datasplash/datastore.clj
+++ src/datasplash/datastore.clj
@@ -3,10 +3,9 @@
   (:import
    [com.google.datastore.v1.client DatastoreHelper]
    [com.google.cloud.dataflow.sdk.io.datastore DatastoreIO]
-   [com.google.cloud.dataflow.sdk Pipeline]
-   [com.google.cloud.dataflow.sdk.values PBegin PCollection]
-   [com.google.datastore.v1 Entity Value Entity$Builder Key$Builder Value$Builder Value$ValueTypeCase]
-   [com.google.protobuf ByteString])
+   [com.google.datastore.v1 Entity Value Key Entity$Builder Key$Builder Value$Builder Value$ValueTypeCase Key$PathElement]
+   [com.google.protobuf ByteString]
+   [java.util Collections$UnmodifiableMap$UnmodifiableEntrySet$UnmodifiableEntry])
   (:gen-class))

 (defn write-datastore-raw
@@ -30,77 +29,105 @@
     (apply-transform pcoll ptrans named-schema opts)))

 (declare value->clj)
+(declare entity->clj)

 (def type-mapping {(Value$ValueTypeCase/valueOf "INTEGER_VALUE") (fn [^Value v] (.getIntegerValue v))
                    (Value$ValueTypeCase/valueOf "DOUBLE_VALUE") (fn [^Value v] (.getDoubleValue v))
                    (Value$ValueTypeCase/valueOf "STRING_VALUE") (fn [^Value v] (.getStringValue v))
                    (Value$ValueTypeCase/valueOf "BOOLEAN_VALUE") (fn [^Value v] (.getBooleanValue v))
-                   (Value$ValueTypeCase/valueOf "BLOB_VALUE") (fn [^Value v] (.toByteArray (.getBlobValue v)))
-                   (Value$ValueTypeCase/valueOf "ARRAY_VALUE") (fn [^Value v] (mapv value->clj (.getValuesList (.getArrayValue v))))
+                   (Value$ValueTypeCase/valueOf "BLOB_VALUE") (fn [^Value v]
+                                                                (.toByteArray (.getBlobValue v)))
+                   (Value$ValueTypeCase/valueOf "ARRAY_VALUE") (fn [^Value v]
+                                                                 (mapv value->clj (.getValuesList (.getArrayValue v))))
+                   (Value$ValueTypeCase/valueOf "ENTITY_VALUE") (fn [^Value v]
+                                                                  (entity->clj (.getEntityValue v)))
                    (Value$ValueTypeCase/valueOf "NULL_VALUE") (constantly nil)})

 (defn value->clj
-  [v]
+  [^Value v]
   (let [t (.getValueTypeCase v)
         tx (type-mapping t)]
     (if tx
       (tx v)
-      (throw (ex-info (format "Datastore type not supported: %s" t) {:value v})))))
+      (throw (ex-info (format "Datastore type not supported: %s" t) {:value v :type t})))))

 (defn entity->clj
-  [e]
-  (reduce (fn [acc kv]
-            (let [value (value->clj (.getValue kv))]
-              (assoc acc (keyword (.getKey kv)) value)))
-          {} (.getProperties e)))
+  "Converts a Datastore Entity to a Clojure map with the same properties. Repeated fields are handled as vectors and nested Entities as maps. All keys are turned to keywords. If the entity has a Key, Kind or Namespace, these can be found as :ds-key, :ds-kind and :ds-namespace in the meta of the returned map"
+  [^Entity e]
+  (let [props (persistent!
+               (reduce (fn [acc ^Collections$UnmodifiableMap$UnmodifiableEntrySet$UnmodifiableEntry kv]
+                         (let [value (value->clj (.getValue kv))]
+                           (assoc! acc (keyword (.getKey kv)) value)))
+                       (transient {}) (.getProperties e)))
+        [^Key k key-name kind] (when (.hasKey e) (let [k (.getKey e)
+                                                       ^Key$PathElement fpl (first (.getPathList k))
+                                                       kind (.getKind fpl)
+                                                       key (.getName fpl)]
+                                                   [k key kind]))
+        namespace (when (and k (.hasPartitionId k))
+                    (some-> k (.getPartitionId) (.getNamespaceId)))]
+    (-> props
+        (cond-> k (with-meta {:ds-key key-name :ds-kind kind :ds-namespace namespace})))))

 (defprotocol IValDS
-  (make-ds-value-builder [v options]))
+  (make-ds-value-builder [v]))

 (declare make-ds-value)
+(declare make-ds-entity)

 (extend-protocol IValDS
   String
-  (make-ds-value-builder [^String v _] (DatastoreHelper/makeValue v))
+  (make-ds-value-builder [^String v] (DatastoreHelper/makeValue v))
   clojure.lang.Keyword
-  (make-ds-value-builder [v _] (DatastoreHelper/makeValue (name v)))
+  (make-ds-value-builder [v] (DatastoreHelper/makeValue (name v)))
   java.util.Date
-  (make-ds-value-builder [^java.util.Date v _] (DatastoreHelper/makeValue v))
+  (make-ds-value-builder [^java.util.Date v] (DatastoreHelper/makeValue v))
   clojure.lang.PersistentList
-  (make-ds-value-builder [v options] (DatastoreHelper/makeValue ^Iterable (mapv #(make-ds-value % options) v)))
+  (make-ds-value-builder [v] (DatastoreHelper/makeValue ^Iterable (mapv #(make-ds-value %) v)))
   clojure.lang.PersistentHashSet
-  (make-ds-value-builder [v options] (DatastoreHelper/makeValue ^Iterable (mapv #(make-ds-value % options) v)))
+  (make-ds-value-builder [v] (DatastoreHelper/makeValue ^Iterable (mapv #(make-ds-value %) v)))
   clojure.lang.PersistentTreeSet
-  (make-ds-value-builder [v options] (DatastoreHelper/makeValue ^Iterable (mapv #(make-ds-value % options) v)))
+  (make-ds-value-builder [v] (DatastoreHelper/makeValue ^Iterable (mapv #(make-ds-value %) v)))
   clojure.lang.PersistentVector
-  (make-ds-value-builder [v options] (DatastoreHelper/makeValue ^Iterable (mapv #(make-ds-value % options) v)))
+  (make-ds-value-builder [v] (DatastoreHelper/makeValue ^Iterable (mapv #(make-ds-value %) v)))
+  clojure.lang.PersistentHashMap
+  (make-ds-value-builder [v] (DatastoreHelper/makeValue ^Entity (make-ds-entity v)))
+  clojure.lang.PersistentArrayMap
+  (make-ds-value-builder [v] (DatastoreHelper/makeValue ^Entity (make-ds-entity v)))
+  clojure.lang.PersistentTreeMap
+  (make-ds-value-builder [v] (DatastoreHelper/makeValue ^Entity (make-ds-entity v)))
   Object
-  (make-ds-value-builder [v _] (DatastoreHelper/makeValue v)))
+  (make-ds-value-builder [v] (DatastoreHelper/makeValue v)))
+
+(defn- add-ds-key-namespace-kind
+  [^Entity$Builder builder {:keys [ds-key ds-namespace ds-kind] :as options}]
+  (let [^Key$Builder key-builder (DatastoreHelper/makeKey (into-array [ds-kind ds-key]))]
+    (when ds-namespace (.setNamespaceId (.getPartitionIdBuilder key-builder) ds-namespace))
+    (.setKey builder (.build key-builder))
+    builder))

 (defn- make-ds-entity-builder
-  [raw-key raw-values {:keys [ds-namespace ds-kind exclude-from-index] :as options}]
-  (let [^Key$Builder key-builder (DatastoreHelper/makeKey (into-array [ds-kind raw-key]))
-        excluded-set (into #{} (map name exclude-from-index))
+  [raw-values {:keys [ds-key ds-namespace ds-kind exclude-from-index] :as options}]
+  (let [excluded-set (into #{} (map name exclude-from-index))
         ^Entity$Builder entity-builder (Entity/newBuilder)]
-    (when ds-namespace (.setNamespaceId (.getPartitionIdBuilder key-builder) ds-namespace))
-    (.setKey entity-builder (.build key-builder))
     (doseq [[v-key v-val] raw-values
             :when v-val]
       (.put (.getMutableProperties entity-builder)
             (if (keyword? v-key) (name v-key) v-key)
-            (let [^Value$Builder val-builder (make-ds-value-builder v-val options)]
+            (let [^Value$Builder val-builder (make-ds-value-builder v-val)]
               (-> val-builder
                   (cond-> (excluded-set (name v-key)) (.setExcludeFromIndexes true))
                   (.build)))))
     entity-builder))

 (defn- make-ds-value
-  [v options]
-  ;; stop building here when print bug id fixed in gcloud and handle excluded afterwards
-  (.build ^Value$Builder (make-ds-value-builder v options)))
+  [v]
+  (.build ^Value$Builder (make-ds-value-builder v)))

 (defn make-ds-entity
-  "Builds a Datastore Entity with the given key, value is a map corresponding to the desired entity, and options contains namespace, kind and an optional set of keys that shoud not be indexed (irrespective of nesting). For now repeated fields are supported but not nested entity"
-  [raw-key raw-values {:keys [ds-namespace ds-kind exclude-from-index] :as options}]
-  (-> ^Entity$Builder (make-ds-entity-builder raw-key raw-values options)
-      (.build)))
+  "Builds a Datastore Entity with the given Clojure value which is a map or seq of KVs corresponding to the desired entity, and options contains an optional key, namespace, kind and an optional set of field names that shoud not be indexed (only supported for top level fields for now). Supports repeated fields and nested entities (as nested map)"
+  ([raw-values {:keys [ds-key ds-namespace ds-kind exclude-from-index] :as options}]
+   (let [^Entity$Builder builder (-> (make-ds-entity-builder raw-values options)
+                                     (cond-> ds-key (add-ds-key-namespace-kind options)))]
+     (.build builder)))
+  ([raw-values] (make-ds-entity raw-values {})))


Added todo comment.

Added todo comment.


Re-tagged "Black Box Testing"

Re-tagged "Black Box Testing"

--- src/foreclojure/data_set.clj
+++ src/foreclojure/data_set.clj
@@ -675,7 +675,7 @@
             :title "Black Box Testing"
             :times-solved 0
             :description "Clojure has many collection types, which act in subtly different ways. The core functions typically convert them into a uniform \"sequence\" type and work with them that way, but it can be important to understand the behavioral and performance differences so that you know which kind is appropriate for your application.

Write a function which takes a collection and returns one of :map, :set, :list, or :vector - describing the type of collection it was given.
You won't be allowed to inspect their class or use the built-in predicates like list? - the point is to poke at them and understand their behavior."
-            :tags ["medium" "seqs" "testing"]
+            :tags ["hard" "seqs" "testing"]
             :tests ["(= :map (__ {:a 1, :b 2}))",
                     "(= :list (__ (range (rand-int 20))))",
                     "(= :vector (__ [1 2 3 4 5 6]))",


add hints

add hints

--- src/functional_music/tab.clj
+++ src/functional_music/tab.clj
@@ -13,6 +13,7 @@

 (defn filter-tab-lines
   "Only keep the lines that are tabs. Assuming that tab lines must have a '-' and '|' characters."
+  ; hint: filter, defn, .contains, ->, ->>
   [coll]
   )

@@ -29,12 +30,14 @@
        (reduce join-tabs)))

 (defn remove-format [coll]
+  ; hint: map, s/replace, #
   )

 (defn to-string-fret [[s f]]
   [s (java.lang.Character/getNumericValue f)])

 (defn tab->string-fret [e B G D A E]
+  ; hint: map-indexed, vector, filter, re-seq, map
   )

 (defn parse-guitar-tab [s]


formatting fix.

formatting fix.

--- src/metabase/api/dataset.clj
+++ src/metabase/api/dataset.clj
@@ -29,7 +29,7 @@
   (read-check Database database)
   ;; add sensible constraints for results limits on our query
   (let [query (assoc body :constraints dataset-query-api-constraints)]
-      (driver/dataset-query query {:executed_by *current-user-id*})))
+    (driver/dataset-query query {:executed_by *current-user-id*})))

 (defendpoint POST "/csv"


Use environment variable for port instead of argument

--- src/infoq_podcast/server.clj
+++ src/infoq_podcast/server.clj
@@ -73,7 +73,7 @@
   (route/files "/static/")
   (route/not-found "Not found"))

-(defn -main [& args]
+(defn -main []
   (info "Starting web server")
-  (let [port (if args (util/parse-int (first args)) 8080)]
+  (let [port (util/parse-int (or (. System getenv "PORT") "8080"))]
     (http/run-server (handler/site app-routes) {:port port})))


Rewriting conditions for computing the arrow relation

Signed-off-by: Daniel Borchmann <25857343a15bf1edafebc2912e82ecf775c585c1@mailbox.tu-dresden.de>

--- src/conexp/fca/contexts.clj
+++ src/conexp/fca/contexts.clj
@@ -319,8 +319,8 @@
              m att
              :when (and (not (inz [g m]))
                         (forall [h obj]
-                          (=> (proper-subset? (prime g) (prime h))
-                              (inz [h m]))))])))
+                          (or (inz [h m])
+                              (not (proper-subset? (prime g) (prime h))))))])))

 (defn up-arrows
   "Computes the up arrow relation of ctx."
@@ -334,8 +334,8 @@
              m att
              :when (and (not (inz [g m]))
                         (forall [n att]
-                          (=> (proper-subset? (prime m) (prime n))
-                              (inz [g n]))))])))
+                          (or (inz [g n])
+                              (not (proper-subset? (prime m) (prime n))))))])))

 (defn up-down-arrows
   "Returns up-down-arrow relation of ctx."
@@ -350,11 +350,11 @@
              m atts
              :when (and (not (inz [g m]))
                         (forall [h objs]
-                          (=> (proper-subset? (oprime g) (oprime h))
-                              (inz [h m])))
+                          (or (inz [h m])
+                              (not (proper-subset? (oprime g) (oprime h)))))
                         (forall [n atts]
-                          (=> (proper-subset? (aprime m) (aprime n))
-                              (inz [g n]))))])))
+                          (or (inz [g n])
+                              (not (proper-subset? (aprime m) (aprime n))))))])))

 (defn reduce-objects
   "Object reduction for ctx."


add very basic js-await macro for promise interop

--- src/main/shadow/cljs/modern.cljc
+++ src/main/shadow/cljs/modern.cljc
@@ -305,4 +305,38 @@
      :children [:parts]}))

 (defmacro js-template [& body]
-  `(js-template* ~@body))+  `(js-template* ~@body))
+
+;; FIXME: use spec for parsing this. bad errors otherwise if used incorrectly
+(defmacro js-await [[name thenable] & body]
+  (let [last-expr (last body)
+
+        [body catch]
+        (if (and (seq? last-expr) (= 'catch (first last-expr)))
+          [(butlast body) last-expr]
+          [body nil])]
+
+    ;; FIXME: -> here will always return a promise so shouldn't be necessary to add js hint?
+    `(-> ~thenable
+         ~@(when (seq body)
+             [`(.then (fn [~name] ~@body))])
+         ~@(when catch
+             (let [[name & body] catch]
+               [`(.catch (fn [~name] ~@body))]
+               )))))
+
+
+(comment
+  (macroexpand-1
+    '(js-await [{:keys [foo]} (bar)]
+       (do-thing foo)
+       (catch x (fail x))
+       ))
+
+  (macroexpand-1
+    '(js-await [{:keys [foo]} (bar)]
+       (do-thing foo)))
+
+  (macroexpand-1
+    '(js-await [foo (bar)]
+       (catch e :yo))))


Reduce the verbage leading up to performance.

--- src/klangmeister/ui/jam.cljs
+++ src/klangmeister/ui/jam.cljs
@@ -12,9 +12,9 @@

 (defn render [handle! state-atom]
   [:div
-   [:p "Now we know how to make both instruments and melodies, we can create whole songs. To make the experience more interactive, lets graph the notes we're playing, and loop them over and over again as we edit the synth and music."]
    [graph/render handle! state-atom]
    [editor/render :main (-> @state-atom :main :text) handle! @state-atom]
    [controls handle! @state-atom]
    [:div
+    [:p "Now we know how to make both instruments and melodies, we can create whole songs. To make the experience more interactive, lets graph the notes we're playing, and loop them over and over again as we edit the synth and music."]
     [:p "If you find anything confusing, refer back to the " [:a {:href "/klangmeister/synthesis"} "synthesis tutorial"] " or the " [:a {:href "/klangmeister/music"} " music tutorial"] "."]]])


Make all functions except translate private

--- exercises/pig-latin/src/example.clj
+++ exercises/pig-latin/src/example.clj
@@ -1,7 +1,7 @@
 (ns pig-latin
   (:require [clojure.string :as str]))

-(defn starts-with-any [prefixes word]
+(defn- starts-with-any [prefixes word]
   (some (partial str/starts-with? word) prefixes))

 (defn- starts-with-vowel-like? [word]
@@ -23,7 +23,7 @@
 (defn- rotate [word n]
   (str (subs word n) (subs word 0 n)))

-(defn append-ay [word]
+(defn- append-ay [word]
   (str word "ay"))

 (defn- translate-word [word]


Show Yamato Twitter stream.

Show Yamato Twitter stream.

--- src/orbitingnews/twitter.clj
+++ src/orbitingnews/twitter.clj
@@ -1,6 +1,6 @@
 (ns orbitingnews.twitter
   (:require [orbitingnews.config :as config])
-  (:import [twitter4j TwitterFactory TwitterStreamFactory StatusListener Query QueryResult FilterQuery]
+  (:import [twitter4j TwitterFactory TwitterStreamFactory StatusListener UserStreamListener Query QueryResult FilterQuery]
            [twitter4j.auth AccessToken])
   (:gen-class))

@@ -38,6 +38,30 @@
     (onScrubGeo [userId upToStatusId] ())
     (onTrackLimitationNotice [numberOfLimitedStatuses] ())))

+(defn user-listener []
+  "Implementation of twitter4j's StatusListener interface"
+  (proxy [UserStreamListener] []
+    (onStatus [^twitter4j.Status status] (println (.getText status)))
+    (onException [^java.lang.Exception e] (.printStackTrace e))
+    (onDeletionNotice [^twitter4j.StatusDeletionNotice statusDeletionNotice] ())
+    (onScrubGeo [userId upToStatusId] ())
+    (onTrackLimitationNotice [numberOfLimitedStatuses] ())
+    (onBlock [source blockedUser] ())
+    (onDirectMessage [dm] ())
+    (onFavorite [source target favorited-status] ())
+    (onFollow [source followed] ())
+    (onFriendList [friends] ())
+    (onUnblock [source unblocked] ())
+    (onUnfavorite [source target status] ())
+    (onUserListCreation [owner user-list] ())
+    (onUserListDeletion [listOwner ll] ())
+    (onUserListMemberAddition [addedMember listOwner ll] ())
+    (onUserListMemberDeletion [deletedMember listOwner ll] ())
+    (onUserListSubscription [subscriber listOwner ll] ())
+    (onUserListUnsubscription [subscriber listOwner ll] ())
+    (onUserListUpdate [listOwner UserList ll] ())
+    (onUserProfileUpdate [User updatedUser] ())))
+
 (defn do-sample-stream []
   (let [stream (oauth-stream-authorized-twitter)]
     (.addListener stream (status-listener))
@@ -50,10 +74,10 @@
     (.addListener stream (status-listener))
     (.filter stream filter-query)))

-(defn link-stream []
+(defn user-stream []
   (let [stream (oauth-stream-authorized-twitter)]
-    (.addListener stream (status-listener))
-    (.links stream 0)))
+    (.addListener stream (user-listener))
+    (.user stream)))

 (defn search
   "Returns tweets from search"


trim docstrings to 80 chars wide

trim docstrings to 80 chars wide

--- src/overtone/sc/ugen/doc.clj
+++ src/overtone/sc/ugen/doc.clj
@@ -7,7 +7,8 @@
    [clojure.contrib.string :only (split)]))

 (defn- length-of-longest-key
-  "Returns the length of the longest key of map m. Assumes m's keys are strings and returns 0 if map is empty:
+  "Returns the length of the longest key of map m. Assumes m's keys are strings
+   and returns 0 if map is empty:
    (length-of-longest-key {\"foo\" 1 \"barr\" 2 \"bazzz\" 3}) ;=> 5
    (length-of-longest-key {}) ;=> 0"

@@ -18,7 +19,8 @@
 (defn- gen-padding
   "Generates a padding string starting concatting s with len times pad:
    (gen-padding \"\" 5 \"b\") ;=> \"bbbbb\"
-   May be called without starting string s in which case it defaults to the empty string."
+   May be called without starting string s in which case it defaults to the
+   empty string."
   ([len pad] (gen-padding "" len pad))
   ([s len pad]
      (if (> len 0)
@@ -26,9 +28,9 @@
        s)))

 (defn- indented-str-block
-  "Appends a list ls of strings to string s in a formatted block with a specific width max-len
-   and indentation indent. May be called with a basic text string and max-len and indent in which
-   case text will be split on whitespace."
+  "Appends a list ls of strings to string s in a formatted block with a specific
+   width max-len and indentation indent. May be called with a basic text string
+   and max-len and indent in which case text will be split on whitespace."
   ([txt max-len indent] (indented-str-block "" (split #" +" txt) 0 max-len indent))
   ([s ls cur-len max-len indent]
      (if (empty? ls)
@@ -101,16 +103,18 @@
     (merge last-resort default arg)))

 (defn with-arg-defaults
-  "Manipulates the spec's arg key to add documentation strings for each argument. If the doc string is
-   present it is left unmodified. Otherwise it will look up the argument in a list of default doc strings
-   for common keys. If a default is present it will add it otherwise last resort default NO-ARG-DOC-FOUND
-   will be used."
+  "Manipulates the spec's arg key to add documentation strings for each
+  argument. If the doc string is present it is left unmodified. Otherwise it
+  will look up the argument in a list of default doc strings for common keys.
+  If a default is present it will add it otherwise last resort default
+  NO-ARG-DOC-FOUND will be used."
   [spec]
   (let [new-args (map merge-arg-doc-default (:args spec))]
     (assoc spec :args new-args)))

 (defn with-full-doc
-  "Adds an extra key to the spec representing the full documentation string specifically prepared to be the
-   final ugen fn's docstring for printing on the REPL"
+  "Adds an extra key to the spec representing the full documentation string
+   specifically prepared to be the final ugen fn's docstring for printing on
+   the REPL"
   [spec]
   (assoc spec :full-doc (full-doc-str spec)))


Extract header-button into a mixin

Extract header-button into a mixin

--- src/braid/core/client/ui/styles/header.cljs
+++ src/braid/core/client/ui/styles/header.cljs
@@ -64,6 +64,26 @@
       [:&.settings::after
        (mixins/fontawesome \uf013)]]]])

+(defn header-button [size]
+  [:&
+   {:color "white"
+    :height size
+    :line-height size
+    :width size
+    :-webkit-font-smoothing "antialiased"
+    :text-align "center"
+    :text-decoration "none"}
+
+   [:>.icon
+    {:font-family "fontawesome"}]
+
+   [:&:hover
+    :&.active
+    {:background "rgba(0,0,0,0.25)"}]
+
+   [:&.open-sidebar::after
+    (mixins/fontawesome \uf0e8)]])
+
 (defn group-header [size]
   [:>.group-header

@@ -90,19 +110,7 @@
       :vertical-align "top"}

      [:>a
-      {:width size
-       :text-align "center"
-       :text-decoration "none"}
-
-      [:>.icon
-       {:font-family "fontawesome"}]
-
-      [:&:hover
-       :&.active
-       {:background "rgba(0,0,0,0.25)"}]
-
-      [:&.open-sidebar::after
-       (mixins/fontawesome \uf0e8)]]]
+      (header-button size)]]

     [:>.search-bar
      {:display "inline-block"


removed unused require

removed unused require

--- src/clj/swarmpit/docker/mapper/outbound.clj
+++ src/clj/swarmpit/docker/mapper/outbound.clj
@@ -1,7 +1,6 @@
 (ns swarmpit.docker.mapper.outbound
   "Map swarmpit domain to docker domain"
   (:require [clojure.string :as str]
-            [swarmpit.docker.client :as docker]
             [swarmpit.base64 :as base64]))

 (defn- as-bytes


Safely catch exceptions caused by peers being reallocated away from input tasks

--- src/onyx/peer/task_lifecycle.clj
+++ src/onyx/peer/task_lifecycle.clj
@@ -284,28 +284,33 @@
        (loop []
          (when-let [[v ch] (alts!! [task-kill-ch completion-ch seal-ch release-ch retry-ch])]
            (when v
-             (cond (= ch release-ch)
-                   (->> (p-ext/ack-segment pipeline event v)
-                        (lc/invoke-after-ack event compiled v))
-
-                   (= ch completion-ch)
-                   (let [{:keys [id peer-id]} v
-                         site (peer-site peer-replica-view peer-id)]
-                     (when site
-                       (emit-latency :peer-complete-segment
-                                     monitoring
-                                     #(extensions/internal-complete-segment messenger id site))))
-
-                   (= ch retry-ch)
-                   (->> (p-ext/retry-segment pipeline event v)
-                        (lc/invoke-after-retry event compiled v))
-
-                   (= ch seal-ch)
-                   (do
+             (try
+              (cond (= ch release-ch)
+                    (->> (p-ext/ack-segment pipeline event v)
+                         (lc/invoke-after-ack event compiled v))
+
+                    (= ch completion-ch)
+                    (let [{:keys [id peer-id]} v
+                          site (peer-site peer-replica-view peer-id)]
+                      (when site
+                        (emit-latency :peer-complete-segment
+                                      monitoring
+                                      #(extensions/internal-complete-segment messenger id site))))
+
+                    (= ch retry-ch)
+                    (->> (p-ext/retry-segment pipeline event v)
+                         (lc/invoke-after-retry event compiled v))
+
+                    (= ch seal-ch)
+                    (do
                      (p-ext/seal-resource pipeline event)
                      (let [entry (entry/create-log-entry :seal-output {:job (:onyx.core/job-id event)
                                                                        :task (:onyx.core/task-id event)})]
                        (>!! outbox-ch entry))))
+              (catch IllegalArgumentException iae
+                (info "Message arrived for a peer when it was allocated for alternative task.
+                       This is generally safe to ignore, but may result due to high peer allocation churn.
+                       Error:" (.getMessage iae))))
              (recur)))))
      (catch Throwable e
        (fatal (logger/merge-error-keys e (:onyx.core/task-information event) "Internal error. Failed to read core.async channels"))))))


Split state and input checkpointing out of barrier prep

--- src/onyx/peer/task_lifecycle.clj
+++ src/onyx/peer/task_lifecycle.clj
@@ -126,28 +126,25 @@
   (m/poll (get-messenger state))
   (advance state))

-(defn checkpoint-input! [state]
-  (let [messenger (get-messenger state)]
-    (if (= :input (:onyx/type (:task-map (get-event state))))
-      (let [pipeline (get-pipeline state)
-            {:keys [job-id task-id slot-id log]} (get-event state)
-            replica-version (m/replica-version messenger)
-            epoch (m/epoch messenger)
-            checkpoint (oi/checkpoint pipeline)]
-        (extensions/write-checkpoint log job-id replica-version epoch task-id slot-id :input checkpoint)
-        state)
-      state)))
-
-(defn checkpoint-state! [state]
-  (when (:windowed-task? (get-event state))
-    (let [messenger (get-messenger state)
-          {:keys [job-id task-id slot-id log]} (get-event state)
-          replica-version (m/replica-version messenger)
-          epoch (m/epoch messenger)]
-      (extensions/write-checkpoint log job-id replica-version epoch task-id slot-id
-                                   :state
-                                   (mapv ws/export-state (get-windows-state state)))))
-  state)
+(defn checkpoint-input [state]
+  (let [messenger (get-messenger state)
+        pipeline (get-pipeline state)
+        {:keys [job-id task-id slot-id log]} (get-event state)
+        replica-version (m/replica-version messenger)
+        epoch (m/epoch messenger)
+        checkpoint (oi/checkpoint pipeline)]
+    (extensions/write-checkpoint log job-id replica-version epoch task-id slot-id :input checkpoint)
+    (advance state)))
+
+(defn checkpoint-state [state]
+  (let [messenger (get-messenger state)
+        {:keys [job-id task-id slot-id log]} (get-event state)
+        replica-version (m/replica-version messenger)
+        epoch (m/epoch messenger)]
+    (extensions/write-checkpoint log job-id replica-version epoch task-id slot-id
+                                 :state
+                                 (mapv ws/export-state (get-windows-state state)))
+    (advance state)))

 (defn prepare-offer-barriers [state]
   (let [messenger (get-messenger state)]
@@ -160,8 +157,6 @@
         (-> state
             (set-context! {:barrier-opts {:completed? all-barriers-completed?}
                            :publishers (m/publishers messenger)})
-            (checkpoint-input!)
-            (checkpoint-state!)
             (advance)))
       (goto-next-batch! state))))

@@ -237,7 +232,7 @@
     (if-not (= :beginning checkpointed)
       checkpointed)))

-(defn recover-pipeline-input [state]
+(defn recover-input [state]
   (let [{:keys [recover] :as context} (get-context state)
         pipeline (get-pipeline state)
         event (get-event state)
@@ -249,7 +244,7 @@
         (set-pipeline! next-pipeline)
         (advance))))

-(defn recover-windows-state
+(defn recover-state
   [state]
   (let [{:keys [recover] :as context} (get-context state)
         {:keys [log-prefix task-map windows triggers] :as event} (get-event state)
@@ -410,17 +405,23 @@
       (#{:input :function} task-type)         (conj {:lifecycle :offer-barriers
                                                      :fn offer-barriers
                                                      :blockable? true})
-      (#{:input} task-type)                   (conj {:lifecycle :recover-pipeline-input
-                                                     :fn recover-pipeline-input})
-      windowed?                               (conj {:lifecycle :recover-windows-state
-                                                     :fn recover-windows-state})
+      (#{:input} task-type)                   (conj {:lifecycle :recover-input
+                                                     :fn recover-input})
+      windowed?                               (conj {:lifecycle :recover-state
+                                                     :fn recover-state})
       (#{:input :function :output} task-type) (conj {:lifecycle :next-iteration
                                                      :fn next-iteration})
       (#{:input} task-type)                   (conj {:lifecycle :input-poll-barriers
                                                      :fn input-poll-barriers})
       (#{:input :function} task-type)         (conj {:lifecycle :prepare-offer-barriers
                                                      :fn prepare-offer-barriers})
-      ;; prepare-offer-barriers must come before offer-barriers
+      ;; TODO: double check that checkpoint doesn't occur immediately after recovery
+      (#{:input} task-type)                   (conj {:lifecycle :checkpoint-input
+                                                     :fn checkpoint-input
+                                                     :blockable? true})
+      windowed?                               (conj {:lifecycle :checkpoint-state
+                                                     :fn checkpoint-state
+                                                     :blockable? true})
       (#{:input :function} task-type)         (conj {:lifecycle :offer-barriers
                                                      :fn offer-barriers
                                                      :blockable? true})
@@ -597,7 +598,6 @@
         recover-idx (int 0)
         iteration-idx (int (lookup-lifecycle-idx lifecycles :next-iteration))
         batch-idx (int (lookup-lifecycle-idx lifecycles :before-batch))]
-    (println "INDEXES ARE" task-map recover-idx iteration-idx batch-idx)
     (->TaskStateMachine recover-idx iteration-idx batch-idx (alength arr) names arr
                         (int 0) false false replica messenger coordinator
                         pipeline event event (c/event->windows-states event) nil)))


Add better warning when handling exception

--- src/onyx/peer/task_lifecycle.clj
+++ src/onyx/peer/task_lifecycle.clj
@@ -520,7 +520,7 @@
           (:onyx.core/triggers event)))

 (defn handle-exception [log restart-pred-fn e restart-ch outbox-ch job-id]
-  (warn e)
+  (warn e "task-lifecycle: handle-exception")
   (if (restart-pred-fn e)
     (>!! restart-ch true)
     (let [entry (entry/create-log-entry :kill-job {:job job-id})]


Add abstraction: Synchronous websocket calls

--- src/org/timmc/heim_logger/v2.clj
+++ src/org/timmc/heim_logger/v2.clj
@@ -2,7 +2,9 @@
   "Version 2 of logger."
   (:require [cheshire.core :as json]
             [gniazdo.core :as ws]
-            [org.timmc.heim-logger.common :as cm]))
+            [org.timmc.heim-logger.common :as cm])
+  (:import (clojure.lang ExceptionInfo)
+           (java.util.concurrent.atomic AtomicLong)))

 (defn ssocket
   "Get the socket from a session."
@@ -15,6 +17,73 @@
   (ws/send-msg (ssocket session)
                (json/generate-string {:type (name ptype)
                                       :data pdata})))
+
+(def blocking-call-timeout-ms
+  "How many milliseconds to wait, maximum, on a blocking call."
+  5000)
+
+(defn now<-call-command-blocking-start
+  "Redefable time lookup."
+  []
+  (System/currentTimeMillis))
+
+(defn call-command-blocking
+  "Send a command to the heim server and block on a reply.
+
+Yield a response object or throw an exception-info with the following
+fields:
+
+- `:source` with constant `:call-command-blocking-receive`
+- `:type` with either `:timeout` for receive timeout or `:unexpected`
+  for an unknown exception
+- `:packet-id` with the ID string of the packet that was
+  sent (possibly useful if logging all Rx and Tx packets."
+  [session ptype pdata]
+  (let [packet-id ((:gen-unique-id @session))
+        recv-promise (promise)]
+    ;; Register a blocking request *before* sending it to avoid race
+    ;; conditions.
+    (swap! session assoc-in [:blocking-calls packet-id]
+           ;; Recorded start time may overestimate length of call.
+           {:start (now<-call-command-blocking-start)
+            :result recv-promise})
+    ;; Now send! We'll use the ID to find the response.
+    (ws/send-msg (ssocket session)
+                 (json/generate-string {:type (name ptype)
+                                        :data pdata
+                                        :id packet-id}))
+    ;; Wait for results. Timeout may underestimate length of call.
+    (try
+      (let [response (deref recv-promise
+                            blocking-call-timeout-ms ::timeout)]
+        ;; Convert timeout-val into exception for consistency
+        (if (= response ::timeout)
+          (throw (ex-info "Timed out while waiting for blocking call response."
+                          {:type :timeout
+                           :source :call-command-blocking-receive
+                           :packet-id packet-id}))
+          response))
+      (catch ExceptionInfo ei
+        ;; Exclude EIs from the general Exception clause
+        (throw ei))
+      (catch Exception e
+        (throw (ex-info (str "Unexpected exception while "
+                             "receiving result from blocking call")
+                        {:type :unexpected
+                         :source :call-command-blocking-receive
+                         :packet-id packet-id}
+                        e)))
+      (finally ;; Make sure to clean up either way.
+        (swap! session update-in [:blocking-calls]
+               dissoc packet-id)))))
+
+(defn maybe-deliver-blocking-call-result
+  "If the message is a response to a blocking call, deliver it."
+  [session msg]
+  (when-let [recv-id (:id msg)]
+    (when-let [blocked-promise (get-in @session
+                                       [:blocking-calls recv-id :result])]
+      (deliver blocked-promise msg))))

 (defn on-connect
   [session _jetty-ws-session]
@@ -29,6 +98,7 @@
                 (throw t)))
         mtype (:type msg)
         data (:data msg)]
+    (maybe-deliver-blocking-call-result session msg)
     (when-let [error (:error msg)]
       (println "ERROR" msg))
     (case mtype
@@ -56,7 +126,14 @@
 (defn connect
   "Connect to a room and yield a session."
   [room]
-  (let [session (atom {:socket (promise)})
+  (let [id-counter (AtomicLong.)
+        session (atom { ;; Promise of an implementation-defined
+                       ;; "socket" object we can send to or close.
+                       :socket (promise)
+                       ;; AtomicLong, source of unique IDs for packets.
+                       :gen-unique-id #(str (.getAndIncrement id-counter))
+                       ;; Registry of in-flight blocking calls, by packet-id.
+                       :blocking-calls {}})
         socket (ws/connect
                 (cm/address "euphoria.io" room)
                 ;; Var indirection should allow code reloading during a session.


Hacking on exec-repl.

Hacking on exec-repl.

--- src/datomish/exec_repl.cljc
+++ src/datomish/exec_repl.cljc
@@ -9,6 +9,7 @@
       [datomish.pair-chan :refer [go-pair <?]]
       [cljs.core.async.macros :refer [go]]))
   (:require
+     [datomish.db-factory]
      [datomish.db :as db]
      [datomish.sqlite :as s]
      [datomish.sqlite-schema :as ss]
@@ -44,7 +45,7 @@
 #_
 (defn xxopen []
     (datomish.pair-chan/go-pair
-      (let [d (datomish.pair-chan/<? (s/<sqlite-connection "/tmp/foo.sqlite"))]
+      (let [d (datomish.pair-chan/<? (s/<sqlite-connection "/tmp/import.sqlite"))]
         (clojure.core.async/<!! (ss/<ensure-current-version d))
         (def db d))))

@@ -59,19 +60,26 @@
       "/tmp/foo.sqlite"
       '[:find ?page :in $ :where [?page :page/starred true ?t]]))

+#_(require 'datomish.exec-repl)
+#_(in-ns 'datomish.exec-repl)
 #_
 (go-pair
-  (let [connection (<? (s/<sqlite-connection "/tmp/foo.sqlite"))
-        d (<? (db/<with-sqlite-connection connection))]
-    (println
-      "Result: "
-      (<! (db/<?q d '[:find ?page :in $ :where [?page :page/starred true ?t]] {})))))
+  (let [connection (<? (s/<sqlite-connection "/tmp/bigport.db"))
+        d (<? (datomish.db-factory/<db-with-sqlite-connection connection))]
+    (def db d)))
+
+#_
+(go-pair
+  (println (count (first (time
+    (<! (db/<?q db
+                '[:find ?url ?title :in $ :where
+                  [?page :page/visitAt ?v] [(> ?v 1438748166567751)] [?page :page/title ?title] [?page :page/url ?url] ] {})))))))

 #_
 (go-pair
   (let [connection (<? (s/<sqlite-connection "/tmp/foo.sqlite"))
-        dd (<? (db/<with-sqlite-connection connection))]
+        dd (<? (datomish.db-factory/<db-with-sqlite-connection connection))]
     (def *db* dd)))
 #_
 (clojure.core.async/<!!


figwheel.main: background builds

figwheel.main: background builds

--- figwheel-main/src/figwheel/main.clj
+++ figwheel-main/src/figwheel/main.clj
@@ -28,36 +28,52 @@
 ;; config :reload-clj-files false
 ;; :reload-clj-files {:clj true :cljc false}

+;; simple protection against printing the compiler env
+(defrecord WatchInfo [id paths options compiler-env reload-config])
+(defmethod print-method WatchInfo [wi ^java.io.Writer writer]
+  (.write writer (pr-str
+                  (cond-> (merge {} wi)
+                    (:compiler-env wi) (assoc :compiler-env 'compiler-env...)))))
+
 (defn watch-build [id inputs opts cenv & [reload-config]]
   (when-let [inputs (if (coll? inputs) inputs [inputs])]
-    (fww/add-watch! id
-                {:paths inputs
-                 :filter (fww/suffix-filter (into #{"cljs" "js"}
-                                              (cond
-                                                (coll? (:reload-clj-files reload-config))
-                                                (mapv name (:reload-clj-files reload-config))
-                                                (false? (:reload-clj-files reload-config)) []
-                                                :else ["clj" "cljc"])))
-                 :handler (fww/throttle
-                           50
-                           (fn [evts]
-                             (binding [cljs.env/*compiler* cenv]
-                               (let [files (mapv (comp #(.getCanonicalPath %) :file) evts)
-                                     inputs (if (coll? inputs) (apply bapi/inputs inputs) inputs)]
-                                 (try
-                                   (when-let [clj-files
-                                              (not-empty
-                                               (filter
-                                                #(or (.endsWith % ".clj")
-                                                     (.endsWith % ".cljc"))
-                                                files))]
-                                     (figwheel.core/reload-clj-files clj-files))
-                                   (figwheel.core/build inputs opts cenv files)
-                                   (catch Throwable t
-                                     #_(clojure.pprint/pprint
-                                        (Throwable->map t))
-                                     (figwheel.core/notify-on-exception cenv t {})
-                                     false))))))})))
+    (fww/add-watch!
+     id
+     (merge
+      {::watch-info (merge
+                     (:extra-info reload-config)
+                     {:id id
+                      :paths inputs
+                      :options opts
+                      :compiler-env cenv
+                      :reload-config reload-config})}
+      {:paths inputs
+       :filter (fww/suffix-filter (into #{"cljs" "js"}
+                                        (cond
+                                          (coll? (:reload-clj-files reload-config))
+                                          (mapv name (:reload-clj-files reload-config))
+                                          (false? (:reload-clj-files reload-config)) []
+                                          :else ["clj" "cljc"])))
+       :handler (fww/throttle
+                 50
+                 (fn [evts]
+                   (binding [cljs.env/*compiler* cenv]
+                     (let [files (mapv (comp #(.getCanonicalPath %) :file) evts)
+                           inputs (if (coll? inputs) (apply bapi/inputs inputs) inputs)]
+                       (try
+                         (when-let [clj-files
+                                    (not-empty
+                                     (filter
+                                      #(or (.endsWith % ".clj")
+                                           (.endsWith % ".cljc"))
+                                      files))]
+                           (figwheel.core/reload-clj-files clj-files))
+                         (figwheel.core/build inputs opts cenv files)
+                         (catch Throwable t
+                           #_(clojure.pprint/pprint
+                              (Throwable->map t))
+                           (figwheel.core/notify-on-exception cenv t {})
+                           false))))))}))))

 (def validate-config!
   (if (try
@@ -143,6 +159,12 @@
 (defn build-once-opt [cfg bn]
   (let [cfg (build-opt cfg bn)]
     (assoc-in cfg [::config :mode] :build-once)))
+
+(defn background-build-opt [cfg bn]
+  (let [{:keys [options ::build]} (build-opt {} bn)]
+    (update cfg ::background-builds
+            (fnil conj [])
+            (assoc build :options options))))

 (def figwheel-commands
   {:init {["-w" "--watch"]
@@ -163,7 +185,11 @@
           ["-bo" "--build-once"]
           {:group :cljs.cli/compile :fn build-once-opt
            :arg "build-name"
-           :doc (str "The name of a build config to build once.")}}})
+           :doc (str "The name of a build config to build once.")}
+          ["-bb" "--background-build"]
+          {:group :cljs.cli/compile :fn background-build-opt
+           :arg "build-name"
+           :doc (str "The name of a build config to watch and build in the background.")}}})

 ;; ----------------------------------------------------------------------------
 ;; Config
@@ -211,13 +237,6 @@
     (let [config-edn (process-figwheel-main-edn
                       (fetch-figwheel-main-edn cfg))]
       (-> cfg
-          (update :repl-env-options
-                  merge (select-keys config-edn
-                                     [:ring-server
-                                      :ring-server-options
-                                      :ring-stack
-                                      :ring-stack-options
-                                      :ring-handler]))
           (update ::config merge config-edn)))))

 (defn- config-merge-current-build-conf [{:keys [::extra-config ::build] :as cfg}]
@@ -226,13 +245,16 @@
                      (merge-with (fn [a b] (if b b a)) % (:config build))
                      extra-config)))

-;; targets local config
-(defn- config-repl-serve? [{:keys [ns args] :as cfg}]
-  (let [rfs      #{"-r" "--repl"}
-        sfs      #{"-s" "--serve"}]
-    (cond-> cfg
-      (boolean (or (rfs ns) (rfs (first args)))) (assoc-in [::config :mode] :repl)
-      (boolean (or (sfs ns) (sfs (first args)))) (assoc-in [::config :mode] :serve))))
+(defn host-port-arg? [arg]
+  (and arg (re-matches #"(.*):(\d*)" arg)))
+
+(defn update-server-host-port [config [f address-port & args]]
+  (if (and (#{"-s" "--serve"} f) address-port)
+    (let [[_ host port] (host-port-arg? address-port)]
+      (cond-> config
+        (not (string/blank? host)) (assoc-in [:ring-server-options :host] host)
+        (not (string/blank? port)) (assoc-in [:ring-server-options :port] (Integer/parseInt port))))
+    config))

 ;; targets options
 (defn- config-main-ns [{:keys [ns options] :as cfg}]
@@ -242,6 +264,24 @@
     (cond-> cfg
       main-ns (assoc :ns main-ns)       ;; TODO not needed?
       main-ns (assoc-in [:options :main] main-ns))))
+
+;; targets local config
+(defn- config-repl-serve? [{:keys [ns args] :as cfg}]
+  (let [rfs      #{"-r" "--repl"}
+        sfs      #{"-s" "--serve"}]
+    (cond-> cfg
+      (boolean (or (rfs ns) (rfs (first args))))
+      (assoc-in [::config :mode] :repl)
+      (boolean (or (sfs ns) (sfs (first args))))
+      (->
+       (assoc-in [::config :mode] :serve)
+       (update ::config update-server-host-port args))
+      (rfs (first args))
+      (update :args rest)
+      (sfs (first args))
+      (update :args rest)
+      (and (sfs (first args)) (host-port-arg? (second args)))
+      (update :args rest))))

 ;; targets local config
 (defn- config-update-watch-dirs [{:keys [options ::config] :as cfg}]
@@ -361,8 +401,8 @@
 #_(add-to-query "ws://localhost:9500/figwheel-connect?hey=5" {:ab 'ab})

 (defn config-connect-url [{:keys [::config repl-env-options] :as cfg} connect-id]
-  (let [port (get-in repl-env-options [:ring-server-options :port] figwheel.repl/default-port)
-        host (get-in repl-env-options [:ring-server-options :host] "localhost")
+  (let [port (get-in config [:ring-server-options :port] figwheel.repl/default-port)
+        host (get-in config [:ring-server-options :host] "localhost")
         connect-url
         (fill-connect-url-template
          (:connect-url config "ws://[[config-hostname]]:[[server-port]]/figwheel-connect")
@@ -419,6 +459,35 @@
                'figwheel.repl/print-output
                (string/join "," (distinct (map name (:client-print-to config)))))))

+(defn get-repl-options [{:keys [options args inits repl-options] :as cfg}]
+  (assoc (merge (dissoc options :main)
+                repl-options)
+         :inits
+         (into
+          [{:type :init-forms
+            :forms (when-not (empty? args)
+                     [`(set! *command-line-args* (list ~@args))])}]
+          inits)))
+
+(defn get-repl-env-options [{:keys [repl-env-options ::config] :as cfg}]
+  (let [repl-options (get-repl-options cfg)]
+    (merge
+     (select-keys config
+                  [:ring-server
+                   :ring-server-options
+                   :ring-stack
+                   :ring-stack-options
+                   :ring-handler])
+     repl-env-options ;; from command line
+     (select-keys repl-options [:output-to :output-dir]))))
+
+(defn config-finalize-repl-options [cfg]
+  (let [repl-options (get-repl-options cfg)
+        repl-env-options (get-repl-env-options cfg)]
+    (assoc cfg
+           :repl-options repl-options
+           :repl-env-options repl-env-options)))
+
 #_(config-connect-url {::build-name "dev"})

 (defn update-config [cfg]
@@ -436,23 +505,8 @@
        config-client-print-to
        config-open-file-command
        config-watch-css
+       config-finalize-repl-options
        config-clean))
-
-(defn get-repl-options [{:keys [options args inits repl-options] :as cfg}]
-  (assoc (merge (dissoc options :main)
-                repl-options)
-         :inits
-         (into
-          [{:type :init-forms
-            :forms (when-not (empty? args)
-                     [`(set! *command-line-args* (list ~@args))])}]
-          inits)))
-
-(defn get-repl-env-options [{:keys [repl-env-options] :as cfg}]
-  (let [repl-options (get-repl-options cfg)]
-    (merge
-     repl-env-options
-     (select-keys repl-options [:output-to :output-dir]))))

 ;; ----------------------------------------------------------------------------
 ;; Main action
@@ -493,13 +547,30 @@
   (when-let [server (and join? @(:server repl-env))]
     (.join server)))

-(defn update-server-host-port [repl-env [f address-port & args]]
-  (if (and (#{"-s" "--serve"} f) address-port)
-    (let [[_ host port] (re-matches #"(.*):(\d*)" address-port)]
-      (cond-> repl-env
-        (not (string/blank? host)) (assoc-in [:ring-server-options :host] host)
-        (not (string/blank? port)) (assoc-in [:ring-server-options :port] (Integer/parseInt port))))
-    repl-env))
+(defn background-build [cfg {:keys [id config options]}]
+  (let [{:keys [::build ::config repl-env-options] :as cfg}
+        (-> (select-keys cfg [::start-figwheel-options])
+            (assoc :options options
+                   ::build {:id id :config config})
+            update-config)
+        cenv (cljs.env/default-compiler-env)]
+    (println "Figwheel: Starting background autobuild for build: " (:id build))
+    (binding [cljs.env/*compiler* cenv]
+      (bapi/build (apply bapi/inputs (:watch-dirs config)) (:options cfg) cenv)
+      (watch-build (:id build)
+                   (:watch-dirs config)
+                   (:options cfg)
+                   cenv
+                   (select-keys config [:reload-clj-files]))
+      (when (figwheel-mode? cfg)
+        (binding [cljs.repl/*repl-env* (figwheel.repl/repl-env*
+                                        (select-keys repl-env-options
+                                                     [:connection-filter]))]
+          (figwheel.core/start*))))))
+
+(defn start-background-builds [{:keys [::background-builds] :as cfg}]
+  (doseq [build background-builds]
+    (background-build cfg build)))

 ;; TODO what happens to inits like --init and --eval in all cases

@@ -507,29 +578,30 @@
 ;; takes the correct config
 ;; and make an adapter function that produces the correct args for this fn
 (defn default-compile [repl-env-fn cfg]
-  (let [{:keys [ns args options repl-env-options ::config] :as cfg} (update-config cfg)
+  (let [{:keys [options repl-options repl-env-options ::config] :as b-cfg} (update-config cfg)
         {:keys [mode pprint-config]} config
-        repl-env (apply repl-env-fn (mapcat identity (get-repl-env-options cfg)))
+        repl-env (apply repl-env-fn (mapcat identity repl-env-options))
         cenv (cljs.env/default-compiler-env)]
     (cljs.env/with-compiler-env cenv
       (if pprint-config
-        (do (clojure.pprint/pprint cfg) cfg)
+        (do (clojure.pprint/pprint b-cfg) b-cfg)
         (binding [cljs.repl/*repl-env* repl-env]
-          (let [fw-mode? (figwheel-mode? cfg)]
+          (let [fw-mode? (figwheel-mode? b-cfg)]
             (build config options cenv)
             (when-not (= mode :build-once)
-              (doseq [init-fn (::initializers cfg)] (init-fn))
+              (start-background-builds cfg)
+              (doseq [init-fn (::initializers b-cfg)] (init-fn))
               (cond
                 (= mode :repl)
                 ;; this forwards command line args
-                (repl repl-env (get-repl-options cfg))
+                (repl repl-env repl-options)
                 (or (= mode :serve) fw-mode?)
                 ;; we need to get the server host:port args
-                (serve {:repl-env (update-server-host-port repl-env args)
-                        :repl-options (get-repl-options cfg)
+                (serve {:repl-env repl-env
+                        :repl-options repl-options
                         ;; TODO need to iterate through the inits
                         :eval-str (when fw-mode? (start-figwheel-code config))
-                        :join? (get cfg ::join-server? true)})))))))))
+                        :join? (get b-cfg ::join-server? true)})))))))))

 (defn start [{:keys [figwheel-options build join-server?]}]
   (let [[build-id build-options] (if (map? build)
@@ -638,7 +710,7 @@
           (println (.getMessage e))
           (throw e))))))

-(def args
+#_(def test-args
   (concat ["-co" "{:aot-cache false :asset-path \"out\"}" "-b" "dev" "-e" "(figwheel.core/start-from-repl)"]
           (string/split "-w src -d target/public/out -o target/public/out/mainer.js -c exproj.core -r" #"\s")))


moved some code around in an attempt to fix a race condition

--- src/server/client-interface.cljs
+++ src/server/client-interface.cljs
@@ -408,9 +408,6 @@
                                                                         (clj->js %1)))
                             (.unpipe stream)
                             (.unlink fs temp-absolute-file-path))))
-                    (println (str "Saving" original-filename "as" temp-absolute-file-path))
-                    (.pipe stream (.createWriteStream fs temp-absolute-file-path #js {:start start
-                                                                                :flags "a"}))

                   (.on stream "data"
                     (fn [data-chunk]
@@ -427,12 +424,8 @@
                                         :filename      original-filename}))))))

                   (.on stream "end"
-                    (fn []
-                      (println "Upload of" original-filename
-                               "from" (.-id socket) "is complete!")
-                      (rooms/upload-complete room file-id #(.emit (.to io room)
-                                                                  "new-uploads-order"
-                                                                  (clj->js %1)))
+                    (fn [] (println "Upload of" original-filename "from" (.-id socket) "is complete!")
+                      (rooms/upload-complete room file-id #(.emit (.to io room) "new-uploads-order" (clj->js %1)))
                       (redis-lock. room
                         (fn [done]
                           (let [magic (Magic. (.-MAGIC_MIME_TYPE mmm))]
@@ -472,7 +465,11 @@
                                                             (rooms/get-num-of-tracks room
                                                               (fn [num-of-tracks]
                                                                 (change-track room (- num-of-tracks 1) (.v4 js-uuid))))))))))
-                                                (done))))))))))))))))))))))))))))
+                                                (done))))))))))))))))))
+
+                  (println (str "Saving" original-filename "as" temp-absolute-file-path))
+                  (.pipe stream (.createWriteStream fs temp-absolute-file-path #js {:start start
+                                                                                :flags "a"}))))))))))))

 (defn start-listening! []
   (.on io "connection" connection))


Rework deflayout to take destructuing vector.

--- src/incise/layouts/html.clj
+++ src/incise/layouts/html.clj
@@ -9,30 +9,28 @@

 (defmacro deflayout
   "This is a helper macro for defining html layout functions. An html layout
-   function at its core is just a function which takes two arguments:
+  function at its core is just a function which takes two arguments:

-     site-options - Global options for the site from incise.edn
-     parse        - An instance of Parse containing keys such as content and
-                    title
+    site-options - Global options for the site from incise.edn
+    parse        - An instance of Parse containing keys such as content and
+                   title

-   This macro makes it just a little bit easier to define such functions by
-   taking care of some boiler plate stuff like using the robert.hooke with-scope
-   macro and binind the functions arguments to *site-options* and *parse* so
-   partials can easily access them."
-  [sym-name doc-string? & body]
-  (let [[doc-string body]
+  This macro makes it just a little bit easier to define such functions by
+  taking care of some boiler plate stuff like using the robert.hooke with-scope
+  macro and binind the functions arguments to *site-options* and *parse* so
+  partials can easily access them."
+  [sym-name doc-string? destructuring & body]
+  (let [[doc-string destructuring]
         (if (string? doc-string?)
-          [doc-string? body]
-          ["" (conj body doc-string?)])]
+          [doc-string? destructuring]
+          ["" doc-string?])]
     `(defn ~sym-name
        ~doc-string
-       [{:keys [~'site-title ~'author ~'contacts]
-         :as ~'site-options}
-        ^incise.parsers.core.Parse
-        {:keys [~'date ~'tags ~'category ~'title ~'content] :as ~'parse}]
-       (binding [*site-options* ~'site-options
-                 *parse* ~'parse]
-           (with-scope (html5 ~@body))))))
+       [site-options# ^incise.parsers.core.Parse parse#]
+       (binding [*site-options* site-options#
+                 *parse* parse#]
+         (let [~destructuring [*site-options* *parse*]]
+           (with-scope (html5 ~@body)))))))

 (defmacro defpartial
   "Defines a 'partial' which is baically some hiccup markup. An arguments vector


CMR-4562: update metadata preview gem (#356)

* CMR-4562: update metadata preview gem

--- collection-renderer-lib/project.clj
+++ collection-renderer-lib/project.clj
@@ -14,7 +14,7 @@
    the hardcoded commit id during dev integration with cmr_metadata_preview project.
    The hardcoded commit id should be updated when MMT releases a new version of the gem."
   (or (System/getenv "CMR_METADATA_PREVIEW_COMMIT")
-      "c84bf83"))
+      "328ab9bcc41"))

 (def gem-install-path
   "The directory within this library where Ruby gems are installed."


Improve grid styles.

Improve grid styles.

--- src/uxbox/ui/workspace/grid.cljs
+++ src/uxbox/ui/workspace/grid.cljs
@@ -46,7 +46,7 @@
                               :x2 position
                               :stroke grid-color
                               :stroke-width (/ 0.5 zoom)
-                              :opacity 0.25}])))
+                              :opacity 0.50}])))
             (horizontal-line [position value]
               (if (< (mod value ticks-mod) step-size-y)
                 (html [:line {:key position


update and read remotes

update and read remotes

--- src/wishlistd/views/wishlist.clj
+++ src/wishlistd/views/wishlist.clj
@@ -19,4 +19,10 @@
   (response/json (model/update-wishlist wishlist)))

 (defremote create-wishlist [wishlist]
-  (model/create-wishlist wishlist))+  (model/create-wishlist wishlist))
+
+(defremote update-wishlist [wishlist]
+  (model/update-wishlist wishlist))
+
+(defremote read-wishlist [code]
+  (model/read-wishlist code))


- Transferring java objects from Ooze Engine to Pixel Perversion Engine

- Prototyping update for scenes within scenes.

--- src/pixel_perversion_engine/scene/scene.clj
+++ src/pixel_perversion_engine/scene/scene.clj
@@ -3,7 +3,8 @@
 (def scene {:counter 0
             :entities {}
             :processors []
-            :messages []})
+            :messages []
+            :scenes []})

 (defn send-message
   ([scene message]
@@ -92,4 +93,14 @@
   [scene]
   (swap! scene (fn [s] (-> s
                            apply-processors-to-entities
-                           apply-messages))))+                           apply-messages))))
+
+(defn kek
+  [scene]
+  (if (seq (:scene scene))
+    (assoc
+      (update-in scene
+                 [:v]
+                 (fn [v] (* 10 v)))
+      :scene (vec (for [s (:scene scene)] (kek s))))
+    (update-in scene [:v] (fn [v] (* 10 v)))))


Save/load for specularPower

Save/load for specularPower

--- yaw/yaw/world.clj
+++ yaw/yaw/world.clj
@@ -373,7 +373,7 @@
 			 	;; Representation of spotLights as a Clojure vector
 			 	spotLightVector (createSpotLightVector (vec (.getSpotTable sceneLight)))
 		 	]
-		(vector ambiantVector sunVector pointLightVector spotLightVector)
+		(vector (.specularPower sceneLight) ambiantVector sunVector pointLightVector spotLightVector)
 	))

 (defn saveFile [filename world]
@@ -522,10 +522,11 @@
 (defn loadLights [loadedLights world]
 	"Loads all lights from an EDN vector created with saveLights."
 	(let [sceneLight (.getSceneLight world)]
-		(.setAmbiant sceneLight (ednToObject (get loadedLights 0)))
-		(.setSun sceneLight (ednToObject (get loadedLights 1)))
-		(addPointLights (lazy-seq (get loadedLights 2)) sceneLight 0)
-		(addSpotLights (lazy-seq (get loadedLights 3)) sceneLight 0)
+		(set! (.specularPower sceneLight) (get loadedLights 0))
+		(.setAmbiant sceneLight (ednToObject (get loadedLights 1)))
+		(.setSun sceneLight (ednToObject (get loadedLights 2)))
+		(addPointLights (lazy-seq (get loadedLights 3)) sceneLight 0)
+		(addSpotLights (lazy-seq (get loadedLights 4)) sceneLight 0)
 	))

 (defn loadFile [filename world]


remove unneeded images

remove unneeded images

--- frontend/components/language_landing.cljs
+++ frontend/components/language_landing.cljs
@@ -23,9 +23,6 @@
 (def templates {"ruby" {:language "Ruby"
                         :headline "CircleCI makes Continous Integration and Deployment for Ruby projects a breeze."
                         :logo-path (utils/cdn-path "/img/outer/languages/ruby-logo.svg")
-                        :ss-1 "/assets/img/outer/languages/ruby-ss-1.png"
-                        :ss-2 "/assets/img/outer/languages/ruby-ss-1.png"
-                        :ss-3 "/assets/img/outer/languages/ruby-ss-1.png"
                         :features [{:feature "CircleCI uses RVM to provide support for a wide variety of Ruby versions and gems. It is also trivial to add any packages or frameworks that are not installed on our machines by default, allowing you to effortlessly customize your test enviroment.  CircleCI also supports Test::Unit, RSpec, Cucumber, Spinach, Jasmine, Konacha, and just about any other testing framework you use for your Ruby project."
                                     :title "Built For Ruby"
                                     :icon (utils/cdn-path "/img/outer/languages/gear-icon.svg")}


minor syntax fix

minor syntax fix

--- test/clj/salava/user/db_test.clj
+++ test/clj/salava/user/db_test.clj
@@ -78,7 +78,7 @@

       (testing " check can login with user"
         (let [emails (db/email-addresses ctx (:id registered-user))]
-          (is (= "deleted-test.registration@example.com.so.deleted"  (get-in (first emails) [:email] )))))
+          (is (= "deleted-test.registration@example.com.so.deleted" (:email (first emails))))))

       ))


rename test

rename test

--- test/clj_kafka/test/consumer.clj
+++ test/clj_kafka/test/consumer.clj
@@ -10,7 +10,7 @@
 ;; Figure out why zk/messages can return the iterator sequence but
 ;; can't map the contents for us. Instead, use to-clojure directly
 ;; here for now
-(deftest test-sending-string-message
+(deftest test-zookeeper-consumption
   (with-broker
     (let [p (producer {"metadata.broker.list" "localhost:9999"
                        "serializer.class" "kafka.serializer.DefaultEncoder"


Upgrade lein-cljsbuild.

Upgrade lein-cljsbuild.

--- .lein/profiles.clj
+++ .lein/profiles.clj
@@ -6,14 +6,14 @@
                        [spyscope "0.1.3"]
                        [slamhound "1.3.3"]]
         :plugins [[lein-difftest "1.3.7"]
-                  [lein-drip "0.1.1-SNAPSHOT"]
                   [lein-exec "0.3.0"]
                   [lein-clojars "0.9.1"]
                   [lein-pprint "1.1.1"]
                   [lein-ring "0.8.0"]
-                  [lein-cljsbuild "0.1.9"]
+                  [lein-cljsbuild "0.3.2"]
                   [lein-deps-tree "0.1.2"]
                   [lein-marginalia "0.7.1"]]
+        :hooks [leiningen.cljsbuild]
         :repl-options {:timeout 120000}
         :injections [(require '[redl core complete])
                      (require 'spyscope.core)


add unit tests for adding and removing items

--- test/clj_money/models/transactions_test.clj
+++ test/clj_money/models/transactions_test.clj
@@ -755,7 +755,121 @@
              (:balance (accounts/reload storage-spec checking)))
           "Checking should have the correct balance after update"))))

-; update a transaction
-
-; add a transaction item
-; remove a transaction item
+(def add-remove-item-context
+  {:users [(factory :user, {:email "john@doe.com"})]
+   :entities [{:name "Personal"}]
+   :accounts [{:name "Checking"
+               :type :asset}
+              {:name "Salary"
+               :type :income}
+              {:name "Pets"
+               :type :expense}
+              {:name "Groceries"
+               :type :expense}]
+   :transactions [{:transaction-date (t/local-date 2016 3 2)
+                   :entity-id "Personal"
+                   :items [{:action :debit
+                            :account-id "Checking"
+                            :amount 1000}
+                           {:action :credit
+                            :account-id "Salary"
+                            :amount 1000}]}
+                  {:transaction-date (t/local-date 2016 3 9)
+                   :entity-id "Personal"
+                   :items [{:action :debit
+                            :account-id "Groceries"
+                            :amount 103}
+                           {:action :credit
+                            :account-id "Checking"
+                            :amount 103}]}
+                  {:transaction-date (t/local-date 2016 3 16)
+                   :entity-id "Personal"
+                   :items [{:action :debit
+                            :account-id "Groceries"
+                            :amount 90}
+                           {:action :debit
+                            :account-id "Pets"
+                            :amount 12}
+                           {:action :credit
+                            :account-id "Checking"
+                            :amount 102}]}
+                  {:transaction-date (t/local-date 2016 3 23)
+                   :entity-id "Personal"
+                   :items [{:action :debit
+                            :account-id "Groceries"
+                            :amount 101}
+                           {:action :credit
+                            :account-id "Checking"
+                            :amount 101}]}]})
+
+(deftest update-a-transaction-remove-item
+  (let [context (serialization/realize storage-spec add-remove-item-context)
+        [checking
+         salary
+         pets
+         groceries] (:accounts context)
+        [t1 t2 t3 t4] (:transactions context)
+        to-update (-> t3
+                      (assoc-in [:items 0 :amount] (bigdec 102))
+                      (update-in [:items] #(remove (fn [item]
+                                                     (= (:account-id item)
+                                                        (:id pets)))
+                                                   %)))
+        updated (transactions/update storage-spec to-update)
+        expected-items [{:index 2
+                         :amount (bigdec 101)
+                         :balance (bigdec 306)}
+                        {:index 1
+                         :amount (bigdec 102)
+                         :balance (bigdec 205)}
+                        {:index 0
+                         :amount (bigdec 103)
+                         :balance (bigdec 103)}]
+        actual-items (map #(select-keys % [:index :amount :balance])
+                          (transactions/items-by-account storage-spec (:id groceries)))]
+    (testing "item values are correct"
+      (is (= expected-items actual-items "The Pets account should have the correct items")))
+    (testing "account balances are correct"
+      (is (= (bigdec 0)
+             (:balance (accounts/reload storage-spec pets)))
+          "Pets should have the correct balance after update")
+      (is (= (bigdec 306)
+             (:balance (accounts/reload storage-spec groceries)))
+          "Groceries should have the correct balance after update")
+      (is (= (bigdec 694)
+             (:balance (accounts/reload storage-spec checking)))
+          "Checking should have the correct balance after update"))))
+
+(deftest update-a-transaction-add-item
+  (let [context (serialization/realize storage-spec add-remove-item-context)
+        [checking
+         salary
+         pets
+         groceries] (:accounts context)
+        [t1 t2 t3 t4] (:transactions context)
+        to-update (-> t2
+                      (assoc-in [:items 0 :amount] (bigdec 90))
+                      (update-in [:items] #(conj % {:action :debit
+                                                    :account-id (:id pets)
+                                                    :amount (bigdec 13)})))
+        updated (transactions/update storage-spec to-update)
+        expected-items [{:index 1
+                         :amount (bigdec 12)
+                         :balance (bigdec 25)}
+                        {:index 0
+                         :amount (bigdec 13)
+                         :balance (bigdec 13)}]
+        actual-items (map #(select-keys % [:index :amount :balance])
+                          (transactions/items-by-account storage-spec (:id pets)))]
+    (testing "item values are correct"
+      (is (= expected-items actual-items "The Pets account should have the correct items")))
+    (testing "account balances are correct"
+      (is (= (bigdec 25)
+             (:balance (accounts/reload storage-spec pets)))
+          "Pets should have the correct balance after update")
+      (is (= (bigdec 281)
+             (:balance (accounts/reload storage-spec groceries)))
+          "Groceries should have the correct balance after update")
+      (is (= (bigdec 694)
+             (:balance (accounts/reload storage-spec checking)))
+          "Checking should have the correct balance after update"))))


add more keyword completion candidates

add more keyword completion candidates

--- planck-cljs/src/planck/repl.cljs
+++ planck-cljs/src/planck/repl.cljs
@@ -449,6 +449,7 @@
 (def ^:private keyword-completions
   [:require :require-macros :import
    :refer :refer-macros :include-macros
+   :refer-clojure :exclude
    :keys :strs :syms
    :as :or
    :pre :post


Keep st and *loaded* in sync when rolling back

Fixes #359

--- planck-cljs/src/planck/repl.cljs
+++ planck-cljs/src/planck/repl.cljs
@@ -383,9 +383,19 @@
       "via ns:\n  "
       (pr-str ns-form))))

+(defn- compiler-state-memo
+  []
+  {:st     @st
+   :loaded @cljs/*loaded*})
+
+(defn- restore-compiler-state
+  [memo]
+  (reset! st (:st memo))
+  (reset! cljs/*loaded* (:loaded memo)))
+
 (defn- process-require
   [kind cb specs]
-  (let [current-st @st]
+  (let [memo (compiler-state-memo)]
     (try
       (let [is-self-require? (and (= :kind :require) (self-require? specs))
             [target-ns restore-ns]
@@ -403,11 +413,11 @@
               (reset! current-ns restore-ns))
             (when e
               (handle-error e false)
-              (reset! st current-st))
+              (restore-compiler-state memo))
             (cb))))
       (catch :default e
         (handle-error e true)
-        (reset! st current-st)))))
+        (restore-compiler-state memo)))))

 (defn- resolve-var
   "Given an analysis environment resolve a var. Analogous to


CMR-3279 fixes another acl name

CMR-3279 fixes another acl name

--- access-control-app/int_test/cmr/access_control/int_test/acl_search_test.clj
+++ access-control-app/int_test/cmr/access_control/int_test/acl_search_test.clj
@@ -689,8 +689,8 @@
         coll3 (save-access-value-collection "coll3" 10)
         ;; and one with no access value
         coll4 (save-access-value-collection "coll4" nil)
-        acl1 (ingest-acl token (assoc (catalog-item-acl "Access values 1-10")
-                                      :catalog_item_identity {:name "Access values 1-10"
+        acl1 (ingest-acl token (assoc (catalog-item-acl "Access value 1-10")
+                                      :catalog_item_identity {:name "Access value 1-10"
                                                               :collection_applicable true
                                                               :collection_identifier {:access_value {:min_value 1 :max_value 10}}
                                                               :provider_id "PROV1"}))


allow for inline images via `data:`

allow for inline images via `data:`

--- src/metabase/middleware.clj
+++ src/metabase/middleware.clj
@@ -153,7 +153,8 @@
                                                                     "fonts.googleapis.com"]
                                                       :font-src    ["fonts.gstatic.com"
                                                                     "themes.googleusercontent.com"]
-                                                      :img-src     ["*"]
+                                                      :img-src     ["*"
+                                                                    "self data:"]
                                                       :connect-src ["'self'"
                                                                     "metabase.us10.list-manage.com"
                                                                     "*.intercom.io"


linty fix

linty fix

--- src/metabase/util/logic.clj
+++ src/metabase/util/logic.clj
@@ -24,23 +24,23 @@
      (butlast° ?more-half1-butlast ?more-half1-last more-half1))))

 (defn sorted-into°
-  "A relation such that OUT is the list L with V sorted into it doing comparisons with PRED."
-  [pred l v out]
+  "A relation such that OUT is the list L with V sorted into it doing comparisons with PRED-F."
+  [pred-f l v out]
   (matche [l]
     ([[]]           (== out [v]))
     ([[?x . ?more]] (conda
-                     ((pred v ?x) (conso v (lcons ?x ?more) out))
-                     (s#          (fresh [more]
-                                    (sorted-into° pred ?more v more)
-                                    (conso ?x more out)))))))
+                     ((pred-f v ?x) (conso v (lcons ?x ?more) out))
+                     (s#            (fresh [more]
+                                      (sorted-into° pred-f ?more v more)
+                                      (conso ?x more out)))))))

 (defna sorted-permutation°
-  "A relation such that OUT is a permutation of L where all items are sorted by PRED."
-  [pred l out]
+  "A relation such that OUT is a permutation of L where all items are sorted by PRED-F."
+  [pred-f l out]
   ([_ [] []])
   ([_ [?x . ?more] _] (fresh [more]
-                        (sorted-permutation° pred ?more more)
-                        (sorted-into° pred more ?x out))))
+                        (sorted-permutation° pred-f ?more more)
+                        (sorted-into° pred-f more ?x out))))

 (defn matches-seq-order°
   "A relation such that V1 is present and comes before V2 in list L."