figwheel.main: use repl from any directory

--- figwheel-main/src/figwheel/main.cljc
+++ figwheel-main/src/figwheel/main.cljc
@@ -254,18 +254,37 @@
                    (merge (build-once-opt cfg build-name)
                           {:args args})))

-(defn repl-main-opt [repl-env-fn [_ & args] cfg]
-  (default-compile
-   repl-env-fn
-   (-> cfg
-       (assoc :args args)
-       (update :options (fn [opt] (merge {:main 'figwheel.repl.preload} opt)))
-       (assoc-in [:repl-env-options :open-url]
-                 "http://[[server-hostname]]:[[server-port]]/?figwheel-server-force-default-index=true")
-       ;; TODO :default-index-body should be a function that takes the build options as an arg
-       (assoc-in [:repl-env-options :default-index-body] default-main-repl-index-body)
-       (assoc-in [::config :mode] :repl)
-       (assoc-in [::build] {:id "figwheel-default-repl-build"}))))
+(declare default-output-dir default-output-to)
+
+(defn repl-main-opt [repl-env-fn args cfg]
+  (let [target-on-classpath?
+        (when-let [target-dir
+                   (try (:target-dir (read-string (slurp "figwheel-main.edn")) "target")
+                        (catch Throwable t
+                          nil))]
+          (fw-util/dir-on-classpath? target-dir))
+        temp-dir (when-not target-on-classpath?
+                   (let [tempf (java.io.File/createTempFile "figwheel" "repl")]
+                     (.delete tempf)
+                     (.mkdirs tempf)
+                     (.deleteOnExit (io/file tempf))
+                     (fw-util/add-classpath! (.toURL (.toURI tempf)))
+                     tempf))]
+    (default-compile
+     repl-env-fn
+     (-> cfg
+         (cond->
+             temp-dir (assoc-in [:options :output-dir] (default-output-dir temp-dir))
+             temp-dir (assoc-in [:options :output-to]  (default-output-to temp-dir))
+             temp-dir (assoc-in [:options :asset-path]  "cljs-out"))
+         (assoc :args args)
+         (update :options (fn [opt] (merge {:main 'figwheel.repl.preload} opt)))
+         (assoc-in [:repl-env-options :open-url]
+                   "http://[[server-hostname]]:[[server-port]]/?figwheel-server-force-default-index=true")
+         ;; TODO :default-index-body should be a function that takes the build options as an arg
+         (assoc-in [:repl-env-options :default-index-body] default-main-repl-index-body)
+         (assoc-in [::config :mode] :repl)
+         (assoc-in [::build] {:id "figwheel-default-repl-build"})))))

 (declare serve update-config)

@@ -429,31 +448,23 @@
 ;; needs local config
 (defn figwheel-mode? [{:keys [::config options]}]
   (and (:figwheel config true)
-       (not-empty (:watch-dirs config))
+       (or (= :repl (:mode config)) (not-empty (:watch-dirs config)))
        (= :none (:optimizations options :none))))

 ;; TODO this is a no-op right now
 (defn prep-client-config [config]
   (let [cl-config (select-keys config [])]
     cl-config))
-
-(defn start-figwheel-code [config]
-  (let [client-config (prep-client-config config)]
-    (if (not-empty client-config)
-      (str "(figwheel.core/start-from-repl " (pr-str client-config)  ")")
-      "(figwheel.core/start-from-repl)")))

 ;; targets options needs local config
 (defn- config-figwheel-mode? [{:keys [::config options] :as cfg}]
   (cond-> cfg
     ;; check for a main??
     (figwheel-mode? cfg)
-    (->
-     (#'cljs.cli/eval-opt (start-figwheel-code config))
-     (update-in [:options :preloads]
-                (fn [p]
-                  (vec (distinct
-                        (concat p '[figwheel.repl.preload figwheel.core figwheel.main]))))))))
+    (update-in [:options :preloads]
+               (fn [p]
+                 (vec (distinct
+                       (concat p '[figwheel.repl.preload figwheel.core figwheel.main])))))))

 ;; targets options
 ;; TODO needs to consider case where one or the other is specified???
@@ -672,20 +683,20 @@

 (defn build [{:keys [watch-dirs mode ::build] :as config} options cenv]
   (let [source (when (and (= :none (:optimizations options :none)) (:main options))
-                 (:uri (bapi/ns->location (symbol (:main options)))))]
+                 (:uri (bapi/ns->location (symbol (:main options)))))
+        id (:id (::build *config*) "dev")]
     ;; TODO should probably try obtain a watch path from :main here
     ;; if watch-dirs is empty
     (if-let [paths (and (not= mode :build-once) (not-empty watch-dirs))]
       (do
-        (build-cljs (:id build "dev") (apply bapi/inputs paths) options cenv)
-        (watch-build (:id build "dev")
-                     paths options cenv (select-keys config [:reload-clj-files])))
+        (build-cljs id (apply bapi/inputs paths) options cenv)
+        (watch-build id paths options cenv (select-keys config [:reload-clj-files])))
       (cond
         source
-        (build-cljs (:id build "dev") source options cenv)
+        (build-cljs id source options cenv)
         ;; TODO need :compile-paths config param
         (not-empty watch-dirs)
-        (build-cljs (:id build "dev") (apply bapi/inputs watch-dirs) options cenv)))))
+        (build-cljs id (apply bapi/inputs watch-dirs) options cenv)))))

 (defn log-server-start [repl-env]
   (let [host (get-in repl-env [:ring-server-options :host] "localhost")
@@ -747,6 +758,7 @@
                                                false
                                                ansip/*use-color*)]
                    (ansip/format-str (log/format-ex except-data))))
+        #_(clojure.pprint/pprint (Throwable->map err))
         (flush)))))

 ;; TODO this needs to work in nrepl as well
@@ -819,34 +831,29 @@
   (doseq [build background-builds]
     (background-build cfg build)))

-(defn validate-fix-target-classpath! [{:keys [::config options]}]
+(defn validate-fix-target-classpath! [{:keys [::config ::build options]}]
   (when-not (contains? (:ring-stack-options config) :static)
     (when-let [output-to (:output-to options)]
-      (let [parts (fw-util/path-parts output-to)
-            target-dir (first (split-with (complement #{"public"}) parts))]
-        (when-not (empty? target-dir)
-          (let [target-dir (apply io/file target-dir)]
-            (when-not (fw-util/dir-on-classpath? target-dir)
-              (log/warn (ansip/format-str
-                         [:yellow "Target directory " (pr-str (str target-dir))
-                          " is not on the classpath"]))
-              (log/warn "Please fix this by adding" (pr-str (str target-dir))
-                        "to your classpath\n"
-                        "I.E.\n"
-                        "For Clojure CLI Tools\n"
-                        "   ensure " (pr-str (str target-dir))
-                        "is in your :paths key"
-                        "in your deps.edn file\n\n"
-                        "For leiningen:\n"
-                        "   either set your :target key to" (pr-str (str target-dir))
-                        "or add it to the :resource-paths key\n"
-                        "   in your project.clj\n")
-              (log/warn (ansip/format-str [:yellow "Attempting to dynamically add classpath!!"]))
-              (fw-util/add-classpath! (.toURL (.toURI target-dir))))))))))
-
-#_(validate-fix-classpath! {:options {:output-to (default-output-to "targ")}})
-
-#_(io/resource "public/cljs-out/figwheel-default-repl-build-main.js")
+      (when-not (.isAbsolute (io/file output-to))
+        (let [parts (fw-util/path-parts output-to)
+              target-dir (first (split-with (complement #{"public"}) parts))]
+          (when-not (empty? target-dir)
+            (let [target-dir (apply io/file target-dir)]
+              (when-not (fw-util/dir-on-classpath? target-dir)
+                (log/warn (ansip/format-str
+                           [:yellow "Target directory " (pr-str (str target-dir))
+                            " is not on the classpath"]))
+                (log/warn "Please fix this by adding" (pr-str (str target-dir))
+                          "to your classpath\n"
+                          "I.E.\n"
+                          "For Clojure CLI Tools in your deps.edn file:\n"
+                          "   ensure " (pr-str (str target-dir))
+                          "is in your :paths key\n\n"
+                          "For Leiningen in your project.clj:\n"
+                          "   either set your :target key to" (pr-str (str target-dir))
+                          "or add it to the :resource-paths key\n")
+                (log/warn (ansip/format-str [:yellow "Attempting to dynamically add classpath!!"]))
+                (fw-util/add-classpath! (.toURL (.toURI target-dir)))))))))))

 (defn default-compile [repl-env-fn cfg]
   (let [{:keys [options repl-options repl-env-options ::config] :as b-cfg} (update-config cfg)
@@ -867,6 +874,7 @@
                                                 ::start-figwheel-options
                                                 config))
                 (doseq [init-fn (::initializers b-cfg)] (init-fn))
+                (figwheel.core/start*)
                 (cond
                   (= mode :repl)
                   ;; this forwards command line args
@@ -875,27 +883,28 @@
                   ;; we need to get the server host:port args
                   (serve {:repl-env repl-env
                           :repl-options repl-options
-                          :eval-str (when fw-mode? (start-figwheel-code config))
                           :join? (get b-cfg ::join-server? true)}))))))))))

-(defn start [{:keys [figwheel-options build join-server?]}]
-  (let [[build-id build-options] (if (map? build)
-                                   [(:id build) (:options build)]
-                                   [build])
-        build-id (name (or build-id "dev"))
-        options  (or (and (not build-options)
-                          (get-build build-id))
-                     build-options
-                     {})
-        cfg
-        (cond-> {:options options
-                 ::join-server? (if (true? join-server?) true false)}
-          figwheel-options (assoc ::start-figwheel-options figwheel-options)
-          build-id    (assoc ::build {:id  build-id
-                                      :config (meta options)})
-          (not (get figwheel-options :mode))
-          (assoc-in [::config :mode] :repl))]
-    (default-compile cljs.repl.figwheel/repl-env cfg)))
+(defn start
+  ([] (start {}))
+  ([{:keys [figwheel-options build join-server?]}]
+   (let [[build-id build-options] (if (map? build)
+                                    [(:id build) (:options build)]
+                                    [build])
+         build-id (name (or build-id "dev"))
+         options  (or (and (not build-options)
+                           (get-build build-id))
+                      build-options
+                      {})
+         cfg
+         (cond-> {:options options
+                  ::join-server? (if (true? join-server?) true false)}
+           figwheel-options (assoc ::start-figwheel-options figwheel-options)
+           build-id    (assoc ::build {:id  build-id
+                                       :config (meta options)})
+           (not (get figwheel-options :mode))
+           (assoc-in [::config :mode] :repl))]
+     (default-compile cljs.repl.figwheel/repl-env cfg))))

 ;; ----------------------------------------------------------------------------
 ;; REPL api


Validate schema on event loops

Validate schema on event loops

It's cheap and easy, but it feels like a really important safety precaution

--- src/com/frereth/common/async_zmq.clj
+++ src/com/frereth/common/async_zmq.clj
@@ -211,6 +211,16 @@
                :async-loop nil
                :zmq-loop nil)))

+(def event-loopless-pair
+  "This is the almost-constructed EventPair that gets passed in to the messaging loops"
+  (dissoc (map->EventPair {:interface EventPairInterface
+                           :stopper s/Symbol
+                           :async-sock mq/Socket
+                           :->zmq-sock mq/Socket
+                           :_name s/Str
+                           :ex-chan fr-sch/async-channel
+                           :in<->ex-sock mq/InternalPair}) :async-loop :zmq-loop))
+
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;; Internal

@@ -313,8 +323,8 @@
    (and val (not= val stopper))  ; got a message that wasn't stopper
    (and (not= c in-chan) (not= c status-chan))))

-(s/defn run-async-loop! :- fr-sch/async-channel
-  [{:keys [async->sock interface _name stopper]} :- EventPair]
+(s/defn ^:always-validate run-async-loop! :- fr-sch/async-channel
+  [{:keys [async->sock interface _name stopper]}]
   (let [{:keys [in-chan status-chan status-out]} interface
         internal-> async->sock
         minutes-5 (partial async/timeout (* 5 (util/minute)))]
@@ -447,9 +457,9 @@
         (log/error ex "Unhandled 0mq Exception. 0mq loop exiting")
         :unhandled-0mq-exception))))

-(s/defn run-zmq-loop! :- fr-sch/async-channel
+(s/defn ^:always-validate run-zmq-loop! :- fr-sch/async-channel
   [{:keys [interface ->zmq-sock ex-chan]
-    :as component} :- EventPair]
+    :as component}]
   (let [{:keys [ex-sock external-reader externalwriter]} interface
         poller (mq/poller 2)]
     (mq/register-socket-in-poller! poller (:socket ex-sock))


Remode additional encoding step for data and metada on fixtures.

--- src/uxbox/fixtures.clj
+++ src/uxbox/fixtures.clj
@@ -57,10 +57,10 @@
                     {:id (mk-uuid "page" i)
                      :user (mk-uuid "user" ui)
                      :project (mk-uuid "project" pi)
-                     :data (data-encode nil)
-                     :metadata (data-encode {:width 1024
-                                             :height 768
-                                             :layout "tablet"})
+                     :data nil
+                     :metadata {:width 1024
+                                :height 768
+                                :layout "tablet"}
                      :name (str "page " i)}))

 (def num-users 50)


[FLINK-10631] Set number of slots per TM to 3 for Jepsen tests

--- flink-jepsen/src/jepsen/flink/db.clj
+++ flink-jepsen/src/jepsen/flink/db.clj
@@ -42,7 +42,7 @@
 (def deb-mesos-package "1.5.0-2.0.2")
 (def deb-marathon-package "1.6.322")

-(def taskmanager-slots 1)
+(def taskmanager-slots 3)

 (defn flink-configuration
   [test node]
@@ -293,7 +293,6 @@
        "-Djobmanager.rpc.port=6123 "
        "-Dmesos.resourcemanager.tasks.mem=2048 "
        "-Dtaskmanager.heap.mb=2048 "
-       "-Dtaskmanager.numberOfTaskSlots=2 "
        "-Dmesos.resourcemanager.tasks.cpus=1 "
        "-Drest.bind-address=$(hostname -f) "))


score c_elegans result twice higher than others

--- src/wb_es/web/core.clj
+++ src/wb_es/web/core.clj
@@ -25,7 +25,7 @@
 (defn- compose-search-query [q options]
   (if (and q (not= (clojure.string/trim q) ""))
     {:bool
-     {:must [{:bool {:filter (get-filter options)}}]
+     {:filter (get-filter options)
       :should [{:dis_max
                 {:boost 2
                  :queries [{:term {:wbid q}}
@@ -39,7 +39,7 @@
                {:match_phrase {:other {:query q
                                        :boost 0.1}}}]
       :minimum_should_match 1}}
-    {:bool {:filter (get-filter options)}}))
+    {:bool {:must (get-filter options)}}))

 (defn search [es-base-url index q options]
   (if (:autocomplete options)
@@ -48,7 +48,14 @@
                  :sort [:_score
                         {:label.raw {:order :asc}}]
                  :query
-                 (compose-search-query q options)
+                 {:function_score
+                  {:query (compose-search-query q options)
+                   :boost_mode "multiply"
+                   :score_mode "multiply"
+                   :functions
+                   [{:weight 2
+                     :filter
+                     {:term {:species.key {:value "c_elegans"}}}}]}}
                  :highlight
                  {:fields {:wbid {}
                            :wbid_as_label {}


make to variable more descriptive in nav controllers

--- frontend/controllers/navigation.cljs
+++ frontend/controllers/navigation.cljs
@@ -19,26 +19,26 @@
 ;; --- Navigation Multimethod Declarations ---

 (defmulti navigated-to
-  (fn [history-imp to args state] to))
+  (fn [history-imp navigation-point args state] navigation-point))

 (defmulti post-navigated-to!
-  (fn [history-imp to args previous-state current-state]
+  (fn [history-imp navigation-point args previous-state current-state]
     (put! (get-in current-state [:comms :ws]) [:unsubscribe-stale-channels])
-    to))
+    navigation-point))

 ;; --- Navigation Mutlimethod Implementations ---

 (defmethod navigated-to :default
-  [history-imp to args state]
-  (mlog "Unknown nav event: " (pr-str to))
+  [history-imp navigation-point args state]
+  (mlog "Unknown nav event: " (pr-str navigation-point))
   state)

 (defmethod post-navigated-to! :default
-  [history-imp to args previous-state current-state]
-  (mlog "No post-nav for: " to))
+  [history-imp navigation-point args previous-state current-state]
+  (mlog "No post-nav for: " navigation-point))

 (defmethod post-navigated-to! :navigate!
-  [history-imp to path previous-state current-state]
+  [history-imp navigation-point path previous-state current-state]
   (let [path (if (= \/ (first path))
                (subs path 1)
                path)]
@@ -46,7 +46,7 @@

 (defmethod navigated-to :dashboard
-  [history-imp to args state]
+  [history-imp navigation-point args state]
   (-> state
       (assoc :navigation-point :dashboard
              :navigation-data (select-keys args [:branch :repo :org]))
@@ -54,7 +54,7 @@
       state-utils/reset-current-build))

 (defmethod post-navigated-to! :dashboard
-  [history-imp to args previous-state current-state]
+  [history-imp navigation-point args previous-state current-state]
   (let [api-ch (get-in current-state [:comms :api])
         dashboard-data (:navigation-data current-state)]
     (api/get-projects api-ch)
@@ -63,7 +63,7 @@

 (defmethod navigated-to :build-inspector
-  [history-imp to [project-name build-num org repo] state]
+  [history-imp navigation-point [project-name build-num org repo] state]
   (-> state
       (assoc :navigation-data {:project project-name
                                :build-num build-num}
@@ -82,7 +82,7 @@

 ;; XXX: add unsubscribe when you leave the build page
 (defmethod post-navigated-to! :build-inspector
-  [history-imp to [project-name build-num] previous-state current-state]
+  [history-imp navigation-point [project-name build-num] previous-state current-state]
   (let [api-ch (get-in current-state [:comms :api])
         ws-ch (get-in current-state [:comms :ws])]
     (utils/ajax :get
@@ -109,11 +109,11 @@

 (defmethod navigated-to :add-projects
-  [history-imp to [project-id build-num] state]
+  [history-imp navigation-point [project-id build-num] state]
   (assoc state :navigation-point :add-projects :navigation-data {}))

 (defmethod post-navigated-to! :add-projects
-  [history-imp to args previous-state current-state]
+  [history-imp navigation-point args previous-state current-state]
   (let [api-ch (get-in current-state [:comms :api])]
     (utils/ajax :get "/api/v1/user/organizations" :organizations api-ch)
     (utils/ajax :get "/api/v1/user/collaborator-accounts" :collaborators api-ch))
@@ -121,7 +121,7 @@

 (defmethod navigated-to :project-settings
-  [history-imp to {:keys [project-name subpage org repo]} state]
+  [history-imp navigation-point {:keys [project-name subpage org repo]} state]
   (-> state
       (assoc :navigation-point :project-settings)
       (assoc :navigation-data {}) ;; XXX: maybe put subpage info here?
@@ -143,7 +143,7 @@
 ;; XXX: find a better place for all of the ajax functions, maybe a separate api
 ;;      namespace that knows about all of the api routes?
 (defmethod post-navigated-to! :project-settings
-  [history-imp to {:keys [project-name subpage]} previous-state current-state]
+  [history-imp navigation-point {:keys [project-name subpage]} previous-state current-state]
   (let [api-ch (get-in current-state [:comms :api])]
     (if (get-in current-state state/project-path)
       (mlog "project settings already loaded for" project-name)


More ClojureScript dep cleanup

More ClojureScript dep cleanup

--- planck-cljs/project.clj
+++ planck-cljs/project.clj
@@ -3,8 +3,7 @@
              {:dependencies [[org.clojure/clojurescript "1.9.456"]]}
              :dev
              [:shared
-              {:dependencies [[org.clojure/clojurescript "1.9.456"]
-                              [org.clojure/test.check "0.9.0"]
+              {:dependencies [[org.clojure/test.check "0.9.0"]
                               [tubular "1.0.0"]]
                :source-paths ["dev"]}]
              :build-release


:sparkles: Start using normal pool (instead of thread local) for db.

--- backend/src/uxbox/db.clj
+++ backend/src/uxbox/db.clj
@@ -15,8 +15,7 @@
    [uxbox.core :refer [system]]
    [uxbox.util.data :as data]
    [uxbox.util.pgsql :as pg]
-   [vertx.core :as vx])
-  (:import io.vertx.core.buffer.Buffer))
+   [vertx.core :as vx]))

 (defn- create-pool
   [config system]
@@ -28,7 +27,7 @@
                   (assoc :password password)
                   (str))]
     (log/info "creating connection pool with" dburi)
-    (pg/tl-pool dburi {:system system})))
+    (pg/pool dburi {:system system :max-size 8})))

 (defstate pool
   :start (create-pool cfg/config system))


Fix core API fn signatures for API docs and code assist

--- src/re_frame/core.cljc
+++ src/re_frame/core.cljc
@@ -475,7 +475,7 @@
   "
   std-interceptors/debug)

-(def path
+(defn path
   "returns an interceptor whose `:before` substitutes the coeffects `:db` with
   a sub-path of `:db`. Within `:after` it grafts the handler's return value
   back into db, at the right path.
@@ -502,9 +502,10 @@
     1. `path` may appear more than once in an interceptor chain. Progressive narrowing.
     2. if `:effects` contains no `:db` effect, can't graft a value back in.
   "
-  std-interceptors/path)
-
-(def enrich
+  [& args]
+  (apply std-interceptors/path args))
+
+(defn enrich
   "Interceptor factory which runs the given function `f` in the `after handler`
   position.  `f` is called with two arguments: `db` and `v`, and is expected to
   return a modified `db`.
@@ -547,7 +548,8 @@

   This brings huge simplicity at the expense of some re-computation
   each time. This may be a very satisfactory trade-off in many cases."
-  std-interceptors/enrich)
+  [f]
+  (std-interceptors/enrich f))

 (def trim-v
   "An interceptor which removes the first element of the event vector,
@@ -564,7 +566,7 @@
     "
   std-interceptors/trim-v)

-(def after
+(defn after
   "An interceptor factory, which is to say, a function which will return an interceptor.

   Returns an interceptor which runs a given function `f` in the `:after`
@@ -578,9 +580,10 @@

      - `f` runs schema validation (reporting any errors found).
      - `f` writes to localstorage."
-  std-interceptors/after)
-
-(def on-changes
+  [f]
+  (std-interceptors/after f))
+
+(defn on-changes
   "An interceptor factory, which is to say, a function which will return an interceptor.

   Returns an interceptor which will observe N paths within `db`, and if any of them
@@ -611,7 +614,8 @@
      - call `f` with the values extracted from [:a] [:b]
      - assoc the return value from `f` into the path  [:c]
   "
-  std-interceptors/on-changes)
+  [f out-path & in-paths]
+  (apply std-interceptors/on-changes (into [f out-path] in-paths)))

 (defn reg-global-interceptor


Spelling

Spelling

--- src/re_frame/core.cljc
+++ src/re_frame/core.cljc
@@ -49,7 +49,7 @@
    which is expected to take two arguments: app-db and query vector, and return
    a `reaction`.

-  This is a low level, advanced function.  You should probably be using re-sub
+  This is a low level, advanced function.  You should probably be using reg-sub
   instead."
   [query-id handler-fn]
   (registrar/register-handler subs/kind query-id handler-fn))


Improve core API docstrings

Improve core API docstrings

--- src/re_frame/core.cljc
+++ src/re_frame/core.cljc
@@ -630,7 +630,26 @@
 ;;                   (assoc-effect context :http-ajax {...}])))))
 ;;
 (defn ->interceptor
-  "Create an interceptor from named arguments"
+  "A utility function for creating interceptors.
+
+   Accepts three optional, named arguments:
+     - `:id` - an id for the interceptor (decorative only)
+     - `:before` - the before function
+     - `:after`  - the after function
+
+   Example use:
+   ```clj
+   (def my-interceptor
+     (->interceptor
+       :id     :my-interceptor
+       :before (fn [context]            ;; you normally want to change :coeffects
+                  ... in here use get-coeffect  and assoc-coeffect)
+
+       :after  (fn [context]                         ;; you normally want to change :effects
+                 (let [db (get-effect context :db)]  ;; (get-in context [:effects :db])
+                   (assoc-effect context :http-ajax {...}])))))
+   ```
+   "
   [& {:as m :keys [id before after]}]
   (utils/apply-kw interceptor/->interceptor m))


refactored track to be agnostic to whether you have the owner or a current-state

--- src-cljs/frontend/analytics/core.cljs
+++ src-cljs/frontend/analytics/core.cljs
@@ -20,16 +20,12 @@
 (def AnalyticsEvent
   (merge
     CoreAnalyticsEvent
-    {:owner s/Any}))
-
-(def AnalyticsEventForControllers
-  (merge
-    CoreAnalyticsEvent
-    {:current-state {s/Any s/Any}}))
+    (s/either {:owner s/Any}
+              {:current-state {s/Any s/Any}})))

 (def PageviewEvent
   (merge
-    AnalyticsEventForControllers
+    AnalyticsEvent
     {:navigation-point s/Keyword}))

 (def ExternalClickEvent
@@ -39,7 +35,7 @@

 (def BuildEvent
   (merge
-    AnalyticsEventForControllers
+    AnalyticsEvent
     {:build {s/Keyword s/Any}}))

 ;; Below are the lists of our supported events.
@@ -137,21 +133,26 @@
 (defmulti track (fn [data]
                   (when (frontend.config/analytics-enabled?)
                     (cond
-                      (supported-click-and-impression-events (:event-type data)) :track-click-and-impression-event
-                      (supported-controller-events (:event-type data)) :track-controller-events
-                      :else (:event-type data)))))
+                      (or (supported-click-and-impression-events (:event-type data))
+                          (supported-controller-events (:event-type data)))
+                      :event
+
+                      :else
+                      (:event-type data)))))

 (defmethod track :default [data]
   (when (frontend.config/analytics-enabled?)
     (merror-unsupported-event (:event-type data))))

-(s/defmethod track :track-click-and-impression-event [event-data :- AnalyticsEvent]
-  (let [{:keys [event-type properties owner]} event-data]
-    (segment/track-event event-type (supplement-tracking-properties-from-owner properties owner))))
+(s/defmethod track :event [event-data :- AnalyticsEvent]
+  (let [{:keys [event-type properties owner current-state]} event-data]
+    (if owner
+      (segment/track-event event-type (supplement-tracking-properties-from-owner properties owner))
+      (segment/track-event event-type (supplement-tracking-properties-from-state properties current-state)))))

 (s/defmethod track :track-controller-events [event-data :- AnalyticsEventForControllers]
   (let [{:keys [event-type properties current-state]} event-data]
-    (segment/track-event event-type (supplement-tracking-properties-from-state properties current-state))))
+    (segment/track-event event-type (supplement-tracking-properties-from-state properties current-state)))

 (s/defmethod track :external-click [event-data :- ExternalClickEvent]
   (let [{:keys [event properties owner]} event-data]
@@ -181,5 +182,5 @@
                       {:vcs-url (vcs-url/project-name (:vcs_url build))
                        :outcome (:outcome build)}))))

-(s/defmethod track :init-user [event-data :- AnalyticsEventForControllers]
+(s/defmethod track :init-user [event-data :- AnalyticsEvent]
   (segment/identify (get-user-properties-from-state (:current-state event-data))))


Fix A/B test.

Fix A/B test.

--- src-cljs/frontend/components/app.cljs
+++ src-cljs/frontend/components/app.cljs
@@ -49,11 +49,11 @@
     om/IRender
     (render [_] (html [:div.loading-spinner common/spinner]))))

-(defn dominant-component [app-state]
+(defn dominant-component [app-state owner]
   (condp = (get-in app-state [:navigation-point])
     :build build-com/build
     :dashboard dashboard/dashboard
-    :add-projects (if (= (get-in app-state [:ab-tests :new_add_projects]) :old)
+    :add-projects (if (= (om/get-shared owner [:ab-tests :new_add_projects]) :old)
                     add-projects-old/add-projects
                     add-projects/add-projects)
     :invite-teammates invites/teammates-invites
@@ -100,7 +100,7 @@
               ;; simple optimzation for real-time updates when the build is running
               app-without-container-data (dissoc-in app state/container-data-path)
               slim-aside? (get-in app state/slim-aside-path)
-              dom-com (dominant-component app)]
+              dom-com (dominant-component app owner)]
           (reset! keymap {["ctrl+s"] persist-state!
                           ["ctrl+r"] restore-state!})
           (html


document: Make sure `current-page' doesn't fail for empty page vectors.

--- src-cljs/pepa/workflows/document.cljs
+++ src-cljs/pepa/workflows/document.cljs
@@ -205,8 +205,10 @@
           tag-changes (:tag-changes state)
           date-changes (:date-changes state)
           sidebars (om/observe owner (data/ui-sidebars))
-          current-page (nth (:pages (om/value document))
-                            (dec (or page-number 1)))]
+          current-page (let [pages (:pages (om/value document))
+                             pagenum (dec (or page-number 1))]
+                         (when (< pagenum (count pages))
+                           (nth pages pagenum)))]
       [:.workflow.document
        ;; Left (thunbmail) pane
        (let [width (get sidebars ::thumbnails


allow passing :runtime-id via nrepl-select opts

--- src/main/shadow/cljs/devtools/server/nrepl_impl.clj
+++ src/main/shadow/cljs/devtools/server/nrepl_impl.clj
@@ -115,14 +115,18 @@
       ;; :else
       (send msg {:err (pr-str [:FIXME result])}))))

-(defn do-cljs-eval [{::keys [worker] :keys [ns session code runtime-id] :as msg}]
+(defn do-cljs-eval [{::keys [worker] :keys [ns session code] :as msg}]
   (let [reader (StringReader. code)

         session-id
         (-> session meta :id str)

         {:keys [last-msg-ref] :as repl-state}
-        (get @session #'*repl-state*)]
+        (get @session #'*repl-state*)
+
+        runtime-id
+        (or (:runtime-id msg)
+            (:runtime-id repl-state))]

     ;; :last-msg-ref is used by the print loop started by repl-init
     ;; to ensure that all prints use the latest message id when sending it out


Avoid calling flush! when flushing

Avoid calling flush! when flushing

--- src/reagent/ratom.cljs
+++ src/reagent/ratom.cljs
@@ -375,7 +375,9 @@
       (set! dirty? true)
       (if (nil? auto-run)
         (rea-enqueue this)
-        (auto-run this))))
+        (if (true? auto-run)
+          (._run this)
+          (auto-run this)))))

   (_update-watching [this derefed]
     (let [new (set derefed)
@@ -410,9 +412,7 @@

   (_set-opts [this {:keys [auto-run on-set on-dispose no-cache]}]
     (when (some? auto-run)
-      (set! (.-auto-run this) (case auto-run
-                                true run
-                                auto-run)))
+      (set! (.-auto-run this) auto-run))
     (when (some? on-set)
       (set! (.-on-set this) on-set))
     (when (some? on-dispose)


Add halo rendering to morphs

Add halo rendering to morphs

--- src-cljs/cljs_workspace/om_morph.cljs
+++ src-cljs/cljs_workspace/om_morph.cljs
@@ -120,6 +120,19 @@
   (let [prop-path (get-prop-path model id [:shape :Extent])]
     (swap! model assoc-in prop-path extent)))

+(defn set-border-color [model id fill]
+  (let [prop-path (get-prop-path model id [:shape :BorderColor])]
+    (swap! model assoc-in prop-path fill)))
+
+(defn toggle-halo [model id]
+  (let [prop-path (get-prop-path model id [:morph :Halo])]
+    (prn prop-path " before:" (get-in @model prop-path))
+    (swap! model (fn [m]
+                    (if (get-in m prop-path)
+                      (assoc-in m prop-path false)
+                      (assoc-in m prop-path true))))
+    (prn prop-path "Halo value after:" (get-in @model prop-path))))
+
 ; multimethod for morph

 (defmethod morph "Text" [app owner]
@@ -128,27 +141,40 @@
     (render [this]
       (let [style (dict->js (extract-style (:morph app)))]
         (dom/div  #js {:style style
-                     :className "morphNode" } (shape app owner))))))
+                       :className "morphNode" } (shape app owner))))))

 (defn handle-click [e state]
   ; add/remove morph from preserve list
   ; (branch-merge/toggle-preserve state)
   ; handle the custom behavior
+  (when (and (not-yet-handled e) (.-altKey e))
+    (@right-click-behavior e state))
   (when-let [cb (get-in state [:morph :onClick])]
               (cb state)))
+
+; render based on ad hoc definition of morph like frame
+; to visualize the halo
+(defn render-halo [app owner]
+  (let [css {:Extent (get-in app [:shape :Extent])
+             :BorderWidth 1
+             :Position {:x 0 :y 0}
+             :BorderColor "red"}]
+    (dom/div #js {:style (dict->js (extract-style css))})))

 (defmethod morph :default [app owner]
   (reify
     om/IRender
     (render [this]
-      (let [style (dict->js (extract-style (:morph app)))]
-        (dom/div  #js {:style style
-                     :className "morphNode"
-                     :onClick #(handle-click % @app)
-                     :onMouseDown #(draggable/start-dragging % app owner)
-                     :onMouseUp #(draggable/stop-dragging % app)
-                    }
-                 (shape app owner))))))
+        (let [style (dict->js (extract-style (:morph app)))]
+          (dom/div  #js {:style style
+                       :className "morphNode"
+                       :onClick #(handle-click % @app)
+                       :onMouseDown #(draggable/start-dragging % app owner)
+                       :onMouseUp #(draggable/stop-dragging % app)
+                      }
+                   (when (get-in app [:morph :Halo])
+                      (render-halo app owner))
+                   (shape app owner))))))

 ;; multi method for shape
 (defn handle-input [e owner app]


Pagerduty is now a part of config by default.

--- src/riemann/config.clj
+++ src/riemann/config.clj
@@ -11,6 +11,7 @@
   (:require [riemann.pubsub :as pubsub])
   (:require [riemann.graphite :as graphite])
   (:use clojure.tools.logging)
+  (:use [riemann.pagerduty :only [pagerduty]])
   (:use riemann.client)
   (:use [riemann.librato :only [librato-metrics]])
   (:use [riemann.streams :exclude [update-index delete-from-index]])


Slackbot scheduler wip

Slackbot scheduler wip

--- slackbot/src/org/teamweek/slackbot.clj
+++ slackbot/src/org/teamweek/slackbot.clj
@@ -1,8 +1,14 @@
 (ns org.teamweek.slackbot
   (:require [clojure.core.async :as async]
+            [datomic.api :as d]
             [aleph.http :as http]
             [manifold.stream :as stream]
             [cheshire.core :as json]
+            [clojurewerkz.quartzite.scheduler :as scheduler]
+            [clojurewerkz.quartzite.jobs :as jobs :refer (defjob)]
+            [clojurewerkz.quartzite.triggers :as triggers]
+            [clojurewerkz.quartzite.schedule.cron :as cron]
+            [clojurewerkz.quartzite.schedule.simple :as simple-scheduler] ;; TODO remove
             [byte-streams])
   (:gen-class))

@@ -123,6 +129,7 @@
                (conj question-answers
                      {:ts (java.util.Date.)
                       :team (:name (:team conn))
+                      :domain (:domain (:team conn))
                       :user username
                       :question question
                       :answer (:text (async/<!! answer-chan))}))
@@ -131,6 +138,41 @@
     (async/unsub dm-pub username answer-chan)
     (async/close! answer-chan)
     qas))
+
+
+(defjob NoOpJob [ctx]
+  (comment "Does nothing!"))
+
+(defjob QuestionnaireJob [ctx]
+  )
+
+(defn schedule-questionnaire-job [scheduler domain cron-string]
+  (let [job (jobs/build
+             (jobs/of-type QuestionnaireJob)
+             (jobs/using-job-data {:domain domain})
+             (jobs/with-identity (jobs/key (str "jobs." domain))))
+        trigger (triggers/build
+                 (triggers/with-identity (triggers/key (str "triggers." domain)))
+                 (triggers/with-schedule
+                   (cron/schedule
+                    (cron/cron-schedule cron-string))))]
+    (scheduler/schedule scheduler job trigger)))
+
+(defn init-start-jobs [scheduler db]
+  (doseq [{:keys [domain schedule]} (d/q '[:find (pull ?team [:team/domain :team/schedule])
+                                           :where
+                                           [?team :team/domain]]
+                                         db)]
+    (schedule-questionnaire-job scheduler
+                                domain
+                                schedule)))
+
+(defn -main [db-uri]
+  (let [scheduler (scheduler/start (scheduler/initialize))
+        db-conn (d/connect db-uri)
+        db (d/db db-conn)]
+    (init-start-jobs scheduler db))
+  (println "Hello world!"))

 (comment
   (def conn (connect slack-token))
@@ -146,6 +188,3 @@
       (send-to-user! conn "jonas" (str "You answered: " (pr-str answers)))))

   )
-
-(defn -main [& args]
-  (println "Hello world!"))


Monkey-patch clojush's initial-pop handling

So I can continue to evolve my best program.

--- src/spellcast/core.clj
+++ src/spellcast/core.clj
@@ -6,12 +6,62 @@
         [clojush.instructions.common]
         [clojush.instructions.return]
         [clojure.math.numeric-tower]
-        [clojure.set])
+        [clojure.set]
+        [clojush globals util pushstate random individual evaluate simplification]
+        )
   (:require [analemma.charts :as chart])
   (:import [spellcast.core Graph Graph$P HCABS Selector]
            [java.util BitSet]
            [org.uncommons.maths.random MersenneTwisterRNG])
   (:gen-class))
+
+;; XXX monkey patch clojush's initial population handling
+(in-ns 'clojush.pushgp.pushgp)
+(defn make-agents-and-rng
+  [{:keys [initial-population use-single-thread population-size
+           max-points-in-initial-program atom-generators random-seed
+           save-initial-population]}]
+  (let [agent-error-handler (fn [agnt except]
+                              (.printStackTrace except System/out)
+                              (.printStackTrace except)
+                              (System/exit 0))
+        ;random-seeds (repeatedly population-size #(random/lrand-bytes (:mersennetwister random/*seed-length*)))];; doesn't ensure unique seeds
+        random-seeds (loop [seeds '()]
+                       (let [num-remaining (if initial-population
+                                             ;; XXX here's the bug, I think they expect initial-population to
+                                             ;; already be read, but at this point it's a string
+                                             ;; (- (count initial-population) (count seeds))
+                                             ;; assume it's the same pop size
+                                             (- population-size (count seeds))
+                                             (- population-size (count seeds)))]
+                         (if (pos? num-remaining)
+                           (let [new-seeds (repeatedly num-remaining #(random/lrand-bytes (:mersennetwister random/*seed-length*)))]
+                             (recur (concat seeds (filter (fn [candidate]
+                                                            (not (some #(random/=byte-array % candidate)
+                                                                       seeds))) new-seeds)))); only add seeds that we do not already have
+                           seeds)))]
+    {:pop-agents (if initial-population
+                   (let [p (->> (read-string (slurp (str "data/" initial-population)))
+                                (map #(if use-single-thread (atom %) (agent %)))
+                                (vec))]
+                     (println (p 0))
+                     p)
+                   (let [pa (doall (for [_ (range population-size)]
+                                     (make-individual
+                                       :program (random-code max-points-in-initial-program atom-generators))))
+                         f (str "data/" (System/currentTimeMillis) ".ser")]
+                     (when save-initial-population
+                       (io/make-parents f)
+                       (spit f (pr-str pa)))
+                     (vec (map #(if use-single-thread (atom %) (agent %)) pa))))
+     :child-agents (vec (doall (for [_ (range population-size)]
+                                 ((if use-single-thread atom agent)
+                                      (make-individual)
+                                      :error-handler agent-error-handler))))
+     :random-seeds random-seeds
+     :rand-gens (vec (doall (for [k (range population-size)]
+                              (random/make-mersennetwister-rng (nth random-seeds k)))))
+     }))

 ;;;;;;;;;;;;
 ;; To make the integer stack less overloaded, define some similar
@@ -392,7 +442,7 @@
   For most graphs, bfs-depth is too low, so programs can't be perfect (0 vector).
   But otherwise, it's a decent function with forgiving slope."
   [selector graph]
-    (double (/ (HCABS/run graph selector) (.depth graph))))
+    (- (double (/ (HCABS/run graph selector) (.depth graph))) 1))

 (defn run-tests
   [selector test-graphs]
@@ -584,16 +634,27 @@
                                      :fill "rgba(0,0,255,1)"
                                      :size 2))))
        )
-     ))
+     "log-progress" ;; read log.csv and graph generation performance
+     (with-open [rdr (clojure.java.io/reader "log.csv")]
+       (let [lines (drop 1 (line-seq rdr))
+             vecs (for [line lines] (clojure.string/split line #","))
+             points (vec (for [[gen in error size] vecs] [(read-string gen)
+                                                     (read-string error)]))
+
+             ]
+         (spit (str "progress.csv")
+               (clojure.string/join "\n"
+                                    (for [point points]
+                                      (clojure.string/join "," point))))))))
   ([]
    (pushgp
      {:error-function error-function
       ;; try to beat paper's best average
-      :error-threshold (average (run-tests Selector/NUM_UNINFORMED))
+      :error-threshold (average (run-tests Selector/NUM_UNINFORMED test-graphs))
       :atom-generators atoms
       ; :use-single-thread true
       :population-size 500
-      :max-generations 100
+      :max-generations 200
       :max-points 500
       :max-points-in-initial-program 200
       :evalpush-limit 500
@@ -604,6 +665,8 @@
       :ultra-probability 0.0
       :print-timings false
       :print-csv-logs true
+      :save-initial-population true
+      :initial-population "1398667653967.ser"
       :report-simplifications 0
       :print-history false})
    (shutdown-agents)))


use let-bound fns instead of private defn-

--- src/braid/client/ui/views/thread.cljs
+++ src/braid/client/ui/views/thread.cljs
@@ -37,26 +37,13 @@
               ^{:key (tag :id)}
               [tag-pill-view (tag :id)]))])})))

-(defn- unseen? [message thread]
-  (> (:created-at message)
-     (thread :last-open-at)))
-
-(defn- thread-private? [thread]
-  (and
-    (not (thread :new?))
-    (empty? (thread :tag-ids))
-    (seq (thread :mentioned-ids))))
-
-(defn- thread-limbo? [thread]
-  (and
-    (not (thread :new?))
-    (empty? (thread :tag-ids))
-    (empty? (thread :mentioned-ids))))
-
 (defn messages-view [thread]
   ; Closing over thread-id, but the only time a thread's id changes is the new
   ; thread box, which doesn't have messages anyway
   (let [messages (subscribe [:messages-for-thread (thread :id)])
+
+        unseen? (fn [message thread] (> (:created-at message)
+                                        (thread :last-open-at)))

         scroll-to-bottom!
         (fn [component]
@@ -106,6 +93,16 @@
         set-focused! (fn [bool] (swap! state assoc :focused? bool))
         set-dragging! (fn [bool] (swap! state assoc :dragging? bool))

+        thread-private? (fn [thread] (and
+                                       (not (thread :new?))
+                                       (empty? (thread :tag-ids))
+                                       (seq (thread :mentioned-ids))))
+
+        thread-limbo? (fn [thread] (and
+                                     (not (thread :new?))
+                                     (empty? (thread :tag-ids))
+                                     (empty? (thread :mentioned-ids))))
+
         ; Closing over thread-id, but the only time a thread's id changes is the new
         ; thread box, which is always open
         open? (subscribe [:thread-open? (thread :id)])


show threads in user pages

show threads in user pages

--- src/chat/client/views/pages/user.cljs
+++ src/chat/client/views/pages/user.cljs
@@ -16,18 +16,22 @@
             (om/build user-view user))
           (dom/div #js {:className "description"}
             (dom/img #js {:className "avatar" :src (user :avatar)})
-            (dom/span nil "One day, a profile will be here."))
+            (dom/p nil "One day, a profile will be here.")
+            (dom/p nil "Currently only showing your open threads that mention this user.")
+            (dom/p nil "Soon, you will see all recent threads this user has participated in."))
           (apply dom/div #js {:className "threads"}
             (concat
               [(new-thread-view)]
               (map (fn [t] (om/build thread-view t {:key :id}))
-                   (let [user-id (get-in @store/app-state [:session :user-id])]
-                     ; sort by last reply
-                     (->> (select-keys (data :threads) (get-in data [:page :search-result-ids]))
+                   (let [current-user-id (get-in @store/app-state [:session :user-id])]
+                     ; sort by last message sent by logged-in user, most recent first
+                     (->> (select-keys (data :threads) (get-in data [:user :open-thread-ids]))
                           vals
+                          (filter (fn [thread]
+                                    (contains? (set (thread :mentioned-ids)) user-id)))
                           (sort-by
                             (comp (partial apply max)
                                   (partial map :created-at)
+                                  (partial filter (fn [m] (= (m :user-id) current-user-id)))
                                   :messages))
-                          reverse)
-                     )))))))))
+                          reverse))))))))))


Param for est-end.

Param for est-end.

--- src/clj/forma/hadoop/jobs/scatter.clj
+++ src/clj/forma/hadoop/jobs/scatter.clj
@@ -74,29 +74,30 @@

 ;; ## Forma

-(def forma-run-parameters
-  {"1000-32" {:est-start "2005-12-31"
-              :est-end "2011-08-01" ;; I KEEP FUCKING THIS UP
-              :s-res "1000"
-              :t-res "32"
-              :neighbors 1
-              :window-dims [600 600]
-              :vcf-limit 25
-              :long-block 15
-              :window 5}
-   "500-16" {:est-start "2005-12-31"
-             :est-end "2012-06-25"
-             :s-res "500"
-             :t-res "16"
-             :neighbors 1
-             :window-dims [600 600]
-             :vcf-limit 25
-             :long-block 30
-             :window 10
-             :ridge-const 1e-8
-             :convergence-thresh 1e-6
-             :max-iterations 500
-             :min-coast-dist 3}})
+(defn forma-run-parameters [k est-end]
+  (-> {"1000-32" {:est-start "2005-12-31"
+                  :est-end est-end
+                  :s-res "1000"
+                  :t-res "32"
+                  :neighbors 1
+                  :window-dims [600 600]
+                  :vcf-limit 25
+                  :long-block 15
+                  :window 5}
+       "500-16" {:est-start "2005-12-31"
+                 :est-end est-end
+                 :s-res "500"
+                 :t-res "16"
+                 :neighbors 1
+                 :window-dims [600 600]
+                 :vcf-limit 25
+                 :long-block 30
+                 :window 10
+                 :ridge-const 1e-8
+                 :convergence-thresh 1e-6
+                 :max-iterations 500
+                 :min-coast-dist 3}}
+      (get k)))

 (defn constrained-tap
   [ts-pail-path dataset s-res t-res]
@@ -121,14 +122,14 @@
           (:distinct false))))

 (defmain formarunner
-  [tmp-root pail-path ts-pail-path fire-pail-path out-path run-key]
-  (let [{:keys [s-res t-res est-end] :as est-map} (forma-run-parameters run-key)
+  [tmp-root pail-path ts-pail-path fire-pail-path out-path run-key est-end]
+  (let [{:keys [s-res t-res est-end] :as est-map} (forma-run-parameters run-key est-end)
         mk-filter (fn [static-path ts-src]
                     (forma/filter-query (hfs-seqfile static-path)
                                         (:vcf-limit est-map)
                                         ts-src))]
     (assert est-map (str run-key " is not a valid run key!"))
-
+
     (workflow [tmp-root]

               vcf-step
@@ -199,7 +200,7 @@
               ndvi-filter
               ([:tmp-dirs ndvi-path]
                  "Filters out NDVI with VCF < 25"
-                 (?- (hfs-seqfile ndvi-path)
+                 (?- (hfs-seqfile ndvi-path)
                      (mk-filter static-path (hfs-seqfile ndvi-seq-path))))

               reli-filter
@@ -207,7 +208,7 @@
                  "Filters out reliability with VCF < 25"
                  (?- (hfs-seqfile reli-path)
                      (mk-filter static-path (hfs-seqfile reli-seq-path))))
-
+
               rain-filter
               ([:tmp-dirs rain-path]
                  "Filters out rain with VCF < 25, before stretching rain ts"
@@ -229,7 +230,7 @@
                        (forma/dynamic-filter (hfs-seqfile ndvi-path)
                                              (hfs-seqfile reli-path)
                                              (hfs-seqfile rain-stretch-path)))))
-
+
               cleanseries
               ([:tmp-dirs clean-series]
                  "Screen out extremely cloudy pixels. Currently doesn't
@@ -246,14 +247,14 @@
                      (forma/analyze-trends
                       est-map
                       (hfs-seqfile clean-series))))
-
+
               trends-cleanup
               ([:tmp-dirs cleanup-path]
                  "Clean up data after trends to improve join performance. Joins
                   kill us with lots of observations"
                  (?- (hfs-seqfile cleanup-path)
                      (forma/trends-cleanup (hfs-seqfile trends-path))))
-
+
               fire-step
               ([:tmp-dirs fire-path]
                  "Create fire series"
@@ -280,7 +281,7 @@
                                       est-map
                                       (hfs-seqfile cleanup-path)
                                       (hfs-seqfile adjusted-fire-path))))
-
+
               final-forma
               ([:tmp-dirs final-path]
                  "Process neighbors"
@@ -324,8 +325,8 @@
                      (hfs-seqfile "/mnt/hgfs/Dropbox/yikestimes"))))))

 (defmain simplerunner
-  [tmp-root pail-path ts-pail-path out-path run-key]
-  (let [{:keys [s-res t-res est-end] :as est-map} (forma-run-parameters run-key)
+  [tmp-root pail-path ts-pail-path out-path run-key est-end]
+  (let [{:keys [s-res t-res est-end] :as est-map} (forma-run-parameters run-key est-end)
         mk-filter (fn [vcf-path ts-src]
                     (forma/filter-query (hfs-seqfile vcf-path)
                                         (:vcf-limit est-map)
@@ -338,12 +339,10 @@
                      (<- [?subpail ?data-chunk]
                          ((constrained-tap pail-path "vcf" s-res "00") ?subpail ?data-chunk))))

-
+
               ndvi-step
               ([:tmp-dirs ndvi-path]
                  (?- (hfs-seqfile ndvi-path)
                      (mk-filter vcf-path
                                 (constrained-tap
-                                 ts-pail-path "ndvi" s-res t-res))))
-
-              )))
+                                 ts-pail-path "ndvi" s-res t-res)))))))


lookup previous balance for new reconciliation

--- src/clj_money/web/reconciliations.clj
+++ src/clj_money/web/reconciliations.clj
@@ -1,5 +1,6 @@
 (ns clj-money.web.reconciliations
-  (:require [environ.core :refer [env]]
+  (:require [clojure.pprint :refer [pprint]]
+            [environ.core :refer [env]]
             [clj-time.core :as t]
             [ring.util.response :refer :all]
             [clj-money.validation :as validation]
@@ -27,7 +28,8 @@
   ([req] (new-reconciliation req {:end-of-period (t/today)}))
   ([{params :params} reconciliation]
    (let [account-id (Integer. (:account-id params))
-         account (accounts/find-by-id (env :db) account-id)]
+         account (accounts/find-by-id (env :db) account-id)
+         previous-balance (reconciliations/previous-balance (env :db) (:id account))]
      (with-layout "Reconcile account" {}
        [:form {:action (format "/accounts/%s/reconciliations" account-id)
                :method :post}
@@ -37,7 +39,7 @@
           [:div.form-group
            [:label.control-label {:for :previous-balance} "Previous balance"]
            [:input.form-control {:name :previous-balance
-                                 :value "0.00"
+                                 :value (util/format-number previous-balance)
                                  :disabled true}]]
           (number-input-field reconciliation :balance)
           [:input.btn.btn-primary {:type :submit


fix gallery badge ticket link

fix gallery badge ticket link

--- src/cljs/salava/admin/ui/tickets.cljs
+++ src/cljs/salava/admin/ui/tickets.cljs
@@ -3,7 +3,7 @@
             [reagent.session :as session]
             [reagent-modals.modals :as m]
             [clojure.set :as set :refer [intersection]]
-            [clojure.string :refer [trim]]
+            [clojure.string :refer [trim split]]
             [salava.core.ui.ajax-utils :as ajax]
             [salava.core.ui.layout :as layout]
             [salava.core.ui.grid :as g]
@@ -11,7 +11,8 @@
             [salava.core.i18n :refer [t]]
             [salava.core.helper :refer [dump]]
             [salava.admin.ui.helper :refer [message-form email-select status-handler]]
-            [salava.core.time :refer [date-from-unix-time]]))
+            [salava.core.time :refer [date-from-unix-time]]
+            [salava.admin.ui.admintool :refer [open-admintool-modal]]))

 (defn text-shorter [text length]
   (let [sorted-text (subs text 0 (min (count text) length))
@@ -28,43 +29,43 @@

 (defn ticket-send-message [state name]
-(let [{:keys [user_id gallery-state init-data info]} @state
+  (let [{:keys [user_id gallery-state init-data info]} @state
         mail (cursor state [:mail])
         status (cursor state [:status])
         email-atom (cursor state [:selected-email])
         ]

-  [:div {:class "row flip"}
-   [:div {:class "col-xs-12"}
+    [:div {:class "row flip"}
+     [:div {:class "col-xs-12"}
       [:div.form-group
-        [:label
-         (str (t :user/Email) ":")]
-        (email-select (:emails info) email-atom) ]
+       [:label
+        (str (t :user/Email) ":")]
+       (email-select (:emails info) email-atom) ]
       (message-form mail)
       [:button {:type         "button"
                 :class        "btn btn-primary pull-right"
                 :disabled (if-not (and
-                                   (< 1 (count (:subject @mail)))
-                                   (< 1 (count (:message @mail))))
+                                    (< 1 (count (:subject @mail)))
+                                    (< 1 (count (:message @mail))))
                             "disabled")
                 :on-click     #(ajax/POST
-                                (path-for (str "/obpv1/admin/send_message/" user_id ))
-                                {:response-format :json
-                                 :keywords?       true
-                                 :params        {:subject (:subject @mail)
-                                                 :message (:message @mail)
-                                                 :email  @email-atom}
-                                 :handler         (fn [data]
-                                                    (reset! status data)
-                                                    (reset! mail {:subject ""
-                                                                  :message ""})
-                                                      )
-                                 :error-handler   (fn [{:keys [status status-text]}]
-                                                    (.log js/console (str status " " status-text))
-                                                    )})
+                                 (path-for (str "/obpv1/admin/send_message/" user_id ))
+                                 {:response-format :json
+                                  :keywords?       true
+                                  :params        {:subject (:subject @mail)
+                                                  :message (:message @mail)
+                                                  :email  @email-atom}
+                                  :handler         (fn [data]
+                                                     (reset! status data)
+                                                     (reset! mail {:subject ""
+                                                                   :message ""})
+                                                     )
+                                  :error-handler   (fn [{:keys [status status-text]}]
+                                                     (.log js/console (str status " " status-text))
+                                                     )})
                 }
        (t :admin/Sendmessage)]
-       (status-handler status "user")]
+      (status-handler status "user")]
      ])
   )

@@ -81,28 +82,28 @@
 (defn ticket-modal [state]
   [:div
    [:div.modal-header
-      [:button {:type         "button"
-                :class        "close"
-                :data-dismiss "modal"
-                :aria-label   "OK"}
-       [:span {:aria-hidden             "true"
-               :dangerouslySetInnerHTML {:__html "×"}}]]
+    [:button {:type         "button"
+              :class        "close"
+              :data-dismiss "modal"
+              :aria-label   "OK"}
+     [:span {:aria-hidden             "true"
+             :dangerouslySetInnerHTML {:__html "×"}}]]
     [:h4 {:class "modal-title"} (t :admin/Sendmessagetoreporter)]]
    [:div.modal-body
     (ticket-modal-container state)
-      ]])
+    ]])

 (defn get-closed-tickets [state]
   (ajax/GET
-   (path-for "/obpv1/admin/closed_tickets/")
-   {:handler (fn [tickets]
-               (swap! state assoc :tickets tickets))}))
+    (path-for "/obpv1/admin/closed_tickets/")
+    {:handler (fn [tickets]
+                (swap! state assoc :tickets tickets))}))

 (defn init-data [state]
   (ajax/GET
-   (path-for "/obpv1/admin/tickets/")
-   {:handler (fn [tickets]
-               (swap! state assoc :tickets tickets))}))
+    (path-for "/obpv1/admin/tickets/")
+    {:handler (fn [tickets]
+                (swap! state assoc :tickets tickets))}))

 (defn open-ticket-modal [user-id name gallery-state init-data]
   (let [state (atom {:mail          {:subject ""
@@ -115,18 +116,20 @@
                      :init-data init-data
                      :status ""})]
     (ajax/GET
-     (path-for (str "/obpv1/admin/user/" user-id))
-     {:handler (fn [data]
-                 (do
-                   (let [primary-email (first (filter #(:primary_address %) (get-in data [:info :emails])))]
-                     (swap! state assoc :name (:name data)
-                            :image_file (:image_file data)
-                            :user (:item_owner data)
-                            :user_id (:item_owner_id data)
-                            :selected-email (:email primary-email)
-                            :info (:info data))))
-                 (m/modal! [ticket-modal state init-data]))})))
-
+      (path-for (str "/obpv1/admin/user/" user-id))
+      {:handler (fn [data]
+                  (do
+                    (let [primary-email (first (filter #(:primary_address %) (get-in data [:info :emails])))]
+                      (swap! state assoc :name (:name data)
+                             :image_file (:image_file data)
+                             :user (:item_owner data)
+                             :user_id (:item_owner_id data)
+                             :selected-email (:email primary-email)
+                             :info (:info data))))
+                  (m/modal! [ticket-modal state init-data]))})))
+
+(defn badge-id [url]
+  (second (split url #"/badgeview/")))

 (defn ticket [ticket-data state]
@@ -139,8 +142,12 @@
        [:h3 {:class "media-heading"}
         [:u (t (keyword (str "admin/" report_type)))]]
        [:h4 {:class "media-heading"}
-        [:a {:href item_url :target "_blank"}
-         (str (t (keyword (str "admin/" item_type))) " - " item_name)]]]
+        (if (= "badges" item_type)
+          [:a {:href "#" :on-click #(do (.preventDefault %)
+                         (open-admintool-modal "badges" (badge-id item_url) state init-data))}
+           (str (t (keyword (str "admin/" item_type))) " - " item_name)]
+          [:a {:href item_url :target "_blank"}
+           (str (t (keyword (str "admin/" item_type))) " - " item_name)])]]
       [:div.media-descriprtion
        [:div {:class "col-xs-12"  :id (if open? "" "closed")}
         [:div [:label (str (t :admin/Description) ": ")] " " (if (< 130 (count description)) [text-shorter description 130]   description) ]
@@ -156,23 +163,23 @@
                  :on-click #(do
                               (.preventDefault %)
                               (ajax/POST
-                               (path-for (str "/obpv1/admin/close_ticket/" id))
-                               {:response-format :json
-                                :keywords? true
-                                :params {:new-status (if open? "closed" "open")}
-                                :handler (fn [data]
-                                           (if open?
-                                             (init-data state)
-                                             (get-closed-tickets state))
-                                           )
-                                :error-handler (fn [{:keys [status status-text]}])}))}
+                                (path-for (str "/obpv1/admin/close_ticket/" id))
+                                {:response-format :json
+                                 :keywords? true
+                                 :params {:new-status (if open? "closed" "open")}
+                                 :handler (fn [data]
+                                            (if open?
+                                              (init-data state)
+                                              (get-closed-tickets state))
+                                            )
+                                 :error-handler (fn [{:keys [status status-text]}])}))}
         (if open? (t :admin/Done) (t :admin/Restore))]]]]))

 (defn ticket-visible? [element state]
   (if (or (> (count
-              (intersection
-               (into #{} (:types-selected @state))
-               #{(:report_type element)}))
+               (intersection
+                 (into #{} (:types-selected @state))
+                 #{(:report_type element)}))
              0)
           (= (:types-all @state)
              true))
@@ -192,22 +199,22 @@
                              (swap! state assoc (keyword all-key) true))}
         (t :core/All)]
        (doall
-        (for [button buttons]
-          (let [value button
-                checked? (boolean (some #(= value %) buttons-checked))]
-            [:button {:class    (str "btn btn-default " value " " (if checked? "btn-active"))
-                      :key      value
-                      :on-click (fn []
-                                  (swap! state assoc (keyword all-key) false)
-                                  (if checked?
-                                    (do
-                                      (if (= (count buttons-checked) 1)
-                                        (swap! state assoc (keyword all-key) true))
-                                      (swap! state assoc (keyword key)
-                                             (remove (fn [x] (= x value)) buttons-checked)))
-                                    (swap! state assoc (keyword key)
-                                           (conj buttons-checked value))))}
-             (t (keyword (str "admin/" value)))])))])]])
+         (for [button buttons]
+           (let [value button
+                 checked? (boolean (some #(= value %) buttons-checked))]
+             [:button {:class    (str "btn btn-default " value " " (if checked? "btn-active"))
+                       :key      value
+                       :on-click (fn []
+                                   (swap! state assoc (keyword all-key) false)
+                                   (if checked?
+                                     (do
+                                       (if (= (count buttons-checked) 1)
+                                         (swap! state assoc (keyword all-key) true))
+                                       (swap! state assoc (keyword key)
+                                              (remove (fn [x] (= x value)) buttons-checked)))
+                                     (swap! state assoc (keyword key)
+                                            (conj buttons-checked value))))}
+              (t (keyword (str "admin/" value)))])))])]])

 (defn grid-show-closed-tickets [state]
   (let [show-closed?  (cursor state [:show-closed?])]


oops need to update this to match the generation process

--- src/block_chain/block_validations.clj
+++ src/block_chain/block_validations.clj
@@ -17,7 +17,7 @@
   (b/meets-target? block))

 (defn valid-target? [db block]
-  (let [expected (hex->int (target/next-target (take 10 (q/chain db (q/get-parent db block)))))
+  (let [expected (hex->int (target/next-target (drop-last (take 30 (q/chain db (q/get-parent db block))))))
         received (hex->int (get-in block [:header :target]))
         threshold (/ expected 1000)]
     (in-delta? expected received threshold)))


moar headers for securitaiiii | #53

moar headers for securitaiiii | #53

--- src/clj/conference_rating/handler.clj
+++ src/clj/conference_rating/handler.clj
@@ -122,6 +122,8 @@
   (-> secure-api-defaults
       (assoc-in [:security :ssl-redirect] (not ssl-redirect-disabled))
       (assoc-in [:security :frame-options] :deny)
+      (assoc-in [:security :xss-protection :mode] :block)
+      (assoc-in [:security :content-type-options] :nosniff)
       (assoc :proxy true)))

 (defn prevent-open-redirect-through-relay-state [handler]


meaningful error for missing layer

meaningful error for missing layer

--- src/clj/infinitelives/pixi/macros.clj
+++ src/clj/infinitelives/pixi/macros.clj
@@ -10,7 +10,10 @@
             (list* `assert-args more)))))

 (defmacro get-layer [canvas layer]
-  `(-> ~canvas :layer ~layer))
+  `(or
+    (-> ~canvas :layer ~layer)
+    (throw (js/Error (str "canvas layer " ~layer " not found.")))
+    ))

 (defmacro with-sprite [canvas layer bindings & body]
   (assert-args


pass caching optionally via meta

pass caching optionally via meta

--- src/cljc/commos/delta/compscribe.cljc
+++ src/cljc/commos/delta/compscribe.cljc
@@ -305,7 +305,15 @@
   (doto (chan)
     (on-close-pipe target on-close)))

-(defrecord CompscribeService [cached-service source-service subscriptions]
+(defn- caching
+  [service cached-service]
+  (vary-meta service assoc ::cached-service cached-service))
+
+(defn- this-cached
+  [service]
+  (::cached-service (meta service) service))
+
+(defrecord CompscribeService [source-service subscriptions]
   IStream
   (subscribe [this identifier target]
     (let [[spec id] identifier
@@ -326,7 +334,7 @@
           (swap! subscriptions assoc target
                  (vary-meta (compscribe* subs-target
                                          source-service
-                                         cached-service
+                                         (this-cached this)
                                          spec
                                          id)
                             assoc ::identifier identifier))))))
@@ -402,7 +410,7 @@
                   IStream
                   (subscribe [this identifier target]
                     (-> service
-                        (assoc :cached-service this)
+                        (caching this)
                         (subscribe identifier target)))
                   (cancel [this target]
                     (cancel service target)))


Remove unnecessary conj for current pixel

--- src/cljs/goya/components/drawing.cljs
+++ src/cljs/goya/components/drawing.cljs
@@ -340,7 +340,7 @@
   (when (= paint-tool :brush)
     (let [active-pixels-since-last-event (bresenham/bresenham doc-x doc-y last-x last-y)]
       (set! (.-fillStyle preview-context) preview-color)
-      (paint-pixels-for-pencil-tool (conj active-pixels-since-last-event [doc-x doc-y]) pixel-size)
+      (paint-pixels-for-pencil-tool active-pixels-since-last-event pixel-size)
       (visit-pixels-for-line-segment doc-x doc-y last-x last-y doc-canvas-width)
       (reset! guistate/transient-state
               (assoc @guistate/transient-state :last-mouse-pos [doc-x doc-y]))))


added size and weight section to phone detail view

--- src/cljs/phonecat_re_frame/views.cljs
+++ src/cljs/phonecat_re_frame/views.cljs
@@ -147,7 +147,7 @@
 (defn size-and-weight
   [size-and-weight]
   [phone-info-template "Size And Weight" [{:name "Dimensions"
-                                           :value (:dimensions @size-and-weight)}
+                                           :value (clojure.string/join ", " (:dimensions @size-and-weight))}
                                           {:name "Weight"
                                            :value (:weight @size-and-weight)}]])

@@ -198,6 +198,7 @@
    [display (reaction (:display @phone))]
    [hardware (reaction (:hardware @phone))]
    [camera (reaction (:camera @phone))]
+   [size-and-weight (reaction (:sizeAndWeight @phone))]
    [additional-features (reaction (:additionalFeatures @phone))]])

 (defn phone-page


adding export csv doc

adding export csv doc

--- src/clojure/com/zensol/cisql/conf.clj
+++ src/clojure/com/zensol/cisql/conf.clj
@@ -30,7 +30,8 @@
    :tg "[variable]        toggle a boolean variable"
    :shtab "[table]        show table metdata or all if no table given"
    :orph "[label]         orphan (spawn new next) window in GUI mode"
-   :cfcat "[catalog]      configure (set) the database (like 'use <db name>')"})
+   :cfcat "[catalog]      configure (set) the database (like 'use <db name>')"
+   :export "[filename]    export the last query as a CSV file"})

 (defn set-config [key value]
   (log/tracef "%s -> %s" key value)


Delete temp file

Delete temp file


Fix typo in addicted soure

Fix typo in addicted soure

--- src/clj/subman/sources/addicted.clj
+++ src/clj/subman/sources/addicted.clj
@@ -214,7 +214,7 @@
                                   (clojure.string/split #"x"))]
            {:show (first name-parts)
             :season (-> season-episode first helpers/remove-first-0)
-            :episodes (-> season-episode last helpers/remove-first-0)
+            :episode (-> season-episode last helpers/remove-first-0)
             :name (last name-parts)
             :url (-> item :attrs :href make-url)}))


Added solving cases paginator

Added solving cases paginator

--- src/cljs/asols/client/solvings.cljs
+++ src/cljs/asols/client/solvings.cljs
@@ -97,11 +97,25 @@
           {:keys [body]} (<! (http/post "/render-network/" params))]
       body)))

+(def ^:private cases-per-page 10)
+
+(defn get-page [coll page-size page-num]
+  (->> coll
+       (drop (* page-size page-num))
+       (take page-size)))
+
+(defn has-page? [coll page-size page-num]
+  (and (>= page-num 0)
+       (< (* page-size (inc page-num))
+          (count coll))))
+
 (defcomponent solving-block [{:keys [number solving visible?]
-                              :or {visible? false}} owner]
+                              :or {visible? false}}
+                             owner]
   (init-state [_]
     {:visible? visible?
-     :hover-chan (chan)})
+     :hover-chan (chan)
+     :cases-page 0})

   (will-mount [_]
     (let [hover-chan (om/get-state owner :hover-chan)]
@@ -112,9 +126,10 @@
                             (nth (:cases solving) case-num))]
                  (recur (<! hover-chan))))))

-  (render-state [_ {:keys [visible? hover-chan]}]
+  (render-state [_ {:keys [visible? hover-chan cases-page]}]
     (html
       (let [{:keys [cases best-case ms-took]} solving
+            visible-cases (get-page cases cases-per-page cases-page)
             [mutation train-cost test-cost] (default-case-data best-case)]
         [:li.list-group-item.solving
          [:.row {:on-click #(om/update-state! owner :visible? not)}
@@ -130,21 +145,35 @@
             (format-time ms-took)]]]
          [:.row {:class (when-not visible? "hidden")}
           [:.col-xs-12
-           [:table.table.table-condensed.table-hover
-            [:thead
-             [:tr (for [h (case-headers best-case)]
-                    [:th h])]]
-            [:tbody
-             (om/build solving-case-block {:solving-case best-case
-                                           :hover-chan hover-chan
-                                           :case-id :none
-                                           :best? true})
-             (for [i (range (count cases))
-                   :let [case (nth cases i)]]
-               (om/build solving-case-block {:solving-case case
-                                             :hover-chan hover-chan
-                                             :case-id i
-                                             :best? false}))]]]]]))))
+           [:.row
+            [:.col-xs-12
+             [:table.table.table-condensed.table-hover
+              [:thead
+               [:tr (for [h (case-headers best-case)]
+                      [:th h])]]
+              [:tbody
+               (om/build solving-case-block {:solving-case best-case
+                                             :hover-chan   hover-chan
+                                             :case-id      :none
+                                             :best?        true})
+               (for [[i case] (map-indexed vector visible-cases)]
+                 (om/build solving-case-block {:solving-case case
+                                               :hover-chan   hover-chan
+                                               :case-id      i
+                                               :best?        false}))]]]]
+           [:.row
+            [:.col-xs-12
+             [:ul.pager
+              (when (has-page? cases cases-per-page (dec cases-page))
+                [:li
+                 [:a
+                  {:href "#" :on-click #(om/update-state! owner :cases-page dec)}
+                  [:i.fui-arrow-left]]])
+              (when (has-page? cases cases-per-page (inc cases-page))
+                [:li
+                 [:a
+                  {:href "#" :on-click #(om/update-state! owner :cases-page inc)}
+                  [:i.fui-arrow-right]]])]]]]]]))))

 (defcomponent solvings-panel [{:keys [solvings]}]
   (render [_]


fix deck selection issue

fix deck selection issue

--- src/cljs/netrunner/deckbuilder.cljs
+++ src/cljs/netrunner/deckbuilder.cljs
@@ -11,6 +11,12 @@

 (def app-state (atom {:decks []}))

+(def select-channel (chan))
+
+(defn load-decks [decks]
+  (swap! app-state assoc :decks decks)
+  (put! select-channel (first (sort-by :date > decks))))
+
 (defn process-decks [decks]
   (for [deck decks]
     (let [cards (map #(str (:qty %) " " (:card %)) (:cards deck))]
@@ -18,9 +24,9 @@

 (go (let [cards (<! cards-channel)
           decks (process-decks (:json (<! (GET (str "/data/decks")))))]
-      (swap! app-state assoc :decks decks)
+      (load-decks decks)
       (go (let [data (<! auth-channel)]
-            (swap! app-state assoc :decks (process-decks (:decks data)))))
+            (load-decks (process-decks (:decks data)))))
       (>! cards-channel cards)))

 (defn side-identities [side]
@@ -194,13 +200,9 @@
                                       (<= new-qty 0) rest
                                       :else (conj rest {:qty new-qty :card card}))]
                   (om/set-state! owner [:deck :cards] new-cards))
-                (deck->str owner))))))
-
-    om/IDidUpdate
-    (did-update [this prev-props prev-state]
-      (let [deck (:deck prev-state)]
-        (when-not (some #{deck} decks)
-          (om/set-state! owner :deck (first (sort-by :date > decks))))))
+                (deck->str owner)))))
+      (go (while true
+            (om/set-state! owner :deck (<! select-channel)))))

     om/IRenderState
     (render-state [this state]
@@ -217,7 +219,7 @@
               [:h4 "You have no deck"]
               (for [deck (sort-by :date > decks)]
                 [:div.deckline {:class (when (= (:deck state) deck) "active")
-                                :on-click #(om/set-state! owner :deck deck)}
+                                :on-click #(put! select-channel deck)}
                  [:img {:src (image-url (:identity deck))}]
                  [:h4 (:name deck)]
                  [:div.float-right (-> (:date deck) js/Date. js/moment (.format "MMM Do YYYY - HH:mm"))]


Delete applications.clj

Delete applications.clj

--- bin/codestarter/views/applications.clj
+++ bin/codestarter/views/applications.clj
@@ -1,145 +0,0 @@
-(ns codestarter.views.applications
-  (:use codestarter.views.common
-        hiccup.core
-        hiccup.form-helpers
-        [hiccup.page-helpers :exclude (url)]
-        [korma.core :exclude (select* delete*)]
-        korma.db)
-  (:require [clojure.data :as data]
-            [clojure.string :as string]
-            [noir.validation :as vali]))
-
-(defn index [id {:keys [params] :as request}]
-  (body* [project (select-one projects (where {:id id}) (with applications (with users)))]
-         (= (project :type) "new [funding, lead]")
-         request
-         (html
-           (header project request)
-           (let [user-id (:id (get-user request))
-                 application (select-one applications
-                                         (where {:project_id id :user_id user-id})
-                                         (with users))]
-             (html
-               (if (and (not application) (not= (project :user_id) user-id))
-                 [:p (link-to {:class "button"} "create/" "create application")])
-               (if (empty? (project :applications))
-                 (html [:hr]
-                       [:div.item [:em "No applications"]])
-                 [:ul#applications.items
-                  (let [user-id? #(= (% :user_id) user-id)
-                        item #(vector
-                                :li.item
-                                [:h4 (link-to (url "users" (% :id_2)) (display %))]
-                                [:div (markdown (% :application))]
-                                (if (user-id? %)
-                                  (link-to {:class "button secondary tiny"}
-                                           (url "projects" id "applications" (% :id) "delete") "delete"))
-                                (if (= user-id (project :user_id))
-                                  (link-to {:class "button secondary tiny"}
-                                           (url "projects" id "applications" (% :id) "select") "select as lead")))]
-                    (html (if application (item application))
-                          (map item (filter #(not (user-id? %)) (project :applications)))))]))))))
-
-(defn create [id {:keys [params] :as request}]
-  (body* [project (select-one projects (where {:id id}))]
-         (if-let [user-id (get-user request :id)]
-           (and
-             (= (project :type) "new [funding, lead]")
-             (not= (project :user_id) user-id)
-             (empty? (select applications (where {:project_id id :user_id user-id})))))
-         request
-         (html
-           (header project (assoc request :uri (url "projects" id "applications")))
-           (form-to [:post "."]
-                    (csrf)
-                    (warning params)
-                    [:h4 "why should you lead this project?"]
-                    (wmd params :big true)
-                    [:hr]
-                    [:button.button "create application"]))
-         (do
-           (required params :accept?)
-           (vali/rule (vali/has-value? (params :wmd-input))
-                      [:wmd-input "... is required."]))
-         "..."
-         (let [user (get-user request)
-               application (insert applications (values {:project_id id
-                                                         :user_id (user :id)
-                                                         :time (timestamp)
-                                                         :application (params :wmd-input)}))]
-           (notify id
-                   user
-                   (application :time)
-                   :application
-                   nil
-                   (format "/projects/%s/applications/" id)
-                   (application :application))
-           (redirect (format "/projects/%s/applications/" id)))))
-
-(defn delete* [id application-id {:keys [params] :as request}]
-  (body* [application (select-one applications (where {:id application-id}) (with projects))]
-         (and (= (application :type) "new [funding, lead]")
-              (= (application :user_id) (get-user request :id)))
-         request
-         (html
-           (header application request :uri (url "projects" id "applications"))
-           (html
-             (form-to [:post "."]
-                      (csrf)
-                      [:div.alert-box.secondary
-                       [:h4 "Warning!"]
-                       [:p "You are about to delete your application."]
-                       (control :accept?
-                                [:label.controls (check-box :accept? (params :accept?)) "I understand and accept the responsibilties and consequences of this project."]
-                                :label "")]
-                      [:button.button "delete"])))
-         (required params :accept?)
-         "boom!"
-         (do
-           (delete applications (where {:id application-id}))
-           ;;(send-email id
-           ;;            :applications
-           ;;            (application :application)
-           ;;            id
-           ;;            (application :id)
-           ;;            (application :application)
-           ;;            (application :application)))
-           (redirect (format "/projects/%s/applications/" id)))))
-
-(defn select* [id application-id {:keys [params] :as request}]
-  (body* [application (select-one applications (where {:id application-id}) (with projects))]
-         (and (= (application :type) "new [funding, lead]")
-              (= (application :user_id) (get-user request :id)))
-         request
-         (html
-           (header application request :uri (url "projects" id "applications"))
-           (html
-             (form-to [:post "."]
-                      (csrf)
-                      [:div.alert-box.secondary
-                       [:h4 "Warning!"]
-                       [:p "You are about to select a lead for this project. By doing so, you will remain the project founder, but all control and responsibility will shift from you to the person you are selecting to be the lead."]
-                      (control :accept?
-                               [:label.controls (check-box :accept? (params :accept?)) "I understand and accept the responsibilties and consequences of this project."]
-                               :label "")]
-                      [:div
-                       [:h4 (link-to (url "users" (application :id)) (display application))]
-                       [:div (markdown (application :application))]]
-                      [:hr]
-                      [:button.button "select as lead"])))
-         (required params :accept?)
-         "boom!"
-         (let [project (update projects (set-fields {:edit_time (timestamp)
-                                                     :user_id (application :user_id )
-                                                     :type "new [funding]"
-                                                     :changes "lead"})
-                               (where {:id id}))]
-           (delete applications (where {:id application-id}))
-           (notify id
-                   (project :user_id)
-                   (project :edit_time)
-                   :edit
-                   (project :changes)
-                   (url "projects" id)
-                   (project :changes))
-           (redirect (url "projects" id)))))


Typo.

Typo.

--- src-cljs/frontend/components/app.cljs
+++ src-cljs/frontend/components/app.cljs
@@ -125,7 +125,7 @@
              [:div#app {:class (concat [(if inner? "inner" "outer")]
                                        (when-not logged-in? ["aside-nil"])
                                        (when (feature/enabled? :ui-v2) ["ui-v2"])
-                                       ;; The following 2 are meant for the landing ab test to hide old heaqder/footer
+                                       ;; The following 2 are meant for the landing ab test to hide old header/footer
                                        (when (= :landing (:navigation-point app)) ["landing"])
                                        (when (= :pricing (:navigation-point app)) ["pricing"]))}
               (om/build keyq/KeyboardHandler app-without-container-data


Minor readme changes.

Minor readme changes.

--- src/zprint/zprint.cljc
+++ src/zprint/zprint.cljc
@@ -1169,6 +1169,12 @@
                  options)]
         #_(def jo (conj jo [justify-width justify-options]))
         (let [beginning-coll (butlast coll)
+	      ; If beginning-coll is () because there is only a single pair
+	      ; in coll, then this all works -- but only because
+	      ; () is truthy, and zpmap returns () which is also truthy.
+	      ; I hate relying on the truthy-ness of (), but in this case
+	      ; it works out and it would be even more complicated to do
+	      ; it another way.
               beginning-remaining
                 (if one-line? (fit-within? (- width ind) beginning-coll) true)
               _ (dbg options


Choose grid BPC from a dropdown.

Choose grid BPC from a dropdown.

--- sonic-jam/src/sonic_jam/core.cljs
+++ sonic-jam/src/sonic_jam/core.cljs
@@ -46,6 +46,8 @@
                           :synths []
                           :types ["synth" "sample" "grid"]
                           :grid-types ["synth" "sample"]
+                          :bpc-values ["1/32" "1/16" "1/8" "1/4" "1/2"
+                                       "1" "2" "4" "8" "16" "32"]
                           :errors []
                           :console []
                           :beat-cursors []}))
@@ -67,6 +69,9 @@

 (defn synths []
   (om/ref-cursor (:synths (om/root-cursor app-state))))
+
+(defn bpc-values []
+  (om/ref-cursor (:bpc-values (om/root-cursor app-state))))

 (defn handle-change [e owner state key]
   (om/set-state! owner key (.. e -target -value)))
@@ -330,6 +335,9 @@
 (def sample-editor
   (select-editor-builder "sample" samples))

+(def bpc-editor
+  (select-editor-builder "bpc" bpc-values))
+
 (def type-editor
   (select-editor-builder "type" types
                          (fn [{:keys [cursor id set-state-ch key value owner]}]
@@ -338,7 +346,7 @@
                              (let [grid-id (new-id)
                                    grid {"name" ""
                                          "id" grid-id
-                                         "bpc" 1
+                                         "bpc" "1"
                                          "tracks" []}]
                                (om/transact! cursor (fn [c] (assoc c
                                                                    "type" value
@@ -616,7 +624,7 @@
                                            :get-state-ch (:get-state-ch state)}]
                             (om/build grid-view {:id id :beat-cursors (second beat-cursors)} {:state sub-state})))))))))

-(defn grid-editor [{:keys [id cursor set-state-ch]} owner]
+(defn grid-editor [{:keys [name id cursor set-state-ch], :as inputs} owner]
   (reify
     om/IInitState
     (init-state [_]
@@ -664,42 +672,35 @@
                         (om/transact! cursor (fn [c] (assoc c "tracks" (clj->js halved-tracks))))
                         (go (>! set-state-ch id)))]
         (condp = (:state state)
-          :init (dom/span #js {:onClick #(transition {:state :open})
-                               :style #js {:color (:link theme)}}
-                          "{..}")
-          :open (dom/span nil
-                          (closer "{")
-                          (dom/span nil
-                                    (dom/span nil " bpc: ")
-                                    (dom/span #js {:onClick #(transition {:state :editing-bpc})
-                                                   :style #js {:color (:link theme)}}
-                                              (str (get cursor "bpc"))))
-                          (dom/span nil
-                                    (dom/span nil " width: ")
-                                    (dom/span #js {:onClick double-width
-                                                   :style #js {:color (:link theme)}} "+")
-                                    (dom/span nil "/")
-                                    (dom/span #js {:onClick half-width
-                                                   :style #js {:color (:link theme)}} "-"))
-                          (dom/span nil
-                                    (dom/span nil " res ")
-                                    (dom/span #js {:onClick double-res
-                                                   :style #js {:color (:link theme)}} "+")
-                                    (dom/span nil "/")
-                                    (dom/span #js {:onClick half-res
-                                                   :style #js {:color (:link theme)}} "-"))
-                          (dom/span nil " }"))
-          :editing-bpc (dom/span nil
-                                 (closer "{ ")
-                                 (dom/span nil
-                                           (dom/span nil "bpc: "))
-                                 (dom/input #js {:type "text" :value (:bpc state)
-                                                 :onChange #(handle-change % owner state :bpc)
-                                                 :onKeyDown #(when (= 13 (.-which %))
-                                                               (transition {:state :open})
-                                                               (om/transact! cursor (fn [c] (assoc c "bpc"(:bpc state))))
-                                                               (go (>! set-state-ch id)))})
-                                 (dom/span nil " }")))))))
+          :init (dom/table nil
+                           (dom/tbody nil
+                                      (dom/tr nil
+                                              (dom/td nil (str name " "))
+                                              (dom/td #js {:onClick #(transition {:state :open})
+                                                           :style #js {:color (:link theme)}}
+                                                      "{..}"))))
+          :open (dom/table nil
+                           (dom/tbody nil
+                                      (dom/tr nil
+                                              (dom/td nil (str name " "))
+                                              (dom/td nil (closer "{"))
+                                              (dom/td nil " bpc: ")
+                                              (dom/td nil (om/build bpc-editor inputs))
+                                              (dom/td nil " ")
+                                              (dom/td nil " width: ")
+                                              (dom/td #js {:onClick double-width
+                                                           :style #js {:color (:link theme)}} "+")
+                                              (dom/td nil "/")
+                                              (dom/td #js {:onClick half-width
+                                                           :style #js {:color (:link theme)}} "-")
+                                              (dom/td nil " ")
+                                              (dom/td nil " res ")
+                                              (dom/td #js {:onClick double-res
+                                                           :style #js {:color (:link theme)}} "+")
+                                              (dom/td nil "/")
+                                              (dom/td #js {:onClick half-res
+                                                           :style #js {:color (:link theme)}} "-")
+                                              (dom/td nil " }")))))))))

 (defn grid-view [{:keys [id beat-cursors]} owner]
   (reify
@@ -733,9 +734,9 @@
                                       (if-not (:grid-expanded state)
                                         (dom/div nil " ")
                                         (dom/div nil
-                                                 (dom/p style-grey
-                                                        (dom/span nil (str name " "))
-                                                        (om/build grid-editor {:id id
+                                                 (dom/div style-grey
+                                                        (om/build grid-editor {:name name
+                                                                               :id id
                                                                                :set-state-ch (:set-state-ch state)
                                                                                :cursor cursor}))
                                                  (dom/table nil


quick fix for editing name

quick fix for editing name

--- src-cljs/frontend/components/chat.cljs
+++ src-cljs/frontend/components/chat.cljs
@@ -208,18 +208,22 @@
                 [:form {:on-submit #(do (when-not (str/blank? new-name)
                                           (cast! :self-updated {:name new-name}))
                                         (om/set-state! owner :editing-name? false)
-                                        false)
+                                        (om/set-state! owner :new-name "")
+                                        (utils/stop-event %))
                         :on-blur #(do (when-not (str/blank? new-name)
                                         (cast! :self-updated {:name new-name}))
                                       (om/set-state! owner :editing-name? false)
-                                      false)
+                                      (om/set-state! owner :new-name "")
+                                      (utils/stop-event %))
                         :on-key-down #(when (= "Escape" (.-key %))
                                         (om/set-state! owner :editing-name? false)
                                         (om/set-state! owner :new-name "")
-                                        false)}
+                                        (utils/stop-event %))}
                  [:input {:type "text"
                           :ref "name-edit"
                           :tab-index 1
+                          ;; TODO: figure out why we need value here
+                          :value new-name
                           :on-change #(om/set-state! owner :new-name (.. % -target -value))}]]
                 [:span (or (get-in app [:cust :name]) "You")])])
            (for [[id {:keys [show-mouse? color cust-name]}] (dissoc (:subscribers app) client-id)


Don't have 2 h1 tags in jobs page

Don't have 2 h1 tags in jobs page

--- src-cljs/frontend/components/jobs.cljs
+++ src-cljs/frontend/components/jobs.cljs
@@ -16,8 +16,10 @@
       (html
        [:div.jobs.page
         [:div.jobs-head
-         [:h1 "Build amazing products"]
-         [:h1 "with a great team"]]
+         [:h1
+          "Build amazing products"
+          [:br]
+          "with a great team"]]
         [:div.jobs-body
          [:div.jobs-types
           [:a {:href "#engineer"} [:i.fa.fa-code] [:h3 "Engineering"]]


remove identical? check on strings in get-expander-ns for ClojureScript JVM

--- src/main/clojure/cljs/analyzer.cljc
+++ src/main/clojure/cljs/analyzer.cljc
@@ -2265,16 +2265,13 @@

 (defn get-expander-ns [env ^String nstr]
   (cond
-    (identical? "clojure.core" nstr)
-    #?(:clj  (find-ns 'cljs.core)
-       :cljs (find-macros-ns CLJS_CORE_MACROS_SYM))
-    (identical? "clojure.repl" nstr)
-    #?(:clj  (find-ns 'cljs.repl)
-       :cljs (find-macros-ns 'cljs.repl))
-    #?@(:clj  [(.contains nstr ".") (find-ns (symbol nstr))]
-        :cljs [(goog.string/contains nstr ".") (find-macros-ns (symbol nstr))])
-    :else
-    (some-> env :ns :require-macros (get (symbol nstr)) find-ns)))
+    #?@(:clj  [(= "clojure.core" nstr)          (find-ns 'cljs.core)]
+        :cljs [(identical? "clojure.core" nstr) (find-macros-ns CLJS_CORE_MACROS_SYM)])
+    #?@(:clj  [(= "clojure.repl" nstr)          (find-ns 'cljs.repl)]
+        :cljs [(identical? "clojure.repl" nstr) (find-macros-ns 'cljs.repl)])
+    #?@(:clj  [(.contains nstr ".")             (find-ns (symbol nstr))]
+        :cljs [(goog.string/contains nstr ".")  (find-macros-ns (symbol nstr))])
+    :else (some-> env :ns :require-macros (get (symbol nstr)) find-ns)))

 (defn get-expander* [sym env]
   (when-not (or (not (nil? (gets env :locals sym))) ; locals hide macros