Cleaning up ingest lifecycle test to enhance readability.

--- system-int-test/test/cmr/system_int_test/ingest/ingest_lifecycle_integration_test.clj
+++ system-int-test/test/cmr/system_int_test/ingest/ingest_lifecycle_integration_test.clj
@@ -17,6 +17,7 @@
   ([granules]
    (assert-granules-found granules {}))
   ([granules params]
+   (index/wait-until-indexed)
    (is (d/refs-match? granules (search/find-refs :granule params))
        (str "Could not find granules with " (pr-str params)))))

@@ -24,6 +25,7 @@
   ([collections]
    (assert-collections-found collections {}))
   ([collections params]
+   (index/wait-until-indexed)
    (is (d/refs-match? collections (search/find-refs :collection params)))))

 (defn assert-collections-and-granules-found
@@ -96,11 +98,14 @@
   ;; Nothing should be found yet.
   (assert-collections-and-granules-found [] [])

+  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+  ;; Inserts
+  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
   ;; Insert collections
   (let [coll1 (make-coll 1)
         coll2 (make-coll 2)
         coll3 (make-coll 3)]
-    (index/wait-until-indexed)
     ;; The collections can be found
     (assert-collections-and-granules-found [coll1 coll2 coll3] [])

@@ -109,42 +114,41 @@
           gr2 (make-gran coll1 2)
           gr3 (make-gran coll2 3)
           gr4 (make-gran coll2 4)]
-      (index/wait-until-indexed)
-      ;; The granule can be found
-      (assert-granules-found [gr1 gr2 gr3 gr4])
+      (assert-collections-and-granules-found [coll1 coll2 coll3] [gr1 gr2 gr3 gr4])
+
+      ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+      ;; Updates
+      ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

       (let [;; Update a collection
             coll2 (update-coll coll2 {:projects (dc/projects "ESI")})
             ;; Update a granule
             gr1 (update-gran coll1 gr1 {:data-granule (dg/data-granule {:day-night "DAY"})})]
-        (index/wait-until-indexed)
         ;; All items can still be found
         (assert-collections-and-granules-found [coll1 coll2 coll3] [gr1 gr2 gr3 gr4])

-        ;; Updated collections are found
+        ;; Updated collections and granule are found with specific parameters
         (assert-collections-found [coll2] {:project "ESI"})
+        (assert-granules-found [gr1] {:day-night-flag "DAY"})

-        ;; Updated granules are found
-        (assert-granules-found [gr1] {:day-night-flag "DAY"})
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        ;; Deletion and Recreation
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

         ;; Delete a granule
         (ingest/delete-concept (d/item->concept gr3))
-        (index/wait-until-indexed)
         (assert-collections-and-granules-found [coll1 coll2 coll3] [gr1 gr2 gr4])

         ;; Reingest the granule
         (let [gr3 (ingest-gran coll2 gr3)]
-          (index/wait-until-indexed)
           (assert-collections-and-granules-found [coll1 coll2 coll3] [gr1 gr2 gr3 gr4])

           ;; Delete a collection
           (ingest/delete-concept (d/item->concept coll1))
-          (index/wait-until-indexed)
           ;; Verify collection delete results in collection and child collections not found
           (assert-collections-and-granules-found [coll2 coll3] [gr3 gr4])

           ;; Reingest the collection
           (let [coll1 (ingest-coll coll1)]
-            (index/wait-until-indexed)
             (assert-collections-and-granules-found [coll1 coll2 coll3] [gr3 gr4])))))))


bugfix in distillery.view.hitlist: - no automatic suppression of confidence value - possible format exception with integer values for confidence

--- src/distillery/view/hitlist.clj
+++ src/distillery/view/hitlist.clj
@@ -12,9 +12,9 @@
                   (let [minc (cfg/value :min-confidence config)
                         cnf* (/ (- cnf minc) (- 1 minc))]
                     (* cnf* cnf*)))
-        stats-str-fn (if (= 1.0 (mean (map :mean-confidence hitlist)))
+        stats-str-fn (if (== 1 (mean (map :mean-confidence hitlist)))
                        (fn [n c] (str n))
-                       (fn [n c] (str n " | " (format "%2.1f%%" (* 100 c)))))
+                       (fn [n c] (str n " | " (format "%2.1f%%" (* 100.0 c)))))
         item-gen (fn [{:keys [id lexical-form pronunciation mean-confidence] :as w}]
                    (let [num-occ (count (occ-fn w))]
                      (list-item
@@ -34,5 +34,3 @@
          [(headline 3 "Häufige Worte")
           (olist (map item-gen hitlist))])))

-
-


(SERVER-1204) Update catalog schema for version field

A catalog's version entry can be anything when a custom config_version
script is used, so this commit updates the schema accordingly.

--- test/integration/puppetlabs/puppetserver/testutils.clj
+++ test/integration/puppetlabs/puppetserver/testutils.clj
@@ -34,7 +34,7 @@
   {(schema/required-key "name") schema/Str
    (schema/required-key "classes") [schema/Str]
    (schema/required-key "environment") schema/Str
-   (schema/required-key "version") schema/Int
+   (schema/required-key "version") schema/Any
    (schema/required-key "resources") [PuppetResource]
    (schema/required-key "edges") [{schema/Str schema/Str}]
    (schema/optional-key "code_id") (schema/maybe schema/Str)


no need to nuke cookie

no need to nuke cookie

--- src/crawler/template_removal.clj
+++ src/crawler/template_removal.clj
@@ -6,21 +6,12 @@

 (def my-cs (cookies/cookie-store))

-(defn look-at-cookie
+(defn look-at
   ([a-link]
      (look-at a-link (set [])))

   ([a-link blacklist]
      (try (let [body  (-> a-link (client/get {:cookie-store my-cs}) :body)]
-            (extractor/state-action body a-link blacklist))
-          (catch Exception e nil))))
-
-(defn look-at
-  ([a-link]
-     (look-at a-link (set [])))
-
-  ([a-link blacklist]
-     (try (let [body  (-> a-link (client/get) :body)]
             (extractor/state-action body a-link blacklist))
           (catch Exception e nil))))


Make make-completion-item a multimethod

Make make-completion-item a multimethod

--- src/de/kotka/vimclojure/util.clj
+++ src/de/kotka/vimclojure/util.clj
@@ -241,25 +241,76 @@
                             (catch IllegalStateException _
                               "v"))))

-(defn make-completion-item
+(defmulti make-completion-item
   "Create a completion item for Vim's popup-menu."
-  [the-name the-thing]
-  (let [typ      (type-of-completion the-thing)
-        info     (str "  " the-name \newline)
-        metainfo (when (some #{\f \m \v \n} typ)
-                   (meta the-thing))
-        arglists (:arglists metainfo)
+  (fn [_ the-thing] (type-of-completion the-thing)))
+
+(defmethod make-completion-item "n"
+  [the-name the-space]
+  (let [docs (-> the-space meta :doc)
+        info (str " " the-name \newline
+                  (when docs (str \newline docs)))]
+    (hash-map "word" the-name
+              "kind" "n"
+              "menu" ""
+              "info" info)))
+
+(defmethod make-completion-item "c"
+  [the-name _]
+  (hash-map "word" the-name
+            "kind" "c"
+            "menu" ""
+            "info" ""))
+
+(defmethod make-completion-item "M"
+  [the-name the-method]
+  (let [rtype    (-> the-method .getReturnType .getSimpleName str)
+        arglist  (.getParameterTypes the-method)
+        menu     (str-cat (concat arglist [rtype]) " -> ")
+        info     (str the-name " :: " menu)]
+    (hash-map "word" the-name
+              "kind" "M"
+              "menu" menu
+              "info" info)))
+
+(defmethod make-completion-item "v"
+  [the-name the-var]
+  (let [info (str "  " the-name \newline)
+        info (if-let [docstring (-> the-var meta :doc)]
+               (str info \newline "  " docstring)
+               info)]
+    (hash-map "word" the-name
+              "kind" "v"
+              "menu" (pr-str (try
+                               (type @the-var)
+                               (catch IllegalStateException _
+                                 "<UNBOUND>")))
+              "info" info)))
+
+(defn- make-completion-item-fm
+  [the-name the-fn typ]
+  (let [info     (str "  " the-name \newline)
+        metadata (meta the-fn)
+        arglists (:arglists metadata)
         info     (if arglists
                    (reduce #(str %1 "  " (prn-str (cons (symbol the-name) %2)))
                            (str info \newline) arglists)
                    info)
-        info     (if-let [docstring (:doc metainfo)]
+        info     (if-let [docstring (:doc metadata)]
                    (str info \newline "  " docstring)
                    info)]
     (hash-map "word" the-name
               "kind" typ
               "menu" (pr-str arglists)
               "info" info)))
+
+(defmethod make-completion-item "f"
+  [the-name the-fn]
+  (make-completion-item-fm the-name the-fn "f"))
+
+(defmethod make-completion-item "m"
+  [the-name the-fn]
+  (make-completion-item-fm the-name the-fn "m"))

 ; Namespace helpers
 (defn resolve-and-load-namespace


adapt and extend retrieval tests for public/private companies

--- test/open_company/integration/company/company_retrieval.clj
+++ test/open_company/integration/company/company_retrieval.clj
@@ -55,7 +55,7 @@
                      (after :contents (ts/teardown-system!))
                      (before :facts (pool/with-pool [conn (-> @ts/test-system :db-pool :pool)]
                                       (company/delete-all-companies! conn)
-                                      (company/create-company! conn (company/->company r/open r/coyote))
+                                      (company/create-company! conn (company/->company (assoc r/open :public true) r/coyote))
                                       (section/put-section conn r/slug :update r/text-section-1 r/coyote)
                                       (section/put-section conn r/slug :finances r/finances-section-1 r/coyote)
                                       (section/put-section conn r/slug :team r/text-section-2 r/coyote)
@@ -65,7 +65,7 @@
                      (after :facts (pool/with-pool [conn (-> @ts/test-system :db-pool :pool)]
                                      (company/delete-all-companies! conn)))]

-  (facts "about available options for retrieving a company"
+  (facts "about available options for retrieving a public company"

     (fact "with a bad JWToken"
       (let [response (mock/api-request :options (company-rep/url r/open) {:auth mock/jwtoken-bad})]
@@ -95,7 +95,7 @@
         (:body response) => ""
         ((:headers response) "Allow") => full-options)))

-  (facts "about failing to retrieve a company"
+  (facts "about failing to retrieve a public company"

     (fact "with an invalid JWToken"
       (let [response (mock/api-request :get (company-rep/url r/open) {:auth mock/jwtoken-bad})]
@@ -107,7 +107,7 @@
         (:status response) => 404
         (:body response) => "")))

-  (facts "about retrieving a company"
+  (facts "about retrieving a public company"

     (fact "that does match the retrieving user's organization"
       (let [response (mock/api-request :get (company-rep/url r/open))
@@ -162,4 +162,78 @@
             section-rep/media-type (:links (body section-key))))
         ;; verify the company has only a self HATEOAS link
         (count (:links body)) => 2
-        (hateoas/verify-link "self" GET (company-rep/url (:slug r/open)) company-rep/media-type (:links body))))))+        (hateoas/verify-link "self" GET (company-rep/url (:slug r/open)) company-rep/media-type (:links body))))))
+
+(with-state-changes [(before :contents (ts/setup-system!))
+                     (after :contents (ts/teardown-system!))
+                     (before :facts (pool/with-pool [conn (-> @ts/test-system :db-pool :pool)]
+                                      (company/delete-all-companies! conn)
+                                      (company/create-company! conn (company/->company r/open r/coyote))))
+                     (after :facts (pool/with-pool [conn (-> @ts/test-system :db-pool :pool)]
+                                     (company/delete-all-companies! conn)))]
+
+  (facts "about available options for retrieving a private company"
+
+    (fact "with a bad JWToken"
+      (let [response (mock/api-request :options (company-rep/url r/open) {:auth mock/jwtoken-bad})]
+        (:status response) => 401
+        (:body response) => common-api/unauthorized))
+
+    (fact "with no company matching the company slug"
+      (let [response (mock/api-request :options (company-rep/url "foo"))]
+        (:status response) => 404
+        (:body response) => ""))
+
+    (fact "with no JWToken"
+      (let [response (mock/api-request :options (company-rep/url r/open) {:skip-auth true})]
+        (:status response) => 204
+        (:body response) => ""
+        ((:headers response) "Allow") => limited-options))
+
+    (fact "with an organization that doesn't match the company"
+      (let [response (mock/api-request :options (company-rep/url r/open) {:auth mock/jwtoken-sartre})]
+        (:status response) => 204
+        (:body response) => ""
+        ((:headers response) "Allow") => limited-options))
+
+    (fact "with a user's org in a JWToken that matches the company's org"
+      (let [response (mock/api-request :options (company-rep/url r/open))]
+        (:status response) => 204
+        (:body response) => ""
+        ((:headers response) "Allow") => full-options)))
+
+  (facts "about failing to retrieve a private company"
+
+    (fact "with an invalid JWToken"
+      (let [response (mock/api-request :get (company-rep/url r/open) {:auth mock/jwtoken-bad})]
+        (:status response) => 401
+        (:body response) => common-api/unauthorized))
+
+    (fact "that doesn't exist"
+      (let [response (mock/api-request :get (company-rep/url "foo"))]
+        (:status response) => 404
+        (:body response) => "")))
+
+  (facts "about retrieving a private company"
+
+    (fact "that does match the retrieving user's organization"
+      (let [response (mock/api-request :get (company-rep/url r/open))
+            body (mock/body-from-response response)]
+        (:status response) => 200
+        (:name body) => (:name r/open)
+        (:slug body) => (:slug r/open)
+        (:org-id body) => nil ; verify no org-id
+        (:categories body) => (map name common/category-names)
+        (hateoas/verify-company-links (:slug r/open) (:links body))))
+
+    (fact "anonymously with no JWToken"
+      ;; retrieve with no JWToken
+      (let [response (mock/api-request :get (company-rep/url r/open) {:skip-auth true})
+            body (mock/body-from-response response)]
+        (:status response) => 403))
+
+    (fact "that doesn't match the retrieving user's organization"
+      ;; retrieve with Sartre (different org)
+      (let [response (mock/api-request :get (company-rep/url r/open) {:auth mock/jwtoken-sartre})
+            body (mock/body-from-response response)]
+        (:status response) => 403))))


Be a little more helpful when decoding fails

--- namespaces/common/src/main/clojure/immutant/codecs.clj
+++ namespaces/common/src/main/clojure/immutant/codecs.clj
@@ -54,15 +54,30 @@

 (defmethod decode :clojure [data _]
   "Turn a string into a clojure data structure"
-  (and data (read-string data)))
+  (try
+    (and data (read-string data))
+    (catch Throwable e
+      (throw (RuntimeException.
+              (str "Invalid clojure-encoded data (type=" (class data) "): " data)
+              e)))))

 (defmethod decode :edn [data & _]
-  "Turn a string into an edn data structure"
-  (and data (read-string data)))
+  "Turn an edn string into a clojure data structure"
+  (try
+    (and data (read-string data))
+    (catch Throwable e
+      (throw (RuntimeException.
+              (str "Invalid edn-encoded data (type=" (class data) "): " data)
+              e)))))

 (defmethod decode :json [data _]
-  "Turn a string into a json data structure"
-  (and data (json/parse-string data true)))
+  "Turn a json string into a clojure data structure"
+  (try
+    (and data (json/parse-string data true))
+    (catch Throwable e
+      (throw (RuntimeException.
+              (str "Invalid json-encoded data (type=" (class data) "): " data)
+              e)))))

 (defmethod decode :none [data _]
   "Treats the payload as raw. No decoding is done."


Use existing (map :key) convention for env

/cc @drsnyder

--- src/poky/protocol/http.clj
+++ src/poky/protocol/http.clj
@@ -125,7 +125,7 @@
         ; properly
         (wrap-charset "utf-8")
         trace/wrap-stacktrace
-        (statsd/wrap-response-code-counter (str (:statsd-key-base env "poky") ".resp_status")))))
+        (statsd/wrap-response-code-counter (str (env :statsd-key-base  "poky") ".resp_status")))))

 (defn start-server
@@ -136,7 +136,7 @@
   STATSD_KEY_BASE
   "
   [kvstore port]
-  (when-let [statsd-host (:statsd-host env)]
+  (when-let [statsd-host (env :statsd-host)]
     (let [[host port] (clojure.string/split statsd-host #":")]
       (when (and host port)
         (infof "Sending statsd metrics to %s" statsd-host)


wait a sec before launching :open-urls

wait a sec before launching :open-urls

--- sidecar/src/figwheel_sidecar/components/cljs_autobuild.clj
+++ sidecar/src/figwheel_sidecar/components/cljs_autobuild.clj
@@ -127,7 +127,10 @@
                     :build-config
                     :figwheel
                     :open-urls))]
-    (doseq [url urls] (open-url-once url))))
+    ;; wait a tick for files to flush into directories
+    (Thread/sleep 400)
+    (doseq [url urls]
+      (open-url-once url))))

 (defn open-urls-hook [build-fn]
   (fn [build-state]


Delete old version of helper fn

Delete old version of helper fn

--- src/braid/core/client/gateway/forms/join_group/events.cljs
+++ src/braid/core/client/gateway/forms/join_group/events.cljs
@@ -9,9 +9,6 @@
   (fn [{state :db}]
     {:dispatch-n [[:braid.core.client.gateway.forms.user-auth.events/initialize :log-in]
                   [::remote-get-group-info]]}))
-
-(defn get-url-group-id []
-  (last (string/split js/window.location #"/")))

 (reg-event-fx
   ::handle-group-info


insights: add filter to `get-projects-builds`

--- src-cljs/frontend/api.cljs
+++ src-cljs/frontend/api.cljs
@@ -136,9 +136,11 @@
           ;; Fire off an ajax call for the page. The API controllers will
           ;; deliver the response to page-result, and put the full data in the
           ;; state once all of the page-results are delivered.
-          (ajax/ajax :get url :recent-project-builds api-ch :context {:project-id build-key
-                                                                      :page-result page-result
-                                                                      :all-page-results page-results}))))))
+          (ajax/ajax :get url :recent-project-builds api-ch
+                     :context {:project-id build-key
+                               :page-result page-result
+                               :all-page-results page-results}
+                     :params {:filter "build-insights"}))))))

 (defn get-action-output [{:keys [vcs-url build-num step index output-url]
                           :as args} api-ch]


Send keyword vcs-type to get-org-workflows API

--- src-cljs/frontend/api.cljs
+++ src-cljs/frontend/api.cljs
@@ -103,7 +103,7 @@
              :params
              {:type :get-org-workflows
               :params {:organization/name org-name
-                       :organization/vcs-type vcs-type}}))
+                       :organization/vcs-type (keyword vcs-type)}}))

 (defn request-retry-run [api-ch run-id]
   (ajax/ajax :post


Removed https from Facebook thingy

Removed https from Facebook thingy

--- src/skidskytte/views.clj
+++ src/skidskytte/views.clj
@@ -12,7 +12,7 @@
   fjs.parentNode.insertBefore(js, fjs);
 }(document, 'script', 'facebook-jssdk'));</script>")

-(def fb-like-button "

")
+(def fb-like-button "

")

 (def tweet-button "Tweeta
 ")


Jobs need to be added into the build queue after creation

--- src/emender_jenkins/rest_api.clj
+++ src/emender_jenkins/rest_api.clj
@@ -285,14 +285,20 @@
                     (-> (job-already-exist-response job-name :create-job)
                         (send-error-response request :bad-request))
                     (if (job-metadata-ok? job-name git-repo branch)
-                        (-> (jenkins-api/create-job (config/get-jenkins-url request)
-                                                    (config/get-jenkins-auth request)
-                                                    (config/include-jenkins-reply? request)
-                                                    job-name git-repo branch
-                                                    (config/get-credentials-id request)
-                                                    metadata-directory metadata)
-                            (reload-job-list request)
-                            (send-response request))
+                        (let [response
+                            (-> (jenkins-api/create-job (config/get-jenkins-url request)
+                                                        (config/get-jenkins-auth request)
+                                                        (config/include-jenkins-reply? request)
+                                                        job-name git-repo branch
+                                                        (config/get-credentials-id request)
+                                                        metadata-directory metadata))]
+                            (-> (jenkins-api/start-job  (config/get-jenkins-url request)
+                                                        (config/get-jenkins-auth request)
+                                                        (config/include-jenkins-reply? request)
+                                                        job-name))
+                            (-> response
+                                (reload-job-list request)
+                                (send-response request)))
                         (send-job-invalid-metadata-response request :create-job (job-invalid-input job-name git-repo branch))))
                 (send-wrong-job-name-response request job-name :create-job)))
         (catch Exception e


Add step* impl for s/coll-of

Add step* impl for s/coll-of

--- src/spectrace/trace.cljc
+++ src/spectrace/trace.cljc
@@ -94,6 +94,14 @@
                  :val (nth val segment))
           (update :in rest)))))

+(defmethod step* `s/coll-of [{:keys [val in] :as state} succ fail]
+  (with-cont succ fail
+    (let [[key & in] in]
+      (-> state
+          (update :spec get-in [:args :spec])
+          (assoc :val (nth val key))
+          (assoc :in in)))))
+
 (defmethod step* `s/cat [state succ fail]
   (step-by-key state succ fail :val-fn nth))


Add stop-marker component

Add stop-marker component

--- src/cljs/gtfve/components/maps_canvas/google.cljs
+++ src/cljs/gtfve/components/maps_canvas/google.cljs
@@ -26,6 +26,24 @@
             [:p (pr-str (js->clj (.getBounds gmap)))]
             [:p (count data) (pr-str [(:stop/latitude (last data))
                                       (:stop/longitude (last data))])]])]]))))
+
+(defn stop-marker [data owner]
+  (reify
+    om/IDisplayName (display-name [_] "Stop Marker")
+    om/IWillMount
+    (will-mount [_]
+      (let [gmap (om/get-state owner :gmap)
+            marker (maps/marker [(:stop/latitude data)
+                                 (:stop/longitude data)]
+                                :map gmap)]
+        (om/set-state! owner :marker marker)))
+    om/IWillUnmount
+    (will-unmount [_]
+      (let [{:keys [marker]} (om/get-state owner)]
+        (.setMap marker nil)))
+    om/IRender
+    (render [_]
+      (html [:noscript (pr-str data)]))))

 (defn search-stop-marker [data owner]
@@ -136,10 +154,23 @@
     (render-state [_ {:keys [gmap info-window data-click-mult] :as state}]
       (let [stops (:stops-search-results data)]
         (html
-         (into [:div.maps-viewport [:div.maps-canvas {:ref "gmap"}]]
-               (when gmap
-                 (om/build-all search-stop-marker stops {:key :stop/id
-                                                         :state {:gmap gmap
-                                                                 :info-window info-window
-                                                                 :data-click-mult data-click-mult}}))
-               ))))))
+         (->> [:div.maps-viewport
+               #_(om/build maps-canvas-dev (:stops data) {:state {:gmap gmap}})
+               [:div.maps-canvas {:ref "gmap"}]]
+              (#(if gmap
+                  (into
+                   %
+                   (om/build-all search-stop-marker stops {:key :stop/name
+                                                           :state {:gmap gmap
+                                                                   :info-window info-window
+                                                                   :data-click-mult data-click-mult}}))
+                  %))
+              (#(if gmap
+                  (into
+                   %
+                   (om/build-all stop-marker
+                                 (:stops data)
+                                 {:key :stop/id
+                                  :state {:gmap gmap}}))
+                  %))
+              ))))))


Memoize a bit more of the expensive work in dispatcher

--- src/flatland/useful/dispatch.clj
+++ src/flatland/useful/dispatch.clj
@@ -14,7 +14,10 @@
   [dispatch-fn & options]
   (let [{:keys [hierarchy wrap default]} (into-map options)
         wrap    (or wrap identity)
-        require (memoize require)]
+        publics (memoize (fn [ns]
+                           (try (require ns)
+                                (ns-publics (find-ns ns))
+                                (catch java.io.FileNotFoundException e))))]
     (fn [& args]
       (let [fname   (apply dispatch-fn args)
             default (or default
@@ -23,10 +26,7 @@
                           {:no-wrap true}))]
         (loop [[ns method] (map symbol ((juxt namespace name) (symbol fname)))]
           (if-let [f (if ns
-                       (try (require ns)
-                            (-> (ns-publics (find-ns ns))
-                                (get method))
-                            (catch java.io.FileNotFoundException e))
+                       (get (publics ns) method)
                        default)]
             (let [wrap (if (:no-wrap (meta f))
                          identity


propagate group-opts only to immediate successor

--- pigpen-cascading/src/main/clojure/pigpen/cascading.clj
+++ pigpen-cascading/src/main/clojure/pigpen/cascading.clj
@@ -119,7 +119,8 @@
                                        (into-array (map cfields keys))
                                        Fields/NONE
                                        (BufferJoin.)))
-        (add-val [:cogroup-opts] id {:group-type        :group
+        (add-val [:cogroup-opts] id {:group-id          id
+                                     :group-type        :group
                                      :join-nils         (true? (:join-nils opts))
                                      :group-all         is-group-all
                                      :num-streams       (count pipes)
@@ -144,14 +145,15 @@
                                        (group-key-cfields keys join-nils)
                                        (cfields fields)
                                        joiner))
-        (add-val [:cogroup-opts] id {:group-type :join
+        (add-val [:cogroup-opts] id {:group-id   id
+                                     :group-type :join
                                      :all-args   (true? (:all-args opts))}))))

 (defmethod command->flowdef :projection-flat
   [{:keys [code alias pipe field-projections]} flowdef]
   {:pre [code alias]}
   (command->flowdef (assoc code :pipe pipe
-                           :field-projections (or field-projections [{:alias alias}])) flowdef))
+                                :field-projections (or field-projections [{:alias alias}])) flowdef))

 (defmethod command->flowdef :generate
   [{:keys [id ancestors projections field-projections opts]} flowdef]
@@ -166,12 +168,12 @@
                               (println "ancestors" ancestors)
                               (throw (Exception. "not implemented"))))
         flowdef (let [pipe-opts (get-in flowdef [:cogroup-opts ancestor])]
-                  (if pipe-opts
+                  (if (= (:group-id pipe-opts) ancestor)
                     (add-val flowdef [:cogroup-opts] id pipe-opts)
                     flowdef))
         flowdef (reduce (fn [def cmd] (command->flowdef
                                         (assoc cmd :pipe id
-                                               :field-projections field-projections)
+                                                   :field-projections field-projections)
                                         def))
                         flowdef
                         flat-projections)]


DEPRECATED: `hmget*`, `hgetall*` in favor of new `as-map`, `parse-map`

--- src/taoensso/carmine.clj
+++ src/taoensso/carmine.clj
@@ -72,6 +72,23 @@
 (defmacro parse-raw     [& body] `(parse (with-meta identity {:raw? true}) ~@body))
 (defmacro parse-nippy [thaw-opts & body]
   `(parse (with-meta identity {:thaw-opts ~thaw-opts}) ~@body))
+
+(defn as-map [coll & [kf vf]]
+  (when-let [s' (seq coll)]
+    (let [kf (if-not (identical? kf :keywordize) kf
+                     (fn [k _] (keyword k)))]
+      (loop [m (transient {}) [k v :as s] s']
+        (let [k (if-not kf k (kf k v))
+              v (if-not vf v (vf k v))
+              new-m (assoc! m k v)]
+          (if-let [n (nnext s)]
+            (recur new-m n)
+            (persistent! new-m)))))))
+
+(comment (as-map ["a" "A" "b" "B" "c" "C"] :keywordize
+           (fn [k v] (case k (:a :b) (str "boo-" v) v))))
+
+(defmacro parse-map [form & [kf vf]] `(parse #(as-map % ~kf ~vf) ~form))

 (defn key
   "Joins parts to form an idiomatic compound Redis key name. Suggested style:
@@ -190,35 +207,6 @@

 (defn hmset* "Like `hmset` but takes a map argument."
   [key m] (apply hmset key (reduce concat m)))
-
-(defn hmget*
-  "Like `hmget` but automatically coerces reply into a hash-map.
-  Any parser will apply to each hash value."
-  [key field & more]
-  (let [fields (cons field more)
-        inner-parser (when-let [p protocol/*parser*] #(mapv p %))
-        outer-parser #(zipmap fields %)]
-    (->> (apply hmget key fields)
-         (parse (parser-comp outer-parser inner-parser)))))
-
-(defn hgetall*
-  "Like `hgetall` but automatically coerces reply into a hash-map. Optionally
-  keywordizes map keys. Any parser will apply to each hash value."
-  [key & [keywordize?]]
-  (let [inner-parser (when-let [p protocol/*parser*] #(mapv p %))
-        outer-parser (if keywordize?
-                       #(utils/keywordize-map (apply hash-map %))
-                       #(apply hash-map %))]
-    (->> (hgetall key)
-         (parse (parser-comp outer-parser inner-parser)))))
-
-(comment (wcar {} (hmset* "hkey" {:a "aval" :b "bval" :c "cval"}))
-         (wcar {} (hmset* "hkey" {})) ; ex
-         (wcar {} (hmget* "hkey" :a :b))
-         (wcar {} (parse str/upper-case (hmget* "hkey" :a :b)))
-         (wcar {} (hmget* "hkey" "a" "b"))
-         (wcar {} (hgetall* "hkey"))
-         (wcar {} (parse str/upper-case (hgetall* "hkey"))))

 (defn info*
   "Like `info` but automatically coerces reply into a hash-map."
@@ -458,7 +446,7 @@
      ~message-handlers ; Initial state
      ~@subscription-commands))

-;;;; Renamed/deprecated
+;;;; Deprecated

 (defn kname "DEPRECATED: Use `key` instead. `key` does not filter nil parts."
   [& parts] (apply key (filter identity parts)))
@@ -516,3 +504,28 @@
              (throw (Exception. (str "`ensure-atomically` failed after " idx#
                                      " attempts")))
              (recur (inc idx#))))))))
+
+(defn hmget* "DEPRECATED: Use `parse-map` instead."
+  [key field & more]
+  (let [fields (cons field more)
+        inner-parser (when-let [p protocol/*parser*] #(mapv p %))
+        outer-parser #(zipmap fields %)]
+    (->> (apply hmget key fields)
+         (parse (parser-comp outer-parser inner-parser)))))
+
+(defn hgetall* "DEPRECATED: Use `parse-map` instead."
+  [key & [keywordize?]]
+  (let [inner-parser (when-let [p protocol/*parser*] #(mapv p %))
+        outer-parser (if keywordize?
+                       #(utils/keywordize-map (apply hash-map %))
+                       #(apply hash-map %))]
+    (->> (hgetall key)
+         (parse (parser-comp outer-parser inner-parser)))))
+
+(comment (wcar {} (hmset* "hkey" {:a "aval" :b "bval" :c "cval"}))
+         (wcar {} (hmset* "hkey" {})) ; ex
+         (wcar {} (hmget* "hkey" :a :b))
+         (wcar {} (parse str/upper-case (hmget* "hkey" :a :b)))
+         (wcar {} (hmget* "hkey" "a" "b"))
+         (wcar {} (hgetall* "hkey"))
+         (wcar {} (parse str/upper-case (hgetall* "hkey"))))


[#189] Hotfix: `redis-call` was broken by 1ec18fe

--- src/taoensso/carmine.clj
+++ src/taoensso/carmine.clj
@@ -138,7 +138,7 @@
     (fn [[cmd & args]]
       (let [cmd-parts (-> cmd name str/upper-case (str/split #"-"))
             request   (into (vec cmd-parts) args)]
-        (commands/enqueue-request request (count cmd-parts))))
+        (commands/enqueue-request (count cmd-parts) request)))
     requests))

 (comment (wcar {} (redis-call [:set "foo" "bar"] [:get "foo"]


Revert change to challenge functions path

--- src/rpi_challenger/app.clj
+++ src/rpi_challenger/app.clj
@@ -17,7 +17,7 @@

 (def save-interval-in-seconds (* 5 60))

-(def challenge-functions-dir (File. "../challenges/src/")) ; TODO: parameterize the dir on command line or create an admin screen
+(def challenge-functions-dir (File. "../rpi-challenges/src/")) ; TODO: parameterize the dir on command line or create an admin screen

 (def app-state-file (File. "rpi-challenger-state.clj"))


New testing code

New testing code

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

--- acqEngine/src/org/micromanager/test.clj
+++ acqEngine/src/org/micromanager/test.clj
@@ -1,6 +1,6 @@
 (ns org.micromanager.test
-  (:import (java.util List)
-           (java.util.concurrent Executors)
+  (:import (java.util ArrayList List)
+           (java.util.concurrent Executors LinkedBlockingQueue ConcurrentLinkedQueue)
            (mmcorej TaggedImage)
            (org.json JSONObject)
            (org.micromanager MMStudioMainFrame)
@@ -90,12 +90,12 @@
 (def pop-lock (Object.))

 (defn pop-next []
-  (locking pop-lock
-           (when (or (core isSequenceRunning)
-                     (pos? (core getRemainingImageCount)))
-             (while (zero? (core getRemainingImageCount))
-               (Thread/sleep 10))
-             (core popNextImage))))
+  (when (or true
+          ;(core isSequenceRunning)
+            (pos? (core getRemainingImageCount)))
+    (while (zero? (core getRemainingImageCount))
+      (Thread/sleep 1))
+    (core popNextImage)))

 (defn pop-n [n]
   (repeatedly n pop-next))
@@ -104,36 +104,73 @@
   (pmap (fn [_] (pop-next)) (range n)))

 (defn test-speed [n]
-  (do (core startSequenceAcquisition n 0 true)
-      (time (dotimes [i n] (pop-next))))
+  (println
+    (do (core startSequenceAcquisition n 0 true) ;(Thread/sleep 1000)
+        (count (remove nil? (time (doall (repeatedly n pop-next)))))))
   (println (core isBufferOverflowed)))

-(defn fill-circular-buffer [n]
-  (core startSequenceAcquisition n 0 true)
-  (while (core isSequenceRunning) (Thread/sleep 10)))
+(defn fill-circular-buffer
+  ([n wait?]
+    (core startSequenceAcquisition n 0 true)
+    (when wait?
+      (while (core isSequenceRunning) (Thread/sleep 2))))
+  ([n] (fill-circular-buffer n true)))

-(defn single-thread-pop-test [n]
-  (fill-circular-buffer n)
-  (time (dotimes [i n]
-          (core popNextImage))))
+
+(def pop-lock (Object.))

-
-(defn multithread-pop [nthreads n]
-  (fill-circular-buffer n)
-  (let [pop-service (Executors/newFixedThreadPool nthreads)
-        pop-fn (cast Runnable #(core popNextImage))]
+
+
+(defn pop-next-image [image-queue]
+  (when-let [image
+             (locking pop-lock
+                      (while (and (zero? (core getRemainingImageCount))
+                                  (not (core isBufferOverflowed)))
+                        (Thread/sleep 0))
+                      (when (pos? (core getRemainingImageCount))
+                        (core popNextImage)))]
+    (when (and image image-queue)
+      (.add image-queue image))))
+
+(defn single-thread-pop-test [n wait? image-queue]
+  (def temp-queue image-queue)
+  (System/gc)
+  (fill-circular-buffer n wait?)
+  (time (do (dotimes [i n]
+              (pop-next-image image-queue))
+            (while (or (core isSequenceRunning)
+                       (pos? (core getRemainingImageCount)))
+              (Thread/sleep 1))))
+  (when (core isBufferOverflowed) (println "Buffer overflowed")))
+
+(defn multithread-pop [nthreads n wait? image-queue]
+  (let [pop (fn [] (pop-next-image image-queue))]
+    (fill-circular-buffer n wait?)
     (time
-      (do
+    (let [pop-service (Executors/newFixedThreadPool nthreads)]
+      (dorun
         (dotimes [i n]
-          (.submit pop-service pop-fn))
-        (while (pos? (core getRemainingImageCount))
-          (Thread/sleep 1))))))
+          (.submit pop-service ^Runnable pop))
+        (while (or (core isSequenceRunning)
+                   (and (pos? (core getRemainingImageCount))
+                        (pos? (count (.getQueue pop-service)))))
+          (Thread/sleep 1)))))
+        (when (core isBufferOverflowed) (println "Buffer overflowed"))
+    (Thread/sleep 10)
+    image-queue))

 (defn repeat-with-params [f & more]
   (doseq [[n args] (partition 2 more)]
     (println n args)
     (doall
       (repeatedly n #(apply f args)))))
+
+(defn memory []
+  (let [runtime (Runtime/getRuntime)
+        mb (* 1024 1024.)]
+    {:total (/ (.totalMemory runtime) mb)
+     :free (/ (.freeMemory runtime) mb)
+     :max (/ (.maxMemory runtime) mb)}))


Add a paragraph on terminal handlers to dispatcher ns docstring

--- src/io/aviso/rook/dispatcher.clj
+++ src/io/aviso/rook/dispatcher.clj
@@ -10,7 +10,7 @@

   The expected way to use this namespace is as follows:

-   - namespaces still correspond to resources;
+   - namespaces correspond to resources;

    - namespace-dispatch-table produces a dispatch table for a single
      namespace;
@@ -22,7 +22,13 @@
      compile-dispatch-table.

   compile-dispatch-table takes several options; these are all
-  described in its docstring."
+  described in its docstring.
+
+  The individual \"terminal handlers\" -- functions held in Vars with
+  path or route specs attached -- are expected to support a single
+  arity only. The arglist for that arity and the metadata on the
+  terminal handler Var will be examined to determine the correct
+  argument resolution strategy at dispatch table compilation time."
   (:require [clojure.core.async :as async]
             [clojure.string :as string]
             [clojure.pprint :as pp]


Organize cues into separate pages.

Organize cues into separate pages.

Make them easier to understand in the code, and to move around as the
show evolves.

--- src/afterglow/examples.clj
+++ src/afterglow/examples.clj
@@ -7,6 +7,7 @@
             [afterglow.controllers.tempo]
             [afterglow.core :as core]
             [afterglow.effects :as fx]
+            [afterglow.effects.channel :as chan-fx]
             [afterglow.effects.color :as color-fx]
             [afterglow.effects.cues :as cues]
             [afterglow.effects.dimmer :refer [dimmer-effect master-set-level]]
@@ -89,9 +90,12 @@
                        :z (tf/inches 164.5))
   (show/patch-fixture! :hyp-rgb (adj/hypnotic-rgb) universe 45)

+  ;; These two can be patched as generic switches instead if you don't want them to respond to dimmer cues.
+  (show/patch-fixture! :eco-uv (afterglow.fixtures/generic-dimmmer) universe 61)
+  (show/patch-fixture! :h2o-led (afterglow.fixtures/generic-dimmmer) universe 62)
+
   (reset! var-binder (var-fx/create-for-show *show*))
   '*show*)
-

 (defn global-color-effect
   "Make a color effect which affects all lights in the sample show.
@@ -275,8 +279,8 @@

 (defn- make-torrent-gobo-cues
   "Create cues for the fixed and moving gobo options, stationary and
-  shaking. Takes up half a page on the Push, with the top left at the
-  coordinates specified."
+  shaking. Takes up half a page, with the top left at the coordinates
+  specified."
   [prefix fixtures top left]
   ;; Make cues for the stationary and shaking versions of all fixed gobos
   (doseq [_ (map-indexed (fn [i v]
@@ -567,10 +571,14 @@
                          :name "Cycles"}
                         {:key "phase" :min 0 :max 1 :start :starting-phase :name "Phase"}]))

-(defn make-cues
-  "Create a bunch of example cues for experimentation."
-  []
-  (let [hue-bar (oscillators/build-oscillated-param  ; Spread a rainbow across a bar of music
+(defn make-main-color-dimmer-cues
+  "Creates a page of cues that assign dimmers and colors to the
+  lights. This is probably going to be assigned as the first page, but
+  can be moved by passing non-zero values for `page-x` and `page-y`."
+  [page-x page-y]
+  (let [x-base (* page-x 8)
+        y-base (* page-y 8)
+        hue-bar (oscillators/build-oscillated-param  ; Spread a rainbow across a bar of music
                  (oscillators/sawtooth :interval :bar) :max 360)
         desat-beat (oscillators/build-oscillated-param  ; Desaturate a color as a beat progresses
                     (oscillators/sawtooth :down? true) :max 100)
@@ -583,10 +591,10 @@

     ;; Bottom row assigns colors, first to all fixtures, and then (at a higher priority, so they can
     ;; run a the same time as the first, and locally override it) individual fixture groups.
-    (make-color-cue "white" 0 0 :include-color-wheels? true
+    (make-color-cue "white" (+ x-base 0) (+ y-base 0) :include-color-wheels? true
                     :fixtures (show/all-fixtures) :effect-key :all-color :effect-name "Color All")
     (doall (map-indexed (fn [i group]
-                          (make-color-cue "white" (inc i) 0 :include-color-wheels? true
+                          (make-color-cue "white" (+ x-base (inc i)) (+ y-base 0) :include-color-wheels? true
                                           :fixtures (show/fixtures-named group)
                                           :effect-key (keyword (str (name group) "-color"))
                                           :effect-name (str "Color " (name group))
@@ -595,21 +603,21 @@

     ;; Some special/fun cues
     (show/set-variable! :rainbow-saturation 100)
-    (ct/set-cue! (:cue-grid *show*) 0 1
+    (ct/set-cue! (:cue-grid *show*) (+ x-base 0) (+ y-base 1)
                  (let [color-param (params/build-color-param :s :rainbow-saturation :l 50 :h hue-bar)]
                    (cues/cue :all-color (fn [_] (global-color-effect color-param))
                              :color-fn (cues/color-fn-from-param color-param)
                              :short-name "Rainbow Bar Fade"
                              :variables [{:key :rainbow-saturation :name "Saturatn" :min 0 :max 100 :start 100
                                           :type :integer}])))
-    (ct/set-cue! (:cue-grid *show*) 1 1
+    (ct/set-cue! (:cue-grid *show*) (+ x-base 1) (+ y-base 1)
                  (cues/cue :all-color (fn [_] (global-color-effect
                                                (params/build-color-param :s :rainbow-saturation :l 50 :h hue-gradient)
                                                :include-color-wheels? true))
                            :short-name "Rainbow Grid"
                            :variables [{:key :rainbow-saturation :name "Saturatn" :min 0 :max 100 :start 100
                                         :type :integer}]))
-    (ct/set-cue! (:cue-grid *show*) 2 1
+    (ct/set-cue! (:cue-grid *show*) (+ x-base 2) (+ y-base 1)
                  (let [color-param (params/build-color-param :s :rainbow-saturation :l 50 :h hue-gradient
                                                              :adjust-hue hue-bar)]
                    (cues/cue :all-color (fn [_] (global-color-effect color-param))
@@ -617,30 +625,30 @@
                              :short-name "Rainbow Grid+Bar"
                              :variables [{:key :rainbow-saturation :name "Saturatn" :min 0 :max 100 :start 100
                                           :type :integer}])))
-    (ct/set-cue! (:cue-grid *show*) 3 1  ; Desaturate the rainbow as each beat progresses
+    (ct/set-cue! (:cue-grid *show*) (+ x-base 3) (+ y-base 1) ; Desaturate the rainbow as each beat progresses
                  (let [color-param (params/build-color-param :s desat-beat :l 50 :h hue-gradient
                                                              :adjust-hue hue-bar)]
                    (cues/cue :all-color (fn [_] (global-color-effect color-param))
                              :color-fn (cues/color-fn-from-param color-param)
                              :short-name "Rainbow Pulse")))

-    (ct/set-cue! (:cue-grid *show*) 4 1
+    (ct/set-cue! (:cue-grid *show*) (+ x-base 4) (+ y-base 1)
                  (cues/cue :transform-colors (fn [_] (color-fx/transform-colors (show/all-fixtures)))
                            :priority 1000))

-    (ct/set-cue! (:cue-grid *show*) 5 1
+    (ct/set-cue! (:cue-grid *show*) (+ x-base 5) (+ y-base 1)
                  (cues/cue :all-color (fn [_] (global-color-effect
                                                (params/build-color-param :s 100 :l 50 :h hue-z-gradient)
                                                :include-color-wheels? true))
                            :short-name "Z Rainbow Grid"))
-    (ct/set-cue! (:cue-grid *show*) 6 1
+    (ct/set-cue! (:cue-grid *show*) (+ x-base 6) (+ y-base 1)
                  (let [color-param (params/build-color-param :s 100 :l 50 :h hue-z-gradient
                                                              :adjust-hue hue-bar)]
                    (cues/cue :all-color (fn [_] (global-color-effect color-param))
                              :color-fn (cues/color-fn-from-param color-param)
                              :short-name "Z Rainbow Grid+Bar")))

-    (ct/set-cue! (:cue-grid *show*) 7 1
+    (ct/set-cue! (:cue-grid *show*) (+ x-base 7) (+ y-base 1)
                  (let [color-param (params/build-color-param :s 100 :l 50 :h hue-gradient
                                                              :adjust-hue hue-bar)]
                    (cues/cue :all-color (fn [_] (global-color-effect color-param
@@ -648,16 +656,16 @@
                              :color-fn (cues/color-fn-from-param color-param)
                              :short-name "Rainbow Blades")))

-    #_(ct/set-cue! (:cue-grid *show*) 7 7
+    #_(ct/set-cue! (:cue-grid *show*) (+ x-base 7) (+ y-base 7)
                  (cues/function-cue :strobe-all :strobe (show/all-fixtures) :effect-name "Raw Strobe"))

     ;; Dimmer cues to turn on and set brightness of groups of lights
-    (make-dimmer-cue nil 0 2 :yellow)
-    (doall (map-indexed (fn [i group] (make-dimmer-cue group (inc i) 2 :yellow)) light-groups))
+    (make-dimmer-cue nil (+ x-base 0) (+ y-base 2) :yellow)
+    (doall (map-indexed (fn [i group] (make-dimmer-cue group (+ x-base (inc i)) (+ y-base 2) :yellow)) light-groups))

     ;; TODO: Write a macro to make it easier to bind cue variables?
-    (ct/set-cue! (:cue-grid *show*) 7 2
+    (ct/set-cue! (:cue-grid *show*) (+ x-base 7) (+ y-base 2)
                  (cues/cue :sparkle (fn [var-map] (fun/sparkle (show/all-fixtures)
                                                                :chance (:chance var-map 0.05)
                                                                :fade-time (:fade-time var-map 50)))
@@ -667,32 +675,36 @@
                                        {:key "fade-time" :name "Fade" :min 1 :max 2000 :start 50 :type :integer}]))

     ;; Dimmer oscillator cues: Sawtooth
-    (make-sawtooth-dimmer-cue nil 0 3 :yellow)
-    (doall (map-indexed (fn [i group] (make-sawtooth-dimmer-cue group (inc i) 3 :orange)) light-groups))
+    (make-sawtooth-dimmer-cue nil (+ x-base 0) (+ y-base 3) :yellow)
+    (doall (map-indexed (fn [i group]
+                          (make-sawtooth-dimmer-cue group (+ x-base (inc i)) (+ y-base 3) :orange)) light-groups))

     ;; Dimmer oscillator cues: Triangle
-    (make-triangle-dimmer-cue nil 0 4 :orange)
-    (doall (map-indexed (fn [i group] (make-triangle-dimmer-cue group (inc i) 4 :red)) light-groups))
+    (make-triangle-dimmer-cue nil (+ x-base 0) (+ y-base 4) :orange)
+    (doall (map-indexed (fn [i group]
+                          (make-triangle-dimmer-cue group (+ x-base (inc i)) (+ y-base 4) :red)) light-groups))

     ;; Dimmer oscillator cues: Sine
-    (make-sine-dimmer-cue nil 0 5 :cyan)
-    (doall (map-indexed (fn [i group] (make-sine-dimmer-cue group (inc i) 5 :blue)) light-groups))
+    (make-sine-dimmer-cue nil (+ x-base 0) (+ y-base 5) :cyan)
+    (doall (map-indexed (fn [i group]
+                          (make-sine-dimmer-cue group (+ x-base (inc i)) (+ y-base 5) :blue)) light-groups))

     ;; Dimmer oscillator cues: Square
-    (make-square-dimmer-cue nil 0 6 :cyan)
-    (doall (map-indexed (fn [i group] (make-square-dimmer-cue group (inc i) 6 :green)) light-groups))
+    (make-square-dimmer-cue nil (+ x-base 0) (+ y-base 6) :cyan)
+    (doall (map-indexed (fn [i group]
+                          (make-square-dimmer-cue group (+ x-base (inc i)) (+ y-base 6) :green)) light-groups))

     ;; Strobe cues
-    (make-strobe-cue-2 "All" (show/all-fixtures) 0 7)
-    (make-strobe-cue-2 "Torrents" (show/fixtures-named "torrent") 1 7)
-    (make-strobe-cue-2 "Blades" (show/fixtures-named "blade") 2 7)
-    (make-strobe-cue-2 "Weather Systems" (show/fixtures-named "ws") 3 7)
-    (make-strobe-cue-2 "Hexes" (show/fixtures-named "hex") 4 7)
-    (make-strobe-cue-2 "Pucks" (show/fixtures-named "puck") 5 7)
-    (make-strobe-cue-2 "Snowball" (show/fixtures-named "snowball") 6 7)
+    (make-strobe-cue-2 "All" (show/all-fixtures) (+ x-base 0) (+ y-base 7))
+    (make-strobe-cue-2 "Torrents" (show/fixtures-named "torrent") (+ x-base 1) (+ y-base 7))
+    (make-strobe-cue-2 "Blades" (show/fixtures-named "blade") (+ x-base 2) (+ y-base 7))
+    (make-strobe-cue-2 "Weather Systems" (show/fixtures-named "ws") (+ x-base 3) (+ y-base 7))
+    (make-strobe-cue-2 "Hexes" (show/fixtures-named "hex") (+ x-base 4) (+ y-base 7))
+    (make-strobe-cue-2 "Pucks" (show/fixtures-named "puck") (+ x-base 5) (+ y-base 7))
+    (make-strobe-cue-2 "Snowball" (show/fixtures-named "snowball") (+ x-base 6) (+ y-base 7))

     (let [color-var {:key :strobe-color :type :color :name "Strobe Color"}]
-      (ct/set-cue! (:cue-grid *show*) 7 7
+      (ct/set-cue! (:cue-grid *show*) (+ x-base 7) (+ y-base 7)
                    (cues/cue :strobe-color (fn [_] (fx/blank "Strobe Color"))
                              :color :purple
                              :color-fn (cues/color-fn-from-cue-var color-var)
@@ -700,265 +712,302 @@

     ;; This was the old way of adjusting strobe cues with only numeric parameters. The above
     ;; cue shows how to do it with the newer color parameter approach.
-    #_(ct/set-cue! (:cue-grid *show*) 7 6
+    #_(ct/set-cue! (:cue-grid *show*) (+ x-base 7) (+ y-base 6)
                  (cues/cue :adjust-strobe (fn [_] (fun/adjust-strobe))
                            :color :purple
                            :variables [{:key :strobe-hue :min 0 :max 360 :name "Hue" :centered true}
-                                       {:key :strobe-saturation :min 0 :max 100 :name "Saturatn"}]))
-
-    ;; The upper page of torrent config cues
-    (ct/set-cue! (:cue-grid *show*) 0 15
+                                       {:key :strobe-saturation :min 0 :max 100 :name "Saturatn"}]))))
+
+(defn make-torrent-cues
+  "Create a page of cues for configuring aspects of the Torrent F3s
+  and another to its right for their gobo selection."
+  [page-x page-y]
+  (let [x-base (* page-x 8)
+        y-base (* page-y 8)]
+    (ct/set-cue! (:cue-grid *show*) (+ x-base 0) (+ y-base 7)
                  (cues/function-cue :torrent-shutter :shutter-open (show/fixtures-named "torrent")))
-    (ct/set-cue! (:cue-grid *show*) 1 15
+    (ct/set-cue! (:cue-grid *show*) (+ x-base 1) (+ y-base 7)
                  (cues/function-cue :torrent-reset :motor-reset (show/fixtures-named "torrent")
                                     :color (create-color :red) :held true))

-    (ct/set-cue! (:cue-grid *show*) 6 15
+    (ct/set-cue! (:cue-grid *show*) (+ x-base 6) (+ y-base 7)
                  (cues/function-cue :t1-focus :focus (show/fixtures-named "torrent-1") :effect-name "Torrent 1 Focus"
                                     :color (create-color :yellow)))
-    (ct/set-cue! (:cue-grid *show*) 7 15
+    (ct/set-cue! (:cue-grid *show*) (+ x-base 7) (+ y-base 7)
                  (cues/function-cue :t2-focus :focus (show/fixtures-named "torrent-2") :effect-name "Torrent 2 Focus"
                                     :color (create-color :yellow)))
-    (ct/set-cue! (:cue-grid *show*) 4 15
+    (ct/set-cue! (:cue-grid *show*) (+ x-base 4) (+ y-base 7)
                  (build-focus-oscillator :t1-focus "Torrent 1 Focus Sine" (show/fixtures-named "torrent-1")))
-    (ct/set-cue! (:cue-grid *show*) 5 15
+    (ct/set-cue! (:cue-grid *show*) (+ x-base 5) (+ y-base 7)
                  (build-focus-oscillator :t2-focus "Torrent 2 Focus Sine" (show/fixtures-named "torrent-2")))
-    (ct/set-cue! (:cue-grid *show*) 6 14
+    (ct/set-cue! (:cue-grid *show*) (+ x-base 6) (+ y-base 6)
                  (cues/function-cue :t1-prism :prism-clockwise (show/fixtures-named "torrent-1") :level 100
                                     :effect-name "T1 Prism Spin CW" :color (create-color :orange)))
-    (ct/set-cue! (:cue-grid *show*) 7 14
+    (ct/set-cue! (:cue-grid *show*) (+ x-base 7) (+ y-base 6)
                  (cues/function-cue :t2-prism :prism-clockwise (show/fixtures-named "torrent-2") :level 100
                                     :effect-name "T2 Prism Spin CW" :color (create-color :orange)))
-    (ct/set-cue! (:cue-grid *show*) 6 13
+    (ct/set-cue! (:cue-grid *show*) (+ x-base 6) (+ y-base 5)
                  (cues/function-cue :t1-prism :prism-in (show/fixtures-named "torrent-1")
                                     :effect-name "T1 Prism In" :color (create-color :orange)))
-    (ct/set-cue! (:cue-grid *show*) 7 13
+    (ct/set-cue! (:cue-grid *show*) (+ x-base 7) (+ y-base 5)
                  (cues/function-cue :t2-prism :prism-in (show/fixtures-named "torrent-2")
                                     :effect-name "T2 Prism In" :color (create-color :orange)))
-    (ct/set-cue! (:cue-grid *show*) 6 12
+    (ct/set-cue! (:cue-grid *show*) (+ x-base 6) (+ y-base 4)
                  (cues/function-cue :t1-prism :prism-counterclockwise (show/fixtures-named "torrent-1")
                                     :effect-name "T1 Prism Spin CCW" :color (create-color :orange)))
-    (ct/set-cue! (:cue-grid *show*) 7 12
+    (ct/set-cue! (:cue-grid *show*) (+ x-base 7) (+ y-base 4)
                  (cues/function-cue :t2-prism :prism-counterclockwise (show/fixtures-named "torrent-2")
                                     :effect-name "T2 Prism Spin CCW" :color (create-color :orange)))
-    (ct/set-cue! (:cue-grid *show*) 6 11
+    (ct/set-cue! (:cue-grid *show*) (+ x-base 6) (+ y-base 3)
                  (cues/function-cue :t1-gobo-fixed :gobo-fixed-clockwise (show/fixtures-named "torrent-1")
                                     :effect-name "T1 Fixed Gobos Swap CW" :color (create-color :blue)))
-    (ct/set-cue! (:cue-grid *show*) 7 11
+    (ct/set-cue! (:cue-grid *show*) (+ x-base 7) (+ y-base 3)
                  (cues/function-cue :t2-gobo-fixed :gobo-fixed-clockwise (show/fixtures-named "torrent-2")
                                     :effect-name "T2 Fixed Gobos Swap CW" :color (create-color :blue)))
-    (ct/set-cue! (:cue-grid *show*) 6 10
+    (ct/set-cue! (:cue-grid *show*) (+ x-base 6) (+ y-base 2)
                  (cues/function-cue :t1-gobo-moving :gobo-moving-clockwise (show/fixtures-named "torrent-1")
                                     :effect-name "T1 Moving Gobos Swap CW" :color (create-color :green)))
-    (ct/set-cue! (:cue-grid *show*) 7 10
+    (ct/set-cue! (:cue-grid *show*) (+ x-base 7) (+ y-base 2)
                  (cues/function-cue :t2-gobo-moving :gobo-moving-clockwise (show/fixtures-named "torrent-2")
                                     :effect-name "T2 Moving Gobos Swap CW" :color (create-color :green)))
-    (ct/set-cue! (:cue-grid *show*) 6 9
+    (ct/set-cue! (:cue-grid *show*) (+ x-base 6) (+ y-base 1)
                  (cues/function-cue :t1-gobo-rotation :gobo-rotation-clockwise (show/fixtures-named "torrent-1")
                                     :effect-name "T1 Spin Gobo CW" :color (create-color :cyan) :level 100))
-    (ct/set-cue! (:cue-grid *show*) 7 9
+    (ct/set-cue! (:cue-grid *show*) (+ x-base 7) (+ y-base 1)
                  (cues/function-cue :t2-gobo-rotation :gobo-rotation-clockwise (show/fixtures-named "torrent-2")
                                     :effect-name "T2 Spin Gobo CW" :color (create-color :cyan) :level 100))
-    (ct/set-cue! (:cue-grid *show*) 6 8
+    (ct/set-cue! (:cue-grid *show*) (+ x-base 6) (+ y-base 0)
                  (cues/function-cue :t1-gobo-rotation :gobo-rotation-counterclockwise (show/fixtures-named "torrent-1")
                                     :effect-name "T1 Spin Gobo CCW" :color (create-color :cyan)))
-    (ct/set-cue! (:cue-grid *show*) 7 8
+    (ct/set-cue! (:cue-grid *show*) (+ x-base 7) (+ y-base 0)
                  (cues/function-cue :t2-gobo-rotation :gobo-rotation-counterclockwise (show/fixtures-named "torrent-2")
                                     :effect-name "T2 Spin Gobo CCW" :color (create-color :cyan)))

-    ;; Some basic moving head chases
-    (let [triangle-phrase (oscillators/build-oscillated-param ; Move back and forth over a phrase
-                           (oscillators/triangle :interval :phrase) :min -90 :max 90)
-          staggered-triangle-bar (params/build-spatial-param ; Bounce over a bar, staggered across grid x
-                                  (show/all-fixtures)
-                                  (fn [head]
-                                    (oscillators/build-oscillated-param
-                                     (oscillators/triangle :interval :bar :phase (x-phase head *show*))
-                                     :min -90 :max 0)))
-          can-can-dir (params/build-direction-param-from-pan-tilt :pan triangle-phrase :tilt staggered-triangle-bar)
-          can-can-p-t (params/build-pan-tilt-param :pan triangle-phrase :tilt staggered-triangle-bar)]
-      (ct/set-cue! (:cue-grid *show*) 0 9
-                   (cues/cue :movement (fn [var-map]
-                                         (move/direction-effect "Can Can" can-can-dir (show/all-fixtures)))))
-      (ct/set-cue! (:cue-grid *show*) 1 9
-                   (cues/cue :movement (fn [var-map]
-                                         (move/pan-tilt-effect "P/T Can Can" can-can-p-t (show/all-fixtures))))))
-
-    ;; A couple snowball cues
-    (ct/set-cue! (:cue-grid *show*) 0 10 (cues/function-cue :sb-pos :beams-fixed (show/fixtures-named "snowball")
-                                                            :effect-name "Snowball Fixed"))
-    (ct/set-cue! (:cue-grid *show*) 1 10 (cues/function-cue :sb-pos :beams-moving (show/fixtures-named "snowball")
-                                                            :effect-name "Snowball Moving"))
-
-    ;; The separate page of specific gobo cues for each Torrent
-    (make-torrent-gobo-cues :t1 (show/fixtures-named "torrent-1") 15 8)
-    (make-torrent-gobo-cues :t2 (show/fixtures-named "torrent-2") 15 12)
-
-    ;; TODO: Write a function to create direction cues, like function cues? Unless macro solves.
-    (ct/set-cue! (:cue-grid *show*) 0 8
-                 (cues/cue :torrent-dir (fn [var-map]
-                                          (move/direction-effect
-                                           "Pan/Tilt"
-                                           (params/build-direction-param-from-pan-tilt :pan (:pan var-map 0.0)
-                                                                                :tilt (:tilt var-map 0.0)
-                                                                                :degrees true)
-                                           (show/all-fixtures)))
-                           :variables [{:key "pan" :name "Pan"
-                                        :min -180.0 :max 180.0 :start 0.0 :centered true :resolution 0.5}
-                                       {:key "tilt" :name "Tilt"
-                                        :min -180.0 :max 180.0 :start 0.0 :centered true :resolution 0.5}]))
-    (ct/set-cue! (:cue-grid *show*) 1 8
-                 (cues/cue :torrent-dir (fn [var-map]
-                                          (move/aim-effect
-                                           "Aim"
-                                           (params/build-aim-param :x (:x var-map 0.0)
-                                                                   :y (:y var-map 0.0)
-                                                                   :z (:z var-map 1.0))
-                                           (show/all-fixtures)))
-                           :variables [{:key "x" :name "X"
-                                        :min -20.0 :max 20.0 :start 0.0 :centered true :resolution 0.05}
-                                       {:key "z" :name "Z"
-                                        :min -20.0 :max 20.0 :start 0.0 :centered true :resolution 0.05}
-                                       {:key "y" :name "Y"
-                                        :min 0.0 :max 20.0 :start 0.0 :centered false :resolution 0.05}]))
-    (ct/set-cue! (:cue-grid *show*) 3 8
-                 (cues/function-cue :blade-speed :movement-speed (show/fixtures-named "blade")
-                                    :color :purple :effect-name "Slow Blades"))
-
-    ;; Some fades
-    (ct/set-cue! (:cue-grid *show*) 0 12
-                 (cues/cue :color-fade (fn [var-map]
-                                         (fx/fade "Color Fade"
-                                                  (global-color-effect :red :include-color-wheels? true)
-                                                  (global-color-effect :green :include-color-wheels? true)
-                                                  (params/bind-keyword-param (:phase var-map 0) Number 0)))
-                           :variables [{:key "phase" :min 0.0 :max 1.0 :start 0.0 :name "Fade"}]
-                           :color :yellow))
-
-    (ct/set-cue!
-     (:cue-grid *show*) 1 12
-     (cues/cue :fade-test (fn [var-map]
-                            (fx/fade "Fade Test"
-                                     (fx/blank)
-                                     (global-color-effect :blue :include-color-wheels? true)
-                                     (params/bind-keyword-param (:phase var-map 0) Number 0)))
-               :variables [{:key "phase" :min 0.0 :max 1.0 :start 0.0 :name "Fade"}]
-               :color :cyan))
-
-    (ct/set-cue!
-     (:cue-grid *show*) 2 12
-     (cues/cue :fade-test-2 (fn [var-map]
-                              (fx/fade "Fade Test 2"
-                                       (move/direction-effect
-                                        "p/t" (params/build-direction-param-from-pan-tilt :pan 0 :tilt 0)
-                                        (show/fixtures-named "torrent"))
-                                       (move/direction-effect
-                                        "p/t" (params/build-direction-param-from-pan-tilt :pan 0 :tilt 0)
-                                        (show/fixtures-named "blade"))
-                                       (params/bind-keyword-param (:phase var-map 0) Number 0)))
-               :variables [{:key "phase" :min 0.0 :max 1.0 :start 0.0 :name "Fade"}]
-               :color :red))
-
-    (ct/set-cue!
-     (:cue-grid *show*) 3 12
-     (cues/cue :fade-test-3 (fn [var-map]
-                              (fx/fade "Fade Test P/T"
-                                       (move/pan-tilt-effect
-                                        "p/t" (params/build-pan-tilt-param :pan 0 :tilt 0)
-                                        (show/fixtures-named "torrent"))
-                                       (move/pan-tilt-effect
-                                        "p/t" (params/build-pan-tilt-param :pan 0 :tilt 0)
-                                        (show/fixtures-named "blade"))
-                                       (params/bind-keyword-param (:phase var-map 0) Number 0)))
-               :variables [{:key "phase" :min 0.0 :max 1.0 :start 0.0 :name "Fade"}]
-               :color :orange))
-
-    ;; Some chases
-    (ct/set-cue!
-     (:cue-grid *show*) 0 13
-     (cues/cue :chase (fn [var-map]
-                        (fx/chase "Chase Test"
-                                  [(global-color-effect :red :include-color-wheels? true)
-                                   (global-color-effect :green :fixtures (show/fixtures-named "hex"))
-                                   (global-color-effect :blue :include-color-wheels? true)]
-                                  (params/bind-keyword-param (:position var-map 0) Number 0)
-                                  :beyond :bounce)
-                        )
-               :variables [{:key "position" :min -0.5 :max 10.5 :start 0.0 :name "Position"}]
-               :color :purple))
-
-    ;; Set up an initial value for our step parameter
-    (reset! step-param (params/build-step-param :fade-fraction 0.3 :fade-curve :sine))
-
-    (ct/set-cue!
-     (:cue-grid *show*) 1 13
-     (cues/cue :chase (fn [var-map]
-                        (fx/chase "Chase Test 2"
-                                  [(global-color-effect :red :fixtures (show/fixtures-named "hex"))
-                                   (global-color-effect :green :fixtures (show/fixtures-named "blade"))
-                                   (global-color-effect :blue :fixtures (show/fixtures-named "hex"))
-                                   (global-color-effect :white :fixtures (show/all-fixtures))]
-                                  @step-param :beyond :loop))
-               :color :magenta))
-
     ;; Some compound cues
-    (ct/set-cue! (:cue-grid *show*) 8 0
+    (ct/set-cue! (:cue-grid *show*) (+ x-base 0) (+ y-base 0)
                  (cues/cue :star-swirl (fn [_] (cues/compound-cues-effect
                                                 "Star Swirl" *show* [[8 12]
                                                                      [10 9]
                                                                      [6 15 {:level 60}]
                                                                      [6 8 {:level 25}]]))))
-    ;; Some color cycle chases
-    (ct/set-cue! (:cue-grid *show*) 8 1
-                 (cues/cue :all-color (fn [_] (fun/iris-out-color-cycle-chase (show/all-fixtures)))))
-    (ct/set-cue! (:cue-grid *show*) 9 1
-                 (cues/cue :all-color (fn [_] (fun/wipe-right-color-cycle-chase
-                                           (show/all-fixtures) :transition-phase-function rhythm/snapshot-bar-phase))))
-    (ct/set-cue! (:cue-grid *show*) 10 1
-                 (cues/cue :all-color (fn [_] (fun/wipe-right-color-cycle-chase
-                                               (show/all-fixtures)
-                                               :color-index-function rhythm/snapshot-beat-within-phrase
-                                               :transition-phase-function rhythm/snapshot-beat-phase
-                                               :effect-name "Wipe Right Beat"))))
-
-    ;; Some cues to show the Hypnotic RGB Laser
-    (ct/set-cue! (:cue-grid *show*) 8 3
+
+    (make-torrent-gobo-cues :t1 (show/fixtures-named "torrent-1") (+ y-base 7) (+ x-base 8))
+    (make-torrent-gobo-cues :t2 (show/fixtures-named "torrent-2") (+ y-base 7) (+ x-base 12))))
+
+(defn make-ambient-cues
+  "Create a page of cues for controlling lasers, and ambient effects
+  like the H2O LED and black light."
+  [page-x page-y]
+  (let [x-base (* page-x 8)
+        y-base (* page-y 8)]
+
+    ;; Various ultraviolet options
+    (ct/set-cue! (:cue-grid *show*) (+ x-base 0) (+ y-base 0)
+                 (cues/cue :uv (fn [_]
+                                 (fx/scene "All UV"
+                                           (dimmer-effect 255 (show/fixtures-named :eco-uv))
+                                           (chan-fx/function-effect "Hex UV" :uv 100 (show/fixtures-named "hex"))))
+                           :color :purple))
+
+    (ct/set-cue! (:cue-grid *show*) (+ x-base 1) (+ y-base 0)
+                 (cues/cue :eco-uv (fn [_] (dimmer-effect 255 (show/fixtures-named :eco-uv) :effect-name "Eco UV Bar"))
+                           :color :purple :end-keys [:uv]))1
+
+    (ct/set-cue! (:cue-grid *show*) (+ x-base 2) (+ y-base 0)
+                 (cues/function-cue :hex-uv :uv (show/fixtures-named "hex")
+                                    :level 100 :color :Purple :effect-name "Hex UV"
+                                    :end-keys [:uv]))
+
+    ;; Turn on the H2O LED
+    (ct/set-cue! (:cue-grid *show*) (+ x-base 7) (+ y-base 0)
+                 (cues/cue :h2o-led (fn [_] (dimmer-effect 255 (show/fixtures-named :h2o-led)
+                                                           :effect-name "H2O LED"))))
+
+    ;; Control the Hypnotic RGB Laser
+    (ct/set-cue! (:cue-grid *show*) (+ x-base 0) (+ y-base 3)
                  (cues/function-cue :hypnotic-beam :beam-red (show/fixtures-named "hyp-rgb")
                                     :color :red :effect-name "Hypnotic Red"))
-    (ct/set-cue! (:cue-grid *show*) 9 3
+    (ct/set-cue! (:cue-grid *show*) (+ x-base 1) (+ y-base 3)
                  (cues/function-cue :hypnotic-beam :beam-green (show/fixtures-named "hyp-rgb")
                                     :color :green :effect-name "Hypnotic Green"))
-    (ct/set-cue! (:cue-grid *show*) 10 3
+    (ct/set-cue! (:cue-grid *show*) (+ x-base 2) (+ y-base 3)
                  (cues/function-cue :hypnotic-beam :beam-blue (show/fixtures-named "hyp-rgb")
                                     :color :blue :effect-name "Hypnotic Blue"))
-    (ct/set-cue! (:cue-grid *show*) 11 3
+    (ct/set-cue! (:cue-grid *show*) (+ x-base 3) (+ y-base 3)
                  (cues/function-cue :hypnotic-beam :beam-red-green (show/fixtures-named "hyp-rgb")
                                     :color :yellow :effect-name "Hypnotic Red Green"))
-    (ct/set-cue! (:cue-grid *show*) 12 3
+    (ct/set-cue! (:cue-grid *show*) (+ x-base 4) (+ y-base 3)
                  (cues/function-cue :hypnotic-beam :beam-red-blue (show/fixtures-named "hyp-rgb")
                                     :color :purple :effect-name "Hypnotic Red Blue"))
-    (ct/set-cue! (:cue-grid *show*) 13 3
+    (ct/set-cue! (:cue-grid *show*) (+ x-base 5) (+ y-base 3)
                  (cues/function-cue :hypnotic-beam :beam-green-blue (show/fixtures-named "hyp-rgb")
                                     :color :cyan :effect-name "Hypnotic Green Blue"))
-    (ct/set-cue! (:cue-grid *show*) 14 3
+    (ct/set-cue! (:cue-grid *show*) (+ x-base 6) (+ y-base 3)
                  (cues/function-cue :hypnotic-beam :beam-red-green-blue (show/fixtures-named "hyp-rgb")
                                     :color :white :effect-name "Hypnotic Red Green Blue"))
-    (ct/set-cue! (:cue-grid *show*) 15 3
+    (ct/set-cue! (:cue-grid *show*) (+ x-base 7) (+ y-base 3)
                  (cues/function-cue :hypnotic-beam :beam-all-random (show/fixtures-named "hyp-rgb")
                                     :color :white :effect-name "Hypnotic Random"))
-    (ct/set-cue! (:cue-grid *show*) 14 4
+    (ct/set-cue! (:cue-grid *show*) (+ x-base 6) (+ y-base 4)
                  (cues/function-cue :hypnotic-spin :beams-ccw (show/fixtures-named "hyp-rgb")
                                     :color :cyan :effect-name "Hypnotic Rotate CCW" :level 50))
-    (ct/set-cue! (:cue-grid *show*) 15 4
+    (ct/set-cue! (:cue-grid *show*) (+ x-base 7) (+ y-base 4)
                  (cues/function-cue :hypnotic-spin :beams-cw (show/fixtures-named "hyp-rgb")
-                                    :color :cyan :effect-name "Hypnotic Rotate Clockwise" :level 50))
-
-    ;; What else?
-    ;; TODO: Refine this and make a cue
-    #_(show/add-effect! :torrent-focus (afterglow.effects.channel/function-effect
-                                        "F" :focus (oscillators/build-oscillated-param (oscillators/sine :interval :bar)
-                                                                                :min 20 :max 200)
-                                        (show/fixtures-named "torrent")))))
+                                    :color :cyan :effect-name "Hypnotic Rotate Clockwise" :level 50))))
+
+(defn make-cues
+  "Create a bunch of example cues for experimentation."
+  []
+  (make-main-color-dimmer-cues 0 0)  ; Creates a sigle 8x8 page at the origin
+  (make-torrent-cues 0 2)  ; Creates 2 8x8 pages: two pages up from the origin, and the next page to the right
+  (make-ambient-cues 1 0)  ; Creates a single 8x8 page to the right of the origin
+
+  ;; Not sure what to do with the rest of this yet! Move or discard...
+  ;; For now they are hardcoded to appear on the page above the origin.
+
+  ;; Some basic moving head chases
+  (let [triangle-phrase (oscillators/build-oscillated-param ; Move back and forth over a phrase
+                         (oscillators/triangle :interval :phrase) :min -90 :max 90)
+        staggered-triangle-bar (params/build-spatial-param ; Bounce over a bar, staggered across grid x
+                                (show/all-fixtures)
+                                (fn [head]
+                                  (oscillators/build-oscillated-param
+                                   (oscillators/triangle :interval :bar :phase (x-phase head *show*))
+                                   :min -90 :max 0)))
+        can-can-dir (params/build-direction-param-from-pan-tilt :pan triangle-phrase :tilt staggered-triangle-bar)
+        can-can-p-t (params/build-pan-tilt-param :pan triangle-phrase :tilt staggered-triangle-bar)]
+    (ct/set-cue! (:cue-grid *show*) 0 9
+                 (cues/cue :movement (fn [var-map]
+                                       (move/direction-effect "Can Can" can-can-dir (show/all-fixtures)))))
+    (ct/set-cue! (:cue-grid *show*) 1 9
+                 (cues/cue :movement (fn [var-map]
+                                       (move/pan-tilt-effect "P/T Can Can" can-can-p-t (show/all-fixtures))))))
+
+  ;; A couple snowball cues
+  (ct/set-cue! (:cue-grid *show*) 0 10 (cues/function-cue :sb-pos :beams-fixed (show/fixtures-named "snowball")
+                                                          :effect-name "Snowball Fixed"))
+  (ct/set-cue! (:cue-grid *show*) 1 10 (cues/function-cue :sb-pos :beams-moving (show/fixtures-named "snowball")
+                                                          :effect-name "Snowball Moving"))
+
+  ;; TODO: Write a function to create direction cues, like function cues? Unless macro solves.
+  (ct/set-cue! (:cue-grid *show*) 0 8
+               (cues/cue :torrent-dir (fn [var-map]
+                                        (move/direction-effect
+                                         "Pan/Tilt"
+                                         (params/build-direction-param-from-pan-tilt :pan (:pan var-map 0.0)
+                                                                                :tilt (:tilt var-map 0.0)
+                                                                                :degrees true)
+                                         (show/all-fixtures)))
+                         :variables [{:key "pan" :name "Pan"
+                                      :min -180.0 :max 180.0 :start 0.0 :centered true :resolution 0.5}
+                                     {:key "tilt" :name "Tilt"
+                                      :min -180.0 :max 180.0 :start 0.0 :centered true :resolution 0.5}]))
+  (ct/set-cue! (:cue-grid *show*) 1 8
+               (cues/cue :torrent-dir (fn [var-map]
+                                        (move/aim-effect
+                                         "Aim"
+                                         (params/build-aim-param :x (:x var-map 0.0)
+                                                                 :y (:y var-map 0.0)
+                                                                 :z (:z var-map 1.0))
+                                         (show/all-fixtures)))
+                         :variables [{:key "x" :name "X"
+                                      :min -20.0 :max 20.0 :start 0.0 :centered true :resolution 0.05}
+                                     {:key "z" :name "Z"
+                                      :min -20.0 :max 20.0 :start 0.0 :centered true :resolution 0.05}
+                                     {:key "y" :name "Y"
+                                      :min 0.0 :max 20.0 :start 0.0 :centered false :resolution 0.05}]))
+  (ct/set-cue! (:cue-grid *show*) 3 8
+               (cues/function-cue :blade-speed :movement-speed (show/fixtures-named "blade")
+                                  :color :purple :effect-name "Slow Blades"))
+
+  ;; Some fades
+  (ct/set-cue! (:cue-grid *show*) 0 12
+               (cues/cue :color-fade (fn [var-map]
+                                       (fx/fade "Color Fade"
+                                                (global-color-effect :red :include-color-wheels? true)
+                                                (global-color-effect :green :include-color-wheels? true)
+                                                (params/bind-keyword-param (:phase var-map 0) Number 0)))
+                         :variables [{:key "phase" :min 0.0 :max 1.0 :start 0.0 :name "Fade"}]
+                         :color :yellow))
+
+  (ct/set-cue!
+   (:cue-grid *show*) 1 12
+   (cues/cue :fade-test (fn [var-map]
+                          (fx/fade "Fade Test"
+                                   (fx/blank)
+                                   (global-color-effect :blue :include-color-wheels? true)
+                                   (params/bind-keyword-param (:phase var-map 0) Number 0)))
+             :variables [{:key "phase" :min 0.0 :max 1.0 :start 0.0 :name "Fade"}]
+             :color :cyan))
+
+  (ct/set-cue!
+   (:cue-grid *show*) 2 12
+   (cues/cue :fade-test-2 (fn [var-map]
+                            (fx/fade "Fade Test 2"
+                                     (move/direction-effect
+                                      "p/t" (params/build-direction-param-from-pan-tilt :pan 0 :tilt 0)
+                                      (show/fixtures-named "torrent"))
+                                     (move/direction-effect
+                                      "p/t" (params/build-direction-param-from-pan-tilt :pan 0 :tilt 0)
+                                      (show/fixtures-named "blade"))
+                                     (params/bind-keyword-param (:phase var-map 0) Number 0)))
+             :variables [{:key "phase" :min 0.0 :max 1.0 :start 0.0 :name "Fade"}]
+             :color :red))
+
+  (ct/set-cue!
+   (:cue-grid *show*) 3 12
+   (cues/cue :fade-test-3 (fn [var-map]
+                            (fx/fade "Fade Test P/T"
+                                     (move/pan-tilt-effect
+                                      "p/t" (params/build-pan-tilt-param :pan 0 :tilt 0)
+                                      (show/fixtures-named "torrent"))
+                                     (move/pan-tilt-effect
+                                      "p/t" (params/build-pan-tilt-param :pan 0 :tilt 0)
+                                      (show/fixtures-named "blade"))
+                                     (params/bind-keyword-param (:phase var-map 0) Number 0)))
+             :variables [{:key "phase" :min 0.0 :max 1.0 :start 0.0 :name "Fade"}]
+             :color :orange))
+
+  ;; Some chases
+  (ct/set-cue!
+   (:cue-grid *show*) 0 13
+   (cues/cue :chase (fn [var-map]
+                      (fx/chase "Chase Test"
+                                [(global-color-effect :red :include-color-wheels? true)
+                                 (global-color-effect :green :fixtures (show/fixtures-named "hex"))
+                                 (global-color-effect :blue :include-color-wheels? true)]
+                                (params/bind-keyword-param (:position var-map 0) Number 0)
+                                :beyond :bounce)
+                      )
+             :variables [{:key "position" :min -0.5 :max 10.5 :start 0.0 :name "Position"}]
+             :color :purple))
+
+  ;; Set up an initial value for our step parameter
+  (reset! step-param (params/build-step-param :fade-fraction 0.3 :fade-curve :sine))
+
+  (ct/set-cue!
+   (:cue-grid *show*) 1 13
+   (cues/cue :chase (fn [var-map]
+                      (fx/chase "Chase Test 2"
+                                [(global-color-effect :red :fixtures (show/fixtures-named "hex"))
+                                 (global-color-effect :green :fixtures (show/fixtures-named "blade"))
+                                 (global-color-effect :blue :fixtures (show/fixtures-named "hex"))
+                                 (global-color-effect :white :fixtures (show/all-fixtures))]
+                                @step-param :beyond :loop))
+             :color :magenta))
+
+  ;; Some color cycle chases
+  (ct/set-cue! (:cue-grid *show*) 0 15
+               (cues/cue :all-color (fn [_] (fun/iris-out-color-cycle-chase (show/all-fixtures)))))
+  (ct/set-cue! (:cue-grid *show*) 1 15
+               (cues/cue :all-color (fn [_] (fun/wipe-right-color-cycle-chase (show/all-fixtures)
+                                             :transition-phase-function rhythm/snapshot-bar-phase))))
+  (ct/set-cue! (:cue-grid *show*) 2 15
+               (cues/cue :all-color (fn [_] (fun/wipe-right-color-cycle-chase
+                                             (show/all-fixtures)
+                                             :color-index-function rhythm/snapshot-beat-within-phrase
+                                             :transition-phase-function rhythm/snapshot-beat-phase
+                                             :effect-name "Wipe Right Beat")))))

 (defn use-push
   "A trivial reminder of how to connect the Ableton Push to run the


Fix variable name.

Fix variable name.

--- src/afterglow/examples.clj
+++ src/afterglow/examples.clj
@@ -362,7 +362,7 @@
                                         :type :integer}]))
     (ct/set-cue! (:cue-grid *show*) 3 1  ; Desaturate the rainbow as each beat progresses
                  (cues/cue :color (fn [_] (global-color-effect
-                                           (params/build-color-param :s sat-beat :l 50 :h hue-gradient
+                                           (params/build-color-param :s desat-beat :l 50 :h hue-gradient
                                                                      :adjust-hue hue-bar)))
                            :short-name "Rainbow Pulse"))


commit date -> author date

commit date -> author date

--- src-clj/acha/git_parser.clj
+++ src-clj/acha/git_parser.clj
@@ -118,7 +118,7 @@
         commit-tree (.treeIterator df rev-commit)
         diffs (.scan df parent-tree commit-tree)
         ident (.getAuthorIdent rev-commit)
-        time (-> (.getCommitTime rev-commit) (* 1000) java.util.Date.)
+        time (-> (.getTime (.getWhen ident)) (* 1000) java.util.Date.)
         message (-> (.getFullMessage rev-commit) str string/trim)]
     (merge {:id (.getName rev-commit)
             :author (.getName ident)


Connect to database lazily

Connect to database lazily

--- src/territory_bro/db.clj
+++ src/territory_bro/db.clj
@@ -6,10 +6,10 @@

 (ns ^{:resource-deps ["sql/queries.sql"]} territory-bro.db
   (:require [cheshire.core :refer [generate-string parse-string]]
-            [clojure.data.json :as json]
             [clojure.java.jdbc :as jdbc]
             [clojure.tools.logging :as log]
             [conman.core :as conman]
+            [hikari-cp.core :as hikari-cp]
             [mount.core :as mount]
             [ring.util.codec :refer [form-decode]]
             [territory-bro.config :refer [env]]
@@ -25,12 +25,20 @@
 ; See hikari-cp.core/default-datasource-options for available options.
 (def datasource-options {:idle-timeout (-> (Duration/ofSeconds 60) (.toMillis))
                          :minimum-idle 0
-                         :maximum-pool-size 2})
+                         :maximum-pool-size 2
+                         :initialization-fail-timeout -1})
+
+(defn my-connect! [pool-spec]
+  ;; XXX: the hikari-cp wrapper doesn't support setInitializationFailTimeout
+  (let [{:keys [initialization-fail-timeout]} pool-spec
+        config (hikari-cp/datasource-config (conman/make-config pool-spec))]
+    (when initialization-fail-timeout (.setInitializationFailTimeout config initialization-fail-timeout))
+    {:datasource (HikariDataSource. config)}))

 (defn connect! [database-url]
   (log/info "Connect" database-url)
-  (conman/connect! (merge datasource-options
-                          {:jdbc-url database-url})))
+  (my-connect! (merge datasource-options
+                      {:jdbc-url database-url})))

 (defn disconnect! [connection]
   (log/info "Disconnect" (if-let [ds (:datasource connection)]


Render entities.

Render entities.

--- src/kixi/hecuba/api/entities.clj
+++ src/kixi/hecuba/api/entities.clj
@@ -366,7 +366,7 @@
     (allowed-all?* programmes projects roles request-method params store)))

 (defn index-handle-ok [store ctx]
-  (:entities ctx))
+  (util/render-items (:entities ctx)))

 (defmulti malformed? content-type-from-context)


properly return decision on index-exists?

--- src/kixi/hecuba/api/profiles.clj
+++ src/kixi/hecuba/api/profiles.clj
@@ -73,7 +73,9 @@
       (case method
         :post (not (nil? entity))
         :get (let [items (db/execute session (hayt/select :profiles (hayt/where [[= :entity_id entity_id]])))]
-               {::items items})))))
+               (if (empty? items)
+                 false
+                 [true {::items items}]))))))

 (defn add-profile-keys [& pairs]
   (->> pairs


Generalise or reduction.

Generalise or reduction.

--- src/smallex/reductions.clj
+++ src/smallex/reductions.clj
@@ -220,14 +220,19 @@
   "Reduces an `or` whenever possible."
   [or-op]
   (cond (every? #(= :char-set (:type %)) (:args or-op))
-        ;; Not general enough. (or [ax] expr [by] "c") could be reduced to
-        ;; (or [abcxy] expr).
         {:type :char-set,
          :value (apply set/union (map :value (:args or-op)))}
         (= 1 (count (:args or-op)))
         (first (:args or-op))
         :else
-        or-op))
+        (let [grouped (group-by (comp :type meta) (:args or-op))
+              char-sets (apply set/union (map :value (:char-set grouped)))]
+          {:type :string ;; <- exists at least one :string
+           :value (vec
+                   (cond-> (:string grouped)
+                           (seq char-sets)
+                           (conj {:type :char-set
+                                  :value char-sets})))})))

 (defn- expand-opt
   "Expands (opt x) to (or \"\" x)."


Name the white bit creation strategy.

Name the white bit creation strategy.

--- src/klangmeister/synthesis.cljs
+++ src/klangmeister/synthesis.cljs
@@ -88,7 +88,9 @@
         (-> .-buffer (set! buffer))
         (.start at)))))

-(def white-noise (partial noise #(-> (js/Math.random) (* 2.0) dec)))
+(def white-noise
+  (let [white #(-> (js/Math.random) (* 2.0) (- 1.0))]
+    (partial noise white)))

 ; Oscillators


Only compute hash for merging two kv pairs once

--- src/main/cljs/lean_map/core.cljs
+++ src/main/cljs/lean_map/core.cljs
@@ -69,19 +69,18 @@
       (array-copy arr (+ idx-new 2) dst (inc idx-new) (- (alength arr) idx-new 2))
       (BitmapIndexedNode. e (bit-xor datamap bit) (bit-or nodemap bit) dst)))

-  (merge-two-kv-pairs [inode medit shift key1 val1 key2hash key2 val2]
-    (let [key1hash (hash key1)]
-      (if (and (< 32 shift) (== key1hash key2hash))
-        (HashCollisionNode. medit key1hash 2 (array key1 val1 key2 val2))
-        (let [mask1 (mask key1hash shift)
-              mask2 (mask key2hash shift)]
-          (if (== mask1 mask2)
-            (let [new-node (.merge-two-kv-pairs inode medit (+ shift 5) key1 val1 key2hash key2 val2)]
-              (BitmapIndexedNode. medit 0 (bitpos key1hash shift) (array new-node)))
-            (let [new-datamap (bit-or (bitpos key1hash shift) (bitpos key2hash shift))]
-              (if (< mask1 mask2)
-                (BitmapIndexedNode. medit new-datamap 0 (array key1 val1 key2 val2))
-                (BitmapIndexedNode. medit new-datamap 0 (array key2 val2 key1 val1)))))))))
+  (merge-two-kv-pairs [inode medit shift key1hash key1 val1 key2hash key2 val2]
+    (if (and (< 32 shift) (== key1hash key2hash))
+      (HashCollisionNode. medit key1hash 2 (array key1 val1 key2 val2))
+      (let [mask1 (mask key1hash shift)
+            mask2 (mask key2hash shift)]
+        (if (== mask1 mask2)
+          (let [new-node (.merge-two-kv-pairs inode medit (+ shift 5) key1hash key1 val1 key2hash key2 val2)]
+            (BitmapIndexedNode. medit 0 (bitpos key1hash shift) (array new-node)))
+          (let [new-datamap (bit-or (bitpos key1hash shift) (bitpos key2hash shift))]
+            (if (< mask1 mask2)
+              (BitmapIndexedNode. medit new-datamap 0 (array key1 val1 key2 val2))
+              (BitmapIndexedNode. medit new-datamap 0 (array key2 val2 key1 val1))))))))

   (inode-seq [inode]
     (let [nodes (make-array 7)
@@ -92,8 +91,8 @@
         (create-inode-seq arr 0 nodes cursors-lengths 0 0)
         (NodeSeq. nil arr 0 nodes cursors-lengths 0 (dec (.data-arity inode)) nil))))

-  (inode-assoc [inode aedit shift hash key val added-leaf?]
-    (let [bit (bitpos hash shift)]
+  (inode-assoc [inode aedit shift keyhash key val added-leaf?]
+    (let [bit (bitpos keyhash shift)]
       (cond
         (not (zero? (bit-and datamap bit)))
         (let [idx (bitmap-indexed-node-index datamap bit)
@@ -101,13 +100,13 @@
           (if (key-test k key)
             (.copy-and-set inode aedit (inc (* 2 idx)) val)
             (let [v (aget arr (inc (* 2 idx)))
-                  new-node (.merge-two-kv-pairs inode aedit (+ shift 5) k v hash key val)]
+                  new-node (.merge-two-kv-pairs inode aedit (+ shift 5) (hash k) k v keyhash key val)]
               (set! (.-val added-leaf?) true)
               (.copy-and-migrate-to-node inode aedit bit new-node))))
         (not (zero? (bit-and nodemap bit)))
         (let [node-idx (.node-at inode bit)
               sub-node (aget arr node-idx)
-              sub-node-new (.inode-assoc sub-node aedit (+ shift 5) hash key val added-leaf?)]
+              sub-node-new (.inode-assoc sub-node aedit (+ shift 5) keyhash key val added-leaf?)]
           (if (identical? sub-node sub-node-new)
             inode
             (.copy-and-set inode aedit node-idx sub-node-new)))


fixed bug with rule evaluation

fixed bug with rule evaluation

--- server/src/gratefulplace/db/transform.clj
+++ server/src/gratefulplace/db/transform.clj
@@ -3,14 +3,14 @@

 (declare rules transform-entity)

-(defn one
+(defmacro one
   [ref-fn rules]
-  #(transform-entity rules (ref-fn %)))
+  `#(transform-entity ~rules (~ref-fn %)))

-(defn many
+(defmacro many
   [remote-key rules]
-  (fn [ent] (map #(transform-entity rules %)
-                (db/all remote-key [remote-key (:db/id ent)]))))
+  `(fn [ent#] (map #(transform-entity ~rules %)
+                 (db/all ~remote-key [~remote-key (:db/id ent#)]))))

 (defn ref-count
   [ref-attr]


Fix bug on deftest macro

Fix bug on deftest macro

--- src/buster_cljs/macros.clj
+++ src/buster_cljs/macros.clj
@@ -14,9 +14,9 @@
    `describe' function, is just here for compatibility with the
    clojure.test library"
   [test-title & body]
-  `(if (and (goog.isDefAndNotNull "window")
-            (not (goog.isDefAndNotNull "window.buster"))
-            (goog.isDefAndNotNull "window.buster_cljs_drop_test_on_missing_buster"))
+  `(if (and (goog.isDefAndNotNull js/window)
+            (not (goog.isDefAndNotNull js/window.buster))
+            (goog.isDefAndNotNull js/window.buster_cljs_drop_test_on_missing_buster))
      nil
      ;; else
      (describe ~(str/replace (clojure.core/name test-title) #"-" " ") ~@body)))


add usage messages for clojars tasks

add usage messages for clojars tasks

--- src/cake/tasks/clojars.clj
+++ src/cake/tasks/clojars.clj
@@ -105,7 +105,7 @@
 	deps-seq (partition 3 (for [x (xml-seq deps-xml)
 				    :when (or (= (:tag x) :artifactId)
 					      (= (:tag x) :groupId)
-					      (= (:tag x) :version))]
+					      (= (:tag x) :version))]
 				(hash-map (:tag x) (first (:content x)))))]
     (into #{} (for [v deps-seq] (apply merge v)))
     (map :content (:content (first deps-xml)))))
@@ -133,27 +133,40 @@
 	 (print-library-dependencies library-name version)))))

 (deftask dependencies
-  "Look up the dependencies on a library on clojars."
+  "Look up the dependencies of a library on clojars."
   {[library-name version] :dependencies}
-  (print-library-dependencies library-name version))
+  (if (nil? library-name)
+    (println "Usage: cake dependencies <library-name> [version]")
+    (print-library-dependencies library-name version)))

 (deftask describe
   "Describe a library on clojars."
-  (apply clojars-describe (:describe *opts*)))
+  {[library-name] :describe}
+  (if (nil? library-name)
+    (println "Usage: cake describe <library-name>")
+    (clojars-describe library-name)))

 (deftask versions
   "List all available versions of a library on clojars."
   {[library-name] :versions}
-  (clojars-versions library-name))
+  (if (nil? library-name)
+    (println "Usage: cake versions <library-name>")
+    (clojars-versions library-name)))

 (deftask search
   "Search clojars.org for libraries."
-  {term :search}
-  (->> term (s/join " ") clojars-search))
+  {terms :search}
+  (if (nil? terms)
+    (println "Usage: cake search <terms>")
+    (->> terms (s/join " ") clojars-search)))

 (deftask add-dep
   "Install a library from into your project."
   "The library will be added to the :deps or :dependencies vector in your project.clj.
    If you pass the --dev option, it'll be added to :dev-deps or :dev-dependencies."
-  {args :add-dep dev :dev}
-  (apply clojars-install (conj args dev)))+  {[library-name version] :add-dep [dev] :dev}
+  (if (nil? library-name)
+    (println "Usage: cake add-dep <library-name> [version] [--dev]")
+    (if version
+      (clojars-install library-name version dev)
+      (clojars-install library-name dev))))


Use manifold deferred `success-deferred` constructor insead of `future`.

--- src/cats/labs/manifold.clj
+++ src/cats/labs/manifold.clj
@@ -56,7 +56,7 @@

     p/Applicative
     (-pure [_ v]
-      (d/future v))
+      (d/success-deferred v))

     (-fapply [mn af av]
       (d/chain (d/zip' af av)
@@ -65,7 +65,7 @@

     p/Monad
     (-mreturn [_ v]
-      (d/future v))
+      (d/success-deferred v))

     (-mbind [it mv f]
       (d/chain mv (fn [v]


resurrect search threads when replying

resurrect search threads when replying

--- src/chat/client/store.cljs
+++ src/chat/client/store.cljs
@@ -68,9 +68,12 @@

 (defn- maybe-create-thread! [thread-id]
   (when-not (get-in @app-state [:threads thread-id])
-    (transact! [:threads thread-id] (constantly {:id thread-id
-                                                 :messages []
-                                                 :tag-ids #{}}))))
+    (if-let [thread (get-in @app-state [:search-results thread-id])]
+      (do (transact! [:threads thread-id] (constantly thread))
+          (transact! [:search-results] #(dissoc % thread-id)))
+      (transact! [:threads thread-id] (constantly {:id thread-id
+                                                   :messages []
+                                                   :tag-ids #{}})))))

 (defn add-message! [message]
   (maybe-create-thread! (message :thread-id))


don't throw double exceptions on error

don't throw double exceptions on error

--- src/main/clojure/com/xebia/visualreview/middleware.clj
+++ src/main/clojure/com/xebia/visualreview/middleware.clj
@@ -36,9 +36,9 @@
       (try
         (handler (assoc req :tx-conn conn))
         (catch SQLException e
-          (timbre/log :error e "SQLException caught.")
+          (timbre/log :error "SQLException caught.")
           (throw e))
         (catch Exception e
-          (timbre/log :error e "Exception occured whilst inside transaction. Transaction was rolled back.")
+          (timbre/log :error "Exception occured whilst inside transaction. Transaction was rolled back.")
           (j/db-set-rollback-only! conn)
           (throw e))))))


make login a form, so hitting enter works

--- src/chat/client/views.cljs
+++ src/chat/client/views.cljs
@@ -25,7 +25,16 @@
        :error false})
     om/IRenderState
     (render-state [_ state]
-      (dom/div #js {:className "login"}
+      (dom/form #js {:className "login"
+                     :onSubmit (fn [e]
+                                 (.preventDefault e)
+                                 (dispatch! :auth
+                                            {:email (state :email)
+                                             :password (state :password)
+                                             :on-error
+                                             (fn []
+                                               (om/set-state! owner :error true))})
+                                 )}
         (when (state :error)
           (dom/div #js {:className "error"}
             "Bad credentials, please try again"))
@@ -39,15 +48,7 @@
                :type "password"
                :value (state :password)
                :onChange (fn [e] (om/set-state! owner :password (.. e -target -value)))})
-        (dom/button
-          #js {:onClick (fn [e]
-                          (dispatch! :auth
-                                     {:email (state :email)
-                                      :password (state :password)
-                                      :on-error
-                                      (fn []
-                                        (om/set-state! owner :error true))}))}
-          "Let's do this!")))))
+        (dom/button nil "Let's do this!")))))

 (defn main-view [data owner]
   (reify