Fix user auth state detection

Fix user auth state detection

--- src/cljs/daveconservatoire/site/ui.cljs
+++ src/cljs/daveconservatoire/site/ui.cljs
@@ -52,10 +52,15 @@
 (defn auth-state [state]
   (let [user (get state :app/me)]
     (cond
-      (some-> user first (= :user/by-id)) ::authenticated
+      (and (some-> user first (= :user/by-id))
+           (some-> user second (not= -1)))
+      ::authenticated
+
       (or (some-> user first (= :unknown))
           (and (map? user)
-               (contains? user :ui/fetch-state))) ::loading
+               (contains? user :ui/fetch-state)))
+      ::loading
+
       :else ::guest)))

 (defprotocol IRequireAuth


big ideas

big ideas

--- src/cljs/triboard/logic/transition.cljs
+++ src/cljs/triboard/logic/transition.cljs
@@ -36,6 +36,15 @@
 (defn- ^boolean? in-board?
   [x y]
   (and (< -1 x board/width) (< -1 y board/height)))
+
+;; TODO - Completely change the algorithm (solution 1):
+;; - We only need one pass... for each dimention
+;; - partition-by to get the zones of same color
+;; - partition size 3 step 1 to get the surroundings
+;; - filter on "one side exactly is :none" and you get the jumps
+
+;; TODO - Completely change the algorithm (solution 2):
+;; Search from the cells owned by a player... allows more incremental mode

 (defn- seek-jump-source-toward
   "Starting from the destination of a jump (an empty cell):


reapply changes from bad merge c09e0d8

reapply changes from bad merge c09e0d8

--- src/clojure/zensols/actioncli/parse.clj
+++ src/clojure/zensols/actioncli/parse.clj
@@ -33,6 +33,11 @@
   * **:single-action-mode?** whether the action context was created
   with [[multi-action-context]] or [[single-action-context]]"
   nil)
+
+(def ^:dynamic *include-program-in-errors*
+  "If non-nil add program name to error and warning messages
+  in [[handle-exception]] and [[error-message]] and [[print-error-message]]."
+  true)

 (defa- program-name-inst "prog")

@@ -217,18 +222,23 @@
 (defn handle-exception
   "Handle exceptions thrown from CLI actions."
   [e]
-  (log/debugf "handle exception: <%s>" e)
-  (let [msg (.getMessage e)]
+  (log/trace e "handle exception: %s" e)
+  (let [msg (.getMessage e)
+        prog-name (if *include-program-in-errors*
+                    (str (program-name) ": ")
+                    "")]
     (if *log-error* (log/error e "action line parse error"))
-    (if (instance? java.io.FileNotFoundException e)
-      (binding [*out* *err*]
-        (println (format "%sio error: %s" (program-fmt) msg)))
-      (binding [*out* *err*]
-        (println (format "%serror: %s"
-                         (program-fmt)
-                         (if ex-data
-                           (.getMessage e)
-                           (.toString e)))))))
+    (binding [*out* *err*]
+      (cond (instance? java.io.FileNotFoundException e)
+            (println (format "%sio error: %s" prog-name msg))
+            (instance? java.lang.NullPointerException e)
+            (println (format "%sio error: null pointer (%s)" prog-name msg))
+            true
+            (println (format "%serror: %s"
+                             prog-name
+                             (if ex-data
+                               (.getMessage e)
+                               (.toString e)))))))
   (log/debugf "dumping JVM: %s, rethrow: %s"
               *dump-jvm-on-error* *rethrow-error*)
   (if *dump-jvm-on-error*
@@ -251,7 +261,9 @@
   singleton then only print one in the common usage format."
   [errors]
   (if (= (count errors) 1)
-    (str (program-fmt) (first errors))
+    (str (if *include-program-in-errors*
+           (str (program-name) ": "))
+         (first errors))
     (str "The following errors occurred while parsing your action:\n\n"
          (s/join \newline errors))))


fix classpath-js cache issue

fix classpath-js cache issue

didn't restore properly on partial cache

--- src/main/shadow/build/closure.clj
+++ src/main/shadow/build/closure.clj
@@ -1646,7 +1646,8 @@
           []
           ;; compare each cache key
           (->> (for [{:keys [resource-id cache-key] :as src} sources
-                     :when (= cache-key (get cache-index resource-id))]
+                     :when (and (= cache-key (get cache-index resource-id))
+                                (get-in state [:output resource-id]))]
                  src)
                ;; need to preserve order for later
                (into [])))


fix shadow-cljs start hanging when server fails to start

fixes #875

--- src/main/shadow/cljs/npm/cli.cljs
+++ src/main/shadow/cljs/npm/cli.cljs
@@ -408,11 +408,20 @@
         (run! project-root "powershell" ps-args {})))))

 (defn wait-for-server-start! [port-file ^js proc]
-  (if (fs/existsSync port-file)
+  (cond
+    (fs/existsSync port-file)
     (do (js/process.stderr.write " ready!\n")
         ;; give the server some time to settle before we release it
         ;; hopefully fixes some circleci issues
         (js/setTimeout #(.unref proc) 500))
+
+    ;; nil while process is still running, any exit is an error
+    (.-exitCode proc)
+    (do (js/process.stderr.write " server failed to launch! Please check logs for errors.\n")
+        (js/process.stderr.write " stdout log: .shadow-cljs/server.stdout.log\n")
+        (js/process.stderr.write " stderr log: .shadow-cljs/server.stderr.log\n"))
+
+    :else
     (do (js/process.stderr.write ".")
         (js/setTimeout #(wait-for-server-start! port-file proc) 250))
     ))


making progress in inner trace 3 ??

making progress in inner trace 3 ??

--- src/com/billpiel/sayid/inner_trace3.clj
+++ src/com/billpiel/sayid/inner_trace3.clj
@@ -159,8 +159,8 @@
     tree-atom))

 (defn record-trace-tree!
-  [tree-atom]
-  (let [children (some-> (@tree-atom nil)
+  [tree-atom root-path]
+  (let [children (some-> (@tree-atom root-path)
                          deref-children
                          :children
                          deref)]
@@ -170,11 +170,11 @@
              child))))

 (defn get-temp-root-tree
-  []
+  [path]
   (-> trace/*trace-log-parent*
       (select-keys [:depth :path])
       (assoc :children (atom [])
-             :inner-path nil)
+             :inner-path path)
       atom))

 (defn push-to-tree-atom!
@@ -201,8 +201,8 @@

 (defn mk-recent-tree-at-inner-path
   [path path-parents tree-atom]
-  (if (empty? path) ;; TODO is this the right way to detect root?
-    (let [new-tree (get-temp-root-tree)]
+  (if (= (count path) 1) ;; TODO is this the right way to detect root?
+    (let [new-tree (get-temp-root-tree path)]
       (push-to-tree-atom!  new-tree
                            tree-atom)
       new-tree)
@@ -321,7 +321,7 @@
                                                                      src-map
                                                                      fn-meta
                                                                      (conj path %)
-                                                                     path-parent)
+                                                                     path #_path-parent)
                                                         form)))]
       (update-in xmap
                  [:form]
@@ -423,8 +423,8 @@
                    {:outer true})
                  idx
                  parent-fn-meta)
-           :args
-           args)))
+           :body-idx idx
+           :args args)))

 #_(defn xpand-fn*
   [form parent-fn-meta]
@@ -456,7 +456,7 @@
                 `(~(:args m)
                   (let [~'$$ (atom {})
                         ~'$$return (do ~@(apply list (:form m)))]
-                    (record-trace-tree! ~'$$)
+                    (record-trace-tree! ~'$$ [~(:body-idx m)])
                     ~'$$return)))
               traced-bods)})

@@ -559,4 +559,4 @@
                           :name 'com.billpiel.sayid.inner-trace3/f1}
                             :ns' 'com.billpiel.sayid.inner-trace3})]
        (f1 2)
-       #_       (clojure.pprint/pprint trace/*trace-log-parent*)))
+       (clojure.pprint/pprint trace/*trace-log-parent*)))


making progress in inner trace 3 ??

making progress in inner trace 3 ??

--- src/com/billpiel/sayid/inner_trace3.clj
+++ src/com/billpiel/sayid/inner_trace3.clj
@@ -136,39 +136,20 @@
                                    (clojure.walk/macroexpand-all form))
         olop->op (util/deep-zipmap (swap-in-path-syms form) form)
         f (fn [xl]
-            {(if (coll? xl)
-               (sym-seq->parent xl)
-               xl)
-             {:tree nil ;; placeholder for trace tree
-              :xl xl    ;; expanded location
-              :orig (-> xl
+            {(sym->path
+              (if (coll? xl)
+                (sym-seq->parent xl)
+                xl))
+             {:orig (-> xl
                         xl->xform
                         xform->form) ;; original symbol or value
               :x (-> xl
-                     xl->xform)
-              :xlxp (xl->xlxp xl) ;; expanded locations expanded parent
-              :ol (xloc->oloc xl)
-              :olop (-> xl
-                        xloc->oloc
-                        ol->olop)
-              :xp  (-> xl
-                       xl->xlxp
-                       xlxp->xp)
-              :op (-> xl
-                      xloc->oloc
-                      ol->olop
-                      olop->op)
-              :olxp (-> xl
-                        xloc->oloc
-                        ol->olxp)
-              :xlop (-> xl
-                        xloc->oloc
-                        ol->olop
-                        ((partial deep-replace-symbols oloc->xloc)))}})]
+                     xl->xform)}})]
     (util/$- ->> xls
              (map f)
              (apply merge))))

+
 (defn record-trace-tree!
   [tree-atom]
   :NOT-IMPLEMENTED)
@@ -178,27 +159,25 @@
   :NOT-IMPLEMENTED)

 (defn mk-tree-template
-  [src-map frm-meta fn-meta path-parent & {:keys [macro?]}]
-  (let [sub-src-map (util/$- -> path-parent
-                             last
-                             (remove #{:macro} $)
-                             path->sym
-                             src-map)
+  [src-map frm-meta fn-meta path & {:keys [macro?]}]
+  (let [sub-src-map (->> path
+                         rest
+                         (remove #{:macro})
+                         src-map)
         form (if macro?
                (:orig sub-src-map)
                (:x sub-src-map))]
-    {:inner-path-parent path-parent
+    {:inner-body-idx (first path)
+     :inner-path path
      :name (if (seq? form)
              (first form)
              form)
      :form form
      :macro? macro?
-     :inner-path (last path-parent)
      :parent-name (symbol (format "%s/%s"
                                   (-> fn-meta :ns str)
                                   (:name fn-meta)))
      :ns (-> fn-meta :ns str symbol)
-     :xpanded-parent (:xp sub-src-map)
      :xpanded-frm (:x sub-src-map)
      :src-pos (select-keys frm-meta [:line :column :end-line :end-column :file])}))

@@ -210,16 +189,39 @@

 (declare xpand-form)

+(defn merge-xpansion-maps
+  [ms]
+  {:templates (->> ms
+                   (map :templates)
+                   (apply merge))
+   :path-parents (->> ms
+                      (map :path-parents)
+                      (apply merge))
+   :form (map :form ms)})
+
+(defn layer-xpansion-maps
+  [bottom top]
+  (assoc top
+         :templates (->> [bottom top]
+                         (map :templates)
+                         (apply merge))
+         :path-parents (->> [bottom top]
+                            (map :path-parents)
+                            (apply merge))))
+
 (defn xpand-all
   [form src-map fn-meta path path-parent]
   (when-not (nil? form)
-    (util/back-into form
-                    (doall (map-indexed #(xpand-form %2
-                                                     src-map
-                                                     fn-meta
-                                                     (conj path %)
-                                                     path-parent)
-                                        form)))))
+    (let [xmap (merge-xpansion-maps (doall (map-indexed #(xpand-form %2
+                                                                     src-map
+                                                                     fn-meta
+                                                                     (conj path %)
+                                                                     path-parent)
+                                                        form)))]
+      (update-in xmap
+                 [:form]
+                 (partial util/back-into
+                          form)))))

 (defn get-form-meta-somehow
   [form]
@@ -243,17 +245,20 @@

 (defn xpand-fn
   [head form src-map fn-meta path path-parent]
-  (let [path-parent' (conj path-parent path)]
-    {:template {path (mk-tree-template src-map
-                                       (get-form-meta-somehow form)
-                                       fn-meta
-                                       path-parent')}
-     :form (xpand-fn-form head
-                          (xpand-all form
-                                     src-map
-                                     fn-meta
-                                     path
-                                     path-parent'))}))
+  (let [xmap (xpand-all form
+                        src-map
+                        fn-meta
+                        path
+                        path-parent)]
+    (layer-xpansion-maps xmap
+                         {:path-parents {path path-parent}
+                          :templates {path (mk-tree-template src-map
+                                                             (get-form-meta-somehow form)
+                                                             fn-meta
+                                                             path)}
+                          :form (xpand-fn-form head
+                                               (:form xmap)
+                                               (path->sym path))})))

 #_(defn xpand-form
   [form src-map fn-meta & [path path-parent]]
@@ -281,7 +286,7 @@
           :else (apply xpand-fn head args)))

       (coll? form) (apply xpand-all args)
-      :else form)))
+      :else {:form form})))

 #_ (defn xpand
   [form parent-fn-meta]
@@ -309,11 +314,12 @@
 (defn xpand-body
   [parent-fn-meta idx fn-body]
   (let [[args & tail] fn-body]
-    (cons args  ;; wrong
-          (xpand (with-meta (vec tail)
+    (assoc (xpand (with-meta (vec tail)
                    {:outer true})
                  idx
-                 parent-fn-meta))))
+                 parent-fn-meta)
+           :args
+           args)))

 #_(defn xpand-fn*
   [form parent-fn-meta]
@@ -323,13 +329,29 @@
     (cons (first form)
           bods)))

+(defn quote* [x] `'~x)
+
 (defn prep-traced-bods
-  [r]
-  {:templates ['$0-0 {}]
-   :path {'$0-1 ['$$$ '$$$]}
-   :bods '(([] 123))
-   :r r}
-  :NOT-IMPLEMENTED)
+  [traced-bods]
+  {:templates (->> traced-bods
+                   (map :templates)
+                   (apply merge)
+                   (mapcat (fn [[k v]]
+                             [(path->sym k) (-> v
+                                                (update-in [:ns] quote*)
+                                                (update-in [:name] quote*)
+                                                (update-in [:parent-name] quote*)
+                                                (update-in [:form] quote*)
+                                                (update-in [:xpanded-frm] quote*)
+                                                (assoc :path-parents '$$paths))])))
+   :path-parents (->> traced-bods
+                      (map :path-parents)
+                      (apply merge))
+   :form (map (fn [m]
+                `(~(:args m)
+                  (let [~'$$ (atom [])]
+                    ~@(apply list (:form m)))))
+              traced-bods)})

 (defn xpand-fn*
   [form parent-fn-meta]
@@ -338,9 +360,9 @@
                   (map-indexed (partial xpand-body
                                         parent-fn-meta))
                   prep-traced-bods)]
-    `(let [~'$$p ~(:paths bods)
+    `(let [~'$$paths ~(:paths bods)
            ~@(:templates bods)]
-       (fn ~@(:bods bods)))))
+       (fn ~@(:form bods)))))

 (defn get-fn
   [[d s f & r]]
@@ -389,7 +411,7 @@
         (record-trace-tree! $$)
         $return)))

-#_ (inner-tracer {:qual-sym 'com.billpiel.sayid.inner-trace2/f1
-                  :meta' {:ns 'com.billpiel.sayid.inner-trace2
-                          :name 'com.billpiel.sayid.inner-trace2/f1}
-                 :ns' 'com.billpiel.sayid.inner-trace2})
+#_ (inner-tracer {:qual-sym 'com.billpiel.sayid.inner-trace3/f1
+                  :meta' {:ns 'com.billpiel.sayid.inner-trace3
+                          :name 'com.billpiel.sayid.inner-trace3/f1}
+                 :ns' 'com.billpiel.sayid.inner-trace3})


Filter episodes w/o Netflix, Hulu or Amazon options

--- streamable.clj
+++ streamable.clj
@@ -87,7 +87,7 @@
                      (kcore/where {:ignore 0}))]
   (->> episode-data
        (map throttled-options)
-       (remove (comp empty? :streaming_options))
+       (filter (comp #(some #{"AMZN" "HULU" "NFLX"} %) :streaming_options))
        (sort-by :episode_id)
        format-results
        print))


Bump version to 0.8.0  * Trimmed extraneous code  * Use resilient decoder as default entry point

--- src/ais/resilient_decoder.clj
+++ src/ais/resilient_decoder.clj
@@ -10,30 +10,41 @@
   (:require [clojure.stacktrace :as strace])
   (:gen-class))

-;;;; Resilient message decoding
-
-;; Single fragment decoding -- trivial case
-;;  * forward to processing pipeline
-
-;; Multi fragment decoding -- nontrivial
-;;
-;; Multiple cases -- each depending on sequencing order
-;;
-;; 1. A - B
-;;  * messages stream back-to-back in correct ordinal positions
-;;
-;; 2. B - A
-;;  * messages stream back-to-back in reversed ordinal positions
-;;
-;; 3. A - X+ - B
-;;  * messages stream in correct ordinal positions separated by + messages
-;;
-;; 4. B - X+ - A
-;;  * messages stream in reversed ordinal positions separated by + messages
-;;
-;;
-
-(def buffer-size 1000)
+;;;                      ____                     _
+;;;                     |  _ \  ___  ___ ___   __| | ___ _ __
+;;;                     | | | |/ _ \/ __/ _ \ / _` |/ _ \ '__|
+;;;                     | |_| |  __/ (_| (_) | (_| |  __/ |
+;;;                     |____/ \___|\___\___/ \__,_|\___|_|
+;;;
+;;; The following application is a robust implemenation of ais-lib's core decoding functionality.  In practice, multipart
+;;; messages tend to stream in correct monotonically increasing order however we must account for all streaming configurations
+;;; and not naively consume input streams.
+;;;
+;;; Consider two sets or multipart messages, [a, a'] and [b, b']. x+ denotes 1 more messages.
+;;;
+;;; We must consider the following senarios when parsing multipart fragments from input streams:
+;;;
+;;; 1. a  a'
+;;; 2. a' a
+;;; 3. a  x+ a'
+;;; 4. a' x+ a
+;;; 5. a  b' b a'
+;;;
+;;;
+;;; Entry point parameters:
+;;;  * output-prefix: string
+;;;    - Output filename prefix
+;;;  * supported-types: [1-28]
+;;;    - Messages types to decode.  All other messages are dropped
+;;;  * n-threads: [1..)
+;;;    - Number of processing threads.  Also sets the number of output files (where output files have the suffix
+;;;      part-n).
+;;;  * format: [csv | json]
+;;;    - Output file data format
+;;;
+
+
+(def buffer-size 1000)

 (def ais-msg-types (into {} (for [k (range 1 28)] [k false])))

@@ -81,10 +92,8 @@
 ;; Core
 ;;---

-
 (defn details [line]
   (hash-map
-    "line"       line
     "frag-count" (ais-ex/parse "frag-count" line)
     "frag-num"   (ais-ex/parse "frag-num" line)
     "type"       (extract-type (ais-ex/parse "payload" line))))
@@ -92,53 +101,36 @@
 (defn group-key [line]
   (if-let  [prefix (ais-ex/parse "g" line)]
     (let [key (format "%s-%s" prefix (ais-ex/parse "radio-ch" line))]
-      (println (format "group key: %s" key))
       key)))

-(defn find-match [key fragments]
-  (if-let [frag (@fragments key)]
-    frag))
-
-(defn find-fragment-match [out-ch group-key line unpaired-frags]
-  (if-let [ret (find-match group-key unpaired-frags)]
-    (async/>!! out-ch (sort-by (partial ais-ex/parse "frag-num") [line ret]))
-    (swap! unpaired-frags assoc group-key line)))
-
-(defn consume-multipart [base candidate out-ch unpaired-frags]
-  (if (nil? candidate)
-    ;; Find match for base in unpaired set
-    (find-fragment-match out-ch (group-key (base "line")) (base "line") unpaired-frags)
-    (let [frag-num   (ais-ex/parse "frag-num" candidate)
-          frag-count (ais-ex/parse "frag-count" candidate)
-          candidate-group-key  (group-key candidate)
-          base-group-key (group-key (base "line"))]
-      (if (nil? candidate-group-key)
-        ;; Candidate message is not a multipart fragment.  Send candidate
-        ;; to out channel and find possible match for base in unpaired set.
-        ;; If match cannot be found, add base to unpaired fragments.
-
+(defn find-fragment-match! [out-ch group-key msg unpaired-frags]
+  (if-let [frag-match (@unpaired-frags group-key)]
+    (async/>!! out-ch (sort-by (partial ais-ex/parse "frag-num") [msg frag-match]))
+    (swap! unpaired-frags assoc group-key msg)))
+
+(defn consume-multipart [a-msg b-msg unpaired-frags out-ch]
+  (if (nil? b-msg)
+    ;; Clearly msg b is not a match, let's look up a possible match in unpaired fragments
+    (find-fragment-match! out-ch (group-key a-msg) a-msg unpaired-frags)
+    (let [a-key (group-key a-msg)
+          b-key (group-key b-msg)]
+      (if (nil? b-key)
+
+        ;; Msg b is not a multipart fragment.  Send to out channel for processing
+        ;; and find possible match for msg a in unpaired fragments.  If a match is
+        ;; not found, add to unpaired fragments
         (do
-          (println (format "candidate-group-key nil: %s %s" base-group-key candidate-group-key))
-          (async/>!! out-ch [candidate])
-          (find-fragment-match out-ch base-group-key (base "line") unpaired-frags)
-          (pprint/pprint @unpaired-frags))
-
-        ;; Candidate message is a multipart fragment.  Determine if candidate
-        ;; and base fragment are a pair.  If yes, send to out channel, otherwise
-        ;; find match for base in unpaired and add candidate to unpaired set. If
-        ;; match found, send pair to out channel otherwise add base to unpaired.
-
-        (if (= base-group-key candidate-group-key)
+          (async/>!! out-ch [b-msg])
+          (find-fragment-match! out-ch a-key a-msg unpaired-frags))
+
+        ;; Msg b is a multipart fragment; if grouping key matches msg a, send pair
+        ;; to out channel otherwise find possible matches for both msgs in unparied
+        ;; fragments.  Add msgs to unpaired fragments if matches not found.
+        (if (= a-key b-key)
+          (async/>!! out-ch (sort-by (partial ais-ex/parse "frag-num") [a-msg b-msg]))
           (do
-            (println (format "group key match: %s %s" base-group-key candidate-group-key))
-            (async/>!! out-ch (sort-by (partial ais-ex/parse "frag-num") [(base "line") candidate])))
-          (do
-            (println (format "group key doesn't match: %s %s" base-group-key candidate-group-key))
-            ;;(swap! unpaired-frags assoc candidate-group-key candidate)
-            (find-fragment-match out-ch candidate-group-key candidate unpaired-frags)
-            (find-fragment-match out-ch base-group-key (base "line") unpaired-frags)
-            (pprint/pprint @unpaired-frags)))
-      ))))
+            (find-fragment-match! out-ch b-key b-msg unpaired-frags)
+            (find-fragment-match! out-ch a-key a-msg unpaired-frags)))))))

 (defn passthru? [supported-types d]
   (or
@@ -160,21 +152,13 @@
         (if-let [line (async/<!! in-ch)]
           (do
             (when (valid-syntax? line)
-              (println (format "filter-stream: %s" line))
               (let [d (details line)]
-                ;; Fragment 2 of multipart messages should be automatically passed thru.
                 (if (passthru? supported-types d)
 	          (condp = (d "frag-count")
-	            1 (do
-                        (println "Consume 1")
-			(println line)
-                        (async/>!! out-ch [line]))
-	            2 (do
-                        (println (format "Consume 2: %s" (group-key line)))
-			(println line)
-                        (consume-multipart d (async/<!! in-ch) out-ch unpaired-frags))
-	     	    (.println *err* (str "Unexpected fragment count: " (d "frag-count") ". " line)))
-	          (.println *err* (str "Dropping [type=" (d "type") "] " line)))))
+	            1 (async/>!! out-ch [line])
+	            2 (consume-multipart line (async/<!! in-ch) unpaired-frags out-ch)
+	     	    (.println *err* (str "Unexpected fragment count: " (d "frag-count") ". " line)))
+	          (.println *err* (str "Dropping [type=" (d "type") "] " line)))))
             (recur))
           (async/close! out-ch))))
     out-ch))


RJ9 holder

RJ9 holder

--- src/dactyl_keyboard/dactyl-manuform.clj
+++ src/dactyl_keyboard/dactyl-manuform.clj
@@ -444,30 +444,33 @@
          (translate [0 (/ mount-height 2) -15])
                         ; (Math/sin (/ α 2)))
          )))
-; (def test-shape (on-wall-place 1 20 (translate [2.5 15 5] (cube 5 30 10))))
 (def test-shape (on-wall-place 1 20 (cube 5 30 10)))

+(def rj9-holder1
+  (on-wall-place 1 20
+    (difference (cube 14.78 13 22.38)
+                (translate [0 0 -5] (cube 10.78 13  5)))))
+
+
+(def rj9-cube   (cube 14.78 13 22.38))
+(def rj9-space  (on-wall-place 1 20 rj9-cube))
+(def rj9-holder (on-wall-place 1 20
+                  (difference rj9-cube
+                              (union (translate [0 2 0] (cube 10.78  9 18.38))
+                                     (translate [0 0 5] (cube 10.78 13  5))))))
+
+(def rj9-holder (on-wall-place 1 20
+                  (difference rj9-cube
+                              (union (translate [0 2 0] (cube 10.78  9 18.38))
+                                     (translate [0 0 5] (cube 10.78 13  5))))))
 (def teensy-width 20)
 (def teensy-height 12)
 (def teensy-length 33)
+(def teensy2-length 53)
 (def teensy-pcb-thickness 1.6)
 (def teensy-offset-height 5)

-(def usb-cutout
-  (let [hole-height 6.2
-        side-radius (/ hole-height 2)
-        hole-width 10.75
-        side-cylinder (->> (cylinder side-radius teensy-length)
-                           (with-fn 20)
-                           (translate [(/ (- hole-width hole-height) 2) 0 0]))]
-    (->> (color [20/255 163/255 163/255 1])
-         (hull side-cylinder
-               (mirror [-1 0 0] side-cylinder))
-         (translate [0 (/ teensy-length 2) (- side-radius)])
-         (translate [0 0 (- 1)])
-         (translate [0 0 (- teensy-offset-height)])
-         (on-wall-place 1 20))))
-
+(def teensy2 (on-wall-place 0 20 (cube teensy-height teensy2-length teensy-width)))

 (spit "repl.scad"
@@ -476,9 +479,9 @@
                    connectors
                    thumb
                    thumb-connectors
-                   case-walls
-                   test-shape
-                  ;  usb-cutout
+                   (difference case-walls rj9-space)
+                   rj9-holder
+                   teensy2
                   ;  thumbcaps
                   ;  caps
                    )))


[Fix #180] Give the bencode encoder a helping hand

--- src/refactor_nrepl/middleware.clj
+++ src/refactor_nrepl/middleware.clj
@@ -20,7 +20,8 @@
             [refactor-nrepl.ns.pprint :refer [pprint-ns]]
             [refactor-nrepl.ns.resolve-missing :refer [resolve-missing]]
             [refactor-nrepl.rename-file-or-dir :refer [rename-file-or-dir]]
-            [refactor-nrepl.stubs-for-interface :refer [stubs-for-interface]]))
+            [refactor-nrepl.stubs-for-interface :refer [stubs-for-interface]]
+            [clojure.walk :as walk]))

 (defmacro ^:private with-errors-being-passed-on [transport msg & body]
   `(try
@@ -44,10 +45,24 @@
        (transport/send ~transport
                        (response-for ~msg ~(apply hash-map :status :done kvs))))))

+(defn- bencode-friendly-data [data]
+  ;; Bencode only supports byte strings, integers, lists and maps.
+  ;; To prevent the bencode serializer in nrepl blowing up we manually
+  ;; convert certain data types.
+  ;; See refactor-nrepl#180 for more details.
+  (walk/postwalk (fn [v]
+                   (cond
+                     (or (keyword? v) (symbol? v))
+                     (str v)
+
+                     (set? v) (list v)
+
+                     :else v))))
+
 (defn- serialize-response [{:keys [serialization-format] :as msg} response]
   (condp = serialization-format
     "edn" (pr-str response)
-    "bencode" response
+    "bencode" (bencode-friendly-data response)
     (pr-str response) ; edn as default
     ))

@@ -108,7 +123,8 @@
          :status :done))

 (defn- find-used-publics-reply [{:keys [transport] :as msg}]
-  (reply transport msg :used-publics (serialize-response msg (find-used-publics msg)) :status :done))
+  (reply transport msg
+         :used-publics (serialize-response msg (find-used-publics msg)) :status :done))

 (def refactor-nrepl-ops
   {


Use one function for serving random image, with bucket or not

--- src/silly_image_store/handler.clj
+++ src/silly_image_store/handler.clj
@@ -36,11 +36,7 @@
   (let [image-file (store/load-image images-dir bucket image)]
     (or image-file (not-found image))))

-(defn- serve-random-image-route [request]
-  (let [image-file (store/random-image images-dir)]
-    (or image-file (not-found "random"))))
-
-(defn- serve-random-image-from-bucket-route [{{bucket :bucket} :params}]
+(defn- serve-random-image-route [bucket]
   (let [image-file (store/random-image images-dir bucket)]
     (or image-file (not-found "random"))))

@@ -53,11 +49,11 @@
 (defroutes app-routes
   (GET "/images" request (list-images-route request ""))
   (GET "/images/:image" [image] (serve-image-route "" image))
-  (GET "/random" request serve-random-image-route)
+  (GET "/random" [] (serve-random-image-route ""))
   (GET "/buckets" request list-buckets-route)
   (GET "/buckets/:bucket/images" [bucket :as request] (list-images-route request bucket))
   (GET "/buckets/:bucket/images/:image" [bucket image] (serve-image-route bucket image))
-  (GET "/buckets/:bucket/random" request serve-random-image-from-bucket-route)
+  (GET "/buckets/:bucket/random" [bucket] (serve-random-image-route bucket))
   (route/resources "/")
   (route/not-found "Not Found"))


don't need nasty old bitcoind

don't need nasty old bitcoind

--- src/bitsplit_cli/bitcoind.clj
+++ src/bitsplit_cli/bitcoind.clj
@@ -1,46 +0,0 @@
-(ns bitsplit-cli.bitcoind
-    (:use bitsplit.client.protocol
-          [bitsplit.utils.thread :only (thread-interval)]
-          [bitsplit.utils.calculate :only (address-amounts)]
-          [clojure.core.async :only (chan put!)])
-    (:require [clj-btc.core :as btc]))
-
-(def INTERVAL 0.1)
-
-(def list-unspent
-    #(btc/listunspent
-        :minconf 1
-        :maxconf 9999999))
-
-(def list-addresses
-    (partial
-        btc/getaddressesbyaccount
-        :account))
-
-(defrecord Bitcoind [account]
-    Queries
-    (addresses [this]
-        (list-addresses account))
-    (unspent-amounts [this]
-        (let [unspent-tx (list-unspent)
-              addresses (-> account list-addresses set)
-              account-address? #(contains? addresses (% "address"))]
-            (->> unspent-tx
-                (filter account-address?)
-                address-amounts)))
-    (unspent-channel [this]
-        (let [return (chan)]
-            (thread-interval INTERVAL
-                (println "checking for unspent coins")
-                (let [unspent (unspent-amounts this)]
-                    (when (-> unspent empty? not)
-                        (println "found some coins" unspent)
-                        (put! return unspent))))
-            return))
-    Operations
-    (send-amounts! [this amounts]
-        (btc/sendmany
-            :fromaccount account
-            :address-amount-maps amounts))
-    (new-address! [this]
-        (btc/getnewaddress :account account)))


Make `(sift :move)` create resources (#680)

--- boot/core/src/boot/task_helpers.clj
+++ boot/core/src/boot/task_helpers.clj
@@ -117,12 +117,14 @@
 (defmethod sift-action :move
   [_ _ args]
   (let [proc    #(reduce-kv string/replace % args)
-        reducer (fn [xs k v]
-                  (let [k (proc k)]
-                    (assoc xs k (assoc v :path k))))]
+        mkreducer (fn [dir]
+                    (fn [xs k v]
+                      (let [k (proc k)]
+                        (assoc xs k (assoc v :path k :dir dir)))))]
     (fn [fileset]
-      (->> (partial reduce-kv reducer {})
-           (update-in fileset [:tree])))))
+      (let [dir (#'core/get-add-dir fileset #{:resource})]
+        (->> (partial reduce-kv (mkreducer dir) {})
+             (update-in fileset [:tree]))))))

 (defmethod sift-action :add-jar
   [v? _ args]


make clear inbox button clickable

make clear inbox button clickable

--- src/braid/ui/styles/misc.cljs
+++ src/braid/ui/styles/misc.cljs
@@ -100,7 +100,10 @@

    ["> .intro"
     {:color vars/grey-text
-     :margin vars/pad}]
+     :margin vars/pad
+     ; make intro above threads, so you can click on clear inbox button
+     :z-index 100
+     :position "relative"}]

    ["> .content"
     {:overflow "scroll"


Links need an external attribute

Links need an external attribute

--- src/catalog/layout/dtbook.clj
+++ src/catalog/layout/dtbook.clj
@@ -23,7 +23,7 @@
 (defmulti to-dtbook (fn [{:keys [tag attrs content]}] tag))
 (defmethod to-dtbook :p [{content :content}] [:p content])
 (defmethod to-dtbook :a [{content :content {href :href} :attrs}]
-  [:a {:href href} (if (not-empty content) content href)])
+  [:a {:href href :external "true"} (if (not-empty content) content href)])
 ;; make sure the md headings are lower than h1. That way they will
 ;; fit properly into the hierarchy, where :editorial is h1 and the
 ;; actual md content is below


spacing

spacing

--- src/celestial/api/systems.clj
+++ src/celestial/api/systems.clj
@@ -131,6 +131,7 @@

   (GET- "/systems/:id/type" [^:int id] {:nickname "getSystemType" :summary "Fetch type of provided system id"}
         (success (t/get-type (:type (s/get-system id))))))
+
 (defroutes- systems-admin {:path "/systems" :description "Operations on Systems"}

   (POST- "/systems/reindex" []
@@ -138,6 +139,7 @@
       (wrap-errors (success (s/re-index (working-username)))))

   )
+
 (defroutes- environments {:path "/environments" :description "Operations on environments"}
   (GET- "/environments" [] {:nickname "getEnvironments" :summary "Get sanitized environments for current user"}
      (let [{:keys [envs] :as user} (u/get-user (working-username))]


remove debug code

remove debug code

--- src/ceres_collector/mongo.clj
+++ src/ceres_collector/mongo.clj
@@ -82,7 +82,6 @@

 (defn store [db db-entry]
-  (debug (:value db-entry))
   (mc/insert-and-return db (type->coll (:type db-entry)) (:value db-entry)))


Report in info log-level when starting/stopping daemon

--- src/cider_ci/utils/daemon.clj
+++ src/cider_ci/utils/daemon.clj
@@ -22,7 +22,7 @@
        (defn ~start-fn []
          (~stop-fn)
          (let [done# (atom false)
-               runner# (future (logging/debug "daemon " ~daemon-name " started")
+               runner# (future (logging/info "daemon " ~daemon-name " started")
                                ;(Thread/sleep (* ~secs-pause 1000))
                                (loop []
                                  (when-not @done#
@@ -34,7 +34,7 @@
                            (reset! done# true)
                            (future-cancel runner#)
                            ;@runner#
-                           (logging/debug "daemon " ~daemon-name "stopped")
+                           (logging/info "daemon " ~daemon-name "stopped")
                            ))))
        )))


Updated default weight for gap cards.

Updated default weight for gap cards.

--- src/clj/funstructor/cards.clj
+++ src/clj/funstructor/cards.clj
@@ -20,7 +20,7 @@
     :action-equality-1
     :action-equality-2
     :action-equality-3
-
+
     })

 (def cards
@@ -100,7 +100,7 @@
     "add gap to the leftmost position of your funstruct"
     :target :self
     :type :mutator
-    :weight 100
+    :weight 75
     :img "mutator_left_gap.svg"}

    :mutator-right-gap
@@ -109,7 +109,7 @@
     "add gap to the rightmost position of your funstruct"
     :target :self
     :type :mutator
-    :weight 100
+    :weight 75
     :img "mutator_right_gap.svg"}

    :mutator-position-gap
@@ -118,7 +118,7 @@
     "add gap to the specific position of your funstruct"
     :target :self
     :type :mutator
-    :weight 100
+    :weight 150
     :img "mutator_pos_gap.svg"}

    :mutator-shot
@@ -143,7 +143,7 @@
     :type :action
     :weight 40
     :img "action_thief_1.svg"}
-
+
    :action-discard-1
    {:name "Discard v1.0"
     :description
@@ -205,7 +205,7 @@
     :turns-left 3
     :img "duration_luck_2.svg"}

-
+
    })

 (defn- in? [n a b]


only count rezzed Museums of History

only count rezzed Museums of History

--- src/clj/game/cards-assets.clj
+++ src/clj/game/cards-assets.clj
@@ -428,7 +428,7 @@
    "Museum of History"
    {:flags {:corp-phase-12 (req (pos? (count (get-in @state [:corp :discard]))))}
     :abilities [{:label "Shuffle cards in Archives into R&D"
-                 :prompt (msg (let [mus (count (filter #(= "10019" (:code %)) (all-installed state :corp)))]
+                 :prompt (msg (let [mus (count (filter #(and (= "10019" (:code %)) (rezzed? %)) (all-installed state :corp)))]
                                 (str "Choose " (if (< 1 mus) (str mus " cards") "a card")
                                      " in Archives to shuffle into R&D")))
                  :choices {:req #(and (card-is? % :side :corp) (= (:zone %) [:discard]))


added async-connect option

added async-connect option

--- src/clj/http/async/client.clj
+++ src/clj/http/async/client.clj
@@ -20,7 +20,8 @@
   (:use [http.async.client request headers util]
         clojure.template)
   (:import (java.io ByteArrayOutputStream)
-           (com.ning.http.client AsyncHttpClient AsyncHttpClientConfig$Builder)))
+           (com.ning.http.client AsyncHttpClient AsyncHttpClientConfig$Builder)
+           (com.ning.http.client.providers.netty NettyAsyncHttpProviderConfig)))

 (defn create-client
   "Creates new Async Http Client.
@@ -47,7 +48,8 @@
              proxy
              realm
              request-timeout
-             user-agent]}]
+             user-agent
+             async-connect]}]
   (AsyncHttpClient.
    (.build
     (let [b (AsyncHttpClientConfig$Builder.)]
@@ -55,10 +57,17 @@
       (when connection-timeout (.setConnectionTimeoutInMs b connection-timeout))
       (when (not (nil? follow-redirects)) (.setFollowRedirects b follow-redirects))
       (when idle-in-pool-timeout (.setConnectionTimeoutInMs b idle-in-pool-timeout))
-      (when (not (nil? keep-alive)) (.setKeepAlive b keep-alive))
+      (when (not (nil? keep-alive)) (.setAllowPoolingConnection b keep-alive))
       (when max-conns-per-host (.setMaximumConnectionsPerHost b max-conns-per-host))
       (when max-conns-total (.setMaximumConnectionsTotal b max-conns-total))
       (when max-redirects (.setMaximumNumberOfRedirects b max-redirects))
+      (when (or connection-timeout      ;; connection timeout is not enforced by the underlying library
+                ;; unless it's in the async connect mode, which is not the default
+                (not (nil? async-connect)))
+        (let [provider-config (doto (NettyAsyncHttpProviderConfig.)
+                                (.removeProperty NettyAsyncHttpProviderConfig/USE_BLOCKING_IO)
+                                (.addProperty NettyAsyncHttpProviderConfig/EXECUTE_ASYNC_CONNECT true))]
+          (.setAsyncHttpClientProviderConfig b provider-config)))
       (set-proxy proxy b)
       (when realm
         (set-realm realm b))


fix cache related race condition

fix cache related race condition

--- src/clj/shadow/cljs/build.clj
+++ src/clj/shadow/cljs/build.clj
@@ -460,31 +460,39 @@
           (dissoc manifest "deps.cljs")
           foreign-libs)))))

+(defonce JAR-LOCK (Object.))

 (defn find-jar-resources
   [{:keys [manifest-cache-dir cache-level] :as state} path]
   {:pre [(compiler-state? state)]}
   ;; FIXME: assuming a jar with the same name and same last modified is always identical, probably not. should md5 the full path?
-  (let [manifest-name
-        (let [jar (io/file path)]
-          (str (.lastModified jar) "-" (.getName jar) ".manifest"))
-
-        mfile
-        (io/file manifest-cache-dir manifest-name)
-
-        jar-file
-        (io/file path)
-
-        manifest
-        (if (and (.exists mfile)
-                 (>= (.lastModified mfile) (.lastModified jar-file)))
-          (read-jar-manifest mfile)
-          (let [manifest (create-jar-manifest state path)]
-            (io/make-parents mfile)
-            (write-jar-manifest mfile manifest)
-            manifest))]
-    (-> (process-deps-cljs state manifest path)
-        (vals))))
+
+  ;; locking to avoice race-condition in cache where two threads might be read/writing jar manifests at the same time
+  ;; A is writing
+  ;; B sees that file exists and starts reading although A is not finished yet
+  ;; boom strange EOF errors
+  ;; could instead write to temp file and move and but that basically just causes manifests to be generated twice
+  (locking JAR-LOCK
+    (let [manifest-name
+          (let [jar (io/file path)]
+            (str (.lastModified jar) "-" (.getName jar) ".manifest"))
+
+          mfile
+          (io/file manifest-cache-dir manifest-name)
+
+          jar-file
+          (io/file path)
+
+          manifest
+          (if (and (.exists mfile)
+                   (>= (.lastModified mfile) (.lastModified jar-file)))
+            (read-jar-manifest mfile)
+            (let [manifest (create-jar-manifest state path)]
+              (io/make-parents mfile)
+              (write-jar-manifest mfile manifest)
+              manifest))]
+      (-> (process-deps-cljs state manifest path)
+          (vals)))))

 (defn make-fs-resource [state source-path rc-name ^File rc-file]
   (inspect-resource


Handle properly nil inputs on check function.

--- src/clojure/buddy/hashers.clj
+++ src/clojure/buddy/hashers.clj
@@ -250,6 +250,7 @@
   "Check if a unencrypted password matches
   with another encrypted password."
   [attempt encrypted]
-  (let [pwdparams (parse-password encrypted)
-        attempt (str->bytes attempt)]
-    (check-password pwdparams attempt)))
+  (when (and attempt encrypted)
+    (let [pwdparams (parse-password encrypted)
+          attempt (str->bytes attempt)]
+      (check-password pwdparams attempt))))


Tweak with-gensyms

Tweak with-gensyms

--- src/main/cljc/mikron/compiler/util.cljc
+++ src/main/cljc/mikron/compiler/util.cljc
@@ -25,7 +25,7 @@
     [& args]
     (let [{:keys [syms body]} (enforce-spec ::util-specs/with-gensyms-args args)]
       `(let [~@(mapcat (fn [sym]
-                         (let [gensym-expr `(gensym ~(str sym))]
+                         (let [gensym-expr `(gensym ~(str sym "-"))]
                            [sym (if-some [sym-meta (meta sym)]
                                   `(vary-meta ~gensym-expr merge ~(meta sym))
                                   gensym-expr)]))


CMR-1983: Reset db to in-memory

CMR-1983: Reset db to in-memory

--- dev-system/dev/user.clj
+++ dev-system/dev/user.clj
@@ -37,8 +37,8 @@
   (system/set-dev-system-echo-type! :in-memory)
   ; (system/set-dev-system-echo-type! :external)

-  ; (system/set-dev-system-db-type! :in-memory)
-  (system/set-dev-system-db-type! :external)
+  (system/set-dev-system-db-type! :in-memory)
+  ; (system/set-dev-system-db-type! :external)

   (system/set-dev-system-message-queue-type! :in-memory)
   ; (system/set-dev-system-message-queue-type! :external)


stop importing for now as that seems to be deselecting all projects on CI


Started work on value stream visualisation

--- kuona-api/src/kuona_api/handler.clj
+++ kuona-api/src/kuona_api/handler.clj
@@ -6,6 +6,7 @@
             [compojure.route :as route]
             [kuona-api.environments :refer :all]
             [kuona-core.metric.store :as store]
+            [kuona-core.util :as util]
             [ring.adapter.jetty :as jetty]
             [ring.middleware.defaults :refer [wrap-defaults api-defaults]]
             [ring.middleware.json :as middleware]
@@ -148,6 +149,28 @@
 (defn put-environment!
   [environment]
   (response (decorate-environment (store/put-document environments environment))))
+
+
+(defn get-value-stream
+  "Returns a single valuestream object identified by the supplied id"
+  [id]
+  (response
+   {
+    :id          (util/uuid)
+    :artifact    {:id "some-unique-identifier" :version "1.0.1"}
+    :lead_time   91237842
+    :commits     []
+    :build       {:timestamp (util/timestamp)
+                  :duration  234234
+                  :builder   "Jenkins"
+                  :build_url "http://jenkins.com/stage/job"
+                  }
+    :deployments [{:timestamp   (util/timestamp)
+                   :environment {:name "PROD"}
+                   :duration    234523}]
+    })
+  )
+

 (defroutes app-routes
   (GET "/" [] (service-data))
@@ -175,6 +198,8 @@
   (POST "/api/environments/:id/status" request (put-environment-status! (get-in request [:params :id]) (get-in request [:body :status])))
   (POST "/api/environments" request (put-environment! (get-in request [:body :environment])))

+  (GET "/api/valuestreams/:id" [id] (get-value-stream id))
+
   (route/not-found "Not Found"))

 (def app


proper card desactivation

proper card desactivation

--- src/node/game/core.cljs
+++ src/node/game/core.cljs
@@ -63,7 +63,8 @@
   (let [c (dissoc card :counter :advance-counter :current-strength :abilities :rezzed)
         cdef (card-def card)]
     (when-let [leave-effect (:leave-play (card-def card))]
-      (leave-effect state side card nil))
+      (when (or (= (:side card) "Runner") (:rezzed card))
+        (leave-effect state side card nil)))
     (unregister-events state side card)
     (when-let [mu (:memoryunits card)]
       (gain state :runner :memory mu))
@@ -83,8 +84,7 @@
     (let [dest (if (sequential? to) (vec to) [to])
           c (if (and (= side :corp) (= (first dest) :discard) (:rezzed card))
               (assoc card :seen true) card)
-          c (if (and (#{:servers :rig :scored} (first zone)) (#{:hand :deck :discard} (first dest))
-                     (or (= (:side card) "Runner") (:rezzed card)))
+          c (if (and (#{:servers :rig :scored} (first zone)) (#{:hand :deck :discard} (first dest)))
               (desactivate state side c) c)
           moved-card (assoc c :zone dest)]
       (if front


bug fixes

bug fixes

--- src/node/game/core.cljs
+++ src/node/game/core.cljs
@@ -76,7 +76,7 @@
              (or (not req) (req state card targets))
              (<= counter-cost counter)
              (apply pay (concat [state side] cost)))
-    (when (>= counter-cost (:counter card))
+    (when (<= counter-cost (:counter card))
       (let [c (update-in card [:counter] #(- % counter-cost))]
         (update! state side c)
         (effect state side c targets)))
@@ -329,7 +329,7 @@
   (let [dest [:rig (keyword (.toLowerCase type))]]
     (when (and (can-move? state side card dest)
                (or (not uniqueness) (not (in-play? state card)))
-               (if-let [req (card-def card)] (req state card) true)
+               (if-let [req (:req (card-def card))] (req state card) true)
                (pay state side :click 1 :credit cost :memory memoryunits))
       (let [c (move state side card dest)]
         (system-msg state side (str "installs " title))


Starting problem 73. (Tic-Tac-Toe Board)

--- src/fourclojure/4_clojure.clj
+++ src/fourclojure/4_clojure.clj
@@ -70,4 +70,6 @@
     #{#{}}))

 (defn tic-tac-toe [board]
-  )+  (let [players (into #{} (apply concat board))]
+    (cond
+      (empty? (rest players)) nil)))


Version 0.4.0

Version 0.4.0

--- metlog-vault/project.clj
+++ metlog-vault/project.clj
@@ -1,4 +1,4 @@
-(defproject metlog-vault "0.4.0-SNAPSHOT"
+(defproject metlog-vault "0.4.0"
   :description "Repository for long term storage of series data."

   :license {:name "Eclipse Public License"


Unbind with dissoc and channel close on bind!

--- src/cljs/hacker_agent/hacker-base.cljs
+++ src/cljs/hacker_agent/hacker-base.cljs
@@ -146,7 +146,12 @@
       (.log js/console (clj->js [event key val])))))

 (defn bind! [data path ref binder]
+(defn unbind! [data path]
   (close-channel! data path)
+  (swap! data dissoc-in path))
+
+(defn bind! [data path ref binder]
+  (unbind! data path)
   (let [close-chan (chan)
         fbc (fb->chan ref close-chan)]
     (save-channel-closer! data path close-chan)


Split handlers chaining constructor into separate helper function.

--- src/clojure/catacumba/impl/routing.clj
+++ src/clojure/catacumba/impl/routing.clj
@@ -38,6 +38,12 @@
            ratpack.registry.RegistrySpec
            ratpack.func.Action
            java.util.List))
+
+(defn- combine-handlers
+  "Given a list of handlers, return a handler
+  that chains them."
+  [handlers]
+  (Handlers/chain (mapv hs/adapter handlers)))

 (defmulti attach-route
   (fn [chain [method & args]]
@@ -96,8 +102,7 @@
   [chain [method & handlers-and-path]]
   (let [path (first handlers-and-path)]
     (if (string? path)
-      (let [^Handler handler (-> (mapv hs/adapter (rest handlers-and-path))
-                                 (Handlers/chain))]
+      (let [^Handler handler (combine-handlers (rest handlers-and-path))]
         (case method
           :any (.prefix chain path (hp/fn->action #(.all % handler)))
           :all (.prefix chain path (hp/fn->action #(.all % handler)))


Extract common new-board! on-click handler

--- src/tile_game/grid.cljs
+++ src/tile_game/grid.cljs
@@ -14,15 +14,13 @@
   (r/atom {:board (b/create-board 4)
            :size 4}))

+(defn new-board! [& args]
+  #(swap! app-state assoc :board (apply b/create-board args)))
+
 (defn board-size-slider [size]
   [:div
-   [:button
-    {:on-click #(swap! app-state assoc :board (b/create-board size))}
-    "New Game"]
-   [:button
-    {:on-click #(swap! app-state assoc
-                       :board (b/create-board size :shuffle))}
-    "Shuffle"]
+   [:button {:on-click (new-board! size)} "New Game"]
+   [:button {:on-click (new-board! size :shuffle)} "Shuffle"]
    [:label (str "Board size: " size)]
    [:input {:type "range" :style {:width "25%"}
             :value size :min 2 :max 8


Update available-migrations to migrate-action-data

--- src/ctia/task/migration/migrations.clj
+++ src/ctia/task/migration/migrations.clj
@@ -242,4 +242,6 @@
                  pluralize-target)
    :1.0.0 (comp (append-version "1.0.0")
                 (rename-observable-type "pki-serial" "pki_serial")
-                simplify-incident)})
+                simplify-incident)
+   :1.1.0 (comp (append-version "1.1.0")
+                migrate-action-data)})


Actually Adding example 5 for tutorial

Actually Adding example 5 for tutorial

--- example-code/ex5.cljs
+++ example-code/ex5.cljs
@@ -0,0 +1,63 @@
+
+(enable-console-print!)
+;
+(defn log [data]
+  (.log js/console data))
+
+(def app-state (atom {:board-name "Yo yo yo, get it done!"
+                      :columns [{:name "To Do"
+                                 :cards [{:name "Make it look good"}]}
+                                {:name "Doing"
+                                 :cards [{:name "Tutorial number two"}]}
+                                {:name "Done"
+                                 :cards [{:name "Explain WTF#js"}]}]}))
+
+(defn card-component [data owner]
+  (reify
+    om/IRender
+    (render [_]
+      (dom/div #js {:className "list-card"
+                    :onClick #(log %)}
+        (dom/div nil (:name data))))))
+
+
+
+(defn column-component [data owner]
+  (reify
+    om/IInitState
+    (init-state [_]
+      {:add-card? false})
+
+    om/IRenderState
+    (render-state [_ {:keys [add-card?]}]
+      (dom/div #js {:className "column"}
+               (dom/div nil (:name data))
+               (apply dom/div #js {:className "cards-wrapper"}
+                 (om/build-all card-component (:cards data)))
+               (if add-card?
+                 (dom/input #js
+                   {:placeholder "Add a card"
+                    :ref "new-card"
+                    :onKeyDown (fn [event] (if (= 13 (aget event "keyCode"))
+                                            (let [input (om/get-node owner "new-card")
+                                                  input-val (.-value input)
+                                                  new-card {:name input-val}]
+                                              (do
+                                                (om/transact! data :cards #(conj % new-card))
+                                                (set! (.-value input) "")
+                                                (om/set-state! owner :add-card? false)))))})
+                 (dom/div #js {:onClick #(om/set-state! owner :add-card? true)} "Add a card ..."))))))
+
+(defn app-component [data owner]
+  (reify
+    om/IRender
+    (render [_]
+      (dom/div #js {:className "container"}
+        (dom/div nil (:board-name data))
+        (apply dom/div nil
+          (om/build-all column-component (:columns data)))))))
+
+(om/root
+  app-component
+  app-state
+  {:target (. js/document (getElementById "app"))})


workaround for lexical compilation bug

workaround for lexical compilation bug

--- src/babel/english/lexicon.cljc
+++ src/babel/english/lexicon.cljc
@@ -1698,7 +1698,9 @@
                              :pred :student}}}

    "study"  {:synsem {:cat :verb
-                      :sem {:pred :study}}
+                      :sem {:pred :study
+                            :obj {:legible true}}} ;; TODO: needed temporarily until
+             ;; English lexical compilation is made consistent with as used in Italian.
              :english {:past "studied"}}

    "stupid" (unify adjective


add compilation tag :share-sem

add compilation tag :share-sem

--- src/babel/english/lexicon.cljc
+++ src/babel/english/lexicon.cljc
@@ -2247,6 +2247,20 @@
                                            :subcat {:1 modal-subject
                                                     :2 '()}}}}}))

+
+                 ;; prevent :shared-semantics :obj unless it's already set
+                 (default
+                  {:share-sem false
+                   :synsem {:cat :verb}})
+
+                 ;; semantic object of lexical verb is the same as the object of verb's prepositional phrase.
+                 (default
+                  (let [obj (atom :top)]
+                    {:share-sem :obj
+                     :synsem {:sem {:obj obj}
+                              :subcat {:2 {:cat :prep
+                                           :sem {:obj obj}}}}}))
+
                  ;; add :sem :obj if necessary, so that intransitivize is triggered.
                  (if-then {:modal-with false
                            :synsem {:cat :verb


added go out

added go out

--- src/babel/english/lexicon.cljc
+++ src/babel/english/lexicon.cljc
@@ -650,6 +650,15 @@
     :english {:past "went downstairs"
               :present {:3sing "goes downstairs"}}}

+   "go out"
+   {:synsem {:cat :verb
+              :sem {:activity true
+                    :discrete false
+                    :pred :go-out
+                    :subj {:animate true}}}
+    :english {:past "went out"
+              :present {:3sing "goes out"}}}
+
    "go upstairs"
    {:synsem {:cat :verb
               :sem {:activity true
@@ -657,7 +666,7 @@
                     :pred :go-upstairs
                     :subj {:animate true}}}
     :english {:past "went upstairs"
-              :present {:3sing "goes downstairs"}}}
+              :present {:3sing "goes upstairs"}}}

    "grab"  {:synsem {:cat :verb
                      :sem {:pred :prendere}}


Update tests to demonstrate upserts working

--- test/onyx/plugin/output_update_test.clj
+++ test/onyx/plugin/output_update_test.clj
@@ -77,6 +77,11 @@
    {:id 4 :word "Door"}
    {:id 5 :word "Surf board"}])

+(def all-words
+  ;; "Dog" and "Window" will be replaced by "Cat" and "Door" after upserts.
+  (concat [{:id 1 :word "Dog"}
+           {:id 4 :word "Window"}] words))
+
 (defn ensure-database! [db-user db-pass db-sub-base db-name]
   (let [db-spec {:classname "com.mysql.jdbc.Driver"
                  :subprotocol "mysql"
@@ -103,8 +108,10 @@
               :words
               [[:id :int "PRIMARY KEY"]
                [:word "VARCHAR(32)"]])))
-    (doseq [word words]
-      (jdbc/insert! cpool :words word))))
+    (doseq [word all-words]
+      (jdbc/execute! cpool (mysql/upsert :words
+                                         (dissoc word :id)
+                                         (dissoc word :word))))))

 (defn transform-word
   [word]
@@ -112,8 +119,8 @@

 (deftest sql-update-output-test
   (let [{:keys [env-config peer-config mysql-config]} (read-config
-                                                     (io/resource "config.edn")
-                                                     {:profile :test})
+                                                       (io/resource "config.edn")
+                                                       {:profile :test})
         {:keys [sql/username sql/password sql/subname sql/db-name]} mysql-config
         job (build-job username password subname db-name 10 1000)
         {:keys [in]} (get-core-async-channels job)
@@ -124,7 +131,7 @@
                      :password password})]
     (with-test-env [test-env [4 env-config peer-config]]
       (ensure-database! username password subname db-name)
-      (pipe (spool words) in true)
+      (pipe (spool all-words) in true)
       (onyx.test-helper/validate-enough-peers! test-env job)
       (->> (:job-id (onyx.api/submit-job peer-config job))
            (onyx.api/await-job-completion peer-config))


(maint) Update testutils to return leaf cert keys

This commit updates the `generate-cert-chain-with-crls` test utility to return
the key pair for the last cert in the chain. This is useful for any testing that
involves actually importing the generated certs and crls or signing anything
after the original certs and crls are generated.

--- test/puppetlabs/ssl_utils/testutils.clj
+++ test/puppetlabs/ssl_utils/testutils.clj
@@ -190,7 +190,7 @@
             issuer root-cert
             issuer-key-pair root-key-pair]
        (if (< certs-to-generate 1)
-         [certs crls]
+         [certs crls issuer-key-pair]
          (let [[new-cert new-key-pair] (generate-ca-cert
                                         (cn (get-cn-from-x509-certificate issuer))
                                         issuer-key-pair
@@ -211,17 +211,17 @@
   (if (< number-of-certs 2)
     (throw (Exception. (format "Can't perform revocations on a %d-cert chain."
                                number-of-certs))))
-  (let [key-pair (generate-key-pair 2048)
-        [certs crls] (generate-cert-chain-with-crls number-of-certs
-                                                    generate-crl
-                                                    key-pair)
+  (let [root-key-pair (generate-key-pair 2048)
+        [certs crls leaf-keys] (generate-cert-chain-with-crls number-of-certs
+                                                              generate-crl
+                                                              root-key-pair)
         cert-to-revoke (nth certs (- number-of-certs 2))
         crl-to-update (last crls)
         updated-crl (revoke crl-to-update
-                            (get-private-key key-pair)
-                            (get-public-key key-pair)
+                            (get-private-key root-key-pair)
+                            (get-public-key root-key-pair)
                             (get-serial cert-to-revoke))]
-    [certs (-> crls drop-last (conj updated-crl))]))
+    [certs (-> crls drop-last (conj updated-crl) leaf-keys)]))

 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;; Writing test files
@@ -249,28 +249,28 @@
   [number-of-certs test-subpath]
   (let [certs-filename (str number-of-certs "-cert-chain.pem")
         crls-filename (str number-of-certs "-crl-chain.pem")
-        [certs crls] (generate-cert-chain-with-crls number-of-certs)]
+        [certs crls _] (generate-cert-chain-with-crls number-of-certs)]
     (write-certs-and-crls certs crls test-subpath certs-filename crls-filename)))

 (defn write-expired-crl
   [test-subpath]
   (let [cert-filename "cert-with-expired-crl.pem"
         crl-filename "expired-crl.pem"
-        [cert expired-crl] (generate-cert-chain-with-crls 1 generate-expired-crl)]
+        [cert expired-crl _] (generate-cert-chain-with-crls 1 generate-expired-crl)]
     (write-certs-and-crls cert expired-crl test-subpath cert-filename crl-filename)))

 (defn write-not-yet-valid-crl
   [test-subpath]
   (let [cert-filename "cert-with-not-valid-crl.pem"
         crl-filename "not-yet-valid-crl.pem"
-        [cert crl] (generate-cert-chain-with-crls 1 generate-not-yet-valid-crl)]
+        [cert crl _] (generate-cert-chain-with-crls 1 generate-not-yet-valid-crl)]
     (write-certs-and-crls cert crl test-subpath cert-filename crl-filename)))

 (defn write-crl-with-bad-sig
   [test-subpath]
   (let [cert-filename "cert-with-crl-bad-sig.pem"
         crl-filename "crl-with-bad-signature.pem"
-        [cert bad-crl] (generate-cert-chain-with-crls 1 generate-crl-with-bad-signature)]
+        [cert bad-crl _] (generate-cert-chain-with-crls 1 generate-crl-with-bad-signature)]
     (write-certs-and-crls cert bad-crl test-subpath cert-filename crl-filename)))

 (defn write-cert-chain-with-revoked-cert


language byte

language byte

--- src/neversleep_clojure_client/core.clj
+++ src/neversleep_clojure_client/core.clj
@@ -47,7 +47,7 @@
           (if-not (nil? stream-in-ch)
             (let [responce (<!! stream-in-ch)
                   ;_ (println "got responce" responce)
-                  responce (clojure.walk/keywordize-keys (cheshire/decode (String. (byte-array responce))))
+                  responce (util/de-serialize (byte-array responce))
                   request-uuid (keyword (get responce :request-uuid))
                   callback (get @pending-requests request-uuid)]
               ;gc atom
@@ -101,12 +101,13 @@
 (defn- header-bytes
   "Bytes common to all requests"
   [command]
-  (let [api-version (byte-array [api-version])
+  (let [language (byte-array [0])
+        api-version (byte-array [api-version])
         command (byte-array [command])
         verbose-mode (byte-array [0])
         uuid (util/uuid)
         request-uuid (util/uuid-to-bytes uuid)]
-    {:header-bytes (byte-array (concat api-version command verbose-mode request-uuid))
+    {:header-bytes (byte-array (concat language api-version command verbose-mode request-uuid))
      :request-uuid (str uuid)}))


(PDB-2852) export: write data via Files/copy

Files/copy has been observed to be notably more efficient than io/copy.

--- src/puppetlabs/puppetdb/cli/export.clj
+++ src/puppetlabs/puppetdb/cli/export.clj
@@ -15,7 +15,9 @@
             [puppetlabs.puppetdb.schema :as pls]
             [puppetlabs.puppetdb.utils :as utils]
             [schema.core :as s]
-            [slingshot.slingshot :refer [throw+ try+]]))
+            [slingshot.slingshot :refer [throw+ try+]])
+  (:import
+   [java.nio.file Files StandardCopyOption]))

 (def admin-api-version :v1)

@@ -53,7 +55,9 @@
                          (not= anonymization ::no-anonymization)
                          (assoc :query-params {"anonymization_profile" anonymization})))
       :body
-      (io/copy (io/file filename))))
+      (Files/copy (.toPath (io/file filename))
+                  (into-array StandardCopyOption
+                              [StandardCopyOption/REPLACE_EXISTING]))))

 (defn -main
   [& args]


Add send logs button to exception dialog

--- src/status_im/utils/error_handler.cljs
+++ src/status_im/utils/error_handler.cljs
@@ -1,6 +1,8 @@
 (ns status-im.utils.error-handler
   (:require [clojure.string :as string]
-            [status-im.utils.utils :as utils]))
+            [status-im.utils.utils :as utils]
+            [status-im.i18n :as i18n]
+            [re-frame.core :as re-frame]))

 ;; Error handling code based on https://gist.github.com/pesterhazy/e6846be1b6712a9038537022d131ce46

@@ -54,4 +56,8 @@
          (handle-error e isFatal)
          (if js/goog.DEBUG
            (some-> orig-handler (.call nil e isFatal))
-           (utils/show-popup "Error" (.-message e))))))))+           (utils/show-confirmation
+            {:title               "Error"
+             :content             (.-message e)
+             :confirm-button-text (i18n/label :t/send-logs)
+             :on-accept           #(re-frame/dispatch [:logging.ui/send-logs-pressed])})))))))


Lots of tests of domain.

Lots of tests of domain.

--- test/elephantdb/common/domain_test.clj
+++ test/elephantdb/common/domain_test.clj
@@ -34,12 +34,28 @@
 (fact
   "Getting a seq on a domain should return the documents from ALL
    shards, no matter what the split."
-  (let [shard-seq [0 0 1 1]
-        doc-seq   [(KeyValDocument. 1 2)
-                   (KeyValDocument. 3 4)
-                   (KeyValDocument. 5 6)
-                   (KeyValDocument. 7 8)]]
+  (let [domain-spec (berkeley-spec 3)
+        shard-seq   [0 0 1 1]
+        doc-seq     [(KeyValDocument. 1 2)
+                     (KeyValDocument. 3 4)
+                     (KeyValDocument. 5 6)
+                     (KeyValDocument. 7 8)]]
     (with-basic-domain [domain
-                        (berkeley-spec 3)
-                        (map vector shard-seq doc-seq)]
-      (seq domain) => (contains doc-seq :in-any-order))))
+                        domain-spec
+                        (map vector shard-seq doc-seq)
+                        :version 10]
+
+      "We check that the seq produces values from shards 0 and 1."
+      (seq domain) => (contains doc-seq :in-any-order)
+      (current-version domain) => 10
+      (newest-version domain) => 10
+      (version-seq domain) => [10]
+      (has-version? domain 5) => falsey
+      (has-version? domain 10) => truthy
+      (has-data? domain) => truthy
+
+      "Testing an empty local domain."
+      (t/with-fs-tmp [_ tmp]
+        (let [other-domain (build-domain tmp :spec domain-spec)]
+          (version-seq other-domain) => nil
+          (has-data? other-domain) => falsey)))))


change the users model to also support the new yesql release

--- src/bitfondue/models/users.clj
+++ src/bitfondue/models/users.clj
@@ -10,8 +10,12 @@
                           (:email user)
                           (:password user)))

+(defn insert-user!
+  "Insert a user into the database"
+  [user]
+  (database/insert-user<! user))
+
 (defn get-user
   "Get a user by its username"
   [username]
-  (database/get-user config/database
-                     username))
+  (database/get-user {:username username}))


Small fix

Small fix

--- src/clj/salava/core/layout.clj
+++ src/clj/salava/core/layout.clj
@@ -128,7 +128,7 @@
        [:link {:rel "icon" :type "image/png" :href  (:png favicons)}]

        [:script {:type "text/javascript"} (context-js ctx)]
-       (include-js "/js/dataLayer.js"))]
+       (include-js "/js/dataLayer.js")]

       [:body {:class (if (nil? (get-in ctx [:user])) "anon")}
        [:div#app]


Dropbox setup now handles app dev reloads better

--- src/cljs/modern_cljs/core.cljs
+++ src/cljs/modern_cljs/core.cljs
@@ -67,10 +67,11 @@

 (defn data_from_db [url]
   "Getting data from Dropbox"
-  (.read js/crud url (fn [resp]
-                                (println "Fetched from DB")
-                                (let [data (.parse js/JSON resp)]
-                                  (updatedb [:data] (js->clj data))))))
+  (.read js/crud url
+         (fn [resp]
+           (println "Fetched data from DB")
+           (let [data (.parse js/JSON resp)]
+           (updatedb [:data] (js->clj data))))))

 (defn setpage [next]
   (updatedb [:start] next))
@@ -178,14 +179,14 @@
 (println "Hello All!!!")
 (js/foo)

-(js/setup_dropbox)
-(if (and (not(nil? js/client)) (.isAuthenticated js/client))
+(if (nil? js/client) (js/setup_dropbox))
+(if (.isAuthenticated js/client)
   (do
     (set! (.-mode (.-route js/m)) "hash")
     (.route js/m
-            (.getElementById js/document "app")
-            "/"
-            (clj->js {"/" app})))
+      (.getElementById js/document "app")
+      "/"
+      (clj->js {"/" app})))
   (println "No auth!"))

 ;; (require '[modern-cljs.core :as c] :reload)


Bookmarklet query params now go to note form

Also, Mithril helper for getting route params

--- src/cljs/modern_cljs/core.cljs
+++ src/cljs/modern_cljs/core.cljs
@@ -37,6 +37,10 @@
    (if (= (type z) (type []))
      '("Tag with attrs and children")
      '("Tag with attrs and text worthy content, I hope"))))
+
+(defn route_param [param]
+  "Get param from route params"
+  (.param (.-route js/m) param))

 ;
 ; Closure helpers
@@ -220,13 +224,16 @@
             (clj->js {"/" app}))))

 (if (and (not (nil? js/client)) (.isAuthenticated js/client))
-  (setup)
+  (do
+    (setup)
+    (let [params {"title" (route_param "title")
+                  "url" (route_param "url")
+                  "referer" (route_param "referer")}]
+      (if (not(nil? params))
+        (do (println "initial param was:" params)
+            (updatedb [:editing] params)
+            (.route js/m "/")))))
   (println "No auth!"))
-
-;(let [par (.param (.-route js/m) "hih")]
-;  (if (not(nil? par))
-;    (println "initial param was:" par)
-;    (.route js/m "/")))

 ;; (require '[modern-cljs.core :as c] :reload)
 ;; alt cmd e -> search repl history


http-kit/clojure: Add remaining constants (ported from LFE).

--- src/clojure/src/dnsresolvh.clj
+++ src/clojure/src/dnsresolvh.clj
@@ -28,6 +28,12 @@
 (defmacro DIGITS           [] #"\d+")
 (defmacro PARAMS-SEPS      [] #"=|&")

+; JSON entities :-).
+(defmacro CB1 []   "{\"")
+(defmacro CB2 []   "\"}")
+(defmacro DQ1 [] "\":\"")
+(defmacro DQ2 [] "\",\"")
+
 ; Common error messages.
 (defmacro ERR-PREFIX                    [] "error"                        )
 (defmacro ERR-PORT-MUST-BE-POSITIVE-INT [](str ": <port_number> must be "
@@ -38,6 +44,7 @@
                                                "Exiting..."              ))
 (defmacro ERR-SRV-PORT-IS-IN-USE        [](str "due to the port requested "
                                                "is in use. Exiting..."   ))
+(defmacro ERR-COULD-NOT-LOOKUP          [] "could not lookup hostname"    )

 ; Print this error message when there are no any args passed.
 (defmacro ERR-MUST-BE-ONE-TWO-ARGS-1 [](str ": There must be one or two args "
@@ -74,6 +81,12 @@
 (defmacro HDR-PRAGMA-N            [] "pragma"                       )
 (defmacro HDR-PRAGMA-V            [] "no-cache"                     )
 (defmacro RSC-HTTP-200-OK         [] 200                            )
+
+; Response data names.
+(defmacro DAT-HOSTNAME-N [] "hostname")
+(defmacro DAT-ADDRESS-N  [] "address" )
+(defmacro DAT-VERSION-N  [] "version" )
+(defmacro DAT-VERSION-V  [] "IPv"     )

 ; Daemon name, version, and copyright banners.
 (defmacro DMN-NAME        [] "DNS Resolver Daemon (dnsresolvd)"       )


Add dynamic url

Add dynamic url

--- src/discuss/communication.cljs
+++ src/discuss/communication.cljs
@@ -85,7 +85,7 @@
   []
   (let [url (:init config/api)]
     (lib/update-state-item! :layout :add? (fn [_] false))
-    (ajax-get url)))
+    (ajax-get-and-change-view url :default)))

 ;;;; Discussion-related functions
@@ -117,7 +117,7 @@
 (defn request-references
   "When this app is loaded, request all available references from the external discussion system."
   []
-  (let [url "api/get/references"                            ; TODO hardcoded url = bad
+  (let [url (str (:base config/api) (get-in config/api [:get :references]))
         headers {"X-Host" js/location.host
                  "X-Path" js/location.pathname}]
     (ajax-get url headers references-handler)))


Added defaults for flickr API configuration.

--- src/dragon/config/defaults.clj
+++ src/dragon/config/defaults.clj
@@ -33,6 +33,9 @@
    :cli {
      :log-level :error
      :log-nss '[dragon]}
+   :apis {
+     :flickr {
+       :access "~/.flickr/access.key"}}
    :processor {
      :constructor :default}
    :workflow {


prototype of defop

prototype of defop

Signed-off-by: Yen-Chin Lee <082d453d72dce940e12089a4ad48b97cfe1f3ec4@gmail.com>

--- src/emulator_chip8/opcode.cljc
+++ src/emulator_chip8/opcode.cljc
@@ -1,6 +1,19 @@
-(ns emulator-chip8.opcode)
+(ns emulator-chip8.opcode
+  #?(:cljs (:require-macros [emulator-chip8.opcode :refer [defop]])))
+
+#?(:clj
+   (defmacro defop
+     [name & body]
+     (let [name (symbol (str "opcode-" name))
+           args [{'r :registers 'm :memory :as 'cpu}
+                 'addr-mode
+                 ['n 'n-addr]]]
+       `(defn ~name ~args ~@body))))

 ;; 0NNN
+(defop 0NNN
+
+  )

 ;; 00E0
 (defn opcode-00E0


added ring ex

added ring ex

--- src/higher_order_functions.clj
+++ src/higher_order_functions.clj
@@ -30,11 +30,14 @@

 ;; Pull "columns" out of a collection of collections.
 (map vector [:a :b :c] {:one 1 :two 2 :three 3} [:g :h :i])
+
 (apply map vector [[:a :b :c]
                    {:one 1 :two 2 :three 3}
                    [:g :h :i]])

-(map #(vector (first %) (* 2 (second %)))
+(map #(vector (first %) (let [crzy (fn [e]
+                                     (* e 10))]
+                          (* (crzy 10) (second %))))
      {:a 1 :b 2 :c 3})

 ;; applies fn (list) to first element of each collection as (fn 1 a 10)
@@ -77,7 +80,10 @@

 ;; Use a hash-map as a function to translate values in a collection from the
 ;; given key to the associated value; then use (filter identity... to remove the nils
-(filter not-empty (map {2 "two" 3 "three"} [1 2 3 4 5]))
+(map
+ (filter even?
+         (map
+          {2 "two" 3 "three"} [1 2 3 4 5])))

 ;;;;;;;;;;
@@ -99,3 +105,36 @@
   (reduce #(assoc %1 %2 (inc (%1 %2 0)))
           {}
           (re-seq #"\w+" s)))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Ring Middlewares as HoF
+
+;; request
+(def request
+  {:server-port "8080"
+   :content-type :text
+   :remote-addr "http://localhost:8080"})
+
+;; handler
+(defn my-ip [request]
+  {:status 200
+   :headers {"Content-Type" "text/plain"}
+   :body (:remote-addr request)})
+
+;; middleware
+(defn wrap-content-type [handler content-type]
+  (fn [request]
+    (let [response (handler request)]
+      (assoc-in response [:headers "Content-Type"] content-type))))
+
+(defn json-response [data & [status]]
+  {:status (or status 200)
+   :headers {"Content-Type" "application/edn"}
+   :body (pr-str data)})
+
+(def app
+  (wrap-content-type my-ip "text/html"))
+
+(defn serve [request]
+  (app request))


html->etyms

html->etyms

--- src/instantetymonline/core.clj
+++ src/instantetymonline/core.clj
@@ -89,6 +89,14 @@
   (dotimes [n (get letter-page-map letter)]
     (save-html! letter (str n))))

+(defonce words (atom {}))
+
+(defn html->etyms []
+  (doseq [char (keys letter-page-map)] ;; the alphabet
+    (dotimes [n (get letter-page-map char)]
+      (do (swap! words #(merge % (etyms (read-html char (str n)))))
+          (println "read into atom" char (str n))))))
+
 (comment
   ;; Ran this for all letters on October 24, 2015
   (persist-letter! "a")
@@ -96,12 +104,14 @@
   ;; To read it into mem, then save and merge with dict map
   (etyms (read-html "y" "1"))

-  ;;defonce? temp atom
-  ;;(def words (atom {}))
+  (html->etyms)
+
+  (spit "src/dict2.cljs" @words)
+

   ;; This is cheap so we can do this multiple times I think
   ;; Also we can just read all files from raw_html directory
-  (dotimes [n (get letter-page-map "y")]
-    (do (swap! words #(merge % (etyms (read-html "y" (str n)))))
-        (println "read into atom" "y" (str n))))
-)
+
+
+;;  (slurp (first (.listFiles (clojure.java.io/file "raw_html"))))
+  )


add present-tense test for "se plaindre"

--- test/babel/test/fr.cljc
+++ test/babel/test/fr.cljc
@@ -382,6 +382,16 @@
     (is (= (fo have-fun-expression)
            "il l'amuse"))))

-
-
-
+(deftest se-plaindre
+  (let [to-conjugate {:français "se plaindre", :initial false,
+                      :agr {:number :sing,
+                            :person :1st,
+                            :gender :masc},
+                      :essere true,
+                      :infl :present}]
+    (is (= "plains"
+           (babel.francais.morphology/get-string to-conjugate)))))
+
+
+
+


rewriting with try-hard-to

rewriting with try-hard-to

--- test/babel/test/fr.cljc
+++ test/babel/test/fr.cljc
@@ -182,12 +182,11 @@
          (is (= (fo result) "nous sommes allées")))))

 (deftest generate-passe-compose
-  (let [result (engine/generate {:synsem {:sem {:pred :go
-                                                :subj {:pred :noi
-                                                       :gender :fem}
-                                                :aspect :perfect
-                                                :tense :past}}}
-                                small)]
+  (let [result (try-hard-to #(generate {:synsem {:sem {:pred :go
+                                                       :subj {:pred :noi
+                                                              :gender :fem}
+                                                       :aspect :perfect
+                                                       :tense :past}}}))]
     (is (not (nil? result)))
     (is (= (fo result) "nous sommes allées"))))

@@ -207,23 +206,30 @@
            "je m'amuse"))))

 (deftest generate-have-fun-sentence
-  (let [result (engine/expression medium
-                                  {:synsem {:sem {:pred :have-fun}}})]
+  (let [result (try-hard-to #(generate
+                              {:synsem {:sem {:pred :have-fun}}}))]
     (is (= (get-in result [:synsem :sem :pred]) :have-fun))))

 (deftest generate-vp-aux-reflexive
   (let [result
-        (engine/expression
-         medium
-         {:synsem {:subcat '() :sem {:subj {:pred :lei}
-                                     :pred :have-fun :tense :past}}})]
+        (try-hard-to #(generate
+                       {:synsem {:subcat '() :sem {:subj {:pred :lei}
+                                                   :pred :have-fun :tense :past}}}))]
     (is (= (fo result) "elle l'est amusée"))))

+(deftest generate-vp-present-reflexive
+  (let [result
+        (try-hard-to #(generate
+                       {:synsem {:subcat '() :sem {:subj {:pred :lei}
+                                                   :pred :have-fun :tense :present}}}))]
+    (is (= (fo result) "elle l'amuse"))))
+
 (deftest generate-named-sentence
-  (let [result (engine/expression medium
-                                  {:synsem {:sem {:pred :be-called
-                                                  :subj {:pred :lui}
-                                                  :obj {:pred :Jean}}}})]
+  (let [result
+        (try-hard-to #(generate
+                       {:synsem {:sem {:pred :be-called
+                                       :subj {:pred :lui}
+                                       :obj {:pred :Jean}}}}))]
     (is (= (fo result) "il l'appele Jean"))))

 (deftest parse-reflexive
@@ -389,5 +395,3 @@
                                    :tense :present}}}))]
     (is (not (empty? the-foo)))))

-
-(deftest generate-vp-present-reflexive


Dereference the value as it is an atom

Dereference the value as it is an atom

--- src/io/cyanite/engine.clj
+++ src/io/cyanite/engine.clj
@@ -54,7 +54,7 @@
           to-purge (filter #(< (key %) floor) (entries slots))]
       (doseq [slot (map key to-purge)]
         (remove! slots slot))
-      (mapv #(snapshot! (val %) (key %)) to-purge))))
+      (mapv #(snapshot! @(val %) (key %)) to-purge))))

 (defn make-resolutions
   [rules metric]


minors updates for utility functions

minors updates for utility functions

--- src/io/perun/markdown.clj
+++ src/io/perun/markdown.clj
@@ -6,15 +6,23 @@
             [endophile.core  :as endophile]
             [clj-yaml.core   :as yaml]))

-(defn extract-between [s prefix suffix]
-  (some-> s
-          (str/split prefix)
-          second
-          (str/split suffix)
-          first))
+(defn substr-between
+  "Find string that is nested in between two strings. Return first match.
+  Copied from https://github.com/funcool/cuerdas"
+  [s prefix suffix]
+  (cond
+    (nil? s) nil
+    (nil? prefix) nil
+    (nil? suffix) nil
+    :else
+    (some-> s
+            (str/split prefix)
+            second
+            (str/split suffix)
+            first)))

 (defn parse-file-metadata [file-content]
-  (if-let [metadata-str (extract-between file-content #"---\n" #"---\n")]
+  (if-let [metadata-str (substr-between file-content #"---\n" #"---\n")]
     (if-let [parsed-yaml (yaml/parse-string metadata-str)]
       ; we use `original` file flag to distinguish between generated files
       ; (e.x. created those by plugins)


update test/example

update test/example

--- test/example/demand.clj
+++ test/example/demand.clj
@@ -113,11 +113,15 @@
         (pan2 (* 0.1 src))))

 ;;diwhite example
-(demo 5
-      (let [vals (diwhite 0 15 INF)
+(demo 10
+      (let [vals (dwhite 0 15 INF)
             trig (impulse:kr (mouse-x 1 40 1))
-            freq (+ 340 (* 30 (demand:kr trig 0 vals)))]
+            val (demand:kr trig 0 vals)
+            poll (poll trig val "diwhite val:")
+            freq (+ 340 (* 30 val))]
         (* 0.1 (sin-osc freq))))
+
+

 ;; write demand sequence into a buffer
@@ -131,17 +135,3 @@
             write (mouse-button)]
         (demand:kr write 0 (dbufwr val b pos 1))
         (* 0.1 (sin-osc (duty:kr (* 0.2 (dseq [0.5 0.75 0.5 1] INF)) 0 (dbufrd b (dseries 0 1 INF)))))))
-
-;;dbrown
-(demo 10
-      (let [vals (dbrown 0 15 1 INF)
-            trig (impulse:kr (mouse-x 1 40 1))
-            freq (+ 340 (* 30 (demand:kr trig 0 vals)))]
-        (* 0.1 (sin-osc freq))))
-
-;;dibrown
-(demo 10
-      (let [vals (dibrown 0 15 1 INF)
-            trig (impulse:kr (mouse-x 1 40 1))
-            freq (+ 340 (* 30 (demand:kr trig 0 vals)))]
-        (* 0.1 (sin-osc freq))))


get rid of austin reference

get rid of austin reference

--- repl/user.clj
+++ repl/user.clj
@@ -5,8 +5,7 @@
             [jamesmacaulay.zelkova.signal-test :as signals-test]
             [clojure.core.async :as async :refer [go go-loop <! <!! >! >!! chan]]
             [clojure.tools.namespace.repl :refer [refresh]]
-            [clojure.test]
-            [cemerick.austin.repls]))
+            [clojure.test]))

 (defn run-tests
   []


make user/run-tests more refreshing

make user/run-tests more refreshing

--- repl/user.clj
+++ repl/user.clj
@@ -7,4 +7,5 @@

 (defn run-tests
   []
+  (refresh)
   (clojure.test/run-all-tests #"jamesmacaulay\..*"))


Add doc string to defmannerisms.

Add doc string to defmannerisms.

--- src/manners/victorian.clj
+++ src/manners/victorian.clj
@@ -51,6 +51,7 @@
   ([etiquette value] (avow! nil etiquette value)))

 (defmacro defmannerisms
+  "Define helper functions for validating using a consistent etiquette."
   [obj-sym & etiquette]
   (let [bad-manners-sym (symbol (str "bad-" obj-sym "-manners"))
         proper?-sym (symbol (str "proper-" obj-sym \?))


Add unit info

Add unit info

--- src/obb_demo/views/player.cljs
+++ src/obb_demo/views/player.cljs
@@ -4,6 +4,7 @@
             [obb-rules.element :as element]
             [obb-rules.actions.move :as move]
             [obb-rules.stash :as stash]
+            [obb-rules.unit :as unit]
             [obb-rules.host-dependent :as host]
             [obb-demo.processor :as processor]
             [obb-demo.views.power-bar :as power-bar]
@@ -181,6 +182,41 @@
        ]]
     ))

+(defn- selected-element-info
+  "Adds docs"
+  [game-data]
+  (if-let [element (:selected-element game-data)]
+    (let [unit (element/element-unit element)]
+     [:div.panel.panel-info {:style {:margin-top "20px"}}
+      [:div.panel-heading
+       [:h3.panel-title (str "Selected element: " (unit/unit-name unit))]]
+      [:div.panel-body
+       [:div.row
+        [:div.col-lg-4
+         [:ul.list-group
+          [:li.list-group-item [:span.badge (unit/unit-attack unit)] "Attack"]
+          [:li.list-group-item [:span.badge (name (unit/attack-type unit))] "Type"]
+          [:li.list-group-item [:span.badge (unit/unit-range unit)] "Range"]
+          (when (:after-attack unit)
+            [:li.list-group-item [:span.badge (map #(name (first %)) (:after-attack unit))] "Powers"])]]
+
+        [:div.col-lg-4
+         [:ul.list-group
+          [:li.list-group-item [:span.badge (unit/unit-defense unit)] "Defense"]
+          (when (:after-hit unit)
+            [:li.list-group-item [:span.badge (map #(name (first %)) (:after-hit unit))] "Powers"])
+          [:li.list-group-item [:span.badge (name (unit/unit-category unit))] "Category"]]]
+
+        [:div.col-lg-4
+         [:ul.list-group
+          [:li.list-group-item [:span.badge (name (unit/unit-movement-type unit))] "Movement"]
+          [:li.list-group-item [:span.badge (unit/unit-movement-cost unit)] "Movement cost"]]]
+
+        ]
+       ]]
+  )))
+
+
 (defn render
   [state]
   (let [game-data (get-game-data state)
@@ -196,7 +232,8 @@
        (rotate-panel game-data)
        [:button.btn.btn-default {:on-click (partial reset-turn game-data)} "Reset turn"]]
       [:div.col-lg-5
-        [boardground/render {} game-data]]
+        [boardground/render {} game-data]
+        (selected-element-info game-data)]
       [:div.col-lg-5
        [:div.jumbotron
         [:h1 "Demo"]


Skip input recovery when resume mode is :initialize (#872)

--- src/onyx/peer/resume_point.clj
+++ src/onyx/peer/resume_point.clj
@@ -111,10 +111,9 @@
           {:keys [onyx.core/slot-id]} event]
       (checkpoint-decompress (read-checkpoint event :output resume-mapping slot-id)))))

-(defn recover-input [event recover-coordinates]
-  (if-let [resume-mapping (coordinates->input-resume-point event recover-coordinates)]
-    (let [{:keys [slot-migration]} resume-mapping
-          ;; TODO, support slot-id mappings
-          _ (assert (= slot-migration :direct))
-          {:keys [onyx.core/slot-id]} event]
+(defn recover-input [{:keys [onyx.core/slot-id] :as event} recover-coordinates]
+  (when-let [{:keys [mode slot-migration] :as resume-mapping} (coordinates->input-resume-point event recover-coordinates)]
+    (when (not= mode :initialize)
+      ;; TODO, support slot-id mappings
+      (assert (= slot-migration :direct))
       (checkpoint-decompress (read-checkpoint event :input resume-mapping slot-id)))))


Bump up to 10 posts per page.

Bump up to 10 posts per page.

--- src/oc/storage/config.clj
+++ src/oc/storage/config.clj
@@ -86,4 +86,4 @@

 (defonce inline-comment-count 10)

-(defonce default-activity-limit 7)+(defonce default-activity-limit 10)


Tweak org.httpkit.timer API

Tweak org.httpkit.timer API

--- src/org/httpkit/timer.clj
+++ src/org/httpkit/timer.clj
@@ -1,26 +1,52 @@
 (ns org.httpkit.timer
+  "TimerService wrapper:
+     * Can schedule many tasks at once.
+     * When scheduled for 1000ms, may run in 1000ms, 10001ms, etc.
+     * Cancel returns true => future task guaranteed cancelled;
+             returns false => already cancelled || already run.
+     * Scheduling a new task is O(log(N)) where N is # active tasks.
+     * Cancelling a task is O(N).
+     * Timer-service thread will kill itself automatically when no task is
+       scheduled for 4 minutes, and will restart automatically when a new task
+       is added."
   (:import [org.httpkit TimerService CancelableFutureTask]))

-;; TimerService
-;; 1. can schedule many many timeout tasks at once
-;; 2. schedule in 1000ms, maybe run in 1000ms, 10001ms, etc.
-;; 3. cancel return true => future task guaranteed canceled; return false => already cancelled || already runned
-;; 4. schedule a new timeout task O(log(N))  : N is active task
-;; 5. cancel O(N)
-;; 6. not used, not pay => timer-service thread will kill itself when no task to schedule for 4 minites, restart the thread automatically if new task get added
+(defn cancel [^CancelableFutureTask task]
+  (.cancel task))

-(defmacro set-timeout [ms & forms]
-  `(.timeout TimerService/SERVICE ~ms (fn [] ~@forms)))
+(defmacro schedule-task
+  "Schedules body for invocation after given time and returns a
+  CancelableFutureTask. `(cancel task)` will cancel the task if possible and
+  return true iff cancellation was successful.

-(defn cancel [^CancelableFutureTask timer]
-  (.cancel timer))
+    (let [task (schedule-task 800 (println \"Task triggered\"))]
+      (Thread/sleep (rand-nth [900 700]))
+      (when (cancel task) ; Returns true iff task successfully cancelled
+        (println \"Task was cancelled\")))"
+  [ms & body]
+  `(.timeout TimerService/SERVICE ~ms (fn [] ~@body)))

-(comment
-  (let [timers (doall
-                (map (fn [idx]
-                       (let [time (+ (rand-int 10000) 1000)]
-                         (set-timeout time
-                                      (println (str "#" idx ", with timeout " time)))))
-                     (range 10)))]
-    (if (cancel (nth timers 3))
-      (println "3 get canceled"))))
+(comment (let [task (schedule-task 800 (println "Task triggered"))]
+           (Thread/sleep (rand-nth [900 700]))
+           (when (cancel task)
+             (println "Task was cancelled"))))
+
+(defmacro with-timeout
+  "Schedules timeout-form for invocation after given timeout and wraps named
+  fn so that calling it with any arguments also cancels the timeout if possible.
+  If the timeout has already been invoked, the fn will not run and will
+  immediately return nil.
+
+    (with-timeout println 800 (println \"Timeout task triggered\")
+      (Thread/sleep (rand-nth [900 700]))
+      (println \"Timeout task was cancelled\"))"
+  [f ms timeout-form & body]
+  `(let [timeout-task# (schedule-task ~ms ~timeout-form)
+         ~f (fn [& args#]
+              (when (cancel timeout-task#)
+                (apply ~f args#)))]
+     ~@body))
+
+(comment (with-timeout println 800 (println "Timeout task triggered")
+           (Thread/sleep (rand-nth [900 700]))
+           (println "Timeout task was cancelled")))


accept user-name in the ascii art print fn

--- src/overtone/util/lib.clj
+++ src/overtone/util/lib.clj
@@ -6,8 +6,7 @@
            [java.util.concurrent TimeUnit TimeoutException])
   (:use [clojure.stacktrace]
         [clojure.pprint]
-        [overtone.util doc])
-  (:require [overtone.util.log :as log]))
+        [overtone.util doc]))

 (defn indexed
   "Takes col and returns a list of index val pairs for each successive val in
@@ -226,7 +225,7 @@
          (throw (Exception. (str "deref! timeout error. Dereference took longer than " timeout " ms")))
          res))))

-(defn user-name
+(defn system-user-name
   "returns the name of the current user"
   []
   (System/getProperty "user.name"))
@@ -245,7 +244,7 @@
   (into {} (map (fn [[k v]] [k (if (keyword? v) (name v) (str v))]) m)))

 (defn print-ascii-art-overtone-logo
-  [version-str]
+  [user-name version-str]
   (println (str "
           _____                 __
          / __  /_  _____  _____/ /_____  ____  ___
@@ -256,7 +255,7 @@
                           Programmable Music. "version-str"

-Hello " (user-name) ", may this be the start of a beautiful music hacking session...")))
+Hello " user-name ", may this be the start of a beautiful music hacking session...")))

 (defn capitalize
   "Make the first char of the text uppercase and leave the rest unmodified"


Exercise 1.24

Exercise 1.24


Sigh, whoops. Would have been nice to get an error out of this.

--- src-cljs/githubcomments/github.cljs
+++ src-cljs/githubcomments/github.cljs
@@ -7,7 +7,7 @@
   ([endpoint] (api-call http/get endpoint))
   ([method endpoint & [parameters]] (method (.resolve url endpoint)
                                             {:with-credentials? false
-                                             :json-parameters parameters})))
+                                             :json-params parameters})))

 (defn repo-comments [[owner name]]
   (api-call (Uri. (str "/repos/" owner "/" name "/comments"))))


align let statement

align let statement

--- examples/wobble.clj
+++ examples/wobble.clj
@@ -8,10 +8,10 @@
    min {:doc "minimum freq to always let through" :default 40}
    max {:doc "maximum freq to let through the wobble" :default 3000}]
   (:ar
-   (let [scaled-wob (lin-exp wobble-amount -1 1 min max)
-         wob   (lpf src scaled-wob)
-         wob   (* 0.8 (normalizer wob))
-         wob   (+ wob (bpf wob 1500 2))]
+   (let [scaled-wob (lin-exp (lf-tri wobble-amount) -1 1 min max)
+         wob        (lpf src scaled-wob)
+         wob        (* 0.8 (normalizer wob))
+         wob        (+ wob (bpf wob 1500 2))]
      (+ wob (* 0.2 (g-verb wob 9 0.7 0.7))))))

 (defcgen auto-wobble


Fix typo in LaTeX renderer.

Fix typo in LaTeX renderer.

--- src/algebolic/expression/render.clj
+++ src/algebolic/expression/render.clj
@@ -25,7 +25,7 @@
       :times  (str/join " \\cdot " (map latexify (rest expr)))
       :div (str "\\frac{" (latexify (first (rest expr))) " }{ " (latexify (second (rest expr))) "}")
       :sin (str "\\sin(" (latexify (second expr)) ")")
-      :cos (str "\\cos(" (latexify (second expr))) ")")
+      :cos (str "\\cos(" (latexify (second expr)) ")"))
     (if (float? expr) (format "%.3f" expr)
                       (pr-str expr))))


Added prismatic/schema dependency to the project.

--- app/project.clj
+++ app/project.clj
@@ -10,7 +10,8 @@
                  [metosin/potpuri "0.2.2"]
                  [http-kit "2.1.19"]
                  [metosin/compojure-api "0.21.0"]
-                 [metosin/ring-swagger-ui "2.1.5-M2"]]
+                 [metosin/ring-swagger-ui "2.1.5-M2"]
+                 [prismatic/schema "0.4.3"]]
   :main ^:skip-aot clj-web-example.main
   :target-path "target/%s"
   :profiles {:uberjar {:aot :all}})


kill workers when runner thread is killed

--- src/bolth.clj
+++ src/bolth.clj
@@ -97,14 +97,19 @@

 (defn run-gathered-tests [^AbstractQueue tests-to-run pharrallelism]
   (let [results (LinkedBlockingQueue.)
-        finished (into [] (map (fn [_] (promise)) (range pharrallelism)))]
-    (dotimes [worker-id pharrallelism]
-      (run-worker results tests-to-run worker-id finished))
-    (doseq [n finished]
-      (deref n))
-    (doseq [r (iterator-seq (.iterator results))]
-      (print r))
-    (apply merge-with + (map (comp deref deref) finished))))
+        finished (into [] (map (fn [_] (promise)) (range pharrallelism)))
+        workers (map #(run-worker results tests-to-run % finished) (range pharrallelism))]
+    (try
+      (dorun workers)
+      (doseq [n finished]
+        (deref n))
+      (doseq [r (iterator-seq (.iterator results))]
+        (print r))
+      (apply merge-with + (map (comp deref deref) finished))
+      (catch java.lang.ThreadDeath e
+        (doseq [worker workers]
+          (future-cancel worker))
+        (throw e)))))

 (defn gather-tests [ns-re]
   (let [queue (LinkedBlockingQueue.)]


:bug: Fix display of colorpalette

:bug: Fix display of colorpalette

--- frontend/src/uxbox/main/ui/workspace/colorpalette.cljs
+++ frontend/src/uxbox/main/ui/workspace/colorpalette.cljs
@@ -88,12 +88,12 @@
            [:div.btn-palette.create i/close]]]

        [:span.left-arrow {}
-        (if (> (:position @local) 0)
-          {:on-click #(swap! local update :position dec)}
-          {:class :disabled})
+        ;;(if (> (:position @local) 0)
+        ;;  {:on-click #(swap! local update :position dec)}
+        ;;  {:class :disabled})
         ;; FIXME Objects are not valid as a React child (found: :on-click).
-        ;;(when (> offset 0)
-        ;;  {:on-click #(swap! local update :offset (fnil dec 1))})
+        (when (> offset 0)
+          {:on-click #(swap! local update :offset (fnil dec 1))})
         i/arrow-slide]

        [:div.color-palette-content {:ref "container"}
@@ -104,13 +104,13 @@
                (mx/with-key color)))]]

        [:span.right-arrow
-        (if (< (* (+ 1 (:position @local)) 10) (count (:colors selected-coll)))
-          {:on-click #(swap! local update :position inc)}
-          {:class :disabled})
+        ;;(if (< (* (+ 1 (:position @local)) 10) (count (:colors selected-coll)))
+        ;;  {:on-click #(swap! local update :position inc)}
+        ;;  {:class :disabled})
         ;; FIXME Objects are not valid as a React child (found: :on-click).
-        ;;(if (< offset invisible)
-        ;;  {:on-click #(swap! local update :offset (fnil inc 0))}
-        ;;  {})
+        (if (< offset invisible)
+          {:on-click #(swap! local update :offset (fnil inc 0))}
+          {})
         i/arrow-slide]
        [:span.close-palette {:on-click close}
         i/close]])))