Convert search ns

Convert search ns

--- src/cljs/clojuredocs/mods/search.cljs
+++ src/cljs/clojuredocs/mods/search.cljs
@@ -1,5 +1,7 @@
 (ns clojuredocs.mods.search
-  (:require [om.core :as om :include-macros true]
+  (:require [reagent.core :as rea]
+            [nsfw.ops :as ops]
+            [nsfw.page :as page]
             [dommy.core :as dommy :refer-macros [sel1 sel]]
             [cljs.core.async :as async
              :refer [<! >! chan close! sliding-buffer put! alts! timeout pipe mult tap]]
@@ -7,7 +9,6 @@
             [clojuredocs.anim :as anim]
             [clojure.string :as str]
             [cljs.reader :as reader]
-            [sablono.core :as sab :refer-macros [html]]
             [clojuredocs.util :as util]
             [clojuredocs.metrics :as metrics])
   (:require-macros [cljs.core.async.macros :refer [go go-loop]]))
@@ -35,12 +36,15 @@
       [:div.see-alsos
        [:span.see-also-label "see also:"]
        [:ul
-        (for [{:keys [ns name href] :as sa} see-alsos]
-          [:li
-           [:a {:href href :class "var-link"}
-            [:span.namespace ns]
-            "/"
-            [:span.name name]]])]
+        (->> see-alsos
+             (map-indexed
+               (fn [i {:keys [ns name] :as sa}]
+                 ^{:key i}
+                 [:li
+                  [:a {:href "#" :class "var-link"}
+                   [:span.namespace ns]
+                   "/"
+                   [:span.name name]]])))]
        (when (> num-left 0)
          [:span.remaining-label
           (str "+ " num-left " more")])])))
@@ -84,206 +88,422 @@
     (= "page" type) ($ac-entry-page ac-entry)
     :else (.log js/console (str "Couldn't render ac entry:" type))))

-(defn search-keydown [e app ac-results text-chan]
-  (when app
-    (let [ctrl? (.-ctrlKey e)
-          key-code (.-keyCode e)
-          {:keys [highlighted-index]} @app]
-      (when (= 27 key-code)
-        (om/update! app :ac-text "")
-        (om/update! app :ac-results nil)
-        (put! text-chan ""))
-      (let [f (cond
-                (and ctrl? (= 78 key-code)) inc ; ctrl-n
-                (= 40 key-code) inc             ; down arrow
-                (and ctrl? (= 80 key-code)) dec ; ctrl-p
-                (= 38 key-code) dec             ; up arrow
-                :else identity)]
-        (when (and (not (= identity f))
-                   (not (and (= inc f)
-                             (= highlighted-index (dec (count ac-results)))))
-                   (not (and (= dec f)
-                             (= highlighted-index 0))))
-          (om/transact! app :highlighted-index f))
-        (when (not (= identity f))
-          false)))))
-
-
 (defn focused? [$el]
   (= $el (.-activeElement js/document)))

-(defn $quick-search-bar
-  [{:keys [highlighted-index search-loading?
-           ac-results ac-text search-focused?] :as app} owner]
-  (reify
-    om/IDidMount
-    (did-mount [_]
-      (let [$input (om/get-node owner "input")]
-        (when (and (not (focused? $input))
-                   search-focused?)
-          (.focus $input)
-          (aset $input "value" (.-value $input)))))
-    om/IDidUpdate
-    (did-update [_ _ _]
-      (handle-search-active-state ac-text)
-      (let [$input (om/get-node owner "input")]
-        (when (and (not (focused? $input))
-                   search-focused?)
-          (.focus $input)
-          (aset $input "value" (.-value $input)))))
-    om/IRenderState
-    (render-state [this {:keys [text-chan action-ch placeholder]}]
-      (sab/html
-        [:form.search
-         {:autoComplete "off"
-          :on-submit #(do
-                        (let [{:keys [highlighted-index ac-results]} @app]
-                          (put! action-ch (nth ac-results (or highlighted-index 0))))
-                        false)
-          :action "/search"
-          :method :get}
-         [:input.form-control.query
-          {:class (when search-loading? " loading")
-           :placeholder (or placeholder "Looking for? (ctrl-s)")
-           :name "q"
-           :autoComplete "off"
-           :ref "input"
-           :value ac-text
-           :on-change #(let [text (.. % -target -value)]
-                         (put! text-chan text)
-                         (om/update! app :ac-text text))
-           :on-key-down #(search-keydown % app ac-results text-chan)}]]))))
+#_(defn $quick-search-bar
+    [{:keys [highlighted-index search-loading?
+             ac-results ac-text search-focused?] :as app} owner]
+    (reify
+      om/IDidMount
+      (did-mount [_]
+        (let [$input (om/get-node owner "input")]
+          (when (and (not (focused? $input))
+                     search-focused?)
+            (.focus $input)
+            (aset $input "value" (.-value $input)))))
+      om/IDidUpdate
+      (did-update [_ _ _]
+        (handle-search-active-state ac-text)
+        (let [$input (om/get-node owner "input")]
+          (when (and (not (focused? $input))
+                     search-focused?)
+            (.focus $input)
+            (aset $input "value" (.-value $input)))))
+      om/IRenderState
+      (render-state [this {:keys [text-chan action-ch placeholder]}]
+        (sab/html
+          [:form.search
+           {:autoComplete "off"
+            :on-submit #(do
+                          (let [{:keys [highlighted-index ac-results]} @app]
+                            (put! action-ch (nth ac-results (or highlighted-index 0))))
+                          false)
+            :action "/search"
+            :method :get}
+           [:input.form-control.query
+            {:class (when search-loading? " loading")
+             :placeholder (or placeholder "Looking for? (ctrl-s)")
+             :name "q"
+             :autoComplete "off"
+             :ref "input"
+             :value ac-text
+             :on-change #(let [text (.. % -target -value)]
+                           (put! text-chan text)
+                           (om/update! app :ac-text text))
+             :on-key-down #(search-keydown % app ac-results text-chan)}]]))))
+
+#_ #(search-keydown % app ac-results text-chan)
+
+#_(defn search-keydown [e app ac-results text-chan]
+    (when app
+      (let [ctrl? (.-ctrlKey e)
+            key-code (.-keyCode e)
+            {:keys [highlighted-index]} @app]
+
+        ;; execute search
+        (when (= 27 key-code)
+          (om/update! app :ac-text "")
+          (om/update! app :ac-results nil)
+          (put! text-chan ""))
+
+
+        (let [f (cond
+                  (and ctrl? (= 78 key-code)) inc ; ctrl-n
+                  (= 40 key-code) inc             ; down arrow
+                  (and ctrl? (= 80 key-code)) dec ; ctrl-p
+                  (= 38 key-code) dec             ; up arrow
+                  :else identity)]
+          (when (and (not (= identity f))
+                     (not (and (= inc f)
+                               (= highlighted-index (dec (count ac-results)))))
+                     (not (and (= dec f)
+                               (= highlighted-index 0))))
+            (om/transact! app :highlighted-index f))
+          (when (not (= identity f))
+            false)))))
+
+(defn cancel-search? [{:keys [key-code]}]
+  (= 27 key-code))
+
+(defn next-res? [{:keys [key-code ctrl?]}]
+  (or (and ctrl? (= 78 key-code)) ; ctrl-n
+      (= 40 key-code)             ; down arrow
+      ))
+
+(defn prev-res? [{:keys [key-code ctrl?]}]
+  (or (and ctrl? (= 80 key-code)) ; ctrl-p
+      (= 38 key-code)             ; up arrow
+      ))
+
+(defn $quick-search-bar [app bus]
+  (let [on-change-throttle
+        (page/throttle-debounce
+          (fn [text]
+            (ops/send bus ::ac-text-throttled text))
+          {:throttle 200
+           :debounce 200})]
+    (rea/create-class
+      {:reagent-render
+       (fn [{:keys [highlighted-index search-loading?
+                    ac-results ac-text search-focused?
+                    placeholder] :as app}]
+         [:form.search
+          {:autoComplete "off"
+           :on-submit (fn [e]
+                        (ops/send bus
+                          ::ac-select
+                          (nth ac-results (or highlighted-index 0)))
+                        (.preventDefault e)
+                        nil)
+           :action "/search"
+           :method :get}
+          [:input.form-control.query
+           {:class (when search-loading? " loading")
+            :placeholder (or placeholder "Looking for? (ctrl-s)")
+            :name "q"
+            :autoComplete "off"
+            :ref "input"
+            :value ac-text
+            :on-change (fn [e]
+                         (let [text (.. e -target -value)]
+                           (ops/send bus ::ac-text-changed text)
+                           (on-change-throttle text)))
+            :on-key-down (fn [e]
+                           (let [act {:key-code (.-keyCode e)
+                                      :ctrl? (.-ctrlKey e)}]
+                             (cond
+                               (cancel-search? act) (do
+                                                      (ops/send bus ::cancel-search ac-text)
+                                                      (.preventDefault e))
+                               (next-res? act) (do
+                                                 (ops/send bus ::move-highlight 1)
+                                                 (.preventDefault e))
+                               (prev-res? act) (do
+                                                 (ops/send bus ::move-highlight -1)
+                                                 (.preventDefault e)))))}]])
+       :did-mount (fn []
+                    #_(let [$input (om/get-node owner "input")]
+                        (when (and (not (focused? $input))
+                                   search-focused?)
+                          (.focus $input)
+                          (aset $input "value" (.-value $input)))))
+       :did-update (fn [])
+       #_(fn []
+           (handle-search-active-state ac-text)
+           (let [$input (om/get-node owner "input")]
+             (when (and (not (focused? $input))
+                        search-focused?)
+               (.focus $input)
+               (aset $input "value" (.-value $input)))))})))
+
+(defn $quick-search-widget [!state bus]
+  [$quick-search-bar
+   (merge @!state {:placeholder "Looking for? (ctrl-s)"})
+   bus])
+
+#_(defn $ac-results [{:keys [highlighted-index ac-results results-empty?]
+                      :or {highlighted-index 0}
+                      :as app}
+                     owner]
+    (reify
+      om/IDidUpdate
+      (did-update [_ prev-props prev-state]
+        (when (> (count ac-results) 0)
+          (let [$el (om/get-node owner)]
+            (when (and (not= (:highlighted-index prev-props)
+                             (:highlighted-index app))
+                       $el)
+              (anim/scroll-into-view $el {:pad 130})))))
+      om/IRenderState
+      (render-state [this {:keys [action-ch]}]
+        (sab/html
+          [:ul.ac-results
+           (if results-empty?
+             [:li.null-state "Nothing Found"]
+             (map-indexed
+               (fn [i {:keys [href type] :as res}]
+                 [:li {:on-click #(do
+                                    (put! action-ch res)
+                                    false)
+                       :class (when (= i highlighted-index)
+                                "highlighted")
+                       :ref i}
+                  ($ac-entry res)])
+               ac-results))]))))

 (defn $ac-results [{:keys [highlighted-index ac-results results-empty?]
                     :or {highlighted-index 0}
                     :as app}
-                   owner]
-  (reify
-    om/IDidUpdate
-    (did-update [_ prev-props prev-state]
-      (when (> (count ac-results) 0)
-        (let [$el (om/get-node owner)]
-          (when (and (not= (:highlighted-index prev-props)
-                           (:highlighted-index app))
-                     $el)
-            (anim/scroll-into-view $el {:pad 130})))))
-    om/IRenderState
-    (render-state [this {:keys [action-ch]}]
-      (sab/html
-        [:ul.ac-results
-         (if results-empty?
-           [:li.null-state "Nothing Found"]
-           (map-indexed
-             (fn [i {:keys [href type] :as res}]
-               [:li {:on-click #(do
-                                  (put! action-ch res)
-                                  false)
-                     :class (when (= i highlighted-index)
-                              "highlighted")
-                     :ref i}
-                ($ac-entry res)])
-             ac-results))]))))
+                   bus]
+  (rea/create-class
+    {:component-did-update (fn [this old-argv]
+                             (let [{:keys [ac-results] :as app}
+                                   (second (rea/argv this))
+                                   old-app (second old-argv)]
+                               (when (> (count ac-results) 0)
+                                 (let [$el (dommy/sel1
+                                             (rea/dom-node this)
+                                             (str "#ac-" (:highlighted-index app)))]
+                                   (when (and (not= (:highlighted-index old-app)
+                                                    (:highlighted-index app))
+                                              $el)
+                                     (anim/scroll-into-view $el {:pad 130}))))))
+     :reagent-render (fn [{:keys [highlighted-index ac-results results-empty?]
+                           :or {highlighted-index 0}
+                           :as app}
+                          bus]
+                       [:ul.ac-results
+                        (if results-empty?
+                          [:li.null-state "Nothing Found"]
+                          (map-indexed
+                            (fn [i {:keys [href type] :as res}]
+                              ^{:key i}
+                              [:li {:on-click (fn [_]
+                                                (ops/send bus
+                                                  ::select-ac-result
+                                                  res)
+                                                nil)
+                                    :class (when (= i highlighted-index)
+                                             "highlighted")
+                                    :id (str "ac-" i)}
+                               ($ac-entry res)])
+                            ac-results))])}))
+
+(defn $ac-results-widget [!state bus]
+  [$ac-results @!state bus])
+
+#_(defn $quick-lookup-widget
+    [{:keys [highlighted-index ac-results ac-text search-loading? results-empty?]
+      :or {highlighted-index 0}
+      :as app}
+     owner]
+    (reify
+      om/IRenderState
+      (render-state [this {:keys [text-chan
+                                  action-ch]}]
+        (sab/html
+          [:div.quick-lookup-wrapper
+           (om/build $quick-search-bar app {:init-state {:text-chan text-chan
+                                                         :action-ch action-ch
+                                                         :placeholder "Looking for?"}})
+           [:div.not-finding {:class "not-finding"}
+            "Can't find what you're looking for? "
+            [:a.search-feedback
+             {:href (str "/search-feedback"
+                         (when ac-text (str "?query=" (util/url-encode ac-text))))}
+             "Help make ClojureDocs better"]
+            "."]
+           (om/build $ac-results app {:init-state {:action-ch action-ch}})]))))

 (defn $quick-lookup-widget
-  [{:keys [highlighted-index ac-results ac-text search-loading? results-empty?]
-    :or {highlighted-index 0}
-    :as app}
-   owner]
-  (reify
-    om/IRenderState
-    (render-state [this {:keys [text-chan
-                                action-ch]}]
-      (sab/html
-        [:div.quick-lookup-wrapper
-         (om/build $quick-search-bar app {:init-state {:text-chan text-chan
-                                                       :action-ch action-ch
-                                                       :placeholder "Looking for?"}})
-         [:div.not-finding {:class "not-finding"}
-          "Can't find what you're looking for? "
-          [:a.search-feedback
-           {:href (str "/search-feedback"
-                       (when ac-text (str "?query=" (util/url-encode ac-text))))}
-           "Help make ClojureDocs better"]
-          "."]
-         (om/build $ac-results app {:init-state {:action-ch action-ch}})]))))
-
-(defn submit-feedback [owner query clojure-level text]
-  (om/set-state! owner :loading? true)
-  (om/set-state! owner :error-message nil)
-  (ajax
-    {:method :post
-     :path (str "/search-feedback")
-     :data {:query query
-            :clojure-level clojure-level
-            :text text}
-     :data-type :edn
-     :success (fn [_]
-                (util/navigate-to "/search-feedback/success"))
-     :error (fn [& args]
-              (om/set-state! owner
-                :error-message
-                "There was a problem sending your feedback, try again.")
-              (om/set-state! owner :loading? false))})
-  false)
-
-(defn $search-feedback [app owner]
-  (reify
-    om/IWillMount
-    (will-mount [_]
-      (let [query (om/get-state owner :query)]
-        (om/set-state! owner
-          :text (when-not (empty? query)
-                  (str
-                    "Hey ClojureDocs, I searched for \""
-                    query
-                    "\", but couldn't find what I was looking for. Here's a description of what I would have liked to find:")))))
-    om/IRenderState
-    (render-state [_ {:keys [text loading? clojure-level query error-message]}]
-      (sab/html
-        [:form {:on-submit #(submit-feedback owner query clojure-level text)}
-         [:div.form-group
-          [:label.clojure-level
-           "Level of Clojuring"]
-          [:div.radio
-           [:label.radio
-            [:input {:type "radio"
-                     :name "clojure-level"
-                     :value "beginner"
-                     :on-click #(om/set-state! owner :clojure-level "beginner")
-                     :disabled (if loading? "disabled")}]
-            "I haven't written any Clojure"]
-           [:label.radio
-            [:input {:type "radio"
-                     :name "clojure-level"
-                     :value "intermediate"
-                     :on-click #(om/set-state! owner :clojure-level "intermediate")
-                     :disabled (if loading? "disabled")}]
-            "I've done a few things in Clojure"]
-           [:label.radio
-            [:input.radio
-             {:type "radio"
-              :name "clojure-level"
-              :value "advanced"
-              :on-click #(om/set-state! owner :clojure-level "advanced")
-              :disabled (if loading? "disabled")}]
-            "I'm comfortable contributing to Clojure projects"]]]
-         [:div.form-group
-          [:label {:for "feedback"} "Feedback"]
-          [:textarea {:class "form-control"
-                      :rows 10
-                      :name "feedback"
-                      :value text
-                      :on-input #(om/set-state! owner :text (.. % -target -value))
-                      :disabled (if loading? "disabled")}]]
-         [:div.form-group
-          [:span {:class (str "error-message" (when-not error-message " hidden"))}
-           [:i.fa.fa-exclamation-circle]
-           error-message]
-          [:button.btn.btn-default.pull-right
-           {:disabled (if loading? "disabled")}
-           "Send Feedback"]
-          [:img {:class (str "pull-right loading" (when-not loading? " hidden"))
-                 :src "/img/loading.gif"}]]]))))
+  [!state bus]
+  (let [{:keys [highlighted-index ac-results ac-text search-loading? results-empty?]
+         :or {highlighted-index 0}
+         :as app}
+        @!state]
+    [:div.quick-lookup-wrapper
+     [$quick-search-bar
+      (merge app {:placeholder "Looking for?"})
+      bus]
+     [:div.not-finding {:class "not-finding"}
+      "Can't find what you're looking for? "
+      [:a.search-feedback
+       {:href (str "/search-feedback"
+                   (when ac-text (str "?query=" (util/url-encode ac-text))))}
+       "Help make ClojureDocs better"]
+      "."]
+     [$ac-results app bus]]))
+
+#_(defn submit-feedback [owner query clojure-level text]
+    (om/set-state! owner :loading? true)
+    (om/set-state! owner :error-message nil)
+    (ajax
+      {:method :post
+       :path (str "/search-feedback")
+       :data {:query query
+              :clojure-level clojure-level
+              :text text}
+       :data-type :edn
+       :success (fn [_]
+                  (util/navigate-to "/search-feedback/success"))
+       :error (fn [& args]
+                (om/set-state! owner
+                  :error-message
+                  "There was a problem sending your feedback, try again.")
+                (om/set-state! owner :loading? false))})
+    false)
+
+#_(defn $search-feedback [app owner]
+    (reify
+      om/IWillMount
+      (will-mount [_]
+        (let [query (om/get-state owner :query)]
+          (om/set-state! owner
+            :text (when-not (empty? query)
+                    (str
+                      "Hey ClojureDocs, I searched for \""
+                      query
+                      "\", but couldn't find what I was looking for. Here's a description of what I would have liked to find:")))))
+      om/IRenderState
+      (render-state [_ {:keys [text loading? clojure-level query error-message]}]
+        (sab/html
+          [:form {:on-submit #(submit-feedback owner query clojure-level text)}
+           [:div.form-group
+            [:label.clojure-level
+             "Level of Clojuring"]
+            [:div.radio
+             [:label.radio
+              [:input {:type "radio"
+                       :name "clojure-level"
+                       :value "beginner"
+                       :on-click #(om/set-state! owner :clojure-level "beginner")
+                       :disabled (if loading? "disabled")}]
+              "I haven't written any Clojure"]
+             [:label.radio
+              [:input {:type "radio"
+                       :name "clojure-level"
+                       :value "intermediate"
+                       :on-click #(om/set-state! owner :clojure-level "intermediate")
+                       :disabled (if loading? "disabled")}]
+              "I've done a few things in Clojure"]
+             [:label.radio
+              [:input.radio
+               {:type "radio"
+                :name "clojure-level"
+                :value "advanced"
+                :on-click #(om/set-state! owner :clojure-level "advanced")
+                :disabled (if loading? "disabled")}]
+              "I'm comfortable contributing to Clojure projects"]]]
+           [:div.form-group
+            [:label {:for "feedback"} "Feedback"]
+            [:textarea {:class "form-control"
+                        :rows 10
+                        :name "feedback"
+                        :value text
+                        :on-input #(om/set-state! owner :text (.. % -target -value))
+                        :disabled (if loading? "disabled")}]]
+           [:div.form-group
+            [:span {:class (str "error-message" (when-not error-message " hidden"))}
+             [:i.fa.fa-exclamation-circle]
+             error-message]
+            [:button.btn.btn-default.pull-right
+             {:disabled (if loading? "disabled")}
+             "Send Feedback"]
+            [:img {:class (str "pull-right loading" (when-not loading? " hidden"))
+                   :src "/img/loading.gif"}]]]))))
+
+#_(fn []
+    (om/set-state! owner
+      :text (when-not (empty? query)
+              (str
+                "Hey ClojureDocs, I searched for \""
+                query
+                "\", but couldn't find what I was looking for. Here's a description of what I would have liked to find:"))))
+
+(defn $search-feedback [{:keys [query clojure-level text
+                                loading? error-message] :as app} bus]
+  (let [!form (rea/atom {:text (when-not (empty? query)
+                                 (str
+                                   "Hey ClojureDocs, I searched for \""
+                                   query
+                                   "\", but couldn't find what I was looking for. Here's a description of what I would have liked to find:"))
+                         :clojure-level clojure-level
+                         :query query})]
+    (fn []
+      [:form {:on-submit (fn [e]
+                           (ops/send bus
+                             ::submit-feedback
+                             {:query query
+                              :clojure-level clojure-level
+                              :text text}))}
+       [:div.form-group
+        [:label.clojure-level
+         "Level of Clojuring"]
+        [:div.radio
+         [:label.radio
+          [:input {:type "radio"
+                   :name "clojure-level"
+                   :value "beginner"
+                   :on-click (fn [_]
+                               (swap! !form assoc :clojure-level "beginner"))
+                   :disabled (if loading? "disabled")}]
+          "I haven't written any Clojure"]
+         [:label.radio
+          [:input {:type "radio"
+                   :name "clojure-level"
+                   :value "intermediate"
+                   :on-click (fn [_]
+                               (swap! !form assoc :clojure-level "intermediate"))
+                   :disabled (if loading? "disabled")}]
+          "I've done a few things in Clojure"]
+         [:label.radio
+          [:input.radio
+           {:type "radio"
+            :name "clojure-level"
+            :value "advanced"
+            :on-click (fn [_]
+                        (swap! !form assoc :clojure-level "advanced"))
+            :disabled (if loading? "disabled")}]
+          "I'm comfortable contributing to Clojure projects"]]]
+       [:div.form-group
+        [:label {:for "feedback"} "Feedback"]
+        [:textarea {:class "form-control"
+                    :rows 10
+                    :name "feedback"
+                    :value text
+                    :on-input (fn [e]
+                                (swap! !form assoc :text (.. e -target -value)))
+                    :disabled (if loading? "disabled")}]]
+       [:div.form-group
+        [:span {:class (str "error-message" (when-not error-message " hidden"))}
+         [:i.fa.fa-exclamation-circle]
+         error-message]
+        [:button.btn.btn-default.pull-right
+         {:disabled (if loading? "disabled")}
+         "Send Feedback"]
+        [:img {:class (str "pull-right loading" (when-not loading? " hidden"))
+               :src "/img/loading.gif"}]]])))

 (defn ajax-chan [opts]
   (let [c (chan)]
@@ -313,7 +533,6 @@
       #js {}
       nil
       (.. js/window -location -pathname))))
-

 (defn wire-search [text-chan app-state]
   (let [throttled-text-chan (throttle text-chan 200)]
@@ -342,60 +561,100 @@

 (defn init [$root]
   (let [prev-query (util/location-hash)
-        !state (atom {:ac-text (when-not (re-find #"^example[_-]" prev-query)
-                                 prev-query)})
-        text-chan (chan)
-        action-ch (chan)]
+        !state (rea/atom {:ac-text (when-not (re-find #"^example[_-]" prev-query)
+                                     prev-query)})
+        bus (ops/kit
+              !state
+              {}
+              {::ac-text-changed (fn [state ac-text]
+                                   (assoc state :ac-text ac-text))
+
+               ::ac-text-throttled
+               (fn [state ac-text]
+                 (let [ch (chan)]
+                   (go
+                     (put! ch (merge state {:search-loading? true}))
+                     (if (empty? ac-text)
+                       (do
+                         (put! ch (merge state {:results-empty? false
+                                                :ac-results []
+                                                :search-loading? false}))
+                         (set-location-hash! ""))
+                       (do
+                         (put! ch (merge state {:search-loading? true}))
+                         (let [ac-response (<! (ajax-chan {:method :get
+                                                           :path (str "/ac-search?query=" (util/url-encode ac-text))
+                                                           :data-type :edn}))
+                               data (-> ac-response :res :body)]
+                           (when (:success ac-response)
+                             (metrics/track-search ac-text)
+                             (put! ch
+                               (fn [state]
+                                 (merge
+                                   state
+                                   {:highlighted-index 0
+                                    :results-empty? (and (empty? data) (not (empty? ac-text)))
+                                    :ac-results data
+                                    :search-loading? false})))))))
+                     (close! ch))
+                   ch))
+
+               ::move-highlight (fn [state dir]
+
+                                  (assoc state
+                                    :highlighted-index
+                                    (min
+                                      (dec (count (:ac-results state)))
+                                      (max 0 (+ (:highlighted-index state) dir)))))
+
+               ::cancel-search (fn [state]
+                                 (dissoc state :search-loading? :ac-results :ac-text :results-empty?))
+
+               ::ac-select (fn [state res]
+                             (util/navigate-to (util/var-path
+                                                 (:ns res)
+                                                 (:name res))))})]

     (when-not (empty? (sel :.search-widget))
       (swap! !state assoc :search-focused? true))

-    (go-loop []
-      (when-let [res (<! action-ch)]
-        (metrics/track-search-choose (:ac-text @!state) (:href res))
-        (set-location-hash! (:ac-text @!state))
-        (util/navigate-to (:href res))
-        (recur)))
-
-    (wire-search text-chan !state)
-
-    (dommy/listen! js/window :hashchange
-      (fn [_]
-        (let [loc-hash (util/location-hash)]
-          (when-not (re-find #"^example[_-]" loc-hash)
-            (swap! !state assoc :ac-text loc-hash)
-            (put! text-chan loc-hash)))))
-
-    (when (and (not (empty? prev-query))
-               (not (re-find #"^example[_-]" prev-query)))
-      (swap! !state assoc :search-focused? true)
-      (put! text-chan prev-query))
+    #_(go-loop []
+        (when-let [res (<! action-ch)]
+          (metrics/track-search-choose (:ac-text @!state) (:href res))
+          (set-location-hash! (:ac-text @!state))
+          (util/navigate-to (:href res))
+          (recur)))
+
+    #_(wire-search text-chan !state)
+
+    #_(dommy/listen! js/window :hashchange
+        (fn [_]
+          (let [loc-hash (util/location-hash)]
+            (when-not (re-find #"^example[_-]" loc-hash)
+              (swap! !state assoc :ac-text loc-hash)
+              (put! text-chan loc-hash)))))
+
+    #_(when (and (not (empty? prev-query))
+                 (not (re-find #"^example[_-]" prev-query)))
+        (swap! !state assoc :search-focused? true)
+        (put! text-chan prev-query))

     (doseq [$el (sel :.search-widget)]
-      (om/root
-        $quick-lookup-widget
-        !state
-        {:init-state {:text-chan text-chan
-                      :action-ch action-ch}
-         :target $el}))
+      (rea/render-component
+        [$quick-lookup-widget !state bus]
+        $el))

     (doseq [$el (sel :.quick-search-widget)]
-      (om/root
-        $quick-search-bar
-        !state
-        {:init-state {:text-chan text-chan
-                      :action-ch action-ch}
-         :target $el}))
+      (rea/render-component
+        [$quick-search-widget !state bus]
+        $el))

     (doseq [$el (sel :.ac-results-widget)]
-      (om/root
-        $ac-results
-        !state
-        {:target $el
-         :init-state {:action-ch action-ch}}))
+      (rea/render-component
+        [$ac-results-widget !state bus]
+        $el))

     (doseq [$el (sel :.search-feedback-widget)]
-      (om/root
-        $search-feedback
-        !state
-        {:target $el}))))
+      (rea/render-component
+        [$search-feedback @!state bus]
+        $el))))


fix broken links in tickets

fix broken links in tickets

--- src/cljs/salava/admin/ui/tickets.cljs
+++ src/cljs/salava/admin/ui/tickets.cljs
@@ -142,12 +142,18 @@
        [:h3 {:class "media-heading"}
         [:u (t (keyword (str "admin/" report_type)))]]
        [:h4 {:class "media-heading"}
-        (if (= "badges" item_type)
-          [:a {:href "#" :on-click #(do (.preventDefault %)
-                         (open-admintool-modal "badges" (badge-id item_url) state init-data))}
-           (str (t (keyword (str "admin/" item_type))) " - " item_name)]
-          [:a {:href item_url :target "_blank"}
-           (str (t (keyword (str "admin/" item_type))) " - " item_name)])]]
+        (cond
+          (= "badges" item_type)[:a {:href "#" :on-click #(do
+                                                            (.preventDefault %)
+                                                            (open-admintool-modal "badges" (badge-id item_url) nil nil))}
+                                 (str (t (keyword (str "admin/" item_type))) " - " item_name)]
+
+          (= "badge" item_type) [:a {:href "#" :on-click #(do
+                                                            (.preventDefault %)
+                                                            (open-admintool-modal item_id "badge"))}
+                                 (str (t (keyword (str "admin/" item_type))) " - " item_name)]
+          :else [:a {:href item_url :target "_blank"}
+                 (str (t (keyword (str "admin/" item_type))) " - " item_name)])]]
       [:div.media-descriprtion
        [:div {:class "col-xs-12"  :id (if open? "" "closed")}
         [:div [:label (str (t :admin/Description) ": ")] " " (if (< 130 (count description)) [text-shorter description 130]   description) ]


CMR-5275: Removed unnecessary config function.

--- src/cmr/opendap/components/config.clj
+++ src/cmr/opendap/components/config.clj
@@ -83,8 +83,6 @@
   (or (get-in (get-cfg system) [:cmr :opendap :relative :root :url])
       (httpd-config/http-base-url system)))

-(def base-url opendap-base-url)
-
 (defn vendor
   [system]
   (:vendor (get-cfg system)))


No need to generate class for schedule.clj

--- src/clj_mrazik/schedule.clj
+++ src/clj_mrazik/schedule.clj
@@ -10,8 +10,7 @@
 ;      Pavel Tisnovsky
 ;

-(ns clj-mrazik.schedule
-  (:gen-class))
+(ns clj-mrazik.schedule)

 (require '[clojure.pprint :as pprint])
 (require '[clj-calendar.calendar :as calendar])


Function for formatting schedule time

Function for formatting schedule time

--- src/clj_mrazik/schedule.clj
+++ src/clj_mrazik/schedule.clj
@@ -14,6 +14,29 @@
   (:gen-class))

 (require '[clojure.pprint :as pprint])
+(require '[clj-calendar.calendar :as calendar])
+
+(defn format-time
+    "Format given date using the following date/time format: 'HH:mm:ss'"
+    [cal]
+    (calendar/format-date-using-desired-format cal "HH:mm:ss"))
+
+(defn format-schedule-time
+    [time]
+    (format-time
+    (doto (calendar/get-calendar)
+          (.set java.util.Calendar/HOUR_OF_DAY 0)
+          (.set java.util.Calendar/SECOND 0)
+          (.set java.util.Calendar/MINUTE time))))
+
+(defn schedule-entry
+    [time duration]
+    (let [to (+ time duration)]
+        {:minutes {:from time
+                   :to   to}
+         :formatted {:from (format-schedule-time time)
+                     :to   (format-schedule-time to)}}
+    ))

 (defn compute-schedule
     [bot-configuration]


Keep player within canvas

Keep player within canvas

--- src/cljs/kindness/game.cljs
+++ src/cljs/kindness/game.cljs
@@ -401,13 +401,38 @@
               (remove (fn [e] (= (:id e) (:id entity)))
                       (find-entities-by-component :boundable))))

+(defn collides-with-others?
+  [entity]
+  (seq (collision-detect entity)))
+
+(defn outside-bounds?
+  [entity width height]
+  (let [[x y w h] (utils/position-and-bounds entity)]
+    (or (<= (+ x w) 0)
+        (>= y height)
+        (>= x width)
+        (<= (+ y h) 0))))
+
+(defn outside-canvas?
+  [entity]
+  (let [canvas (:canvas @game-state)
+        width (.-width canvas)
+        height (.-height canvas)
+        [x y w h] (utils/position-and-bounds entity)]
+    (or (<= x 0)
+        (>= (+ y h) height)
+        (>= (+ x w) width)
+        (<= y 0))))
+
 (defn move-entity!
   [name dx dy]
-  (let [entity (first (filter (fn [x] (= (:name x) name)) (:entities @game-state)))
+  (let [entity (first (filter (fn [x] (= (:name x) name))
+                              (:entities @game-state)))
         new-entity (update-in entity [:components :positionable :position]
-                               (fn [[x y]]
-                                 [(+ x dx) (+ y dy)]))]
-    (when-not (seq (collision-detect new-entity))
+                              (fn [[x y]]
+                                [(+ x dx) (+ y dy)]))]
+    (when (and (not (collides-with-others? new-entity))
+               (not (outside-canvas? new-entity)))
       (replace-entity new-entity))))

 (defn wrap-round
@@ -535,13 +560,7 @@
       (doseq [action actions]
         (action-dispatch gamepad-move-speed action)))))

-(defn outside-bounds?
-  [entity width height]
-  (let [[x y w h] (utils/position-and-bounds entity)]
-    (or (<= (+ x w) 0)
-        (>= y height)
-        (>= x width)
-        (<= (+ y h) 0))))
+

 (defn cleanup-entities
   []


Use first map in scenarios instead of hard-coding a map

--- src/cljs/zetawar/views.cljs
+++ src/cljs/zetawar/views.cljs
@@ -482,7 +482,7 @@

 ;; TODO: move default-scenario-id to data ns?
 (defn new-game-settings [{:as view-ctx :keys [conn dispatch translate]}]
-  (with-let [default-scenario-id :sterlings-aruba-multiplayer
+  (with-let [default-scenario-id (ffirst data/scenarios)
              selected-scenario-id (r/atom default-scenario-id)
              hide-settings (fn [ev]
                              (when ev (.preventDefault ev))


delete

delete

--- src/clojure_fabric/user.clj
+++ src/clojure_fabric/user.clj
@@ -1,43 +0,0 @@
-(ns clojure-fabric.user
-  (:import [org.hyperledger.fabric.sdk User]))
-
-
-(defn
- user-context-check
- [^org.hyperledger.fabric.sdk.User user0]
- (org.hyperledger.fabric.sdk.User/userContextCheck user0))
-
-
-(defn
- get-account
- [^org.hyperledger.fabric.sdk.User user]
- (. user getAccount))
-
-
-(defn
- get-msp-id
- [^org.hyperledger.fabric.sdk.User user]
- (. user getMspId))
-
-
-(defn
- get-enrollment
- [^org.hyperledger.fabric.sdk.User user]
- (. user getEnrollment))
-
-
-(defn
- get-affiliation
- [^org.hyperledger.fabric.sdk.User user]
- (. user getAffiliation))
-
-
-(defn
- get-roles
- [^org.hyperledger.fabric.sdk.User user]
- (. user getRoles))
-
-
-(defn get-name [^org.hyperledger.fabric.sdk.User user] (. user getName))
-
-


Fixed population size and ULTRA params.

Fixed population size and ULTRA params.

--- src/clojush/examples/wc.clj
+++ src/clojush/examples/wc.clj
@@ -347,13 +347,16 @@
    :max-points 250
    :max-points-in-initial-program 150
    :evalpush-limit 1000
-   :population-size 500
+   :population-size 1000
    :max-generations 300
    :reproduction-probability 0
    :mutation-probability 0
    :crossover-probability 0
    :report-simplifications 0
    :ultra-probability 1.0
+   :ultra-alternation-rate 0.01
+   :ultra-alignment-deviation 10
+   :ultra-mutation-rate 0.01
    :final-report-simplifications 1000
    :use-lexicase-selection true
    :use-ultra-no-paren-mutation true


Added not-lazy to code passed to interpreter, just to be safe.

--- src/clojush/interpreter.clj
+++ src/clojush/interpreter.clj
@@ -1,6 +1,5 @@
 (ns clojush.interpreter
-  (:use [clojush.pushstate]
-        [clojush.globals]
+  (:use [clojush pushstate globals util]
         [clojush.instructions.tag]
         [clojush.experimental.tagged-code-macros]))

@@ -112,7 +111,7 @@
     (run-push code state print-steps trace false))
   ([code state print-steps trace save-state-sequence]
     (let [s (if @global-top-level-push-code (push-item code :code state) state)]
-      (let [s (push-item code :exec s)]
+      (let [s (push-item (not-lazy code) :exec s)]
         (when print-steps
           (printf "\nState after 0 steps:\n")
           (state-pretty-print s))


Made output of conexp.contrib.todo/what-is-left? more readable

with the help of format-output, whose implementation is _very_ ugly...

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

--- src/conexp/contrib/todo.clj
+++ src/conexp/contrib/todo.clj
@@ -31,7 +31,7 @@
 			 { "util"     [ "Add more tests." ],
 			   "base"     [ "Check whether everything has been tested." ],
 			   "fca"      { "contexts" [ "Finish tests." ],
-					"implications " [ "Finish tests." ] }, } ] },
+					"implications" [ "Finish tests." ] }, } ] },
     "doc"    [ "Add docstrings for namespaces.",
 	       "Add docstrings for all functions.",
 	       "Extend LaTeX-Documentation." ] })
@@ -52,14 +52,38 @@
 			    (rest keys))))]
       (runner *conexp-todo-list* ns-as-seq))))

+(defn- format-output
+  "Formats structure given as human-readable output.
+
+  This implementation is ugly."
+  ([object]
+     (format-output object 0))
+  ([object indent]
+     (cond
+       (string? object)
+       (str (apply str (repeat indent \space)) object "\n"),
+       (vector? object)
+       (apply str
+	      (map #(format-output % indent) object)),
+       (map? object)
+       (apply str
+	      (for [key (keys object)]
+		(apply str
+		       (apply str (repeat indent \space))
+		       key
+		       ":\n"
+		       (format-output (object key) (+ indent 2))))),
+       :else
+       nil)))
+
 (defn what-is-left?
   "Returns, given a namespace (as Symbol, String or Namespace), the
   task to be done there."
   ([]
-     (what-is-left? "conexp"))
+     (print (format-output *conexp-todo-list*)))
   ([ns]
      (let [ns-as-seq (re-split #"\." (str ns))
 	   tasks (access-todo-list ns-as-seq)]
-       (pprint tasks))))
+       (print (format-output tasks)))))

 nil


CMR-1383 Removes unused variable binding.

--- metadata-db-app/int_test/cmr/metadata_db/int_test/utility.clj
+++ metadata-db-app/int_test/cmr/metadata_db/int_test/utility.clj
@@ -358,7 +358,7 @@
                               :connection-manager (conn-mgr)
                               :headers {transmit-config/token-header (transmit-config/echo-system-token)}})
         status (:status response)
-        {:keys [errors provider-id]} (:body response)]
+        {:keys [errors]} (:body response)]
     {:status status :errors errors}))

 (defn delete-provider


always calculate intensity range from pixels directly

git-svn-id: 03a8048b5ee8463be5048a3801110fb50f378627@9820 d0ab736e-dc22-4aeb-8dc9-08def0aa14fd

--- plugins/SlideExplorer2/src/slide_explorer/image.clj
+++ plugins/SlideExplorer2/src/slide_explorer/image.clj
@@ -129,15 +129,10 @@
 (defn intensity-range
   "Get the intensity range for one or more processors."
   ([processor]
-    (condp instance? processor
-      ByteProcessor
       (let [stat (ImageStatistics/getStatistics
                    processor ImageStatistics/MIN_MAX nil)]
         {:min (.min stat)
-         :max (.max stat)})
-      ShortProcessor
-      {:min (.getMin processor)
-       :max (.getMax processor)}))
+         :max (.max stat)}))
   ([processor & processors]
     (let [min-maxes (map intensity-range (cons processor processors))]
       {:min (apply min (map :min min-maxes))


Create right-box

Create right-box

--- src/airhead_frontend/components.cljs
+++ src/airhead_frontend/components.cljs
@@ -43,13 +43,15 @@
   [:a.pure-button.pure-u-1-4 {:title "Open stream" :href url :target "_blank"}
    [:i.fa.fa-external-link]])

+(defn right-box [head body]
+  [:div.right-box head [:span body]])
+
 (defn now-playing []
   (let [track (@app-state :now-playing)]
-    [:div
-     [:i.fa.fa-music]
-     [:span (if track
-              (str (:artist track) " - " (:title track))
-              [:em "Nothing is playing."])]]))
+    [right-box [:i.fa.fa-music]
+     (if track
+       (str (:artist track) " - " (:title track))
+       [:em "Nothing is playing."])]))

 (defn player-section []
   (let [audio-ref (r/atom nil)]
@@ -121,14 +123,14 @@
 (defn info-done [track]
   [:div.upload-info
    [:div "Done!"]
-   [:div
+   [right-box
     [playlist-add-button track]
-    [:span (str (:artist track) " - " (:title track))]]])
+    (str (:artist track) " - " (:title track))]])

 (defn info-error [status error-msg]
   [:div.upload-info
    [:div (str "Error " status)]
-   [:div (str error-msg)]])
+   [right-box [:div (str error-msg)]]])

 (defn upload-info [{loaded :loaded
                     total  :total
@@ -201,11 +203,10 @@
          [file-select-button file-input-ref]
          [upload-button form-ref file-input-ref]]

-        [:div
-         [:i.fa.fa-file-o]
-         [:span (when @file-input-ref
-                  (or (get-file-name file-input-ref)
-                      "No file selected."))]]]
+        [right-box [:i.fa.fa-file-o]
+         (when @file-input-ref
+           (or (get-file-name file-input-ref)
+               "No file selected."))]]

        (for [[k upload] (@app-state :uploads)]
         ^{:key k} [upload-info upload])])))


finished-fn for migrations

finished-fn for migrations

--- src/er_cassandra/drift/migrations.clj
+++ src/er_cassandra/drift/migrations.clj
@@ -144,6 +144,8 @@
   "kill the VM when finished"
   []
   (let [config drift.config/*config-map*]
+    (when-let [f (:finished-fn config)]
+      (f))
     (when-not (:remain-when-finished config)
       (System/exit 0))))


ns typos

ns typos

--- src/atom_finder/util/10_clj_util.clj
+++ src/atom_finder/util/10_clj_util.clj
@@ -180,12 +180,12 @@
   (* 1000 1000000.0))

 (def ns-per-min
-  (* 60 ns-in-sec))
+  (* 60 ns-per-sec))

 (defmacro time-secs-data
   "Return time spent in nanoseconds"
   [expr]
-  `(/ (time-ns-data ~expr) ns-per-min))
+  `(/ (time-ns-data ~expr) ns-per-sec))

 ; https://github.com/clojure/clojure/blob/clojure-1.9.0-alpha14/src/clj/clojure/core.clj#L3836
 (defmacro time-mins


oops, update fn

oops, update fn

--- src/chat/server/extensions/asana.clj
+++ src/chat/server/extensions/asana.clj
@@ -133,7 +133,7 @@
   [extension-id resource-id]
   (fetch-asana-info extension-id :post "/webhooks"
                     {:form-params {"resource" resource-id
-                                   "target" (str webhook-uri "/" (:id ext))}}))
+                                   "target" (str webhook-uri "/" extension-id)}}))

 (defn unregister-webhook
   [extension-id webhook-id]


Supply version to getShardSet.

Supply version to getShardSet.

--- src/clj/elephantdb/common/domain.clj
+++ src/clj/elephantdb/common/domain.clj
@@ -306,8 +306,9 @@
 (defn key->shard
   "Accepts a local store and a key (any object will do); returns the
   approprate shard number for the given key."
-  [{:keys [local-store]} key]
-  (let [^ShardSet shard-set (.getShardSet local-store)]
+  [{:keys [local-store] :as domain} key]
+  (let [version (current-version domain)
+        ^ShardSet shard-set (.getShardSet local-store version)]
     (.shardIndex shard-set key)))

 (defn retrieve-shard


fix registry token obtaining

fix registry token obtaining

--- src/clj/swarmpit/registry/client.clj
+++ src/clj/swarmpit/registry/client.clj
@@ -44,9 +44,10 @@
         www-auth-params (dissoc www-auth-header :realm)
         query-params (merge {"client_id" "swarmpit"} (stringify-keys www-auth-params))
         options (assoc-in options [:query-params] query-params)
-        token (execute {:method  :GET
-                        :url     www-auth-url
-                        :options options})]
+        token (-> (execute {:method  :GET
+                            :url     www-auth-url
+                            :options options})
+                  :body)]
     (-> options
         (assoc-in [:headers "Authorization"] (token/bearer (:token token))))))

@@ -76,7 +77,7 @@
   [registry]
   (-> (execute-with-fallback
         {:method  :GET
-         :url     (build-url registry "/_catalog")
+         :url     (build-url registry "/")
          :options {:headers (basic-auth registry)}})
       :body))


Add integration test for ces with component state changes

--- src/cljs/chocolatier/engine/ces.cljs
+++ src/cljs/chocolatier/engine/ces.cljs
@@ -18,15 +18,13 @@
 ;; creates a new copy on every change to state in the game loop due to
 ;; structural sharing

-(def SCENES {})
-(def STATE {})

-(defn add-scene
+(defn mk-scene
   "Add or update existing scene in the scenes hashmap"
   [scenes-hm uid fns]
   (assoc scenes-hm uid fns))

-(println "test add-scene" (add-scene SCENES :yo [identity]))
+(println "test add-scene" (mk-scene {} :yo [identity]))

 (defn iter-fns
   "Pass an initial value through a collection of functions with the
@@ -55,7 +53,7 @@
     (apply merge-with deep-merge vals)
     (last vals)))

-(println "test deep-merge" (deep-merge {:a 1} {:b {:c 2}}))
+(println "test deep-merge" (deep-merge {:a {:b 1}} {:a {:d 2}}))

 (defn entities-with-component
   "Takes a hashmap and returns all keys whose values contain component-id"
@@ -63,27 +61,8 @@
   (map first
        (filter #(boolean (some #{component-id} (second %))) entities)))

-(println "test entities-with-component" (entities-with-component {:a [:b]} :b))
-
-(defn mk-system-fn
-  "Returns a function representing a system.
-
-   Has two arrities:
-   - [f] function f is called with state and wrapped to merge the return
-     value of the function with state
-   - [component-id f] function f is called with state and a collection of
-     entity ids that match the given component id. Results are merged with
-     state"
-  ([f]
-   (fn [state]
-     (deep-merge state (f state (:entities state)))))
-  ([f component-id]
-   (fn [state]
-     (let [entities (entities-with-component component-id (:entities state))]
-       (deep-merge state (f state entities))))))
-
-(println "test mk-system-fn"
-         ((mk-system-fn (fn [s ents] s) :b) {:entities {:a [:b]}}) )
+(println "test entities-with-component"
+         (entities-with-component {:a [:b] :b [:b]} :b))

 (defn mk-entity
   "Adds entity with uid that has component-ids into state"
@@ -93,9 +72,14 @@
 (println "test mk-entity"
          (mk-entity {} :player1 [:a :b]))

+(defn get-component-fns
+  [state component-id]
+  (get-in state [:components component-id :fns]))
+
 (defn get-component-state
   [state component-id entity-id]
-  (get-in state [:components component-id :state entity-id]))
+  (or (get-in state [:components component-id :state entity-id])
+      {}))

 (defn mk-component-state
   "Returns a hashmap that can be merged into the state hashmap
@@ -112,11 +96,13 @@
    merged into the game state."
   [component-id f]
   (fn [state entity-id]
-    (mk-component-state
-     component-id
-     entity-id
-     (f entity-id
-        (get-component-state state component-id entity-id)))))
+    (let [r (mk-component-state
+             component-id
+             entity-id
+             (f (get-component-state state component-id entity-id)
+                entity-id))]
+      (println "component-fn result" r)
+      r)))

 (println "test mk-component-fn"
          ((mk-component-fn :test (fn [& args] (identity {:foo "bar"})))
@@ -130,7 +116,50 @@
    component state which will be merged into the overall state"
   [state uid fns]
   (let [wrapped-fns (for [f fns] (mk-component-fn uid f))]
-    (assoc state :components {uid {:fns fns :state {}}})))
+    (assoc state :components {uid {:fns wrapped-fns :state {}}})))

 (println "test mk-component"
          (mk-component {} :my-component [identity]))
+
+(defn mk-system-fn
+  "Returns a function representing a system.
+
+   Has two arrities:
+   - [f] function f is called with state and wrapped to merge the return
+     value of the function with state
+   - [f component-id] function f is called with state, a collection of
+     component functions, and a collection of entity ids that match the
+     given component id. Results are merged with game state."
+  ([f]
+   (fn [state]
+     (deep-merge state (f state (:entities state)))))
+  ([f component-id]
+   (fn [state]
+     (let [entities (entities-with-component (:entities state) component-id)
+           component-fns (get-component-fns state component-id)]
+       (deep-merge state (f state component-fns entities))))))
+
+(println "test mk-system-fn"
+         ((mk-system-fn (fn [s fns ents] s) :b) {:entities {:a [:b]}}))
+
+(defn integration-test
+  "Test the entire CES implementation with a system that changes component state"
+  []
+  (let [sys-fn (fn [state fns entity-ids]
+                 (apply deep-merge (for [f fns, e entity-ids] (f state e))))
+        test-system (mk-system-fn sys-fn :testable)
+        scenes (-> {}
+                   (mk-scene :test-scene [test-system]))
+        test-fn (fn [component-state entity-id]
+                  (println "testing" entity-id
+                           component-state "->"
+                           (assoc component-state :x
+                                  (inc (or (:x component-state) 0))))
+                  (assoc component-state :x (inc (or (:x component-state) 0))))
+        state (-> {}
+                  (mk-entity :player1 [:testable])
+                  (mk-entity :player2 [:testable])
+                  (mk-component :testable [test-fn]))]
+    (game-loop scenes :test-scene state 0)))
+
+(println "Running integration-test" (integration-test))


lesson <div> - separate lesson type and lesson group

For instance, a lesson type "Lecture" of group "V2" will be split into
the lesson type text "Lecture", followed by a span of class
`lesson-group` with text "V2". This is to enable the toggling of
visibility of the lesson group in an upcoming patch.

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

--- src/cljs/cljs_nusmods/timetable.cljs
+++ src/cljs/cljs_nusmods/timetable.cljs
@@ -956,7 +956,8 @@
   "Creates a <div> element for a new lesson using jQuery"
   [& {:keys [day moduleCode moduleName lessonType lessonGroup startTime endTime
              venue weekTextIdx slotsOcc bgColorCssClass isActuallySelected?]}]
-  (let [$divElem  ($ "<div />" (js-obj "class" "lesson"))]
+  (let [$divElem        ($ "<div />" (js-obj "class" "lesson"))
+        $lessonTypePara (text ($ "<p />") lessonType)]
     (.addClass $divElem bgColorCssClass)
     ; add background color css class
     (.append $divElem
@@ -965,7 +966,10 @@
                             (str moduleCode " "))
                       (text ($ "<span />" (js-obj "class" "module-name"))
                             moduleName)))
-    (.append $divElem (text ($ "<p />") (str lessonType " [" lessonGroup "]")))
+    (.append $lessonTypePara
+             (text ($ "<span />" (js-obj "class" "lesson-group"))
+                   (str " [" lessonGroup "]")))
+    (.append $divElem $lessonTypePara)
     (.append $divElem (text ($ "<p />") venue))
     ; make the <div> less opaque for a lesson added by jQuery UI draggable
     (if (not isActuallySelected?)


Refactor - merge update of `ModulesSelected` due to module removal in new fn

The new function is named `remove-module-from-ModulesSelected`.

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

--- src/cljs/cljs_nusmods/timetable.cljs
+++ src/cljs/cljs_nusmods/timetable.cljs
@@ -212,6 +212,41 @@
   (set! ModulesSelected
         (assoc-in ModulesSelected [moduleCode lessonType]
                   {:label lessonGroup, :info lessonInfoSeq})))
+
+(declare timetable-enumerate-rows-in-day)
+
+(defn- update-ModulesSelected-for-affected-days!
+  "Given a set of days that may possibly be affected by removal and shifting of
+   lessons, update the individual entries in the `ModulesSelected` global."
+  [affectedDaysSet]
+  (doseq [day affectedDaysSet]
+    (doseq [[rowIdx ttRow] (timetable-enumerate-rows-in-day day)]
+      (doseq [[{:keys [moduleCode lessonType lessonGroup
+                       startTime endTime]} _] ttRow]
+        (set! ModulesSelected
+              (update-in
+                ModulesSelected
+                [moduleCode lessonType :info]
+                (fn [modSelLessonInfoSeq]
+                  (conj (filter (fn [modSelLessonInfo]
+                                  (or (not= (:day modSelLessonInfo) day)
+                                      (not= (:startTime modSelLessonInfo)
+                                            startTime)
+                                      (not= (:endTime modSelLessonInfo)
+                                            endTime)))
+                                modSelLessonInfoSeq)
+                        {:day day,
+                         :rowNum rowIdx,
+                         :startTime startTime,
+                         :endTime endTime}))))))))
+
+(defn- remove-module-from-ModulesSelected!
+  "Removes a module from `ModulesSelected`, and updates all lessons with new
+   row indices for days where lesson removal has occurred and row shifting /
+   removal has occurred."
+  [moduleCode affectedDaysSet]
+  (set! ModulesSelected (dissoc ModulesSelected moduleCode))
+  (update-ModulesSelected-for-affected-days! affectedDaysSet))

 (def ^{:doc     "Vector containing module code strings in the order the modules
                  were added."
@@ -744,31 +779,6 @@
     ; adjust rowspan of
     (attr $thElem "rowspan" (max nrNonEmptyRows 2))))

-(defn- update-ModulesSelected-for-affected-days!
-  "Given a set of days that may possibly be affected by removal and shifting of
-   lessons, update the individual entries in the `ModulesSelected` global."
-  [affectedDaysSet]
-  (doseq [day affectedDaysSet]
-    (doseq [[rowIdx ttRow] (timetable-enumerate-rows-in-day day)]
-      (doseq [[{:keys [moduleCode lessonType lessonGroup
-                       startTime endTime]} _] ttRow]
-        (set! ModulesSelected
-              (update-in
-                ModulesSelected
-                [moduleCode lessonType :info]
-                (fn [modSelLessonInfoSeq]
-                  (conj (filter (fn [modSelLessonInfo]
-                                  (or (not= (:day modSelLessonInfo) day)
-                                      (not= (:startTime modSelLessonInfo)
-                                            startTime)
-                                      (not= (:endTime modSelLessonInfo)
-                                            endTime)))
-                                modSelLessonInfoSeq)
-                        {:day day,
-                         :rowNum rowIdx,
-                         :startTime startTime,
-                         :endTime endTime}))))))))
-
 (defn- create-lesson-div
   "Creates a
 element for a new lesson using jQuery"
   [& {:keys [moduleCode moduleName lessonType lessonGroup venue slotsOcc
@@ -1487,9 +1497,6 @@
         ; remove the lesson
s
         (remove-lesson-group-html augTTLessonInfoSeq)

-        ; Remove module from `ModulesSelected`
-        (set! ModulesSelected (dissoc ModulesSelected moduleCode))
-
         (.log js/console "Reached here man")

         ; Perform shifting due to removal of lesson
s
@@ -1498,8 +1505,7 @@
         (overall-timetable-prune-empty-rows affectedDaysSet)
         (.log js/console "Whats up")

-        ; Update `ModulesSelected`
-        (update-ModulesSelected-for-affected-days! affectedDaysSet)
+        (remove-module-from-ModulesSelected! moduleCode affectedDaysSet)
         (.log js/console "Boo ya!")
         (.log js/console (str "ModulesSelected:" (.stringify js/JSON (clj->js ModulesSelected))))


Add some functionality for removing a module

This is still a Work In Progress. Essentially, this patch introduces
functionality to remove a module partially.

What's done
- Removing the <div> element for lessons, and filling in the <td>
  elements that were taken out when adding lessons
- Update the `Timetable` global variable to mark slots formerly
  occupied by the removed lessons as free
- Remove the module from `ModulesSelected` and `ModulesSelectedOrder`
  globals
- Update the Exhibit3 box with the list of remaining modules

What's going to happen in upcoming patches
- Shift lessons upwards in timetable to occupy vacant timeslots caused
  by removing lessons
- Remove any unnecessary, empty rows caused by the removal and shifting

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

--- src/cljs/cljs_nusmods/timetable.cljs
+++ src/cljs/cljs_nusmods/timetable.cljs
@@ -1,6 +1,7 @@
 (ns ^{:doc "Code for Timetable Builder page"}
   cljs-nusmods.timetable
-  (:use [jayq.core :only [$ attr children hide is prevent show text width]])
+  (:use [jayq.core :only [$ attr children hide insert-after is parent prevent
+                          remove-attr show text width]])
   (:require [clojure.set]
             [clojure.string]
             [cljs-nusmods.select2 :as select2]
@@ -274,6 +275,31 @@
                                       (range startTime endTime))
             }))))

+(defn- timetable-mark-lesson-slots-free
+  "Marks the timeslots for a lesson as free. The `lessonInfo` parameter must be
+   a map with the following keys:
+
+     :day       -> 0-indexed day
+     :row       -> 0-indexed row in the day
+     :startTime -> 0-indexed start time of the lesson
+     :endTime   -> 0-indexed end time of the lesson"
+  [lessonInfo]
+  (let [day         (:day lessonInfo)
+        row         (:rowNum lessonInfo)
+        startTime   (:startTime lessonInfo)
+        endTime     (:endTime lessonInfo)
+        ttRow       (get-in Timetable [day row])
+        occupiedVec (reduce (fn [occupiedVec timeIdx]
+                              (assoc occupiedVec timeIdx nil))
+                            (:occupied ttRow)
+                            (range startTime endTime))]
+    (set! Timetable
+          (update-in
+            Timetable [day row]
+            (fn [ttRow]
+              {:nrLessonGroups (dec (:nrLessonGroups ttRow))
+               :occupied       occupiedVec})))))
+
 (defn- find-free-row-for-lesson
   "Returns the 0-indexed row which can accomodate the given lesson (timeslots
    for the lesson are not occupied). If no existing row can accomodate the
@@ -581,15 +607,84 @@
     ; Update url hash
     (set-document-location-hash-from-module-info-seq moduleInfoFinal)))

+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; Functions for Removing Modules
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defn- add-missing-td-elements-replacing-lesson
+  "Adds <td> elements that were removed by the `add-module-lesson` function
+   to make way for the lesson."
+  [$parentTd lessonInfo]
+  (let [startTime (:startTime lessonInfo)
+        endTime   (:endTime lessonInfo)]
+    (loop [$currentTd $parentTd
+           timeIdx    (inc startTime)]
+      (if (>= timeIdx endTime)
+          nil
+          (let [[hourClass minuteClass]
+                (get-css-hour-minute-classes-for-time timeIdx)
+
+                $newTdElem
+                ($ "<td />" (js-obj "class" (str hourClass " " minuteClass)))]
+            ; Insert after new <td> after the current <td>
+            (insert-after $newTdElem $currentTd)
+            ; Then use the new <td> as the current <td> in the next iteration
+            (recur $newTdElem (inc timeIdx)))))))
+
+(defn- remove-lesson-group-html
+  "Removes a lesson group for a module from the HTML timetable.
+   This does NOT remove any empty rows / perform module shifting.
+
+   Returns an array of the map with the following keys:
+
+     :day       -> 0-indexed day where the lesson was stored
+     :rowNum    -> 0-indexed row to the day in `Timetable` where the lesson
+                   was stored
+     :startTime -> 0-indexed start time of the lesson
+     :endTime   -> 0-indexed end time of the lesson"
+  [moduleCode lessonType]
+  (let [lessonGroupDetails (get-in ModulesSelected [moduleCode lessonType])
+        lessonLabel        (:label lessonGroupDetails)
+        lessonInfoSeq      (:info lessonGroupDetails)]
+    (map (fn [lessonInfo]
+           (let [$lessonDiv (:divElem lessonInfo)
+                 $parentTd  (parent $lessonDiv)]
+             ; Remove the `colspan` attribute of the parent <td> so it has
+             ; colspan=1
+             (remove-attr $parentTd "colspan")
+             ; Remove the HTML div elem
+             (.remove $lessonDiv)
+             ; Add the missing <td> elements
+             (add-missing-td-elements-replacing-lesson $parentTd lessonInfo)
+             ; Remove the same lessonInfo without :divElem key
+             (dissoc lessonInfo :divElem)))
+         lessonInfoSeq)))
+
 (defn remove-module
   "Removes a module from the timetable.

    This deletes every lesson of the module from the timetable."
   [moduleCode]
   (if (contains? ModulesSelected moduleCode)
-    ;!!!
-    nil
-  ))
+      (let [lessonTypes
+            (keys (get ModulesSelected moduleCode))
+
+            seqOfRemovedLessons
+            (flatten (map (fn [lessonType]
+                            (remove-lesson-group-html moduleCode lessonType))
+                          lessonTypes))]
+        (doseq [lessonInfo seqOfRemovedLessons]
+          (timetable-mark-lesson-slots-free lessonInfo))
+        ; Remove from `ModulesSelected`
+        (set! ModulesSelected (dissoc ModulesSelected moduleCode))
+        ; Remove from `ModulesSelectedOrder`
+        (set! ModulesSelectedOrder (remove #{moduleCode} ModulesSelectedOrder))
+        ; Update Exhibit3 box
+        (select2/select2-box-set-val select2/$Select2-Box
+                                     (get-selected-module-codes-as-js-array)))))

 (defn remove-all-modules
   "Removes all modules from the timetable"


circle radius, position based on window size

--- src/cljs/passa_paraula/ui/views.cljs
+++ src/cljs/passa_paraula/ui/views.cljs
@@ -1,19 +1,30 @@
 (ns passa-paraula.ui.views
   (:require [passa-paraula.game :as game]))

-(def center-x 500)
-(def center-y 500)
-(def radius 400)
-(def circle-radius "100px")
+
+(.log js/console  (.-innerWidth js/window))
+
+
+#_(def center-x 500)
+#_(def center-y 500)
+
+(def center-x (/ (.-innerWidth js/window) 2))
+(def center-y (/ (.-innerHeight js/window) 2))
+
+(def radius (/ (.-innerWidth js/window) 4.5))
+(def circle-radius (/ (.-innerWidth js/window) 20))

 (def status-colors {:ok "green"
                     :failed "red"
                     :pass "orange"
                     :init "blue"})

+(def circle-line-height (str circle-radius "px"))
+

 (def letter-color "black")
 (def letter-width "1")
+
 (def highlight-letter-color "orange")
 (def highlight-letter-width "5")

@@ -46,9 +57,9 @@
                              :width circle-radius
                              :height circle-radius
                              :border-radius "50%"
-                             :font-size "50px"
+                             :font-size (/ circle-radius 2)
                              :color "#fff"
-                             :line-height "100px"
+                             :line-height circle-line-height
                              :text-align "center"
                              :background (get-letter-color pos)}}
                letter])


Moved the testing code to the dev profile

--- src/leiningen/new/reagent/project.clj
+++ src/leiningen/new/reagent/project.clj
@@ -33,18 +33,7 @@
                                         :output-dir    "resources/public/js/out"
                                         :externs       ["react/externs/react.js"]
                                         :optimizations :none
-                                        :pretty-print  true}}
-                       {{#test-hook?}}
-                       :test {:source-paths ["src/cljs" {{{cljx-cljsbuild-spath}}} "test/cljs"]
-                              :compiler {:output-to "target/test.js"
-                                         :optimizations :whitespace
-                                         :pretty-print true
-                                         :preamble ["react/react.js"]}}{{/test-hook?}}}{{#test-hook?}}
-              :test-commands {"unit" ["phantomjs" :runner
-                                      "test/vendor/es5-shim.js"
-                                      "test/vendor/es5-sham.js"
-                                      "test/vendor/console-polyfill.js"
-                                      "target/test.js"]}{{/test-hook?}}}
+                                        :pretty-print  true}}}}

   :profiles {:dev {:repl-options {:init-ns {{project-ns}}.handler
                                   :nrepl-middleware [cemerick.piggieback/wrap-cljs-repl{{{nrepl-middleware}}}]}
@@ -77,7 +66,19 @@
                                     :rules :cljs}]}
                    {{/cljx-build?}}
                    :cljsbuild {:builds {:app {:source-paths ["env/dev/cljs"]
-                                              :compiler {:source-map true}}}}}
+                                              :compiler {:source-map true}}
+                                        {{#test-hook?}}
+                                        :test {:source-paths ["src/cljs" {{{cljx-cljsbuild-spath}}} "test/cljs"]
+                                               :compiler {:output-to "target/test.js"
+                                                          :optimizations :whitespace
+                                                          :pretty-print true
+                                                          :preamble ["react/react.js"]}}{{/test-hook?}}}
+                               {{#test-hook?}}
+                               :test-commands {"unit" ["phantomjs" :runner
+                                                       "test/vendor/es5-shim.js"
+                                                       "test/vendor/es5-sham.js"
+                                                       "test/vendor/console-polyfill.js"
+                                                       "target/test.js"]}{{/test-hook?}}}}

              :uberjar {:hooks [{{cljx-uberjar-hook}}leiningen.cljsbuild minify-assets.plugin/hooks]
                        :env {:production true}


update plugin tests to handle multiple builds

--- plugin/test/leiningen/figwheel_test.clj
+++ plugin/test/leiningen/figwheel_test.clj
@@ -20,8 +20,9 @@
               :http-server-root "public"
               :resource-paths [(str root "/marty")
                                (str root "/joe")]}]
-    (is (fig/output-dir-in-resources-root? (assoc opts :output-dir "marty/public/hi")))
-    (is (not (fig/output-dir-in-resources-root? (assoc opts :output-dir "marty/something/hi"))))))
+    (is (fig/output-dir-in-resources-root? {:output-dir "marty/public/hi"} opts))
+    (is (not (fig/output-dir-in-resources-root? {:output-dir "marty/something/hi"}
+                                                opts)))))

 (deftest map-to-vec-builds-test
   (is (= [1 2 3 4]
@@ -33,22 +34,29 @@

 (deftest narrow-to-one-build*-test
   (is (= [{:id "there"}]
-         (fig/narrow-to-one-build* {:hello {} :there {}} "there")))
+         (fig/narrow-builds* {:hello {} :there {}} ["there"])))
+
+  (is (= [{:id "there"}]
+         (fig/narrow-builds* [{:id :hello} {:id :there}] ["there"])))
+
+  (is (= (set [{:id "there"} {:id "hello"}])
+         (set (fig/narrow-builds* {:hello {} :there {}} ["there" "hello"]))))
   (is (= [{:id "hello"}]
-         (fig/narrow-to-one-build* {:hello {} :there {}} "hello")))
+         (fig/narrow-builds* {:hello {} :there {}} ["hello"])))
   (is (= [{:id "hello" :compiler {:optimizations :none}}]
-         (fig/narrow-to-one-build* [{:id "hello"
-                                     :compiler { :optimizations :none } }
-                                    {:id "there"
-                                     :compiler { :optimizations :none }}]
-                              nil)))
-  (is (= [ nil ]
-         (fig/narrow-to-one-build* [{:id "hello"} {:id "there"}] nil)))
-  (is (= [ nil ]
-         (fig/narrow-to-one-build* [{:id "hello"} {:id "there"}] "bad-id"))))
+         (fig/narrow-builds* [{:id "hello"
+                               :compiler { :optimizations :none } }
+                              {:id "there"
+                               :compiler { :optimizations :none }}]
+                             nil)))
+  (is (= []
+         (fig/narrow-builds* [{:id "hello"} {:id "there"}] nil)))
+  (is (= []
+         (fig/narrow-builds* [{:id "hello"} {:id "there"}] ["bad-id"]))))

 (deftest narrow-to-one-build-test
   (is (= { :cljsbuild { :builds [{:id "hello"}]} }
-         (fig/narrow-to-one-build { :cljsbuild { :builds {:hello {} :there {}}} }
-                              "hello"))))
+         (fig/narrow-builds { :cljsbuild { :builds {:hello {} :there {}}} }
+                            ["hello"]))))

+(run-tests)


Fix debug logging

Fix debug logging

--- src/cyanite_remover/metric_store.clj
+++ src/cyanite_remover/metric_store.clj
@@ -98,7 +98,7 @@
                   (string-or-empty rollup "rollup: ")
                   (string-or-empty period ", period: ")
                   (string-or-empty path ", path: ")
-                  (string-or-empty times ", time: "))))
+                  (string-or-empty (vec times) ", time: "))))

 (defn- get-delete-channel
   "Get delete channel."
@@ -164,18 +164,18 @@
                 prepared (:prepared statement)
                 cql (:cql statement)
                 query (alia/bind prepared values)]
-            (log/debug "Fetching metrics: "
-                       "rollup: " rollup ", "
-                       "period: " period ", "
-                       "path: " path
-                       (string-or-empty from ", from: ")
-                       (string-or-empty to ", to: "))
+            (log/debug (str "Fetching metrics: "
+                            "rollup: " rollup ", "
+                            "period: " period ", "
+                            "path: " path
+                            (string-or-empty from ", from: ")
+                            (string-or-empty to ", to: ")))
             (alia/execute session query))
           (catch Exception e
             (log-error e rollup period path stats-errors)
             :mstore-error)))
       (delete [this tenant rollup period path]
-        (log-deletion tenant rollup period path)
+        (log-deletion rollup period path)
         (swap! stats-processed inc)
         (let [values (build-values tenant rollup period path)]
           (swap! batch
@@ -183,7 +183,7 @@
                     (conj % values)
                     (do (async/>!! channel {:values (conj % values)}) [])))))
       (delete-times [this tenant rollup period path times]
-        (log-deletion tenant rollup period path times)
+        (log-deletion rollup period path times)
         (swap! stats-processed inc)
         (let [series (map #(build-values tenant rollup period path %) times)
               batches (partition-all batch-size series)]


Simplify messaging client.

Simplify messaging client.

--- src/demo/remote_messaging_client.clj
+++ src/demo/remote_messaging_client.clj
@@ -5,18 +5,14 @@

 (defn -main
   "Connects to a 'remote' HornetQ running on localhost:5445 and delivers
-  the message to the given destination. The destination name must be
-  prefixed with the type (either 'queue' or 'topic') and a colon. The
-  rest of the arguments are considered the message. Example:
+  the message to the given destination. The first argument is the queue
+  name, the rest of the arguments are considered the message. Example:

-    lein msg-client queue:foo hi there friends"
-  [dest-type:name & message]
+    lein msg-client foo hi there friends"
+  [queue-name & message]
   (with-open [connection (msg/connection :host "localhost" :port 5445)]
-    (let [[dest-type dest-name] (str/split dest-type:name #":")
-          dest-fn (if (= dest-type "queue")
-                         msg/queue msg/topic)
-          destination (dest-fn dest-name :connection connection)
+    (let [queue (msg/queue queue-name :connection connection)
           message (str/join " " message)]
-      (println (format "Sending '%s' to %s %s"
-                 message dest-type dest-name))
-      (msg/publish destination message))))
+      (println (format "Sending '%s' to queue %s"
+                 message queue-name))
+      (msg/publish queue message))))


Don't adjust the reference z position if we are using continuous focus.

git-svn-id: 03a8048b5ee8463be5048a3801110fb50f378627@7473 d0ab736e-dc22-4aeb-8dc9-08def0aa14fd

--- acqEngine/src/org/micromanager/acq_engine.clj
+++ acqEngine/src/org/micromanager/acq_engine.clj
@@ -221,8 +221,10 @@
     (await-resume)
     (let [now (clock-ms)
           wake-time (if (> now (+ target-time 10)) now target-time)]
-      (state-assoc! :last-wake-time wake-time
-                    :reference-z-position (get-z-stage-position (core getFocusDevice))))))
+      (state-assoc! :last-wake-time wake-time)
+      (when-not (core isContinuousFocusEnabled)
+        (state-assoc! :reference-z-position
+                      (get-z-stage-position (core getFocusDevice)))))))

 ;; image metadata


fix another minor bug

fix another minor bug

git-svn-id: 03a8048b5ee8463be5048a3801110fb50f378627@6873 d0ab736e-dc22-4aeb-8dc9-08def0aa14fd

--- acqEngine/src/org/micromanager/acq_engine.clj
+++ acqEngine/src/org/micromanager/acq_engine.clj
@@ -151,10 +151,11 @@

 (defn compute-time-from-core [tags]
   ; (log "core tags: " tags)
-  (when (@state :burst-init-time)
+  (if (@state :burst-init-time)
     (when-let [t (tags "ElapsedTime-ms")]
       (+ (Double/parseDouble t)
-         (@state :burst-init-time)))))
+         (@state :burst-init-time)))
+    nil))

 (defn elapsed-time [state]
   (if (state :start-time) (- (clock-ms) (state :start-time)) 0))


Polish example

Polish example

--- examples/frontend/src/frontend/core.cljs
+++ examples/frontend/src/frontend/core.cljs
@@ -1,11 +1,11 @@
 (ns frontend.core
-    (:require [reagent.core :as r]
-              [reitit.frontend :as rf]
-              [reitit.frontend.easy :as rfe]
-              [reitit.coercion :as rc]
-              [reitit.coercion.schema :as rsc]
-              [schema.core :as s]
-              [fipp.edn :as fedn]))
+  (:require [reagent.core :as r]
+            [reitit.frontend :as rf]
+            [reitit.frontend.easy :as rfe]
+            [reitit.coercion :as rc]
+            [reitit.coercion.schema :as rsc]
+            [schema.core :as s]
+            [fipp.edn :as fedn]))

 (defn home-page []
   [:div
@@ -19,7 +19,7 @@
    [:button
     {:type "button"
      :on-click #(rfe/replace-state ::item {:id 4})}
-    "Replace State Item 4"] ])
+    "Replace State Item 4"]])

 (defn about-page []
   [:div
@@ -52,25 +52,26 @@
    [:pre (with-out-str (fedn/pprint @match))]])

 (def routes
-  (rf/router
-    ["/"
-     [""
-      {:name ::frontpage
-       :view home-page}]
-     ["about"
-      {:name ::about
-       :view about-page}]
-     ["item/:id"
-      {:name ::item
-       :view item-page
-       :parameters {:path {:id s/Int}
-                    :query {(s/optional-key :foo) s/Keyword}}}]]
-    {:data {:coercion rsc/coercion}}))
+  [["/"
+    {:name ::frontpage
+     :view home-page}]
+
+   ["/about"
+    {:name ::about
+     :view about-page}]
+
+   ["/item/:id"
+    {:name ::item
+     :view item-page
+     :parameters {:path {:id s/Int}
+                  :query {(s/optional-key :foo) s/Keyword}}}]])

 (defn init! []
-  (rfe/start! routes
-              (fn [m] (reset! match m))
-              {:use-fragment true})
+  (rfe/start!
+    (rf/router routes {:data {:coercion rsc/coercion}})
+    (fn [m] (reset! match m))
+    ;; set to false to enable HistoryAPI
+    {:use-fragment true})
   (r/render [current-page] (.getElementById js/document "app")))

 (init!)


Confirmation before removing environment variable

--- src-cljs/frontend/components/project_settings.cljs
+++ src-cljs/frontend/components/project_settings.cljs
@@ -407,6 +407,34 @@
            [:hr]
            (clear-cache-button "source" project-data owner)]]]))))

+(defn remove-env-var-button [{:keys [env-var project-id]} owner]
+  (reify
+    om/IInitState
+    (init-state [_]
+      {:show-modal? false})
+    om/IRenderState
+    (render-state [_ {:keys [show-modal?]}]
+      (html
+       [:span
+        (table/action-button
+         "Remove"
+         (icon/delete)
+         #(om/set-state! owner :show-modal? true))
+        (when show-modal?
+          (let [close-fn #(om/set-state! owner :show-modal? false)]
+            (modal/modal-dialog {:title "Are you sure?"
+                                 :body (html
+                                        [:span
+                                         "Are you sure you want to remove the environment variable \""
+                                         (:name env-var)
+                                         "\"?"])
+                                 :actions [(button/button {:on-click close-fn} "Cancel")
+                                           (button/button {:primary? true
+                                                           :on-click #(raise! owner [:deleted-env-var {:project-id project-id
+                                                                                :env-var-name (:name env-var)}])}
+                                                          "Delete")]
+                                 :close-fn close-fn})))]))))
+
 (defn env-vars [project-data owner]
   (reify
     om/IRender
@@ -417,58 +445,55 @@
             new-env-var-value (:new-env-var-value inputs)
             project-id (project-model/id project)]
         (html
-          [:section
-           [:article
-            [:h2 "Environment Variables for " (vcs-url/project-name (:vcs_url project))]
-            [:div
-             [:p
-              "Add environment variables to the project build.  You can add sensitive data (e.g. API keys) here, rather than placing them in the repository. "
-              "The values can be any bash expression and can reference other variables, such as setting "
-              [:code "M2_MAVEN"] " to " [:code "${HOME}/.m2)"] "."]
-
-             [:p
-              " To disable string substitution you need to escape the " [:code "$"]
-              " characters by prefixing them with " [:code "\\"] "."
-              " For example, a value like " [:code "usd$"] " would be entered as " [:code "usd\\$"] "." ]
-             [:form
-              [:div.form-group
-               [:label "Name"]
-               [:input.form-control#env-var-name
-                {:required true, :type "text", :value new-env-var-name
-                 :on-change #(utils/edit-input owner (conj state/inputs-path :new-env-var-name) %)}]]
-              [:div.form-group
-               [:label "Value"]
-               [:input.form-control#env-var-value
-                {:required true
-                 :type "text"
-                 :value new-env-var-value
-                 :auto-complete "off"
-                 :on-change #(utils/edit-input owner (conj state/inputs-path :new-env-var-value) %)}]]
-
-              [:div.form-group
-               (forms/managed-button
-                 [:input.btn.btn-primary {:data-failed-text "Failed",
-                                          :data-success-text "Added",
-                                          :data-loading-text "Adding...",
-                                          :value "Add Variable",
-                                          :type "submit"
-                                          :on-click #(raise! owner [:created-env-var {:project-id project-id}])}])]]
-             (when-let [env-vars (seq (:envvars project-data))]
-               (om/build table/table
-                         {:rows env-vars
-                          :columns [{:header "Name"
-                                     :cell-fn :name}
-                                    {:header "Value"
-                                     :cell-fn :value}
-                                    {:header "Remove"
-                                     :type #{:shrink :right}
-                                     :cell-fn
-                                     (fn [env-var]
-                                       (table/action-button
-                                        "Remove"
-                                        (icon/delete)
-                                        #(raise! owner [:deleted-env-var {:project-id project-id
-                                                                          :env-var-name (:name env-var)}])))}]}))]]])))))
+         [:section
+          [:article
+           [:h2 "Environment Variables for " (vcs-url/project-name (:vcs_url project))]
+           [:div
+            [:p
+             "Add environment variables to the project build.  You can add sensitive data (e.g. API keys) here, rather than placing them in the repository. "
+             "The values can be any bash expression and can reference other variables, such as setting "
+             [:code "M2_MAVEN"] " to " [:code "${HOME}/.m2)"] "."]
+
+            [:p
+             " To disable string substitution you need to escape the " [:code "$"]
+             " characters by prefixing them with " [:code "\\"] "."
+             " For example, a value like " [:code "usd$"] " would be entered as " [:code "usd\\$"] "." ]
+            [:form
+             [:div.form-group
+              [:label "Name"]
+              [:input.form-control#env-var-name
+               {:required true, :type "text", :value new-env-var-name
+                :on-change #(utils/edit-input owner (conj state/inputs-path :new-env-var-name) %)}]]
+             [:div.form-group
+              [:label "Value"]
+              [:input.form-control#env-var-value
+               {:required true
+                :type "text"
+                :value new-env-var-value
+                :auto-complete "off"
+                :on-change #(utils/edit-input owner (conj state/inputs-path :new-env-var-value) %)}]]
+
+             [:div.form-group
+              (forms/managed-button
+               [:input.btn.btn-primary {:data-failed-text "Failed",
+                                        :data-success-text "Added",
+                                        :data-loading-text "Adding...",
+                                        :value "Add Variable",
+                                        :type "submit"
+                                        :on-click #(raise! owner [:created-env-var {:project-id project-id}])}])]]
+            (when-let [env-vars (seq (:envvars project-data))]
+              (om/build table/table
+                        {:rows env-vars
+                         :columns [{:header "Name"
+                                    :cell-fn :name}
+                                   {:header "Value"
+                                    :cell-fn :value}
+                                   {:header "Remove"
+                                    :type #{:shrink :right}
+                                    :cell-fn
+                                    (fn [env-var]
+                                      (om/build remove-env-var-button {:env-var env-var
+                                                                       :project-id project-id}))}]}))]]])))))

 (defn advance [project-data owner]
   (reify


updated sessions

updated sessions

--- src-clj/mappt/server/routes.clj
+++ src-clj/mappt/server/routes.clj
@@ -9,14 +9,23 @@
             [compojure.response :as response]
             [prone.middleware :refer [wrap-exceptions]]))

-(defn generate-api-response [data & [status]]
+(defn generate-api-response [data session & [status]]
   {:status (or status 200)
    :headers {"Content-Type" "application/edn"}
-   :body (pr-str data)})
+   :body (pr-str data)
+   :session session})
+
+(defn generate-main-page [session]
+  (if (:test-var session)
+    {:status 200
+     :body (index-page)}
+    {:body "No Session"
+     :session (assoc session :test-var "foo")}))

 (defroutes main-routes
-  (GET "/" [] (index-page))
-  (POST "/api/echo" [data] (generate-api-response data))
+  (GET "/" {session :session} (generate-main-page session))
+  (POST "/api/echo" {session :session {:keys [data]}
+                     :params} (generate-api-response data session))
   (route/resources "/")
   (route/not-found "Page not found"))


Remove unused require

Remove unused require

--- src/com/puppetlabs/puppetdb/http/v2/fact_names.clj
+++ src/com/puppetlabs/puppetdb/http/v2/fact_names.clj
@@ -1,7 +1,6 @@
 (ns com.puppetlabs.puppetdb.http.v2.fact-names
   (:require [com.puppetlabs.puppetdb.query.facts :as f]
-            [com.puppetlabs.http :as pl-http]
-            [cheshire.core :as json])
+            [com.puppetlabs.http :as pl-http])
   (:use [net.cgrand.moustache :only [app]]
         com.puppetlabs.middleware
         [com.puppetlabs.jdbc :only (with-transacted-connection)]))


Interface between DB and rest of the app

--- src/emender_service/db_interface.clj
+++ src/emender_service/db_interface.clj
@@ -54,3 +54,25 @@
         (catch Exception e
             (println e))))

+(defn log-request-information
+    [request]
+    (let [uri       (:uri request)
+          ipaddress (:remote-addr request)
+          datetime  (format-current-date)
+          params    (:params request)
+          useragent ((:headers request) "user-agent")]
+          (record-request-log uri ipaddress datetime params useragent)))
+
+(defn log-job-started
+    [job-name]
+    (record-job-event job-name (format-current-date) "started"))
+
+(defn log-job-finished
+    [job-name]
+    (record-job-event job-name (format-current-date) "finished"))
+
+(defn log-job-results
+    [job-name results]
+    (record-job-event job-name (format-current-date) "results")
+    (record-job-results job-name (format-current-date) results))
+


Doc string typo fix

Doc string typo fix

--- ring-core/src/ring/middleware/session.clj
+++ ring-core/src/ring/middleware/session.clj
@@ -16,9 +16,9 @@
       session is stored. Defaults to in-memory storage
       (ring.middleware.session.store.MemoryStore).
     :root
-      The root path of the session. Anything path above this will not
-      be able to see this session. Equivalent to setting the cookie's
-      path attribute. Defaults to \"/\".
+      The root path of the session. Any path above this will not be able to
+      see this session. Equivalent to setting the cookie's path attribute.
+      Defaults to \"/\".
     :cookie-name
       The name of the cookie that holds the session key. Defaults to
       \"ring-session\"


Inbox: Hold ctrl to copy instead of move.

--- src-cljs/pepa/workflows/inbox2.cljs
+++ src-cljs/pepa/workflows/inbox2.cljs
@@ -18,7 +18,8 @@
             [pepa.components.page :as page]

             [cljs.reader :refer [read-string]]
-            [goog.string :as gstring])
+            [goog.string :as gstring]
+            goog.events.KeyCodes)
   (:require-macros [cljs.core.async.macros :refer [go go-loop]]
                    [cljs.core.match.macros :refer [match]])
   (:import [cljs.core.ExceptionInfo]
@@ -176,6 +177,9 @@
               (read-string))
       (js/console.warn "Couldn't read transfer-data for key:" (pr-str key))))

+(defn- drag-copy? [e]
+  e.ctrlKey)
+
 (defn ^:private column-drag-start
   "Called from `inbox-column' when `dragstart' event is fired. Manages
   selection-updates and sets the drag-data in the event."
@@ -234,12 +238,14 @@
                :on-drop (fn [e]
                           (println "on-drop")
                           (let [source-column (get-transfer-data e "application/x-pepa-column")
-                                page-ids (get-transfer-data e "application/x-pepa-pages")]
+                                page-ids (get-transfer-data e "application/x-pepa-pages")
+                                copy? (drag-copy? e)]
                             ;; Delegate to `inbox'
                             (handle-drop! (:id column)
                                           source-column
                                           page-ids
-                                          drop-idx))
+                                          drop-idx
+                                          copy?))
                           ;; Remove drop-target
                           (om/set-state! owner :drop-idx nil))}
      [:header
@@ -266,12 +272,14 @@
                    :on-drop (fn [e]
                               (println "[new-document-ui] on-drop")
                               (let [source-column (get-transfer-data e "application/x-pepa-column")
-                                    page-ids (get-transfer-data e "application/x-pepa-pages")]
+                                    page-ids (get-transfer-data e "application/x-pepa-pages")
+                                    copy? (drag-copy? e)]
                                 ;; Delegate to `inbox'
                                 (handle-drop! (:id column)
                                               source-column
                                               page-ids
-                                              0)))}
+                                              0
+                                              copy?)))}
      [:header nil]
      [:.center
       "Drag pages here or press \"Open\" to open a document"
@@ -340,7 +348,7 @@
                                                          [:search (:search column)]
                                                          [:document (:id document)]))}})]]))

-(defn ^:private inbox-handle-drop! [state owner page-cache target source page-ids target-idx]
+(defn ^:private inbox-handle-drop! [state owner page-cache target source page-ids target-idx copy?]
   (let [columns (om/get-state owner :columns)
         target  (first (filter #(= (:id %) target) columns))
         source  (first (filter #(= (:id %) source) columns))
@@ -369,8 +377,11 @@
       (go
         (if (<! (accept-drop! target state pages target-idx))
           (do
-            (println "Target saved. Removing from source...")
-            (<! (remove-pages! source state page-ids))
+            ;; TODO: Handle copy instead of move
+            (println "Target saved.")
+            (when-not copy?
+              (println "Removing from source...")
+              (<! (remove-pages! source state page-ids)))
             (println "Drop saved!"))
           (js/console.warn "`accept-drop!' returned non-truthy value. Aborting drop."))))))


More!

More!

--- src-cljs/githubcomments/core.cljs
+++ src-cljs/githubcomments/core.cljs
@@ -1,15 +1,15 @@
 (ns githubcomments.core
   (:require-macros [cljs.core.async.macros :refer [go]])
-   (:require [cljs.core.async :as async]
-             [goog.dom :as dom]
-             [githubcomments.github :refer [repo-comments
-                                            render-user-content-markdown]]))
-
-(def repo ["Magnetic" "Platform-Guild"])
+  (:require [cljs.core.async :as async]
+            [goog.dom :as dom]
+            [goog.dom.dataset :as dataset]
+            [githubcomments.github :refer [repo-comments
+                                           render-user-content-markdown]]))

 (defn rendered-comment [repo comment]
   "Render the given comment in the context of the given repository."
-  (go (let [response (async/<! (render-user-content-markdown (:body comment) repo))]
+  (go (let [response (async/<!
+                       (render-user-content-markdown (:body comment) repo))]
         (.log js/console (:body response)))))

 (enable-console-print!)
@@ -18,8 +18,10 @@
   (map (partial rendered-comment repo) comments))

 (defn init []
-  (go (let [response (async/<! (repo-comments repo))
-            element (dom/getElement "github-comments")]
+  (go (let [element (dom/getElement "github-comments")
+            repo [(dataset/get element "repositoryOwner")
+                  (dataset/get element "repositoryName")]
+            response (async/<! (repo-comments repo))]
         (apply println (rendered-comments repo (:body response))))))

 (init)


Allow ; and - in history token.

Allow ; and - in history token.

--- src-cljs/kixi/hecuba/history.cljs
+++ src-cljs/kixi/hecuba/history.cljs
@@ -11,7 +11,7 @@
 (enable-console-print!)

 (defn match-token [s]
-  (re-matches #"((?:[A-Za-z0-9]+)(?:,(?:[A-Za-z0-9]+))*)(?:/search/(.*))?" s))
+  (re-matches #"((?:[A-Za-z0-9-;]+)(?:,(?:[A-Za-z0-9;-]+))*)(?:/search/(.*))?" s))

 (def ^:private key-order [:programme :project :property :device :sensor :measurement])


update task complete time using database time

--- src/polismath/components/postgres.clj
+++ src/polismath/components/postgres.clj
@@ -310,12 +310,8 @@
 ;; Marks all tasks with the same task_bucket as done.
 (defn mark-task-complete!
   [postgres task_bucket]
-  (log/info "mark-task-complete")
-  (jdbc/update!
-    (:db-spec postgres)
-    :worker_tasks
-    {:finished_time (System/currentTimeMillis)}
-    ["task_bucket = ?" task_bucket]))
+  (log/info "mark-task-complete" task_bucket)
+  (query postgres ["update worker_tasks set finished_time = now_as_millis() where math_env = (?) and task_bucket = (?) returning finished_time;" (name (-> postgres :config :math-env)) task_bucket]))

 (defn upload-math-main
   [postgres zid data]