:editor-xform uses simple dispatch instead of multimethods

--- cljs/src/worker/plastic/worker/editor/xforms.cljs
+++ cljs/src/worker/plastic/worker/editor/xforms.cljs
@@ -5,70 +5,37 @@
             [plastic.worker.schema.paths :as paths]
             [plastic.worker.editor.xforms.editing :as editing]))

-(defmulti handle (fn [command & _] command))
+(def ops
+  {:edit-node                         editing/edit-node
+   :enter                             editing/enter
+   :alt-enter                         editing/alt-enter
+   :space                             editing/space
+   :backspace                         editing/backspace
+   :delete                            editing/delete
+   :alt-delete                        editing/alt-delete
+   :open-list                         editing/open-list
+   :open-vector                       editing/open-vector
+   :open-map                          editing/open-map
+   :open-set                          editing/open-set
+   :open-fn                           editing/open-fn
+   :open-meta                         editing/open-meta
+   :open-quote                        editing/open-quote
+   :open-deref                        editing/open-deref
+   :insert-placeholder-as-first-child editing/insert-placeholder-as-first-child})

-; ----------------------------------------------------------------------------------------------------------------
+; ----------------------------------------------------------------------------------------------------------------------

-(defmethod handle :edit-node [_ editor edit-point value]
-  (editing/edit-node editor edit-point value))
+(defn dispatch-command [editors [editor-id xform & args]]
+  (let [old-editor (get editors editor-id)]
+    (if-let [handler (xform ops)]
+      (if-let [new-editor (apply handler old-editor args)]
+        (assoc-in editors [editor-id] new-editor)
+        editors)
+      (do
+        (error (str "Unknown editor xform for dispatch '" xform "'"))
+        editors))))

-(defmethod handle :enter [_ editor edit-point]
-  (editing/enter editor edit-point))
-
-(defmethod handle :alt-enter [_ editor edit-point]
-  (editing/alt-enter editor edit-point))
-
-(defmethod handle :space [_ editor edit-point]
-  (editing/space editor edit-point))
-
-(defmethod handle :backspace [_ editor edit-point]
-  (editing/backspace editor edit-point))
-
-(defmethod handle :delete [_ editor edit-point]
-  (editing/delete editor edit-point))
-
-(defmethod handle :alt-delete [_ editor edit-point]
-  (editing/alt-delete editor edit-point))
-
-(defmethod handle :open-list [_ editor edit-point]
-  (editing/open-list editor edit-point))
-
-(defmethod handle :open-vector [_ editor edit-point]
-  (editing/open-vector editor edit-point))
-
-(defmethod handle :open-map [_ editor edit-point]
-  (editing/open-map editor edit-point))
-
-(defmethod handle :open-set [_ editor edit-point]
-  (editing/open-set editor edit-point))
-
-(defmethod handle :open-fn [_ editor edit-point]
-  (editing/open-fn editor edit-point))
-
-(defmethod handle :open-meta [_ editor edit-point]
-  (editing/open-meta editor edit-point))
-
-(defmethod handle :open-quote [_ editor edit-point]
-  (editing/open-quote editor edit-point))
-
-(defmethod handle :open-deref [_ editor edit-point]
-  (editing/open-deref editor edit-point))
-
-(defmethod handle :insert-placeholder-as-first-child [_ editor edit-point]
-  (editing/insert-placeholder-as-first-child editor edit-point))
-
-; ----------------------------------------------------------------------------------------------------------------
-
-(defmethod handle :default [command]
-  (error (str "Unknown editor command for dispatch '" command "'")))
-
-(defn dispatch-command [editors [editor-id command & args]]
-  (let [old-editor (get editors editor-id)]
-    (if-let [new-editor (apply handle command old-editor args)]
-      (assoc-in editors [editor-id] new-editor)
-      editors)))
-
-; ----------------------------------------------------------------------------------------------------------------
+; ----------------------------------------------------------------------------------------------------------------------
 ; register handlers

 (register-handler :editor-xform paths/editors-path dispatch-command)


Fix bug where dropdown options would not appear when clicking toggle button

--- src/reabledit/cells/dropdown.cljs
+++ src/reabledit/cells/dropdown.cljs
@@ -69,7 +69,8 @@
      {:component-did-mount
       (fn [this]
         (util/add-blur-emulator! state
-                                 #(if-not (dom/contains this (.-target %))
+                                 #(if-not (dom/getAncestorByClass (.-target %)
+                                                                  "reabledit-dropdown-cell")
                                     (swap! state dissoc :edit? :selected))))
       :component-will-unmount
       (fn [_]


Don't allow admin users to suspend themselves

Or to remove their admin privileges.

--- src-cljs/frontend/components/admin.cljs
+++ src-cljs/frontend/components/admin.cljs
@@ -216,44 +216,46 @@
     "read-settings" "read-only admin"
     "none"))

-(defn user [{:keys [user admin-write-scope?]} owner]
-  (reify
-    om/IRender
-    (render [_]
-      (html
-        [:li
-         (:login user)
-         " "
-         (when admin-write-scope?
-           (let [action (if (:suspended user) :unsuspend-user :suspend-user)]
-             [:button.btn.btn-xs.btn-default
-              {:on-click #(raise! owner [action (select-keys user [:login])])}
-              (case action
-                :suspend-user "suspend"
-                :unsuspend-user "activate")]))
-         " "
-         (let [relevant-scope (-> user :admin_scopes relevant-scope)]
-           (if admin-write-scope?
-             [:div.btn-group.btn-group-xs
-              [:button.btn.btn-default
-               (if (= "write-settings" relevant-scope)
-                 {:class "active"}
-                 {:on-click #(raise! owner [:set-admin-scope
-                                            {:login (:login user)
-                                             :scope :write-settings}])})
-               "admin"]
-              ;; read-settings generally hidden for until we sort out what we
-              ;; really want the scope precision to be
-              (when (= "read-settings" relevant-scope)
-                [:button.btn.btn-default.active "read-only admin"])
-              [:button.btn.btn-default
-               (if (= "none" relevant-scope)
-                 {:class "active"}
-                 {:on-click #(raise! owner [:set-admin-scope
-                                            {:login (:login user)
-                                             :scope :none}])})
-               "none"]]
-             (-> user :admin_scopes admin-in-words)))]))))
+(defn user [{:keys [user current-user]} owner]
+  (reify
+    om/IRender
+    (render [_]
+      (let [show-suspend-unsuspend? (and (#{"all" "write-settings"} (:admin current-user))
+                                         (not= (:login current-user) (:login user)))]
+        (html
+          [:li
+           (:login user)
+           " "
+           (when show-suspend-unsuspend?
+             (let [action (if (:suspended user) :unsuspend-user :suspend-user)]
+               [:button.btn.btn-xs.btn-default
+                {:on-click #(raise! owner [action (select-keys user [:login])])}
+                (case action
+                  :suspend-user "suspend"
+                  :unsuspend-user "activate")]))
+           " "
+           (let [relevant-scope (-> user :admin_scopes relevant-scope)]
+             (if show-suspend-unsuspend?
+               [:div.btn-group.btn-group-xs
+                [:button.btn.btn-default
+                 (if (= "write-settings" relevant-scope)
+                   {:class "active"}
+                   {:on-click #(raise! owner [:set-admin-scope
+                                              {:login (:login user)
+                                               :scope :write-settings}])})
+                 "admin"]
+                ;; read-settings generally hidden for until we sort out what we
+                ;; really want the scope precision to be
+                (when (= "read-settings" relevant-scope)
+                  [:button.btn.btn-default.active "read-only admin"])
+                [:button.btn.btn-default
+                 (if (= "none" relevant-scope)
+                   {:class "active"}
+                   {:on-click #(raise! owner [:set-admin-scope
+                                              {:login (:login user)
+                                               :scope :none}])})
+                 "none"]]
+               (-> user :admin_scopes admin-in-words)))])))))

 (defn users [app owner]
   (reify
@@ -274,8 +276,7 @@
             inactive-users (filter #(and (zero? (:sign_in_count %))
                                          (not (:suspended %)))
                                    all-users)
-            admin-write-scope? (#{"all" "write-settings"}
-                                (get-in app [:current-user :admin]))
+            current-user (:current-user app)
             num-licensed-users (get-in app (conj state/license-path :seats))
             num-active-users (get-in app (conj state/license-path :seat_usage))]
         (html
@@ -288,22 +289,22 @@

           [:h2 "active"]
           [:ul (om/build-all user (mapv (fn [u] {:user u
-                                                 :admin-write-scope? admin-write-scope?})
+                                                 :current-user current-user})
                                         active-users))]

           [:h2 "suspended"]
           [:ul (om/build-all user (mapv (fn [u] {:user u
-                                                 :admin-write-scope? admin-write-scope?})
+                                                 :current-user current-user})
                                         suspended-users))]

           [:h2 "suspended new users"]
           [:ul (om/build-all user (mapv (fn [u] {:user u
-                                                 :admin-write-scope? admin-write-scope?})
+                                                 :current-user current-user})
                                         suspended-new-users))]

           [:h2 "inactive users"]
           [:ul (om/build-all user (mapv (fn [u] {:user u
-                                                 :admin-write-scope? admin-write-scope?})
+                                                 :current-user current-user})
                                         inactive-users))]])))))

 (defn boolean-setting-entry [item owner]


Make the links be links

Make the links be links

--- src-cljs/frontend/components/admin.cljs
+++ src-cljs/frontend/components/admin.cljs
@@ -29,7 +29,7 @@
          [:section {:style {:padding-left "10px"}}
           [:a {:href "/api/v1/admin/build-state" :target "_blank"} "View raw"]
           " / "
-          [:a {:on-click #(raise! owner [:refresh-admin-build-state-clicked])} "Refresh"]
+          [:a {:href "javascript:void(0)" :on-click #(raise! owner [:refresh-admin-build-state-clicked])} "Refresh"]
           (if-not build-state
             [:div.loading-spinner common/spinner]
             [:code (om/build ankha/inspector build-state)])])))))
@@ -101,7 +101,7 @@
          [:header {:style {:padding-top "10px"}}
           [:a {:href "/api/v1/admin/build-state-summary" :target "_blank"} "View raw"]
           " / "
-          [:a {:on-click #(raise! owner [:refresh-admin-fleet-state-clicked])} "Refresh"]]
+          [:a {:href "javascript:void(0)" :on-click #(raise! owner [:refresh-admin-fleet-state-clicked])} "Refresh"]]
          (if-not builders
            [:div.loading-spinner common/spinner]
            (if-not (seq builders)


Show Workflows in aside on Enterprise

Show Workflows in aside on Enterprise

--- src-cljs/frontend/components/aside.cljs
+++ src-cljs/frontend/components/aside.cljs
@@ -508,14 +508,13 @@
       [:i.material-icons "storage"]
       [:div.nav-label "Builds"]]

-     (when-not (config/enterprise?)
-       [:a.aside-item {:class (when (contains? state/workflows-routes current-route) "current")
-                       :data-placement "right"
-                       :data-trigger "hover"
-                       :title "Workflows"
-                       :href (routes/v1-workflows)}
-        (icon/workflows)
-        [:div.nav-label "Workflows"]])
+     [:a.aside-item {:class (when (contains? state/workflows-routes current-route) "current")
+                     :data-placement "right"
+                     :data-trigger "hover"
+                     :title "Workflows"
+                     :href (routes/v1-workflows)}
+      (icon/workflows)
+      [:div.nav-label "Workflows"]]

      [:a.aside-item {:class (when (contains? state/insights-routes current-route)
                               "current")
@@ -637,16 +636,15 @@
       [:i.material-icons "storage"]
       [:div.nav-label "Builds"]]

-     (when-not (config/enterprise?)
-       [:a.aside-item {:class (when (contains? state/workflows-routes current-route)
-                                "current")
-                       :data-placement "right"
-                       :data-trigger "hover"
-                       :title "Workflows"
-                       :href (routes/v1-org-workflows-path (:vcs_type org)
-                                                           (:org org))}
-        (icon/workflows)
-        [:div.nav-label "Workflows"]])
+     [:a.aside-item {:class (when (contains? state/workflows-routes current-route)
+                              "current")
+                     :data-placement "right"
+                     :data-trigger "hover"
+                     :title "Workflows"
+                     :href (routes/v1-org-workflows-path (:vcs_type org)
+                                                         (:org org))}
+      (icon/workflows)
+      [:div.nav-label "Workflows"]]

      [:a.aside-item {:class (when (contains? state/insights-routes current-route)
                               "current")


disable trial button when not signed in

disable trial button when not signed in

--- src-cljs/frontend/components/outer.cljs
+++ src-cljs/frontend/components/outer.cljs
@@ -172,8 +172,9 @@
   (reify
     om/IDisplayName (display-name [_] "Solo signup")
     om/IRenderState
-    (render-state [_ {:keys [trial-created? disabled? submitting? submitted? error]}]
-      (let [{:keys [cast!]} (om/get-shared owner)]
+    (render-state [_ {:keys [trial-created? submitting? submitted? error]}]
+      (let [{:keys [cast!]} (om/get-shared owner)
+            disabled? (or submitting? (not (utils/logged-in? owner)))]
         (html
          [:div.page-trial.page-form
           [:div.content


Don't need mdl

Don't need mdl

--- src-frontend/cljs/cljs_webrepl/mdl.cljs
+++ src-frontend/cljs/cljs_webrepl/mdl.cljs
@@ -1,28 +0,0 @@
-(ns cljs-webrepl.mdl
-  (:require
-   [reagent.core :as r]
-   [cljsjs.material :as material]
-   [taoensso.timbre :as timbre
-    :refer-macros (tracef debugf infof warnf errorf)]))
-
-(defn upgrade-element
-  "Upgrade an element using MDL's componentHandler"
-  [node]
-  (.upgradeElements js/componentHandler (r/dom-node node)))
-
-(defn downgrade-element
-  "Upgrade an element using MDL's componentHandler"
-  [node]
-  (.downgradeElements js/componentHandler (r/dom-node node)))
-
-(defn upgrade
-  "Returns a reagent class that upgrades a child element using MDL's
-  componentHandler.
-
-  Example:
-  [mdl/upgrade [:button.mdl-button.mdl-js-button \"Hi\"]]"
-  [child]
-  (r/create-class
-   {:display-name        "mdl-upgrade"
-    :component-did-mount upgrade-element
-    :reagent-render      (fn [child] child)}))


Disable setTimeout test

Disable setTimeout test

This test can't really work because of the single-threaded
nature of JavaScript.

Former-commit-id: 7ec0389b8827add2609a0e83b064d6a714d704df

--- planck-cljs/test/planck/core_test.cljs
+++ planck-cljs/test/planck/core_test.cljs
@@ -8,7 +8,7 @@
   (testing "exit sets global exit code"
     (is (= 112 (js/PLANCK_GET_EXIT_VALUE)))))

-(deftest setTimeout-can-be-used
+#_(deftest setTimeout-can-be-used
   "This test is intentionally a bit naieve since async macros wouldn't work at time of writing"
   (testing "setTimeout actually gets called and does something"
     (let [now #(.getTime (js/Date.))


Look for sendmail in common locations.

Look for sendmail in common locations.

--- src/clj/com/draines/postal/sendmail.clj
+++ src/clj/com/draines/postal/sendmail.clj
@@ -1,5 +1,13 @@
 (ns com.draines.postal.sendmail
   (:use [com.draines.postal.message :only [message->str sender recipients]]))
+
+(def sendmails ["/usr/lib/sendmail"
+                "/usr/sbin/sendmail"
+                "/usr/bin/sendmail"
+                "/usr/local/lib/sendmail"
+                "/usr/local/sbin/sendmail"
+                "/usr/local/bin/sendmail"
+                "/usr/sbin/msmtp"])

 (def errors {0  [:SUCCESS        "message sent"]
              64 [:EX_USAGE       "command line usage error"]
@@ -24,10 +32,13 @@
      :error e
      :message message}))

+(defn sendmail-find []
+  (first (filter #(.isFile (java.io.File. %)) sendmails)))
+
 (defn sendmail-send [msg]
   (let [mail (message->str msg)
         cmd (concat
-             ["/usr/sbin/sendmail" (format "-f %s" (sender msg))]
+             [(sendmail-find) (format "-f %s" (sender msg))]
              (recipients msg))
         pb (ProcessBuilder. cmd)
         p (.start pb)


Accept caps in email address

Accept caps in email address


generalize route props

generalize route props

--- src/cljs/daveconservatoire/site/ui.cljs
+++ src/cljs/daveconservatoire/site/ui.cljs
@@ -89,9 +89,9 @@

 (defmethod r/route->component ::r/about [_] AboutPage)

-(defn topic-props [c]
+(defn route-props [c [k route-param]]
   (let [{:keys [app/route] :as props} (if (om/component? c) (om/props c) c)]
-    (get props [:topic/by-slug (get-in route [:route-params ::r/slug])])))
+    (get props [k (get-in route [:route-params route-param])])))

 (om/defui ^:once TopicPage
   static uc/InitialAppState
@@ -111,7 +111,7 @@

   Object
   (render [this]
-    (let [props (topic-props this)]
+    (let [props (route-props this [:topic/by-slug ::r/slug])]
       (dom/div nil
         "Topic" (pr-str props)))))


pretty cli help formatting

pretty cli help formatting

--- src/clojure/zensols/actioncli/parse.clj
+++ src/clojure/zensols/actioncli/parse.clj
@@ -83,7 +83,8 @@
   ([{:keys [name description options] :as command} max-len]
    (str (format (str "%-" (+ 4 max-len) "s") name)
         description \newline
-        (:summary (parse-opts nil options)) \newline)))
+        (:summary (parse-opts nil options))
+        (if-not (empty? options) \newline))))

 (defn- help-msg [command-context commands command-key]
   (let [{:keys [print-help-fn]} command-context


Add docstrings to route resolution file

Add docstrings to route resolution file

--- src/cmr/plugin/jar/types/web/routes.clj
+++ src/cmr/plugin/jar/types/web/routes.clj
@@ -11,17 +11,32 @@
   (java.util.jar JarFile)))

 (defn resolve-routes
+  "This function wraps a utility function for resolving fully-qualified
+  function names. What this offers over the utility function is the capability
+  of wrapping multiple functions at ones, and removing any functions that
+  don't resolve."
   [routes-symbols]
   (->> routes-symbols
        (map #(util/resolve-fully-qualified-fn %))
        (remove nil?)))

 (defn plugin-routes
+  "Given a:
+    * jarfile
+    * an in-jarfile path to the plugin's configuration file
+    * the configuration value that points to the route-keys, and
+    * the configuration values that point to the api-key and site-key
+  perform the actual lookup of the plugin routes in the plugin configuration,
+  and assemble these into a data structure that can later be transformed into
+  a hashmap."
   [^JarFile jarfile in-jar-filepath route-keys ^Keyword api-key ^Keyword site-key]
   (let [data (get-in (plugin/config-data jarfile in-jar-filepath) route-keys)]
     [(api-key data) (site-key data)]))

 (defn plugins-routes
+  "Perform the assembly done in `plugin-routes` over one or more jarfiles,
+  converting the final data structure into a hashmap for easy lookup by the
+  application or service that is managing these plugins."
   [jarfiles in-jar-filepath route-keys ^Keyword api-key ^Keyword site-key]
   (let [data (map #(plugin-routes % in-jar-filepath route-keys api-key site-key)
                   jarfiles)]
@@ -29,6 +44,14 @@
      site-key (vec (remove nil? (map second data)))}))

 (defn resolved-routes-fns
+  "This function offers the convenience of locating all of the plugins that
+  had declared themselves of the given name (e.g. 'CMR-Plugin') and type
+  (e.g. 'service-bridge-app'), and once located, performing the function
+  resolution and final data structure creation as done above.
+
+  Note: this function has been refactored several times, and the need for
+  this function vs the `plugins-routes` function above is now questionable,
+  worth determining, and possibly refactoring."
   ([^String plugin-name ^String plugin-type in-jar-filepath route-keys
     ^Keyword api-key ^Keyword site-key]
     (resolved-routes-fns (plugin/jarfiles plugin-name plugin-type)


Tweaked comment.

Tweaked comment.

--- src/com/lemondronor/leaflet_gorilla.clj
+++ src/com/lemondronor/leaflet_gorilla.clj
@@ -91,7 +91,7 @@
    :opacity 1.0})

-;; Might as well use an ID for this tags that theoretically some other
+;; Might as well use an ID for the CSS that theoretically some other
 ;; renderer could reference.
 (def leaflet-css-tag-id "leaflet-css")


Hide dropdown when no focus

Hide dropdown when no focus

--- src/gigrig/components/pedal_search.cljs
+++ src/gigrig/components/pedal_search.cljs
@@ -1,10 +1,13 @@
 (ns gigrig.components.pedal-search
   (:require [redux.core :refer [dispatch!]]
+            [reagent.core :as reagent]
             [gigrig.actions :as a]))

-(defn- search-field [{:keys [handle-change]}]
+(defn- search-field [{:keys [on-focus on-blur handle-change]}]
   [:input {:type "text"
            :placeholder "Search for a pedal"
+           :on-focus on-focus
+           :on-blur on-blur
            :on-change #(handle-change (.. % -target -value))}])

 (defn- suggestion [i props]
@@ -16,7 +19,12 @@
   [:ul
    (map-indexed suggestion (:suggestions props))])

-(defn component [props]
-  [:div
-   [search-field {:handle-change (fn [val] (dispatch! a/searchfield-key-pressed val))}]
-   [dropdown (select-keys props [:suggestions])]])
+(defn component []
+  (let [dropdown-visible (reagent/atom false)]
+    (fn [props]
+      [:div
+       [search-field {:on-focus #(do (reset! dropdown-visible true) nil)
+                      :on-blur #(do (reset! dropdown-visible false) nil)
+                      :handle-change (fn [val] (dispatch! a/searchfield-key-pressed val))}]
+       (if @dropdown-visible
+         [dropdown (select-keys props [:suggestions])])])))


Upgrade 'lein-isolate'

Upgrade 'lein-isolate'

--- lein-ancient/project.clj
+++ lein-ancient/project.clj
@@ -31,7 +31,7 @@
                   :scope "provided"]]
   :scm {:dir ".."}

-  :plugins [[lein-isolate "0.1.2"]]
+  :plugins [[lein-isolate "0.2.1"]]
   :middleware [leiningen.isolate/middleware]

   :eval-in :leiningen


store :last-saved info

store :last-saved info

--- iwaswhere-web/src/clj/iwaswhere_web/files.clj
+++ iwaswhere-web/src/clj/iwaswhere_web/files.clj
@@ -9,7 +9,8 @@
             [clj-time.format :as timef]
             [clojure.tools.logging :as log]
             [iwaswhere-web.fulltext-search :as ft]
-            [ubergraph.core :as uber]))
+            [ubergraph.core :as uber]
+            [matthiasn.systems-toolbox.component :as st]))

 (def data-path (or (System/getenv "DATA_PATH") "data"))
 (def daily-logs-path (str data-path "/daily-logs/"))
@@ -54,11 +55,12 @@
   "Handler function for persisting journal entry."
   [{:keys [current-state msg-payload]}]
   (let [entry-ts (:timestamp msg-payload)
-        new-state (ga/add-node current-state entry-ts msg-payload)]
-    (ft/add-to-index (:lucene-index current-state) msg-payload)
-    (append-daily-log msg-payload)
+        with-last-modified (merge msg-payload {:last-saved (st/now)})
+        new-state (ga/add-node current-state entry-ts with-last-modified)]
+    (ft/add-to-index (:lucene-index current-state) with-last-modified)
+    (append-daily-log with-last-modified)
     {:new-state    new-state
-     :emit-msg     [:entry/saved msg-payload]
+     :emit-msg     [:entry/saved with-last-modified]
      :send-to-self [[:state/stats-tags]
                     [:state/publish-current {}]]}))


Use arg-or-default

Use arg-or-default

--- src/onyx/messaging/messenger_buffer.clj
+++ src/onyx/messaging/messenger_buffer.clj
@@ -1,7 +1,7 @@
 (ns ^:no-doc onyx.messaging.messenger-buffer
   (:require [clojure.core.async :refer [chan >!! <!! thread alts!! close! sliding-buffer]]
             [com.stuartsierra.component :as component]
-            [onyx.static.default-vals :refer [defaults]]
+            [onyx.static.default-vals :refer [defaults arg-or-default]]
             [taoensso.timbre :as timbre]))

 (defrecord MessengerBuffer [opts]
@@ -10,8 +10,7 @@
   (start [component]
     (taoensso.timbre/info "Starting Messenger Buffer")

-    (let [inbound-ch (chan (sliding-buffer (or (:onyx.messaging/inbound-buffer-size opts)
-                                               (:onyx.messaging/inbound-buffer-size defaults))))]
+    (let [inbound-ch (chan (sliding-buffer (arg-or-default :onyx.messaging/inbound-buffer-size opts)))]
       (assoc component :inbound-ch inbound-ch)))

   (stop [component]


Update chart logger; detailed generation analysis

- use box and whisker chart to provide statistics bout each generation

--- clojure/src/evolution_programs/logging/chart.clj
+++ clojure/src/evolution_programs/logging/chart.clj
@@ -2,16 +2,16 @@
   (:require [evolution-programs.util.population-statistic :as stat])
   (:import [javax.swing BoxLayout JFrame]
            [org.jfree.chart ChartFactory ChartPanel StandardChartTheme]
-           [org.jfree.data.category CategoryDataset DefaultCategoryDataset]
            [org.jfree.data.function Function2D]
            [org.jfree.data.general DatasetUtilities]
-           [org.jfree.data.xy XYDataset XYSeries XYSeriesCollection]))
+           [org.jfree.data.xy XYSeries XYSeriesCollection]
+           [org.jfree.data.statistics BoxAndWhiskerCategoryDataset DefaultBoxAndWhiskerCategoryDataset]))

 (ChartFactory/setChartTheme (StandardChartTheme. "JFree/Shadow" true))

 (defmulti ^:private chart class)

-(defmethod chart XYDataset [dataset]
+(defmethod chart XYSeriesCollection [dataset]
   (doto (ChartFactory/createXYLineChart "Curve of function" "X" "Y" dataset)
     (->
       (.getXYPlot)
@@ -20,12 +20,8 @@
         (.setSeriesLinesVisible 0 false)
         (.setSeriesShapesVisible 0 true)))))

-(defmethod chart CategoryDataset [dataset]
-  (doto (ChartFactory/createLineChart "Population Analysis" "Generation" "Fitness" dataset)
-    (->
-      (.getCategoryPlot)
-      (.getRenderer)
-      (.setShapesVisible true))))
+(defmethod chart BoxAndWhiskerCategoryDataset [dataset]
+  (ChartFactory/createBoxAndWhiskerChart "Population Analysis" "Generation" "Fitness" dataset false))

 (defn- panel [chart]
   (doto (ChartPanel. chart)
@@ -52,26 +48,30 @@
   (doto (XYSeriesCollection. (XYSeries. "Individual"))
     (.addSeries (DatasetUtilities/sampleFunction2DToSeries (->Function2D f) min max samples "Value"))))

+(defn- set-individuals [series f population]
+  (doseq [[individual] population]
+    (.add series individual (f individual) false)))
+
 (defn- log-generation
+  ([f generation-series analysis-dataset population generation-number]
+   (doto generation-series
+     (.clear)
+     (set-individuals f population)
+     (.fireSeriesChanged))
+   (log-generation analysis-dataset population generation-number))
   ([analysis-dataset population generation-number]
    (doto analysis-dataset
-     (.addValue (stat/mean-fitness population) "Mean" generation-number)
-     (.addValue (stat/best-fitness population) "Best" generation-number))
-   (Thread/sleep 500))
-  ([f generation-series analysis-dataset population generation-number]
-   (.clear generation-series)
-   (doseq [[individual] population]
-     (.add generation-series individual (f individual)))
-   (log-generation analysis-dataset population generation-number)))
+     (.add (stat/fitness population) "Fitness" generation-number))
+   (Thread/sleep 500)))

 (defn logger
   ([]
-   (let [analysis-dataset (DefaultCategoryDataset.)]
+   (let [analysis-dataset (DefaultBoxAndWhiskerCategoryDataset.)]
      (frame "Popluation Analysis" analysis-dataset)
      (partial log-generation analysis-dataset)))
   ([f min max samples]
    (let [sample-dataset (sample f min max samples)
          generation-series (.getSeries sample-dataset "Individual")
-         analysis-dataset (DefaultCategoryDataset.)]
+         analysis-dataset (DefaultBoxAndWhiskerCategoryDataset.)]
      (frame  "Population Analysis" sample-dataset analysis-dataset)
      (partial log-generation f generation-series analysis-dataset))))


clojure: added a -main function to pgraph-morphisms

--- clojure/org/gavrog/clojure/pgraph_morphisms.clj
+++ clojure/org/gavrog/clojure/pgraph_morphisms.clj
@@ -8,7 +8,8 @@
            (org.gavrog.joss.pgraphs.io Net)
            (org.gavrog.joss.geometry Operator Vector SpaceGroup)
            (org.gavrog.jane.compounds Matrix)
-           (org.gavrog.jane.numbers Whole)))
+           (org.gavrog.jane.numbers Whole))
+  (:gen-class))

 (defn nets [filename]
   (iterator-seq (Net/iterator filename)))
@@ -175,17 +176,30 @@
   (SpaceGroup. (.getDimension net) (map first (symmetries net))))

 (defn systreable? [net]
-  (and (.isLocallyStable net) (not (.hasSecondOrderCollisions net))))
-
-(defn test-net [net]
-  (let [n1 (when (systreable? net) (.getName (.getSpaceGroup net)))
-        n2 (when (node-signatures net) (.getName (spacegroup net)))
-        good (or (nil? n1) (= n1 n2))]
-    (when (not good) (println net n1 n2))
-    good))
-
+  (and (.isConnected net)
+       (.isLocallyStable net)
+       (not (.hasSecondOrderCollisions net))))

 (deftest spacegroup-test
+  (defn test-net [net]
+    (let [n1 (when (systreable? net) (.getName (.getSpaceGroup net)))
+          n2 (when (node-signatures net) (.getName (spacegroup net)))]
+      (or (nil? n1) (= n1 n2))))
+
   (doseq [f ["dia.pgr", "test.pgr", "Fivecases.cgd", "xbad.pgr"]
           g (nets f)]
-        (is (test-net g))))
+        (when (.isConnected g) (is (test-net g)))))
+
+(defn -main [path]
+  (doseq [G (nets path)]
+    (print (.getName G) "")
+    (if (not (systreable? G))
+      (println "n.a.")
+      (try
+        (let [n1 (.getName (.getSpaceGroup G))
+              n2 (.getName (spacegroup G))]
+          (if (= n1 n2)
+            (println "good")
+            (println (str "bad (" n1 " vs " n2 ")"))))
+        (catch Throwable x
+          (do (println "error") (throw x)))))))


fix UI eval not showing result

fix UI eval not showing result

--- src/main/shadow/cljs/ui/worker/inspect.cljs
+++ src/main/shadow/cljs/ui/worker/inspect.cljs
@@ -506,6 +506,7 @@
                    :oid ref-oid
                    :runtime-id from
                    :runtime (db/make-ident ::m/runtime from)})
+           (assoc-in [::m/inspect :current] (inc panel-idx))
            (assoc-in [::m/inspect :stack] stack))})))

 (sw/reg-event-fx env/app-ref ::inspect-eval-compile-error!


Explored adding other middleare, but decided not to. tidy up core.clj

--- src/restaurant_inspections_api/core.clj
+++ src/restaurant_inspections_api/core.clj
@@ -14,11 +14,13 @@
   (:use [clojure.tools.nrepl.server :only (start-server stop-server)])
   (:gen-class))

+
 (def server-error-details
   "\n\nPlease contact the administrator:
-          - Github: teh0xqb
-          - Email: quilesbaker@gmail.com
-          - or Code For Miami Slack Group (http://codefor.miami)")
+       - Github: teh0xqb
+       - Email: quilesbaker@gmail.com
+       - or Code For Miami Slack Group (http://codefor.miami)")
+

 (defn wrap-exception-handling
   [handler]
@@ -29,8 +31,9 @@
         (log/error comm-e "DATABASE NOT AVAILABLE!")
         {:status 500 :body (str "500 INTERNAL SERVER ERROR: Database not available." server-error-details)})
       (catch Exception e
-        (log/error e "GENERIC ERROR bubbled up. replace specific expection here and add to the catch statements.")
+        (log/error e "GENERIC ERROR bubbled up. Replace specific expection here and add to the catch statements.")
         {:status 500 :body (str "500 INTERNAL SERVER ERROR." server-error-details)}))))
+

 (def api (->> (middleware/wrap-canonical-redirect           ;; Not using thread last in first arg
                routes                                       ;; because handler is the second args of this middleware
@@ -43,10 +46,12 @@
               all-cors
               (sweet/api schemas/swagger)))

+
 (def app
   (if const/production?
     api
-    (reload/wrap-reload api)))
+    (reload/wrap-reload #'api)))
+

 (defn -main
   "Starts server and schedules load-api-data process."


simplify

simplify

--- src/babel/generate.cljc
+++ src/babel/generate.cljc
@@ -125,11 +125,11 @@
   "given a bolt, return the lazy sequence of all bolts derived from this bolt after adding,
    at each supplied path in comp-paths, the bolts for that path."
   [bolt model comp-paths bolts-at-paths depth max-depth & [top-bolt path-from-top]]
-  (lazy-seq
-   (let [top-bolt (or top-bolt bolt)]
-     (if (empty? comp-paths)
-       [bolt] ;; done: we've added all the comps to the bolt, so just return the bolt as a singleton vector.
-       ;; else, more comp-paths to go.
+  (let [top-bolt (or top-bolt bolt)]
+    (if (empty? comp-paths)
+      [bolt] ;; done: we've added all the comps to the bolt, so just return the bolt as a singleton vector.
+      ;; else, more comp-paths to go.
+      (lazy-seq
        (flatten
         (mapfn #(add-comps % model
                            (rest comp-paths)


add more params

add more params

--- src/babel/generate.cljc
+++ src/babel/generate.cljc
@@ -92,7 +92,7 @@
                                (rest comp-paths)
                                (rest bolts-at-paths)
                                depth max-depth top-bolt truncate? take-n)
-                   ((fn [comp-paths bolts-at-paths bolt top-bolt]
+                   ((fn [comp-paths bolts-at-paths bolt top-bolt model depth max-depth]
                       (let [path (first comp-paths)
                             bolts-at (first bolts-at-paths)]
                         (flatten
@@ -104,7 +104,7 @@
                                             (if truncate? (truncate with-added-complement [path] model)
                                                 with-added-complement))))))
                                 bolts-at))))
-                    comp-paths bolts-at-paths bolt top-bolt)))))))))
+                    comp-paths bolts-at-paths bolt top-bolt model depth max-depth)))))))))

 (defn add-bolt-at [top-bolt bolt path bolt-at model depth max-depth truncate? & [take-n]]
   (mapfn #(do-defaults % model)


adding add-comps

adding add-comps

--- src/babel/generate.cljc
+++ src/babel/generate.cljc
@@ -169,25 +169,28 @@
                                           "; top-bolt:"
                                           ((:morph-ps model) top-bolt)))
                           (if (= false (get-in bolt-at [:phrasal]))
-                            [(assoc-in
-                              bolt
-                              path
-                              bolt-at)]
-
+                            (do
+                              (log/debug (str "(assoc-in (lexical) " ((:morph-ps model) bolt) " " path " "
+                                              ((:morph-ps model) bolt-at)))
+                              [(assoc-in bolt path bolt-at)])
                             (let [comps-map (comp-paths-to-bolts-map bolt-at model (+ 1 depth) max-depth)
                                   comp-paths (sort (keys comps-map))]
                               (when (not (some empty? (vals comps-map)))
-                                (add-comps bolt-at
-                                           model
-                                           comp-paths
-                                           (map (fn [path]
-                                                  (get comps-map path))
-                                                comp-paths)
-                                           (+ 1 depth)
-                                           max-depth
-                                           top-bolt
-                                           (str (if path-from-top (str path-from-top "/"))
-                                              path))))))
+                                (let [result
+                                      (add-comps bolt-at
+                                                 model
+                                                 comp-paths
+                                                 (map (fn [path]
+                                                        (get comps-map path))
+                                                      comp-paths)
+                                                 (+ 1 depth)
+                                                 max-depth
+                                                 top-bolt
+                                                 (str (if path-from-top (str path-from-top "/"))
+                                                      path))]
+                                  (log/debug (str "(assoc-in (phrasal) " ((:morph-ps model) bolt) " " path " "
+                                                  ((:morph-ps model) bolt-at)))
+                                  result)))))
                         bolts-at))))))
 (defn generate2
   "Return all expressions matching spec _spec_ given the model _model_."


s/debug/trace/

s/debug/trace/

--- src/babel/generate.cljc
+++ src/babel/generate.cljc
@@ -151,7 +151,7 @@
   [bolts path model]
   (if (not (empty? bolts))
     (do
-      (log/debug (str "add-comp-to-bolts: path=" (vec path) "; first bolt=" ((:morph-ps model) (first bolts))))
+      (log/trace (str "add-comp-to-bolts: path=" (vec path) "; first bolt=" ((:morph-ps model) (first bolts))))
       (lazy-cat
        (let [result
              (add-to-bolt-at-path (first bolts) path model)]


+(log/debug) statements in (defn lightning-bolt)

--- src/babel/generate.cljc
+++ src/babel/generate.cljc
@@ -254,7 +254,9 @@
                          (if (= false (get-in parent [:head :phrasal] false))
                            (let [candidate-lexemes (get-lex parent :head index spec)]
                              (filter #(not (nil? %))
-                                     (over/overh parent (shuffle candidate-lexemes))))))
+                                     (do (log/debug (str "trying over parent:" (:rule parent)))
+                                         (log/debug (str " with lexemes:" (string/join ";" (sort (map morph candidate-lexemes)))))
+                                         (over/overh parent (shuffle candidate-lexemes)))))))
                        parents)
           phrasal ;; 2. generate list of all phrases where the head child of each parent is itself a phrase.
           (if (and (< total-depth max-total-depth)


more simplification

more simplification

--- src/babel/generate.cljc
+++ src/babel/generate.cljc
@@ -70,32 +70,30 @@
 (declare add-bolt-at)

 (defn add-bolts-to-path [path bolts-at bolt top-bolt model depth max-depth truncate? take-n]
-  (flatten
-   (mapfn #(let [bolt (assoc-in bolt path %)]
-             (if (= false (get-in % [:phrasal]))
-               [bolt]
-               (-> (add-bolt-at top-bolt bolt path % model depth max-depth truncate? take-n)
-                   ((fn [with-added-complement]
-                      (if truncate? (truncate with-added-complement [path] model)
-                          with-added-complement))))))
-            bolts-at)))
+  (mapfn #(let [bolt (assoc-in bolt path %)]
+            (if (= false (get-in % [:phrasal]))
+              [bolt]
+              (if truncate
+                (truncate
+                 (add-bolt-at top-bolt bolt path % model depth max-depth truncate? take-n) [path] model)
+                (add-bolt-at top-bolt bolt path % model depth max-depth truncate? take-n))))
+         bolts-at))

 (defn add-comps
   "given a bolt, return the lazy sequence of all bolts derived from this bolt after adding,
    at each supplied path in comp-paths, the bolts for that path."
-  [bolt model comp-paths bolts-at-paths depth max-depth & [top-bolt truncate? take-n]]
+  [bolt model comp-paths bolts-at-paths depth max-depth top-bolt truncate? take-n]
   (when (not (= :fail bolt))
-    (let [top-bolt (or top-bolt bolt)
-          truncate? (if (= truncate? false) false true)]
-      (if (empty? comp-paths)
-        [bolt] ;; done: we've added all the comps to the bolt, so just return the bolt as a singleton vector.
-        (mapfn #(add-comps % model
-                           (rest comp-paths)
-                           (rest bolts-at-paths)
-                           depth max-depth top-bolt truncate? take-n)
-               (add-bolts-to-path
-                (first comp-paths) (first bolts-at-paths)
-                bolt top-bolt model depth max-depth truncate? take-n))))))
+    (if (empty? comp-paths)
+      [bolt] ;; done: we've added all the comps to the bolt, so just return the bolt as a singleton vector.
+      (mapfn #(add-comps % model
+                         (rest comp-paths)
+                         (rest bolts-at-paths)
+                         depth max-depth top-bolt truncate? take-n)
+             (flatten
+              (add-bolts-to-path
+               (first comp-paths) (first bolts-at-paths)
+               bolt top-bolt model depth max-depth truncate? take-n))))))

 (defn add-bolt-at [top-bolt bolt path bolt-at model depth max-depth truncate? & [take-n]]
   (mapfn #(do-defaults % model)


improve logging

improve logging

--- src/babel/lexiconfn.clj
+++ src/babel/lexiconfn.clj
@@ -71,8 +71,8 @@

 (defn unify [ & args]
   "like unify/unify, but unify/copy each argument before unifying."
-  (log/trace (str "(lexfn)unify args: " args))
-  (log/trace (str "(lexfn)unify first arg: " (first args)))
+  (log/trace (str "(lexfn)unify args: " (map strip-refs args)))
+  (log/trace (str "(lexfn)unify first arg: " (strip-refs (first args))))
   (let [retval (apply unifyc args)]
     (if (not (fail? retval))
       retval


Optional server-conn-loop override for server-accept-loop.

--- src/cbfg/world/net.cljs
+++ src/cbfg/world/net.cljs
@@ -25,7 +25,8 @@
               (aput lanes-out server-send-ch [(atake lanes-out lanes-out-ch)])
               (recur (inc num-outs)))))

-(defn server-accept-loop [actx accept-ch close-accept-ch]
+(defn server-accept-loop [actx accept-ch close-accept-ch &
+                          {:keys [server-conn-loop] :or {server-conn-loop server-conn-loop}}]
   (act-loop server-accept-loop actx [num-accepts 0]
             (if-let [[server-send-ch server-recv-ch close-server-recv-ch]
                      (atake server-accept-loop accept-ch)]


Added flush-all function to native interface so we can flush IO buffers.

--- src/overtone/sc/machinery/server/native.clj
+++ src/overtone/sc/machinery/server/native.clj
@@ -9,6 +9,12 @@

 (defonce __LOAD_SCSYNTH_NATIVE_LIB__
   (do
+    (defclib
+      libc
+      (:libname "c")
+      (:functions
+        (fflush fflush [void*] i32)))
+
     (defclib
       lib-scsynth
       (:libname "scsynth")
@@ -139,7 +145,12 @@
         (world-send-packet World_SendPacket [void* i32 byte* reply-callback] byte)
         (world-copy-sound-buffer World_CopySndBuf [void* i32 sound-buffer* byte byte*] i32)))

+    (loadlib libc)
     (loadlib lib-scsynth)))
+
+(defn flush-all
+  []
+  (fflush nil))

 (defn set-world-options!
   [ptr option-map]
@@ -213,6 +224,7 @@
   "Starts the synthesis server main loop, and does not return until the /quit message
   is received."
   [sc]
+  (flush-all)
   (world-run (:world sc)))

 (defn scsynth-get-buffer-data


static query, params & ident methods

static query, params & ident methods

--- src/cellophane/next.clj
+++ src/cellophane/next.clj
@@ -1,5 +1,7 @@
 (ns cellophane.next
-  (:require [cellophane.protocols :as p]))
+  (:refer-clojure :exclude [var?])
+  (:require [cellophane.protocols :as p]
+            [clojure.walk :as walk]))

 ;; ===================================================================
 ;; Query Protocols & Helpers
@@ -22,6 +24,18 @@
   (-get-state [this] "Get the component's local state")
   (-get-rendered-state [this] "Get the component's rendered local state")
   (-merge-pending-state! [this] "Get the component's pending local state"))
+
+(defn- dispatch
+  "Helper function for implementing static `query` and `params` multimethods.
+   Dispatches on the (component) class"
+  [class] class)
+
+(defmulti class-query dispatch)
+
+(defmulti class-params dispatch)
+(defmethod class-params :default [_])
+
+(defmulti class-ident dispatch)

 ;; ===================================================================
 ;; React bridging (defui, factory, props, state)
@@ -111,28 +125,41 @@

 ;; TODO: probably need to reshape dt to implement defaults
 (defn defui* [name forms]
-  (let [{:keys [dt statics]} (collect-statics forms)]
-    `(defrecord ~name [~'state props# children#]
-       ;; TODO: props & children
-       ;; TODO: non-lifecycle methods defined in the JS prototype
-       cellophane.protocols/IReactLifecycle
-       ~@(rest dt)
-
-       ~@(:protocols statics)
-
-       cellophane.protocols/IReactChildren
-       (~'-children [this#]
-         children#)
-
-       cellophane.protocols/IReactComponent
-       (~'-props [this#]
-        props#)
-       (~'-render [this#]
-        ;; TODO: circle back. where should this exception be caught?
-        (try
-          (p/render this#)
-          (catch AbstractMethodError e#
-            (println "abstrctmethoderror")))))))
+  (let [{:keys [dt statics]} (collect-statics forms)
+        define-class-methods (when-not (empty? (:protocols statics))
+                               `(do
+                                  ~@(->> (partition 2 (:protocols statics))
+                                      (filter (fn [[p _]]
+                                                (some #{(clojure.core/name p)}
+                                                  '#{"IQuery" "Ident" "IQueryParams"})))
+                                      (map
+                                        (fn [[_ impl]]
+                                          (cons 'defmethod
+                                            (cons (symbol (str "cellophane.next/class-" (first impl)))
+                                              (cons name (rest impl)))))))))]
+    `(do
+       (defrecord ~name [~'state props# children#]
+         ;; TODO: non-lifecycle methods defined in the JS prototype
+         cellophane.protocols/IReactLifecycle
+         ~@(rest dt)
+
+         ~@(:protocols statics)
+
+         cellophane.protocols/IReactChildren
+         (~'-children [this#]
+          children#)
+
+         cellophane.protocols/IReactComponent
+         (~'-props [this#]
+          props#)
+         (~'-render [this#]
+          ;; TODO: circle back. where should this exception be caught?
+          (try
+            (p/render this#)
+            (catch AbstractMethodError e#
+              (println "abstrctmethoderror")))))
+
+       ~define-class-methods)))

 (defmacro defui [name & forms]
   (defui* name forms))


Sort colors in the colors dashboard page by color.

--- src/uxbox/main/ui/dashboard/colors.cljs
+++ src/uxbox/main/ui/dashboard/colors.cljs
@@ -155,14 +155,17 @@
 (mx/defc grid
   {:mixins [mx/static]}
   [selected coll]
-  (let [own? (= (:type coll) :own)]
+  (let [own? (= (:type coll) :own)
+        colors (->> (:data coll)
+                    (remove nil?)
+                    (sort-by identity))]
     [:div.dashboard-grid-content
      [:div.dashboard-grid-row
       (when own?
         [:div.grid-item.small-item.add-project
          {:on-click #(udl/open! :color-form {:coll coll})}
          [:span "+ New color"]])
-      (for [color (remove nil? (:data coll))
+      (for [color colors
             :let [selected? (contains? selected color)]]
         (-> (grid-item color selected?)
             (mx/with-key (str color))))]]))
@@ -185,53 +188,53 @@

 ;; --- Nav

-(mx/defc nav-collection
+(mx/defc nav-item
   {:mixins [mx/static]}
-  [collection selected?]
+  [coll selected?]
   (letfn [(on-click [event]
-            (let [type (:type collection)
-                  id (:id collection)]
+            (let [type (:type coll)
+                  id (:id coll)]
               (rs/emit! (dc/select-collection type id))))]
-    (let [colors (count (:data collection))]
+    (let [colors (count (:data coll))]
       [:li {:on-click on-click
             :class-name (when selected? "current")}
-       [:span.element-title (:name collection)]
+       [:span.element-title (:name coll)]
        [:span.element-subtitle
         (tr "ds.num-elements" (t/c colors))]])))

-(mx/defc nav-collections
+(mx/defc nav-section
   {:mixins [mx/static mx/reactive]}
   [type selected]
   (let [own? (= type :own)
         builtin? (= type :builtin)
-        collections (cond->> (mx/react collections-ref)
-                      own? (filter #(= :own (:type %)))
-                      builtin? (filter #(= :builtin (:type %)))
-                      own? (sort-by :id))]
+        colls (cond->> (mx/react collections-ref)
+                own? (filter #(= :own (:type %)))
+                builtin? (filter #(= :builtin (:type %)))
+                own? (sort-by :id))]
     [:ul.library-elements
      (when own?
        [:li
         [:a.btn-primary
          {:on-click #(rs/emit! (dc/create-collection))}
          "+ New library"]])
-     (for [coll collections
+     (for [coll colls
            :let [selected? (= (:id coll) selected)
                  key (str (:id coll))]]
-       (-> (nav-collection coll selected?)
+       (-> (nav-item coll selected?)
            (mx/with-key key)))]))

 (mx/defc nav
   {:mixins [mx/static mx/reactive]}
   []
   (let [dashboard (mx/react dashboard-ref)
-        collections (mx/react collections-ref)
+        colls (mx/react collections-ref)
         selected (:id dashboard)
         type (:type dashboard)
         own? (= type :own)
         builtin? (= type :builtin)]
     (letfn [(select-tab [type]
               (let [xf (filter #(= type (:type %)))
-                    colls (sequence xf collections)]
+                    colls (sequence xf colls)]
                 (if-let [item (first colls)]
                   (rs/emit! (dc/select-collection type (:id item)))
                   (rs/emit! (dc/select-collection type)))))]
@@ -244,7 +247,7 @@
          [:li {:class-name (when builtin? "current")
                :on-click (partial select-tab :builtin)}
           "COLORS STORE"]]
-        (nav-collections type selected)]])))
+        (nav-section type selected)]])))

 ;; --- Colors Page


fixed unknown recipient

fixed unknown recipient

Signed-off-by: Andrey Shovkoplyas <b713972e59b8e606e23253c4a13e948139fea4d1@gmail.com>

--- src/status_im/ui/screens/signing/views.cljs
+++ src/status_im/ui/screens/signing/views.cljs
@@ -48,11 +48,16 @@
    txt1 " "
    [{:style {:color colors/gray}} txt2]])

+(defn displayed-name [contact]
+  (if (or (:preferred-name contact) (:name contact))
+    (accounts/displayed-name contact)
+    (:address contact)))
+
 (defn contact-item [contact]
   [list-item/list-item {:type        :small
                         :title       (i18n/label :t/to)
                         :accessories [[react/text {:ellipsize-mode :middle :number-of-lines 1 :style {:flex-wrap :wrap}}
-                                       (accounts/displayed-name contact)]]}])
+                                       (displayed-name contact)]]}])

 (defn token-item [{:keys [icon color] :as token} display-symbol]
   (when token
@@ -83,7 +88,7 @@
       [react/nested-text {:style           {:color colors/gray}
                           :ellipsize-mode  :middle
                           :number-of-lines 1} (i18n/label :t/to) " "
-       [{:style {:color colors/black}} (accounts/displayed-name contact)]]
+       [{:style {:color colors/black}} (displayed-name contact)]]
       [react/text {:style {:margin-top 6 :color colors/gray}}
        (str fee " " fee-display-symbol " " (string/lower-case (i18n/label :t/network-fee)))])]
    [react/touchable-highlight (when-not in-progress? {:on-press #(re-frame/dispatch [:signing.ui/cancel-is-pressed])})


lein-release plugin: bumped version from 0.2.3 to 0.2.4-SNAPSHOT for next development cycle

--- material/project.clj
+++ material/project.clj
@@ -1,4 +1,4 @@
-(defproject re-view/material "0.2.3"
+(defproject re-view/material "0.2.4-SNAPSHOT"

   :description "Material design components in re-view"


Adapting the title

Adapting the title

--- src/amindblowingworld/view_index.clj
+++ src/amindblowingworld/view_index.clj
@@ -45,7 +45,8 @@
       (include-css "/css/app.css")]
     [:body {:onload "initApp();"}
       [:div#appViewport
-        [:h1 "AMindBlowingWorld"]
+        [:h1 "A-Mind-Blowing-World"]
+        [:h2 "The miracle of life, civilizations rising and... the possibility to destroy everything one-click away!"]
         [:div#accordion
           [:h3 "Map and updates"]
           [:div#appDiv


An API can return nested data

An API can return nested data

--- test-cljs/frontend/test_send.cljs
+++ test-cljs/frontend/test_send.cljs
@@ -327,7 +327,7 @@
                        (chan 1 (comp
                                 (map #(get % read-from-key))
                                 (map #(hash-map (:key ast) %)))))
-          (throw "Unknown key")))))
+          (throw (ex-info "Unknown key" {:key read-from-key}))))))
    (:channel context)))

@@ -335,17 +335,33 @@
   (let [ast (om/query->ast query)]
     (resolve* context root-mapping (:children ast))))

-(def User
-  {:user/name
+(def resolvers
+  {:root/user
+   (fn [context ast]
+     (resolve* (assoc context
+                      :channel (chan)
+                      :user/name (:user/name (:params ast)))
+               resolvers
+               (:children ast)))
+
+   :user/name
    (fn [context ast]
      (:user/name context))

-   #{:user/favorite-color :user/favorite-number}
+   #{:user/favorite-color :user/favorite-number :user/vehicle}
    (fn [context ast]
      (p/alet [get-user (get-in context [:apis :get-user])
               user (p/await (get-user {:name (:user/name context)}))]
-       (set/rename-keys user {:favorite-color :user/favorite-color
-                              :favorite-number :user/favorite-number})))
+       (-> user
+           (set/rename-keys {:favorite-color :user/favorite-color
+                             :favorite-number :user/favorite-number
+                             :vehicle :user/vehicle})
+           (update :user/vehicle set/rename-keys {:color :vehicle/color
+                                                  :make :vehicle/make
+                                                  :model :vehicle/model})
+           (update :user/vehicle #(om/db->tree (mapv om/ast->query (:children ast))
+                                               %
+                                               {})))))

    :user/favorite-fellow-user
    (fn [context ast]
@@ -355,19 +371,9 @@
          (resolve* (assoc context
                           :channel c
                           :user/name (:favorite-fellow-user-name user))
-                   User
+                   resolvers
                    (:children ast)))
        c))})
-
-
-(def Root
-  {:root/user
-   (fn [context ast]
-     (resolve* (assoc context
-                      :channel (chan)
-                      :user/name (:user/name (:params ast)))
-               User
-               (:children ast)))})

 (deftest new-thing-works
   (async done
@@ -376,6 +382,9 @@
           ;; The resolver must translate.
           users {{:name "nipponfarm"} {:favorite-color :color/blue
                                        :favorite-number 42
+                                       :vehicle {:color :color/white
+                                                 :make "Toyota"
+                                                 :model "Hilux"}
                                        :favorite-fellow-user-name "jburnford"}
                  {:name "jburnford"} {:favorite-color :color/red
                                       :favorite-number 7}}
@@ -385,22 +394,26 @@
                                                   (p/do*
                                                    (swap! api-calls conj [:get-user params])
                                                    (get users params))))}}
-                             Root '[{(:root/user {:user/name "nipponfarm"})
-                                     [:user/name
-                                      :user/favorite-color
-                                      :user/favorite-number
-                                      {:user/favorite-fellow-user [:user/name
-                                                                   :user/favorite-color
-                                                                   :user/favorite-number]}]}
-                                    {(:jamie {:< :root/user :user/name "jburnford"})
-                                     [:user/name
-                                      :user/favorite-color]}])]
+                             resolvers '[{(:root/user {:user/name "nipponfarm"})
+                                          [:user/name
+                                           :user/favorite-color
+                                           :user/favorite-number
+                                           {:user/vehicle [:vehicle/make
+                                                           :vehicle/model]}
+                                           {:user/favorite-fellow-user [:user/name
+                                                                        :user/favorite-color
+                                                                        :user/favorite-number]}]}
+                                         {(:jamie {:< :root/user :user/name "jburnford"})
+                                          [:user/name
+                                           :user/favorite-color]}])]
       (take!
        (async/into #{} data-chan)
        (fn [v]
          (is (= #{{:root/user {:user/name "nipponfarm"}}
                   {:root/user {:user/favorite-color :color/blue}}
                   {:root/user {:user/favorite-number 42}}
+                  {:root/user {:user/vehicle {:vehicle/make "Toyota"
+                                              :vehicle/model "Hilux"}}}
                   {:root/user {:user/favorite-fellow-user {:user/name "jburnford"}}}
                   {:root/user {:user/favorite-fellow-user {:user/favorite-color :color/red}}}
                   {:root/user {:user/favorite-fellow-user {:user/favorite-number 7}}}


Fix tests related to fill funcname change.

--- test/buddy/core/padding_tests.clj
+++ test/buddy/core/padding_tests.clj
@@ -20,7 +20,7 @@

 (deftest pkcs7-padding
   (let [data (byte-array 10)]
-    (bytes/fill data 2)
+    (bytes/fill! data 2)
     (padding/pad! data 6)

     (is (padding/padded? data))
@@ -31,7 +31,7 @@

 (deftest tbc-padding
   (let [data (byte-array 10)]
-    (bytes/fill data 2)
+    (bytes/fill! data 2)
     (padding/pad! data 6 :tbc)

     (is (padding/padded? data :tbc))
@@ -42,7 +42,7 @@

 (deftest zerobyte-padding
   (let [data (byte-array 10)]
-    (bytes/fill data 2)
+    (bytes/fill! data 2)
     (padding/pad! data 6 :zerobyte)

     (is (padding/padded? data :zerobyte))


Update test for VCF writer to test extra fields output

--- test/cljam/io/vcf/writer_test.clj
+++ test/cljam/io/vcf/writer_test.clj
@@ -28,5 +28,6 @@
                                                  {:id "Blood"
                                                   :genomes "Germline"
                                                   :mixture "1."
-                                                  :description "test"})
-         "ID=Blood,Genomes=Germline,Mixture=1.,Description=\"test\"")))
+                                                  :description "test"
+                                                  :note "extra note"})
+         "ID=Blood,Genomes=Germline,Mixture=1.,Description=\"test\",note=\"extra note\"")))


Read disptach interval from configuration

--- src/cider_ci/dispatcher/dispatch.clj
+++ src/cider_ci/dispatcher/dispatch.clj
@@ -240,12 +240,22 @@

 ;#### dispatch service ########################################################
+
+(defn get-dispatch-interval []
+  (try
+    (catcher/wrap-with-log-warn
+      (or (-> (get-config) :services :dispatcher :dispatch_interval)
+          1.0))
+    (catch Exception _
+      1.0)))
+
 (daemon/define "dispatch-service"
   start-dispatch-service
   stop-dispatch-service
-  0.2
+  (get-dispatch-interval)
   (logging/debug "dispatch-service")
   (dispatch-trials))
+

 ;### initialize ##############################################################
 (defn initialize []


Sigh.

Sigh.

--- src/circle/backend/load_balancer.clj
+++ src/circle/backend/load_balancer.clj
@@ -14,6 +14,7 @@
             Listener
             RegisterInstancesWithLoadBalancerRequest))
   (:use [circle.aws-credentials :only (aws-credentials)])
+  (:use [clojure.tools.logging :only (infof)])
   (:use [pallet.thread-expr :only (when->)])
   (:use [circle.utils.except :only (throw-if-not)])
   (:use [circle.utils.core :only (apply-map)]))


Remove unnecessary .getDeclaringClass from fields.

--- src/clj/guangyin/internal/fields.clj
+++ src/clj/guangyin/internal/fields.clj
@@ -9,10 +9,7 @@

 (defn- field-to-symbol
   [class-var field]
-  (let [decl-class (if (instance? java.lang.Enum class-var)
-                       (.getDeclaringClass class-var)
-                       class-var)
-        class-name (.getName decl-class)]
+  (let [class-name (.getName class-var)]
     (symbol (str class-name "/" (name field)))))

 (defn- field-to-keyword


`shift-lessons-upwards-to-replace-empty-slots!` - Use destructuring

Signed-off-by: Pang Yan Han <22594c345857f664c61cd411f607c4d40a9d4af9@gmail.com>

--- src/cljs/cljs_nusmods/timetable.cljs
+++ src/cljs/cljs_nusmods/timetable.cljs
@@ -1276,9 +1276,8 @@
         ; implementation
         exclude-lessons-on-empty-rows
         (fn [lessonInfoSeq]
-          (filter #(let [day    (:day %1)
-                         rowNum (:rowNum %1)]
-                     (timetable-row-not-empty? day rowNum))
+          (filter (fn [{:keys [day rowNum]}]
+                    (timetable-row-not-empty? day rowNum))
                   lessonInfoSeq))

         sort-lesson-info-seq


Store `document.location.hash` in LocalStorage

So that we can implement retrieval of the original
`document.location.hash` from the LocalStorage after the user has left
the site.

Signed-off-by: Pang Yan Han <22594c345857f664c61cd411f607c4d40a9d4af9@gmail.com>

--- src/cljs/cljs_nusmods/timetable.cljs
+++ src/cljs/cljs_nusmods/timetable.cljs
@@ -415,15 +415,29 @@
    (sort-PreToUrlHashLessonGroup-seq
      (get-PreToUrlHashLessonGroup-seq-for-selected-module moduleCode))})

+(def ^{:doc     "HTML localStorage object"
+       :private true}
+  LOCALSTORAGE (aget js/window "localStorage"))
+
+(def ^{:doc     "Key for storing the `document.location.hash` indicating
+                 modules and lessons selected by the user"
+       :private true}
+  LOCALSTORAGE-DOC-LOCATION-HASH-KEY "cljs-nusmods:url-hash")
+
 (defn- get-document-location-hash
   "Retrieves the current value of `document.location.hash`"
   []
   (aget (aget js/document "location") "hash"))

 (defn- set-document-location-hash!
-  "Sets `document.location.hash` to a given string"
+  "Sets `document.location.hash` to a given string and updates the url hash in
+   LocalStorage"
   [newDocLocationHash]
-  (aset (aget js/document "location") "hash" newDocLocationHash))
+  (aset (aget js/document "location") "hash" newDocLocationHash)
+  (if LOCALSTORAGE
+      (.setItem LOCALSTORAGE
+                LOCALSTORAGE-DOC-LOCATION-HASH-KEY
+                newDocLocationHash)))

 (defn- set-document-location-hash-based-on-modules-order!
   "Sets document.location.hash based on the `ModulesSelectedOrder` global."


fix to use reframe 2.0 api

fix to use reframe 2.0 api

--- src/cljs/phonecat_re_frame/core.cljs
+++ src/cljs/phonecat_re_frame/core.cljs
@@ -33,7 +33,7 @@
  (fn [db]
    (reaction (:order-prop @db))))

-(re-frame/register-subs
+(re-frame/register-sub
  :phone-query
  (fn [db [_ phone-id]]
    (let [phone-details-reaction (reaction (:phone-details @db))]
@@ -62,14 +62,14 @@
                    :keywords? true})
    app-state))

-(re-frame/register-pure-handler
+(re-frame/register-handler
  :process-phone-detail-response
  (fn
    ;; store info for the specific phone-id in the db
    [app-state [_ phone-id response]]
    (assoc-in app-state [:phone-details (keyword phone-id)] response)))

-(re-frame/register-pure-handler
+(re-frame/register-handler
  :process-phone-detail-bad-response
  (fn
    [app-state [_ [phone-id response]]]
@@ -77,7 +77,7 @@
    (println response)
    app-state))

-(re-frame/register-pure-handler
+(re-frame/register-handler
  :load-phone-detail
  (fn
    ;; fetch information for the phone with the given phone-id


fix indenting

fix indenting

--- src/cljs/phonecat_re_frame/core.cljs
+++ src/cljs/phonecat_re_frame/core.cljs
@@ -18,13 +18,13 @@
      (reaction (:phones @db))))  ;; pulls out :phones

 (re-frame/register-handler
-   :initialise-db             ;; usage: (dispatch [:initialise-db])
-   (fn
-     [_ _]                   ;; Ignore both params (db and v).
-     {:phones [{:name "Nexus S" :snippet "Fast just got faster with Nexus S."}
-               {:name "Motorola XOOM™ with Wi-Fi" :snippet "The Next, Next Generation tablet."}
-               {:name "Motoral Xoom" :snippet "The Next, Next Generation tablet."}]
-      :search-input ""}))
+ :initialise-db             ;; usage: (dispatch [:initialise-db])
+ (fn
+   [_ _]                   ;; Ignore both params (db and v).
+   {:phones [{:name "Nexus S" :snippet "Fast just got faster with Nexus S."}
+             {:name "Motorola XOOM™ with Wi-Fi" :snippet "The Next, Next Generation tablet."}
+             {:name "Motoral Xoom" :snippet "The Next, Next Generation tablet."}]
+    :search-input ""}))

 (defn handle-search-input-entered
   [app-state [_ search-input]]
@@ -43,12 +43,12 @@
    [:p (:snippet @phone)]])

 (defn matches-query?
- [search-input phone]
- (if (= "" search-input)
-   true
-   (boolean (or
-             (re-find (re-pattern search-input) (:name phone))
-             (re-find (re-pattern search-input) (:snippet phone))))))
+  [search-input phone]
+  (if (= "" search-input)
+    true
+    (boolean (or
+              (re-find (re-pattern search-input) (:name phone))
+              (re-find (re-pattern search-input) (:snippet phone))))))

 (defn phones-component
   []


rename search as search-component

rename search as search-component

--- src/cljs/phonecat_re_frame/core.cljs
+++ src/cljs/phonecat_re_frame/core.cljs
@@ -59,7 +59,7 @@
        (for [phone (filter (partial matches-query? @search-input) @phones)]
          ^{:key phone} [phone-component phone])])))

-(defn search
+(defn search-component
   []
   (let [search-input (re-frame/subscribe [:search-input])])
   (fn []
@@ -69,7 +69,7 @@
   [:div {:class "container-fluid"}
    [:div {:class "row"}
     [:div {:class "col-md-2"}
-     [search]]]
+     [search-component]]]
    [:div {:class "col-md-10"}
     [phones-component]]])


Some refactoring

Some refactoring

--- src/cljs/todogo_cljs/components.cljs
+++ src/cljs/todogo_cljs/components.cljs
@@ -17,14 +17,17 @@

 (defn nav-bar [main-menu-visible]
-  (let [menu-class (if (= main-menu-visible true) "collapse navbar-collapse in" "collapse navbar-collapse")]
+  (let [menu-class (if (= main-menu-visible true)
+                     "collapse navbar-collapse in"
+                     "collapse navbar-collapse")]
     [:nav {:class "navbar navbar-inverse navbar-fixed-top"}
      [:div {:class "container"}
       [:div {:class "navbar-header"}
        [:a {:href "#/" :class "navbar-brand"} "TODOGO"]
        [:button {:class "navbar-toggle"
                  :type "button"
-                 :on-click #(re-frame/dispatch [:set-main-menu-visible (if (= main-menu-visible true) false true)])}
+                 :on-click #(re-frame/dispatch
+                             [:set-main-menu-visible (if (= main-menu-visible true) false true)])}
         [:span {:class "icon-bar"}]
         [:span {:class "icon-bar"}]
         [:span {:class "icon-bar"}]]]
@@ -63,7 +66,8 @@
              :type        "text"
              :value       title
              :placeholder (str "Create a todo list...")
-             :on-change   #(re-frame/dispatch-sync [:set-todo-list-title (-> % .-target .-value)])}]]])
+             :on-change   #(re-frame/dispatch-sync
+                            [:set-todo-list-title (-> % .-target .-value)])}]]])

 (defn create-todo-form [todo-list title]
@@ -93,12 +97,14 @@
               :type        "text"
               :value       (:title todo)
               :placeholder (str "New todo title")
-              :on-change   #(re-frame/dispatch-sync [:set-todo (assoc todo :title (-> % .-target .-value))])}]]
+              :on-change   #(re-frame/dispatch-sync
+                             [:set-todo (assoc todo :title (-> % .-target .-value))])}]]
     [:div {:class "form-group"}
      [:textarea {:class       "form-control"
                  :placeholder (str "Note...")
                  :value       (:note todo)
-                 :on-change   #(re-frame/dispatch-sync [:set-todo (assoc todo :note (-> % .-target .-value))])}]]
+                 :on-change   #(re-frame/dispatch-sync
+                                [:set-todo (assoc todo :note (-> % .-target .-value))])}]]
     [:div {:class "form-group"}
      [single-dropdown
       :choices     priorities
@@ -144,13 +150,15 @@
              :placeholder "Email address"
              :value (:email user)
              :on-change   #(do (re-frame/dispatch-sync [:set-form-errors nil])
-                               (re-frame/dispatch-sync [:set-user-login (assoc user :email (-> % .-target .-value))]))}]
+                               (re-frame/dispatch-sync
+                                 [:set-user-login (assoc user :email (-> % .-target .-value))]))}]
     [:input {:class       "form-control"
              :type        "password"
              :placeholder "Password"
              :value (:password user)
              :on-change   #(do (re-frame/dispatch-sync [:set-form-errors nil])
-                               (re-frame/dispatch-sync [:set-user-login (assoc user :password (-> % .-target .-value))]))}]]
+                               (re-frame/dispatch-sync
+                                 [:set-user-login (assoc user :password (-> % .-target .-value))]))}]]
    [:div
     [:p
      [:span "Or go to "]
@@ -192,7 +200,8 @@
              :type        "password"
              :placeholder "Confirm password"
              :value (:confirm-password user)
-             :on-change   #(do (re-frame/dispatch-sync [:set-user-login (assoc user :confirm-password (-> % .-target .-value))])
+             :on-change   #(do (re-frame/dispatch-sync
+                                 [:set-user-login (assoc user :confirm-password (-> % .-target .-value))])
                                (if (= (:password user) (-> % .-target .-value))
                                  (re-frame/dispatch-sync [:set-form-errors nil])
                                  (re-frame/dispatch-sync [:set-form-errors {:error "Passwords missmatch"}])))}]]


DM+CM - refactor http-api tests

DM+CM - refactor http-api tests

--- test/objective8/http_api_test.clj
+++ test/objective8/http_api_test.clj
@@ -11,207 +11,129 @@
 (def BEARER_NAME "bearer")
 (def BEARER_TOKEN "token")

-(def request-with-bearer-token (contains {:headers (contains {"api-bearer-token" BEARER_TOKEN
-                                                              "api-bearer-name" BEARER_NAME})}))
-
 (background (http-api/get-api-credentials) => {"api-bearer-name" BEARER_NAME
                                                "api-bearer-token" BEARER_TOKEN})

+(facts "about retrieving information from the API"
+       (tabular
+         (fact "maps http response status to API status"
+               (http-api/default-get-call "/some/url") => (contains {:status ?http-api-status})
+               (provided (http-api/get-request "/some/url" {}) => {:body "" :status ?http-status}))
+         ?http-status        ?http-api-status
+         200                 ::http-api/success
+         404                 ::http-api/not-found
+         400                 ::http-api/invalid-input
+         :anything           ::http-api/error))
+
+(facts "about posting information to the API"
+       (tabular
+         (fact "maps http response status to API status"
+               (http-api/default-create-call "/some/url" {:some :data}) => (contains {:status ?http-api-status})
+               (provided (http-api/post-request "/some/url" anything) => {:status ?http-status :body ""}))
+         ?http-status        ?http-api-status
+         201                 ::http-api/success
+         400                 ::http-api/invalid-input
+         :anything           ::http-api/error)
+
+       (fact "accesses the API with the front-end credentials"
+             (http-api/default-create-call "/some/url" {:some :data}) => anything
+             (provided
+               (http-api/post-request "/some/url"
+                                      (contains
+                                        {:headers (contains
+                                                    {"api-bearer-name" BEARER_NAME
+                                                     "api-bearer-token" BEARER_TOKEN})})) => {:status 200 :body ""})))
+
 ;USERS
-(def USER_ID 1)
-(def the-user {:twitter-id "twitter-TWITTER_ID"
-               :email-address "blah@blah.com"})
+(def the-user {:some :data
+               :twitter-id "twitter-TWITTER_ID"})

-(def the-stored-user (into the-user {:_id USER_ID}))
+(fact "creating a user record hits the correct API endpoint"
+       (http-api/create-user the-user) => :api-call-result
+       (provided (http-api/default-create-call (contains "/api/v1/users") the-user) => :api-call-result))

-(facts "about creating user records"
-       (fact "creating a user record requires credentials"
-             (http-api/create-user the-user) => {:status ::http-api/success
-                                                 :result the-stored-user}
-             (provided (http-api/post-request (contains "/api/v1/users")
-                                              request-with-bearer-token)
-                       => {:status 201
-                           :headers {"Content-Type" "application/json"}
-                           :body (json/generate-string the-stored-user)}))
-
-       (fact "returns api-failure when post fails"
-             (http-api/create-user the-user) => {:status ::http-api/error}
-             (provided (http-api/post-request anything anything)
-                       => {:status 500})))
-
-(facts "about finding user records"
-       (fact "finding a user record requires credentials"
-             (http-api/find-user-by-twitter-id (:twitter-id the-user)) => {:status ::http-api/success
-                                                                           :result the-stored-user}
-             (provided (http-api/get-request (contains (str "/api/v1/users?twitter=" (:twitter-id the-user)))
-                                             request-with-bearer-token)
-                       => {:status 200
-                           :headers {"Content-Type" "application/json"}
-                           :body (json/generate-string the-stored-user)})))
+(fact "finding a user record hits the correct API endpoint with credentials"
+      (http-api/find-user-by-twitter-id (:twitter-id the-user)) => :api-call-result
+      (provided
+        (http-api/default-get-call
+          (contains (str "/api/v1/users?twitter=" (:twitter-id the-user)))
+          (contains {:headers (contains {"api-bearer-name" anything
+                                         "api-bearer-token" anything})})) => :api-call-result))

 ;OBJECTIVES
 (def OBJECTIVE_ID 234)

-(def the-objective {:title "My Objective"
-                    :goals "To rock out, All day"
-                    :description "I like cake"
-                    :end-date "2015-01-31"
-                    :username "my username"})
+(def the-objective {:some :data
+                    :end-date (utils/string->date-time "2015-01-31")})

-(def the-stored-objective (into the-objective {:_id OBJECTIVE_ID}))
+(fact "creating an objective hits the correct API endpoint"
+      (http-api/create-objective the-objective) => :api-call-result
+      (provided
+        (http-api/default-create-call
+          (contains "/api/v1/objectives")
+          {:some :data
+           :end-date "2015-01-31T00:00:00.000Z"}) => :api-call-result))

-(facts "about posting objectives"
-       (fact "returns a stored objective when post succeeds"
-             (http-api/create-objective the-objective) => {:status ::http-api/success
-                                                           :result the-stored-objective}
-             (provided (http-api/post-request (contains "/api/v1/objectives")
-                                              request-with-bearer-token)
-                       => {:status 201
-                           :headers {"Content-Type" "application/json"}
-                           :body (json/generate-string the-stored-objective)}))
-
-       (fact "returns api-failure when post fails"
-             (http-api/create-objective the-objective) => {:status ::http-api/error}
-             (provided (http-api/post-request anything anything) => {:status 500})))
-
-(facts "about getting objectives"
-       (fact "returns a stored objective when one exists with given id"
-             (with-fake-http [(str host-url "/api/v1/objectives/" OBJECTIVE_ID)
-                              {:status 200
-                               :headers {"Content-Type" "application/json"}
-                               :body (json/generate-string
-                                       {:_id OBJECTIVE_ID
-                                        :title "Objective title"
-                                        :goals "Objective goals"
-                                        :description "Objective description"
-                                        :end-date "2015-01-31T00:00:00.000Z"})}]
-               (http-api/get-objective OBJECTIVE_ID))
-             => (contains {:status ::http-api/success
-                           :result (contains {:_id OBJECTIVE_ID
-                                              :title "Objective title"
-                                              :goals "Objective goals"
-                                              :description "Objective description"
-                                              :end-date (utils/time-string->date-time "2015-01-31T00:00:00.000Z")})}))
-
-       (fact "returns 404 when no objective found"
-             (with-fake-http [(str host-url "/api/v1/objectives/" OBJECTIVE_ID)
-                              {:status 404}]
-               (http-api/get-objective OBJECTIVE_ID))
-             => (contains {:status ::http-api/not-found})))
+(fact "getting an objective hits the correct API endpoint"
+      (http-api/get-objective OBJECTIVE_ID) => {:status ::http-api/success
+                                                :result the-objective}
+      (provided
+        (http-api/default-get-call
+          (contains (str "/api/v1/objectives/" OBJECTIVE_ID))) => {:status ::http-api/success
+                                                                   :result {:some :data
+                                                                            :end-date "2015-01-31T00:00:00.000Z" }}))

 ;; COMMENTS

-(def the-comment {:comment "The comment"
-                  :objective-id OBJECTIVE_ID
-                  :username "my username"})
+(fact "creating a comment hits the correct API endpoint"
+      (http-api/create-comment {:some :data}) => :api-call-result
+      (provided
+        (http-api/default-create-call (contains "/api/v1/comments") {:some :data}) => :api-call-result))

-(def the-stored-comment (into the-comment {:_id 1}))

-(facts "about posting comments"
-       (fact "returns a stored comment when post succeeds"
-             (http-api/create-comment the-comment) => {:status ::http-api/success :result the-stored-comment}
-             (provided (http-api/post-request (contains "/api/v1/comments")
-                                              request-with-bearer-token)
-                       =>{:status 201
-                          :headers {"Content-Type" "application/json"}
-                          :body (json/generate-string the-stored-comment)}))
-
-       (fact "returns api-failure when post fails"
-             (http-api/create-comment the-comment) => {:status ::http-api/error}
-             (provided (http-api/post-request anything anything) => {:status 500})))
-
-(facts "about retrieving comments"
-       (fact "returns a list of comments for an objective"
-             (with-fake-http [(str host-url "/api/v1/objectives/1/comments") {:status 200
-                                                                              :headers {"Content-Type" "application/json"}
-                                                                              :body (json/generate-string [the-stored-comment])}]
-               (http-api/retrieve-comments 1))
-             => {:status ::http-api/success
-                 :result [the-stored-comment]}))
+(fact "retrieving comments for an objective hits the correct API endpoint"
+      (http-api/retrieve-comments OBJECTIVE_ID) => :api-call-result
+      (provided
+        (http-api/default-get-call (contains (str "/api/v1/objectives/" OBJECTIVE_ID "/comments"))) => :api-call-result))

 ;; QUESTIONS

-(def the-question {:question "The meaning of life?"
-                   :objective-id OBJECTIVE_ID
-                   :created-by USER_ID})
+(def the-question {:some :data
+                   :objective-id OBJECTIVE_ID})

 (def QUESTION_ID 42)

-(def the-stored-question (into the-question {:_id QUESTION_ID}))
+(fact "creating a question hits the correct API endpoint"
+      (http-api/create-question the-question) => :api-call-result
+      (provided
+        (http-api/default-create-call
+          (contains (str "/api/v1/objectives/" OBJECTIVE_ID "/questions"))
+          the-question) => :api-call-result))

-(facts "about posting questions"
-       (fact "returns a stored question when post succeeds"
-             (http-api/create-question the-question) => {:status ::http-api/success
-                                                         :result the-stored-question}
-             (provided (http-api/post-request (contains (str "/api/v1/objectives/" OBJECTIVE_ID "/questions"))
-                                              request-with-bearer-token)
-                       => {:status 201
-                           :headers {"Content-Type" "application/json"}
-                           :body (json/generate-string the-stored-question)}))
+(fact "getting a question for an objective hits the correct API endpoint"
+      (http-api/get-question OBJECTIVE_ID QUESTION_ID) => :api-call-result
+      (provided (http-api/default-get-call (contains (str "/api/v1/objectives/" OBJECTIVE_ID
+                                                          "/questions/" QUESTION_ID))) => :api-call-result))

-       (fact "returns api-failure when post fails"
-             (http-api/create-question the-question) => {:status ::http-api/error}
-             (provided (http-api/post-request anything anything) => {:status 500})))
-
-(facts "about getting questions"
-       (fact "returns a stored question when one exists with a given id"
-             (with-fake-http [(str host-url "/api/v1/objectives/" OBJECTIVE_ID "/questions/" QUESTION_ID) {:status 200
-                                                                                :headers {"Content-Type" "application/json"}
-                                                                                :body (json/generate-string the-stored-question)}]
-               (http-api/get-question OBJECTIVE_ID QUESTION_ID))
-             => {:status ::http-api/success
-                 :result the-stored-question})
-
-       (fact "returns :objective8.http-api/error when request fails"
-             (with-fake-http [(str host-url "/api/v1/objectives/" OBJECTIVE_ID "/questions/" QUESTION_ID) {:status 500}]
-               (http-api/get-question OBJECTIVE_ID QUESTION_ID))
-             => {:status ::http-api/error})
-
-       (fact "returns :objective8.http-api/not-found when no question with that id exists"
-             (with-fake-http [(str host-url "/api/v1/objectives/" OBJECTIVE_ID "/questions/" QUESTION_ID) {:status 404}]
-               (http-api/get-question OBJECTIVE_ID QUESTION_ID))
-             => {:status ::http-api/not-found}))
-
-(facts "about retrieving questions"
-       (fact "returns a list of questions for a given objective"
-             (with-fake-http [(str host-url "/api/v1/objectives/"
-                                   OBJECTIVE_ID "/questions") {:status 200
-                                                               :headers {"Content-Type" "application/json"}
-                                                               :body (json/generate-string [the-stored-question])}]
-               (http-api/retrieve-questions OBJECTIVE_ID)) => {:status ::http-api/success
-                                                               :result [the-stored-question]}))
+(fact "getting all questions for an objective hits the correct API endpoint"
+      (http-api/retrieve-questions OBJECTIVE_ID) => :api-call-result
+      (provided
+        (http-api/default-get-call (contains (str "/api/v1/objectives/" OBJECTIVE_ID
+                                                  "/questions"))) => :api-call-result))
 ;; ANSWERS

-(def the-answer {:answer "The answer"
+(def the-answer {:some :data
                  :objective-id OBJECTIVE_ID
-                 :question-id QUESTION_ID
-                 :created-by-id USER_ID})
-(def the-stored-answer (into the-answer {:_id 3}))
+                 :question-id QUESTION_ID})

-(facts "about posting answers"
-       (fact "returns a stored answer when post succeeds"
-             (http-api/create-answer the-answer) => {:status ::http-api/success
-                                                     :result the-stored-answer}
-             (provided (http-api/post-request (contains (str host-url "/api/v1/objectives/" OBJECTIVE_ID
+(fact "creating an answer hits the correct API endpoint"
+      (http-api/create-answer the-answer) => :api-call-result
+      (provided (http-api/default-create-call (contains (str host-url "/api/v1/objectives/" OBJECTIVE_ID
                                                              "/questions/" QUESTION_ID "/answers"))
-                                              request-with-bearer-token)
-                       => {:status 201
-                           :headers {"Content-Type" "application/json"}
-                           :body (json/generate-string the-stored-answer)}))
+                  the-answer) => :api-call-result))

-       (fact "returns :objective8.http-api/invalid when request is invalid"
-             (http-api/create-answer the-answer) => {:status ::http-api/invalid-input}
-             (provided (http-api/post-request anything anything) => {:status 400}))
-
-       (fact "returns :objective8.http-api/error when request fails"
-             (http-api/create-answer the-answer) => {:status ::http-api/error}
-             (provided (http-api/post-request anything anything) => {:status 500})))
-
-(facts "about retrieving answers"
-       (fact "returns a list of answers for a given objective and question"
-             (with-fake-http [(str host-url "/api/v1/objectives/" OBJECTIVE_ID
-                                   "/questions/" QUESTION_ID "/answers") {:status 200
-                                                                          :headers {"Content-Type" "application/json"}
-                                                                          :body (json/generate-string [the-stored-answer])}]
-               (http-api/retrieve-answers OBJECTIVE_ID QUESTION_ID)) => {:status ::http-api/success
-                                                                         :result [the-stored-answer]}))
+(fact "getting all answers for a question hits the correct API endpoint"
+      (http-api/retrieve-answers OBJECTIVE_ID QUESTION_ID) => :api-call-result
+      (provided
+        (http-api/default-get-call (contains (str "/api/v1/objectives/" OBJECTIVE_ID
+                                                  "/questions/" QUESTION_ID "/answers"))) => :api-call-result))


log when we run scheduled jobs

log when we run scheduled jobs

--- src/pc/utils.clj
+++ src/pc/utils.clj
@@ -63,7 +63,9 @@
   with the same var."
   [schedule f]
   (assert (var? f))
-  (let [new-job (schejulure/schedule schedule (fn [] (future (f))))]
+  (let [new-job (schejulure/schedule schedule (fn []
+                                                (log/infof "running %s" f)
+                                                (future (f))))]
     (dosync
      (alter safe-scheduled-jobs
             (fn [jobs]


시작시 DB init

시작시 DB init

--- src/scr/core.clj
+++ src/scr/core.clj
@@ -114,4 +114,5 @@

 (defn -main []
   (log/info "listen on port 5678")
+  (sql/init)
   (run-server #'app {:port 5678}))


Rewrite wrap-words

Rewrite wrap-words

--- src/str/core.clj
+++ src/str/core.clj
@@ -384,25 +384,6 @@
          true s)
     s))

-(defn wrap-words
-  "Insert newlines in s so the length of each line doesn't exceed width."
-  [^String s width]
-  (let [words (remove empty? (split s #"\n|\t|\n| "))]
-    (loop [out (StringBuffer.), remaining-words words, current-width 0]
-      (cond
-        (not (seq remaining-words)) (trimr (.toString out))
-
-        (<= (+ current-width (inc (.length (first remaining-words)))) width)
-        (recur (.append out (str (first remaining-words) " ")) (rest remaining-words)
-               (+ current-width (inc (.length (first remaining-words)))))
-
-        (>= (.length (first remaining-words)) width)
-        (do (when (= (.charAt out (dec (.length out))) \space)
-              (.deleteCharAt out (dec (.length out))))
-            (recur (.append out (str "\n" (first remaining-words))) (rest remaining-words) width))
-
-        :else (recur (.append out "\n") remaining-words 0)))))
-
 (defn- split-words [^String s]
   (remove empty?
           (-> s
@@ -413,6 +394,21 @@
                #"(\p{javaLowerCase})(\p{javaUpperCase})" "$1 $2")
               (split
                #"[^\w0-9]+"))))
+
+(defn wrap-words
+  "Insert newlines in s so the length of each line doesn't exceed width."
+  [^String s width]
+  (->> (split s #"\n|\t|\n| ")
+       (remove empty?)
+       (reduce
+        (fn [{:keys [len res]} word]
+          (if (< (+ len (.length word)) width)
+            {:len (+ len (.length word) 1) :res (conj res " " word)}
+            {:len (.length word) :res (conj res "\n" word)}))
+        {:len 0 :res []})
+       :res
+       rest ; drop leading " "
+       (apply str)))

 (defn ^String lisp-case
   "Lower case s and separate words with dashes.


No need for model function when we have it as data

--- src-cljs/frontend/components/pages/projects.cljs
+++ src-cljs/frontend/components/pages/projects.cljs
@@ -188,4 +188,4 @@
               [:.main
                (if selected-org
                  (org-projects selected-org)
-                 (no-org-selected orgs (user/bitbucket-authorized? current-user)))]])))}))))
+                 (no-org-selected orgs (:user/bitbucket-authorized? current-user)))]])))}))))


Deprioritize tracking in WF cancel click handler

In case the analytics tracking throws, the run cancel mutation should
happen before tracking

--- src-cljs/frontend/components/pieces/run_row.cljs
+++ src-cljs/frontend/components/pieces/run_row.cljs
@@ -196,8 +196,8 @@
                  (contains? cancelable-statuses status)
                  [:div.action-button.cancel-button
                   {:on-click (fn [_]
-                               (analytics/track! this {:event-type :cancel-clicked})
-                               (transact-run-cancel this id vcs-type org-name project-name))}
+                               (transact-run-cancel this id vcs-type org-name project-name)
+                               (analytics/track! this {:event-type :cancel-clicked}))}
                   (icon/status-canceled)
                   [:span "cancel"]]
                  (contains? rerunnable-statuses status)


Minor cleanup

Minor cleanup

--- src/angelic/search/summaries.clj
+++ src/angelic/search/summaries.clj
@@ -235,17 +235,13 @@
 (comment
  (defn make-leaf-summarizable [reward status]
    (traits/reify-traits [simple-node uncached-summarizer-node (leaf-summarizable reward status)]))
-
- (def worst-summarizable (make-leaf-summarizable Double/NEGATIVE_INFINITY :blocked)))
-
-
-
-(comment
- (defn bound-subsuming [s sum]
-   (summary/bound sum (summary/max-reward (apply summary/min (map summary (node-subsuming-children s))))))
-
- (defn bound-subsuming-x [s sum extra-bound]
-   (summary/bound sum (min extra-bound (summary/max-reward (apply summary/min (map summary (node-subsuming-children s))))))))
+)
+
+(def worst-summarizable
+     (traits/reify-traits [(leaf-summarizable :worst Double/NEGATIVE_INFINITY :blocked)
+                           (fixed-node nil) uncached-summarizer-node] ))
+
+

 ;; Initially shoud be a parent of init, without having child.


Fix -exactly s-c-r shape; indices needed to be bowtie or star

--- src/aerobio/validate/expsheet.clj
+++ src/aerobio/validate/expsheet.clj
@@ -56,9 +56,13 @@

 (defn gbk? [x] (contains? (get-exp-sheet-data (x :EID) :gbks) (x :ncid)))
 (defn gtf? [x] (contains? (get-exp-sheet-data (x :EID) :gtfs) (x :ncid)))
+
 (defn index? [x] (contains? (get-exp-sheet-data (x :EID) :indices) (x :ncid)))
 (defn bt1index? [x]
   (contains? (get-exp-sheet-data (x :EID) :bt1indices) (x :ncid)))
+(defn starindex? [x]
+  (contains? (get-exp-sheet-data (x :EID) :starindices) (x :ncid)))
+
 (defn normgenes? [x]
   (or (not= (ac/get-exp-info (x :EID) :exp) :tnseq)
       (contains? (get-exp-sheet-data (x :EID) :norms) (x :ncid))))
@@ -66,8 +70,12 @@

 (s/def ::gbk? gbk?)
 (s/def ::gtf? gtf?)
+
 (s/def ::index? index?)
 (s/def ::bt1index? bt1index?)
+(s/def ::bowtie? (s/and ::index? ::bt1index?))
+(s/def ::starindex? starindex?)
+(s/def ::bowtie-or-star? (s/or :bowtie ::bowtie? :star ::starindex?))
 (s/def ::normgenes? normgenes?)

 (s/def ::ncid string?)
@@ -75,7 +83,7 @@

 (s/def ::nc-xref-rec
   (s/merge (s/keys :req-un [::ncid ::expnm])
-           ::gbk? ::gtf? ::index? ::bt1index? ::normgenes?))
+           ::gbk? ::gtf? ::bowtie-or-star? ::normgenes?))
 (s/def ::nc-xref-recs (s/coll-of ::nc-xref-rec))

@@ -87,6 +95,7 @@
   [_ problem]
   (format "reference `%s` does not have a registered gtf"
           (-> problem :val :ncid)))
+
 (p/defphraser index?
   [_ problem]
   (format "reference `%s` does not have a Bowtie-2 index"
@@ -95,6 +104,11 @@
   [_ problem]
   (format "reference `%s` does not have a Bowtie-1 index"
           (-> problem :val :ncid)))
+(p/defphraser starindex?
+  [_ problem]
+  (format "reference `%s` does not have a STAR index"
+          (-> problem :val :ncid)))
+
 (p/defphraser normgenes?
   [_ problem]
   (format "reference `%s` does not have normalization genes registered"
@@ -116,9 +130,17 @@
   (contains? (get-exp-sheet-data (x :EID) :strains) (x :s)))

 (defn nodup? [x] (= 0 (x :dupcnt)))
-(defn cond-ok? [x] (re-matches #"[A-Za-z0-9]+" (x :c)))
-(defn repid-ok? [x] (re-matches #"[A-Z]|[a-z]|[0-9]" (x :r)))
-(defn len3? [x] (= (count (dissoc x :EID :v :dupcnt)) 3))
+
+(defn cond-ok? [x]
+  (let [c (x :c)]
+    (and c (re-matches #"[A-Za-z0-9]+" (x :c)))))
+
+(defn repid-ok? [x]
+  (let [r (x :r)]
+    (and r (re-matches #"[A-Z]|[a-z]|[0-9]" (x :r)))))
+
+(defn len3? [x] (and (= (count (dissoc x :EID :v :dupcnt)) 3)
+                     (x :s) (x :c) (x :r)))

 (s/def ::len3? len3?)
 (s/def ::strain? strain?)