typo, move analyze loop bindings into the loop

--- src/main/cljs/cljs/js.cljs
+++ src/main/cljs/cljs/js.cljs
@@ -78,11 +78,11 @@
   (let [rdr  (rt/string-push-back-reader source)
         eof  (js-obj)
         aenv (ana/empty-env)]
-    (binding [env/*compiler*   (:*compiler* bound-vars)
-              ana/*cljs-ns*    (:*cljs-ns* bound-vars)
-              *ns*             (:*ns* bound-vars)
-              r/*data-readers* (:*data-readers* bound-vars)]
-      ((fn analyze-loop []
+    ((fn analyze-loop []
+       (binding [env/*compiler*   (:*compiler* bound-vars)
+                 ana/*cljs-ns*    (:*cljs-ns* bound-vars)
+                 *ns*             (:*ns* bound-vars)
+                 r/*data-readers* (:*data-readers* bound-vars)]
          (let [form (r/read {:eof eof} rdr)]
            (if-not (identical? eof form)
              (let [aenv (assoc aenv :ns (ana/get-namespace ana/*cljs-ns*))
@@ -256,7 +256,7 @@
                  (ns-side-effects bound-vars aenv ast opts
                    (fn [_] (compile-loop)))
                  (recur)))
-             (cb (.toString cb)))))))))
+             (cb (.toString sb)))))))))

 (defn compile
   ([env source cb] (compile env source cb))


dox fix

dox fix

--- src/metabase/driver/generic_sql/query_processor.clj
+++ src/metabase/driver/generic_sql/query_processor.clj
@@ -61,7 +61,7 @@
 ;; ### `:aggregation`
 ;; ex.
 ;;
-;;    ["distinct" 1412]
+;;     ["distinct" 1412]
 (defmethod apply-form :aggregation [[_ value]]
   (match value
     ["rows"]  nil                                  ; don't need to do anything special for `rows` - `select` selects all rows by default
@@ -75,10 +75,10 @@
                        :sum      `(aggregate (~'sum ~field) :sum)))))
                  ;; TODO - `:cum_sum` is not yet implemented (!)

-;; `:breakout`
+;; ### `:breakout`
 ;; ex.
 ;;
-;; [1412 1413]
+;;     [1412 1413]
 (defmethod apply-form :breakout [[_ field-ids]] ; TODO - not yet implemented
   (when-not (= field-ids [nil])                      ; `:breakout [nil]` is considered a valid 'empty' form
     (let [field-names (map field-id->kw field-ids)]
@@ -88,7 +88,7 @@
 ;; ### `:fields`
 ;; ex.
 ;;
-;;    [1412 1413]
+;;     [1412 1413]
 (defmethod apply-form :fields [[_ field-ids]]
   (let [field-names (->> (sel :many [Field :name] :id [in (set field-ids)])
                          (map :name))]
@@ -97,9 +97,9 @@
 ;; ### `:filter`
 ;; ex.
 ;;
-;;    ["AND"
-;;      [">" 1413 1]
-;;      [">=" 1412 4]]
+;;     ["AND"
+;;       [">" 1413 1]
+;;       [">=" 1412 4]]
 (defmethod apply-form :filter [[_ filter-clause]]
   (match filter-clause
     [nil nil]       nil ; empty clause
@@ -111,7 +111,7 @@
 ;; ### `:limit`
 ;; ex.
 ;;
-;;    10
+;;     10
 (defmethod apply-form :limit [[_ value]]
   (when value
     `(limit ~value)))
@@ -119,8 +119,8 @@
 ;; ### `:order_by`
 ;; ex.
 ;;
-;;    [[1416 "ascending"]
-;;     [1412 "descending"]]
+;;     [[1416 "ascending"]
+;;      [1412 "descending"]]
 (defmethod apply-form :order_by [[_ field-ids]]
   (when-not (empty? field-ids)
     (let [fields (->> field-ids


allow Medium/Nerve Agent to keep gaining counters after hitting CVS when empty

--- src/clj/game/cards-programs.clj
+++ src/clj/game/cards-programs.clj
@@ -310,7 +310,7 @@
                                                                      " by clicking on Medium"))
                                       (update! state side (assoc card :medium-active true)))}
              :successful-run {:req (req (and (= target :rd)
-                                             (or (:medium-active card) (nil? (:counter card)))))
+                                             (or (:medium-active card) (nil? (:counter card)) (= 0 (:counter card)))))
                               :effect (effect (add-prop card :counter 1))}
              :pre-access {:req (req (and (= target :rd) (:medium-active card)))
                           :effect (effect (access-bonus (max 0 (dec (get-virus-counters state side (get-card state card))))))}}
@@ -338,7 +338,7 @@
                                                                      " by clicking on Nerve Agent"))
                                       (update! state side (assoc card :nerve-active true)))}
              :successful-run {:req (req (and (= target :hq)
-                                             (or (:nerve-active card) (nil? (:counter card)))))
+                                             (or (:nerve-active card) (nil? (:counter card)) (= 0 (:counter card)))))
                               :effect (effect (add-prop card :counter 1))}
              :pre-access {:req (req (and (= target :hq) (:nerve-active card)))
                           :effect (effect (access-bonus (max 0 (dec (get-virus-counters state side (get-card state card))))))}}


Reformatted fileutils.clj and updated comments

--- src/clj_fileutils/fileutils.clj
+++ src/clj_fileutils/fileutils.clj
@@ -12,97 +12,110 @@

 (ns clj-fileutils.fileutils)

-(require '[hozumi.rm-rf    :as rm-rf])
+(require '[hozumi.rm-rf :as rm-rf])

 (def temporary-name-prefix
-    "clojure-fileutils-")
+  "Prefix for all temporary files."
+  "clojure-fileutils-")

 (defn print-slurp-exception
-    "Print warning message to the standard output."
-    ([filename]
-        (println "Warning: cannot read content of the following file:" filename))
-    ([directory filename]
-        (println "Warning: cannot read content of the following file:" (str directory "/" filename))))
+  "Print warning message to the standard output."
+  ([filename]
+   ; variant with just filename
+   (println "Warning: cannot read content of the following file:" filename))
+  ([directory filename]
+   ; variant with directory and filename
+   (println "Warning: cannot read content of the following file:"
+            (str directory "/" filename))))

 (defn slurp-
-    "Alternative (slurp) implementation that does not throw an exception, but returns nil instead."
-    ([filename]
-        (try
-            (slurp filename)
-            (catch Exception e (print-slurp-exception filename))))
-    ([directory filename]
-        (try
-            (slurp (str directory "/" filename))
-            (catch Exception e (print-slurp-exception directory filename)))))
+  "Alternative (slurp) implementation that does not throw an exception, but returns nil instead."
+  ([filename]
+   ; variant with just filename
+   (try (slurp filename)
+        (catch Exception e (print-slurp-exception filename))))
+  ([directory filename]
+   ; variant with directory and filename
+   (try (slurp (str directory "/" filename))
+        (catch Exception e (print-slurp-exception directory filename)))))

 (defn new-file
-    "Just a shortcut for (new java.io.File filename)."
-    ( [filename]
-    (new java.io.File filename))
-    ( [path filename]
-    (new java.io.File path filename)))
+  "Just a shortcut for (new java.io.File filename)."
+  ([filename]
+   ; variant with just filename
+   (new java.io.File filename))
+  ([path filename]
+   ; variant with path and filename
+   (new java.io.File path filename)))

 (defn remove-temporary-directory
-    "Remove (delete) temporary directory that resides in /tmp (at least on Linux)."
-    [directory-name]
-    (let [file (new java.io.File directory-name)
-          abs-path (.getAbsolutePath file)]
-        ; make sure we are not going to remove wrong directory!
-        (if (.startsWith abs-path "/tmp")
-            (rm-rf/rm-r file))))
+  "Remove (delete) temporary directory that resides in /tmp (at least on Linux)."
+  [directory-name]
+  (let [file (new java.io.File directory-name)
+        abs-path (.getAbsolutePath file)]
+    ; make sure we are not going to remove wrong directory!
+    (if (.startsWith abs-path "/tmp")
+      (rm-rf/rm-r file))))

 (defn remove-directory
-    [directory]
-    (rm-rf/rm-r directory))
+  "Remove specified directory and all its content (recursively)."
+  [directory]
+  (rm-rf/rm-r directory))

 (defn mv-file
-    "Move or rename one file. On the same filesystem the rename should be atomic."
-    [filename1 filename2]
-    (let [file1 (new java.io.File filename1)
-          file2 (new java.io.File filename2)]
-          (.renameTo file1 file2)))
+  "Move or rename one file. On the same filesystem the rename should be atomic."
+  [filename1 filename2]
+  (let [file1 (new java.io.File filename1)
+        file2 (new java.io.File filename2)]
+    (.renameTo file1 file2)))

 (defn move-file
-    "Move or rename one file. On the same filesystem the rename should be atomic."
-    [filename1 filename2]
-    (mv-file filename1 filename2))
+  "Move or rename one file. On the same filesystem the rename should be atomic."
+  [filename1 filename2]
+  (mv-file filename1 filename2))

 (defn make-temporary-log-file-name
-    []
-    (let [basedir-name (new java.io.File (System/getProperty "java.io.tmpdir"))
-          base-name    temporary-name-prefix
-          temp-file    (java.io.File/createTempFile base-name ".log" basedir-name)]
-          (.getAbsolutePath temp-file)))
+  "Special variant of function to make temporary file name that will reside in
+  (at least on Linux)."
+  []
+  (let [basedir-name (new java.io.File (System/getProperty "java.io.tmpdir"))
+        base-name temporary-name-prefix
+        temp-file (java.io.File/createTempFile base-name ".log" basedir-name)]
+    (.getAbsolutePath temp-file)))

 (defn make-temporary-directory
-    "Make temporary directory that would reside in /tmp (at least on Linux)."
-    []
-    (let [basedir-name (System/getProperty "java.io.tmpdir")
-          base-name    (str temporary-name-prefix (System/currentTimeMillis))
-          temp-dir     (new java.io.File basedir-name base-name)]
-        (.mkdir temp-dir)
-        temp-dir))
+  "Make temporary directory that would reside in /tmp (at least on Linux)."
+  []
+  (let [basedir-name (System/getProperty "java.io.tmpdir")
+        base-name (str temporary-name-prefix (System/currentTimeMillis))
+        temp-dir  (new java.io.File basedir-name base-name)]
+    (.mkdir temp-dir)
+    temp-dir))

 (defn filename-list
-    "Return list of file names that resides in specified directory."
-    (   [directory]
-        (->> (.listFiles (new java.io.File directory))
-             (filter #(.isFile %))
-             (map #(.getName %))))
-    (   [directory extension]
-        (->> (.listFiles (new java.io.File directory))
-             (filter #(.isFile %))
-             (map #(.getName %))
-             (filter #(.endsWith % extension)))))
+  "Return list of file names that resides in specified directory."
+  ([directory]
+   ; variant with just directory
+   (->> (.listFiles (new java.io.File directory))
+        (filter #(.isFile %))
+        (map #(.getName %))))
+  ([directory extension]
+   ; variant with directory and extension
+   (->> (.listFiles (new java.io.File directory))
+        (filter #(.isFile %))
+        (map #(.getName %))
+        (filter #(.endsWith % extension)))))

 (defn file-list
-    "Return list of files that resides in specified directory."
-    (   [directory]
-        (->> (.listFiles (new java.io.File directory))
-             (filter #(.isFile %))))
-    (   [directory extension]
-        (->> (.listFiles (new java.io.File directory))
-             (filter #(.isFile %))
-             (filter #(.endsWith (.getName %) extension)))))
+  "Return list of files that resides in specified directory."
+  ([directory]
+   ; variant with just directory
+   (->> (.listFiles (new java.io.File directory))
+        (filter #(.isFile %))))
+  ([directory extension]
+   ; variant with directory and extension
+   (->> (.listFiles (new java.io.File directory))
+        (filter #(.isFile %))
+        (filter #(.endsWith (.getName %) extension)))))


Stub out basic re-frame scaffolding

Stub out basic re-frame scaffolding

--- src/cljs/comic_reader/main.cljs
+++ src/cljs/comic_reader/main.cljs
@@ -11,3 +11,23 @@
             [reagent.core :as reagent :refer [atom]]
             [reagent.ratom :refer-macros [reaction]]
             [re-frame.core :as rf]))
+
+(defonce time-updater (js/setInterval
+                       #(rf/dispatch [:timer (js/Date.)]) 1000))
+
+(defonce initial-state
+  {:page :sites})
+
+(rf/register-handler
+ :initialize
+ (fn
+   [db _]
+   (merge db initial-state)))
+
+(defn comic-reader []
+  [:div])
+
+(defn ^:export run []
+  (rf/dispatch [:initialize])
+  (reagent/render [comic-reader]
+                  (.-body js/document)))


changes editable to use defcomponentk

changes editable to use defcomponentk

--- src/cljs/foosball/editable.cljs
+++ src/cljs/foosball/editable.cljs
@@ -3,6 +3,7 @@
   (:require [cljs.core.async :as async :refer [put! chan alts!]]
             [goog.dom :as gdom]
             [om.core :as om :include-macros true]
+            [om-tools.core :refer-macros [defcomponentk]]
             [sablono.core :as html :refer-macros [html]]
             [foosball.console :refer-macros [debug error]]))

@@ -35,36 +36,35 @@
                        set)]
     (when key-kw {:key key-kw :modifiers modifiers})))

-(defn editable
-  [data owner {:keys [value-fn         ;; fn to apply on editable data to get str (default: identity)
-                      placeholder      ;; placeholder text in input field
-                      input-classes    ;; additional classes for input (seq of kw or str)
-                      input-props      ;; additional properties for the input element
-                      change-ch        ;; channel where changes are put to, as [type value] tuples,
-                                        ; where type in #{:editable/focus :editable/change :editable/blur}
-                      ] :as opts}]
-  (reify
-    om/IInitState
-    (init-state [_]
-      {:editing false
-       :current-value ((or value-fn identity) data)})
+(defcomponentk editable
+  [data owner
+   [:opts
+    {value-fn identity} ;; fn to apply on editable data to get str
+    {placeholder nil}   ;; placeholder text in input field
+    {input-classes nil} ;; additional classes for input (seq of kw or str)
+    {input-props nil}   ;; additional properties for the input element
+    change-ch           ;; channel where changes are put to, as [type value] tuples,
+                        ;; where type in #{:editable/focus :editable/change :editable/blur}
+    :as opts]]
+  (init-state [_]
+    {:editing false
+     :current-value ((or value-fn identity) data)})

-    om/IRenderState
-    (render-state [_ {:keys [editing current-value]}]
-      (let [defaults   {:type "text"
-                        :ref  "input"}
-            must-haves {:class       (mapv name input-classes)
-                        :value       current-value
-                        :placeholder placeholder
-                        :on-change   (fn [e] (on-change change-ch owner e))
-                        :on-key-down (fn [e] (when (om/get-state owner :editing)
-                                              (let [comp-kb-ev (component-keyboard-event e)]
-                                                (when (= (:key comp-kb-ev) :enter)
-                                                  (.blur (om/get-node owner "input"))))))
-                        :on-blur     (fn [e] (when (om/get-state owner :editing)
-                                              (end-edit change-ch owner current-value)))
-                        :on-focus    (fn [e] (begin-edit change-ch owner current-value))}]
-        (html [:input.form-control
-               (merge defaults
-                      input-props
-                      must-haves)])))))
+  (render-state [_ {:keys [editing current-value]}]
+    (let [defaults   {:type "text"
+                      :ref  "input"}
+          must-haves {:class       (mapv name input-classes)
+                      :value       current-value
+                      :placeholder placeholder
+                      :on-change   (fn [e] (on-change change-ch owner e))
+                      :on-key-down (fn [e] (when (om/get-state owner :editing)
+                                            (let [comp-kb-ev (component-keyboard-event e)]
+                                              (when (= (:key comp-kb-ev) :enter)
+                                                (.blur (om/get-node owner "input"))))))
+                      :on-blur     (fn [e] (when (om/get-state owner :editing)
+                                            (end-edit change-ch owner current-value)))
+                      :on-focus    (fn [e] (begin-edit change-ch owner current-value))}]
+      (html [:input.form-control
+             (merge defaults
+                    input-props
+                    must-haves)]))))


Add Parent link when comment is top of view

--- src/cljs/hacker_agent/core.cljs
+++ src/cljs/hacker_agent/core.cljs
@@ -67,7 +67,7 @@
                [:p (:value (r/props this))]])}))

 (declare comment-list)
-(defn comment [data]
+(defn comment [data & top?]
   (let [collapse? (atom false)]
     (fn [data]
       (let [{:keys [id by kids parent text type time score deleted]} @data]
@@ -82,7 +82,11 @@
                  "[+] "
                  "[-] ")]
               (str by " | " (t/time-ago time) " | ")
-              [:a {:href (str "/#/items/" id)} "link"]]
+              [:a {:href (str "/#/items/" id)} "link"]
+              (when top?
+                [:span
+                 " | "
+                 [:a {:href (str "/#items/" parent)} "Parent"]])]
              (when-not @collapse?
                [:div
                 [:p {:dangerouslySetInnerHTML {:__html text}}]
@@ -197,7 +201,7 @@
   (when-let [entry (get-in @state [:current-item])]
     (case (:type entry)
       "story" [story (r/wrap entry swap! state assoc :current-item)]
-      "comment" [comment (r/wrap entry swap! state assoc :current-item)]
+      "comment" [comment (r/wrap entry swap! state assoc :current-item) true]
       [:p "Cannot render item"])))

 (defmethod page :stream [state]


Drop multi method approach in rendering an item

Due to problems with rerendering the right method on state change.

--- src/cljs/hacker_agent/core.cljs
+++ src/cljs/hacker_agent/core.cljs
@@ -24,9 +24,25 @@

 ;; ------------------------
 ;; Components
-(defmulti item :type)
+(defn comment [data]
+  (let [local (atom {:collapse-comments? true})]
+    (fn [data]
+      (let [{:keys [id by kids parent text type time score deleted]} data]
+        (when-not deleted
+          [:ul
+           [:li "ID: " [:a {:href (str "/#/items/" id)} id]]
+           [:li "Parent: " [:a {:href (str "/#/items/" parent)} parent]]
+           [:li "By: " by]
+           [:li {:dangerouslySetInnerHTML {:__html (str "Text: </br>" text)}}]
+           [:li "Time: " time]
+           (when kids
+             [:li [:span {:on-click #(swap! local update-in [:collapse-comments?] not)}
+                   "Comments: "]
+              (when-not (:collapse-comments? @local)
+                (for [[id sub-data] (vec kids)]
+                  ^{:key id} [comment sub-data]))])])))))

-(defmethod item "story" [data]
+(defn story [data]
   (let [local (atom {:collapse? false
                      :collapse-comments? true})]
     (fn [data]
@@ -45,31 +61,7 @@
                    "Comments: "]
               (when-not (:collapse-comments? @local)
                 (for [[id sub-data] (vec kids)]
-                  ^{:key id} [item sub-data]))])])))))
-
-(defmethod item "comment" [data]
-  (let [local (atom {:collapse-comments? true})]
-    (fn [data]
-      (let [{:keys [id by kids parent text type time score deleted]} data]
-        (when-not deleted
-          [:ul
-           [:li "ID: " [:a {:href (str "/#/items/" id)} id]]
-           [:li "Parent: " [:a {:href (str "/#/items/" parent)} parent]]
-           [:li "By: " by]
-           [:li {:dangerouslySetInnerHTML {:__html (str "Text: </br>" text)}}]
-           [:li "Time: " time]
-           (when kids
-             [:li [:span {:on-click #(swap! local update-in [:collapse-comments?] not)}
-                   "Comments: "]
-              (when-not (:collapse-comments? @local)
-                (for [[id sub-data] (vec kids)]
-                  ^{:key id} [item sub-data]))])])))))
-
-(defmethod item "job" [data]
-  [:p "This is a job"])
-
-(defmethod item nil [_]
-  [:p "Cannot render item"])
+                  ^{:key id} [comment sub-data]))])])))))

 (defn top-stories [state]
   (let [{top-stories :top-stories} state]
@@ -91,7 +83,10 @@

 (defmethod page :item [state]
   (when-let [entry (get-in state [:current-item :item])]
-    [item entry]))
+    (case (:type entry)
+      "story" [story entry]
+      "comment" [comment entry]
+      [:p "Cannot render item"])))

 (defn main-page [state]
   [:div


message send ok

message send ok

--- src/cljs/minimal_chat/core.cljs
+++ src/cljs/minimal_chat/core.cljs
@@ -14,19 +14,20 @@
             [matchbox.async :as ma]
             [matchbox.core :as m])
   (:require-macros [reagent.ratom :refer [reaction]]
-                   [cljs.core.async.macros :refer [go go-loop]])
+                   [cljs.core.async.macros :refer [go-loop]])
   (:import goog.History))

 ;; -- REPLACE with your own DB location ---------
 (def firebase-io-root "https://shining-torch-2145.firebaseIO.com")
 ;; ----------------------------------------------

+;; Connection to Firebase
+(defonce fb-root (m/connect firebase-io-root))
+
 (def initial-state
   {:chat-room nil
    :messages []
    :username (str "Guest" (rand-int 100))})
-
-(defonce chat-room (reagent/atom nil))

 (defonce fb-messages (atom nil))
 (defonce messages (reagent/atom []))
@@ -51,11 +52,9 @@
        (str/upper-case)))

 (defn join-room [id]
-  (reset! chat-room id)
-  (let [fb-root (m/connect firebase-io-root)]
-    (let [fb-item (m/get-in fb-root [(str/lower-case id) :messages])]
-      (reset! fb-messages fb-item)
-      (bind-to-ratom messages fb-item))))
+  (let [fb-item (m/get-in fb-root [(str/lower-case id) :messages])]
+    (reset! fb-messages fb-item)
+    (bind-to-ratom messages fb-item)))

 ;; -- Subscriptions ---------

@@ -63,6 +62,16 @@
   :username-input
   (fn [db _]
     (reaction (:username @db))))
+
+(register-sub
+  :current-chat-room
+  (fn [db _]
+    (reaction (:chat-room @db))))
+
+(register-sub
+  :chat-room-messages
+  (fn [db _]
+    (reaction (:messages @db))))

 ;; -- Event Handlers --------

@@ -76,6 +85,20 @@
   (fn [db [_ value]]
     (assoc db :username value)))

+(register-handler
+  :join-chat-room
+  (fn [db [_ room-id]]
+    (join-room room-id)
+    (assoc db :chat-room room-id)))
+
+(register-handler
+  :send-message
+  (fn [db [_ username message chat-room]]
+    (m/conj-in! fb-root [(-> chat-room (str/lower-case) (keyword))
+                         :messages]
+                [username message])
+    db))
+
 ;; -- View Components -------

 (defn username-input []
@@ -85,11 +108,15 @@
              :on-change #(dispatch [:set-username-input (-> % .-target .-value)])}]))

 (defn message-form []
-  (let [message  (reagent/atom "")
-        username (subscribe [:username-input])]
+  (let [message   (reagent/atom "")
+        username  (subscribe [:username-input])
+        chat-room (subscribe [:current-chat-room])]
     [:form {:on-submit (fn [e]
+                         ;; prevent redirect
                          (.preventDefault e)
-                         (firebase-swap! @fb-messages conj [@username @message]))}
+                         (dispatch-sync [:send-message @username @message @chat-room])
+                         ;; reset the form
+                         (.reset (.-target e)))}
      [:input {:type "text"
               :on-change #(reset! message (-> % .-target .-value))}]
      [:button {:type "submit"} "Send"]]))
@@ -109,54 +136,47 @@
    [message-form]])

 (defn join-room-view []
-  (let [this-room (atom (random-four-characters))
+  (let [this-room        (atom (random-four-characters))
         change-location #(set! (.-location js/window) (str "#/room/" @this-room))]
     [:div
-     [:p [:div
-          [:button {:on-click change-location
-                    :type "submit"}
-           "New Room"]]]
-
-     [:p [:div
-          [:input {:placeholder "Room Name"
-                   :type "text"
-                   :on-change #(reset! this-room (-> % .-target .-value))}]
-          [:button {:type "submit"
-                    :on-click change-location}
-           "Join Room"]]]]))
+     [:input {:placeholder "Room Name"
+              :type "text"
+              :on-change #(reset! this-room (-> % .-target .-value))}]
+     [:button {:type "submit"
+               :on-click change-location}
+      "Join Room"]
+     [:button {:on-click change-location
+               :type "submit"}
+      "Random Room"]]))

 (defn home-page []
-  [:div
-   [:div {:class "container"}
-    [:div {:class "page-header"}
-     [:h2 "Minimal Chat"]]
+  (let [chat-room (subscribe [:current-chat-room])
+        messages  (subscribe [:chat-room-messages])]
+    [:div
+     [:div.container
+      [:div.page-header
+       [:h2 "Minimal Chat"]]

-    (if @chat-room
-      [on-going-chat]
-      [join-room-view])
+      (if @chat-room
+        [on-going-chat]
+        [join-room-view])

-    [:div [:br] [:br] [:br]
-     "STATE!!!!"
-     [:div "Messages: " (pr-str @messages)]]]])
+      [:div [:br] [:br] [:br]
+       "STATE!!!!"
+       [:div "Messages: " (pr-str @messages)]]]]))

 (defn current-page []
   [:div [(session/get :current-page)]])

-;; -------------------------
-;; Routes
+;; -- Routes and History ----

 (secretary/defroute "/" []
-  (reset! chat-room nil)
+  (dispatch [:exit-chat-room])
   (session/put! :current-page #'home-page))

-(secretary/defroute "/room/:id" {:as params}
-  (when (not= @chat-room (:id params))
-    (join-room (:id params)))
+(secretary/defroute "/room/:id" [id]
+  (dispatch [:join-chat-room id])
   (session/put! :current-page #'home-page))
-
-;; -------------------------
-;; History
-;; must be called after routes have been defined

 (defn hook-browser-navigation! []
   (doto (History.)
@@ -176,3 +196,4 @@

   ;; mount root
   (reagent/render-component [current-page] (.getElementById js/document "app")))
+


tired of trying different stuff

tired of trying different stuff

--- src/clojure_web_app/handler.clj
+++ src/clojure_web_app/handler.clj
@@ -15,7 +15,7 @@
             [environ.core :refer [env]]
             [ring.middleware.defaults :refer [wrap-defaults site-defaults]]))

-(def production true)
+(def production (or (env :production) false))

 (defn location-by-ip [ip]
   (json/read-str ((client/get (format "http://freegeoip.net/json/%s" ip)) :body) :key-fn keyword))
@@ -36,12 +36,12 @@
            (GET "/cheapest-near-me" [limit distance fuel]
              (fn [request]
                (let [location (location-by-ip (if production
-                                                ((:headers request) "http_x_forwarded_for")
+                                                ((:headers request) "x_forwarded_for")
                                                 (:remote-addr request)))]
                  (response (nearby-fuel-prices (location :latitude) (location :longitude) limit distance fuel)))))
            (GET "/my-location" []
              (fn [request] (response (location-by-ip (if production
-                                                       ((:headers request) "http_x_forwarded_for")
+                                                       ((:headers request) "x_forwarded_for")
                                                        (:remote-addr request))))))
            (GET "/my-ip" []
              (fn [request]


Show info from paths

Show info from paths

--- src-cljs/photon/ui/frontend.cljs
+++ src-cljs/photon/ui/frontend.cljs
@@ -2,7 +2,7 @@
   (:require-macros [cljs.core.async.macros :refer [go go-loop]])
   (:use [jayq.core :only [$ css html]])
   (:require [cljs-http.client :as client]
-            [cljs.core.async :refer [<! >! put! close!]]
+            [cljs.core.async :refer [chan <! >! put! close!]]
             [tailrecursion.cljson :refer [clj->cljson cljson->clj]]
             [chord.client :refer [ws-ch]]
             [goog.net.cookies :as ck]
@@ -877,6 +877,7 @@
         n (render-text (name k) (:mode sch)) ]
     {:text (str n " [" tt "]")
      :a_attr {:style "color: #111111;"}
+     :schema sch
      :icon "ui/images/ic_short_text_black_18dp.png"}))

 (defmethod node->js :vector-object [[k v]]
@@ -892,6 +893,7 @@
         under-type (m->text (:type leaf))]
     {:text (str (render-text (name k) (:mode leaf))
                 " [Array (" under-type ")]")
+     :schema leaf
      :icon "ui/images/ic_more_horiz_black_18dp.png"}))

 (defmethod node->js :tree [[k v]]
@@ -904,41 +906,77 @@
   (map node->js tree))

 (defn schema->tree [schema]
-  (reduce #(assoc-in %1 (key %2) {:leaf (val %2)}) {} (:m schema)))
-
-(defn produce-tree! [data]
+  (reduce #(assoc-in %1 (key %2) {:leaf (assoc (val %2) :path (key %2))})
+          {} (:m schema)))
+
+(defn produce-tree! [data ch]
   (let [tj (tree->js (schema->tree (:schema data)))
         cd (clj->js {:core {:data tj}})]
     (.jstree ($ :#tree) cd)
-    nil))
+    (.on ($ :#tree) "hover_node.jstree"
+         (fn [_ data] (go (>! ch data))))))

 (defn clean-tree! [data]
   (let [tj (tree->js (schema->tree (:schema data)))
         cd (clj->js {:core {:data tj}})
         t (.jstree ($ :#tree) true)]
     (set! (.-data (.-core (.-settings t))) cd)
-    (.destroy t)
-    nil))
-
-(defn stream-schema [data owner]
-  (reify
+    (.destroy t)))
+
+(defn var-inspector [data owner]
+  (reify
+    om/IInitState
+    (init-state [_]
+      {:jstree.node nil})
     om/IDidMount
     (did-mount [_]
-      (produce-tree! data))
+      (go
+        (loop [elem (<! data)]
+          (when-not (nil? elem)
+            (om/update-state! owner
+                              (fn [old] (assoc old :jstree.node elem)))
+            (recur (<! data))))))
+    om/IRenderState
+    (render-state [_ state]
+      (when-not (nil? (:jstree.node state))
+        (let [node (js->clj (:jstree.node state) :keywordize-keys true)
+              sch (-> node :node :original :schema)
+              path (clojure.string/join "." (:path sch))]
+          (apply dom/div
+                 nil
+                 (when-not (nil? sch)
+                   [(dom/p nil path)
+                    (dom/p nil (str "This parameter is probably " (:mode sch)))
+                    (dom/p nil (when-not (= (:values sch) "not-enum")
+                                 (str "Values found: "
+                                      (clojure.string/join
+                                       ", "
+                                       (map name (keys (:values sch)))))))])))))))
+
+(defn stream-schema [data owner]
+  (reify
+    om/IInitState
+    (init-state [_]
+      {:ch (chan)})
+    om/IDidMount
+    (did-mount [_]
+      (produce-tree! data (:ch (om/get-state owner))))
     om/IDidUpdate
     (did-update [_ _ _]
+      (go (>! (:ch (om/get-state owner)) ""))
       (clean-tree! data)
-      (produce-tree! data))
+      (produce-tree! data (:ch (om/get-state owner))))
     om/IRender
     (render [_]
       (dom/div
        nil
        (dom/div
-        #js {:className "container-fluid"}
+        #js {:className "container"}
         (dom/div
          #js {:className "row"}
-         (dom/div #js {:className "col-md-1" :id "tree"})
-         (dom/div #js {:className "col-md-1" :id "tree"} (dom/p nil "hello"))))
+         (dom/div #js {:className "col-lg-4" :id "tree"})
+         (dom/div #js {:className "col-lg-4" :id "tree"}
+                  (om/build var-inspector (:ch (om/get-state owner))))))
        (dom/p nil (pr-str data))))))

 (defn widget-analyse [data owner]


automatically advance the 2017 tournament

--- cljs-common/tourneybot/data.cljs
+++ cljs-common/tourneybot/data.cljs
@@ -278,13 +278,40 @@
 ;; Tournament Advancer
 ;;------------------------------------------------------------------------------

+(def semis-1v4-game-id :game601)
+(def semis-2v3-game-id :game602)
+(def fifth-place-game-id :game603)
+
 (defn- advance-2017-indoor-tournament
   [state]
-  ; (let [all-swiss-games (filter is-swiss-game? (vals (:games state)))
-  ;       all-swiss-rounds-finished? (every? game-finished? all-swiss-games)]
-  ;   ; (log all-swiss-games)
-  ;   (log all-swiss-rounds-finished?))
-  state)
+  (let [games-list (map (fn [[game-id game]] (assoc game :game-id game-id)) (:games state))
+        all-swiss-games (filter is-swiss-game? games-list)
+        all-swiss-games-finished? (every? game-finished? all-swiss-games)
+        total-number-of-games-finished (count (filter game-finished? games-list))
+        semis-1v4-game (get-in state [:games semis-1v4-game-id])
+        semis-2v3-game (get-in state [:games semis-2v3-game-id])
+        fifth-place-game (get-in state [:games fifth-place-game-id])
+        new-state (atom state)]
+    (when (and (= "2017 Houston Indoor") (:title state)
+               all-swiss-games-finished?
+               (= total-number-of-games-finished (count all-swiss-games))
+               semis-1v4-game
+               semis-2v3-game
+               fifth-place-game)
+      (let [results (games->results (:teams state) (:games state))]
+        (when-not (:teamA-id semis-1v4-game)
+          (swap! new-state update-in [:games semis-1v4-game-id] merge
+            {:teamA-id (:team-id (nth results 0))
+             :teamB-id (:team-id (nth results 3))}))
+        (when-not (:teamA-id semis-2v3-game)
+          (swap! new-state update-in [:games semis-2v3-game-id] merge
+            {:teamA-id (:team-id (nth results 1))
+             :teamB-id (:team-id (nth results 2))}))
+        (when-not (:teamA-id fifth-place-game)
+          (swap! new-state update-in [:games fifth-place-game-id] merge
+            {:teamA-id (:team-id (nth results 4))
+             :teamB-id (:team-id (nth results 5))}))))
+    @new-state))

 (defn- advance-pending-game
   [state pending-game]


Fill in missing api/engine for IntegerBlockVector.

--- src/clojure/uncomplicate/neanderthal/internal/host/buffer_block.clj
+++ src/clojure/uncomplicate/neanderthal/internal/host/buffer_block.clj
@@ -412,7 +412,7 @@
     :cpu)
   EngineProvider
   (engine [_]
-    nil)
+    eng)
   FactoryProvider
   (factory [_]
     fact)


https placeholder image

https placeholder image

--- src/pc/views/blog/ideas_are_made_with_precursor.clj
+++ src/pc/views/blog/ideas_are_made_with_precursor.clj
@@ -99,7 +99,7 @@
          "And if we're trying to show it off to a group, why not target a huge group? "
          "Like Reddit, perhaps? "]]

-    [:figure [:img {:src "http://placehold.it/800x600"}]]
+    [:figure [:img {:src "https://placehold.it/800x600"}]]

     [:article
      [:h3 "That's it for now."]


dont calc twice

dont calc twice

--- src/hackerrank/area_under_curves_and_volume_of_revolving_a_curv.clj
+++ src/hackerrank/area_under_curves_and_volume_of_revolving_a_curv.clj
@@ -63,7 +63,7 @@
   []
   (map read-string (clojure.string/split (read-line) #"\s")))

-(defn f-at-x
+(defn f-of-x
   [coefficients powers x]
   (reduce + (map #(* %1 (Math/pow x %2)) coefficients powers)))

@@ -74,8 +74,8 @@
         powers (parse-line)
         [start stop] (parse-line)
         bounds (range start (+ stop delta) delta)
-        f (partial f-at-x coefficients powers)
-        area (* delta (reduce + (map f bounds)))
-        volume (* delta (reduce + (map #(* Math/PI (Math/pow (f %) 2)) bounds)))]
+        y (map (partial f-of-x coefficients powers) bounds) ; y = f(x)
+        area (* delta (reduce + y))
+        volume (* delta (reduce + (map #(* Math/PI (Math/pow % 2)) y)))]
     (println area)
     (println volume)))


Prepare for other response status codes

Prepare for other response status codes

--- src/nhl_score_api/core.clj
+++ src/nhl_score_api/core.clj
@@ -43,25 +43,28 @@
   [request-path request-params fetch-latest-scores-api-fn fetch-scores-in-date-range-api-fn cache-get-fn cache-set-fn]
   (case request-path
     "/"
-    {:version version}
+    {:status 200
+     :body {:version version}}

     "/api/scores/latest"
-    (get-cached-response
-      request-path
-      fetch-latest-scores-api-fn
-      cache-get-fn
-      cache-set-fn
-      60)
+    {:status 200
+     :body (get-cached-response
+             request-path
+             fetch-latest-scores-api-fn
+             cache-get-fn
+             cache-set-fn
+             60)}

     "/api/scores"
-    (get-cached-response
-      request-path
-      #(fetch-scores-in-date-range-api-fn (:start-date request-params) (:end-date request-params))
-      cache-get-fn
-      cache-set-fn
-      60)
+    {:status 200
+     :body (get-cached-response
+             request-path
+             #(fetch-scores-in-date-range-api-fn (:start-date request-params) (:end-date request-params))
+             cache-get-fn
+             cache-set-fn
+             60)}

-    nil))
+    {:status 404 :body {}}))

 (defn json-key-transformer [key]
   (if (keyword? key)
@@ -79,18 +82,17 @@
 (defn request-handler [request]
   (println "Received request" request)
   (try
-    (let [request-params (fmap-keys ->kebab-case-keyword (:params request))
-          success-response
+    (let [request-params
+          (fmap-keys ->kebab-case-keyword (:params request))
+          response
           (get-response
             (:uri request)
             request-params
             fetcher/fetch-latest-scores
             fetcher/fetch-scores-in-date-range
             cache/get-value
-            cache/set-value)
-          response
-          (or success-response {})]
-      (format-response (if success-response 200 404) response))
+            cache/set-value)]
+      (format-response (:status response) (:body response)))
     (catch Exception e
       (println "Caught exception" e)
       (format-response 500 {:error "Server error"}))))


Deprecation worked out

Deprecation worked out

--- src/test/clojure/ru/flamefork/util/clj_string_test.clj
+++ src/test/clojure/ru/flamefork/util/clj_string_test.clj
@@ -7,5 +7,5 @@
 (deftest with-meta-test
   (let [asd (CljString. "test")
         asd-w-meta (with-meta asd {:asd 123})]
-    (is (= ^asd-w-meta {:asd 123}))
+    (is (= (meta asd-w-meta) {:asd 123}))
     (is (= asd-w-meta asd))))


Removing noise

Removing noise

--- namespaces/common/src/main/clojure/immutant/codecs.clj
+++ namespaces/common/src/main/clojure/immutant/codecs.clj
@@ -83,7 +83,6 @@
     (.readObject ois)))

 (defmethod clojure.core/print-dup :default [o ^java.io.Writer w]
-  (.println System/out (str "WARN: using Java serialization for " (.getName (class o))))
   (.write w "#=(immutant.codecs/deserialize ")
   (print-dup (serialize o) w)
   (.write w ")"))


IntegerPathElement

IntegerPathElement

--- src/structural_typing/guts/compile/compile_path.clj
+++ src/structural_typing/guts/compile/compile_path.clj
@@ -176,31 +176,31 @@
                       (conj so-far x)
                       (into so-far (next-fn x))))
                   []
-                  mixture))
-
-        (range-select* [{:keys [inclusive-start desired-count] :as selector-element} {:keys [leaf-value] :as exval} next-fn]
-          (cond (rejected-nil? leaf-value selector-element)
-                (errcase explain/oopsies:should-not-be-applied-to-nil exval {:conj-path selector-element})
-
-                (nil? leaf-value)
-                (pad-the-end [] exval selector-element)
-
-                (not (sequential? leaf-value))
-                (errcase explain/oopsies:shouldbe-sequential exval {:conj-path selector-element})
-
-                :else
-                (-> exval
-                    (extract-desired-range-as-exvals selector-element)
-                    (pad-the-end exval selector-element)
-                    (perhaps-rejecting-nil selector-element)
-                    (descend next-fn))))]
-
-  (extend-type RangePathElement
-    sp/StructurePath
-    (select* [this exval next-fn]
-      (range-select* this exval next-fn))
-
-    (transform* [& _] (no-transform!))))
+                  mixture))]
+
+
+  (defn range-select* [{:keys [inclusive-start desired-count] :as selector-element} {:keys [leaf-value] :as exval} next-fn]
+    (cond (rejected-nil? leaf-value selector-element)
+          (errcase explain/oopsies:should-not-be-applied-to-nil exval {:conj-path selector-element})
+
+          (nil? leaf-value)
+          (pad-the-end [] exval selector-element)
+
+          (not (sequential? leaf-value))
+          (errcase explain/oopsies:shouldbe-sequential exval {:conj-path selector-element})
+
+          :else
+          (-> exval
+              (extract-desired-range-as-exvals selector-element)
+              (pad-the-end exval selector-element)
+              (perhaps-rejecting-nil selector-element)
+              (descend next-fn)))))
+
+(extend-type RangePathElement
+  sp/StructurePath
+  (select* [this exval next-fn]
+    (range-select* this exval next-fn))
+  (transform* [& _] (no-transform!)))

 (letfn [(range-boom! [fmt [inclusive-start exclusive-end]]
@@ -233,19 +233,18 @@

 (extend-type IntegerPathElement
   sp/StructurePath
-  (select* [this {:keys [leaf-value] :as exval} next-fn]
-    (cond (rejected-nil? leaf-value this)
-          (errcase explain/oopsies:should-not-be-applied-to-nil exval {:conj-path this})
-
-          (nil? leaf-value)
-          nil
-
-          (not (sequential? leaf-value))
-          (errcase explain/oopsies:shouldbe-sequential exval {:conj-path this})
-
-          :else
-          (next-fn (update-exval exval {:conj-path (:index this)
-                                        :descend-into (nth leaf-value (:index this))}))))
+  (select* [this exval next-fn]
+    (let [inclusive-start (:index this)
+          exclusive-end (inc inclusive-start)]
+      (range-select* (map->RangePathElement {:inclusive-start inclusive-start
+                                             :exclusive-end exclusive-end
+                                             :bounds [inclusive-start exclusive-end]
+                                             :desired-count 1
+                                             :printable (str inclusive-start)
+                                             :reject-missing? (:reject-missing? this)
+                                             :reject-nil? (:reject-nil? this)})
+                     exval
+                     next-fn)))
   (transform* [& _] (no-transform!)))

 (defmethod clojure.core/print-method IntegerPathElement [o, ^java.io.Writer w]
@@ -269,9 +268,7 @@
         (->StringPathElement signifier)

         (integer? signifier)
-        (->RangePathElement signifier (inc signifier)
-                            [signifier (inc signifier)]
-                            1 (str signifier))
+        (->IntegerPathElement signifier)

         (instance? AllPathElement signifier)
         signifier


Check :ci_address_line_1 instead

Check :ci_address_line_1 instead

These columns are aliased with a prefix of `:ci_` when the tables are
joined.

--- src/vip/data_processor/db/translations/v5_1/contact_information.clj
+++ src/vip/data_processor/db/translations/v5_1/contact_information.clj
@@ -7,7 +7,7 @@
   ([xml-element]
    (fn [idx-fn parent-path row]
      (when-not (every? #(str/blank? (get row %))
-                       [:address_line_1
+                       [:ci_address_line_1
                         :ci_address_line_2
                         :ci_address_line_3
                         :ci_directions


Исправления кнопок на больших разрешениях

--- radiolamp-6P3S/src/r6p3s/cpt/carousel_layout.cljs
+++ radiolamp-6P3S/src/r6p3s/cpt/carousel_layout.cljs
@@ -22,7 +22,7 @@
       (dom/div
        #js {:className ""
             :style     #js {:padding 0}}
-
+
        (->> content-vec
             (map-indexed (fn [i element]
                            (dom/div #js {:style #js {:display
@@ -40,6 +40,7 @@
                                              app :active
                                              #(let [i (dec %)]
                                                 (if (< i 0) (dec pages) i))))})
+                (dom/div #js {})
                 (button/render {:text     (glyphicon/render "chevron-down")
                                 :style     #js {:marginTop 4}
                                 :on-click (fn []


Updated variables  from bp to biological process

--- resources/rules/post_identifier_merge/temp/goa/goa_biological_process_ice_to_bio.clj
+++ resources/rules/post_identifier_merge/temp/goa/goa_biological_process_ice_to_bio.clj
@@ -5,7 +5,7 @@
   :description "This rule creates a subclass of every biological process and types it as a gene ontology biological process concept identifier  (IAO_EXT_0000103)"
   :head (
          ;; create a subclass of the biological process
-         (?/process_sc rdfs/subClassOf ?/process)
+         (?/biological_process_sc rdfs/subClassOf ?/biological_process)
          ;; create a subclass of the participating bioentity
          (?/bioentity_sc rdfs/subClassOf ?/bioentity)

@@ -15,13 +15,13 @@
          (?/participation_restriction  owl/someValuesFrom ?/bioentity_sc)

          ;; connect the process subclass to the participation restriction
-         (?/process_sc rdfs/subClassOf ?/participation_restriction)
+         (?/biological_process_sc rdfs/subClassOf ?/participation_restriction)

          ;; provenance: connect the record to the process subclass
-         (?/record obo/IAO_0000219 ?/process_sc)) ; IAO:denotes
+         (?/record obo/IAO_0000219 ?/biological_process_sc)) ; IAO:denotes

   :body ((?/go_ice_id rdfs/subClassOf ccp/IAO_EXT_0000103) ; ccp:Gene_Ontology_Concept_Identifier__GO_biological_process_concept_identifier
-         (?/go_ice_id obo/IAO_0000219 ?/process) ; IAO:denotes
+         (?/go_ice_id obo/IAO_0000219 ?/biological_process) ; IAO:denotes
          (?/id_field_value rdf/type ?/go_ice_id)
          (?/id_field_value rdf/type ccp/IAO_EXT_0000014) ; ccp:GOA_GAF_v2.0_Annotation_record__ontology_term_identifier_field_value
          (?/record obo/BFO_0000051 ?/id_field_value) ; BFO:has_part
@@ -34,17 +34,16 @@
          (?/bioentity_ice_id obo/IAO_0000219 ?/participating_bioentity) ; IAO:denotes

          ;; filter out the negations
-          (:optional
-           ((?/record obo/BFO_0000051 ?/qualifier_field_value) ; BFO:has_part
-            (?/qualifier_field_value rdf/type ccp/IAO_EXT_0000013) ; ccp:GOA_GAF_v2.0_Annotation_record__qualifier_field_value
-            (?/qualifier_field_value rdfs/label ?/qualifier)))
+          (:optional ((?/record obo/BFO_0000051 ?/qualifier_field_value) ; BFO:has_part
+                      (?/qualifier_field_value rdf/type ccp/IAO_EXT_0000013) ; ccp:GOA_GAF_v2.0_Annotation_record__qualifier_field_value
+                      (?/qualifier_field_value rdfs/label ?/qualifier)))
           (:or (:not (:bound ?/qualifier))
                (:not (:regex ?/qualifier "^NOT" "i")))
          )

-  :reify ([?/process_sc {:ln (:sha-1 ?/process ?/participating_bioentity)
+  :reify ([?/biological_process_sc {:ln (:sha-1 ?/biological_process ?/participating_bioentity)
                  :ns "ccp" :prefix "BP_"}]
-          [?/bioentity_sc {:ln (:sha-1 ?/process ?/participating_bioentity)
+          [?/bioentity_sc {:ln (:sha-1 ?/biological_process ?/participating_bioentity)
                     :ns "ccp" :prefix "B_"}]
           [?/participation_restriction {:ln (:restriction)
                  :ns "ccp" :prefix "R_"}])


fix syntax error

fix syntax error

--- server/src/kyoodos/data.clj
+++ server/src/kyoodos/data.clj
@@ -3,7 +3,6 @@
   (:use [kyoodos.utils.query_generator]))

 (defqueries "queries/queries.sql")
-

 (defn get-user [user-id]
   (get-user-raw {:user_id user-id}))
@@ -15,7 +14,7 @@
   (case (str direction)
         "to" (get-to-kyoodos-raw {:user_or_group_id id})
         "from" (get-from-kyoodos-raw {:user_or_group_id id})
-        (get-kyoodos-raw))
+        (get-kyoodos-raw)))

 (defn valid-user? [id]
   (let [existence (valid-user {:id id})]
@@ -28,4 +27,3 @@
 (defn insert-kyoodos [content]
   (let [to (get-in content [:to])]
     (if (or (valid-user? to) (valid-group? to)) (insert-kyoodo-raw! {:from_user_id (content :from) :to_user_id (content :to) :content_raw (generate-string content) :content (content :content)}) (str "No such user or group: " to))))
-


Ensure that exceptions tossed from fixtures fail the build

--- integration-tests/src/test/clojure/immutant/integs.clj
+++ integration-tests/src/test/clojure/immutant/integs.clj
@@ -148,4 +148,7 @@
            (fn []
              (apply run-tests namespaces)))))
       (shutdown-agents)
-      (System/exit (if (empty? (filter #{:fail :error} @results)) 0 -1)))))
+      (System/exit (if (and (some #{:summary} @results)
+                            (not-any? #{:fail :error} @results))
+                     0
+                     -1)))))


remove redundant header

remove redundant header

--- src/braid/ui/views/pages/me.cljs
+++ src/braid/ui/views/pages/me.cljs
@@ -104,7 +104,6 @@
   (let [email-freq (subscribe [:user-preference :email-frequency])]
     (fn []
       [:div
-       [:h2 "Email Digest Settings"]
        [:p "If you wish, you can recieve emails notifying you of threads that you"
         " haven't seen yet."]
        [:p (str "Currently getting emails " ((fnil name "never") @email-freq))]


Now take multiple attempts at generating a sentence, and pick the one which had most choice points.

--- Spraff/src/spraff/core.clj
+++ Spraff/src/spraff/core.clj
@@ -10,6 +10,7 @@
     (:gen-class)
     (:use
         [clojure.java.io]
+        [clojure.string :only [join]]
         [irclj.core])
 )

@@ -20,6 +21,7 @@
 (def word-pattern #"\S+")
 (def generated-sentence-length 30)
 (def prefix-length 3)
+(def retries 5)

 (def table (ref {}))
 (def starters (ref []))
@@ -32,19 +34,24 @@
             word
             (recur (rest c) (- i weight)))))
 (defn pick-next-word [prefix t]
-    (when-let [candidates (t prefix)]
+    (when-let [candidates (t prefix)] [
         (select candidates
-            (rand-int (reduce + 0 (vals candidates))))))
+            (rand-int (reduce + 0 (vals candidates))))
+        (> (count candidates) 1)
+        ]))
 (defn further-stream-of-shite [prefix t]
     (lazy-seq
-        (when-let [c (pick-next-word prefix t)]
-            (cons c (further-stream-of-shite (concat (rest prefix) [c]) t)))))
+        (when-let [[word had-choice] (pick-next-word prefix t)]
+            (cons [word had-choice] (further-stream-of-shite (concat (rest prefix) [word]) t)))))
 (defn stream-of-shite [prefix t]
-    (concat prefix (further-stream-of-shite prefix t)))
-(defn generate-sentence []
-    (take generated-sentence-length (stream-of-shite
-        (nth @starters (rand-int (count @starters)))
-        @table)))
+    (concat (map vector prefix (repeat false)) (further-stream-of-shite prefix t)))
+(defn generate-sentence [] (dosync
+    (map first
+        (apply max-key #(count (filter true? (map second %)))
+            (take retries (repeatedly
+                #(take generated-sentence-length (stream-of-shite
+                    (nth @starters (rand-int (count @starters)))
+                    @table))))))))

 (defn value-or-default [value default]
     (if (nil? value) default value))
@@ -71,23 +78,21 @@
                 (ref-set starters (conj @starters (take prefix-length words)))))))
 (defn log-sentence! [message]
     (with-open [out (writer corpus-file :append true)]
-        (.write out (str message "\n"))
-        (update-message! message)))
+        (.write out (str message "\n")))
+    (update-message! message))

 (defn -main
-    "Java entry point.  Counts number of visible frames (via callbacks) and
-    terminates the application when none are visible."
     [& args]
     (let [bot (connect
             (create-irc {
                 :name bot-nick
                 :server irc-server
                 :fnmap {
-                    :on-message (fn [{:keys [nick channel message irc]}] (do
+                    :on-message (fn [{:keys [nick channel message irc]}]
                         (log-sentence! message)
                         (if (and (not (= nick (:name @irc))) (.contains message (:name @irc)))
                             (send-message irc channel
-                                (apply str (interpose " " (generate-sentence)))))))
+                                (join " " (generate-sentence)))))
                 }
             })
             :channels irc-channels)]


These actually use the _easy API

These actually use the _easy API

--- src/caesium/crypto/secretbox.clj
+++ src/caesium/crypto/secretbox.clj
@@ -6,7 +6,7 @@
 (defconsts [keybytes noncebytes macbytes primitive])

 (defn encrypt
-  "Encrypt with `secretbox`.
+  "Encrypt with `secretbox_easy`.

   Please note that this returns a (mutable!) byte array.

@@ -18,7 +18,7 @@
   (.encrypt (new SecretBox key) nonce plaintext))

 (defn decrypt
-  "Decrypt with `secretbox_open`.
+  "Decrypt with `secretbox_open_easy`.

   Please note that this returns a (mutable!) byte array.


give correct number of credits with Human First when Corp scores GFI

--- src/clj/game/cards-resources.clj
+++ src/clj/game/cards-resources.clj
@@ -253,10 +253,11 @@
                                   :effect (effect (lose :click 1) (gain :credit 2))}}}

    "Human First"
-   {:events {:agenda-scored {:msg (msg "gain " (get-agenda-points state :runner target) " [Credits]")
-                             :effect (effect (gain :runner :credit (get-agenda-points state :runner target)))}
+   {:events {:agenda-scored {:msg (msg "gain " (get-agenda-points state :corp target) " [Credits]")
+                             :effect (effect (gain :runner :credit (get-agenda-points state :corp target)))}
              :agenda-stolen {:msg (msg "gain " (get-agenda-points state :runner target) " [Credits]")
                              :effect (effect (gain :credit (get-agenda-points state :runner target)))}}}
+
    "Hunting Grounds"
    {:abilities [{:label "Prevent a \"when encountered\" ability on a piece of ICE"
                  :msg "prevent a \"when encountered\" ability on a piece of ICE"


Example Datomic queries.

Example Datomic queries.

--- src/clj/qualityclj/models/db.clj
+++ src/clj/qualityclj/models/db.clj
@@ -1,5 +1,5 @@
 (ns qualityclj.models.db
-  (:require [datomic.api :as d]
+  (:require [datomic.api :as d :refer [q db]]
             [clojure.java.io :as io]))

 (def uri (str "datomic:free://localhost:4334/qualityclj"))
@@ -16,3 +16,28 @@
         @(d/transact @conn schema-tx)
         @(d/transact @conn fixtures)))))

+(defn get-repos
+  "Get a list of all repos in the database."
+  []
+  (map first (q '[:find ?repo
+                  :where [_ :repo/uri ?repo]]
+                (db @conn))))
+
+(defn get-repo
+  "Given the name of a repo, return a database entity representing the
+  repository."
+  [name]
+  (let [id (q '[:find ?repo
+                :in $ ?name
+                :where
+                [?repo :repo/uri ?uri]
+                [(.contains ^String ?uri ^String ?name)]]
+              (db @conn) name)]
+    (d/entity (db @conn) (ffirst id))))
+
+(defn get-files
+
+  [repo]
+  (q '[:find ?file
+       :in $ ?repo
+       :where []]))


Def once the app-state atom

Def once the app-state atom


Change the inflection atoms to be private, and not dynamic vars

Fixes #14

--- src/clojure/contrib/inflect.cljc
+++ src/clojure/contrib/inflect.cljc
@@ -7,34 +7,45 @@
   ;; FIXME: duplicate
   (some #(= x %) coll))

-(def ^:dynamic *pluralize-noun-rules* (atom []))
-(def ^:dynamic *pluralize-noun-exceptions* (atom {}))
+(def ^:private pluralize-noun-rules (atom []))
+(def ^:private pluralize-noun-exceptions (atom {}))

 (defn pluralize-noun [count noun]
   "Return the pluralized noun if the `count' is
    not 1."
   {:pre [(<= 0 count)]}
   (let [singular? (== count 1)]
-    (if singular? noun ;; If singular, return noun
-        (some (fn [[cond? result-fn]]
+    (if singular?
+      noun                                                  ; If singular, return noun
+      (some (fn [[cond? result-fn]]
                 (if (cond? noun)
                   (result-fn noun)))
-              @*pluralize-noun-rules*))))
+            @pluralize-noun-rules))))

 (defn add-pluralize-noun-rule
+  "Adds a rule for pluralizing. The singular form of the noun is passed to the cond?
+  predicate and if that return a truthy value, the singular form is passed
+  to the result-fn to generate the plural form.
+
+  The rule description is for documentation only, it is ignored and may be nil."
   [rule-description cond? result-fn]
-  (swap! *pluralize-noun-rules*
-          conj
-          [cond? result-fn]))
+  (swap! pluralize-noun-rules
+         conj
+         [cond? result-fn]))

 (defn add-pluralize-noun-exceptions
+  "Adds some number of exception cases.
+
+   exceptions is a map from singular form to plural form.
+
+   The exception description is for documentation only, it is ignored and may be nil."
   [execption-description exceptions]
-  (swap! *pluralize-noun-exceptions* into exceptions))
+  (swap! pluralize-noun-exceptions into exceptions))

 ;; the order of rules is important
 (add-pluralize-noun-rule "For irregular nouns, use the exceptions."
-                         (fn [noun] (contains? @*pluralize-noun-exceptions* noun))
-                         (fn [noun] (@*pluralize-noun-exceptions* noun)))
+                         (fn [noun] (contains? @pluralize-noun-exceptions noun))
+                         (fn [noun] (@pluralize-noun-exceptions noun)))

 (add-pluralize-noun-rule "For nouns ending within consonant + y, suffixes `ies' "
                          (fn [noun] (and (ends-with? noun "y")


Adjusted for resolution of variable lat/lon dimensions.

--- src/cmr/opendap/ous/variable.clj
+++ src/cmr/opendap/ous/variable.clj
@@ -62,7 +62,6 @@

 (def default-dim-stride 1)
 (def default-lat-lon-stride 1)
-(def default-lat-lon-resolution 1)

 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;;   Records   ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -114,6 +113,16 @@
 ;;;   Support/Utility Functions   ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

+(defn adjusted-lon
+  [lon resolution]
+  (- (* lon resolution)
+     (* default-lon-lo resolution)))
+
+(defn adjusted-lat
+  [lat resolution]
+  (- (* lat resolution)
+     (* default-lat-lo resolution)))
+
 ;; XXX Can we use these instead? Why was the phase shifting written
 ;;     so obtrusely? There's got to be a reason, I just don't know it ...
 ;; XXX This is being tracked in CMR-4959
@@ -132,21 +141,25 @@

 (defn lon-lo-phase-shift
   [lon-max lon-lo]
-  (log/debug "Got lon-max:" lon-max)
-  (-> (/ (* (dec lon-max)
-            (- lon-lo default-lon-lo))
-         (- default-lon-hi default-lon-lo))
-      Math/floor
-      int))
+  (let [res (/ lon-max default-lon-abs-hi)]
+    (log/debug "Got lon-max:" lon-max)
+    (log/debug "Got resolution:" res)
+    (-> (/ (* (dec lon-max)
+              (adjusted-lon lon-lo res))
+           (adjusted-lon default-lon-hi res))
+        Math/floor
+        int)))

 (defn lon-hi-phase-shift
   [lon-max lon-hi]
-  (log/debug "Got lon-max:" lon-max)
-  (-> (/ (* (dec lon-max)
-            (- lon-hi default-lon-lo))
-         (- default-lon-hi default-lon-lo))
-      Math/ceil
-      int))
+  (let [res (/ lon-max default-lon-abs-hi)]
+    (log/debug "Got lon-max:" lon-max)
+    (log/debug "Got resolution:" res)
+    (-> (/ (* (dec lon-max)
+              (adjusted-lon lon-hi res))
+           (adjusted-lon default-lon-hi res))
+        Math/ceil
+        int)))

 ;; XXX Note that the following two functions were copied from this JS:
 ;;
@@ -191,23 +204,27 @@

 (defn lat-lo-phase-shift
   [lat-max lat-lo]
-  (log/debug "Got lat-max:" lat-max)
-  (int
-    (- lat-max
-       1
-       (Math/floor (/ (* (dec lat-max)
-                         (- lat-lo default-lat-lo))
-                      (- default-lat-hi default-lat-lo))))))
+  (let [res (/ lat-max default-lat-abs-hi)]
+    (log/debug "Got lat-max:" lat-max)
+    (log/debug "Got resolution:" res)
+    (int
+      (- lat-max
+         1
+         (Math/floor (/ (* (dec lat-max)
+                           (adjusted-lat lat-lo res))
+                        (adjusted-lat default-lat-hi res)))))))

 (defn lat-hi-phase-shift
   [lat-max lat-hi]
-  (log/debug "Got lat-max:" lat-max)
-  (int
-    (- lat-max
-       1
-       (Math/ceil (/ (* (dec lat-max)
-                        (- lat-hi default-lat-lo))
-                     (- default-lat-hi default-lat-lo))))))
+  (let [res (/ lat-max default-lat-abs-hi)]
+    (log/debug "Got lat-max:" lat-max)
+    (log/debug "Got resolution:" res)
+    (int
+      (- lat-max
+         1
+         (Math/ceil (/ (* (dec lat-max)
+                          (adjusted-lat lat-hi res))
+                       (adjusted-lat default-lat-hi res)))))))

 (defn normalize-lat-lon
   [dim]


Use correct error spec for process-error definition

--- src/com/wsscode/pathom/core.cljc
+++ src/com/wsscode/pathom/core.cljc
@@ -22,12 +22,17 @@
   (s/fspec :args (s/cat :reader ::reader)
            :ret ::reader))

+(s/def ::error
+  (s/spec #?(:clj  #(instance? Throwable %)
+             :cljs #(instance? js/Error %))
+    :gen #(s/gen #{(ex-info "Generated sample error" {:some "data"})})))
+
 (s/def ::errors (s/map-of vector? any?))

 (s/def ::errors* #(instance? IAtom %))

 (s/def ::process-error
-  (s/fspec :args (s/cat :env ::env :error any?)
+  (s/fspec :args (s/cat :env ::env :error ::error)
            :ret any?))

 (s/def ::entity any?)


Fixed cache async to avoid concurrent issues

--- src/com/wsscode/pathom/core.cljc
+++ src/com/wsscode/pathom/core.cljc
@@ -836,14 +836,17 @@
 (defn cached-async [env key f]
   (if-let [cache (get env ::request-cache)]
     (do
-      (if-let [hit (get @cache key)]
-        (do (pt/trace env {::pt/event ::cache-hit ::cache-key key})
-            (casync/throw-err hit))
-        (do
-          (pt/trace env {::pt/event ::cache-miss ::cache-key key})
-          (let [hit (go-promise (<!maybe (f)))]
-            (swap! cache update key #(or % hit))
-            hit))))
+      (swap! cache update key
+        (fn [x]
+          (if x
+            (do
+              (pt/trace env {::pt/event ::cache-hit ::cache-key key})
+              x)
+            (do
+              (pt/trace env {::pt/event ::cache-miss ::cache-key key})
+              (go-promise (<!maybe (f)))))))
+
+      (get cache key))
     (go-promise (<!maybe (f)))))

 (defn cache-hit [{::keys [request-cache] :as env} key value]


RS + CW | #134 | Add integration tests to ensure writer notes appear on comments dashboard and annotations dashboard

--- test/objective8/integration/front_end/dashboard.clj
+++ test/objective8/integration/front_end/dashboard.clj
@@ -293,7 +293,30 @@
                (http-api/get-comments anything {:sorted-by "up-votes"
                                                 :filter-type "has-writer-note"
                                                 :limit 50}) => {:status ::http-api/success
-                                                                :result []})))
+                                                                :result []}))
+
+       (fact "can see form if comment has no note"
+             (let [{response :response} (-> user-session
+                                            ih/sign-in-as-existing-user
+                                            (p/request (utils/path-for :fe/dashboard-comments :id OBJECTIVE_ID)))]
+               (:status response) => 200
+               (:body response) => (contains "note-on-uri")))
+
+
+       (fact "can see note text if the comment has a note"
+             (against-background
+               (http-api/get-comments anything anything) => {:status ::http-api/success
+                                                       :result [{:comment "A comment"
+                                                                 :_created_at "2015-01-01T01:01:00.000Z"
+                                                                 :username "A User"
+                                                                 :note "test note"
+                                                                 :votes {:up 5 :down 3}}]})
+             (let [{response :response} (-> user-session
+                                            ih/sign-in-as-existing-user
+                                            (p/request (utils/path-for :fe/dashboard-comments :id OBJECTIVE_ID)))]
+               (:status response) => 200
+               (:body response) => (contains "test note"))))
+
 (def section [["h1" {:data-section-label "1234abcd"} "A Heading"]])

 (facts "about the annotations dashboard for writers"
@@ -314,22 +337,45 @@
                                                                        :username "A User"
                                                                        :votes {:up 5 :down 3}}]}]})

-  (fact "can view annotations on dashboard"
-    (let [{response :response} (-> user-session
-                                 ih/sign-in-as-existing-user
-                                 (p/request (utils/path-for :fe/dashboard-annotations :id OBJECTIVE_ID)))]
-      (:status response) => 200
-      (:body response) => (contains "Objective title")
-      (:body response) => (contains "A Heading")
-      (:body response) => (contains "A section comment")))
-
-  (fact "can view drafting warning message when annotaions api returns not-found"
-         (against-background
-           (http-api/get-annotations anything) => {:status ::http-api/not-found
-                                                   :result []})
-
+       (fact "can view annotations on dashboard"
              (let [{response :response} (-> user-session
                                             ih/sign-in-as-existing-user
                                             (p/request (utils/path-for :fe/dashboard-annotations :id OBJECTIVE_ID)))]
                (:status response) => 200
+               (:body response) => (contains "Objective title")
+               (:body response) => (contains "A Heading")
+               (:body response) => (contains "A section comment")))
+
+       (fact "can see form if annotation has no note"
+             (let [{response :response} (-> user-session
+                                            ih/sign-in-as-existing-user
+                                            (p/request (utils/path-for :fe/dashboard-annotations :id OBJECTIVE_ID)))]
+               (:status response) => 200
+               (:body response) => (contains "note-on-uri")))
+
+
+       (fact "can see note text if the annotations has a note"
+             (against-background
+               (http-api/get-annotations anything) => {:status ::http-api/success
+                                                 :result [{:section section
+                                                           :comments [{:comment "A section comment"
+                                                                       :_created_at "2015-01-01T01:01:00.000Z"
+                                                                       :username "A User"
+                                                                       :note "test note"
+                                                                       :votes {:up 5 :down 3}}]}]})
+             (let [{response :response} (-> user-session
+                                            ih/sign-in-as-existing-user
+                                            (p/request (utils/path-for :fe/dashboard-annotations :id OBJECTIVE_ID)))]
+               (:status response) => 200
+               (:body response) => (contains "test note")))
+
+       (fact "can view drafting warning message when annotaions api returns not-found"
+             (against-background
+               (http-api/get-annotations anything) => {:status ::http-api/not-found
+                                                       :result []})
+
+             (let [{response :response} (-> user-session
+                                            ih/sign-in-as-existing-user
+                                            (p/request (utils/path-for :fe/dashboard-annotations :id OBJECTIVE_ID)))]
+               (:status response) => 200
                (:body response) => (contains "There are no annotations associated with this draft."))))


More test cases for camel->snake

More test cases for camel->snake

--- test/vip/data_processor/db/tree_statistics_test.clj
+++ test/vip/data_processor/db/tree_statistics_test.clj
@@ -4,5 +4,8 @@

 (deftest camel->snake-test
   (testing "got the regex close"
-    (are [x y] (= x y)
-      "snake_from_camel" (camel->snake "SnakeFromCamel"))))
+    (are [x y] (= (camel->snake x) y)
+      "SnakeFromCamel" "snake_from_camel"
+       "Oneword" "oneword"
+       "ABBRHandledLikeThis" "abbr_handled_like_this"
+       "lowercase" "lowercase")))


Slightly better example

Slightly better example

--- test/as_documentation/prerequisites__the_basics.clj
+++ test/as_documentation/prerequisites__the_basics.clj
@@ -238,7 +238,7 @@
   (find-letter) => ..letter-result..
   (provided
     (letter & (just "this" "doesn't" "match")) => ..bogus-result.. :times 0
-    (letter & (just "x" "y" "z")) => ..letter-result..))
+    (letter & (contains ["x" "y"])) => ..letter-result..))


Cleanup item create code.

Cleanup item create code.

--- test/fcms/integration/rest_api/item/item_create.clj
+++ test/fcms/integration/rest_api/item/item_create.clj
@@ -233,11 +233,11 @@
     (fact "with a property that conflicts with a reserved property"
       ;; conflicts with each reserved property
       (doseq [keyword-name resource/reserved-properties]
-        (let [response (create-item-with-api {:name i keyword-name "foo"})]
+        (let [response (create-item-with-api {:name i keyword-name "foo"})
+              body (body-from-response response)]
           (:status response) => 422
           (response-mime-type response) => (mime-type :text)
-          (let [body (body-from-response response)]
-            (.contains body "A reserved property was used.") => true)
+          (.contains body "A reserved property was used.") => true
           ;; check if collection is still empty
           (collection/item-count e) => 0)))

@@ -314,12 +314,12 @@
     ;; curl -i --header "Accept: application/vnd.fcms.item+json;version=1" --header "Content-Type: application/vnd.fcms.item+json;version=1" --header "Charset: UTF-8" -X POST -d '{"name":"g' http://localhost:3000/c/'
     (fact "create an item with an invalid body"
       (doseq [bad-body ["Hi Mom!" "{'name': 'i'"]]
-        (let [response (create-item-with-api bad-body)]
+        (let [response (create-item-with-api bad-body)
+              body (body-from-response response)]
           (:status response) => 400
           (response-mime-type response) => (mime-type :text)
           (response-location response) => nil
-          (let [body (body-from-response response)]
-            (.contains body "Bad request.") => true)
+          (.contains body "Bad request.") => true
           (collection/item-count e) => 0)))

     ;; collection doesn't exist - 404 Not Found
@@ -340,11 +340,11 @@
     ;; no "name" in body - 422 Unprocessable Entity
     ;; curl -i --header "Accept: application/vnd.fcms.item+json;version=1" --header "Content-Type: application/vnd.fcms.item+json;version=1" --header "Charset: UTF-8" -X POST -d '{"slug":"i"}' http://localhost:3000/c/
     (fact "create an item without a name"
-      (let [response (create-item-with-api {:slug i})]
+      (let [response (create-item-with-api {:slug i})
+            body (body-from-response response)]
         (:status response) => 422
         (response-mime-type response) => (mime-type :text)
-        (let [body (body-from-response response)]
-          (.contains body "Name is required.") => true)
+        (.contains body "Name is required.") => true
         (collection/item-count e) => 0))

     ;; slug specified in body is already used - 422 Unprocessable Entity
@@ -362,21 +362,21 @@
           :slug i
           :version 1})
         (collection/item-count e) => 1)
-      (let [response (create-item-with-api {:name "another-i" :slug i})]
+      (let [response (create-item-with-api {:name "another-i" :slug i})
+            body (body-from-response response)]
         (:status response) => 422
         (response-mime-type response) => (mime-type :text)
         (response-location response) => nil
-        (let [body (body-from-response response)]
-          (.contains body "Slug already used in collection.") => true)
+        (.contains body "Slug already used in collection.") => true
         (collection/item-count e) => 1))

     ;; slug specified in body is invalid - 422 Unprocessable Entity
     ;; curl -i --header "Accept: application/vnd.fcms.item+json;version=1" --header "Content-Type: application/vnd.fcms.item+json;version=1" --header "Charset: UTF-8" -X POST -d '{"name":"i", "slug":"I i"}' http://localhost:3000/c/
     (fact "create an item with a slug that's invalid"
-      (let [response (create-item-with-api {:name i :slug "I i"})]
+      (let [response (create-item-with-api {:name i :slug "I i"})
+            body (body-from-response response)]
         (:status response) => 422
         (response-mime-type response) => (mime-type :text)
         (response-location response) => nil
-        (let [body (body-from-response response)]
-          (.contains body "Invalid slug.") => true)
+        (.contains body "Invalid slug.") => true
         (collection/item-count e) => 0))))


More cosmectics for with-swing-error-msg

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

--- src/conexp/contrib/gui/util.clj
+++ src/conexp/contrib/gui/util.clj
@@ -56,10 +56,12 @@
          (show!
           (dialog :parent ~frame
                   :size [600 :by 300]
-                  :content (border-panel :north (str cause#)
-                                         :center (scrollable (text :text (apply str (root-cause e#) "\n"
-                                                                                (interpose "\n" (.getStackTrace e#)))
-                                                                   :multi-line? true)))
+                  :content (vertical-panel :items [[:fill-v 10]
+                                                   (.getMessage cause#)
+                                                   [:fill-v 10]
+                                                   (scrollable (text :text (apply str (root-cause e#) "\n"
+                                                                                (interpose "\n" (.getStackTrace e#)))
+                                                                     :multi-line? true))])
                   :type :error
                   :title ~title))))))


Fix test `all-snippets-map-to-function`.

--- test/clj/quil/snippet.clj
+++ test/clj/quil/snippet.clj
@@ -74,7 +74,7 @@
   (define-snippet-as-test snippet))

 (t/deftest all-snippets-map-to-function
-  (doseq [{:keys [fns name]} @as/all-snippets
+  (doseq [{:keys [fns name]} as/all-snippets
           fn fns]
     (when (nil? (ns-resolve 'quil.core (symbol fn)))
       (throw (ex-info (str "Snippet '" name "' matches to non-existent function '" fn "'")


add TODO

add TODO

--- src/main/om_css/core.clj
+++ src/main/om_css/core.clj
@@ -48,6 +48,7 @@
             (recur nil dt')))
         dt'))))

+;; TODO: check that Style does not need to be implemented with `static`
 (defn get-style-form [forms]
   (loop [dt forms]
     (when (seq  dt)


more matchers

more matchers

--- src/matcha.clj
+++ src/matcha.clj
@@ -23,17 +23,18 @@
 ;;  if pass? if false
 ;;
 ;;  TODO: matchers list
-;;  - containsString
-;;  - startsWith
-;;  - endsWith
-;;  - equalIgnoringCase
-;;  - equalIgnoringWhiteSpace
-;;  - stringContainsInOrder
 (defn describe-list [call xs]
   (str "(" call " " (clojure.string/join " " xs) ")"))

 (defn standard-describe-mismatch [x]
   (pr-str x))
+
+(defn describe-class-mismatch [x]
+  (str (pr-str x)
+       (if (clojure.core/nil? x)
+         ""
+         (str " <" (class x) ">"))))
+

 (defn describe-mismatch-feature [x feature-name feature-mismatch]
   (str (standard-describe-mismatch x) " with " feature-name " " feature-mismatch))
@@ -240,6 +241,79 @@
     {:match #(.contains ^String % s)
      :description (str "a string including " (pr-str s))}))

+(defn starts-with
+  "passes if the string starts with the given string
+
+  (matcha/run-match (matcha/starts-with \"a\") \"ab\") ; => passes
+  (matcha/run-match (matcha/starts-with \"a\") \"ba\") ; => fails"
+  [s]
+  (type-matcher
+    core/string?
+    "string"
+    {:match #(.startsWith ^String % s)
+     :description (str "a string starting with " (pr-str s))}))
+
+(defn ends-with
+  "passes if the string ends with the given string
+
+  (matcha/run-match (matcha/ends-with \"a\") \"ba\") ; => passes
+  (matcha/run-match (matcha/ends-with \"a\") \"ab\") ; => fails"
+  [s]
+  (type-matcher
+    core/string?
+    "string"
+    {:match #(.endsWith ^String % s)
+     :description (str "a string ending with " (pr-str s))}))
+
+(defn equal-ignoring-case
+  "passes if the string is equal to the other string ignoring case
+
+  (matcha/run-match (matcha/equal-ignoring-case \"a\") \"A\") ; => passes
+  (matcha/run-match (matcha/equal-ignoring-case \"a\") \"ab\") ; => fails"
+  [s]
+  (type-matcher
+    core/string?
+    "string"
+    (on #(.toLowerCase ^String %) (= (.toLowerCase ^String s)) "lower case" "string")))
+
+(defn equal-ignoring-whitespace
+  "passes if the string is equal to the other string ignoring whitespace
+
+  (matcha/run-match (matcha/equal-ignoring-whitespace \"a\") \"a \") ; => passes
+  (matcha/run-match (matcha/equal-ignoring-whitespace \"a \") \"ab\") ; => fails"
+  [s]
+  (type-matcher
+    core/string?
+    "string"
+    (on #(.replaceAll ^String % "\\s+" "")
+        (= (.replaceAll ^String s "\\s+" ""))
+        "without whitespace"
+        "string")))
+
+(defn contains-in-order-matches [given-string strings]
+  (reduce
+    (fn [prev-index string]
+      (let [index (.indexOf ^String given-string string prev-index)]
+        (if (core/= index -1)
+          (reduced false)
+          index)))
+    0
+    strings))
+
+(defn contains-in-order
+  "passes if the string contains the strings in order
+
+  (matcha/run-match (matcha/contains-in-order \"a\" \"b\") \"ab\") ; => passes
+  (matcha/run-match (matcha/contains-in-order \"a\" \"b\") \"ac\") ; => fails"
+  [& strings]
+  (type-matcher
+    core/string?
+    "string"
+    {:match
+     (fn [given-string]
+       (contains-in-order-matches given-string strings))
+     :description (str "a string containing " (string/join ", " (map pr-str strings)) " in order")}))
+
 (defn not
   "passes if the given matcher fails
   (matcha/run-match (matcha/not (matcha/= 1)) 1) ; => passes
@@ -250,12 +324,6 @@
    :describe-mismatch
    standard-describe-mismatch})

-(defn describe-class-mismatch [x]
-  (str "was " (pr-str x)
-       (if (clojure.core/nil? x)
-         ""
-         (str " <" (class x) ">"))))
-
 (defn instance?
   "passes if the value matches the given class
   (matcha/run-match (matcha/instance? clojure.lang.Keyword) :foo) ; => passes


fix indentation

fix indentation

--- src/overtone/sc/buffer.clj
+++ src/overtone/sc/buffer.clj
@@ -228,5 +228,5 @@
     (create-buffer-data 1024 #(- (* 2 % %) 1) -1 1)"
   [size f range-min range-max]
   (let [range-size (- range-max range-min)
-	rangemap  #(+ range-min (/ (* % range-size) size))]
+        rangemap  #(+ range-min (/ (* % range-size) size))]
     (map #(float (f (rangemap %))) (range 0 size))))


thru rm_lm_device_use_duration

thru rm_lm_device_use_duration

--- src/pg_demo/table_defs.clj
+++ src/pg_demo/table_defs.clj
@@ -3642,6 +3642,310 @@
               PRIMARY KEY (ENTERPRISE_ID,ATTACHMENT_ID)
           ); " }

+    { "rm_lm_birth_type"
+          "CREATE TABLE rm_lm_birth_type (
+              ENTERPRISE_ID numeric NOT NULL,
+              BIRTH_TYPE_ID numeric NOT NULL,
+              BIRTH_TYPE varchar(35) NOT NULL,
+              DISPLAY numeric,
+              PROTECTED numeric,
+              BIRTH_TYPE_J varchar(35),
+              DELETED timestamp,
+              PRIMARY KEY (ENTERPRISE_ID,BIRTH_TYPE_ID)
+          ); " }
+
+    { "rm_lm_case_classification"
+          "CREATE TABLE rm_lm_case_classification (
+              ENTERPRISE_ID numeric NOT NULL,
+              CLASSIFICATION_ID numeric NOT NULL,
+              DESCRIPTION varchar(30) NOT NULL,
+              PROTECTED numeric,
+              DISPLAY numeric,
+              DESCRIPTION_J varchar(30),
+              DELETED timestamp,
+              E2B_CODE numeric,
+              PRIMARY KEY (ENTERPRISE_ID,CLASSIFICATION_ID)
+          ); " }
+
+    { "rm_lm_causality"
+          "CREATE TABLE rm_lm_causality (
+              ENTERPRISE_ID numeric NOT NULL,
+              CAUSALITY_ID numeric NOT NULL,
+              CAUSALITY varchar(35) NOT NULL,
+              REPORTABILITY numeric,
+              PROTECTED numeric,
+              DISPLAY numeric,
+              CAUSALITY_J varchar(35),
+              DELETED timestamp,
+              PRIMARY KEY (ENTERPRISE_ID,CAUSALITY_ID)
+          ); " }
+
+    { "rm_lm_causality_category"
+          "CREATE TABLE rm_lm_causality_category (
+              ENTERPRISE_ID numeric NOT NULL,
+              CAUSALITY_ID numeric NOT NULL,
+              CAUSALITY_MIN_SCORE numeric,
+              CAUSALITY_MAX_SCORE numeric,
+              DELETED timestamp,
+              PRIMARY KEY (ENTERPRISE_ID,CAUSALITY_ID)
+          ); " }
+
+    { "rm_lm_causality_source"
+          "CREATE TABLE rm_lm_causality_source (
+              ENTERPRISE_ID numeric NOT NULL,
+              SOURCE_ID numeric NOT NULL,
+              SOURCE varchar(35),
+              PROTECTED numeric,
+              DISPLAY numeric,
+              SOURCE_J varchar(35),
+              DELETED timestamp,
+              PRIMARY KEY (ENTERPRISE_ID,SOURCE_ID)
+          ); " }
+
+    { "rm_lm_centers"
+          "CREATE TABLE rm_lm_centers (
+              ENTERPRISE_ID numeric NOT NULL,
+              CENTER_ID numeric NOT NULL,
+              CENTER_NO varchar(20),
+              CENTER_NAME varchar(40),
+              ADDRESS varchar(120),
+              CENTER_NAME_J varchar(40),
+              CENTER_NO_J varchar(20),
+              DELETED timestamp,
+              PRIMARY KEY (ENTERPRISE_ID,CENTER_ID)
+          ); " }
+
+    { "rm_lm_classification"
+          "CREATE TABLE rm_lm_classification (
+              ENTERPRISE_ID numeric NOT NULL,
+              CLASSIFICATION_ID numeric NOT NULL,
+              CLASSIFICATION varchar(30) NOT NULL,
+              DISPLAY numeric(1),
+              PROTECTED numeric(1),
+              E2B_ADDITIONAL_DOC numeric,
+              CLASSIFICATION_J varchar(30),
+              DELETED timestamp,
+              PRIMARY KEY (ENTERPRISE_ID,CLASSIFICATION_ID)
+          ); " }
+
+    { "rm_lm_classification_sites"
+          "CREATE TABLE rm_lm_classification_sites (
+              ENTERPRISE_ID numeric NOT NULL,
+              SEQ_NUM numeric(22) NOT NULL,
+              SITE_ID numeric(22) NOT NULL,
+              CLASSIFICATION_ID numeric(22) NOT NULL,
+              DELETED timestamp,
+              PRIMARY KEY (ENTERPRISE_ID,SEQ_NUM)
+          ); " }
+
+    { "rm_lm_clinical_ref_types"
+          "CREATE TABLE rm_lm_clinical_ref_types (
+              ENTERPRISE_ID numeric NOT NULL,
+              REF_TYPE_ID numeric NOT NULL,
+              REF_TYPE_DESC varchar(20),
+              REG_NUM_SIZE numeric,
+              PROTECTED numeric,
+              REF_TYPE_DESC_J varchar(20),
+              DELETED timestamp,
+              PRIMARY KEY (ENTERPRISE_ID,REF_TYPE_ID)
+          ); " }
+
+    { "rm_lm_condition_type"
+          "CREATE TABLE rm_lm_condition_type (
+              ENTERPRISE_ID numeric NOT NULL,
+              CONDITION_TYPE_ID numeric NOT NULL,
+              COND_TYPE varchar(20) NOT NULL,
+              PROTECTED numeric,
+              DISPLAY numeric,
+              DELETED timestamp,
+              COND_CATEGORY numeric(1),
+              COND_TYPE_J varchar(20),
+              PRIMARY KEY (ENTERPRISE_ID,CONDITION_TYPE_ID)
+          ); " }
+
+    { "rm_lm_contact_type"
+          "CREATE TABLE rm_lm_contact_type (
+              ENTERPRISE_ID numeric NOT NULL,
+              CONTACT_ID numeric NOT NULL,
+              CONTACT_TYPE varchar(10) NOT NULL,
+              DESCRIPTION varchar(120),
+              DISPLAY numeric(4) NOT NULL,
+              PROTECTED numeric(4) NOT NULL,
+              CONTACT_TYPE_J varchar(10),
+              DESCRIPTION_J varchar(120),
+              DELETED timestamp,
+              PRIMARY KEY (ENTERPRISE_ID,CONTACT_ID)
+          ); " }
+
+    { "rm_lm_costart"
+          "CREATE TABLE rm_lm_costart (
+              ENTERPRISE_ID numeric NOT NULL,
+              CODE varchar(50) NOT NULL,
+              DESCRIPTION varchar(1000),
+              DELETED timestamp,
+              PRIMARY KEY (ENTERPRISE_ID,CODE)
+          ); " }
+
+    { "rm_lm_countries"
+          "CREATE TABLE rm_lm_countries (
+              ENTERPRISE_ID numeric NOT NULL,
+              COUNTRY_ID numeric NOT NULL,
+              COUNTRY varchar(50) NOT NULL,
+              A2 varchar(2),
+              A3 varchar(3),
+              NUM numeric,
+              PROTECTED numeric,
+              DELETED timestamp,
+              COUNTRY_GROUP_ID numeric,
+              COUNTRY_GROUP varchar(50),
+              COUNTRY_J varchar(50),
+              GROUP_2_COUNTRY numeric,
+              PRIMARY KEY (ENTERPRISE_ID,COUNTRY_ID)
+          ); " }
+
+    { "rm_lm_datasheet"
+          "CREATE TABLE rm_lm_datasheet (
+              ENTERPRISE_ID numeric NOT NULL,
+              DATASHEET_ID numeric NOT NULL,
+              SHEET_NAME varchar(40),
+              CORE_SHEET numeric,
+              FAMILY_ID numeric,
+              DELETED timestamp,
+              REVISION numeric NOT NULL,
+              ACTIVATION_DATE timestamp,
+              MAX_REVISION numeric,
+              NO_LOCAL_ASSESSMENT numeric,
+              INCLUDE_DATASHEET_ID numeric,
+              SHEET_NAME_J varchar(40),
+              NOTES text,
+              PRIMARY KEY (ENTERPRISE_ID,DATASHEET_ID,REVISION)
+          ); " }
+
+    { "rm_lm_datasheet_event_groups"
+          "CREATE TABLE rm_lm_datasheet_event_groups (
+              ENTERPRISE_ID numeric NOT NULL,
+              SEQ_NUM numeric NOT NULL,
+              DATASHEET_ID numeric NOT NULL,
+              REVISION numeric NOT NULL,
+              EG_ID numeric NOT NULL,
+              DELETED timestamp,
+              PRIMARY KEY (ENTERPRISE_ID,SEQ_NUM)
+          ); " }
+
+    { "rm_lm_date_ranges"
+          "CREATE TABLE rm_lm_date_ranges (
+              ENTERPRISE_ID numeric NOT NULL,
+              RANGE_ID numeric NOT NULL,
+              RANGE_NAME varchar(20) NOT NULL,
+              DURATION numeric,
+              FROM_DATE timestamp,
+              TO_DATE timestamp,
+              UNITS varchar(10),
+              RANGE_NAME_J varchar(20),
+              DELETED timestamp,
+              PRIMARY KEY (ENTERPRISE_ID,RANGE_ID)
+          ); " }
+
+    { "rm_lm_delivery_types"
+          "CREATE TABLE rm_lm_delivery_types (
+              ENTERPRISE_ID numeric NOT NULL,
+              DELIVERY_TYPE_ID numeric NOT NULL,
+              DELIVERY_TYPE varchar(30) NOT NULL,
+              PROTECTED numeric,
+              DISPLAY numeric,
+              DELIVERY_TYPE_J varchar(30),
+              DELETED timestamp,
+              PRIMARY KEY (ENTERPRISE_ID,DELIVERY_TYPE_ID)
+          ); " }
+
+    { "rm_lm_device_cur_status"
+          "CREATE TABLE rm_lm_device_cur_status (
+              ENTERPRISE_ID numeric NOT NULL,
+              STATUS_ID numeric NOT NULL,
+              STATUS varchar(30),
+              STATUS_J varchar(30),
+              DELETED timestamp,
+              PRIMARY KEY (ENTERPRISE_ID,STATUS_ID)
+          ); " }
+
+    { "rm_lm_device_future_act"
+          "CREATE TABLE rm_lm_device_future_act (
+              ENTERPRISE_ID numeric NOT NULL,
+              ACTION_ID numeric NOT NULL,
+              ACTION varchar(30),
+              ACTION_J varchar(30),
+              DELETED timestamp,
+              PRIMARY KEY (ENTERPRISE_ID,ACTION_ID)
+          ); " }
+
+    { "rm_lm_device_mal_status"
+          "CREATE TABLE rm_lm_device_mal_status (
+              ENTERPRISE_ID numeric NOT NULL,
+              STATUS_ID numeric NOT NULL,
+              STATUS varchar(10),
+              STATUS_J varchar(10),
+              DELETED timestamp,
+              PRIMARY KEY (ENTERPRISE_ID,STATUS_ID)
+          ); " }
+
+    { "rm_lm_device_pre_comments"
+          "CREATE TABLE rm_lm_device_pre_comments (
+              ENTERPRISE_ID numeric NOT NULL,
+              PRE_COMMENTS_ID numeric NOT NULL,
+              DISPLAY numeric,
+              PROTECTED numeric,
+              DELETED timestamp,
+              PRE_COMMENTS text,
+              PRE_COMMENTS_J text,
+              PRIMARY KEY (ENTERPRISE_ID,PRE_COMMENTS_ID)
+          ); " }
+
+    { "rm_lm_device_rpt_category"
+          "CREATE TABLE rm_lm_device_rpt_category (
+              ENTERPRISE_ID numeric NOT NULL,
+              CATEGORY_ID numeric NOT NULL,
+              CATEGORY varchar(40),
+              CATEGORY_J varchar(40),
+              DISPLAY numeric,
+              PROTECTED numeric,
+              DELETED timestamp,
+              PRIMARY KEY (ENTERPRISE_ID,CATEGORY_ID)
+          ); " }
+
+    { "rm_lm_device_subcomponents"
+          "CREATE TABLE rm_lm_device_subcomponents (
+              ENTERPRISE_ID numeric NOT NULL,
+              SUBCOMPONENT_ID numeric NOT NULL,
+              SUBCOMPONENT_NAME varchar(50),
+              DISPLAY numeric,
+              PROTECTED numeric,
+              SUBCOMPONENT_NAME_J varchar(50),
+              DELETED timestamp,
+              PRIMARY KEY (ENTERPRISE_ID,SUBCOMPONENT_ID)
+          ); " }
+
+    { "rm_lm_device_type"
+          "CREATE TABLE rm_lm_device_type (
+              ENTERPRISE_ID numeric NOT NULL,
+              DEVICE_TYPE_ID numeric NOT NULL,
+              DEVICE_TYPE_DESC varchar(50) NOT NULL,
+              DISPLAY numeric,
+              PROTECTED numeric,
+              DEVICE_TYPE_DESC_J varchar(50),
+              DELETED timestamp,
+              PRIMARY KEY (ENTERPRISE_ID,DEVICE_TYPE_ID)
+          ); " }
+
+    { "rm_lm_device_use_duration"
+          "CREATE TABLE rm_lm_device_use_duration (
+              ENTERPRISE_ID numeric NOT NULL,
+              DURATION_ID numeric NOT NULL,
+              DURATION varchar(10),
+              DURATION_J varchar(10),
+              DELETED timestamp,
+              PRIMARY KEY (ENTERPRISE_ID,DURATION_ID)
+          ); " }
+
   ] ))

 (def dummy


Correct ns

Correct ns

--- metrics-clojure-core/test/metrics/test/timers_test.clj
+++ metrics-clojure-core/test/metrics/test/timers_test.clj
@@ -1,4 +1,4 @@
-(ns metrics.test.timers
+(ns metrics.test.timers-test
   (:require [metrics.core :as mc]
             [metrics.timers :as mt]
             [metrics.test.test-utils :refer :all]


FIX: add missing index on resources table

--- ssclj/jar/src/main/clojure/com/sixsq/slipstream/ssclj/db/database_binding.clj
+++ ssclj/jar/src/main/clojure/com/sixsq/slipstream/ssclj/db/database_binding.clj
@@ -21,6 +21,7 @@
   (acl/-init)
   (kh/korma-init)
   (ddl/create-table! "resources" (ddl/columns "id" "VARCHAR(100)" "data" "VARCHAR(10000)"))
+  (ddl/create-index! "resources" "INDEX_ID" "id")
   (defentity resources))

 ;;


Use new getter function

Use new getter function

--- src/nightmod/screens.clj
+++ src/nightmod/screens.clj
@@ -105,11 +105,11 @@
              e))
          (render! screen)))
   :on-resize
-  (fn [{:keys [camera] :as screen} entities]
+  (fn [screen entities]
     (height! screen screen-height)
     (for [e entities]
       (case (:id e)
-        :error (assoc e :width (. camera viewportWidth))
+        :error (assoc e :width (width screen))
         e))))

 (defgame nightmod


Skip company logo if it's missing. Right property for FoC images.

--- src/oc/email/content.clj
+++ src/oc/email/content.clj
@@ -96,7 +96,8 @@

 (defn- content-topic [snapshot topic-name topic topic-url]
   (let [body? (not (s/blank? (:body topic)))
-        image-url (:image topic)]
+        image-url (:image-url topic)
+        snippet? (not (s/blank? (:snippet topic)))]
     [:table {:class "row topic"}
       [:tbody
         (when image-url (topic-image image-url))
@@ -106,8 +107,8 @@
             [:p {:class "topic-title"} (s/upper-case (:title topic))]
             (spacer 1)
             [:p {:class "topic-headline"} (emojify (:headline topic))]
-            (spacer 2)
-            (emojify (:snippet topic))
+            (when snippet? (spacer 2))
+            (when snippet? (emojify (:snippet topic)))
             (when body? (spacer 20))
             (when body? [:a {:class "topic-read-more" :href topic-url} "READ MORE"])
             (spacer 30)]
@@ -191,22 +192,23 @@
       (content-topic snapshot topic-name topic topic-url))))

 (defn- content [snapshot]
-  [:td
-    (spacer 60 "header")
-    (logo snapshot)
-    (spacer 17 "header")
-    (company-name snapshot)
-    (spacer 17 "header")
-    (title snapshot)
-    (spacer 42 "header")
-    [:table
-      [:tbody
-        [:tr
-          (into [:td]
-            (interleave
-              (map #(topic snapshot % (snapshot (keyword %))) (:sections snapshot))
-              (repeat (spacer 25 "header"))))]]]
-    (spacer 60 "header")])
+  (let [logo? (not (s/blank? (:logo snapshot)))]
+    [:td
+      (spacer 60 "header")
+      (when logo? (logo snapshot))
+      (when logo? (spacer 17 "header"))
+      (company-name snapshot)
+      (spacer 17 "header")
+      (title snapshot)
+      (spacer 42 "header")
+      [:table
+        [:tbody
+          [:tr
+            (into [:td]
+              (interleave
+                (map #(topic snapshot % (snapshot (keyword %))) (:sections snapshot))
+                (repeat (spacer 25 "header"))))]]]
+      (spacer 60 "header")]))

 (defn- message [snapshot]
   [:table {:class "message"}


Fix invite email spacing.

Fix invite email spacing.

--- src/oc/email/content.clj
+++ src/oc/email/content.clj
@@ -357,9 +357,9 @@
                              :org-logo-height logo-height}))
       (when logo? (spacer 40))
       (h1 invite-message)
-      (spacer 40)
+      (spacer 30)
       (paragraph (format invite-instructions from org-name))
-      (spacer 20)
+      (spacer 40)
       (when show-note? (note-author from-avatar from true))
       (when show-note? (spacer 16))
       (when show-note? (paragraph note))


Documentation for atom

Documentation for atom

--- test/demo.cljs
+++ test/demo.cljs
@@ -83,6 +83,25 @@
   [:div
    "Here is a list:"
    [lister {:items (range 3)}]])
+
+(def click-count (atom 0))
+
+(defn counting-component []
+  [:div
+   "The atom " [:code "click-count"] " has value: " @click-count ". "
+   [:input {:type "button"
+            :value "Click me!"
+            :on-click #(swap! click-count inc)}]])
+
+(defn local-state []
+  (let [val (atom "foo")]
+    (fn []
+      [:div
+       [:p "The value of " [:code "val"] " is now: " @val]
+       [:p "Change it: "
+        [:input {:type "text"
+                 :value @val
+                 :on-change #(reset! val (-> % .-target .-value))}]]])))

 (defn calc-bmi [{:keys [height weight bmi] :as params}]
   (let [h (/ height 100)]
@@ -123,6 +142,7 @@

 (defn intro []
   [:div
+   [:h2 "Introduction to Cloact"]

    [:p "Cloact provides a minimalistic interface between ClojureScript
 and React. It allows you to define React components using nothing but
@@ -143,8 +163,35 @@
    [:code "seq"] "." ]

    [demo-component {:comp lister-user
-                    :defs [:lister :lister-user]}]
-   ])
+                    :defs [:lister :lister-user]}]])
+
+(defn managing-state []
+  [:div
+   [:h2 "Managing state in Cloact"]
+
+   [:p "The easiest way to manage state in Cloact is to use Cloact's
+   own version of " [:code "atom"] ". It works exactly like the one in
+   clojure.core, except that it keeps track of every time it is
+   deref'ed. Any component that uses the atom is automagically
+   re-rendered."]
+
+   [:p "Let's demonstrate that with a simple example:"]
+   [demo-component {:comp counting-component
+                    :defs [:ns :click-count :counting-component]}]
+
+   [:p "Sometimes you may want to maintain state locally in a
+   component. That is very easy to do with an " [:code "atom"] " as well."]
+
+   [:p "Here is an example of that:"]
+   [demo-component {:comp local-state
+                    :defs [:ns :local-state]}]
+
+   [:p "This example also uses another feature of Cloact: a component
+   function can return another function, that is used to do the actual
+   rendering. It is called with the same arguments as any other
+   component function. This allows you to perform some setup of newly
+   created components, without resorting to React's lifecycle
+   events."]])

 (defn bmi-demo []
@@ -158,5 +205,6 @@
   [:div
    [:h1 "This will become a demo"]
    [intro]
+   [managing-state]
    [bmi-demo]
    [:p "WIP"]])


Removed unecessary shuffle in poller

Removed unecessary shuffle in poller

--- src/polismath/poller.clj
+++ src/polismath/poller.clj
@@ -104,8 +104,7 @@
       (println "poll >" @last-timestamp)
       ; Get and split new votes
       (let [new-votes (poll pg-spec @last-timestamp)
-            zid-to-votes (group-by :zid new-votes)
-            zid-votes (shuffle (into [] zid-to-votes))]
+            zid-votes (group-by :zid new-votes)]
         ; For each conv...
         (doseq [[zid votes] zid-votes]
           (let [lastVoteTimestamp (:created (last votes))