Removed extra done-ch layer.

Removed extra done-ch layer.

--- src/cbfg/kvs.cljs
+++ src/cbfg/kvs.cljs
@@ -52,53 +52,45 @@
         [state {:status :not-found :status-info :no-kvs}])
       [state {:status :invalid :status-info :no-kvs-ident}])))

-(defn kvs-do [actx state-ch m done-ch work-fn]
+(defn kvs-do [actx state-ch res-ch work-fn]
   (act kvs-do actx
-       (aput kvs-do state-ch [work-fn done-ch])
-       (when done-ch
-         (aput kvs-do (:res-ch m)
-               (merge m (or (atake kvs-do done-ch)
-                            {:status :error :status-info :closed-ch}))))))
+       (aput kvs-do state-ch [work-fn res-ch])))

-(defn make-scan-fn [scan-kind result-key get-entry]
+(defn make-scan-fn [kc-kind scan-kind result-key get-entry]
   (fn [actx state-ch m]
      (let [{:keys [from to res-ch]} m
-           res-m (dissoc m :status :status-info :partial)
            work-fn (fn [state kvs]
                      (act scan-work actx
-                          (let [kc-clean (:clean kvs)]
-                            (doseq [[k v]
-                                    (subseq (into (sorted-map) (scan-kind kc-clean))
-                                            >= from < to)]
-                              (when-let [entry (get-entry kc-clean k v)]
+                          (let [kc (kc-kind kvs)]
+                            (doseq [[k v] (subseq (into (sorted-map) (scan-kind kc))
+                                                  >= from < to)]
+                              (when-let [entry (get-entry kc k v)]
                                 (when (not (:deleted entry))
-                                  (aput scan-work res-ch
-                                        (merge res-m {:partial :ok
-                                                      result-key key
-                                                      :entry entry})))))
-                            (aput scan-work res-ch
-                                  (merge res-m {:status :ok}))))
+                                  (aput scan-work res-ch (merge m {:partial :ok
+                                                                   result-key key
+                                                                   :entry entry})))))
+                            (aput-close scan-work res-ch (merge m {:status :ok}))))
                      nil)]
-       (kvs-do actx state-ch m nil (kvs-checker (:kvs-ident m) work-fn)))))
+       (kvs-do actx state-ch nil (kvs-checker (:kvs-ident m) work-fn)))))

 (def op-handlers
   {:kvs-open
    (fn [actx state-ch m]
-     (kvs-do actx state-ch m (achan actx)
-                 #(if-let [name (:name m)]
-                    (if-let [kvs (get-in % [:kvss name])]
-                      [% {:status :ok :status-info :reopened
-                          :kvs-ident [name (:uuid kvs)]}]
-                      [(-> %
-                           (update-in [:kvss name] (make-kvs name (:next-uuid %)))
-                           (assoc :next-uuid (inc (:next-uuid %))))
-                       {:status :ok :status-info :created
-                        :kvs-ident [name (:next-uuid %)]}])
-                    [% {:status :invalid :status-info :no-name}])))
+     (kvs-do actx state-ch (:res-ch m)
+             #(if-let [name (:name m)]
+                (if-let [kvs (get-in % [:kvss name])]
+                  [% (merge m {:status :ok :status-info :reopened
+                               :kvs-ident [name (:uuid kvs)]})]
+                  [(-> %
+                       (update-in [:kvss name] (make-kvs name (:next-uuid %)))
+                       (assoc :next-uuid (inc (:next-uuid %))))
+                   (merge m {:status :ok :status-info :created
+                             :kvs-ident [name (:next-uuid %)]})])
+                [% (merge m {:status :invalid :status-info :no-name})])))

    :kvs-remove
    (fn [actx state-ch m]
-     (kvs-do actx state-ch m (achan actx)
+     (kvs-do actx state-ch (:res-ch m)
              (kvs-checker (:kvs-ident m)
                           (fn [state kvs]
                             [(dissoc-in state [:kvss (:name kvs)])
@@ -107,22 +99,20 @@
    :multi-get
    (fn [actx state-ch m]
      (let [keys (:keys m)
-           res-m (dissoc m :status :status-info :partial :keys)
+           res-m (dissoc m :keys)
            res-ch (:res-ch m)
            work-fn (fn [state kvs]
                      (act multi-get actx
-                          (let [kc-clean (:clean kvs)]
+                          (let [kc (:clean kvs)]
                             (doseq [key keys]
-                              (if-let [entry (kc-entry-by-key kc-clean key)]
+                              (if-let [entry (kc-entry-by-key kc key)]
                                 (aput multi-get res-ch
                                       (merge res-m {:partial :ok :key key :entry entry}))
                                 (aput multi-get res-ch
                                       (merge res-m {:partial :not-found :key key}))))
-                            (aput multi-get res-ch
-                                  (merge res-m {:status :ok}))))
+                            (aput-close multi-get res-ch (merge res-m {:status :ok}))))
                      nil)]
-       (kvs-do actx state-ch m nil
-                   (kvs-checker (:kvs-ident m) work-fn))))
+       (kvs-do actx state-ch nil (kvs-checker (:kvs-ident m) work-fn))))

    :multi-change
    (fn [actx state-ch m]
@@ -138,20 +128,19 @@
                        (act multi-change actx
                             (doseq [res ress]
                               (aput multi-change res-ch (merge res-m res)))
-                            (aput multi-change res-ch (merge res-m {:status :ok})))
+                            (aput-close multi-change res-ch (merge res-m {:status :ok})))
                        [(assoc-in state [:kvss (:name kvs)] next-kvs) nil]))]
-       (kvs-do actx state-ch m nil
-               (kvs-checker (:kvs-ident m) work-fn))))
+       (kvs-do actx state-ch nil (kvs-checker (:kvs-ident m) work-fn))))

    :scan-keys
-   (make-scan-fn :keys :key kc-entry-by-key-sq)
+   (make-scan-fn :clean :keys :key kc-entry-by-key-sq)

    :scan-changes
-   (make-scan-fn :changes :sq (fn [kc sq-key entry] entry))
+   (make-scan-fn :clean :changes :sq (fn [kc sq-key entry] entry))

    :sync
    (fn [actx state-ch m]
-     (kvs-do actx state-ch m (achan actx)
+     (kvs-do actx state-ch (:res-ch m)
              (kvs-checker (:kvs-ident m)
                           (fn [state kvs]
                             [(assoc-in state [:kvss (:name kvs)]


Removed on-screen TODO

Removed on-screen TODO

--- src-cljs/kixi/hecuba/main.cljs
+++ src-cljs/kixi/hecuba/main.cljs
@@ -189,7 +189,6 @@
     (render [_]
       (dom/div nil
            (dom/h1 nil (:title data))
-           (dom/p nil "TODO: Done enough, now add the table")
            (om/build table (:table data) {:opts (om/get-state owner :programmes-table-channels)})
            (om/build table (:table data) {:opts (om/get-state owner :projects-table-channels)})
            (om/build table (:table data) {:opts (om/get-state owner :properties-table-channels)})


New test: test-log-request

New test: test-log-request

--- test/emender_jenkins/server_test.clj
+++ test/emender_jenkins/server_test.clj
@@ -13,6 +13,8 @@
 (ns emender-jenkins.server-test
   (:require [clojure.test :refer :all]
             [emender-jenkins.server :refer :all]))
+
+(require '[clojure.tools.logging    :as log])

 ;
 ; Common functions used by tests.
@@ -87,6 +89,12 @@
     (testing "if the emender-jenkins.server/handler definition exists."
         (is (callable? 'emender-jenkins.server/handler))))

+
+(deftest test-log-request-existence
+    "Check that the emender-jenkins.server/log-request definition exists."
+    (testing "if the emender-jenkins.server/log-request definition exists."
+        (is (callable? 'emender-jenkins.server/log-request))))
+
 ;
 ; Function behaviours
 ;
@@ -137,3 +145,14 @@
         (are [x y] (= x y)
             nil (get-api-part-from-uri "/wring-api" "/api"))))

+(deftest test-log-request
+    "Check the function emender-jenkins.server/log-request."
+    (testing "the function emender-jenkins.server/log-request."
+        (with-redefs [log/log* (fn [logger level throwable message] message)]
+        (are [x y] (= x y)
+            "Handling request:  nil nil"                 (log-request {})
+            "Handling request:  http://test nil"         (log-request {:uri "http://test"})
+            "Handling request:  nil 10.20.30.40"         (log-request {:remote-addr "10.20.30.40"})
+            "Handling request:  http://test 10.20.30.40" (log-request {:uri "http://test" :remote-addr "10.20.30.40"})
+            ))))
+


Made helpers for state changes

Made helpers for state changes

--- src/webapp/client/init.cljs
+++ src/webapp/client/init.cljs
@@ -50,105 +50,122 @@
     true
     ))

-(swap! ui-watchers conj {
-                         :type     "path equals"
-                         :path     [:ui :request :from-email :mode]
-                         :value    "validate"
-                         :fn       (fn [app]
-                                     (if (validate-email
-                                         (get-in-app app [:ui :request :from-email :value]))
-                                      (update-app app [:ui :request :from-email :error] "")
-                                      (update-app app [:ui :request :from-email :error] "Invalid email")
-                                      ))
-                         })
-
-(swap! ui-watchers conj {
-                         :type     "value change"
-                         :path     [:ui :request :from-email :value]
-                         :fn      (fn [app] (if (= (get-in-app app [:ui :request :from-email :mode]) "validate")
-                                     (if (validate-email
-                                         (get-in-app app [:ui :request :from-email :value]))
-                                      (update-app app [:ui :request :from-email :error] "")
-                                      (update-app app [:ui :request :from-email :error] "Invalid email")
-                                      )))
-                         })
-
-
-(swap! ui-watchers conj {
-                         :type     "path equals"
-                         :path     [:ui :request :from-full-name :mode]
-                         :value    "validate"
-                         :fn      (fn [app] (if (= (get-in-app app [:ui :request :from-full-name :mode]) "validate")
-                                     (if (validate-full-name
-                                         (get-in-app app [:ui :request :from-full-name :value]))
-                                      (update-app app [:ui :request :from-full-name :error] "")
-                                      (update-app app [:ui :request :from-full-name :error] "Invalid full name")
-                                      )))
-                         })
-
-
-(swap! ui-watchers conj {
-                         :type     "value change"
-                         :path     [:ui :request :from-full-name :value]
-                         :fn      (fn [app] (if (= (get-in-app app [:ui :request :from-full-name :mode]) "validate")
-                                     (if (validate-full-name
-                                         (get-in-app app [:ui :request :from-full-name :value]))
-                                      (update-app app [:ui :request :from-full-name :error] "")
-                                      (update-app app [:ui :request :from-full-name :error] "Invalid full name")
-                                      )))
-                         })
-
-
-(swap! ui-watchers conj {
-                         :type     "path equals"
-                         :path     [:ui :request :to-full-name :mode]
-                         :value    "validate"
-                         :fn      (fn [app] (if (= (get-in-app app [:ui :request :to-full-name :mode]) "validate")
-                                     (if (validate-full-name
-                                         (get-in-app app [:ui :request :to-full-name :value]))
-                                      (update-app app [:ui :request :to-full-name :error] "")
-                                      (update-app app [:ui :request :to-full-name :error] "Invalid full name")
-                                      )))
-                         })
-
-
-(swap! ui-watchers conj {
-                         :type     "value change"
-                         :path     [:ui :request :to-full-name :value]
-                         :fn      (fn [app] (if (= (get-in-app app [:ui :request :to-full-name :mode]) "validate")
-                                     (if (validate-full-name
-                                         (get-in-app app [:ui :request :to-full-name :value]))
-                                      (update-app app [:ui :request :to-full-name :error] "")
-                                      (update-app app [:ui :request :to-full-name :error] "Invalid full name")
-                                      )))
-                         })
-
-
-
-
-
-(swap! ui-watchers conj {
-                         :type     "path equals"
-                         :path     [:ui :request :to-email :mode]
-                         :value    "validate"
-                         :fn       (fn [app]
-                                     (if (validate-email
-                                         (get-in-app app [:ui :request :to-email :value]))
-                                      (update-app app [:ui :request :to-email :error] "")
-                                      (update-app app [:ui :request :to-email :error] "Invalid email")
-                                      ))
-                         })
-
-(swap! ui-watchers conj {
-                         :type     "value change"
-                         :path     [:ui :request :to-email :value]
-                         :fn      (fn [app] (if (= (get-in-app app [:ui :request :to-email :mode]) "validate")
-                                     (if (validate-email
-                                         (get-in-app app [:ui :request :to-email :value]))
-                                      (update-app app [:ui :request :to-email :error] "")
-                                      (update-app app [:ui :request :to-email :error] "Invalid email")
-                                      )))
-                         })
+(defn when-path-equals [path value fn-def]
+  (swap! ui-watchers conj
+         {
+          :type     "path equals"
+          :path     path
+          :value    value
+          :fn       fn-def
+          }))
+
+(defn when-value-changes [path fn-def]
+  (swap! ui-watchers conj
+         {
+          :type     "value change"
+          :path     path
+          :fn       fn-def
+          }))
+
+
+
+(when-path-equals
+ [:ui :request :from-email :mode] "validate"
+
+ (fn [app]
+   (if (validate-email
+        (get-in-app app [:ui :request :from-email :value]))
+     (update-app app [:ui :request :from-email :error] "")
+     (update-app app [:ui :request :from-email :error] "Invalid email")
+     )))
+
+
+
+(when-value-changes
+ [:ui :request :from-email :value]
+
+ (fn [app] (if (= (get-in-app app [:ui :request :from-email :mode]) "validate")
+             (if (validate-email
+                  (get-in-app app [:ui :request :from-email :value]))
+               (update-app app [:ui :request :from-email :error] "")
+               (update-app app [:ui :request :from-email :error] "Invalid email")
+               ))))
+
+
+
+(when-path-equals
+ [:ui :request :from-full-name :mode] "validate"
+
+ (fn [app] (if (= (get-in-app app [:ui :request :from-full-name :mode]) "validate")
+             (if (validate-full-name
+                  (get-in-app app [:ui :request :from-full-name :value]))
+               (update-app app [:ui :request :from-full-name :error] "")
+               (update-app app [:ui :request :from-full-name :error] "Invalid full name")
+               ))))
+
+
+
+(when-value-changes
+ [:ui :request :from-full-name :value]
+
+ (fn [app] (if (= (get-in-app app [:ui :request :from-full-name :mode]) "validate")
+             (if (validate-full-name
+                  (get-in-app app [:ui :request :from-full-name :value]))
+               (update-app app [:ui :request :from-full-name :error] "")
+               (update-app app [:ui :request :from-full-name :error] "Invalid full name")
+               ))))
+
+
+
+(when-path-equals
+ [:ui :request :to-full-name :mode]
+
+ "validate"
+ (fn [app] (if (= (get-in-app app [:ui :request :to-full-name :mode]) "validate")
+             (if (validate-full-name
+                  (get-in-app app [:ui :request :to-full-name :value]))
+               (update-app app [:ui :request :to-full-name :error] "")
+               (update-app app [:ui :request :to-full-name :error] "Invalid full name")
+               ))))
+
+
+(when-value-changes
+ [:ui :request :to-full-name :value]
+
+ (fn [app] (if (= (get-in-app app [:ui :request :to-full-name :mode]) "validate")
+             (if (validate-full-name
+                  (get-in-app app [:ui :request :to-full-name :value]))
+               (update-app app [:ui :request :to-full-name :error] "")
+               (update-app app [:ui :request :to-full-name :error] "Invalid full name")
+               ))))
+
+
+
+
+
+(when-path-equals
+ [:ui :request :to-email :mode]     "validate"
+
+ (fn [app]
+   (if (validate-email
+        (get-in-app app [:ui :request :to-email :value]))
+     (update-app app [:ui :request :to-email :error] "")
+     (update-app app [:ui :request :to-email :error] "Invalid email")
+     )))
+
+
+
+
+
+(when-value-changes
+ [:ui :request :to-email :value]
+
+ (fn [app] (if (= (get-in-app app [:ui :request :to-email :mode]) "validate")
+             (if (validate-email
+                  (get-in-app app [:ui :request :to-email :value]))
+               (update-app app [:ui :request :to-email :error] "")
+               (update-app app [:ui :request :to-email :error] "Invalid email")
+               ))))


inverted almost works, except reward calculations are broken.

--- src/exp/sahdd.clj
+++ src/exp/sahdd.clj
@@ -86,10 +86,12 @@
                 (let [next-min-reward (max min-reward (queue-best-reward queue))]
                   (queues/pq-replace! partial-queue best (make-queue-priority best-reward))
                   (let [{:keys [result-pairs max-reward]} (expand-fn best next-min-reward)]
+;                    (println result-pairs max-reward)
                     (if (= max-reward Double/NEGATIVE_INFINITY)
                         (queues/pq-remove! partial-queue best)
                       (queues/pq-replace! partial-queue best (make-queue-priority max-reward)))
                     (doseq [[ni nr] result-pairs]
+;                      (util/assert-is (not (nil? nr)) "%s" (def badd (vec result-pairs)))
  ;                    (println "NEW" max-reward (class ni) nr (:name ni))
                       (assert (not (= :re-added (queues/pq-add! new-queue ni (make-queue-priority nr))))))
                     (recur)))))))))
@@ -304,6 +306,8 @@

 ; Note: right now, reward in parent-pair is being ignored.

+;; TODO: don't clobber global cache.
+
 ;; TODO: remove expensive tests.
 (defn- add-monotonic! [result-pair-atom [new-result new-reward :as new-result-pair]]
   (assert (every? #(not (= (first %) new-result)) @result-pair-atom))
@@ -318,11 +322,11 @@
       (add-monotonic! result-pairs-atom outcome-pair)
       (mapcat #(notify-upward (first %) outcome-pair) @parent-pairs-atom)))

-(declare make-inverted-node notify-upward-node)
-
-(defn connect-downward-cache [state action [new-parent new-reward :as new-parent-pair]]
+(declare make-inverted-node)
+
+(defn connect-downward-cache [#^HashMap cc state action [new-parent new-reward :as new-parent-pair]]
   (let [context (env/precondition-context action state)
-        ic      (get-cached-search [::INV (env/extract-context state context) (env/action-name action)]
+        ic      (util/cache-with cc [(env/extract-context state context) (env/action-name action)]
                   (InvertedCache (atom []) (atom [])))
         {:keys [result-pairs-atom parent-pairs-atom]} ic
         first-visit?  (empty? @parent-pairs-atom)]
@@ -331,39 +335,41 @@
         (let [state (env/get-logger state context)]
           (if (env/primitive? action)
               (when-let [[ss sr] (and (env/applicable? action state) (env/successor action state))]
-                [(make-inverted-node (vary-meta ss assoc :opt [action]) (+ new-reward sr) nil ic)])
+                [(make-inverted-node cc (vary-meta ss assoc :opt [action]) (+ new-reward sr) nil ic)])
             (for [ref (hierarchy/immediate-refinements action state)]
-              (make-inverted-node state new-reward ref ic))))
-      (map #(notify-upward-node new-parent %) @result-pairs-atom))))
+              (make-inverted-node cc state new-reward ref ic))))
+      (mapcat #(notify-upward new-parent %) @result-pairs-atom))))

 ;; TODO: partial expansions for goals ?
-(deftype InvertedNode   [name state reward remaining-actions parent-cache] :as this
+(deftype InvertedNode   [cache-cache name state reward remaining-actions parent-cache] :as this
   Object
    (equals   [y] (= name (:name y)))
    (hashCode []  (hash name))
   SearchNode
    (extract-goal-state [] nil)
    (expand-node        [min-reward]
-     (if-let [[f & r] remaining-actions]
-         (connect-downward-cache state f [this reward])
-       (notify-upward parent-cache [state reward])))
+     (PartialResult
+      (if-let [[f & r] remaining-actions]
+          (connect-downward-cache cache-cache state f [this reward])
+        (notify-upward parent-cache [state reward]))
+      Double/NEGATIVE_INFINITY ))
   InvertedItem
    (notify-upward [outcome-pair]
      (let [[outcome-state outcome-rew] (generalize-outcome-pair outcome-pair state reward)]
-       [(make-inverted-node outcome-state outcome-rew (next remaining-actions) parent-cache)])))
-
-(defn make-inverted-node [state reward remaining-actions parent-cache]
-  [(InvertedNode [state remaining-actions parent-cache] state reward remaining-actions parent-cache) reward])
-
-(defn make-inverted-root-node [state action]
-  (connect-downward-cache state action
+       [(make-inverted-node cache-cache outcome-state outcome-rew (next remaining-actions) parent-cache)])))
+
+(defn make-inverted-node [cc state reward remaining-actions parent-cache]
+  [(InvertedNode cc [state remaining-actions parent-cache] state reward remaining-actions parent-cache) reward])
+
+(defn make-inverted-roots [state action]
+  (connect-downward-cache (HashMap.) state action
     [(reify InvertedItem
-      (notify-upward [outcome-pair] [(update-in outcome-pair 0 GoalNode)]))
+      (notify-upward [outcome-pair]  [(update-in outcome-pair 0 GoalNode)]))
      0]))

 (defn make-inverted-sa-search [state action]
-  (make-incremental-dijkstra-search [(make-inverted-root-node state action)]))
+  (make-incremental-dijkstra-search (make-inverted-roots state action)))


wrong type hint

wrong type hint

--- src/insn/core.clj
+++ src/insn/core.clj
@@ -9,7 +9,7 @@
            [java.io File FileOutputStream]
            [java.lang.reflect Constructor]))

-(def ^{:private true, :tag 'long}
+(def ^{:private true, :tag 'double}
   jvm-version
   (-> (System/getProperty "java.specification.version")
       Double/valueOf))


Per user stat can't use fixed year

Per user stat can't use fixed year

--- src/arachnida/db_interface.clj
+++ src/arachnida/db_interface.clj
@@ -106,8 +106,7 @@
                                         sum(insertions) as insertions,
                                         sum(deletions) as deletions
                                  from commits
-                                 where date between '2015-01-01' and '2015-12-31'
-                                 and author=?" author-name])))
+                                 where author=?" author-name])))

 (defn read-statistic-for-product
     [product-id from to]


Improve Formatting of CLI Options

Improve Formatting of CLI Options

--- src/lens/core.clj
+++ src/lens/core.clj
@@ -6,18 +6,24 @@
             [lens.util :refer [parse-int]]))

 (def cli-options
-  [["-p" "--port PORT" "Listen on this port" :default 8080 :parse-fn parse-int
+  [["-p" "--port PORT" "Listen on this port"
+    :default 8080
+    :parse-fn parse-int
     :validate [#(< 0 % 0x10000) "Must be a number between 0 and 65536"]]
-   ["-i" "--ip IP" "The IP to bind" :default "0.0.0.0"]
-   ["-t" "--thread NUM" "Number of worker threads" :default 4 :parse-fn parse-int
+   ["-i" "--ip IP" "The IP to bind"
+    :default "0.0.0.0"]
+   ["-t" "--thread NUM" "Number of worker threads"
+    :default 4
+    :parse-fn parse-int
     :validate [#(< 0 % 64) "Must be a number between 0 and 64"]]
    ["-d" "--database-uri URI" "The Datomic database URI to use"
     :validate [#(.startsWith % "datomic")
                "Database URI has to start with datomic."]]
-   [nil "--token-introspection-uri URI" "The OAuth2 token inspection URI to use"]
-   ["-c" "--context-path PATH" (str "An optional context path under which the "
-                                    "workbook service runs. Has to start and end "
-                                    "with a slash.") :default "/"]
+   [nil "--token-introspection-uri URI"
+    "The OAuth2 token inspection URI to use"]
+   ["-c" "--context-path PATH"
+    "An optional context path under which the workbook service runs. Has to start and end with a slash."
+    :default "/"]
    ["-h" "--help" "Show this help"]])

 (defn usage [options-summary]


not reduction implemented

not reduction implemented

--- src/logic/cnf.clj
+++ src/logic/cnf.clj
@@ -102,7 +102,52 @@

     formula))

+(defn reduce-not
+  "Takes a formula in clojure code and reduces all negations in the form, e. g.
+     (not (not expr)) -> expr
+     (not false) -> true"
+  [formula]
+  (if (and (not (boolean? formula)) (not (symbol? formula)))
+    (let [op (first formula)
+          a (second formula)]
+
+      (if (= (name op) "not")
+        ; reduce not
+        (cond
+          ;case boolean
+          (and (not (symbol? a)) (boolean? a))
+
+          (not a)
+
+          ;case another not
+          (and
+            (not (symbol? a))
+            (not (boolean? a))
+            (= (-> a first name) "not"))
+
+          (do
+            (println "Hello" )
+          (reduce-not (second a)))
+
+          :else (remove nil? (list
+	                           op
+	                           (reduce-not a)
+	                           (when (not= (name op) "not")
+	                             (reduce-not (nth formula 2)))
+	                           )))
+
+        ; else
+        (remove nil? (list
+                       op
+                       (reduce-not a)
+                       (when (not= (name op) "not")
+                         (reduce-not (nth formula 2)))
+                       ))
+      ))
+    ; else
+    formula))
+
 (defn transform-cnf
   "Takes a formula in clojure code and produces the cnf of it"
   [formula]
-  (-> formula only-and-or-not not-atoms-only))+  (-> formula only-and-or-not not-atoms-only reduce-not))


WIP: Refactored the code to remove passing x and y

--- totem-destroyer/desktop/src-common/totem_destroyer/core.clj
+++ totem-destroyer/desktop/src-common/totem_destroyer/core.clj
@@ -9,18 +9,21 @@
 (def ^:const world-scale 30) ; pixels per meter

 (defn create-brick-body!
-  [screen x y width height]
-  (let [body (add-body! screen (body-def :dynamic))]
-    (->> (polygon-shape :set-as-box (/ (/ width 2) world-scale) (/ (/ height 2) world-scale)
-                        (vector-2 (/ x world-scale) (/ y world-scale)) 0)
+  [screen width height]
+  (let [body (add-body! screen (body-def :dynamic))
+        brick-w (/ width world-scale)
+        brick-h (/ height world-scale)
+        x (/ (/ width 2) world-scale)
+        y (/ (/ height 2) world-scale)]
+    (->> (polygon-shape :set-as-box (/ brick-w 2) (/ brick-h 2) (vector-2 x y) 0)
          (fixture-def :density 2 :restitution 0.4 :friction 0.5 :shape)
          (body! body :create-fixture))
     body))

 (defn create-brick-entity!
-  [screen brick x y width height]
+  [screen brick width height]
   (assoc brick
-         :body (create-brick-body! screen x y width height)
+         :body (create-brick-body! screen width height)
          :width (/ width world-scale) :height (/ height world-scale)))

 (defn create-idol-body!
@@ -70,13 +73,13 @@
                           :camera (orthographic :set-to-ortho true game-w game-h)
                           :world (box-2d 0 5)
                           :debug-renderer (Box2DDebugRenderer.))
-          brick (texture "1x1.png")
-          brick-1 (doto (create-brick-entity! screen brick 15 15 30 30) (body-position! (/ 275 world-scale) (/ 435 world-scale) 0))
-          brick-2 (doto (create-brick-entity! screen brick 15 15 30 30) (body-position! (/ 365 world-scale) (/ 435 world-scale) 0))
-          brick-3 (doto (create-brick-entity! screen brick 60 15 120 30) (body-position! (/ 275 world-scale) (/ 400 world-scale) 0))
-          brick-4 (doto (create-brick-entity! screen brick 30 15 60 30) (body-position! (/ 305 world-scale) (/ 370 world-scale) 0))
-          brick-5 (doto (create-brick-entity! screen brick 45 15 90 30) (body-position! (/ 275 world-scale) (/ 340 world-scale) 0))
-          brick-6 (doto (create-brick-entity! screen brick 60 30 120 60) (body-position! (/ 275 world-scale) (/ 280 world-scale) 0))
+          brick (texture "1x1-transparent.png")
+          brick-1 (doto (create-brick-entity! screen brick 30 30) (body-position! (/ 275 world-scale) (/ 435 world-scale) 0))
+          brick-2 (doto (create-brick-entity! screen brick 30 30) (body-position! (/ 365 world-scale) (/ 435 world-scale) 0))
+          brick-3 (doto (create-brick-entity! screen brick 120 30) (body-position! (/ 275 world-scale) (/ 395 world-scale) 0))
+          brick-4 (doto (create-brick-entity! screen brick 60 30) (body-position! (/ 305 world-scale) (/ 365 world-scale) 0))
+          brick-5 (doto (create-brick-entity! screen brick 90 30) (body-position! (/ 275 world-scale) (/ 335 world-scale) 0))
+          brick-6 (doto (create-brick-entity! screen brick 120 60) (body-position! (/ 275 world-scale) (/ 280 world-scale) 0))
           idol (doto {:body (create-idol-body! screen 320 242)})
           floor (doto {:body (create-floor-body! screen 320 470 640 20)})]
       (width! screen game-w)


adding populate

adding populate

--- test/celestial/fixtures.clj
+++ test/celestial/fixtures.clj
@@ -43,9 +43,10 @@
    ~@body
     ))

-(celestial.persistency/add-type redis-type)
+(defn populate []
+ (celestial.persistency/add-type redis-type)
+ (doseq [i (range 100)] (celestial.persistency/add-system redis-prox-spec)))

-(doseq [i (range 100)] (celestial.persistency/add-system redis-prox-spec))

 (def host (.getHostName (java.net.InetAddress/getLocalHost)))


Fix tests vv date-times

Fix tests vv date-times

--- test/datemo/routes_test.clj
+++ test/datemo/routes_test.clj
@@ -1,5 +1,7 @@
 (ns datemo.routes-test
   (:require [cheshire.core :as json :refer [parse-string]]
+            [clj-time.core :as t]
+            [clj-time.coerce :as c]
             [datomic.api :as d])
   (:use clojure.test
         ring.mock.request
@@ -55,7 +57,8 @@
                            :id (str id)
                            :title "A title"
                            :tags ["tag1"]
-                           :created-at (str tx-inst)
+                           :created-at (c/to-string tx-inst)
+                           :updated-at (c/to-string tx-inst)
                            :doctype "note"
                            :html "
note1
"}]}
              (parse response)))))
@@ -115,8 +118,8 @@
                           :title "A title"
                           :tags ["tag1"]
                           :doctype "note"
-                          :created-at (str tx-inst)
-                          :updated-at (str tx-inst)
+                          :created-at (c/to-string tx-inst)
+                          :updated-at (c/to-string tx-inst)
                           :html "
test
"}}
              (-> (parse response)))))))

@@ -138,7 +141,9 @@
         (is (= "A new title" (get-in body [:_embedded :title])))
         (is (= "essay" (get-in body [:_embedded :doctype])))
         (is (= ["tag2"] (get-in body [:_embedded :tags])))
-        (is (= (str tx-inst) (get-in body [:_embedded :created-at])))
+        (is (t/equal?
+              (c/from-date tx-inst)
+              (c/from-string (get-in body [:_embedded :created-at]))))
         (is (contains? (get-in body [:_embedded]) :updated-at))
         (is (not= nil (get-in body [:_embedded :updated-at])))
         (is (= "
replaced
" (get-in body [:_embedded :html]))))))


separate index names for vertexes and edges

--- src/ophion/db.clj
+++ src/ophion/db.clj
@@ -39,7 +39,7 @@
     (let [index-name (string/join "-" (concat (keys index) ["index"]))
           manage (.openManagement graph)]
       (janus-apply-index manage (.buildIndex manage (str index-name "-vertex") Vertex) index)
-      (janus-apply-index manage (.buildIndex manage index-name "-edge" Edge) index)
+      (janus-apply-index manage (.buildIndex manage (str index-name "-edge") Edge) index)
       (.commit manage))
     (catch Exception e
       (.printStackTrace e))))


missing file

missing file

--- src/puny/core.clj
+++ src/puny/core.clj
@@ -147,8 +147,5 @@

        (bang-fns ~name*)

-       (write-fns ~name* ~opts)
+       (write-fns ~name* ~opts))))

-
-       )))
-


CMR-191: Added test for searching for entry-id

--- test/cmr/system_int_test/search/collection_identifier_search_test.clj
+++ test/cmr/system_int_test/search/collection_identifier_search_test.clj
@@ -122,6 +122,33 @@
            [c1-p1 c1-p2] "v1" {:ignore-case true}
            [] "v1" {:ignore-case false}))

+    (testing "entry id"
+      (are [items ids options]
+           (let [params (merge {:entry-id ids}
+                               (when options
+                                 {"options[entry-id]" options}))]
+             (d/refs-match? items (search/find-refs :collection params)))
+
+           [c1-p1 c1-p2] "S1_V1" {}
+           [] "S44_V44" {}
+           ;; Multiple values
+           [c1-p1 c1-p2 c2-p1 c2-p2] ["S1_V1" "S2_V2"] {}
+           [c1-p1 c1-p2] ["S1_V1" "S44_V44"] {}
+           [c1-p1 c1-p2 c2-p1 c2-p2] ["S1_V1" "S2_V2"] {:and false}
+           [] ["S1_V1" "S2_V2"] {:and true}
+
+           ;; Wildcards
+           all-colls "S*_V*" {:pattern true}
+           [] "S*_V*" {:pattern false}
+           [] "S*_V*" {}
+           [c1-p1 c1-p2] "*1" {:pattern true}
+           [c1-p1 c1-p2] "S1_?1" {:pattern true}
+           [] "*Q*" {:pattern true}
+
+           ;; Ignore case
+           [c1-p1 c1-p2] "S1_v1" {:ignore-case true}
+           [] "S1_v1" {:ignore-case false}))
+
     (testing "Entry title"
       (are [items v options]
            (let [params (merge {:entry-title v}


add a way to get at the state to make debugging easier

--- frontend/core.cljs
+++ frontend/core.cljs
@@ -175,6 +175,8 @@

 (defn ^:export setup! []
   (let [state (app-state)]
+    ;; globally define the state so that we can get to it for debugging
+    (def debug-state state)
     (main state (sel1 :body))
     (dispatch-to-current-location!)
     (handle-browser-resize state)


:nail_care:

--- workspaces/src/com/wsscode/pathom/workspaces/connect/union_query.cljs
+++ workspaces/src/com/wsscode/pathom/workspaces/connect/union_query.cljs
@@ -50,7 +50,7 @@

 (defresolver `items
   {::pc/output [{::items {:friend/id  [:friend/id :friend/name]
-                          :place/id   [:place/id :place/title :place/location]
+                          :place/id   [:place/id :place/title]
                           :address/id [:address/id :address/street :address/number]}}]}
   (fn [_ _]
     {::items [{:friend/id 1 :friend/name "Hulk"}


update keypin.di/partial docstring for completeness

--- src/keypin/di.clj
+++ src/keypin/di.clj
@@ -14,7 +14,7 @@

 (defmacro partial
-  "Same as clojure.core/partial, except it does not"
+  "Same as clojure.core/partial, except it does not lose associativity with the var."
   [f & args]
   `(fn [& args#]
      (apply ~f ~@args args#)))


allow for AND condition in :include/:exclude.

--- src/leiningen/ancient/artifact/check.clj
+++ src/leiningen/ancient/artifact/check.clj
@@ -82,13 +82,22 @@
         artifact (f options (conj path k) data)]
     (update-in artifact [:keys] conj k)))

+(defn- match-it
+  [f sq keys]
+  (f
+    (fn [item]
+      (if (sequential? item)
+        (every? keys (set item))
+        (contains? keys item)))
+    sq))
+
 (defn- include-artifact?
   [{:keys [include exclude]} {:keys [artifact keys]}]
   (when artifact
     (let [k? (set keys)]
       (and (not (k? ::never))
-           (or (empty? include) (some k? include))
-           (or (empty? exclude) (not-any? k? exclude))))))
+           (or (empty? include) (match-it some include k?))
+           (or (empty? exclude) (match-it not-any? exclude k?))))))

 (defn collect-artifacts
   "Collect all artifacts in the given map, based on:


-(defn evaluate): not used or tested

-(defn evaluate): not used or tested

--- src/babel/lexiconfn.cljc
+++ src/babel/lexiconfn.cljc
@@ -781,14 +781,6 @@

       ))

-;; TODO: dangerous to (eval) code that we don't directly control:
-;; replace with a DSL that accomplishes the same thing without
-;; security problems.
-(defn evaluate [lexicon]
-  (into {}
-        (for [[k v] lexicon]
-          [k (eval v)])))
-
 (defn insert-lexeme [canonical lexemes language]
   (log/debug (str "insert-lexeme: canonical=" canonical ", language=" language))
   (exec-raw [(str "INSERT INTO lexeme
@@ -823,7 +815,6 @@
 (defn write-lexicon [language lexicon]
   (transaction
    (truncate-lexicon language)
-
    (let [canonicals (sort (keys lexicon))]
      (loop [remain canonicals
             result 0]


oops had the wrong message in here

oops had the wrong message in here

--- src/block_chain/http.clj
+++ src/block_chain/http.clj
@@ -141,7 +141,7 @@
                                                                             :to-address to_address
                                                                             :amount amount
                                                                             :fee fee}} {})]
-                 (if (= "transaction-accepted" (:message resp))
+                 (if (= "unsigned_transaction" (:message resp))
                    (ok resp)
                    (bad-request resp))))


launching new schedeuling component

launching new schedeuling component

--- src/celestial/launch.clj
+++ src/celestial/launch.clj
@@ -27,7 +27,9 @@
     [hypervisors.networking :refer [initialize-networking]]
     [es.core :as es]
     [celestial.jobs :as jobs]
-    [celestial.api.core :as api]))
+    [celestial.api.core :as api]
+    [celestial.schedule :as sch]
+    ))

 (import-logging)

@@ -43,7 +45,8 @@
     (set-level! (log* :level))))

 (defn build-components []
-  {:es (es/instance) :jobs (jobs/instance) :jetty (api/instance) :persistency (p/instance)})
+  {:es (es/instance) :jobs (jobs/instance) :jetty (api/instance)
+   :persistency (p/instance) :schedule (sch/instance) })

 (defn clean-up
   "Clean/release resources, used also as a shutdown hook"


change `cljs.closure/watch` so it doesn't fail from build exceptions

--- src/clj/cljs/closure.clj
+++ src/clj/cljs/closure.clj
@@ -1155,7 +1155,10 @@
                 (when (seq (.pollEvents key))
                   (println "Change detected, recompiling...")
                   (flush)
-                  (buildf))
+                  (try
+                    (buildf)
+                    (catch Exception e
+                      (.printStackTrace e))))
                 (recur key)))))
         (catch Exception e
           (.printStackTrace e)


Fix transposition of characters.

Fix transposition of characters.

--- src/clj/cljs/closure.clj
+++ src/clj/cljs/closure.clj
@@ -373,7 +373,7 @@
                                                            (string/split-lines (slurp out-file)))]
                                               (javascript-file (to-url out-file)
                                                                (:provides ns-info)
-                                                               (:requries ns-info)))
+                                                               (:requires ns-info)))
                          :else (-compile (io/resource file)
                                          (merge opts {:output-file js-file})))]
     (do (swap! compiled-cljs (fn [old] (assoc old ns javascript)))


Put a note in the alert email that the changeset URL may be for the wrong Nightly

Issue #19

--- src/clj/medusa/alert.clj
+++ src/clj/medusa/alert.clj
@@ -33,7 +33,12 @@
             changeset-url (changesets/find-build-changeset buildid "mozilla-central")]
         (log/info "Changeset URL" changeset-url)
         (send-email (str "Alert for " metric_name " (" detector_name ") on " date)
-                    (str "Alert details: " alert-url "\n\n" "Changeset for " buildid ": " changeset-url)
+                    (str "Alert details: " alert-url
+                         "\n\n"
+                         "This changeset is for the first Nightly on the day of the detected regression, "
+                         "which may not be the Nightly that had the regression in it."
+                         "\n"
+                         "Changeset for " buildid ": " changeset-url)
                     (concat subscribers foreign_subscribers ["dev-telemetry-alerts@lists.mozilla.org"])))
       (catch Throwable e ; could not find revisions for the given build date
         (log/info e "Retrieving changeset failed")


Assume static fields are typed when invoking protocol fns on them. Better check for reflection of setting fields

--- src/cljs/go/compiler.clj
+++ src/cljs/go/compiler.clj
@@ -759,7 +759,8 @@
         variadic-invoke (and (:variadic info)
                              (> arity (:max-fixed-arity info)))
         coerce? (and (or (:field info) (:binding-form? info))
-                     (not (or fn? (= 'function (:tag info)))))]
+                     (not (or fn? (= 'function (:tag info)))))
+        static-field-receiver? (-> expr :args first :target :info :type)]
     (emit-wrap env
       (cond
        opt-not?
@@ -767,7 +768,10 @@

        protocol ;; needs to take the imported name of protocols into account, very lenient now, assumes any type implements it.
        (let [pimpl (str (-> info :name name munge go-public) "_Arity" (count args))]
-         (emits (if tag (first args) (str (emit-str (first args)) ".(" (go-type-fqn protocol) ")"))
+         (emits (if (and (= (go-type tag) "interface{}")
+                         (not static-field-receiver?))
+                  (str (emit-str (first args)) ".(" (go-type-fqn protocol) ")")
+                  (first args) )
                 "." pimpl "(" (comma-sep (rest args)) ")"))

        keyword?
@@ -818,7 +822,7 @@
           (emitln "var " return " = " val))
         (let [val (or return val)
               static? (-> target :target :info :type)]
-          (if-let [reflective-field (and (contains? #{nil 'any} (:tag target))
+          (if-let [reflective-field (and (= "interface{}" (-> target :target :tag go-type))
                                          (not static?)
                                          (:field target))]
             (do


[neko.log] Concatenate strings manually

[neko.log] Concatenate strings manually

--- src/clojure/neko/log.clj
+++ src/clojure/neko/log.clj
@@ -29,10 +29,10 @@
         {:keys [exception tag]} (if (odd? (count kwargs))
                                   (butlast kwargs)
                                   kwargs)
-        my-ns (str *ns*)]
+        tag (or tag (str *ns*))]
     (if exception
-      `(. Log ~logfn ~(or tag my-ns) (pr-str ~@strings) ~exception)
-      `(. Log ~logfn ~(or tag my-ns) (pr-str ~@strings)))))
+      `(. Log ~logfn ~tag (apply str (interpose " " [~@strings])) ~exception)
+      `(. Log ~logfn ~tag (apply str (interpose " " [~@strings]))))))

 (defmacro e
   "Log an ERROR message, applying pr-str to all the arguments and taking


doc change

doc change

--- src/tabby/net.clj
+++ src/tabby/net.clj
@@ -218,7 +218,9 @@
                     :rx-stream (s/stream rx-buffer-size)})
     s))

-(defn stop-server [server]
+(defn stop-server
+  "Stops the server listening socket and rx stream"
+  [server]
   (doall
    (utils/mapf (:peer-sockets server) s/close!))
   (when-let [^java.io.Closeable s (:server-socket server)]


tests

tests

--- test/cljs/triboard/test_runner.cljs
+++ test/cljs/triboard/test_runner.cljs
@@ -1,6 +1,6 @@
 (ns ^:figwheel-always triboard.test-runner
   (:require
-    [cljs.test]
+    [cljs.test :refer [run-tests]]
     ))

-(cljs.test/run-all-tests #"triboard.*test")
+(run-tests 'triboard.core-test)


fixed a small issue

fixed a small issue

--- test/foreclojure/test/solutions.clj
+++ test/foreclojure/test/solutions.clj
@@ -19,8 +19,7 @@
     (fact "about get-solution: hide solutions = true"
       (get-solution :public uid pid) => falsey
       (provided
-        (fetch-one :solutions :where {:user uid :problem pid}) => {:code code}
-        (fetch-one :users :where {:_id uid} :only [:hide-solutions]) => {:hide-solutions true}))
+       (fetch-one :users :where {:_id uid} :only [:hide-solutions]) => {:hide-solutions true}))
     (fact "about get-solution: hide solutions = true"
       (get-solution :public uid pid) => code
       (provided


0.2.7

--- src/kiln/core.clj
+++ src/kiln/core.clj
@@ -12,12 +12,7 @@

 (def config (atom nil))

-(def all-article (atom
-  (let [data-clj (str (:input @config) "/.data.edn")]
-    (if (.isFile (clojure.java.io/file data-clj))
-      (clojure.edn/read-string (slurp data-clj))
-      {}))
-))
+(def all-article (atom nil))

 (defn- load-template
   "加载模板文件"
@@ -185,6 +180,11 @@
 (defn- exec
   []
   (println "exec")
+  (reset! all-article
+          (let [data-clj (str (:input @config) "/.data.edn")]
+            (if (.isFile (clojure.java.io/file data-clj))
+              (clojure.edn/read-string (slurp data-clj))
+              {})))
   (.mkdirs (java.io.File. (str (:output @config) "/article/")))
   (.mkdirs (java.io.File. (str (:output @config) "/tag/")))
   (when (contains? @config :template)
@@ -205,8 +205,13 @@
 (defn -main
   "I don't do a whole lot ... yet."
   [& args]
-  (reset! config (clojure.edn/read-string (slurp (nth args 0 "_config.edn"))) )
-  (cond
-    (not (coll? @config)) (println "error config file")
-    (not (contains? @config :output)) (println "not found :output")
-    :else (exec )))
+  (let [config-default {:input "./_writer/"
+                        :output "./html/"
+                        :blog-name "kiln"
+                        :blog-url "http://hzq.num.run"
+                        :blog-description "我的博客"}
+        config-edn (merge config-default
+                          (clojure.edn/read-string (slurp (nth args 0 "_config.edn"))))]
+    (println :config config-edn)
+    (reset! config config-edn)
+    (exec )))


get rid of unused channels

get rid of unused channels

--- src-cljs/frontend/core.cljs
+++ src-cljs/frontend/core.cljs
@@ -73,20 +73,6 @@
                                     :code (.-which event)
                                     :depressed? (= direction :down)}])))))

-;; Overcome some of the browser limitations around DnD
-(def mouse-move-ch
-  (chan (sliding-buffer 1)))
-
-(def mouse-down-ch
-  (chan (sliding-buffer 1)))
-
-(def mouse-up-ch
-  (chan (sliding-buffer 1)))
-
-(js/window.addEventListener "mousedown" #(put! mouse-down-ch %))
-(js/window.addEventListener "mouseup"   #(put! mouse-up-ch   %))
-(js/window.addEventListener "mousemove" #(put! mouse-move-ch %))
-
 (def controls-ch
   (chan))

@@ -136,13 +122,7 @@
                              :controls-mult (async/mult controls-ch)
                              :api-mult      (async/mult api-ch)
                              :errors-mult   (async/mult errors-ch)
-                             :nav-mult      (async/mult navigation-ch)
-                             :mouse-move    {:ch mouse-move-ch
-                                             :mult (async/mult mouse-move-ch)}
-                             :mouse-down    {:ch mouse-down-ch
-                                             :mult (async/mult mouse-down-ch)}
-                             :mouse-up      {:ch mouse-up-ch
-                                             :mult (async/mult mouse-up-ch)}})
+                             :nav-mult      (async/mult navigation-ch)})
             (browser-settings/restore-browser-settings cust)))))

 (defn controls-handler


+"to"

+"to"

--- src/babel/english/lexicon.cljc
+++ src/babel/english/lexicon.cljc
@@ -1937,6 +1937,10 @@
               :present {:3sing "throws out"}
               :participle "throwing out"}}

+   "to" {:synsem {:cat :prep
+                  :subcat {:1 {:cat :noun}}
+                  :sem {:pred :to}}}
+
    "transfer" {:english {:past "transferred"
                          :participle "transferring"}
                :synsem {:cat :verb


added pret stem durm for dormirse

added pret stem durm for dormirse

--- src/babel/espanol/lexicon.cljc
+++ src/babel/espanol/lexicon.cljc
@@ -271,7 +271,8 @@
    "dormirse"
    (let [subject-semantics (atom {:human true})
          subject-agr (atom :top)]
-     {:espanol {:boot-stem "duerm"}
+     {:espanol {:boot-stem "duerm"
+                :pret-stem "durm"}
       :synsem {:cat :verb
                :sem {:pred :fall-asleep
                      :reflexive true


added salire get on

added salire get on

--- src/babel/espanol/lexicon.cljc
+++ src/babel/espanol/lexicon.cljc
@@ -759,6 +759,10 @@
                (unify shared-part-of-querer
                       {:synsem {:sem {:pred :love}}})])

+   "salir" {:espanol  {:present {:1sing "salgo"}}
+            :synsem {:cat :verb
+                      :sem {:pred :go-out}}}
+
    "se"
    [;; 3rd singular or plural: 'él,ellas,..etc'
     {:synsem {:cat :noun


added verbs from

added verbs from

added verbs from http://www.sipuebla.com/verbos/100verbs.htm

--- src/babel/espanol/lexicon.cljc
+++ src/babel/espanol/lexicon.cljc
@@ -102,6 +102,8 @@
    "añadir" {:synsem {:cat :verb
                         :sem {:pred :add}}}

+   "apagar"
+
    "apoyar" {:synsem {:cat :verb
                       :sem {:pred :support}}}

@@ -137,6 +139,11 @@

    "beber" {:synsem {:cat :verb
                      :sem {:pred :drink}}}
+
+   buscar
+   caber
+   caerse
+

    "cambiar" {:synsem {:cat :verb
                        :sem {:pred :change}}}
@@ -156,6 +163,13 @@
                             :reflexive true
                             :sem subject-semantics}}}})

+
+   caminar
+   cancelar
+   cantar
+   casarse
+
+
    "cenar" {:synsem {:cat :verb
                        :sem {:pred :have-dinner}}}

@@ -195,6 +209,9 @@
              :synsem {:cat :verb
                       :sem {:pred :confess}}}

+   conducir
+   conocer
+
    "consentir" {:espanol {:boot-stem "consient"}
                 :synsem {:cat :verb
                          :sem {:pred :consent}}}
@@ -238,6 +255,8 @@
    "creer" {:synsem {:cat :verb
                           :sem {:pred :believe}}}

+
+   dañar
    "dar" {:espanol  {:present {:1sing "doy"
                                :2plur "dais"}
                      :preterito {:1sing "di"
@@ -276,11 +295,18 @@
    "dejar" {:synsem {:cat :verb
                      :sem {:pred :leave-behind}}}

+
+   deletrear
+
    "desarrollar" {:synsem {:cat :verb
                            :sem {:pred :develop}}}

    "desear" {:synsem {:cat :verb
                       :sem {:pred :desire}}}
+
+   despertarse
+   dibujar
+
    "divertirse"
    (let [subject-semantics (atom {:human true})
          subject-agr (atom :top)]
@@ -385,6 +411,9 @@
    "encender" {:espanol {:boot-stem "enciend"}
              :synsem {:cat :verb
                       :sem {:pred :light}}}
+
+   encontrar
+
    "enojarse"
    (let [subject-semantics (atom {:human true})
          subject-agr (atom :top)]
@@ -412,9 +441,13 @@
    "entrar" {:synsem {:cat :verb
                       :sem {:pred :enter}}}

+   enviar
+
    "escapar" {:synsem {:cat :verb
                        :sem {:pred :escape}}}

+   escribir
+
    "escuchar" {:synsem {:cat :verb
                         :sem {:pred :listen-to}}}

@@ -432,6 +465,8 @@
    "existir" {:synsem {:cat :verb
                        :sem {:pred :exist}}}

+   explicar
+
    "expresar" {:synsem {:cat :verb
                         :sem {:pred :express}}}

@@ -439,12 +474,16 @@
 ;   "faltar" {:synsem {:cat :verb
 ;                      :sem {:pred :to-be-missing}}}

+   firmar
+
    "formar" {:synsem {:cat :verb
                       :sem {:pred :form}}}

    "fregar" {:espanol {:boot-stem "frieg"}
              :synsem {:cat :verb
                       :sem {:pred :scrub}}}
+
+   fumar

    "funcionar" {:synsem {:cat :verb
                          :sem {:subj {:human false}
@@ -462,6 +501,8 @@
    ;; TODO: handle syntax/semantics mismatch between Italian/Espanol and English.
                                         ;                     "gustar" {:synsem {:cat :verb
                                         ;                                         :sem {:pred :??}}}
+
+   gastar

    "hablar" [{:synsem {:cat :verb
                        :sem {:pred :speak
@@ -488,9 +529,13 @@
       (unify common
              {:synsem {:sem {:pred :make}}})])

+   herir
+
    "hervir" {:espanol {:boot-stem "hierv"}
              :synsem {:cat :verb
                       :sem {:pred :boil}}}
+
+   intentar

    "ir" {:espanol {:futuro-stem "ir"
                    :present {:1sing "voy"
@@ -543,6 +588,9 @@
               :sem {:human true
                     :pred :Juan-and-i}
               :subcat '()}}]
+
+   jugar
+
    "la"
    (unify determiner
           {:synsem {:cat :det
@@ -563,6 +611,9 @@
                             :pronoun true
                             :reflexive true
                             :sem subject-semantics}}}})
+
+   leer
+
    "levantarse"
    (let [subject-semantics (atom {:human true})
          subject-agr (atom :top)]
@@ -577,6 +628,9 @@
                             :pronoun true
                             :reflexive true
                             :sem subject-semantics}}}})
+
+   limpiar
+
    "llamarse"
    (let [subject-semantics (atom :top)
          called-semantics (atom :top)
@@ -609,6 +663,8 @@
    "llegar" {:synsem {:cat :verb
                       :sem {:pred :arrive}}}

+   llenar
+
    "llevar" (let [shared-part-of-llevar
                   {:synsem {:cat :verb}}]
               [(unify shared-part-of-llevar
@@ -627,6 +683,9 @@
    "mentir" {:espanol {:boot-stem "mient"}
              :synsem {:cat :verb
                       :sem {:pred :lie}}}
+
+   mirar
+
    "mujer"
    (unify agreement-noun
           common-noun
@@ -641,6 +700,9 @@
             :synsem {:cat :verb
                       :sem {:pred :be-born}}}

+
+   nadar
+   necesitar

    "negar" {:espanol {:boot-stem "nieg"}
                 :synsem {:cat :verb
@@ -679,6 +741,16 @@
              :subcat '()}}

    ;; 2nd person plural informal 'vosotros/as' (ES-only)
+
+   oir
+   olvidar
+   organizar
+   pagar
+   parar
+   pedir
+   peinarse
+
+
    "os"
    {:synsem {:cat cat-of-pronoun
              :pronoun true
@@ -733,6 +805,11 @@
                      :sem {:subj {:animate true}
                            :pred :put}}}

+   ponerse de pie
+   preguntar
+   preocuparse
+   prestar
+
    "quedarse" (let [subject-semantics (atom {:animate true})
                     subject-agr (atom :top)]
                 {:synsem {:cat :verb
@@ -747,6 +824,8 @@
                                        :reflexive true
                                        :sem subject-semantics}}}})

+   quejarse
+
    "querer" (let [shared-part-of-querer
                   {:synsem {:cat :verb}
                    :espanol {:boot-stem "quier"
@@ -757,6 +836,13 @@
                (unify shared-part-of-querer
                       {:synsem {:sem {:pred :love}}})])

+
+   reparar
+   responder
+   romper
+
+   saber
+
    "salir" {:espanol  {:present {:1sing "salgo"}}
             :synsem {:cat :verb
                       :sem {:pred :go-out}}}
@@ -779,6 +865,11 @@
                     :number :plur}
               :subcat '()}}]

+
+   sentarse
+
+  sentir
+
    "te" {:synsem {:cat :noun
                   :pronoun true
                   :reflexive true
@@ -816,10 +907,22 @@
                      :sem {:subj {:animate true}
                            :pred :have}}}

+
+   terminar
+
+
    "tirar" [{:synsem {:cat :verb
                       :sem {:pred :throw-out}}}
             {:synsem {:cat :verb
                       :sem {:pred :throw}}}]
+
+   tocar
+   tomar
+   toser
+   trabajar
+   traducir
+   traer
+

    "tú" {:synsem {:cat :noun
                   :pronoun true
@@ -829,6 +932,9 @@
                   :sem {:human true
                         :pred :tu}
                   :subcat '()}}
+
+   usar
+
    "ustedes"
    {:synsem {:cat cat-of-pronoun
              :pronoun true
@@ -839,6 +945,8 @@
                    :pred :voi}
              :subcat '()}}

+   vender
+
    "venir" {:espanol {:futuro-stem "vendr"
                       :present {:1sing "vengo"
                                 :2sing "vienes"
@@ -855,6 +963,10 @@
                                  :3sing "vio"}}
           :synsem {:cat :verb
                    :sem {:pred :see}}}
+
+   viajar
+   vivir
+   volar

    "vosotras"
    {:synsem {:cat cat-of-pronoun


Destructure server opts

Destructure server opts

--- src/braid/core/server/core.clj
+++ src/braid/core/server/core.clj
@@ -18,12 +18,11 @@
   [server port]
   (run-server server {:port port :legacy-return-value? false}))

-(defn start-servers! [opts]
-  (let [wrap (fn [handler] (wrap-universal-middleware handler (opts :middleware)))
-        desktop-port (:port opts)
+(defn start-servers! [{:keys [middleware port]}]
+  (let [wrap (fn [handler] (wrap-universal-middleware handler middleware))
         desktop-server (do
-                         (timbre/debugf "starting desktop server on port %d" desktop-port)
-                         (start-server! (wrap #'desktop-client-app) desktop-port))
+                         (timbre/debugf "starting desktop server on port %d" port)
+                         (start-server! (wrap #'desktop-client-app) port))
         desktop-port (server-port desktop-server)]
     (timbre/debugf "Started desktop server on port %d" desktop-port)
     (let [mobile-port (inc desktop-port)


Factor out right-header-view

Factor out right-header-view

--- src/braid/ui/views/header.cljs
+++ src/braid/ui/views/header.cljs
@@ -86,16 +86,18 @@
        [recent-page-button-view]
        [search-bar-view]])))

+(defn right-header-view []
+  [:div.right
+   [:div.bar
+    [current-user-button-view]
+    [:div.more]]
+   [:div.options
+    [subscriptions-link-view]
+    [invite-link-view]
+    [edit-profile-link-view]
+    [settings-link-view]]])
+
 (defn header-view []
   [:div.header
    [left-header-view]
-
-   [:div.right
-    [:div.bar
-     [current-user-button-view]
-     [:div.more]]
-    [:div.options
-     [subscriptions-link-view]
-     [invite-link-view]
-     [edit-profile-link-view]
-     [settings-link-view]]]])
+   [right-header-view]])


Change access rule pattern matching to always match against the URI, even when path-info is non-nil.

--- src/buddy/auth/accessrules.clj
+++ src/buddy/auth/accessrules.clj
@@ -190,8 +190,9 @@
   The clout library (https://github.com/weavejester/clout)
   for matching the `:uri`.

-  It also has support for more advanced matching using
-  plain regular expressions:
+  It also has support for more advanced matching using plain
+  regular expressions, which are matched against the full
+  request uri:

       [{:pattern #\"^/foo$\"
         :handler user-access}
@@ -225,8 +226,7 @@
                   (:pattern accessrule)
                   (fn [request]
                     (let [pattern (:pattern accessrule)
-                          uri (or (:path-info request)
-                                  (:uri request))]
+                          uri (:uri request)]
                       (when (and (matches-request-method request request-method)
                                  (seq (re-matches pattern uri)))
                         {})))


Stub out a site scraper component

Stub out a site scraper component

--- src/clj/comic_reader/sites.clj
+++ src/clj/comic_reader/sites.clj
@@ -4,9 +4,12 @@
             [comic-reader.sites.util :as util]
             [comic-reader.scrape :as scrape]
             [comic-reader.util :refer [safe-read-string]]
+            [com.stuartsierra.component :as component]
             [clojure.java.io :as io]
             [clojure.string :as s]))

+;; TODO: Remove this dynamic var.  Pass the options through all of the
+;; function calls explicitly.
 (def ^:dynamic options
   {:root-url                     nil
    :manga-list-format            nil
@@ -286,10 +289,14 @@

 (def sites (dissoc (get-sites) "test-site"))

-
-;;; maybe use component
-
-;; more to the point, just pass in the data.  potentially have
-;; sublevel protocols and structs for each slice of
-;; functionality. Then it is just more explicit, and avoids the
-;; dynamic binding issues.
+(defrecord SiteScraper [sites]
+  component/Lifecycle
+
+  (start [component]
+    (let [sites (dissoc (get-sites) "test-site")]
+      (assoc component :sites sites)))
+
+  (stop [component]))
+
+(defn new-site-scraper []
+  (map->SiteScraper {:sites nil}))


Removed import.

Removed import.

--- src/clj/forma/matrix/jblas.clj
+++ src/clj/forma/matrix/jblas.clj
@@ -1,7 +1,5 @@
 (ns forma.matrix.jblas
   (:import [org.jblas FloatMatrix]))
-
-(import '[org.jblas FloatMatrix])

 (defn feature-vec [n]
   (FloatMatrix.


add :msg to several agendas that are silent about effects when scored

--- src/clj/game/cards-agendas.clj
+++ src/clj/game/cards-agendas.clj
@@ -75,7 +75,8 @@
     :msg (msg "trash " (:title target)) :effect (effect (trash target))}

    "Chronos Project"
-   {:effect (effect (move-zone :runner :discard :rfg))}
+   {:msg "remove all cards in the Runner's Heap from the game"
+    :effect (effect (move-zone :runner :discard :rfg))}

    "Clone Retirement"
    {:msg "remove 1 bad publicity" :effect (effect (lose :bad-publicity 1))
@@ -149,7 +150,7 @@
     :abilities [{:cost [:click 1] :counter-cost 1 :msg "draw 5 cards" :effect (effect (draw 5))}]}

    "Explode-a-palooza"
-   {:access {:optional {:prompt "Gain 5 [Credits] with Explode-a-Palooza ability?"
+   {:access {:optional {:prompt "Gain 5 [Credits] with Explode-a-palooza ability?"
                        :yes-ability {:msg "gain 5 [Credits]"
                                      :effect (effect (gain :corp :credit 5))}}}}

@@ -182,7 +183,6 @@

    "Global Food Initiative"
    {:agendapoints-runner (req (do 2))}
-

    "Glenn Station"
    {:abilities [{:label "Host a card from HQ on Glenn Station" :cost [:click 1]
@@ -224,7 +224,8 @@
                  :effect (effect (gain :credit (:credit runner)))}]}

    "Hostile Takeover"
-   {:effect (effect (gain :credit 7 :bad-publicity 1))}
+   {:msg "gain 7 [Credits] and take 1 bad publicity"
+    :effect (effect (gain :credit 7 :bad-publicity 1))}

    "Hollywood Renovation"
    {:install-state :face-up
@@ -265,7 +266,8 @@
     :effect (effect (corp-install target nil {:install-state :rezzed-no-cost}))}

    "Mandatory Upgrades"
-   {:effect (effect (gain :click 1 :click-per-turn 1))
+   {:msg "gain an additional [Click] per turn"
+    :effect (effect (gain :click 1 :click-per-turn 1))
     :leave-play (req (lose state :corp :click 1 :click-per-turn 1))}

    "Market Research"
@@ -439,7 +441,8 @@
                                              (steal-cost-bonus state side [:credit (* 2 counter)])))}}}

    "Veterans Program"
-   {:effect (effect (lose :bad-publicity 2))}
+   {:msg "lose 2 bad publicity"
+    :effect (effect (lose :bad-publicity 2))}

    "Vulcan Coverup"
    {:msg "do 2 meat damage" :effect (effect (damage :meat 2 {:card card}))


update Character Assassination to use targeting system

--- src/clj/game/cards-agendas.clj
+++ src/clj/game/cards-agendas.clj
@@ -50,7 +50,8 @@
     :end-turn {:effect (effect (lose :runner :tag 2)) :msg "make the Runner lose 2 tags"}}

    "Character Assassination"
-   {:prompt "Choose a resource to trash" :choices (req (get-in runner [:rig :resource]))
+   {:prompt "Choose a resource to trash"
+    :choices {:req #(and (:installed %) (= (:type %) "Resource"))}
     :msg (msg "trash " (:title target)) :effect (effect (trash target))}

    "Chronos Project"


modify ABT and License Acquisition to use :rezzed-no-cost

--- src/clj/game/cards-agendas.clj
+++ src/clj/game/cards-agendas.clj
@@ -4,7 +4,7 @@
   {"Accelerated Beta Test"
    (let [abthelper (fn abt [n i] {:prompt "Select a piece of ICE from the top of the play area to install"
                                   :choices {:req #(and (:side % "Corp") (= (:type %) "ICE") (= (:zone %) [:play-area]))}
-                                  :effect (req (corp-install state side target nil {:no-install-cost true :install-state :rezzed})
+                                  :effect (req (corp-install state side target nil {:no-install-cost true :install-state :rezzed-no-cost})
                                                (trigger-event state side :rez target)
                                                  (when (< n i)
                                                    (resolve-ability state side (abt (inc n) i) card nil)))})]
@@ -251,7 +251,7 @@
                       {:prompt "Choose a card to install" :msg (msg "install and rez " (:title target))
                        :choices (req (filter #(#{"Asset" "Upgrade"} (:type %))
                                              ((if (= target "HQ") :hand :discard) corp)))
-                       :effect (effect (corp-install target nil {:install-state :rezzed}))} card targets))}
+                       :effect (effect (corp-install target nil {:install-state :rezzed-no-cost}))} card targets))}

    "Mandatory Upgrades"
    {:effect (effect (gain :click 1 :click-per-turn 1))


Ensure :standalone gets default subsequent-prompt

--- src/clj/reply/reader/jline.clj
+++ src/clj/reply/reader/jline.clj
@@ -28,8 +28,8 @@

 (defn subsequent-prompt [options ns]
   (let [subsequent-prompt (:subsequent-prompt options)]
-    (if subsequent-prompt
-      (subsequent-prompt ns)
+    (if-let [prompt-string (and subsequent-prompt (subsequent-prompt ns))]
+      prompt-string
       (let [prompt-end (str "#_" prompt-end)]
         (apply str
                (concat (repeat (- (count (@prompt-fn ns))


SVG and PNG import, improved find-tag

SVG and PNG import, improved find-tag

--- src/clj/salava/badge/parse.clj
+++ src/clj/salava/badge/parse.clj
@@ -674,6 +674,13 @@

 ;;;

+(defn- find-tag [depth tag root]
+  (cond
+    (= (:tag root) tag) root
+    (> depth 10) nil
+    :else (some #(find-tag (inc depth) tag %) (:content root))))
+
+
 (defmulti file->badge (fn [_ upload]
                         (or (:content-type upload)
                             (get-in upload [:headers "Content-Type"]))))
@@ -687,20 +694,10 @@
              (str->badge user))))

 (defmethod file->badge "image/svg+xml" [user upload]
-  (some->> (xml/parse (or (:tempfile upload) (:body upload)))
-           :content
-           (filter #(= :openbadges:assertion (:tag %)))
-           first
-           :content
-           first
+  (some->> (or (:tempfile upload) (:body upload))
+           xml/parse (find-tag 0 :openbadges:assertion) :attrs :verify
            string/trim
            (str->badge user)))
-
-
-(defn- find-tag [tag root]
-  (if (= (:tag root) tag)
-    root
-    (some #(find-tag tag %) (:content root))))

 (defmethod file->badge "application/pdf" [user upload]
   (with-open [doc (pdf/obtain-document (or (:tempfile upload) (:body upload)))]
@@ -711,7 +708,7 @@
         (str->badge user))
       (some->>
         doc .getDocumentCatalog .getMetadata .createInputStream
-        xml/parse (find-tag :openbadges:assertion) :attrs :verify
+        xml/parse (find-tag 0 :openbadges:assertion) :attrs :verify
         string/trim
         (str->badge user)))))


Use clj-http connection pool

Use clj-http connection pool

--- src/clj/salava/badge/parse.clj
+++ src/clj/salava/badge/parse.clj
@@ -6,6 +6,7 @@
             [clojure.data.json :as json]
             [clojure.pprint :refer [pprint]]
             [clojure.xml :as xml]
+            [clj-http.client :as clj-http]
             [net.cgrand.enlive-html :as html]
             [salava.core.util :as u]
             [salava.core.http :as http]
@@ -531,25 +532,25 @@
   ([user assertion initial]
    (verify-assertion (:assertion_url initial) assertion)
    (let [now (u/now)]
-     (-> initial
-         (assoc :id nil
-                :user_id (:id user)
-                :email   (recipient (:emails user) assertion)
-                :status "pending"
-                :visibility "private"
-                :show_recipient_name 0
-                :rating nil
-                :ctime now
-                :mtime now
-                :deleted 0
-                :revoked 0
-                :issuer_verified 0
-                :show_evidence 0
-                :last_checked nil
-                :old_id nil)
-         (badge-content assertion)
-         valid-badge
-         ))))
+     (clj-http/with-connection-pool {:timeout 10 :threads 4 :insecure? false :default-per-route 10}
+       (-> initial
+           (assoc :id nil
+                  :user_id (:id user)
+                  :email   (recipient (:emails user) assertion)
+                  :status "pending"
+                  :visibility "private"
+                  :show_recipient_name 0
+                  :rating nil
+                  :ctime now
+                  :mtime now
+                  :deleted 0
+                  :revoked 0
+                  :issuer_verified 0
+                  :show_evidence 0
+                  :last_checked nil
+                  :old_id nil)
+           (badge-content assertion)
+           valid-badge)))))

 ;;;


Extract bench functionality in simulation

--- src/clj_gatling/simulation.clj
+++ src/clj_gatling/simulation.clj
@@ -6,29 +6,38 @@

 (defn- now [] (System/currentTimeMillis))

+(defn- bench [f]
+  (fn [start-promise end-promise callback context]
+    (deliver start-promise (now))
+    (f (fn [result & [context]]
+         (deliver end-promise (now))
+         (callback result context))
+       context)))
+
 (defn- request-fn [request]
-  (if-let [url (:http request)]
-    (partial http/async-http-request url)
-    (:fn request)))
+  (bench (if-let [url (:http request)]
+            (partial http/async-http-request url)
+            (:fn request))))

 (defn async-function-with-timeout [request timeout user-id context]
-  (let [start    (now)
+  (let [start-promise (promise)
+        end-promise (promise)
         response (async/chan)
         function (memoize (request-fn request))
-        callback (fn [result & context]
+        callback (fn [result context]
                    (put! response [{:name (:name request)
                                    :id user-id
-                                   :start start
-                                   :end (now)
-                                   :result result} (first context)]))]
+                                   :start @start-promise
+                                   :end @end-promise
+                                   :result result} context]))]
     (go
-      (function callback (assoc context :user-id user-id))
+      (function start-promise end-promise callback (assoc context :user-id user-id))
       (let [[result c] (alts! [response (async/timeout timeout)])]
         (if (= c response)
           result
           [{:name (:name request)
             :id user-id
-            :start start
+            :start @start-promise
             :end (now)
             :result false} (first context)])))))


Fix a typo

Fix a typo

--- src/cljam/io/util/bgzf/gzi.clj
+++ src/cljam/io/util/bgzf/gzi.clj
@@ -36,7 +36,7 @@
             (bit-and diff 0xffff))))

 (defn comp->uncomp
-  "Returns a uncompressed offset for a given virtual file offset"
+  "Returns an uncompressed offset for a given virtual file offset"
   ^long [gzi ^long compressed-offset]
   (let [off (unsigned-bit-shift-right compressed-offset 16)
         [uncompressed] (->> gzi


Add examples to styleguide

Add examples to styleguide

--- src/cljs/clojuredocs/main.cljs
+++ src/cljs/clojuredocs/main.cljs
@@ -200,8 +200,14 @@

 (wire-search text-chan app-state)

+(defn mk-delete-example [app-state]
+  (fn [ex-to-del]
+    (swap! app-state update-in [:examples]
+      (fn [exs]
+        (vec (remove #(= ex-to-del %) exs))))))
+
 (on-el-om
-  [:.examples-widget examples/$examples]
+  [:.examples-widget examples/$examples {:init-state {:delete-ex (mk-delete-example app-state)}}]
   [:.see-alsos-widget see-alsos/$see-alsos]
   [:.search-widget search/$quick-lookup {:init-state {:text-chan text-chan}}]
   [:.quick-search-widget search/$quick-search {:init-state {:text-chan text-chan}}]
@@ -217,6 +223,72 @@

 (def push-sels [:.mobile-push-wrapper :.mobile-nav-menu :.mobile-nav-bar])

+(def ex-ac-results
+  {:ac-results [{:type "function"
+                 :ns "clojure.core"
+                 :name "map"
+                 :doc "Returns a lazy sequence consisting of the result of applying f to the set of first items of each coll, followed by applying f to the set
+of second items in each coll, until any one of the colls is
+exhausted. Any remaining items in other colls are ignored. Function
+f should accept number-of-colls arguments."}
+                {:type "namespace"
+                 :name "clojure.core"
+                 :doc "Fundamental library of the Clojure language"}
+                {:type "page"
+                 :name "Getting Started"
+                 :desc "Where to go to get started with Clojure. Provides a host of information  con the language, core concepts, tutorials, books, and videos to help you learn Clojure."}]})
+
+(def ex-example-0
+  {:body "user=> (map #(vector (first %) (* 2 (second %)))
+            {:a 1 :b 2 :c 3})
+
+([:a 2] [:b 4] [:c 6])
+
+user=> (into {} *1)
+{:a 2, :b 4, :c 6}"
+   :author {:login "zk" :account-source "github" :avatar-url "https://avatars.githubusercontent.com/u/7194?v=2"}})
+
+
+(def ex-example-1
+  {:body "user=> (map #(vector (first %) (* 2 (second %)))
+            {:a 1 :b 2 :c 3})
+
+([:a 2] [:b 4] [:c 6])
+
+user=> (into {} *1)
+{:a 2, :b 4, :c 6}"
+   :author {:login "zk"
+            :account-source "github"
+            :avatar-url "https://avatars.githubusercontent.com/u/7194?v=2"}
+   :editors [{:login "masondesu"
+              :account-source "github"
+              :avatar-url "http://www.gravatar.com/avatar/091bc95204caaf52b0d299bd9ac59540?s=48&d=identicon"}
+             {:login "dakrone"
+              :account-source "github"
+              :avatar-url "http://www.gravatar.com/avatar/bcacd00a7f05c4772329cf9f446c7987?s=48&d=identicon"}]})
+
+
+(def ex-example-2
+  {:body "user=> (map #(vector (first %) (* 2 (second %)))
+            {:a 1 :b 2 :c 3})
+
+([:a 2] [:b 4] [:c 6])
+
+user=> (into {} *1)
+{:a 2, :b 4, :c 6}"
+   :user {:email "zachary.kim@gmail.com"}
+   :editors [{:email "foo@barrrrrrrrr.com"}
+             {:email "foo@barrrrrrrr.com"}
+             {:email "foo@barrrrrrr.com"}
+             {:email "foo@barrrrrr.com"}
+             {:email "foo@barrrrr.com"}
+             {:email "foo@barrrr.com"}
+             {:email "foo@barrr.com"}
+             {:email "foo@barr.com"}
+             {:email "foo@bar.com"}]})
+:var {:name "bar" :ns "foo"}
+
+
 (on-el
   :.btn.mobile-menu
   (fn [$el]
@@ -257,19 +329,7 @@
   (fn [$el]
     (om/root
       search/$quick-lookup
-      {:ac-results [{:type "function"
-                     :ns "clojure.core"
-                     :name "map"
-                     :doc "Returns a lazy sequence consisting of the result of applying f to the set of first items of each coll, followed by applying f to the set
-of second items in each coll, until any one of the colls is
-exhausted. Any remaining items in other colls are ignored. Function
-f should accept number-of-colls arguments."}
-                    {:type "namespace"
-                     :name "clojure.core"
-                     :doc "Fundamental library of the Clojure language"}
-                    {:type "page"
-                     :name "Getting Started"
-                     :desc "Where to go to get started with Clojure. Provides a host of information  con the language, core concepts, tutorials, books, and videos to help you learn Clojure."}]}
+      ex-ac-results
       {:target $el}))

   :.sg-quick-lookup-null-state
@@ -297,15 +357,7 @@
   (fn [$el]
     (om/root
       examples/$examples
-      {:examples [{:body "user=> (map #(vector (first %) (* 2 (second %)))
-            {:a 1 :b 2 :c 3})
-
-([:a 2] [:b 4] [:c 6])
-
-user=> (into {} *1)
-{:a 2, :b 4, :c 6}"
-                   :user {:email "zachary.kim@gmail.com"}
-                   :history [{:user {:email "zachary.kim@gmail.com"}}]}]
+      {:examples [ex-example-0]
        :var {:name "bar" :ns "foo"}}
       {:target $el}))

@@ -313,70 +365,82 @@
   (fn [$el]
     (om/root
       examples/$examples
-      {:examples [{:body "user=> (foo)"
-                   :user {:email "zachary.kim@gmail.com"}
-                   :history [{:user {:email "lee@writequit.org"}}
-                             {:user {:email "zachary.kim@gmail.com"}}]}
-                  {:body "user=> (map #(vector (first %) (* 2 (second %)))
-            {:a 1 :b 2 :c 3})
-
-([:a 2] [:b 4] [:c 6])
-
-user=> (into {} *1)
-{:a 2, :b 4, :c 6}"
-                   :user {:email "zachary.kim@gmail.com"}
-                   :history [{:user {:email "masondesu@gmail.com"}}
-                             {:user {:email "lee@writequit.org"}}
-                             {:user {:email "zachary.kim@gmail.com"}}]}
-                  {:body "user=> (map #(vector (first %) (* 2 (second %)))
-            {:a 1 :b 2 :c 3})
-
-([:a 2] [:b 4] [:c 6])
-
-user=> (into {} *1)
-{:a 2, :b 4, :c 6}"
-                   :user {:email "zachary.kim@gmail.com"}
-                   :history [{:user {:email "foo@barrrrrrr.com"}}
-                             {:user {:email "foo@barrrrrr.com"}}
-                             {:user {:email "foo@barrrrr.com"}}
-                             {:user {:email "foo@barrrr.com"}}
-                             {:user {:email "foo@barrr.com"}}
-                             {:user {:email "foo@barr.com"}}
-                             {:user {:email "foo@bar.com"}}
-                             {:user {:email "fickamanda@gmail.com"}}
-                             {:user {:email "brentdillingham@gmail.com"}}
-                             {:user {:email "masondesu@gmail.com"}}
-                             {:user {:email "lee@writequit.org"}}
-                             {:user {:email "zachary.kim@gmail.com"}}]}]
-       :var {:name "bar" :ns "foo"}}
+      {:examples [ex-example-0
+                  ex-example-1
+                  ex-example-2]}
       {:target $el}))

   :.sg-add-example
   (fn [$el]
     (om/root
       examples/$add
-      {}
-      {:target $el :init-state {:expanded? true}}))
+      {:editing? true}
+      {:target $el}))

   :.sg-add-example-loading
   (fn [$el]
     (om/root
       examples/$add
-      {}
+      {:editing? true :loading? true :body "(defn greet [name]\n  (println \"Hello\" name))"}
+      {:target $el}))
+
+  :.sg-add-example-errors
+  (fn [$el]
+    (om/root
+      examples/$add
+      {:editing? true :body "(defn greet [name]\n  (println \"Hello\" name))"}
       {:target $el
-       :init-state {:expanded? true
-                    :loading? true
-                    :text "(defn greet [name]\n  (println \"Hello\" name))"}}))
-
-  :.sg-add-example-errors
-  (fn [$el]
-    (om/root
-      examples/$add
-      {}
-      {:target $el
-       :init-state {:expanded? true
-                    :error-message "This is where error messages that apply to the whole form go. And here's some other text to show what happens with a very long error message."
-                    :text "(defn greet [name]\n  (println \"Hello\" name))"}}))
+       :init-state {:error-message "This is where error messages that apply to the whole form go. And here's some other text to show what happens with a very long error message."}}))
+
+  :.sg-edit-example
+  (fn [$el]
+    (om/root
+      examples/$example
+      (merge
+        ex-example-0
+        {:editing? true
+         :can-delete? true})
+      {:target $el}))
+
+  :.sg-delete-example
+  (fn [$el]
+    (om/root
+      examples/$example-meta
+      {:body "user=> (foo)"
+       :author {:login "zk" :account-source "github" :avatar-url "https://avatars.githubusercontent.com/u/7194?v=2"}
+       :history [{:author {:login "dakrone" :account-source "github" :avatar-url "https://avatars3.githubusercontent.com/u/19060?v=2&s=460"}}]
+       :can-delete? true}
+      {:target $el}))
+
+  :.sg-delete-example-confirm
+  (fn [$el]
+    (om/root
+      examples/$example-meta
+      {:body "user=> (foo)"
+       :author {:login "zk" :account-source "github" :avatar-url "https://avatars.githubusercontent.com/u/7194?v=2"}
+       :history [{:author {:login "dakrone" :account-source "github" :avatar-url "https://avatars3.githubusercontent.com/u/19060?v=2&s=460"}}]
+       :can-delete? true}
+      {:target $el :init-state {:delete-state :confirm}}))
+
+  :.sg-delete-example-loading
+  (fn [$el]
+    (om/root
+      examples/$example-meta
+      {:body "user=> (foo)"
+       :author {:login "zk" :account-source "github" :avatar-url "https://avatars.githubusercontent.com/u/7194?v=2"}
+       :history [{:author {:login "dakrone" :account-source "github" :avatar-url "https://avatars3.githubusercontent.com/u/19060?v=2&s=460"}}]
+       :can-delete? true}
+      {:target $el :init-state {:delete-state :loading}}))
+
+  :.sg-delete-example-error
+  (fn [$el]
+    (om/root
+      examples/$example-meta
+      {:body "user=> (foo)"
+       :author {:login "zk" :account-source "github" :avatar-url "https://avatars.githubusercontent.com/u/7194?v=2"}
+       :history [{:author {:login "dakrone" :account-source "github" :avatar-url "https://avatars3.githubusercontent.com/u/19060?v=2&s=460"}}]
+       :can-delete? true}
+      {:target $el :init-state {:delete-state :error}}))

   :.sg-notes-null-state
   (fn [$el]
@@ -432,7 +496,6 @@
     ;; ctrl-s to focus search input
     (when (and (.-ctrlKey e) (= 83 (.-keyCode e)))
       (doseq [$el (sel ".search input[name='query']")]
-        (prn $el)
         (.focus $el)))))

 (def tog (atom false))


add bookmark with ctrl+enter

add bookmark with ctrl+enter

--- src/cljs/lesezeichen/core.cljs
+++ src/cljs/lesezeichen/core.cljs
@@ -118,7 +118,22 @@
   {[:#bm-header] (content "Recent bookmarks")
    [:#url-input] (do-> (set-attr :value (:url-input-text state))
                        (listen :on-change #(do (println (:url-input-text state))
-                                               (handle-text-change % owner :url-input-text))))
+                                               (handle-text-change % owner :url-input-text))
+                               :on-key-down #(if (= (.-keyCode %) 10)
+                                               (do
+                                                 (if (clojure.string/blank? (:url-input-text state))
+                                                   (println "no input")
+                                                   (do
+                                                     (add-bookmark owner)
+                                                     (om/set-state! owner :url-input-text ""))))
+                                                  (when (= (.-which %) 13)
+                                                    (when (.-ctrlKey %)
+                                                      (do
+                                                        (if (clojure.string/blank? (:url-input-text state))
+                                                          (println "no input")
+                                                          (do
+                                                            (add-bookmark owner)
+                                                            (om/set-state! owner :url-input-text "")))))))))
    [:#url-list] (content (map #(url %) (sort-by :ts > (get-bookmarks app))))
    [:#bookmark-btn] (listen
                      :on-click


Improve threshold for determining color name

--- src/cljs/robot_kata/image.cljs
+++ src/cljs/robot_kata/image.cljs
@@ -4,7 +4,7 @@
   (.getContext canvas "2d") )

 (defn get-color-name [color]
-  (let [threshold 192]
+  (let [threshold 128]
     (cond (and (> (color :r) threshold) (> (color :g) threshold) (> (color :b) threshold)) "white"
           (and (> (color :r) threshold) (> (color :g) threshold))                          "yellow"
           (> (color :r) threshold)                                                         "red"


Add current path to classpath when launching slow processes

--- src/clojure/nightcode/lein.clj
+++ src/clojure/nightcode/lein.clj
@@ -98,7 +98,7 @@
                    path
                    java-cmd
                    "-cp"
-                   (System/getProperty "java.class.path")
+                   (str ".:" (System/getProperty "java.class.path"))
                    namespace-name
                    cmd)))


Use direct method of launching process for java projects

--- src/clojure/nightcode/lein.clj
+++ src/clojure/nightcode/lein.clj
@@ -92,7 +92,7 @@

 (defonce class-name (str *ns*))

-(defn start-self-process
+(defn start-process-indirectly
   [process path & args]
   (let [project-map (read-project-clj path)
         java-cmd (or (:java-cmd project-map) (System/getenv "JAVA_CMD") "java")
@@ -111,6 +111,24 @@
                      (.getCanonicalPath jar-file))
                    args)))

+(defn start-process-directly
+  [process path func]
+  (let [project-map (-> (read-project-clj path)
+                        (assoc :eval-in :trampoline
+                               :jvm-opts [(str "-agentlib:jdwp="
+                                               "transport=dt_socket,"
+                                               "server=y,"
+                                               "suspend=n,"
+                                               "address=7896")]))
+        forms leiningen.core.eval/trampoline-forms
+        profiles leiningen.core.eval/trampoline-profiles]
+    (reset! forms [])
+    (reset! profiles [])
+    (func path project-map)
+    (doseq [i (range (count @forms))]
+      (->> (leiningen.core.eval/shell-command project-map (nth @forms i))
+           (start-process process path)))))
+
 (defn stop-process
   [process]
   (when @process
@@ -175,35 +193,45 @@
   [process in out path]
   (stop-process process)
   (->> (do (println (utils/get-string :running))
-         (start-self-process process path class-name "run"))
+         (if (is-java-project? path)
+           (start-process-directly process path run-project-task)
+           (start-process-indirectly process path class-name "run")))
        (start-thread in out)))

 (defn run-repl-project
   [process in out path]
   (stop-process process)
   (->> (do (println (utils/get-string :running_with_repl))
-         (start-self-process process path class-name "repl"))
+         (if (is-java-project? path)
+           (start-process-directly process path run-repl-project-task)
+           (start-process-indirectly process path class-name "repl")))
        (start-thread in out)))

 (defn build-project
   [process in out path]
   (stop-process process)
   (->> (do (println (utils/get-string :building))
-         (start-self-process process path class-name "build"))
+         (if (is-java-project? path)
+           (start-process-directly process path build-project-task)
+           (start-process-indirectly process path class-name "build")))
        (start-thread in out)))

 (defn test-project
   [process in out path]
   (stop-process process)
   (->> (do (println (utils/get-string :testing))
-         (start-self-process process path class-name "test"))
+         (if (is-java-project? path)
+           (start-process-directly process path test-project-task)
+           (start-process-indirectly process path class-name "test")))
        (start-thread in out)))

 (defn clean-project
   [process in out path]
   (stop-process process)
   (->> (do (println (utils/get-string :cleaning))
-         (start-self-process process path class-name "clean"))
+         (if (is-java-project? path)
+           (start-process-directly process path clean-project-task)
+           (start-process-indirectly process path class-name "clean")))
        (start-thread in out)))

 (defn new-project
@@ -220,7 +248,7 @@
 (defn run-repl
   [process in out]
   (stop-process process)
-  (->> (start-self-process process nil "clojure.main")
+  (->> (start-process-indirectly process nil "clojure.main")
        (start-thread in out)))

 (defn run-logcat
@@ -245,13 +273,12 @@
   (System/setProperty "jline.terminal" "dumb")
   (let [path "."
         project-map (-> (read-project-clj path)
-                        add-sdk-path
                         leiningen.core.project/init-project)]
     (case cmd
+      "run" (run-project-task path project-map)
+      "repl" (run-repl-project-task path project-map)
       "build" (build-project-task path project-map)
+      "test" (test-project-task path project-map)
       "clean" (clean-project-task path project-map)
-      "repl" (run-repl-project-task path project-map)
-      "run" (run-project-task path project-map)
-      "test" (test-project-task path project-map)
       nil))
   (System/exit 0))


sparkling.core/intersect-by-key as new additional functionality - still misses tests - missed in sparkling.api.

--- src/clojure/sparkling/core.clj
+++ src/clojure/sparkling/core.clj
@@ -9,6 +9,7 @@

   (:refer-clojure :exclude [map reduce first count take distinct filter group-by values partition-by keys])
   (:require [clojure.tools.logging :as log]
+            [sparkling.destructuring :as ds]
             [sparkling.function :refer [flat-map-function
                                         flat-map-function2
                                         function
@@ -356,9 +357,6 @@
     si/OBJECT-CLASS-TAG
     ))

-
-
-
 (defn join
   "When called on `rdd` of type (K, V) and (K, W), returns a dataset of
   (K, (V, W)) pairs with all pairs of elements for each key."
@@ -371,6 +369,35 @@
    or the pair (K, (V, nil)) if no elements in other have key K."
   [rdd other]
   (.leftOuterJoin rdd other))
+
+
+;; TODO: Add tests
+(defn key-by-fn "Wraps a function f to be called with the value v of a tuple from spark,
+so that the wrapped function returns a tuple [f(v),v]"
+  [f]
+  (fn [^Tuple2 t]
+    (let [v (ds/value t)]
+      (tuple (f v) v))))
+
+(declare rekey)
+
+;; TODO: Add tests
+(defn intersect-by-key
+  "Intersects rdd1 with rdd2 by key,
+  i.e. rdd1 is rekeyed by keyfn,
+  then joined to keep only those elements with keys in rdd2
+  and rekeyed again with keybackfn to bring back the original structure.
+
+  Remember, rekey is performed by partition,
+  thus keyfn and keybackfn and the original partitioning should work with the given partitioner."
+  [rdd1 keyfn keybackfn rdd2]
+  (->>
+    rdd1
+    (rekey (key-by-fn keyfn))
+    (join rdd2)
+    (map-values (ds/second-value-fn identity))
+    (rekey (key-by-fn keybackfn))))
+

 (defn cartesian
   "Creates the cartesian product of two RDDs returning an RDD of pairs"


format interactive layers blogpost

format interactive layers blogpost

--- src/pc/views/blog/interactive_layers.clj
+++ src/pc/views/blog/interactive_layers.clj
@@ -3,49 +3,43 @@
 (defn interactive-layers []
   {:title "Introduction to Interactive Layers"
    :body
-   [:div
+   (list
+    [:article
+     [:p "In this tutorial, we'll show you how to use Precursor's simple interactive layers to prototype complex user flows."]
+     [:p "We'll prototype a simple iPhone app with three different views."]]

-    [:p "In this tutorial, we'll show you how to use Precursor's simple interactive layers to prototype complex user flows."]
+    [:figure [:img {:src "/email/interactive-demo.gif"}]]

-    [:p "We'll prototype a simple iPhone app with three different views."]
+    [:article
+     [:h3 "Name Shapes"]
+     [:p "We'll start by drawing out three static views of our iPhone game."]]

-    [:p [:div
-         [:iframe {:src "http://gfycat.com/ifr/NervousBlissfulGrayling" :frameborder "0" :scrolling "no"
-                   :width "640" :height "480" :style "-webkit-backface-visibility: hidden;-webkit-transform: scale(1);"}]]]
+    [:figure [:img {:src "/blog/interactive-layers/static-view.png"}]]
+
+    [:article
+     [:p "We can right-click on the phone outline to open the properties menu and give each of our views a name. "
+      "We'll name the first view \"Overview\", the second view \"Expanded Game\", and the third view \"Game main menu\". "]]
+
+    [:figure [:img {:src "/blog/interactive-layers/name-layer.png"}]]

-    [:h2 "Name Shapes"]
+    [:article
+     [:h3 "Define Targets"]
+     [:p "Now that we've named our main views, we can right-click on a shape to select one of the views to target from the drop-down menu."]]

-    [:p "We'll start by drawing out three static views of our iPhone game."]
+    [:figure [:img {:src "/blog/interactive-layers/select-target.png"}]]

-    [:p [:img {:src "/blog/interactive-layers/static-view.png"
-               :width "800px"}]]
+    [:article
+     [:p "After we've defined a target, clicking on the shape with the select tool will center its target on the canvas. "
+      "We'll have the illusion of moving to a separate view, but we haven't left our prototyping world. "
+      "This is the beauty of Precursor's interactive prototyping--it's built up of very simple pieces."]]

-    [:p "We can right-click on the phone outline to open the properties menu and give each of our views a name. "
-     "We'll name the first view \"Overview\", the second view \"Expanded Game\", and the third view \"Game main menu\". "]
+    [:article
+     [:h3 "Extend the Illusion"]
+     [:p "The transitions will feel more realistic if we can't see the next view before we move to it. We can accomplish this "
+      "by selecting the views and spacing them out. You can do this very easily by zooming out. Simply hold your "
+      "alt or option key and scroll down. Then select each shape and space them out. "
+      "You can get back to the default view by pressing the \"1\" key."]]

-    [:p [:img {:src "/blog/interactive-layers/name-layer.png"
-               :width "800px"}]]
-
-
-    [:h2 "Define Targets"]
-
-    [:p "Now that we've named our main views, we can right-click on a shape to select one of the views to target from the drop-down menu."]
-
-    [:p [:img {:src "/blog/interactive-layers/select-target.png"
-               :width "800px"}]]
-
-    [:p "After we've defined a target, clicking on the shape with the select tool will center its target on the canvas. "
-     "We'll have the illusion of moving to a separate view, but we haven't left our prototyping world. "
-     "This is the beauty of Precursor's interactive prototyping--it's built up of very simple pieces."]
-
-    [:h3 "Extend the Illusion"]
-
-    [:p "The transitions will feel more realistic if we can't see the next view before we move to it. We can accomplish this "
-     "by selecting the views and spacing them out. You can do this very easily by zooming out. Simply hold your "
-     "alt or option key and scroll down. Then select each shape and space them out. "
-     "You can get back to the default view by pressing the \"1\" key."]
-
-    [:p [:img {:src "/blog/interactive-layers/space-layers.png"
-               :width "400px"}]]
-    ]})
+    [:figure [:img {:src "/blog/interactive-layers/space-layers.png"}]]
+    )})


Typical stage completion and time range

Typical stage completion and time range

--- src/test_utils/fracture_diagnostics.cljc
+++ src/test_utils/fracture_diagnostics.cljc
@@ -162,6 +162,28 @@
   ([] (second (typical-stage-extent)))
   ([length-unit]
    (second (typical-stage-extent (constantly (typical-stage-top length-unit))))))
+
+(defn typical-stage-completion-time
+  "Calculates the typical time in seconds for a stage to be completed."
+  []
+  ;; Empirically, a (relatively poor) model for generating these values is a normal distribution. A better model might be similar
+  ;; to the model for `typical-stage-completion-changeover`.
+  (tuc/draw-normal 7454.19 2166.79))
+
+(defn typical-stage-time-range
+  "Calculates the typical time range for a stage."
+  ([]
+   (let [start-time (tuc/rand-timestamp 2018 2029)]
+     (typical-stage-time-range start-time)))
+  ([start-time]
+   (let [completion-time-in-seconds (typical-stage-completion-time)
+         ;; Not half-even rounding but perhaps good enough
+         completion-time-in-hms (map #(Math/round %)
+                                     (tuc/total-seconds->hms completion-time-in-seconds))
+         stop-time-hms (map + (drop 3 start-time) completion-time-in-hms)
+         stop-time (vec (flatten
+                         [(take 3 start-time) stop-time-hms]))]
+     [start-time stop-time])))

 (defn typical-stage-completion-changeover
   "Calculates the typical (empirically determined) time (in seconds) to change completion operationss from one stage to another"


renamed sound-blob to sound-url

renamed sound-blob to sound-url

--- src/frontend/player.cljs
+++ src/frontend/player.cljs
@@ -42,8 +42,8 @@
   (.resume (:current-sound @app-state))
   (swap! app-state assoc :paused? false))

-(defn play-track [sound-blob sound-id position on-finish]
-  (println "SOUND BLOB" sound-blob)
+(defn play-track [sound-url sound-id position on-finish]
+  (println "Sound URL to play:" sound-url)
   (swap! app-state assoc :on-finish on-finish)
   (swap! app-state assoc :current-sound-id sound-id)
   (swap! app-state assoc :paused? false)
@@ -51,7 +51,7 @@
   (swap! app-state assoc :current-sound
     (.createSound js/soundManager #js {:id sound-id
                                        :type "audio/mpeg"
-                                       :url sound-blob
+                                       :url sound-url
                                        :whileloading while-loading
                                        :onfinish on-finish
                                        :volume (:volume @app-state)}))