Rearrange code

Rearrange code

--- src/clojure_fabric/user.clj
+++ src/clojure_fabric/user.clj
@@ -37,7 +37,8 @@
             [clojure-fabric.core :as core]
             [clojure-fabric.crypto-suite :as crypto-suite]
             [clojure-fabric.proto :as proto]
-            [clojure.java.io :as io])
+            [clojure.java.io :as io]
+            [clojure-fabric.event-hub :as event-hub])
   (:import com.google.protobuf.ByteString
            [java.io ByteArrayOutputStream File FileInputStream]
            [org.apache.commons.compress.archivers.tar TarArchiveEntry TarArchiveOutputStream]
@@ -48,57 +49,6 @@
 (defn ca-user?
   [user]
   (not (nil? (:ca-location user))))
-
-(defn new-user!
-  [{:keys [msp-id name]
-    :as args}]
-  ;; roles - client, auditor
-  ;; %roles - peer, validator
-  (swap! core/users assoc [msp-id name] (core/make-user args)))
-
-;;; new_chain
-;;;
-;; "Initializes a chain instance with the given name. This is really representing the \"Channel\"
-;;   (as explained above), and this call returns an empty object. To initialize the channel, a list of
-;;   participating endorsers and orderer peers must be configured first on the returned object.
-;;   Params:
-;;         name (str): The name of the chain, recommend using namespaces to avoid collision
-;;   Returns:
-;;         (Chain instance): The uninitialized chain instance."
-;;
-;;
-(defn new-channel!
-  ([channel-opts]
-   (new-channel! core/*user* channel-opts))
-  ([{msp-id :msp-id user-name :name} channel-opts]
-   (let [user-key [msp-id user-name]]
-     (swap! core/users assoc-in [user-key :channels (:name channel-opts)]
-            (core/make-channel (assoc channel-opts :user-key user-key))))))
-
-;;; get_chain
-(defn get-channel
-  "Get a chain instance from the state storage. This allows existing chain instances to be saved
-  for retrieval later and to be shared among instances of the application. Note that it's the
-  application/SDK’s responsibility to record the chain information. If an application is not able to
-  look up the chain information from storage, it may call another API that queries one or more Peers
-  for that information.
-  Params:
-        name (str): The name of the chain
-  Returns:
-        (Chain instance or None): the chain instance for the name.
-  Error:  The state store has not been set
-        A chain does not exist under that name"
-  ;; Implementation Note:
-  ;;    Not a storage operation
-  ([channel-name]
-   (get-channel core/*user* channel-name))
-  ([{:keys [channels]} channel-name]
-   (if-let [found (get channels channel-name)]
-     found
-     ;; Implementation Note
-     ;;       The spec says that Returns is chain Instance or None
-     ;;       How it can be None and also throw an exception?
-     (throw (Exception. "A channel does not exist under that name")))))

 (defmacro with-validating-peers
   [[user-or-channel target-peers] & body]
@@ -109,29 +59,6 @@
      ~@body))

 (defonce system-channel-name "")
-
-;;; query_chain-info
-(defn query-channels
-    "This is a network call to the designated Peer(s) to discover the chain information.
-  The target Peer(s) must be part of the chain in question to be able to return the requested
-  information.
-  Params:
-        name (str): The name of the chain
-        peers (array of Peer instances): target Peers to query
-  Returns:
-        (Chain instance or None): the chain instance for the name.
-  Error:
-        The target Peer(s) does not know anything about the chain"
-  ([channel-name peers]
-   (query-channels core/*user* channel-name peers))
-  ([user channel-name target-peers]
-   (let [{:keys [crypto-suite user-context] :as channel} (get-channel user channel-name)]
-     (with-validating-peers [channel target-peers]
-                             (chaincode/send-chaincode-request :query-channels
-                                                               system-channel-name
-                                                               target-peers
-                                                               user
-                                                               {})))))

 ;; (defonce ^:private client-state-store (atom {}))
 ;; ;;; set_state_store
@@ -175,27 +102,9 @@
 (defn new-crypto-suite!
   ([crypto-opts]
    (new-crypto-suite! core/*user* crypto-opts))
-  ([{:keys [msp-id name]} user crypto-opts]
+  ([{:keys [msp-id name]} crypto-opts]
    (swap! core/users assoc-in [[msp-id name] crypto-opts]
           (core/make-crypto-suite crypto-opts))))
-
-;; Params:
-;;   Suite (object): an instance of a crypto suite implementation"
-;;
-;; Immutable
-
-;;; get_crypto_suite
-(defn get-crypto-suite
-  "A convenience method for obtaining the CryptoSuite object in use for this client.
-  Params:
-        None
-  Returns:
-        (CryptoSuite instance): The CryptoSuite implementation object set within this Client,
-        or null if it does not exist"
-  ([]
-   (get-crypto-suite core/*user*))
-  ([user]
-   (:crypto-suite user)))

 ;;; set_user_context
 ;; "Sets an instance of the User class as the security context of this client instance.
@@ -252,18 +161,6 @@
           (known-channel-node? c node plural-type-key) true
           :else (recur more-c))))

-(defn query-installed-chaincodes
-  ([peer]
-   (query-installed-chaincodes core/*user* peer))
-  ([user peer]
-   (if (known-user-node? user peer :peers)
-     (first (chaincode/send-chaincode-request :query-installed-chaincodes
-                                              system-channel-name
-                                              peer
-                                              user
-                                              {}))
-     (throw (Exception. "The target Peer does not know anything about the channel")))))
-
 ;;; get_name
 (defn get-name
   "Get member name. Required property for the instance objects.
@@ -300,13 +197,41 @@
   ([user]
    (:certificate user)))

-(defn create-or-update-channel
-  ([orderer envelope]
-   (proto/broadcast-or-deliver-via-orderer :broadcast orderer envelope))
-  ([user channel-id orderer config-update signatures]
-   (->> (proto/make-config-update-envelope :config-update config-update :signatures signatures)
-        (chaincode/make-envelope channel-id user :config-update)
-        (create-or-update-channel orderer))))
+
+;;(def cu (tx-file->config-update "/home/jc/Work/clojure-fabric/resources/fixture/balance-transfer/artifacts/channel/mychannel.tx"))
+;;
+;; (create-or-update-channel-from-nodes (core/get-user "Org1MSP" "user1") "testchan14"
+;;                                      (merge (first (core/get-nodes (core/get-user "Org1MSP" "user1") :orderers))
+;;                                             (get @core/users  ["Orderer" "admin"]))
+;;                                      [(get @core/users  ["Org1MSP" "admin"]) (get @core/users  ["Org2MSP" "admin"])
+;;                                       (get @core/users  ["Orderer" "admin"])]
+;;                                      cu2)
+;;; set_name
+;;; Immutable
+
+;;; set_roles
+;;; Immutable
+
+;;; set_enrollment_certificate
+;;; Immutable
+
+
+;;; generate_tcerts
+;; Not required any more(?) - https://jira.hyperledger.org/browse/FAB-5740
+;; (defn generate-tcerts
+;;   "Gets a batch of TCerts to use for transaction. there is a 1-to-1 relationship between TCert
+;;   and Transaction. The TCert can be generated locally by the SDK using the user’s crypto materials.
+;;   Params:
+;;         count (number): how many in the batch to obtain?
+;;         Attributes (string[]): list of attributes to include in the TCert
+;;   Returns (TCert[]):
+;;         An array of TCerts"
+;;   ([count attributes]
+;;    (generate-tcerts core/*user*))
+;;   ([user count attributes])
+;;   ;; TBD
+;;   ;; Not sure if this is required now (couldn't find any usage in Java code)
+;;   )

 (defn make-config-signature
   [user config-update {:keys [header-version] :or {header-version 1}}]
@@ -325,67 +250,9 @@
          (proto/make-config-signature :signature-header signature-header
                                       :signature))))

-(defn create-or-update-channel-from-nodes
-  [user channel-id orderer nodes config-update]
-  ;; participants = orderers + peers
-  (create-or-update-channel user
-                            channel-id
-                            orderer
-                            config-update
-                            (mapv (fn [node]
-                                    (make-config-signature node config-update {}))
-                                  nodes)))
-
-(defonce max-tx-file-size 1024)
-(defn tx-file->config-update
-    [tx-filename]
-    (let [tx-file (io/as-file tx-filename)]
-      (assert (<= (.length tx-file) max-tx-file-size))
-      (let [envelope (->> (with-open [in (io/input-stream tx-file)
-                                      out (java.io.ByteArrayOutputStream.)]
-                            (io/copy in out)
-                            (Common$Envelope/parseFrom (.toByteArray out))))]
-        (-> (proto/proto->clj envelope
-                              (proto/parse-trees :block-config-update-envelope))
-            (get-in [:payload :data :config-update])
-            (proto/clj->proto)
-            (.toByteArray)))))
-
-;;(def cu (tx-file->config-update "/home/jc/Work/clojure-fabric/resources/fixture/balance-transfer/artifacts/channel/mychannel.tx"))
-;;
-;; (create-or-update-channel-from-nodes (core/get-user "Org1MSP" "user1") "testchan14"
-;;                                      (merge (first (core/get-nodes (core/get-user "Org1MSP" "user1") :orderers))
-;;                                             (get @core/users  ["Orderer" "admin"]))
-;;                                      [(get @core/users  ["Org1MSP" "admin"]) (get @core/users  ["Org2MSP" "admin"])
-;;                                       (get @core/users  ["Orderer" "admin"])]
-;;                                      cu2)
-;;; set_name
-;;; Immutable
-
-;;; set_roles
-;;; Immutable
-
-;;; set_enrollment_certificate
-;;; Immutable
-
-
-;;; generate_tcerts
-;; Not required any more(?) - https://jira.hyperledger.org/browse/FAB-5740
-;; (defn generate-tcerts
-;;   "Gets a batch of TCerts to use for transaction. there is a 1-to-1 relationship between TCert
-;;   and Transaction. The TCert can be generated locally by the SDK using the user’s crypto materials.
-;;   Params:
-;;         count (number): how many in the batch to obtain?
-;;         Attributes (string[]): list of attributes to include in the TCert
-;;   Returns (TCert[]):
-;;         An array of TCerts"
-;;   ([count attributes]
-;;    (generate-tcerts core/*user*))
-;;   ([user count attributes])
-;;   ;; TBD
-;;   ;; Not sure if this is required now (couldn't find any usage in Java code)
-;;   )
-
+;;;
+;;; Utility functions
+;;;
 (defonce default-tgz-size 500000)       ;500kb, from Java SDK

 (defonce type->file-extensions {:golang #{"go"} :java #{"java"} :node #{"js"}})
@@ -427,6 +294,90 @@
 ;; (make-tgz-package :golang "github.com/example_cc" "/home/jc/Work/clojure-fabric/resources/gocc")

+(defonce max-tx-file-size 1024)
+(defn tx-file->config-update
+  [tx-filename]
+  (let [tx-file (io/as-file tx-filename)]
+    (assert (<= (.length tx-file) max-tx-file-size))
+    (let [envelope (->> (with-open [in (io/input-stream tx-file)
+                                    out (java.io.ByteArrayOutputStream.)]
+                          (io/copy in out)
+                          (Common$Envelope/parseFrom (.toByteArray out))))]
+      (-> (proto/proto->clj envelope
+                            (proto/parse-trees :block-config-update-envelope))
+          (get-in [:payload :data :config-update])
+          ^Configtx$ConfigUpdate (proto/clj->proto)
+          (.toByteArray)))))
+;;;
+;;; Public API
+;;;
+
+(defn create-or-update-channel
+  ([orderer envelope]
+   (proto/broadcast-or-deliver-via-orderer :broadcast orderer envelope))
+  ([user channel-id orderer config-update signatures]
+   (->> (proto/make-config-update-envelope :config-update config-update :signatures signatures)
+        (chaincode/make-envelope channel-id user :config-update)
+        (create-or-update-channel orderer))))
+
+;; This is like create-channel
+(defn create-or-update-channel-from-nodes
+  [user channel-id orderer nodes config-update]
+  ;; participants = orderers + peers
+  (create-or-update-channel user
+                            channel-id
+                            orderer
+                            config-update
+                            (mapv (fn [node]
+                                    (make-config-signature node config-update {}))
+                                  nodes)))
+
+;; This is like create-user
+(defn new-user!
+  [{:keys [msp-id name]
+    :as args}]
+  ;; roles - client, auditor
+  ;; %roles - peer, validator
+  (swap! core/users assoc [msp-id name] (core/make-user args)))
+
+;;; get_chain
+(defn get-channel
+  "Get a chain instance from the state storage. This allows existing chain instances to be saved
+  for retrieval later and to be shared among instances of the application. Note that it's the
+  application/SDK’s responsibility to record the chain information. If an application is not able to
+  look up the chain information from storage, it may call another API that queries one or more Peers
+  for that information.
+  Params:
+        name (str): The name of the chain
+  Returns:
+        (Chain instance or None): the chain instance for the name.
+  Error:  The state store has not been set
+        A chain does not exist under that name"
+  ;; Implementation Note:
+  ;;    Not a storage operation
+  ([channel-name]
+   (get-channel core/*user* channel-name))
+  ([{:keys [channels]} channel-name]
+   (if-let [found (get channels channel-name)]
+     found
+     ;; Implementation Note
+     ;;       The spec says that Returns is chain Instance or None
+     ;;       How it can be None and also throw an exception?
+     (throw (Exception. "A channel does not exist under that name")))))
+
+;;; get_crypto_suite
+(defn get-crypto-suite
+  "A convenience method for obtaining the CryptoSuite object in use for this client.
+  Params:
+        None
+  Returns:
+        (CryptoSuite instance): The CryptoSuite implementation object set within this Client,
+        or null if it does not exist"
+  ([]
+   (get-crypto-suite core/*user*))
+  ([user]
+   (:crypto-suite user)))
+
 (defn install-chaincode
   ([name path version package-filename type target-peers]
    (install-chaincode core/*user* name path version package-filename target-peers))
@@ -447,6 +398,70 @@
                                          target-peers
                                          user
                                          {:args [deployment-spec]})))))
+
+;;; new_chain
+;;;
+;; "Initializes a chain instance with the given name. This is really representing the \"Channel\"
+;;   (as explained above), and this call returns an empty object. To initialize the channel, a list of
+;;   participating endorsers and orderer peers must be configured first on the returned object.
+;;   Params:
+;;         name (str): The name of the chain, recommend using namespaces to avoid collision
+;;   Returns:
+;;         (Chain instance): The uninitialized chain instance."
+;;
+;;
+(defn new-channel!
+  ([channel-opts]
+   (new-channel! core/*user* channel-opts))
+  ([{msp-id :msp-id user-name :name} channel-opts]
+   (let [user-key [msp-id user-name]]
+     (swap! core/users assoc-in [user-key :channels (:name channel-opts)]
+            (core/make-channel (assoc channel-opts :user-key user-key))))))
+
+(defn new-event-hub!
+  [user peer]
+  (if-let [existing-eh (deref (:event-hub peer))]
+    (throw (Exception. "An event-hub already exists!"))
+    (let [event-hub (event-hub/make-event-hub user peer)]
+      (reset! (:event-hub peer) event-hub)
+      event-hub)))
+
+
+;;; query_chain-info
+(defn query-channels
+    "This is a network call to the designated Peer(s) to discover the chain information.
+  The target Peer(s) must be part of the chain in question to be able to return the requested
+  information.
+  Params:
+        name (str): The name of the chain
+        peers (array of Peer instances): target Peers to query
+  Returns:
+        (Chain instance or None): the chain instance for the name.
+  Error:
+        The target Peer(s) does not know anything about the chain"
+  ([channel-name peers]
+   (query-channels core/*user* channel-name peers))
+  ([user channel-name target-peers]
+   (let [{:keys [crypto-suite user-context] :as channel} (get-channel user channel-name)]
+     (with-validating-peers [channel target-peers]
+                             (chaincode/send-chaincode-request :query-channels
+                                                               system-channel-name
+                                                               target-peers
+                                                               user
+                                                               {})))))
+
+
+(defn query-installed-chaincodes
+  ([peer]
+   (query-installed-chaincodes core/*user* peer))
+  ([user peer]
+   (if (known-user-node? user peer :peers)
+     (first (chaincode/send-chaincode-request :query-installed-chaincodes
+                                              system-channel-name
+                                              peer
+                                              user
+                                              {}))
+     (throw (Exception. "The target Peer does not know anything about the channel")))))

 ;; (def e1 (Common$Envelope/parseFrom buf))


Experiment with inherited-errors meta-errors

--- src/clojush/meta_errors.clj
+++ src/clojush/meta_errors.clj
@@ -793,7 +793,7 @@
         0))
     1))

-(defn inherited-errors-meta-error
+#_(defn inherited-errors-meta-error
   [ind evaluated-population argmap]
   (if (and (:parent1-errors ind)
            (:parent2-errors ind)
@@ -801,3 +801,34 @@
            (not= (:errors ind) (:parent2-errors ind)))
     0
     1))
+
+(defn inherited-errors-meta-error
+  [ind evaluated-population argmap]
+  (if (and (:parent1-errors ind)
+           (:parent2-errors ind))
+    (if (and (not= (:errors ind) (:parent1-errors ind))
+             (not= (:errors ind) (:parent2-errors ind)))
+      0
+      1)
+    0))
+
+#_(defn case-inherited-errors-meta-error
+  [ind evaluated-population argmap]
+  (if (and (:parent1-errors ind)
+           (:parent2-errors ind))
+    (mapv #(if (some #{%1} [%2 %3]) 1 0)
+          (:errors ind)
+          (:parent1-errors ind)
+          (:parent2-errors ind))
+    (vec (repeat (count (:errors ind)) 1))))
+
+(defn case-inherited-errors-meta-error
+  [ind evaluated-population argmap]
+  (if (and (:parent1-errors ind)
+           (:parent2-errors ind))
+    (mapv #(if (some #{%1} [%2 %3]) 1 0)
+          (:errors ind)
+          (:parent1-errors ind)
+          (:parent2-errors ind))
+    (vec (repeat (count (:errors ind)) 0))))
+


Render sparkline axis/labels to an image because CSSBox and HTML email hate Tom

--- src/metabase/pulse.clj
+++ src/metabase/pulse.clj
@@ -89,6 +89,45 @@
 (defn card-href
   [card]
   (h (str (setting/get :-site-url) "/card/" (:id card) "?clone")))
+
+; ported from https://github.com/radkovo/CSSBox/blob/cssbox-4.10/src/main/java/org/fit/cssbox/demo/ImageRenderer.java
+(defn render-to-png
+  [html, os, width]
+  (let [is (new java.io.ByteArrayInputStream (.getBytes html java.nio.charset.StandardCharsets/UTF_8))
+        docSource (new org.fit.cssbox.io.StreamDocumentSource is nil "text/html")
+        parser (new org.fit.cssbox.io.DefaultDOMSource docSource)
+        doc (-> parser .parse)
+        windowSize (new java.awt.Dimension width 1)
+        media (new cz.vutbr.web.css.MediaSpec "screen")]
+    (.setDimensions media (.width windowSize) (.height windowSize))
+    (.setDeviceDimensions media (.width windowSize) (.height windowSize))
+    (let [da (new org.fit.cssbox.css.DOMAnalyzer doc (.getURL docSource))]
+      (.setMediaSpec da media)
+      (.attributesToStyles da)
+      (.addStyleSheet da nil (org.fit.cssbox.css.CSSNorm/stdStyleSheet) org.fit.cssbox.css.DOMAnalyzer$Origin/AGENT)
+      (.addStyleSheet da nil (org.fit.cssbox.css.CSSNorm/userStyleSheet) org.fit.cssbox.css.DOMAnalyzer$Origin/AGENT)
+      (.addStyleSheet da nil (org.fit.cssbox.css.CSSNorm/formsStyleSheet) org.fit.cssbox.css.DOMAnalyzer$Origin/AGENT)
+      (.getStyleSheets da)
+      (let [contentCanvas (new org.fit.cssbox.layout.BrowserCanvas (.getRoot da) da (.getURL docSource))]
+        (-> contentCanvas (.setAutoMediaUpdate false))
+        (-> contentCanvas (.setAutoSizeUpdate true))
+        (-> contentCanvas .getConfig (.setClipViewport false))
+        (-> contentCanvas .getConfig (.setLoadImages true))
+        (-> contentCanvas .getConfig (.setLoadBackgroundImages true))
+        (-> contentCanvas (.createLayout windowSize))
+        (javax.imageio.ImageIO/write (.getImage contentCanvas) "png" os)))))
+
+(defn render-html-to-png
+  [html-body width]
+  (let [html (html [:html [:body {:style "margin: 0; padding: 0; background-color: white;"} html-body]])
+        os (new java.io.ByteArrayOutputStream)]
+    (render-to-png html os width)
+    (.toByteArray os)))
+
+(defn render-img-data-uri
+  "Takes a PNG byte array and returns a Base64 encoded URI"
+  [img-bytes]
+  (str "data:image/png;base64," (new String (org.fit.cssbox.misc.Base64Coder/encode img-bytes))))

 (defn render-button
   [text href icon render-img]
@@ -182,8 +221,8 @@
     (javax.imageio.ImageIO/write image "png" os)
     (.toByteArray os)))

-(defn render-card-sparkline
-  [card {:keys [rows cols] :as data} render-img]
+(defn render-sparkline-with-axis-to-png
+  [card {:keys [rows cols] :as data}]
   (let [xs (for [row rows :let [x (first row)]] (if (instance? java.util.Date x) (.getTime x) x))
         xmin (apply min xs)
         xmax (apply max xs)
@@ -194,14 +233,14 @@
         ymax (apply max ys)
         yrange (- ymax ymin)
         ys' (map #(/ (- % ymin) yrange) ys)]
-    [:div
-      [:div {:style (str "color: " color-grey-2 ";") }
-        [:div {:style "display: inline-block; position: relative; margin-left: 30px;" }
+    (render-html-to-png
+      [:div {:style (str font-style "color: " color-grey-2 ";") }
+        [:div {:style "display: inline-block; position: relative; margin-left: 40px;" }
           [:div {:style "position: relative;"}
             [:div {:style "position: absolute; height: 100%; text-align: right; background-color: red;"}
-              [:div {:style "position: absolute; top: 0; right: 0;"} (format-number-short ymax)]
+              [:div {:style "position: absolute; right: 0;"} (format-number-short ymax)]
               [:div {:style "position: absolute; top: 150px; right: 0;"} (format-number-short ymin)]]
-            [:img {:style "display: block; left: 20px;" :src (render-img (render-sparkline-to-png xs' ys' 285 150))}]
+            [:img {:style "display: block; left: 20px;" :src (render-img-data-uri (render-sparkline-to-png xs' ys' 275 150))}]
           ]
           [:div
             [:div {:style (str "height: 15px; margin-left: 10px; margin-right: 10px; border: 4px solid " color-grey-1 "; border-top: none; border-bottom: none;")} " "]
@@ -209,8 +248,14 @@
               [:div {:style "float: left;"} (format-timestamp xmin (first cols))]
               [:div {:style "float: right;"} (format-timestamp xmax (first cols))]]
           ]]]
-      [:div {:style "margin-top: 20px; margin-left: 30px;"}
-        (render-table card [(last rows) (first rows)] cols render-img [0 1] nil)]]))
+        300)))
+
+(defn render-card-sparkline
+  [card {:keys [rows cols] :as data} render-img]
+  [:div
+    [:img {:style "display: block" :src (render-img (render-sparkline-with-axis-to-png card data))}]
+    [:div {:style "margin-top: 20px; margin-left: 30px;"}
+      (render-table card [(last rows) (first rows)] cols render-img [0 1] nil)]])

 (defn detect-pulse-card-type
   [card data]
@@ -245,11 +290,6 @@
     (log/warn (str "Pulse card render error:" e))
     [:div {:style (str font-style "color: #EF8C8C; font-weight: 700;")} "An error occurred while displaying this card."])))

-(defn render-img-data-uri
-  "Takes a PNG byte array and returns a Base64 encoded URI"
-  [img-bytes]
-  (str "data:image/png;base64," (new String (org.fit.cssbox.misc.Base64Coder/encode img-bytes))))
-
 (defn- render-pulse-section
   [render-img {:keys [card result]}]
   [:div {:style "margin-top: 10px; margin-bottom: 20px;"}
@@ -280,36 +320,6 @@
                                                 :content (write-byte-array-to-temp-file bytes)})
                                @images))))

-; ported from https://github.com/radkovo/CSSBox/blob/cssbox-4.10/src/main/java/org/fit/cssbox/demo/ImageRenderer.java
-(defn render-to-png
-  [html, os]
-  (let [is (new java.io.ByteArrayInputStream (.getBytes html java.nio.charset.StandardCharsets/UTF_8))
-        docSource (new org.fit.cssbox.io.StreamDocumentSource is nil "text/html")
-        parser (new org.fit.cssbox.io.DefaultDOMSource docSource)
-        doc (-> parser .parse)
-        windowSize (new java.awt.Dimension card-width 1)
-        media (new cz.vutbr.web.css.MediaSpec "screen")]
-    (.setDimensions media (.width windowSize) (.height windowSize))
-    (.setDeviceDimensions media (.width windowSize) (.height windowSize))
-    (let [da (new org.fit.cssbox.css.DOMAnalyzer doc (.getURL docSource))]
-      (.setMediaSpec da media)
-      (.attributesToStyles da)
-      (.addStyleSheet da nil (org.fit.cssbox.css.CSSNorm/stdStyleSheet) org.fit.cssbox.css.DOMAnalyzer$Origin/AGENT)
-      (.addStyleSheet da nil (org.fit.cssbox.css.CSSNorm/userStyleSheet) org.fit.cssbox.css.DOMAnalyzer$Origin/AGENT)
-      (.addStyleSheet da nil (org.fit.cssbox.css.CSSNorm/formsStyleSheet) org.fit.cssbox.css.DOMAnalyzer$Origin/AGENT)
-      (.getStyleSheets da)
-      (let [contentCanvas (new org.fit.cssbox.layout.BrowserCanvas (.getRoot da) da (.getURL docSource))]
-        (-> contentCanvas (.setAutoMediaUpdate false))
-        (-> contentCanvas (.setAutoSizeUpdate true))
-        (-> contentCanvas .getConfig (.setClipViewport false))
-        (-> contentCanvas .getConfig (.setLoadImages true))
-        (-> contentCanvas .getConfig (.setLoadBackgroundImages true))
-        (-> contentCanvas (.createLayout windowSize))
-        (javax.imageio.ImageIO/write (.getImage contentCanvas) "png" os)))))
-
 (defn render-pulse-card-to-png
   [card data include-title]
-  (let [html (html [:html [:body {:style "margin: 0; background-color: white;"} (render-pulse-card card data include-title render-img-data-uri)]])
-        os (new java.io.ByteArrayOutputStream)]
-    (render-to-png html os)
-    (.toByteArray os)))
+  (render-html-to-png (render-pulse-card card data include-title render-img-data-uri) card-width))


Update to ClojureScript 0.0-3058

Update to ClojureScript 0.0-3058

--- Clojure/project.clj
+++ Clojure/project.clj
@@ -4,6 +4,6 @@
   :license {:name "Eclipse Public License"
             :url "http://www.eclipse.org/legal/epl-v10.html"}
   :dependencies [[org.clojure/clojure "1.6.0"]
-                 [org.clojure/clojurescript "0.0-3053"]
+                 [org.clojure/clojurescript "0.0-3058"]
                  [com.github.rickyclarkson/jmdns "3.4.2-r353-1"]]
   :source-paths ["src"])


Fixed the enforceApiDeadlines error introduced with App Engine 1.5.0.

--- src/appengine_magic/local_env_helpers.clj
+++ src/appengine_magic/local_env_helpers.clj
@@ -36,6 +36,7 @@
                                 "")
         proxy-factory (ApiProxyLocalFactory.)
         environment (proxy [LocalServerEnvironment] []
+                      (enforceApiDeadlines [] true)
                       (getAppDir [] dir)
                       (getAddress [] "localhost")
                       (getPort [] port)


changed the logic for parsing the include tags

--- src/selmer/template_parser.clj
+++ src/selmer/template_parser.clj
@@ -24,8 +24,8 @@
          (into {}))))

 (defn split-include-tag [^String tag-str]
-  (let [sep (if (= java.io.File/separator "\\") "\\\\" java.io.File/separator)]
-    (seq (.split ^String (get-tag-params (re-pattern (str "[^" sep "]include")) tag-str) " "))))
+  (seq (.split ^String (get-tag-params #"[^/]include" (.replace tag-str "\\" "/")) " ")))
+

 (defn insert-includes
   "parse any included templates and splice them in replacing the include tags"


add button for admins to delete tags

add button for admins to delete tags

--- src/braid/client/ui/views/pages/tags.cljs
+++ src/braid/client/ui/views/pages/tags.cljs
@@ -29,6 +29,11 @@
             (aset (.. e -target) "value" "")))
         :placeholder "New Tag"}])))

+(defn delete-tag-view
+  [tag]
+  [:button {:on-click (fn [_] (dispatch! :retract-tag (tag :id)))}
+   "Delete Tag"])
+
 (defn tag-info-view
   [tag]
   (let [group-id (subscribe [:open-group-id])
@@ -47,7 +52,9 @@
            "One day, a tag description will be here."
            (tag :description))]
         (when @admin?
-          [edit-description-view tag]) ]])))
+          [:div
+           [edit-description-view tag]
+           [delete-tag-view tag]])]])))

 (defn tags-page-view
   []


using aget over nth on next-row

using aget over nth on next-row

on size 325 cuts from ~45ms -> ~22ms

--- src/sierpinski_sieve/core.cljs
+++ src/sierpinski_sieve/core.cljs
@@ -16,8 +16,8 @@
     (aset next 0 1)
     (aset next (dec size) 1)
     (doseq [x (range 1 (dec size))]
-      (let [before (nth row (dec x))
-            above (nth row x)]
+      (let [before (aget row (dec x))
+            above (aget row x)]
         (aset next x (mod (+ before above) modulus))))
     next))


Fixing issue with java interface code

Fixing issue with java interface code

Type hints were not cleaned from the calls to the actual conexp-clj
functions.  This is fixed now.

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

--- src/conexp/contrib/java.clj
+++ src/conexp/contrib/java.clj
@@ -51,7 +51,8 @@
     arglist
     (let [[a b] (split-with #(not= '& %) arglist)]
       (if (not-empty b)
-        (vec (concat (map dissect-arglist a) (list (with-meta (second b) {:tag "[Ljava.lang.Object;"}))))
+        (vec (concat (map dissect-arglist a)
+                     (list (with-meta (second b) {:tag "[Ljava.lang.Object;"}))))
         (vec (map dissect-arglist arglist))))))

 (defn- function-signatures
@@ -81,7 +82,10 @@
     `(defn ~(symbol (str prefix new-name))
        ~@(for [args arglists]
            `(~(dissect-arglist args)
-             (apply ~(symbol orig-name) ~(dissect-arglist args)))))))
+             (~(symbol orig-name)
+              ~@(map (fn [arg]
+                       (with-meta arg {}))
+                     (dissect-arglist args))))))))

 ;;;


fix issue with rez message

fix issue with rez message

--- src/node/game/core.cljs
+++ src/node/game/core.cljs
@@ -552,6 +552,7 @@
   (let [cdef (card-def card)]
     (when (or no-cost (pay state side card :credit (:cost card) (:additional-cost cdef)))
       (card-init state side (assoc card :rezzed true))
+      (system-msg state side (str "rez " (:title card)))
       (trigger-event state side :rez card))))

 (defn corp-install
@@ -589,7 +590,6 @@
     ("ICE" "Upgrade" "Asset" "Agenda") (corp-install state side card server {:extra-cost [:click 1]})))

 (defn rez-card [state side {:keys [card]}]
-  (system-msg state side (str "rez " (:title card)))
   (rez state side card nil))

 (defn derez [state side {:keys [card]}]


Whitespace

Whitespace

--- src/oxcart/pattern.clj
+++ src/oxcart/pattern.clj
@@ -56,6 +56,7 @@
   [form]
   (-> form :meta :form :dynamic true?))

+
 (defn const?
   [form]
   (case (-> form :meta :form :const)


fix broken utf-8 in svgs

fix broken utf-8 in svgs

--- src/pc/http/routes.clj
+++ src/pc/http/routes.clj
@@ -169,7 +169,7 @@
           (auth/has-document-permission? db doc (-> req :auth) :read)
           (if (= :head (:request-method req))
             {:status 200
-             :headers (merge {"Content-Type" "image/svg+xml"}
+             :headers (merge {"Content-Type" "image/svg+xml; charset=UTF-8"}
                              (image-cache-headers db doc))
              :pc/doc doc
              :body ""}
@@ -177,7 +177,7 @@
                   layer-db (if as-of (d/as-of db as-of) db)
                   layers (layer-model/find-by-document layer-db doc)]
               {:status 200
-               :headers (merge {"Content-Type" "image/svg+xml"}
+               :headers (merge {"Content-Type" "image/svg+xml; charset=UTF-8"}
                                (when (-> req :params :dl)
                                  {"Content-Disposition" (format "attachment; filename=\"precursor-document-%s.svg\""
                                                                 (:db/id doc))})
@@ -187,13 +187,13 @@

           (auth/logged-in? req)
           {:status 200
-           :headers {"Content-Type" "image/svg+xml"
+           :headers {"Content-Type" "image/svg+xml; charset=UTF-8"
                      "Cache-Control" "no-cache; private"}
            :body (render/render-layers private-layers :invert-colors? (-> req :params :printer-friendly (= "false")))}

           :else
           {:status 200
-           :headers {"Content-Type" "image/svg+xml"
+           :headers {"Content-Type" "image/svg+xml; charset=UTF-8"
                      "Cache-Control" "no-cache; private"}
            :body (render/render-layers private-layers :invert-colors? (-> req :params :printer-friendly (= "false")))})))


Namespace checkpoint key by job-id

Namespace checkpoint key by job-id

--- src/onyx/plugin/sql.clj
+++ src/onyx/plugin/sql.clj
@@ -74,20 +74,20 @@
 (defn update-partition [content acked]
   (dissoc content acked))

-(defn start-commit-loop! [log task-id content checkpoint-ch checkpoint-loop-ms]
+(defn start-commit-loop! [log checkpoint-key content checkpoint-ch checkpoint-loop-ms]
   (go-loop [updated-content content]
            (let [timeout-ch (timeout checkpoint-loop-ms)
                  [acked ch] (alts!! [timeout-ch checkpoint-ch] :priority true)]
              (cond (= ch timeout-ch)
                    (do
-                     (extensions/force-write-chunk log :chunk updated-content task-id)
+                     (extensions/force-write-chunk log :chunk updated-content checkpoint-key)
                      (recur updated-content))
                    (and (= ch checkpoint-ch)
                         (not (nil? acked)))
                    (recur (update-partition updated-content acked))))))

 (defn inject-partition-keys
-  [table-partitioner {:keys [onyx.core/pipeline onyx.core/task-map onyx.core/log onyx.core/task-id] :as event}
+  [table-partitioner {:keys [onyx.core/pipeline onyx.core/task-map onyx.core/log onyx.core/job-id onyx.core/task-id] :as event}
    lifecycle]
   (let [ch (:read-ch pipeline)
         checkpoint-ch (:checkpoint-ch pipeline)
@@ -103,7 +103,8 @@
         ;; in either case.
         _ (extensions/write-chunk log :chunk chunk task-id)
         content (extensions/read-chunk log :chunk task-id)
-        commit-go-loop (start-commit-loop! log task-id content checkpoint-ch checkpoint-ms)]
+        checkpoint-key (str job-id "#" task-id)
+        commit-go-loop (start-commit-loop! log checkpoint-key content checkpoint-ch checkpoint-ms)]
     (go
      (try
          (doseq [part (keys content)]


cache recent bookmarks

cache recent bookmarks

--- src/clj/lesezeichen/core.clj
+++ src/clj/lesezeichen/core.clj
@@ -51,7 +51,7 @@
 (defn authorized?
   "Check authorization status of given topic and token"
   [state {:keys [topic token]}]
-  (if (#{:sign-up :register-device :verify-token :error} topic)
+  (if (#{:sign-up :register-device :verify-token :error :get-recent-bookmarks} topic)
     true
     (= :valid (-> @state :authenticated-tokens (get token) :status))))

@@ -72,9 +72,13 @@
         (case topic
           :get-user-bookmarks {:topic topic :data (get-user-bookmarks conn data)}
           :get-all-bookmarks {:topic topic :data (get-all-bookmarks conn)}
+          :get-recent-bookmarks {:topic topic :data (:recent-bookmarks @state)}
           :sign-up {:topic topic :data (add-user conn (assoc data :host (:mail-host @state) :port (:mail-port @state) :host-name (:host-name @state)))}
           :register-device {:topic topic :data (register-device conn data)}
-          :add-bookmark {:topic topic :data (add-bookmark conn (assoc data :title (fetch-url-title (:url data))))}
+          :add-bookmark (let [new-bm (get-all-bookmarks conn)]
+                          (do
+                            (swap! state (fn [s] (update-in s :recent-bookmarks conj)))
+                            {:topic topic :data new-bm}))
           :verify-token (handle-token state channel msg)
           {:topic :error :data :unknown-request})
         {:topic :error :data :not-authorized})))
@@ -119,7 +123,7 @@

 (defn init-db [state]
-  (let [conn (db-conn)]
+  (let [conn #_(scratch-conn) (db-conn)]
     (swap! state #(assoc %1 :conn %2) conn))
   (init-schema (:conn @state) (:schema @state))
   state)


fonts should be used over https

fonts should be used over https

--- src/clj/yambox/templates.clj
+++ src/clj/yambox/templates.clj
@@ -12,8 +12,8 @@
    [:title title]
    [:link {:rel "icon" :type "image/png" :href "/img/icon.png"}]
    (include-css "https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css")
-   (include-css "http://fonts.googleapis.com/css?family=PT+Sans+Narrow&subset=latin,cyrillic")
-   (include-css "http://fonts.googleapis.com/css?family=PT+Sans:400,700&subset=cyrillic,latin")
+   (include-css "https://fonts.googleapis.com/css?family=PT+Sans+Narrow&subset=latin,cyrillic")
+   (include-css "https://fonts.googleapis.com/css?family=PT+Sans:400,700&subset=cyrillic,latin")
    (include-css "/css/style.css")])

 (defn- wrap-top


mocking up layer hover interaction

mocking up layer hover interaction

--- src/cljs/ta_crash/crash.cljs
+++ src/cljs/ta_crash/crash.cljs
@@ -20,8 +20,9 @@
   :maxZoom 17})
 (def feature-style {:weight 2
                     :opacity 1
-                    :fill false
+                    :fill true
                     :stroke true
+                    :fillOpacity 0
                     :color "#000000"})

 (defn get-type-identifier
@@ -62,10 +63,16 @@
       (remove-layer)
       (swap! outline-layer (fn [] geo-layer)))))

+(defn set-feature
+  [feature layer]
+  (println "set-feature" layer)
+  (.bindPopup layer (.. js/feature -properties -identifier))
+  (.on layer "click" (fn [e] (println "properties" (.. js/feature -properties -identifier)))))
+
 (defn set-shape
   [geo-data]
   (let [crash-map (get-map)
-        geo-layer (set-geo-layer geo-data {:style feature-style})]
+        geo-layer (set-geo-layer geo-data {:style feature-style :onEachFeature set-feature})]
     (do
       (check-outline-layer geo-layer)
       (-> geo-layer


Backport mocking functions from Clojure 1.3

Signed-off-by: Deepak Giridharagopal <d11186354d1ef01ca06ae37d7e23e827da13e85f@puppetlabs.com>

--- src/com/puppetlabs/utils.clj
+++ src/com/puppetlabs/utils.clj
@@ -30,3 +30,40 @@
   (incubator/-?> x
                  (class)
                  (.isArray)))
+
+;;;; These redef functions are backported from Clojure 1.3 core
+
+(defn with-redefs-fn
+  "Temporarily redefines Vars during a call to func.  Each val of
+  binding-map will replace the root value of its key which must be
+  a Var.  After func is called with no args, the root values of all
+  the Vars will be set back to their old values.  These temporary
+  changes will be visible in all threads.  Useful for mocking out
+  functions during testing."
+  {:added "1.3"}
+  [binding-map func]
+  (let [root-bind (fn [m]
+                    (doseq [[a-var a-val] m]
+                      (.bindRoot ^clojure.lang.Var a-var a-val)))
+        old-vals (zipmap (keys binding-map)
+                         (map deref (keys binding-map)))]
+    (try
+      (root-bind binding-map)
+      (func)
+      (finally
+        (root-bind old-vals)))))
+
+(defmacro with-redefs
+  "binding => var-symbol temp-value-expr
+
+  Temporarily redefines Vars while executing the body.  The
+  temp-value-exprs will be evaluated and each resulting value will
+  replace in parallel the root value of its Var.  After the body is
+  executed, the root values of all the Vars will be set back to their
+  old values.  These temporary changes will be visible in all threads.
+  Useful for mocking out functions during testing."
+  {:added "1.3"}
+  [bindings & body]
+  `(with-redefs-fn ~(zipmap (map #(list `var %) (take-nth 2 bindings))
+                            (take-nth 2 (next bindings)))
+                    (fn [] ~@body)))


STORM-130: Supervisor getting killed due to java.io.FileNotFoundException: File '../stormconf.ser' does not exist.

--- storm-core/src/clj/backtype/storm/daemon/supervisor.clj
+++ storm-core/src/clj/backtype/storm/daemon/supervisor.clj
@@ -43,7 +43,7 @@

 (defn- assignments-snapshot [storm-cluster-state callback assignment-versions]
   (let [storm-ids (.assignments storm-cluster-state callback)]
-    (let [new-assignments
+    (let [new-assignments
           (->>
            (dofor [sid storm-ids]
                   (let [recorded-version (:version (get assignment-versions sid))]
@@ -263,7 +263,7 @@
         (worker-launcher-and-wait conf user ["signal" pid "9"] :log-prefix (str "kill -9 " pid))
         (force-kill-process pid))
       (if as-user
-        (rmr-as-user conf id user (worker-pid-path conf id pid))
+        (rmr-as-user conf id user (worker-pid-path conf id pid))
         (try
           (rmpath (worker-pid-path conf id pid))
           (catch Exception e)))) ;; on windows, the supervisor may still holds the lock on the worker directory
@@ -271,7 +271,7 @@
   (log-message "Shut down " (:supervisor-id supervisor) ":" id))

 (def SUPERVISOR-ZK-ACLS
-  [(first ZooDefs$Ids/CREATOR_ALL_ACL)
+  [(first ZooDefs$Ids/CREATOR_ALL_ACL)
    (ACL. (bit-or ZooDefs$Perms/READ ZooDefs$Perms/CREATE) ZooDefs$Ids/ANYONE_ID_UNSAFE)])

 (defn supervisor-data [conf shared-context ^ISupervisor isupervisor]
@@ -360,7 +360,7 @@
             cached-assignment-info @(:assignment-versions supervisor)
             assignment-info (if (and (not-nil? cached-assignment-info) (contains? cached-assignment-info storm-id ))
                               (get cached-assignment-info storm-id)
-                              (.assignment-info-with-version storm-cluster-state storm-id nil))
+                              (.assignment-info-with-version storm-cluster-state storm-id nil))
 	    storm-code-map (read-storm-code-locations assignment-info)
             master-code-dir (if (contains? storm-code-map :data) (storm-code-map :data))
             stormroot (supervisor-stormdist-root conf storm-id)]
@@ -371,20 +371,27 @@
     (wait-for-workers-launch
      conf
      (dofor [[port assignment] reassign-executors]
-       (let [id (new-worker-ids port)]
-         (log-message "Launching worker with assignment "
-                      (pr-str assignment)
-                      " for this supervisor "
-                      (:supervisor-id supervisor)
-                      " on port "
-                      port
-                      " with id "
-                      id
-                      )
-         (launch-worker supervisor
-                        (:storm-id assignment)
-                        port
-                        id)
+            (let [id (new-worker-ids port)]
+              (try
+                (log-message "Launching worker with assignment "
+                             (pr-str assignment)
+                             " for this supervisor "
+                             (:supervisor-id supervisor)
+                             " on port "
+                             port
+                             " with id "
+                             id
+                             )
+                (launch-worker supervisor
+                               (:storm-id assignment)
+                               port
+                               id)
+                (catch java.io.FileNotFoundException e
+                  (log-message "Unable to launch worker due to "
+                               (.getMessage e)))
+                (catch java.io.IOException e
+                  (log-message "Unable to launch worker due to "
+                               (.getMessage e))))
          id)))
     ))


Updating for spatial refactoring.

Updating for spatial refactoring.

--- src/cmr/indexer/data/concepts/spatial.clj
+++ src/cmr/indexer/data/concepts/spatial.clj
@@ -3,16 +3,17 @@
   (:require [cmr.spatial.derived :as d]

             ;; Must be required for derived calculations
-            [cmr.spatial.ring :as r]
+            [cmr.spatial.geodetic-ring :as gr]
             [cmr.spatial.polygon :as p]
             [cmr.spatial.mbr :as mbr]
             [cmr.spatial.lr-binary-search :as lr]
             [cmr.spatial.serialize :as srl]
-            [cmr.common.services.errors :as errors]))
+            [cmr.common.services.errors :as errors]
+            [cmr.umm.spatial :as umm-s]))

 (def temporary-supported-cartesian-types
   "A temporary list of the subset of spatial types that we support."
-  #{cmr.spatial.mbr.Mbr cmr.spatial.point.Point})
+  #{cmr.spatial.mbr.Mbr cmr.spatial.point.Point cmr.spatial.polygon.Polygon})

 (defn mbr->elastic-attribs
   [prefix mbr]
@@ -30,8 +31,9 @@
 (defn shapes->elastic-doc
   "Converts a spatial shapes into the nested elastic attributes"
   [shapes coordinate-system]
-  ;; ignores coordinate system for now
-  (let [shapes (map d/calculate-derived shapes)
+  (let [shapes (map d/calculate-derived
+                    (map (partial umm-s/set-coordinate-system coordinate-system)
+                         shapes))
         ords-info-map (srl/shapes->ords-info-map shapes)
         lrs (map srl/shape->lr shapes)
         ;; union mbrs to get one covering the whole area


Add ability to input comma in gas inputs

--- src/status_im/utils/money.cljs
+++ src/status_im/utils/money.cljs
@@ -30,7 +30,7 @@
 (defn bignumber [n]
   (when n
     (try
-      (dependencies/Web3.prototype.toBigNumber (str n))
+      (dependencies/Web3.prototype.toBigNumber (normalize (str n)))
       (catch :default err nil))))

 (defn valid? [bn]


CMR-5433: Fixed index set granule mappings test.

--- system-int-test/resources/index_set_granule_mapping.clj
+++ system-int-test/resources/index_set_granule_mapping.clj
@@ -258,4 +258,13 @@
  :project-refs.lowercase {:index "not_analyzed",
                           :type "string"},
  :end-lat {:store "yes", :type "double"},
- :lr-west-doc-values {:doc_values true, :type "float"}}
+ :lr-west-doc-values {:doc_values true, :type "float"}
+ :cycle {:type "integer"},
+ :passes
+ {:properties
+  {:pass {:type "integer"},
+   :tiles {:type "string", :index "not_analyzed"}},
+  :type "nested",
+  :_all {:enabled false},
+  :dynamic "strict",
+  :_source {:enabled false}}}


refactored schema in analytics

refactored schema in analytics

--- src-cljs/frontend/analytics.cljs
+++ src-cljs/frontend/analytics.cljs
@@ -14,15 +14,19 @@
             [goog.style]
             [goog.string :as gstr]))

-(def AnalyticsEvent
+(def CoreAnalyticsEvent
   {:event-type s/Keyword
-   :owner s/Any
    (s/optional-key :properties) (s/maybe {s/Keyword s/Any})})

+(def AnalyticsEvent
+  (merge
+    CoreAnalyticsEvent
+    {:owner s/Any}))
+
 (def AnalyticsEventForControllers
-  (-> AnalyticsEvent
-      (dissoc :owner)
-      (merge {:current-state {s/Any s/Any}})))
+  (merge
+    CoreAnalyticsEvent
+    {:current-state {s/Any s/Any}}))

 (def PageviewEvent
   (merge
@@ -81,19 +85,15 @@
     :project-unfollowed})

 (defn- add-properties-to-track-from-state [current-state]
-  "Get a dict of the mutable properties we want to track out of the
+  "Get a map of the mutable properties we want to track out of the
   state. Also add a timestamp."
-  (let [view (get-in current-state state/current-view-path)
-        user (get-in current-state state/user-login-path)
-        repo (get-in current-state state/navigation-repo-path)
-        org (get-in current-state state/navigation-org-path)]
-    {:user user
-     :view view
-     :org org
-     :repo repo}))
+  {:user (get-in current-state state/user-login-path)
+   :view (get-in current-state state/current-view-path)
+   :repo (get-in current-state state/navigation-repo-path)
+   :org (get-in current-state state/navigation-org-path)})

 (defn- add-properties-to-track-from-owner [owner]
-  "Get a dict of the mutable properties we want to track out of the
+  "Get a map of the mutable properties we want to track out of the
   owner."
   (let [app-state @(om/get-shared owner [:_app-state-do-not-use])]
     (add-properties-to-track-from-state app-state)))


trying to fix etcd2 config

trying to fix etcd2 config

--- src/terraboot/cluster.clj
+++ src/terraboot/cluster.clj
@@ -18,7 +18,6 @@
                     {:name "cadvisor.service" :command "start" :content (snippet "systemd/cadvisor.service") :enable true}
                     {:name "docker-cleanup.service" :command "start" :content (snippet "systemd/docker-cleanup.service")}
                     {:name "docker-cleanup.timer" :command "start" :content (snippet "systemd/docker-cleanup.timer") :enable true}
-                    {:name "etcd2.service" :command "start" :enable "true"}
                     {:name "install-confd.service" :command "start" :content (snippet "systemd/install-confd.service")}
                     {:name "confd.service" :command "start" :enable true :content (snippet "systemd/confd.service")}]
             :update {:reboot-strategy "off"}}


added category list to global word include

--- src/distillery/view/word.clj
+++ src/distillery/view/word.clj
@@ -1,7 +1,7 @@
 (ns distillery.view.word
   (:require [clojure.string :as string])
   (:require [net.cgrand.enlive-html :as eh])
-  (:require [distillery.data :refer [key-comp]])
+  (:require [distillery.data :refer [key-comp any?]])
   (:require [distillery.files :refer :all])
   (:require [distillery.view.html :refer :all])
   (:require [distillery.view.transcript :as transcript]))
@@ -47,8 +47,28 @@
     (ulist (map (partial render-video-list-item word-id) videos))))

 (defn- render-word-category-list
-  [{:keys [word] :as args}]
-  (TODO "Word Category List"))
+  [{:keys [categories word] :as args}]
+  (let [word-id (:id word)
+        tmp (map
+             (fn [{:keys [matches] :as category}]
+                (vals matches))
+             categories)
+        cats (filter
+              (fn [{:keys [matches] :as category}]
+                (any?
+                 (fn [{:keys [word-scores] :as match}]
+                   (contains? (set (keys word-scores)) word-id))
+                 (vals matches)))
+              categories)
+        items (map
+               (fn [{:keys [id name] :as category}]
+                 (list-item
+                  (link (str "categories/" id "/index.html?word=" word-id)
+                        name)))
+               cats)]
+    (if (> (count items) 0)
+      (ulist items)
+      (paragraph "Dieses Wort kommt in keiner Kategorie vor."))))

 (defn- render-category-word-video-list
   [{:keys [videos category word] :as args}]


Added inject-configuration middleware into ring app

--- src/emender_service/core.clj
+++ src/emender_service/core.clj
@@ -1,3 +1,15 @@
+;
+;  (C) Copyright 2016  Pavel Tisnovsky
+;
+;  All rights reserved. This program and the accompanying materials
+;  are made available under the terms of the Eclipse Public License v1.0
+;  which accompanies this distribution, and is available at
+;  http://www.eclipse.org/legal/epl-v10.html
+;
+;  Contributors:
+;      Pavel Tisnovsky
+;
+
 (ns emender-service.core
     "Core module that contains -main function called by Leiningen to start the application.")

@@ -7,7 +19,9 @@

 (require '[clojure.tools.cli       :as cli])

-(require '[emender-service.server  :as server])
+(require '[emender-service.server      :as server])
+(require '[emender-service.config      :as config])
+(require '[emender-service.middleware  :as middleware])

 (def default-port
     "3000")
@@ -17,9 +31,13 @@
     ;; an option with a required argument
     [["-p" "--port   PORT"    "port number"   :id :port]])

+; we need to load the configuration in advance so the 'app' could use it
+(def configuration (config/load-configuration "emender-service.ini"))
+
 (def app
     "Definition of a Ring-based application behaviour."
     (-> server/handler            ; handle all events
+        (middleware/inject-configuration configuration) ; inject configuration structure into the parameter
         cookies/wrap-cookies      ; we need to work with cookies
         http-params/wrap-params)) ; and to process request parameters, of course


Rename namespace

Rename namespace

--- test/hundred_pushups/doo_runner.cljs
+++ test/hundred_pushups/doo_runner.cljs
@@ -1,4 +1,4 @@
-(ns hundred-pushups.node-runner
+(ns hundred-pushups.doo-runner
   (:require [doo.runner :refer-macros [doo-tests]]
             [hundred-pushups.datetime-test]
             [hundred-pushups.db-test]


Yet another test

Yet another test

--- test/buildviz/pipelineinfo_test.clj
+++ test/buildviz/pipelineinfo_test.clj
@@ -49,4 +49,12 @@
                                   {:start 30 :end 40 :outcome "fail" :job "a job"}
                                   {:start 50 :end 60 :outcome "fail" :job "another job"}
                                   {:start 70 :end 80 :outcome "pass" :job "another job"}
-                                  {:start 90 :end 100 :outcome "pass" :job "a job"}])))))
+                                  {:start 90 :end 100 :outcome "pass" :job "a job"}])))
+    (is (= [{:start 30 :end 130 :culprits #{"a job", "another job", "yet another job"}}]
+           (pipeline-fail-phases [{:start 10 :end 20 :outcome "pass" :job "a job"}
+                                  {:start 30 :end 40 :outcome "fail" :job "a job"}
+                                  {:start 50 :end 60 :outcome "fail" :job "another job"}
+                                  {:start 70 :end 80 :outcome "pass" :job "another job"}
+                                  {:start 90 :end 100 :outcome "fail" :job "yet another job"}
+                                  {:start 110 :end 120 :outcome "pass" :job "yet another job"}
+                                  {:start 130 :end 140 :outcome "pass" :job "a job"}])))))


Fix clojure tests.

Fix clojure tests.

--- test/cats/monad/exception_spec.cljx
+++ test/cats/monad/exception_spec.cljx
@@ -54,7 +54,7 @@
   #+clj
   (t/testing "Test try-or-else macro"
     (let [m1 (exc/try-or-else (+ 1 nil) 40)]
-      (s/should (exc/success? m1))
+      (t/is (exc/success? m1))
       (t/is (= 40 (exc/from-try m1)))))

   #+clj


fixing tests and adding envs validation check

--- test/celestial/test/persistency.clj
+++ test/celestial/test/persistency.clj
@@ -38,7 +38,9 @@
 (fact "user validation"
      (validate-user {:username "foo" :password "bar" :roles admin :envs []})  => truthy
      (validate-user {:password "bar" :roles admin :envs []})  =>
-       (throws ExceptionInfo (with-m? {:username '("must be present")} ))
+       (throws ExceptionInfo (with-m? {:username '("must be present")}))
+     (validate-user {:username "foo" :password "bar" :roles admin})  =>
+       (throws ExceptionInfo (with-m? {:envs '("must be present")}))
      (validate-user {:username "foo" :password "bar" :roles ["foo"] :envs []})  =>
        (throws ExceptionInfo (with-m? {:roles '(({0 ("role must be either #{:celestial.roles/anonymous :celestial.roles/user :celestial.roles/admin}")}))} ))
       )


Use github avatars for build invites

Use github avatars for build invites

--- frontend/components/build_invites.cljs
+++ frontend/components/build_invites.cljs
@@ -23,14 +23,12 @@
   (reify
     om/IRender
     (render [_]
-      (let [{:keys [gravatar_id email login index]} user
+      (let [{:keys [avatar_url email login index]} user
             controls-ch (om/get-shared owner [:comms :controls])]
         (html
          [:li
           [:div.invite-gravatar
-           [:img {:src (gh-utils/gravatar-url {:gravatar_id gravatar_id
-                                               :login login
-                                               :size 200})}]]
+           [:img {:src avatar_url}]]
           [:div.invite-profile
            login
            [:input {:on-change #(utils/edit-input controls-ch (conj (state/build-github-user-path index) :email) %)


Fix typo on postgresql.clj

Fix typo on postgresql.clj

--- src/continuo/postgresql.clj
+++ src/continuo/postgresql.clj
@@ -38,6 +38,6 @@
 (defmethod impl/connect :postgresql
   [uri options]
   (let [options (merge options (util/parse-params uri))
-        connection (bootstrap/connec options)
+        connection (bootstrap/connect options)
         schema {}]
     (Transactor. connection schema)))


Shuffle data since order should not matter.

--- test/onyx/peer/kw_grouping_test.clj
+++ test/onyx/peer/kw_grouping_test.clj
@@ -81,52 +81,53 @@
 (def size 3000)

 (def data
-  (concat
-   (map (fn [_] {:name "Mike" :amount 10}) (range size))
-   (map (fn [_] {:name "Dorrene" :amount 10}) (range size))
-   (map (fn [_] {:name "Benti" :amount 10}) (range size))
-   (map (fn [_] {:name "John" :amount 10}) (range size))
-   (map (fn [_] {:name "Shannon" :amount 10}) (range size))
-   (map (fn [_] {:name "Kristen" :amount 10}) (range size))
-   (map (fn [_] {:name "Benti" :amount 10}) (range size))
-   (map (fn [_] {:name "Mike" :amount 10}) (range size))
-   (map (fn [_] {:name "Steven" :amount 10}) (range size))
-   (map (fn [_] {:name "Dorrene" :amount 10}) (range size))
-   (map (fn [_] {:name "John" :amount 10}) (range size))
-   (map (fn [_] {:name "Shannon" :amount 10}) (range size))
-   (map (fn [_] {:name "Santana" :amount 10}) (range size))
-   (map (fn [_] {:name "Roselyn" :amount 10}) (range size))
-   (map (fn [_] {:name "Krista" :amount 10}) (range size))
-   (map (fn [_] {:name "Starla" :amount 10}) (range size))
-   (map (fn [_] {:name "Derick" :amount 10}) (range size))
-   (map (fn [_] {:name "Orlando" :amount 10}) (range size))
-   (map (fn [_] {:name "Rupert" :amount 10}) (range size))
-   (map (fn [_] {:name "Kareem" :amount 10}) (range size))
-   (map (fn [_] {:name "Lesli" :amount 10}) (range size))
-   (map (fn [_] {:name "Carol" :amount 10}) (range size))
-   (map (fn [_] {:name "Willie" :amount 10}) (range size))
-   (map (fn [_] {:name "Noriko" :amount 10}) (range size))
-   (map (fn [_] {:name "Corine" :amount 10}) (range size))
-   (map (fn [_] {:name "Leandra" :amount 10}) (range size))
-   (map (fn [_] {:name "Chadwick" :amount 10}) (range size))
-   (map (fn [_] {:name "Teressa" :amount 10}) (range size))
-   (map (fn [_] {:name "Tijuana" :amount 10}) (range size))
-   (map (fn [_] {:name "Verna" :amount 10}) (range size))
-   (map (fn [_] {:name "Alona" :amount 10}) (range size))
-   (map (fn [_] {:name "Wilson" :amount 10}) (range size))
-   (map (fn [_] {:name "Carly" :amount 10}) (range size))
-   (map (fn [_] {:name "Nubia" :amount 10}) (range size))
-   (map (fn [_] {:name "Hollie" :amount 10}) (range size))
-   (map (fn [_] {:name "Allison" :amount 10}) (range size))
-   (map (fn [_] {:name "Edwin" :amount 10}) (range size))
-   (map (fn [_] {:name "Zola" :amount 10}) (range size))
-   (map (fn [_] {:name "Britany" :amount 10}) (range size))
-   (map (fn [_] {:name "Courtney" :amount 10}) (range size))
-   (map (fn [_] {:name "Mathew" :amount 10}) (range size))
-   (map (fn [_] {:name "Luz" :amount 10}) (range size))
-   (map (fn [_] {:name "Tyesha" :amount 10}) (range size))
-   (map (fn [_] {:name "Eusebia" :amount 10}) (range size))
-   (map (fn [_] {:name "Fletcher" :amount 10}) (range size))))
+  (shuffle
+    (concat
+      (map (fn [_] {:name "Mike" :amount 10}) (range size))
+      (map (fn [_] {:name "Dorrene" :amount 10}) (range size))
+      (map (fn [_] {:name "Benti" :amount 10}) (range size))
+      (map (fn [_] {:name "John" :amount 10}) (range size))
+      (map (fn [_] {:name "Shannon" :amount 10}) (range size))
+      (map (fn [_] {:name "Kristen" :amount 10}) (range size))
+      (map (fn [_] {:name "Benti" :amount 10}) (range size))
+      (map (fn [_] {:name "Mike" :amount 10}) (range size))
+      (map (fn [_] {:name "Steven" :amount 10}) (range size))
+      (map (fn [_] {:name "Dorrene" :amount 10}) (range size))
+      (map (fn [_] {:name "John" :amount 10}) (range size))
+      (map (fn [_] {:name "Shannon" :amount 10}) (range size))
+      (map (fn [_] {:name "Santana" :amount 10}) (range size))
+      (map (fn [_] {:name "Roselyn" :amount 10}) (range size))
+      (map (fn [_] {:name "Krista" :amount 10}) (range size))
+      (map (fn [_] {:name "Starla" :amount 10}) (range size))
+      (map (fn [_] {:name "Derick" :amount 10}) (range size))
+      (map (fn [_] {:name "Orlando" :amount 10}) (range size))
+      (map (fn [_] {:name "Rupert" :amount 10}) (range size))
+      (map (fn [_] {:name "Kareem" :amount 10}) (range size))
+      (map (fn [_] {:name "Lesli" :amount 10}) (range size))
+      (map (fn [_] {:name "Carol" :amount 10}) (range size))
+      (map (fn [_] {:name "Willie" :amount 10}) (range size))
+      (map (fn [_] {:name "Noriko" :amount 10}) (range size))
+      (map (fn [_] {:name "Corine" :amount 10}) (range size))
+      (map (fn [_] {:name "Leandra" :amount 10}) (range size))
+      (map (fn [_] {:name "Chadwick" :amount 10}) (range size))
+      (map (fn [_] {:name "Teressa" :amount 10}) (range size))
+      (map (fn [_] {:name "Tijuana" :amount 10}) (range size))
+      (map (fn [_] {:name "Verna" :amount 10}) (range size))
+      (map (fn [_] {:name "Alona" :amount 10}) (range size))
+      (map (fn [_] {:name "Wilson" :amount 10}) (range size))
+      (map (fn [_] {:name "Carly" :amount 10}) (range size))
+      (map (fn [_] {:name "Nubia" :amount 10}) (range size))
+      (map (fn [_] {:name "Hollie" :amount 10}) (range size))
+      (map (fn [_] {:name "Allison" :amount 10}) (range size))
+      (map (fn [_] {:name "Edwin" :amount 10}) (range size))
+      (map (fn [_] {:name "Zola" :amount 10}) (range size))
+      (map (fn [_] {:name "Britany" :amount 10}) (range size))
+      (map (fn [_] {:name "Courtney" :amount 10}) (range size))
+      (map (fn [_] {:name "Mathew" :amount 10}) (range size))
+      (map (fn [_] {:name "Luz" :amount 10}) (range size))
+      (map (fn [_] {:name "Tyesha" :amount 10}) (range size))
+      (map (fn [_] {:name "Eusebia" :amount 10}) (range size))
+      (map (fn [_] {:name "Fletcher" :amount 10}) (range size)))))

 (doseq [x data]
   (>!! in-chan x))


Fix formatting [ci skip]

Fix formatting [ci skip]

--- test/provisdom/spectomic/t_core.clj
+++ test/provisdom/spectomic/t_core.clj
@@ -132,12 +132,12 @@
 (s/def ::foo (s/multi-spec foo :foo))
 (deftest datomic-schema*-valueType-test
   (are [schema specs] (= schema (spectomic/datomic-schema* specs))
-                      [{:db/ident       ::string
-                        :db/valueType   :db.type/keyword
-                        :db/cardinality :db.cardinality/one}]
-                      [[::string {:db/valueType :db.type/keyword :db/cardinality :db.cardinality/one}]]))
+    [{:db/ident       ::string
+      :db/valueType   :db.type/keyword
+      :db/cardinality :db.cardinality/one}]
+    [[::string {:db/valueType :db.type/keyword :db/cardinality :db.cardinality/one}]]))

 (deftest datascript-schema*-valueType-test
   (are [schema specs] (= schema (spectomic/datascript-schema* specs))
-                      {::string {:db/valueType   :db.type/keyword :db/cardinality :db.cardinality/one}}
-                      [[::string {:db/valueType :db.type/keyword :db/cardinality :db.cardinality/one}]]))+    {::string {:db/valueType :db.type/keyword :db/cardinality :db.cardinality/one}}
+    [[::string {:db/valueType :db.type/keyword :db/cardinality :db.cardinality/one}]]))


Dropout documentation

Dropout documentation

--- src/cortex/impl/layers.cljc
+++ src/cortex/impl/layers.cljc
@@ -49,13 +49,14 @@

 ;; DROPOUT
 ;; Module implementing "dropout" functionality when training
+;; dropout field stores 0.0 or 1.0/probability as multiplicative noise
 ;; Works as a identity function otherwise
 #?(:cljs (register-module cortex.impl.layers.Dropout))
 (defrecord Dropout [output input-gradient ^double probability dropout]
   cp/PModule
     (calc [this input]
       (m/assign! output input)
-       this)
+      this)

     (output [this]
       (:output this))


Make SPARQL functions public

Make SPARQL functions public

--- src/db_quiz_prep/sparql.clj
+++ src/db_quiz_prep/sparql.clj
@@ -43,17 +43,19 @@
             (println body)
             (throw+)))))

-(defn- execute-query
+; ----- Public functions -----
+
+(defn execute-query
   [config sparql-string]
   (execute-sparql config :GET sparql-string))

-(defn- execute-update
+(defn execute-update
   "Execute a SPARQL Update operation."
   [config sparql-string]
   (execute-sparql config :POST sparql-string))

-(defn- select
-  "Execute SPARQL SELECT query.
+(defn select
+  "Execute SPARQL SELECT query.
   Returns empty sequence when query has no results."
   [config sparql-string]
   (let [results (xml->zipper (execute-query config sparql-string))
@@ -62,29 +64,31 @@
         get-bindings (comp (partial zipmap sparql-variables) #(zip-xml/xml-> % :binding zip-xml/text))]
     (map get-bindings sparql-results)))

-; ----- Public functions -----
-
 (defn execute-unlimited-select-query
   "Lazily stream pages of SPARQL SELECT query results
   by executing paged query from `sparql-template`"
-  [{:keys [page-size params start-from] :as config} sparql-template]
+  [{:keys [page-size params start-from] :as config} sparql-template & {:keys [data]}]
   (letfn [(paged-select [offset]
             (println (format "Executing SELECT query with offset %s..." offset))
             (select config (render-string sparql-template
                                           (merge {:limit page-size
-                                                  :offset offset} params))))]
+                                                  :offset offset}
+                                                 params
+                                                 data))))]
     (->> (iterate (partial + page-size) 0)
          (map paged-select)
          (take-while seq)
          lazy-cat')))

 (defn execute-unlimited-update
-  [{:keys [page-size params start-from] :as config} sparql-template]
+  [{:keys [page-size params start-from] :as config} sparql-template & {:keys [data]}]
   (let [message-regex (re-pattern #"(\d+)( \(or less\))? triples")
         update-fn (fn [offset]
                     (let [sparql (render-string sparql-template
                                                 (merge {:limit page-size
-                                                        :offset offset} params))]
+                                                        :offset offset}
+                                                       params
+                                                       data))]
                       (println (format "Executing update operation with offset %s..." offset))
                       (execute-update config sparql)))
         triples-changed (comp (fn [number-like]


Fix NPE when ship not found.

Fix NPE when ship not found.

--- src/viewer/model/ship.clj
+++ src/viewer/model/ship.clj
@@ -8,7 +8,7 @@
    (ds/query :kind Ship)))

 (defn put-ship [name data]
-  (let [s (Ship. name data)]
+  (let [s (Ship. name (ds/as-text (pr-str data)))]
     (ds/save! s)
     name))

@@ -18,6 +18,8 @@
        ships))

 (defn get-ship [name]
-  (first (ds/query :kind Ship :filter (= :name name))))
+  (let [ship (first (ds/query :kind Ship :filter (= :name name)))]
+    (if (not (nil? ship))
+      {:name (:name ship) :data (read-string (.getValue (:data ship)))})))


Searches should now be case insensitive.

--- src/viewer/model/ship.clj
+++ src/viewer/model/ship.clj
@@ -1,5 +1,6 @@
 (ns viewer.model.ship
-  (:require [appengine-magic.services.datastore :as ds]))
+  (:require [appengine-magic.services.datastore :as ds]
+            [clojure.string :refer [upper-case]]))

 (ds/defentity Ship [^{:tag :key} name, ^{:tag :clj} data])

@@ -8,7 +9,7 @@
    (ds/query :kind Ship)))

 (defn put-ship [name data]
-  (let [s (Ship. name (ds/as-text (pr-str data)))]
+  (let [s (Ship. (upper-case name) (ds/as-text (pr-str data)))]
     (ds/save! s)
     name))

@@ -18,7 +19,7 @@
        ships))

 (defn get-ship [name]
-  (let [ship (first (ds/query :kind Ship :filter (= :name name)))]
+  (let [ship (first (ds/query :kind Ship :filter (= :name (upper-case name))))]
     (if (not (nil? ship))
       {:name (:name ship) :data (read-string (.getValue (:data ship)))})))


remove duplication by using update-in instead of constructing the list again.

--- clojure/robot-name/robot.clj
+++ clojure/robot-name/robot.clj
@@ -1,11 +1,11 @@
 (ns robot)

 (def id-seq (ref 0))
-(def name-seq (ref (list "A" "A" 0)))
+(def name-seq (ref ["A" "A" 0]))
 (def robots (ref {}))

 (defn- inc-name-seq [curr-seq]
-  (list "A" "A" (inc (last curr-seq))))
+  (update-in curr-seq [2] inc))

 (defn- format-name [name]
   (apply format "%s%s%03d" name))


Make lava and mountains non-traversable

Make lava and mountains non-traversable

--- src/robinson/world.clj
+++ src/robinson/world.clj
@@ -287,6 +287,8 @@
   (contains? #{:vertical-wall
                :horizontal-wall
                :fire
+               :lava
+               :mountain
                :close-door
                :tree
                :bamboo


WIP: add assert

WIP: add assert

--- src/graphql_clj/executor.clj
+++ src/graphql_clj/executor.clj
@@ -28,17 +28,15 @@

 (defn get-selection-name
   [selection]
-  (log/debug "get-selection-name: " selection)
-  (let [name (or (get-in selection [:selection :field :name])
+  (assert (:selection selection) (format "Not a valid selection: %s." selection))
+  (if-let [name (or (get-in selection [:selection :field :name])
                  (get-in selection [:selection :fragment-spread :fragment-name]))]
-    (log/debug "get-selection-name: name: " name)
-    (if name
-      name
-      (throw (ex-info (format "Selection Name is null for selection: %s." selection)
-                      {:selection selection})))))
+    name
+    (throw (ex-info (format "Selection Name is null for selection: %s." selection)
+                    {:selection selection}))))

 (defn get-selection-type [selection]
-  (log/debug "get-selection-type: selection: " selection)
+  (assert (:selection selection) (format "Not a valid selection: %s." selection))
   (let [opts (:selection selection)]
     (cond
       (:field opts) :field
@@ -48,23 +46,17 @@
                                 :opts opts})))))

 (defn get-field-selection-set [selection]
-  (log/debug "*** get-field-selection-set: selection: " selection)
+  (assert (:selection selection) (format "Not a valid selection: %s." selection))
   (let [opts (:selection selection)
         selection-set (get-in opts [:field :selection-set])]
-    (log/debug "field: " opts)
     (log/debug "get-field-selection-set: selection-set: " selection-set)
     selection-set))

 (defn expand-fragment [fragment-name fragments]
-  (log/debug "expand-fragment: " fragment-name)
-  (log/debug "expand-fragment: fragments: " fragments)
   (let [fragment (get fragments fragment-name)
         selection-set (:selection-set fragment)]
-    (if fragment
-      selection-set
-      (throw (ex-info (format "expand-fragment: cannot find fragment(%s)." fragment-name)
-                      {:fragment-name fragment-name
-                       :fragments fragments})))))
+    (assert fragment (format "Cannot found fragment: %s." fragment-name))
+    selection-set))

 (defn collect-selection-fn
   [fragments]


Import java.io.File

Import java.io.File

--- src/grimoire/api/fs/read.clj
+++ src/grimoire/api/fs/read.clj
@@ -10,9 +10,10 @@
             [grimoire.api.fs.impl :as impl]
             [clojure.java.io :as io]
             [clojure.string :as string]
-            [cemerick.url :as url]))
-
-(defn- f->name [^java.io.File f]
+            [cemerick.url :as url])
+  (:import [java.io File]))
+
+(defn- f->name [^File f]
   (url/url-decode (.getName f)))

 ;; List things
@@ -121,7 +122,7 @@
           ;; versions is a Fail, pass it down
           versions))

-      (let [^java.io.File h (impl/thing->notes-handle config thing)]
+      (let [^File h (impl/thing->notes-handle config thing)]
         (if (.exists h)
           (let [rhs (.toPath h)
                 p   (.relativize lhs rhs)]


small popover mods

small popover mods

--- src/re_com/popover.cljs
+++ src/re_com/popover.cljs
@@ -19,10 +19,8 @@
   [kw delimiter] ;; TODO: Possibly move to util
   "I return the vector of the two keywords formed by splitting
    another keyword 'kw' on an internal delimiter (usually '-').
-
    (split-keyword  :above-left  \"-\")
-   =>  [:above :left]
-   "
+   =>  [:above :left]"
   (let [keywords (string/split (str kw) (re-pattern (str "[" delimiter ":]")))]
     [(keyword (keywords 1)) (keyword (keywords 2))]))

@@ -70,7 +68,6 @@
                      :right (str (point arrow-length 0) (point 0 half-arrow-width)            (point arrow-length arrow-width))
                      :above (str (point 0 0)            (point half-arrow-width arrow-length) (point arrow-width 0))
                      :below (str (point 0 arrow-length) (point half-arrow-width 0)            (point arrow-width arrow-length))}]
-
     [:svg {:style {:position "absolute"
                    (case orientation ;; Connect arrow to edge of popover
                      :left  :right
@@ -118,7 +115,6 @@
        - :margin-top        [nil           ] vertical offset from anchor after position
        - :arrow-length      [11            ] length in pixels of arrow (from pointy part to middle of arrow base)
        - :arrow-width       [22            ] length in pixels of arrow base"
-
   (let [rendered-once           (reagent/atom false)
         pop-id                  (gensym "popover-")
         [orientation arrow-pos] (split-keyword position "-")
@@ -186,7 +182,6 @@
        - :backdrop-callback if specified, add a backdrop div between the main screen (including element) and the popover.
                             when clicked, this callback is called (usually to close the popover)
        - :backdrop-opacity  0 = transparent, 1 = black (http://jsfiddle.net/Rt9BJ/1)"
-
   (let [[orientation arrow-pos] (split-keyword position "-") ;; only need orientation here
         place-anchor-before?    (case orientation (:left :above) false true)
         flex-flow               (case orientation (:left :right) "row" "column")
@@ -209,8 +204,7 @@
       (when @showing?
         [:div {:style {:position "relative" :display "inline-block"}} ;; :flex-grow 0 :flex-shrink 1 :flex-basis "auto"
          [make-popover popover-params]])
-      (when-not place-anchor-before? anchor)
-      ]]))
+      (when-not place-anchor-before? anchor)]]))

 (defn make-button


Better error reporting and status reporting.

--- src/riemann/elastic.clj
+++ src/riemann/elastic.clj
@@ -128,9 +128,13 @@
                             raw)]
             (when (seq bulk-create-items)
               (try
-                (let [res (eb/bulk-with-index index bulk-create-items)]
-                  (info "elasticized" (count (:items res)) "items to index " index "in " (:took res) "ms")
-                  (info "Results: " res))
+                (let [res (eb/bulk-with-index index bulk-create-items)
+                      total (count (:items res))
+                      succ (filter :ok (:items res))
+                      failed (filter :error (:items res))]
+
+                  (info "elasticized" total "/" (count succ) "/" (count failed) " (total/succ/fail) items to index " index "in " (:took res) "ms")
+                  (debug "Failed: " failed))
                 (catch Exception e
                   (error "Unable to bulk index:" e))))))))))


language auto-detect; console messages; documentation

--- src/me/panzoo/story.clj
+++ src/me/panzoo/story.clj
@@ -25,9 +25,14 @@

 ; ## Utilities
 ;
-; A few utility functions to make it easier to iterate side-effects through a
-; collection, access resources, encode a string for use as an id or fragment
-; identifier, and bind an output stream to `*out*` over a lexical scope.
+; A few utility functions to make it easier to print messages to the console,
+; iterate side-effects through a collection, access resources, encode a string
+; for use as an id or fragment identifier, and bind an output stream to `*out*`
+; over a lexical scope.
+
+(defn message [& s]
+  (binding [*out* (io/writer System/err)]
+    (println (apply str s))))

 (defn each
   "Apply f to each item of coll in order for side effects only.
@@ -38,11 +43,27 @@

 (defn slurp-resource
   "Get the complete contents of a Java resource."
-  [resource-name]
-  (-> (.getContextClassLoader (Thread/currentThread))
-    (.getResourceAsStream resource-name)
-    (java.io.InputStreamReader.)
-    (slurp)))
+  [resource-name & continue-on-failure?]
+  (try
+    (-> (.getContextClassLoader (Thread/currentThread))
+      (.getResourceAsStream resource-name)
+      (java.io.InputStreamReader.)
+      (slurp))
+    (catch Exception e
+      (message "failed to read resource " resource-name)
+      (if continue-on-failure?
+        (message "    continuing anyway...")
+        (do (message "    aborting...")
+          (throw e))))))
+
+(defn slurp-file|resource
+  "Get the contents of the file at path, or failing that, the contents of a
+  Java resource."
+  [path & continue-on-failure?]
+  (try (slurp path)
+    (catch java.io.FileNotFoundException _
+      (message path " not found; reading as a resource instead")
+      (slurp-resource path continue-on-failure?))))

 (defn encode-anchor [s]
   (java.net.URLEncoder/encode (.replace s " " "-") "UTF-8"))
@@ -67,27 +88,81 @@
   "A string containing a single comment token."
   ";")

-(def comment
+(defn comment
   "A regular expression matching the beginning of a commented line."
-  (delay (re-pattern (str "^\\Q" *single-comment* "\\E ?"))))
-
-(def anchor
+  []
+  (re-pattern (str "^\\Q" *single-comment* "\\E ?")))
+
+(defn anchor
   "A regular expression matching the beginning of an anchor line."
-  (delay (re-pattern (str @comment "@ *"))))
-
-(def include
+  []
+  (re-pattern (str (comment) "@ *")))
+
+(defn include
   "A regular expression matching the beginning of an include line."
-  (delay (re-pattern (str @comment "%include +"))))
+  []
+  (re-pattern (str (comment) "%include +")))

 ; ### Style variables

-(def ^:dynamic *brush*
-  "Path to a SyntaxHighlighter brush file."
-  nil)
+;@language map
+(def languages
+  "A map of language names to a pairs of comment syntax and SyntaxHighlighter
+  brush file names."
+  {"clojure" [";" "shBrushClojure.js"]
+   "clj" [";" "shBrushClojure.js"]
+   "cljs" [";" "shBrushClojure.js"]
+   "applescript" ["--" "shBrushAppleScript.js"]
+   "actionscript3" ["//" "shBrushAS3.js"]
+   "as3" ["//" "shBrushAS3.js"]
+   "bash" ["#" "shBrushBash.js"]
+   "shell" ["#" "shBrushBash.js"]
+   "sh" ["#" "shBrushBash.js"]
+   ;"coldfusion" "shBrushColdFusion.js"
+   "cpp" ["//" "shBrushCpp.js"]
+   "c++" ["//" "shBrushCpp.js"]
+   "cxx" ["//" "shBrushCpp.js"]
+   "c" ["//" "shBrushCpp.js"]
+   "c#" ["//" "shBrushCSharp.js"]
+   "c-sharp" ["//" "shBrushCSharp.js"]
+   "csharp" ["//" "shBrushCSharp.js"]
+   "delphi" ["//" "shBrushDelphi.js"]
+   "pascal" ["//" "shBrushDelphi.js"]
+   ;"diff" "shBrushDiff.js"
+   ;"patch" "shBrushDiff.js"
+   "erlang" ["%" "shBrushErlang.js"]
+   "erl" ["%" "shBrushErlang.js"]
+   "groovy" ["//" "shBrushGroovy.js"]
+   "java" ["//" "shBrushJava.js"]
+   "javafx" ["//" "shBrushJavaFX.js"]
+   "jfx" ["//" "shBrushJavaFX.js"]
+   "javascript" ["//" "shBrushJScript.js"]
+   "js" ["//" "shBrushJScript.js"]
+   "perl" ["#" "shBrushPerl.js"]
+   "pl" ["#" "shBrushPerl.js"]
+   "php" ["#" "shBrushPhp.js"]
+   ;"text" "shBrushPlain.js"
+   ;"txt" "shBrushPlain.js"
+   ;"plain" "shBrushPlain.js"
+   "python" ["#" "shBrushPython.js"]
+   "py" ["#" "shBrushPython.js"]
+   "ruby" ["#" "shBrushRuby.js"]
+   "rb" ["#" "shBrushRuby.js"]
+   "sass" ["//" "shBrushSass.js"]
+   "scss" ["//" "shBrushSass.js"]
+   "scala" ["//" "shBrushScala.js"]
+   "sql" ["--" "shBrushSql.js"]
+   "vb" ["'" "shBrushVb.js"]
+   "vbnet" ["'" "shBrushVb.js"]
+   ;"xml" "shBrushXml.js"
+   ;"xhtml" "shBrushXml.js"
+   ;"xslt" "shBrushXml.js"
+   ;"html" "shBrushXml.js"
+   })

 (def ^:dynamic *theme*
   "Path to a SyntaxHighlighter theme file."
-  nil)
+  "shThemeEclipse.css")

 (def ^:dynamic *language*
   "A language string for use with SyntaxHighlighter."
@@ -135,6 +210,10 @@
       ([node url title text]
        (proxy-super render node url title text)))))

+; ### Mutable variables
+
+(def brushes (atom #{}))
+
 ; ## Parsing
 ;
 ; Each line of a source file will be either code, comment, anchor, or include.
@@ -143,11 +222,11 @@
   "Classify a line as :code or :comment. Return a pair of the classification
   and line string, sans leading comment tokens in the case of a comment."
   [line]
-  (if-let [s (re-find @include line)]
-    [:include (.substring line (count s))]
-    (if-let [s (re-find @anchor line)]
+  (if-let [s (re-find (include) line)]
+    [:include (string/split (.substring line (count s)) #"\s+")]
+    (if-let [s (re-find (anchor) line)]
       [:anchor (.substring line (count s))]
-      (if-let [s (re-find @comment line)]
+      (if-let [s (re-find (comment) line)]
         [:comment (.substring line (count s))]
         [:code line]))))

@@ -156,18 +235,18 @@

 (defn- gather-lines- [lines]
   (lazy-seq
-    (let [classfn (first (first lines))
-          [same tail] (if (#{:comment :code} classfn)
-                        (split-with #(= classfn (first %)) lines)
-                        (split-at 1 lines))
-          text (string/join "\n" (map second same))]
-      (when classfn (cons [classfn text] (gather-lines- tail))))))
+    (when-let [classfn (first (first lines))]
+      (if (#{:comment :code} classfn)
+        (let [[same tail] (split-with #(= classfn (first %)) lines)
+              text (string/join "\n" (map second same))]
+          (cons [classfn text] (gather-lines- tail)))
+        (cons (first lines) (gather-lines- (rest lines)))))))

 (defn- gather-lines [lines]
   (gather-lines- (map classify-line lines)))

 ; The result of gathering is a list of pairs of the form
-; `[<classification> <string>]`.
+; `[<classification> <data>]`.

 ; ## Rendering
 ;
@@ -182,11 +261,18 @@
 ; be determined by the largest comment or code chunk and not the total size of
 ; the source file.

-(defn render-file [tag path]
-  (with-open [r (io/reader path)]
-    (println (str "<" tag ">"))
-    (each html<- (gather-lines (line-seq r)))
-    (println (str "</" tag ">"))))
+(defn render-file [tag path & [token lang]]
+  (let [lang (or lang (re-find #"(?<=\.)[^.]+$" path))
+        token (or token (first (languages lang)))]
+    (when-let [b (and lang (second (languages lang)))]
+      (message path " auto-associated with brush " b)
+      (swap! brushes conj b))
+    (with-open [r (io/reader path)]
+      (binding [*single-comment* (or token *single-comment*)
+                *language* (or lang *language*)]
+        (println (str "<" tag ">"))
+        (each html<- (gather-lines (line-seq r)))
+        (println (str "</" tag ">"))))))

 ; Code chunks are wrapped in a `pre` with the correct incantation for
 ; SyntaxHighlighter in its `class` attribute; comments are run through the
@@ -209,8 +295,9 @@
 (defmethod html<- :anchor [[_ text]]
   (println (str "")))

-(defmethod html<- :include [[_ path]]
-  (render-file "section" path))
+(defmethod html<- :include [[_ [path & [token lang]] :as args]]
+  (let [lang (or lang (re-find #"(?<=\.)[^.]+$" path))]
+    (render-file "section" path token lang)))

 ; ## Look and feel
 ;
@@ -226,17 +313,14 @@
 ; overridden on the commandline, and an additional stylesheet can be included
 ; too.

-(defn inline-brush []
-  (inline-js
-    (if *brush*
-      (slurp *brush*)
-      (slurp-resource "shBrushClojure.js"))))
+(defn inline-brushes []
+  (message "Adding the following brushes to output:")
+  (each (partial message "    ") @brushes)
+  (each (comp inline-js #(slurp-file|resource % :continue-on-failure))
+        @brushes))

 (defn inline-theme []
-  (inline-css
-    (if *theme*
-      (slurp *theme*)
-      (slurp-resource "shThemeEclipse.css"))))
+  (inline-css (slurp-file|resource *theme* :continue-on-faliure)))

 (defn inline-stylesheet []
   (when *stylesheet*
@@ -247,7 +331,6 @@
 (defn look-and-feel []
   (inline-js (slurp-resource "XRegExp.js"))
   (inline-js (slurp-resource "shCore.js"))
-  (inline-brush)
   (inline-theme)
   (inline-js (slurp-resource "outliner.0.5.0.62.js"))
   (inline-css (slurp-resource "page.css"))
@@ -300,6 +383,7 @@
 ; file's rendering is wrapped in its own `article` tags.

   (each (partial render-file "article") paths)
+  (inline-brushes)
   (javascript-setup))

 ; The output stream can be a file or standard output or anything
@@ -309,18 +393,31 @@
   (with-out-stream out
     (render-files in-paths)))

+;@commandline
+;
 ; ## Commandline
 ;
 ; Use this program from the commandline like so.

-;@commandline entry point
 (def usage "Usage: java -jar story.jar [options] <input-files>")

 (defn -main [& args]
   (let [[amap tail banner]
         (cli/cli args
+
+; For the brush, theme, and stylesheet options the program first tries to read
+; from the filesystem and if that fails because the file is not found the
+; an attempt is made to read from the program's resources. The resources
+; contain the standard SyntaxHighlighter brushes and themes under their normal
+; file names including an additional `shBrushClojure.js` and
+; `shThemeClojure.css`.
+;
+; Multiple brushes can be used by repeating the `-b` or `--brush` options.
+; Additional brushes may be added by the program as a result of file includes
+; and file suffixes.
+
                  ["-c" "--comment" "Comment syntax" :default ";"]
-                 ["-b" "--brush" "SyntaxHighlighter brush file"]
+                 ["-b" "--brush" "SyntaxHighlighter brush file" :multi true]
                  ["-t" "--theme" "SyntaxHighlighter theme file"]
                  ["-l" "--language" "SyntaxHighlighter language"]
                  ["-s" "--stylesheet" "A stylesheet file to include"]
@@ -329,10 +426,10 @@
       (do (println usage banner)
         (System/exit 1))
       (binding [*single-comment* (:comment amap)
-                *brush* (:brush amap)
                 *theme* (:theme amap)
                 *language* (or (:language amap) *language*)
                 *stylesheet* (:stylesheet amap)]
+        (swap! brushes #(or (set (:brush amap)) %))

 ; When no output file is given, the program renders to standard-out.


complete static language titles

complete static language titles

--- src/solar_system_of_js/core.cljs
+++ src/solar_system_of_js/core.cljs
@@ -320,18 +320,30 @@
     )
   (restore!))

+(defn draw-static-text!
+  [{:keys [alpha]} text y]
+  (when-not (zero? alpha)
+    (save!)
+    (global-alpha! alpha)
+    (text-baseline! "middle")
+    (text-align! "left")
+    (font! "100 100px Roboto")
+    (fill-style! "#FFF")
+    (fill-text! text 800 y)
+    (restore!)))
+
 (defn draw-typescript!
-  [{:keys [alpha]}]
-  (when-not (zero? alpha)
-    nil))
+  [opts]
+  (draw-static-text! opts "TYPESCRIPT" 0))
+
+(defn draw-flow!
+  [opts]
+  (draw-static-text! opts "FLOW" 100))

 (defn draw-soundscript!
   [opts]
-  )
-
-(defn draw-flow!
-  [opts]
-  )
+  (draw-static-text! opts "SOUNDSCRIPT" 200))
+

 (defn draw-staticsphere!
   [{:keys [angle alpha r]}]
@@ -341,7 +353,7 @@
     (circle! 0 0 r)
     (fill-style! "#BCC")
     (fill!)
-
+
     ;; draw the arc
     (let [a (/ PI 2)
           da (/ (* 2 PI) 3)
@@ -625,7 +637,8 @@
               {:a :_ :b 1 :duration 1} [:static :sphere :alpha]
               {:a :_ :b 400 :duration 1} [:static :sphere :r])))

-     (let [angle (/ (* 2 PI) 3)]
+     (let [angle (/ (* 2 PI) 3) ;; arc angle
+           low 0.2]             ;; alpha of faded out title
        [;; show typescript
         #(go
            (<! (multi-animate!
@@ -636,16 +649,16 @@

         ;; show flow
         #(go
+           (swap! state assoc-in [:static :typescript :alpha] low)
            (<! (multi-animate!
                  {:a :_ :b 1 :duration 1} [:static :flow :alpha]
-                 {:a :_ :b 0.5 :duration 1} [:static :typescript :alpha]
                  {:a :_ :b (* 2 angle) :duration 1} [:static :sphere :angle]
                  )))

         ;; show soundscript
         #(go
+           (swap! state assoc-in [:static :flow :alpha] low)
            (<! (multi-animate!
-                 {:a :_ :b 0.5 :duration 1} [:static :flow :alpha]
                  {:a :_ :b 1 :duration 1} [:static :soundscript :alpha]
                  {:a :_ :b (* 3 angle) :duration 1} [:static :sphere :angle]
                  )))])


revise caption wording, and add new caption

--- src/solar_system_of_js/core.cljs
+++ src/solar_system_of_js/core.cljs
@@ -874,7 +874,7 @@
      #(go
         (swap! state assoc :caption
                (html [:div
-                      "Thus, the modern view of JS development must include these tools as an effective foundation."
+                      "Thus, anyone using JS directly today must use some combination of these tools as foundation for the language."
                       ]))
         (swap! state assoc-in [:modulesys :highlight] false)
         (let [t 2]
@@ -940,7 +940,7 @@
                          [:a {:href "http://flowtype.org/"
                               :target "_blank"}
                           "Flow"]
-                         " will check for type safety as well, but even without type annotations."
+                         " will check for type safety as well, even for plain JS without type annotations."
                          ]))
            (swap! state assoc-in [:static :typescript :alpha] low)
            (<! (multi-animate!
@@ -952,11 +952,11 @@
         #(go
            (swap! state assoc :caption
                   (html [:div
-                         "Google uses its own "
+                         "Google makes heavy usage of its own "
                          [:a {:href "https://developers.google.com/closure/"
                               :target "_blank"}
                           "Closure Tools"]
-                         " to support "
+                         ", supporting "
                          [:a {:href "https://developers.google.com/closure/compiler/docs/js-for-compiler"
                               :target "_blank"}
                           "jsdoc tags"]
@@ -986,6 +986,10 @@

         ;; fade out staticsphere details
         #(go
+           (swap! state assoc :caption
+                  (html [:div
+                         "This is our simplified two-layer view of JS. We now leave the JS language for new worlds..."
+                         ]))
            (<! (multi-animate!
                  {:a :_ :b 0 :duration 1} [:static :typescript :alpha]
                  {:a :_ :b 0 :duration 1} [:static :flow :alpha]
@@ -999,6 +1003,9 @@

      ;; show coffeescript
      #(go
+           (swap! state assoc :caption
+                  (html [:div
+                         "(to be continued...)"]))
         (swap! state assoc :enable-orbits? true)
         (swap! state assoc-in [:radar :orbit] :coffeescript)
         (swap! state assoc-in [:coffeescript :highlight] true)


use datalog to store all runtime data, instead of a series of refs

--- src/subrosa/server.clj
+++ src/subrosa/server.clj
@@ -1,24 +1,28 @@
 (ns subrosa.server
+  (:use [clojure.contrib.datalog.database :only [make-database]])
   (:import [java.util Date]
            [java.net InetAddress]))
+
+(defn make-subrosa-db []
+  (make-database
+   (relation :user [:nick :real-name :user-name :channel :pending?])
+   (index :user :nick)
+   (index :user :channel)
+
+   (relation :room [:name :topic])
+   (index :room :name)
+
+   (relation :user-in-room [:user-nick :room-name])
+   (index :user-in-room :user-nick)
+   (index :user-in-room :room-name)))
+
+(defonce db (ref (make-subrosa-db)))

 (defonce +server+ {:host (.getHostName (InetAddress/getLocalHost))
                    :version "subrosa-1.0.0-SNAPSHOT"
                    :started (Date.)})
-(defonce +pending-connections+ (ref {}))  ; channel -> successful commands set
-(defonce +channels+ (ref {}))             ; channel -> nick
-(defonce +nicks+ (ref {}))                ; nick    -> user info map
-;;                                                     {:user-name ""
-;;                                                      :real-name ""}
-(defonce +rooms+ (ref {}))                ; room    -> room info map
-;;                                                     {:nicks #{}
-;;                                                      :topic ""
-;;                                                     }

 (defn reset-all-state! []
   (dosync
    (alter-var-root #'+server+ assoc :started (Date.))
-   (ref-set +pending-connections+ {})
-   (ref-set +channels+ {})
-   (ref-set +nicks+ {})
-   (ref-set +rooms+ {})))
+   (ref-set db (make-subrosa-db))))


if you can't find the version number, don't have a cow

--- src/subrosa/server.clj
+++ src/subrosa/server.clj
@@ -10,7 +10,10 @@
 ;; :user-in-room => [:user-nick :room-name]

 (defonce server {:host (config :host)
-                 :version (str "subrosa-" (.trim (slurp "etc/version.txt")))
+                 :version (try
+                            (str "subrosa-" (.trim (slurp "etc/version.txt")))
+                            (catch Exception e
+                              "subrosa-UNKNOWN"))
                  :started (Date.)})

 (def supported-room-modes #{\p})


Make it possible to migrate db from the REPL.

--- dev/src/user.clj
+++ dev/src/user.clj
@@ -12,7 +12,13 @@
             [clj-templates.db.db :as db]
             [clj-templates.logger]
             [clojure.java.io :as io]
+            [migratus.core :as migratus]
             [clj-templates.clojars-feed :refer [extract-templates-from-gzip-stream adapt-template-to-db]]))
+
+(defn migratus-config []
+  {:store         :database
+   :migration-dir "migrations"
+   :db            (:db/postgres system)})

 (defn get-config []
   (merge main-config dev-config))
@@ -20,7 +26,11 @@
 (defn cljs-repl []
   (ra/cljs-repl))

-(integrant.repl/set-prep! get-config)
+(defn migrate []
+  (migratus/migrate (migratus-config)))
+
+(defn rollback []
+  (migratus/migrate (migratus-config)))

 (defn bootstrap []
   (let [db (:db/postgres system)
@@ -29,6 +39,4 @@
       (db/upsert-template db (adapt-template-to-db template)))
     :bootstrapped))

-(comment
-  (db/delete-all-templates (:db/postgres system))
-  (bootstrap))
+(integrant.repl/set-prep! get-config)


Specifically override the problematic devcard style

--- src/clj/comic_reader/web_app.clj
+++ src/clj/comic_reader/web_app.clj
@@ -62,7 +62,7 @@
         [:div#cards.small-12.columns]]]
       :css [[:style (garden/css
                      [:.com-rigsomelight-devcards_rendered-card
-                      [:ul [:li [:a.button {:color "#FFF"}]]]])]]
+                      [:a.button {:color "#FFF !important"}]])]]
       :js [(page/include-js "js/compiled/devcards.js")]))

    (c/context "/api/v1" []


Added function for sending single command by single channel

--- src/clj/funstructor/commands.clj
+++ src/clj/funstructor/commands.clj
@@ -21,6 +21,9 @@
           (let [json (encode-command command)]
             (>! channel json))))))

+(defn send-command [command channel]
+  (send-commands :commands [command] :channels [channel]))
+
 (defn pending-checker []
   (go-loop []
     (<! (timeout 3000))
@@ -29,14 +32,14 @@
             [channel1 channel2] (map #(channel-for-uuid (current-global-state) %) pending-pair)
             game-id (u/gen-uuid)]
         (u/log "Taking two players for game " game-id " with uuids: " pending-pair "\n\n")
-        (send-commands :commands [{:type :start-game
-                                   :data {:game-id game-id
-                                          :enemy uuid2}}]
-                       :channels [channel1])
-        (send-commands :commands [{:type :start-game
-                                   :data {:game-id game-id
-                                          :enemy uuid1}}]
-                       :channels [channel2])
+        (send-command {:type :start-game
+                        :data {:game-id game-id
+                               :enemy uuid2}}
+                       channel1)
+        (send-command {:type :start-game
+                        :data {:game-id game-id
+                               :enemy uuid1}}
+                       channel2)

         (update-global-state add-game game-id (f/make-game uuid1 uuid2))
         (update-global-state #(apply remove-from-pending % pending-pair))))
@@ -58,13 +61,13 @@
         [p1 p2 :as players] (f/get-game-players initialized-game)
         [c1 c2] (map #(channel-for-uuid (current-global-state) %) players)]
     (u/log "Sending game-update's for game " game-id)
-    (send-commands :commands [{:type :game-update
-                               :data (make-update-data initialized-game p1)
-                               }]
-                   :channels [c1])
-    (send-commands :commands [{:type :game-update
-                               :data (make-update-data initialized-game p2)}]
-                   :channels [c2])))
+    (send-command {:type :game-update
+                    :data (make-update-data initialized-game p1)
+                    }
+                   c1)
+    (send-command {:type :game-update
+                    :data (make-update-data initialized-game p2)}
+                   c2)))

 ;; Functions for command handling
@@ -77,10 +80,10 @@
     (update-global-state (comp #(add-channel % channel uuid)
                                #(add-pending % uuid)))
     (u/log "Processing game-request and generating uuid: " uuid)
-    (send-commands :commands [{:type :game-request-ok
-                               :data {:uuid uuid
-                                      :pending (get-pending-players (current-global-state))}}]
-                   :channels [channel]
+    (send-command {:type :game-request-ok
+                    :data {:uuid uuid
+                           :pending (get-pending-players (current-global-state))}}
+                   channel
                    )))

 (defmethod handle-command "start-game-ok" [command channel]