Refactoring specs.

Refactoring specs.

--- spec/freefrog/governance_roles_spec.clj
+++ spec/freefrog/governance_roles_spec.clj
@@ -42,6 +42,42 @@
       (should-throw IllegalArgumentException "Name may not be empty"
         (fn sample-anchor-with-role "" val)))))

+(defn should-handle-collection-properly [add-fn remove-fn type type-str coll1
+                                         coll2 val1 val2]
+  (describe type-str
+    (it (str "can add a " type-str " to a role with no " type-str "s")
+      (should= (update-in sample-anchor-with-role [:roles role-name]
+                          assoc type #{val1})
+        (add-fn sample-anchor-with-role role-name val1)))
+
+    (it (str "can add a " type-str " to a role with existing " type-str "s")
+      (let [expected
+            (update-in coll1 [:roles role-name type] conj val2)]
+        (should= expected
+          (add-fn coll1 role-name val2))))
+
+    (should-not-update-missing-or-empty-roles add-fn
+      (str "adding a " type-str) val1)
+
+    (it (str "refuses to add the same " type-str " twice")
+      (should-throw IllegalArgumentException
+        (format "%s '%s' already exists on role '%s'" type-str val1 role-name)
+        (add-fn coll1 role-name val1)))
+
+    (it (str "can remove a " type-str " from a role")
+      (should= coll1 (remove-fn coll2 role-name val2)))
+
+    (it (str "removes the " type-str "s array when there are none left")
+      (should= sample-anchor-with-role (remove-fn coll1 role-name val1)))
+
+    (it (str "refuses to remove a " type-str " that doesn't exist")
+      (should-throw IllegalArgumentException
+        (format "%s '%s' doesn't exist on role '%s'" type-str val2 role-name)
+        (remove-fn coll1 role-name val2)))
+
+    (should-not-update-missing-or-empty-roles remove-fn
+      (str "removing a " type-str) val1)))
+
 ;; Section 3.1.a
 (describe "Role Manipulation"
   (describe "adding"
@@ -141,88 +177,20 @@
         "Stuff"))

     ;; Section 1.1.b
-    (describe "domains"
-      (it "can add a domain to a role with no domains"
-        (should= (update-in sample-anchor-with-role [:roles role-name]
-                            assoc :domains #{sample-domain-1})
-          (g/add-domain sample-anchor-with-role role-name sample-domain-1)))
-
-      (it "can add a domain to a role with existing domains"
-        (let [expected
-              (update-in sample-anchor-with-domain [:roles role-name :domains]
-                         conj sample-domain-2)]
-          (should= expected
-            (g/add-domain sample-anchor-with-domain role-name sample-domain-2))))
-
-      (should-not-update-missing-or-empty-roles g/add-domain "adding a domain"
-        sample-domain-1)
-
-      (it "refuses to add the same domain twice"
-        (should-throw IllegalArgumentException
-          (format "Domain '%s' already exists on role '%s'" sample-domain-1
-                  role-name)
-          (g/add-domain sample-anchor-with-domain role-name sample-domain-1)))
-
-      (it "can remove a domain from a role"
-        (should= sample-anchor-with-domain
-          (g/remove-domain sample-anchor-with-domains role-name
-                           sample-domain-2)))
-
-      (it "removes the domains array when there are no domains"
-        (should= sample-anchor-with-role
-          (g/remove-domain sample-anchor-with-domain role-name
-                           sample-domain-1)))
-
-      (it "refuses to remove a domain that doesn't exist"
-        (should-throw IllegalArgumentException
-          (format "Domain '%s' doesn't exist on role '%s'" sample-domain-2
-                  role-name)
-          (g/remove-domain sample-anchor-with-domain role-name
-                           sample-domain-2)))
-
-      (should-not-update-missing-or-empty-roles g/remove-domain
-        "removing domain" sample-domain-1))
+    (should-handle-collection-properly g/add-domain g/remove-domain
+                                       :domains "Domain"
+                                       sample-anchor-with-domain
+                                       sample-anchor-with-domains
+                                       sample-domain-1
+                                       sample-domain-2)

     ;; Section 1.1.c
-    (describe "accountabilities"
-      (it "adds an accountability to a role that has no accountabilities"
-        (should= (update-in sample-anchor-with-role [:roles role-name]
-                            assoc :accountabilities #{sample-acc-1})
-          (g/add-accountability sample-anchor-with-role role-name
-                                sample-acc-1)))
-
-      (it "adds an accountability to a role that already has one"
-        (should= (update-in sample-anchor-with-acc [:roles role-name
-                                                    :accountabilities]
-                            conj sample-acc-2)
-          (g/add-accountability sample-anchor-with-acc role-name
-                                sample-acc-2)))
-
-      (it "refuses to add the same accountability twice"
-        (should-throw IllegalArgumentException
-          (format "Accountability '%s' already exists on role '%s'" sample-acc-1
-                  role-name)
-          (g/add-accountability sample-anchor-with-acc role-name sample-acc-1)))
-
-      (should-not-update-missing-or-empty-roles g/add-accountability
-        "adding accountability" sample-acc-1)
-
-      (it "can remove an accountability"
-        (should= sample-anchor-with-acc
-          (g/remove-accountability sample-anchor-with-accs role-name sample-acc-2))
-        (should= sample-anchor-with-role
-          (g/remove-accountability sample-anchor-with-acc role-name sample-acc-1)))
-
-      (it "refuses to remove an accountability that doesn't exist"
-        (should-throw IllegalArgumentException
-          (format "Accountability '%s' doesn't exist on role '%s'"
-                  sample-acc-2 role-name)
-          (g/remove-accountability sample-anchor-with-acc role-name
-                                   sample-acc-2)))
-
-      (it "should not remove an accountability from a missing or empty role"
-        (should-not-update-missing-or-empty-roles g/remove-accountability
-          "removing accountability" sample-acc-1)))))
+    (should-handle-collection-properly g/add-accountability g/remove-accountability
+                                       :accountabilities "Accountability"
+                                       sample-anchor-with-acc
+                                       sample-anchor-with-accs
+                                       sample-acc-1
+                                       sample-acc-2)))

 ;; Section 2.2
 (describe "Lead Link Role"


test hook

test hook

--- src/main/cawala/api/read.clj
+++ src/main/cawala/api/read.clj
@@ -6,7 +6,7 @@
                      :person/relation :friend}
                  2  {:db/id 2 :person/name "Sally" :person/age 22
                      :person/relation :friend}
-                 3  {:db/id 3 :person/name "Allie" :person/age 58
+                 3  {:db/id 3 :person/name "Allie" :person/age 59
                      :person/relation :enemy}
                  4  {:db/id 4 :person/name "Zoe" :person/age 32
                      :person/relation :friend}


CLJS-1348: meta is printing for def at REPL

Coerce to boolean to additionally cover the
case that it is not false, while simultaneously
honoring ^boolean return annotation.

--- src/main/cljs/cljs/core.cljs
+++ src/main/cljs/cljs/core.cljs
@@ -8624,7 +8624,7 @@
 (declare print-map)

 (defn ^boolean print-meta? [opts obj]
-  (and (not (nil? (get opts :meta)))
+  (and (boolean (get opts :meta))
        (implements? IMeta obj)
        (not (nil? (meta obj)))))


Also fix the ClojureScript implementation of entity-for-data

--- src/main/workflo/macros/entity.cljs
+++ src/main/workflo/macros/entity.cljs
@@ -76,7 +76,8 @@

 (defn- entity-with-attr [attr]
   (some (fn [[_ entity]]
-          (some #{attr} (memoized-entity-attrs entity)))
+          (when (some #{attr} (memoized-entity-attrs entity))
+            entity))
         (registered-entities)))

 (def memoized-entity-with-attr


Remove 'by Paul'

Remove 'by Paul'

--- src-cljs/frontend/components/about.cljs
+++ src-cljs/frontend/components/about.cljs
@@ -191,7 +191,7 @@
            [:div.fact.col-xs-4
             [:h3.header "Born"]
             [:p.value "2011"]
-            [:p.caption "CircleCI was founded in 2011 by " [:a {:href "/about/team"} "Paul Biggar"]]]
+            [:p.caption "CircleCI was founded in 2011"]]
            [:div.fact.col-xs-4
             [:h3.header "Team"]
             [:p.value "25+"]


Add a legend to the project settings page

--- src-cljs/frontend/components/admin.cljs
+++ src-cljs/frontend/components/admin.cljs
@@ -278,7 +278,7 @@
             num-active-users (get-in app (conj state/license-path :seat_usage))]
         (html
          [:div.users
-          [:legend "Users"]
+          [:legend "User Administration"]

           [:div.card.detailed
            [:h3 "Active"]
@@ -345,19 +345,20 @@

     om/IRenderState
     (render-state [this {:keys [filter-str] :as state}]
-      (js/console.log (clj->js state))
       (html
-        (if-let [all-projects (:all-projects app)]
-          [:div
-           (card/basic
-             (om/build form/text-field {:value filter-str
-                                        :label "Filter projects"
-                                        :on-change #(om/set-state! owner {:filter-str (-> % .-target .-value)})}))
-           (om/build projects-table
-                     (filter-projects
-                       all-projects
-                       filter-str))]
-          (spinner))))))
+        [:div
+         [:legend "Project Administration"]
+         (if-let [all-projects (:all-projects app)]
+           [:div
+            (card/basic
+              (om/build form/text-field {:value filter-str
+                                         :label "Filter projects"
+                                         :on-change #(om/set-state! owner {:filter-str (-> % .-target .-value)})}))
+            (om/build projects-table
+                      (filter-projects
+                        all-projects
+                        filter-str))]
+           (spinner))]))))

 (defn boolean-setting-entry [item owner]
   (reify


Show flash notification when API token is added

--- src-cljs/frontend/controllers/api.cljs
+++ src-cljs/frontend/controllers/api.cljs
@@ -825,9 +825,15 @@

 (defmethod api-event [:create-api-token :success]
   [target message status {:keys [resp context]} state]
-  (-> state
-      (assoc-in state/new-user-token-path "")
-      (update-in state/user-tokens-path conj resp)))
+  (let [label (:label context)
+        label (if (empty? label)
+                label
+                (str "'" label "'"))]
+    (-> state
+        (assoc-in state/new-user-token-path "")
+        (update-in state/user-tokens-path conj resp)
+        (state/add-flash-notification (gstring/format "API token %s added successfully."
+                                                      label)))))

 (defmethod api-event [:delete-api-token :success]
   [target message status {:keys [resp context]} state]


Update builtins.clj

Update builtins.clj

--- src/iyye/subcon/knowledge/builtins.clj
+++ src/iyye/subcon/knowledge/builtins.clj
@@ -42,7 +42,7 @@
           p2-name (:Name (:atom p2-type))
           p1-data (:Data p1-type)
           p2-data (:Data p2-type)]
-      (and (= p1-name (:super p2-data))
+      (and (= p1-name (:super p2-data))                     ; FIXME Yumzia modal logic
            (= p2-name (:sub p1-data))))))

 (defn iyye_is_type_function [p1-types p2-types]
@@ -62,11 +62,12 @@
 (defn iyye_is_type_create_function [p1-name p2-type]
   (let [p1-type (words/create-iyye-type p1-name)]
     (when (and p1-type p2-type)
-      (let [new-p1-type (assoc p1-type :Relations (conj (:Relations p1-type) ))])
+      (let [new-p1-type (assoc p1-type :Relations (conj (:Relations p1-type)))
+            p2-subtypes (assoc @iyye_is_type :Data {:sub (:Name (:atom p1-type))})
+            new-p2-type (assoc p2-type :Relations p2-subtypes)]
       (do
-        ()
-        ()
-        ()))))
+        (words/set-iyye-type! new-p1-type)
+        (words/set-iyye-type! new-p2-type))))))

 (defn iyye_consists_function [p1 p2]
   (let [])
@@ -88,20 +89,23 @@
 (defn create-iyye-builtin-relation [name types func pred-func]
   (words/create-iyye-relation name
                               (words/->Iyye_ModalPredicate :IYE :AXIOM (persistence/current-time-to-string) :ALWAYS)
-                              types func pred-func))
+                              types func pred-func true))
+
+(defn- create-entry [entry] {(:Uname (:atom entry)) entry})

 (defn- init-builtin-words []
-  (let [actor (words/create-iyye-type "actor")
-        ai (words/create-iyye-type "ai")
-        iyye (words/create-iyye-type "iyye")
-        human (words/create-iyye-type "human")
-        yumzya (words/create-iyye-type "yumzya")]
+  (let [actor (words/create-iyye-type "actor" true)
+        ai (words/create-iyye-type "ai" true)
+        iyye (words/create-iyye-type "iyye" true)
+        human (words/create-iyye-type "human" true)
+        yumzya (words/create-iyye-type "yumzya" true)]
     (dosync (ref-set iyye_actor actor))
     (dosync (ref-set iyye_ai ai))
     (dosync (ref-set iyye_iyye iyye))
     (dosync (ref-set iyye_human human))
     (dosync (ref-set iyye_yumzya yumzya))
-    (dosync (alter words/noun-words conj actor ai iyye human yumzya))))
+    (dosync (alter words/noun-words conj (create-entry actor)
+                   (create-entry ai) (create-entry iyye) (create-entry human) (create-entry yumzya)))))

 (defn- init-builtin-relations []
   (let [t_is (create-iyye-builtin-relation "is" ["type" "type"] iyye_is_type_function iyye_is_type_predicate_function)
@@ -111,8 +115,7 @@
     (dosync (ref-set iyye_is_type t_is))
     (dosync (ref-set iyye_consists_type consistsof))
     (dosync (ref-set iyye_create_instance instof))
-    (dosync (alter words/action-words conj t_is t_is2 consistsof instof))))
-
+    (dosync (alter words/action-words conj (create-entry t_is) (create-entry t_is2) (create-entry consistsof) (create-entry instof)))))

 (defn- apply-builtin-relations []
   (do
@@ -131,8 +134,9 @@

 (defn- init-db-kb []
   (let []
-      (dosync (alter words/action-words #(apply conj %1 %2) (persistence/read-knowledge-from-db "relations" {:When :ALWAYS})))
-      (dosync (alter words/noun-words #(apply conj %1 %2) (persistence/read-knowledge-from-db "types" {:When :ALWAYS})))
+    (dosync (alter words/action-words #(apply conj %1 %2) (persistence/read-knowledge-from-db "relations" {}))) ; {:When :ALWAYS}
+    (dosync (alter words/noun-words #(apply conj %1 %2) (persistence/read-knowledge-from-db "types" {} ; {:When :ALWAYS}
+    )))
       ; others
     ))


running forever works on quotaless user

running forever works on quotaless user

--- test/celestial/integration/persistency/quotas.clj
+++ test/celestial/integration/persistency/quotas.clj
@@ -5,7 +5,7 @@
     [celestial.redis :refer (clear-all)]
     [celestial.fixtures.core :refer (is-type? with-admin)]
     [celestial.fixtures.data :refer (redis-prox-spec user-quota)]
-    [celestial.fixtures.populate :refer (add-types)]
+    [celestial.fixtures.populate :refer (add-types add-users)]
     [celestial.persistency :as p]
     [celestial.persistency.systems :as s]
     [celestial.persistency.quotas :as q]))
@@ -13,6 +13,7 @@
 (defn quotas-populate []
   (clear-all)
   (add-types)
+  (add-users)
   (p/add-user {:username "foo" :password "bla" :roles {} :envs []})
   (q/add-quota (assoc-in user-quota [:quotas :proxmox :used] nil)) )

@@ -35,7 +36,16 @@
         (s/add-system redis-prox-spec') => truthy
         (s/add-system redis-prox-spec') => (throws ExceptionInfo (is-type? :celestial.persistency.quotas/quota-limit-reached))
         (s/delete-system id) => truthy
-        (s/add-system redis-prox-spec') => truthy)))
+        (s/add-system redis-prox-spec') => truthy))))
+
+  (fact "quotasless user can run forever" :integration :redis :quota
+    (let [redis-prox-admin (assoc redis-prox-spec :owner "admin")]
+      (with-admin
+        (s/add-system redis-prox-admin) => truthy
+        (s/add-system redis-prox-admin) => truthy
+        (s/add-system redis-prox-admin) => truthy
+        (s/add-system redis-prox-admin) => truthy
+        ))
     )
   )


Generate invocations for input

Generate invocations for input

--- test/onyx_peers/jobs/basic_test.clj
+++ test/onyx_peers/jobs/basic_test.clj
@@ -15,6 +15,9 @@
             [taoensso.timbre :refer [fatal info]]
             [onyx.api]))

+(def input
+  (vec (range 6)))
+
 (deftest ^:test-jepsen-tests basic-test
   (let [id (java.util.UUID/randomUUID)
         config (load-config)
@@ -23,6 +26,7 @@
         test "basic-clojure-test"
         version "dummy-version"
         test-setup {:job-params {:batch-size 1}
+                    :job-type :simple-job
                     :nemesis :na
                     :time-limit 800 ; unused in this test
                     :awake-mean 200 ; unused in this test
@@ -33,21 +37,18 @@
                     :n-peers 3}
         fake-clients 5
         n-peers-total (* fake-clients (:n-peers test-setup))
-        events [{:type :invoke :f :add :value 1}
-                {:type :invoke :f :add :value 2}
-                {:type :invoke :f :add :value 3}
-                {:type :invoke :f :add :value 4}
-                {:type :invoke :f :add :value 5}
-                {:type :invoke :f :add :value 6}
-                {:type :invoke
-                 :f :submit-job
-                 :job-type :simple-job
-                 :job-num 0
-                 :n-jobs (:n-jobs test-setup)
-                 :params (:job-params test-setup)}
-                {:type :invoke :f :close-ledgers-await-completion}
-                {:type :invoke :f :read-ledgers :task :persist}
-                {:type :invoke :f :read-peer-log :timeout 1000}]
+        events (into (mapv (fn [v]
+                             {:type :invoke :f :add :value v})
+                           input)
+                     [{:type :invoke
+                       :f :submit-job
+                       :job-type (:job-type test-setup)
+                       :job-num 0
+                       :n-jobs (:n-jobs test-setup)
+                       :params (:job-params test-setup)}
+                      {:type :invoke :f :close-ledgers-await-completion}
+                      {:type :invoke :f :read-ledgers :task :persist}
+                      {:type :invoke :f :read-peer-log :timeout 1000}])
         {:keys [client checker model generator] :as basic-test}
         (onyx-test/jepsen-test env-config peer-config test-setup test version (gen/seq events))]
     (with-test-env [test-env [n-peers-total env-config peer-config]]


write-batch-timeout -> write-batch-test

write-batch-timeout -> write-batch-test

--- test/onyx/state/log/bookkeeper_stateful_check.clj
+++ test/onyx/state/log/bookkeeper_stateful_check.clj
@@ -30,7 +30,7 @@
 (def peer-config (assoc (:peer-config config)
                         :onyx/id id
                         :onyx.bookkeeper/write-batch-size 2
-                        :onyx.bookkeeper/write-batch-timeout 5))
+                        :onyx.bookkeeper/write-batch-backoff 5))

 (def bookkeeper-peer-state (atom nil))

@@ -110,7 +110,7 @@
    :real/postcondition (fn [state] true)
    :initial-state #'init-state})

-#_(deftest log-test-correct
+(deftest log-test-correct
   (with-redefs [log-bk/assign-bookkeeper-log-id-spin (fn [event new-ledger-id]
                                                        (swap! bookkeeper-peer-state update :ledger-ids conj new-ledger-id))
                 log-bk/event->ledger-ids (fn [event]


formatting reactor fn

formatting reactor fn

--- src/app/cljs/one/sample/controller.cljs
+++ src/app/cljs/one/sample/controller.cljs
@@ -37,8 +37,8 @@
   (callback (get @docs (keyword id))))

 (dispatch/react-to #{:document-requested}
-                   (fn [t d] (get-document d #(dispatch/fire
-                                               :document-retrieved %))))
+                   (fn [t d]
+                     (get-document d #(dispatch/fire :document-retrieved %))))

 (dispatch/react-to #{:init :workspace}
                    (fn [t d] (action (assoc d :type t))))


forward :foreign-libs

forward :foreign-libs

--- sidecar/src/figwheel_sidecar/auto_builder.clj
+++ sidecar/src/figwheel_sidecar/auto_builder.clj
@@ -35,7 +35,7 @@
 (defn merge-build-into-server-state [figwheel-server {:keys [id build-options]}]
   (merge figwheel-server
          (if id {:build-id id} {})
-         (select-keys build-options [:output-dir :output-to :recompile-dependents])))
+         (select-keys build-options [:output-dir :output-to :recompile-dependents :foreign-libs])))

 (defn check-changes [figwheel-server build]
   (let [{:keys [additional-changed-ns build-options id old-mtimes new-mtimes]} build]


Add lein-drip

Add lein-drip

--- share/profiles.clj
+++ share/profiles.clj
@@ -3,6 +3,7 @@
                   "lint" ["do" ["cljfmt" "check"] "kibit"]
                   "fix" ["do" ["cljfmt" "fix"] ["kibit" "--replace" "--interactive"]]}
         :plugins [
+                  [lein-drip "0.1.1-SNAPSHOT"];; faster JVM
                   [venantius/ultra "0.5.1"];; pretty print
                   [lein-auto "0.1.3"];; watch tasks
                   [lein-try "0.4.3"];; REPL experimenting


portable exceptions

portable exceptions

--- src/babel/espanol/morphology/verbs.cljc
+++ src/babel/espanol/morphology/verbs.cljc
@@ -243,7 +243,7 @@
   (let [infinitive (reflexive-to-infinitive (get-in word [:espanol]))
         ar-type (try (re-find #"ar$" infinitive)
                      (catch Exception e
-                       (throw (Exception. (str "Can't regex-find on non-string: " infinitive " from word: " word)))))
+                       (exception (str "Can't regex-find on non-string: " infinitive " from word: " word))))
         er-type (re-find #"er$" infinitive)
         ir-type (re-find #"ir$" infinitive)
         stem (string/replace infinitive #"[iae]r$" "")
@@ -344,7 +344,7 @@
          (if (= suppress-morph-exceptions true)
            (do (log/warn message)
                "??")
-           (throw (Exception. message))))))))
+           (exception message)))))))

 (defn present [word & [ {usted :usted
                          vosotros :vosotros
@@ -352,7 +352,7 @@
   (let [infinitive (reflexive-to-infinitive (get-in word '(:espanol)))
         ar-type (try (re-find #"ar$" infinitive)
                      (catch Exception e
-                       (throw (Exception. (str "Can't regex-find on non-string: " infinitive " from word: " word)))))
+                       (exception (str "Can't regex-find on non-string: " infinitive " from word: " word))))
         er-type (re-find #"er$" infinitive)
         ir-type (re-find #"ir$" infinitive)

@@ -449,7 +449,7 @@
        (if (= suppress-morph-exceptions true)
          (do (log/warn message)
              "??")
-         (throw (Exception. message)))))))
+         (exception message))))))

 (declare irregular-preterito)
 (declare regular-preterito)
@@ -507,7 +507,7 @@
   (let [infinitive (reflexive-to-infinitive (get-in word '(:espanol)))
         ar-type (try (re-find #"ar$" infinitive)
                      (catch Exception e
-                       (throw (Exception. (str "Can't regex-find on non-string: " infinitive " from word: " word)))))
+                       (exception (str "Can't regex-find on non-string: " infinitive " from word: " word))))
         er-type (re-find #"er$" infinitive)
         ir-type (re-find #"ir$" infinitive)

@@ -605,4 +605,5 @@
        (if (= suppress-morph-exceptions true)
          (do (log/warn message)
              "??")
-         (throw (Exception. message)))))))
+         (exception message))))))
+


set server-port to x-forwarded-port

set server-port to x-forwarded-port

--- src/blog/web_server/web_server_impl.clj
+++ src/blog/web_server/web_server_impl.clj
@@ -12,6 +12,28 @@
             [blog.handler :as h]))

+;;; insert forwarded port into request-map
+
+(def default-port-header
+  "The default header used in wrap-forwarded-port (x-forwarded-port)."
+  "x-forwarded-port")
+
+(defn wrap-forwarded-port
+  "Middleware that changes the :server-port of the request map to the value present
+  in a request header. This is useful if your application sits behind a
+  reverse proxy or load balancer that handles the SSL transport.
+
+  The header defaults to x-forwarded-port."
+  ([handler]
+     (wrap-forwarded-port handler default-port-header))
+  ([handler header]
+     (fn [req]
+       (let [header  (str/lower-case header)
+             default (:server-port req)
+             port    (Integer/parseInt (get-in req [:headers header] default))]
+         (handler (assoc req :server-port port))))))
+
+
 ;;; debug-tracer

 (defn wrap-tracer [handler name]
@@ -144,6 +166,9 @@
           (ssl/wrap-ssl-redirect h (select-keys ssl #{:ssl-port}))
           (if reverse-proxy?
             (ssl/wrap-forwarded-scheme h)
+            h)
+          (if reverse-proxy?
+            (wrap-forwarded-port h)
             h))))

 (defn make-handler [this]


Added too many functions to remember. K-means now works.

--- src/brevis/math/logistic_regression.clj
+++ src/brevis/math/logistic_regression.clj
@@ -15,6 +15,26 @@
       (rand)
       (unchecked-negate (lrand)))))

+(defn abs
+  "Returns absolute value of a number"
+  [num]
+  (if (pos? num)
+    num
+    (unchecked-negate num)))
+
+(defn csv-to-matrix
+  [path]
+  (map #(seq (clojure.string/split % #", "))
+       (clojure.string/split-lines (slurp path))))
+
+(defn nest-seq-to-csv
+  [seq path]
+  (let [width (count (first seq))
+        string-seq (for [x (partition width (map str (flatten seq)))]
+                     (apply str (interpose ", " x)))
+        output-string (apply str (interpose "\n" string-seq))]
+    (spit path output-string)))
+
 (defn normalize-data ;should this be abs?
   "subtracts mean vector from all row vectors"
   [mat]
@@ -22,26 +42,118 @@
         width (matrix-width mat)
         mean-vector (map #(/ % height) (matrix-to-seq (sum-rows mat)))
         normalized-data (seq-to-matrix width height
-                                       (for [x1 (partition width (matrix-to-seq mat))]
-                                         (map #(- %1 %2) x1 mean-vector)))
+                                       (flatten
+                                         (for [x1 (partition width (matrix-to-seq mat))]
+                                           (map #(- %1 %2) x1 mean-vector))))
         ]
     normalized-data))
+

 (defn theta-init
   "Random m x n matrix with all element values between -1 & 1."
   [num]
   (seq-to-matrix num 1 (repeatedly num #(theta-rand))))

+(defn pca
+  ""
+  [mat]
+  (let [data (normalize-data mat)
+        sigma (divide (matrix-mult data (transpose data)) (matrix-width data))
+        ]))
+
+(defn matrix-to-rvec-seq
+  "takes matrix and turns into sequence of row vectors."
+  [mat]
+  (map #(seq-to-matrix 1 (matrix-width mat) %)
+       (partition (matrix-width mat) (matrix-to-seq mat))))
+
+(defn rvec-seq-to-matrix ; most likely will break when seq-to-matrix is fixed
+  "takes row vector sequence and returns matrix"
+  [rvec-seq]
+  (let [new-seq-nest (map #(matrix-to-seq %) rvec-seq)
+        height (count new-seq-nest)
+        width (count (first new-seq-nest))
+        new-mat (seq-to-matrix width height (flatten new-seq-nest))] ;Seq-to-matrix
+    new-mat))
+
+(defn rvec-seq-to-seq
+  "takes a row vector sequence and returns nested sequence."
+  [rvec-seq]
+  (map matrix-to-seq rvec-seq))
+
+(defn seq-to-rvec-seq
+  "takes a nested sequence and returns a row vector sequence."
+  [seq]
+  (map #(seq-to-matrix 1 (count (first seq)) %) seq))
+
+(defn rvec-seq-sort
+  ([rvec-seq] (rvec-seq-sort rvec-seq :main))
+  ([rvec-seq option]
+    (let [sorted (sort-by #(apply + %) (rvec-seq-to-seq rvec-seq))]
+      (if (= option :seq)
+        sorted
+        (seq-to-rvec-seq sorted)))))
+
+(defn k-start
+  "simple k-start for k-means with no repeat centroids"
+  ([k mat] (k-start k mat (matrix-to-rvec-seq mat)))
+  ([k mat rvec-seq]
+  (let [start (repeatedly k #(nth rvec-seq (lrand-int (matrix-height mat))))
+        copies? (flatten
+                  (for [x start]
+                    (map #(= x %) start)))
+        truths (count (filter true? copies?))
+        total (count start)]
+    (if (= truths total)
+      start
+      (k-start k mat rvec-seq)))))
+
+
+(defn k-means ; will most likely break if seq-to-matrix is fixed
+  "k-means clustering algorithm"
+  [k mat]
+  (let [rvec-seq (matrix-to-rvec-seq mat)]
+    (loop [iterations 0
+           means (k-start k mat rvec-seq)]
+      (let [new-clusters (group-by
+                           #(first
+                              (apply min-key second
+                                     (map-indexed vector
+                                                  (for [x1 means]
+                                                    (frobenius-norm
+                                                      (sub x1 %)))))) rvec-seq)
+
+            new-means (for [x (map second new-clusters)]
+                        (matrix-map #(/ % (count x))
+                                   (sum-rows (transpose (rvec-seq-to-matrix (flatten x)))))) ; what is up with transpose?
+
+            mean-distance (apply + (map #(frobenius-norm (sub %1 %2)) (rvec-seq-sort means) (rvec-seq-sort new-means)))
+
+            end (if (<= mean-distance 0)
+                  true
+                  false)]
+
+      (if (or (= end true) (> iterations 2000))
+        {:clusters new-clusters
+         :centroids (rvec-seq-sort new-means )
+         ;:old-centroids means
+         :iterations iterations
+         ;:distance mean-distance
+         }
+        (recur (inc iterations)
+               new-means))))))
+
+
 (defn logistic-regression
   "Logistic regression. x feature matrix, y label vector."
   ([x y stop] (logistic-regression x y stop (theta-init (matrix-width x))))
   ([x y stop theta-start]
-    (loop [start 0
+    (loop [iteration 0
            theta theta-start
            ]
-      (if (= stop start)
+      (if (= stop iteration)
         theta
-        (recur (inc start)
+        (recur (inc iteration)
                (matrix-mult x
                             (transpose (sub y
                                             (matrix-pmap sigmoid


Configs endpoint added

Configs endpoint added

--- src/toggler/handler.clj
+++ src/toggler/handler.clj
@@ -57,7 +57,25 @@
    (backup-config)
    (spit (str @filepath "config.json") (encode @cfg)))
   ([filename]
-   (spit (str @filepath (str @filename ".json")) (encode @cfg))))
+   (spit (str @filepath (str filename ".json")) (encode @cfg))))
+
+(defn only-files
+  "Filter a sequence of files/directories by the .isFile property of
+  java.io.File"
+  [file-s]
+  (filter #(.isFile %) file-s))
+
+(defn file-names
+  "Return the .getName property of a sequence of files"
+  [file-s]
+  (map #(.getName %) file-s))
+
+(defn getconfigs
+  ([]
+   (->> (file-seq (clojure.java.io/file @filepath))
+        (only-files)
+        (file-names)
+        (vec))))

 (defresource status
   :allowed-methods [:get]
@@ -148,11 +166,17 @@
   :available-media-types ["application/json"]
   :post! (fn [_] (reset-cfg filename))
   :handle-ok (encode {:filename filename}) )
+
+(defresource get-configs
+ :allowed-methods [:get]
+ :available-media-types ["application/json"]
+ :handle-ok (fn [_] (encode (getconfigs))))

 (defroutes app-routes
   (GET "/" [] status)
   (PUT "/reconfigure" {body :body} (let [bodydecoded (decode (slurp body) true)]
                                      (reconfigure bodydecoded)))
+  (GET "/configs" [] get-configs)
   (PUT "/reset" [] reset-config)
   (POST "/reset" {body :body} (let [bodydecoded (decode (slurp body) true)]
                                (load-config-from-file (get bodydecoded :filename))))


Add IFn.invoke implementations to containers

--- src/main/clojure/com/stuartsierra/lazytest2.clj
+++ src/main/clojure/com/stuartsierra/lazytest2.clj
@@ -121,30 +121,34 @@
 ;;; Container types

 (deftype SimpleContainer [children] :as this
-  TestInvokable
-  (invoke-test [active]
-    (try
-     (TestResults this (map #(invoke-test % active) children))
-     (catch Throwable t
-       (TestThrown this active t)))))
+  clojure.lang.IFn
+    (invoke [] (invoke-test this {}))
+  TestInvokable
+    (invoke-test [active]
+      (try
+       (TestResults this (map #(invoke-test % active) children))
+       (catch Throwable t
+         (TestThrown this active t)))))

 (deftype ContextualContainer [contexts children] :as this
-  TestInvokable
-  (invoke-test [active]
-    (let [merged (reduce open-context active contexts)
-          states (map merged contexts)]
-      (try
-       (let [results (map #(invoke-test % active) children)]
-         ;; Force non-lazy evaluation when contexts need closing:
-         (when (some has-after? contexts) (dorun results))
-         (TestResults this results))
-       (catch Throwable t
-         (TestThrown this states t))
-       (finally
-        (reduce close-context merged
-                ;; Only close contexts that weren't active at start:
-                (filter #(not (contains? active %))
-                        (reverse contexts))))))))
+  clojure.lang.IFn
+    (invoke [] (invoke-test this {}))
+  TestInvokable
+    (invoke-test [active]
+      (let [merged (reduce open-context active contexts)
+            states (map merged contexts)]
+        (try
+         (let [results (map #(invoke-test % active) children)]
+           ;; Force non-lazy evaluation when contexts need closing:
+           (when (some has-after? contexts) (dorun results))
+           (TestResults this results))
+         (catch Throwable t
+           (TestThrown this states t))
+         (finally
+          (reduce close-context merged
+                  ;; Only close contexts that weren't active at start:
+                  (filter #(not (contains? active %))
+                          (reverse contexts))))))))

 ;;; Public API


Badge advert content fix

Badge advert content fix

--- src/clj/salava/extra/application/db.clj
+++ src/clj/salava/extra/application/db.clj
@@ -162,6 +162,7 @@
     {:badge_content_id
      (b/save-badge-content! ctx
                             {:id ""
+                             :language_code ""
                              :name (:name badge)
                              :image_file (u/file-from-url ctx (:image badge))
                              :description (:description badge)
@@ -170,6 +171,7 @@
      :issuer_content_id
      (b/save-issuer-content! ctx
                              {:id ""
+                              :language_code ""
                               :name (:name client)
                               :description (:description client)
                               :url (:url client)
@@ -180,8 +182,9 @@
      :criteria_content_id
      (b/save-criteria-content! ctx
                                {:id ""
-                                :html_content criteria
-                                :markdown_content (u/alt-markdown criteria)})}))
+                                :language_code ""
+                                :url (:criteria_url data)
+                                :markdown_text (u/alt-markdown criteria)})}))

 (defn publish-badge [ctx data]
   (try


Stop using potentially not-real feature of require

--- src/cljs/comic_reader/ui/site_list.cljs
+++ src/cljs/comic_reader/ui/site_list.cljs
@@ -1,12 +1,11 @@
 (ns comic-reader.ui.site-list
-  (:refer-clojure :exclude [get set]
-                  :rename {get cget})
+  (:refer-clojure :exclude [get set])
   (:require [re-frame.core :as re-frame]
             [reagent.ratom :refer-macros [reaction]]
             [comic-reader.ui.base :as base]))

 (defn get [db]
-  (cget db :site-list))
+  (clojure.core/get db :site-list))

 (defn set [db [_ sites]]
   (assoc db :site-list sites))


run scheduler every 15 mins

run scheduler every 15 mins

--- src/com/ig/swagger/search/collector.clj
+++ src/com/ig/swagger/search/collector.clj
@@ -156,7 +156,7 @@
      :initial-load-task (future (run-indexing))
      :index-fn          run-indexing
      :scheduled-task    (schedule/schedule                  ;; TODO: make schedule configurable
-                          {:minute (range 0 60 5)} run-indexing)}))
+                          {:minute (range 0 60 15)} run-indexing)}))

 (defn destroy-component [{:keys [scheduled-task json-client http-client initial-load-task]}]
     (when scheduled-task


run with multiple threads

run with multiple threads

--- src/wb_es/bulk/core.clj
+++ src/wb_es/bulk/core.clj
@@ -1,6 +1,7 @@
 (ns wb-es.bulk.core
   (:gen-class)
   (:require [clj-http.client :as http]
+            [clojure.core.async :refer [>! <! >!! <!! go chan buffer close!]]
             [cheshire.core :as json]
             [datomic.api :as d]
             [mount.core :as mount]
@@ -48,10 +49,31 @@
       (http/put index-url {:headers {:content-type "application/json"}
                            :body (json/generate-string index-settings)})
       (let [eids (get-eids-by-type db :go-term/id)
-            step 100
-            batches (partition step step [] eids)]
-        (doseq [batch batches]
-          (run-index-batch db batch))))))
+            n-max (dec (count eids))
+            step 1000
+            batches (partition step step [] eids)
+            n-threads 4
+            scheduler (chan n-threads)]
+        (dotimes [i n-threads]
+          (go
+            (loop []
+              (if-let [job (<! scheduler)]
+                ;; normal batches won't be nil
+                ;; only get nil when channel is closed
+                (do
+                  (let [n-start (* (:index job) step)
+                        n-end (min n-max (+ n-start step))]
+                    (println
+                     (format "Processing %s - %s" n-start n-end)))
+                  (run-index-batch db (:data job))
+                  (recur))
+                ))))
+        (do
+          (doseq [[i batch] (keep-indexed (fn [i b] [i b]) batches)]
+            (let [job {:index i :data batch}]
+              (>!! scheduler job)))
+          (close! scheduler))
+        ))))

 (defn -main
   "I don't do a whole lot ... yet."
@@ -59,5 +81,5 @@
   (do
     (println "Hello, Bulky World!")
     (mount/start)
-    (run)
+    (time (run))
     (mount/stop)))


uses status code of 503 for request streaming timeout (#807)

--- waiter/src/waiter/process_request.clj
+++ waiter/src/waiter/process_request.clj
@@ -276,6 +276,7 @@
                     (statsd/inc! metric-group "request_bytes" unreported-bytes-to-statsd))
                   (let [description-map {:bytes-pending bytes-read
                                          :bytes-streamed bytes-streamed
+                                         :status 503
                                          :streaming-timeout-ms streaming-timeout-ms}]
                     (log/error "unable to stream request bytes" description-map)
                     (stream-error-handler (ex-info "unable to stream request bytes" description-map)))))


Synchronizes scrollbars on scrolling

Synchronizes scrollbars on scrolling

Resolves #15

--- src/wordsmith/core.cljs
+++ src/wordsmith/core.cljs
@@ -5,7 +5,8 @@
             [wordsmith.persistence :as p]
             [cljs.core.async :refer [put! chan <!]]
             [goog.events :as events])
-  (:import [goog.events EventType]))
+  (:import [goog.events EventType]
+           [goog.async Throttle]))

 (enable-console-print!)

@@ -223,6 +224,8 @@
     :change (change-document app params)
     :new    (new-document app)))

+;; Hot keys
+
 (defn listen-to-hotkeys
   "Listens to KEYDOWN events using goog.events and checks for Ctrl+S or
   Cmd+S. When identified, sends a :save command on app channel."
@@ -234,6 +237,29 @@
        (.preventDefault %)
        (put! (:channel @app) [:save nil]))))

+;; Scroll both
+
+(defn parse-int [x]
+  (js/parseInt x 10))
+
+(defn set-scroll-top [source target]
+  "Calculates the progress of scrolling in source as a percentage and
+  sets the target scroll to the same relative place."
+  (let [source-scroll-top (parse-int (.-scrollTop source))
+        source-height     (parse-int (.-scrollHeight source))
+        source-percentage (/ source-scroll-top source-height)
+        target-height     (parse-int (.-scrollHeight target))]
+    (set! (.-scrollTop target) (* source-percentage target-height))))
+
+(defn synchronize-scroll []
+  "Attaches an event listener to input-area that synchronizes the scroll
+  position to output-area. Uses Throttle to avoid triggering too often."
+  (let [input-area (. js/document (getElementById "input-area"))
+        output-area (. js/document (getElementById "output-area"))
+        throttle (Throttle. #(set-scroll-top input-area output-area) 50)]
+    (events/listen input-area EventType/SCROLL
+      #(.fire throttle))))
+
 ;; The main app

 (defn wordsmith-app
@@ -246,13 +272,17 @@
       "Fetches document titles and starts the asynchronous command event
       dispatch loop which handles all major app state changing events.
       Also attaches a KEYDOWN event listener to the page, for hot keys."
-      (listen-to-hotkeys app)
       (om/update! app :titles (p/get-all-titles))
       (let [channel (:channel app)]
         (go-loop []
           (let [[command params] (<! channel)]
             (dispatch command params app)
             (recur)))))
+    om/IDidMount
+    (did-mount [_]
+      "Sets up event listeners when app has been properly loaded."
+      (listen-to-hotkeys app)
+      (synchronize-scroll))
     om/IRender
     (render [_]
       "Renders the app components in a container."


Fixes minor bug, gets rid of unnecessary state references

--- src/wordsmith/core.cljs
+++ src/wordsmith/core.cljs
@@ -6,11 +6,11 @@

 (def app-state (atom {}))

-(defn handle-input [event app owner]
-  (om/set-state! owner :input (.. event -target -value))
-  (let [input (om/get-state owner :input)
+(defn handle-input [event owner]
+  (let [input (.. event -target -value)
         output (.marked js/window input)
         output-area (om/get-node owner "output-area")]
+    (om/set-state! owner :input (.. event -target -value))
     (set! (.-innerHTML output-area) output)))

 (defn wordsmith-app [app owner]
@@ -19,9 +19,9 @@
     (init-state [_]
       {:input ""})
     om/IRenderState
-    (render-state [_ {:keys [input]}]
+    (render-state [_ _]
       (dom/div #js {:className "container"}
-        (dom/textarea #js {:onInput #(handle-input % app owner)
+        (dom/textarea #js {:onInput #(handle-input % owner)
                            :value input})
         (dom/div #js {:ref "output-area"})))))


tests for FCC, Notoriety, Stimhack; re-alphabetize

--- src/clj/test/cards-events.clj
+++ src/clj/test/cards-events.clj
@@ -6,7 +6,6 @@
     (new-game (default-corp) (default-runner [(qty "Account Siphon" 3)]))
     (take-credits state :corp) ; pass to runner's turn by taking credits
     (is (= 8 (:credit (get-corp))))
-
     ; play Account Siphon, use ability
     (play-run-event state (first (:hand (get-runner))) :hq)
     (prompt-choice :runner "Run ability")
@@ -53,138 +52,6 @@
     (let [tmc (get-in @state [:runner :rig :facedown 0])]
       (is (:facedown (refresh tmc)) "Tri-maf Contact is facedown")
       (is (= 3 (count (:hand (get-runner)))) "No meat damage dealt by Tri-maf's leave play effect"))))
-
-(deftest demolition-run
-  "Demolition Run - Trash at no cost"
-  (do-game
-    (new-game (default-corp [(qty "False Lead" 1) (qty "Shell Corporation" 1)(qty "Hedge Fund" 3)])
-              (default-runner [(qty "Demolition Run" 1)]))
-    (core/move state :corp (find-card "False Lead" (:hand (get-corp))) :deck) ; put False Lead back in R&D
-    (play-from-hand state :corp "Shell Corporation" "R&D") ; install upgrade with a trash cost in root of R&D
-    (take-credits state :corp 2) ; pass to runner's turn by taking credits
-    (play-from-hand state :runner "Demolition Run")
-    (is (= 3 (:credit (get-runner))) "Paid 2 credits for the event")
-    (prompt-choice :runner "R&D")
-    (is (= [:rd] (get-in @state [:run :server])) "Run initiated on R&D")
-    (prompt-choice :runner "OK") ; dismiss instructional prompt for Demolition Run
-    (core/no-action state :corp nil)
-    (core/successful-run state :runner nil)
-    (let [demo (get-in @state [:runner :play-area 0])] ; Demolition Run "hack" is to put it out in the play area
-      (prompt-choice :runner "Unrezzed upgrade in R&D")
-      (card-ability state :runner demo 0)
-      (is (= 3 (:credit (get-runner))) "Trashed Shell Corporation at no cost")
-      (prompt-choice :runner "Card from deck")
-      (card-ability state :runner demo 0)  ; trash False Lead instead of stealing
-      (is (= 0 (:agenda-point (get-runner))) "Didn't steal False Lead")
-      (is (= 2 (count (:discard (get-corp)))) "2 cards in Archives")
-      (is (empty? (:prompt (get-runner))) "Run concluded"))))
-
-(deftest sure-gamble
-  "Sure Gamble"
-  (do-game
-    (new-game (default-corp) (default-runner))
-    (take-credits state :corp)
-    (is (= 5 (:credit (get-runner))))
-    (core/play state :runner {:card (first (:hand (get-runner)))})
-    (is (= 9 (:credit (get-runner))))))
-
-;Surge and virus counter flag tests
-(deftest virus-counter-flag-on-enter
-  "Set counter flag when virus card enters play with counters"
-  (do-game
-    (new-game (default-corp) (default-runner [(qty "Surge" 1) (qty "Imp" 1) (qty "Crypsis" 1)]))
-    (take-credits state :corp)
-    (play-from-hand state :runner "Imp")
-    (let [imp (get-in @state [:runner :rig :program 0])]
-      (is (get-in imp [:added-virus-counter]) "Counter flag was not set on Imp")
-      )))
-
-(deftest virus-counter-flag-on-add-prop
-  "Set counter flag when add-prop is called on a virus"
-  (do-game
-    (new-game (default-corp)
-              (default-runner [(qty "Crypsis" 1)]))
-    (take-credits state :corp)
-    (play-from-hand state :runner "Crypsis")
-    (let [crypsis (get-in @state [:runner :rig :program 0])]
-      (card-ability state :runner crypsis 2) ;click to add a virus counter
-      (is (= 1 (get-in (refresh crypsis) [:counter])) "Crypsis did not add a virus token")
-      (is (get-in (refresh crypsis) [:added-virus-counter] "Counter flag was not set on Crypsis"))
-      )))
-
-(deftest virus-counter-flag-clear-on-end-turn
-  "Clear the virus counter flag at the end of each turn"
-  (do-game
-    (new-game (default-corp)
-              (default-runner [(qty "Crypsis" 1)]))
-    (take-credits state :corp)
-    (play-from-hand state :runner "Crypsis")
-    (let [crypsis (get-in @state [:runner :rig :program 0])]
-      (card-ability state :runner crypsis 2) ;click to add a virus counter
-      (take-credits state :runner 2)
-      (take-credits state :corp 1)
-      (is (not (get-in (refresh crypsis) [:added-virus-counter])) "Counter flag was not cleared on Crypsis")
-      )))
-
-(deftest surge-valid-target
-  "Add counters if target is a virus and had a counter added this turn"
-  (do-game
-    (new-game (default-corp)
-              (default-runner [(qty "Imp" 1) (qty "Surge" 1)]))
-    (take-credits state :corp)
-    (play-from-hand state :runner "Imp")
-    (let [imp (get-in @state [:runner :rig :program 0])]
-      (is (= 2 (get-in imp [:counter])))
-      (play-from-hand state :runner "Surge")
-      (prompt-select :runner imp)
-      (is (= 4 (get-in (refresh imp) [:counter])))
-      )))
-
-(deftest surge-target-not-virus
-  "Don't fire surge if target is not a virus"
-  (do-game
-    (new-game (default-corp)
-              (default-runner [(qty "Security Testing" 1) (qty "Surge" 1)]))
-    (take-credits state :corp)
-    (play-from-hand state :runner "Security Testing")
-    (let [st (get-in @state [:runner :rig :resource 0])]
-      (play-from-hand state :runner "Surge")
-      (prompt-select :runner st)
-      (is (not (contains? st :counter)))
-      )
-    ))
-
-(deftest surge-target-no-token-this-turn
-  "Don't fire surge if target does not have virus counter flag set"
-  (do-game
-    (new-game (default-corp)
-              (default-runner [(qty "Imp" 1) (qty "Surge" 1)]))
-    (take-credits state :corp)
-    (play-from-hand state :runner "Imp")
-    (let [imp (get-in @state [:runner :rig :program 0])]
-      (is (= 2 (get-in imp [:counter])))
-      (take-credits state :runner 3)
-      (take-credits state :corp)
-      (play-from-hand state :runner "Surge")
-      (prompt-select :runner imp)
-      (is (= 2 (get-in (refresh imp) [:counter])))
-      )))
-
-(deftest surge-target-gorman-drip
-  "Don't allow surging Gorman Drip, since it happens on the corp turn"
-  (do-game
-    (new-game (default-corp)
-              (default-runner [(qty "Gorman Drip v1" 1) (qty "Surge" 1)]))
-    (take-credits state :corp)
-    (play-from-hand state :runner "Gorman Drip v1")
-    (let [gd (get-in @state [:runner :rig :program 0])]
-      (is (= nil (get-in gd [:counter])))
-      (take-credits state :runner 3)
-      (take-credits state :corp)
-      (is (= 3 (get-in (refresh gd) [:counter])))
-      (play-from-hand state :runner "Surge")
-      (prompt-select :runner gd)
-      (is (= 3 (get-in (refresh gd) [:counter]))))))

 (deftest blackmail
   "Prevent rezzing of ice for one run"
@@ -210,8 +77,7 @@
       ;Do another run, where the ice should rez
       (core/click-run state :runner {:server "HQ"})
       (core/rez state :corp iwall1)
-      (is (get-in (refresh iwall1) [:rezzed]))
-    )))
+      (is (get-in (refresh iwall1) [:rezzed])))))

 (deftest blackmail-tmi-interaction
   "Regression test for a rezzed tmi breaking game state on a blackmail run"
@@ -231,5 +97,183 @@
       (core/no-action state :corp nil)
       (core/continue state :runner nil)
       (core/jack-out state :runner nil)
-      (core/click-run state :runner {:server "Archives"})
-      )))+      (core/click-run state :runner {:server "Archives"}))))
+
+(deftest demolition-run
+  "Demolition Run - Trash at no cost"
+  (do-game
+    (new-game (default-corp [(qty "False Lead" 1) (qty "Shell Corporation" 1)(qty "Hedge Fund" 3)])
+              (default-runner [(qty "Demolition Run" 1)]))
+    (core/move state :corp (find-card "False Lead" (:hand (get-corp))) :deck) ; put False Lead back in R&D
+    (play-from-hand state :corp "Shell Corporation" "R&D") ; install upgrade with a trash cost in root of R&D
+    (take-credits state :corp 2) ; pass to runner's turn by taking credits
+    (play-from-hand state :runner "Demolition Run")
+    (is (= 3 (:credit (get-runner))) "Paid 2 credits for the event")
+    (prompt-choice :runner "R&D")
+    (is (= [:rd] (get-in @state [:run :server])) "Run initiated on R&D")
+    (prompt-choice :runner "OK") ; dismiss instructional prompt for Demolition Run
+    (core/no-action state :corp nil)
+    (core/successful-run state :runner nil)
+    (let [demo (get-in @state [:runner :play-area 0])] ; Demolition Run "hack" is to put it out in the play area
+      (prompt-choice :runner "Unrezzed upgrade in R&D")
+      (card-ability state :runner demo 0)
+      (is (= 3 (:credit (get-runner))) "Trashed Shell Corporation at no cost")
+      (prompt-choice :runner "Card from deck")
+      (card-ability state :runner demo 0)  ; trash False Lead instead of stealing
+      (is (= 0 (:agenda-point (get-runner))) "Didn't steal False Lead")
+      (is (= 2 (count (:discard (get-corp)))) "2 cards in Archives")
+      (is (empty? (:prompt (get-runner))) "Run concluded"))))
+
+(deftest freelance-coding-contract
+  "Freelance Coding Contract - Gain 2 credits per program trashed from Grip"
+  (do-game
+    (new-game (default-corp)
+              (default-runner [(qty "Freelance Coding Contract" 1) (qty "Paricia" 1) (qty "Cloak" 1) (qty "Inti" 1)]))
+    (take-credits state :corp)
+    (play-from-hand state :runner "Freelance Coding Contract")
+    (prompt-select :runner (find-card "Cloak" (:hand (get-runner))))
+    (prompt-select :runner (find-card "Paricia" (:hand (get-runner))))
+    (prompt-select :runner (find-card "Inti" (:hand (get-runner))))
+    (prompt-choice :runner "Done")
+    (is (= 3 (count (filter #(= (:type %) "Program") (:discard (get-runner))))) "3 programs in Heap")
+    (is (= 11 (:credit (get-runner))) "Gained 6 credits from 3 trashed programs")))
+
+(deftest notoriety
+  "Notoriety - Run all 3 central servers successfully and play to gain 1 agenda point"
+  (do-game
+    (new-game (default-corp [(qty "Hedge Fund" 1)])
+              (default-runner [(qty "Notoriety" 1)]))
+    (play-from-hand state :corp "Hedge Fund")
+    (take-credits state :corp)
+    (core/click-run state :runner {:server "Archives"})
+    (core/no-action state :corp nil)
+    (core/successful-run state :runner nil)
+    (core/click-run state :runner {:server "R&D"})
+    (core/no-action state :corp nil)
+    (core/successful-run state :runner nil)
+    (core/click-run state :runner {:server "HQ"})
+    (core/no-action state :corp nil)
+    (core/successful-run state :runner nil)
+    (play-from-hand state :runner "Notoriety")
+    (is (= 1 (count (:scored (get-runner)))) "Notoriety moved to score area")
+    (is (= 1 (:agenda-point (get-runner))) "Notoriety scored for 1 agenda point")))
+
+(deftest stimhack
+  "Stimhack - Gain 9 temporary credits and take 1 brain damage after the run"
+  (do-game
+    (new-game (default-corp [(qty "Eve Campaign" 1)])
+              (default-runner [(qty "Stimhack" 1) (qty "Sure Gamble" 1)]))
+    (take-credits state :corp)
+    (play-from-hand state :runner "Stimhack")
+    (prompt-choice :runner "HQ")
+    (is (= [:hq] (get-in @state [:run :server])) "Run initiated on HQ")
+    (core/no-action state :corp nil)
+    (core/successful-run state :runner nil)
+    (is (= 14 (:credit (get-runner))))
+    (is (= 9 (:run-credit (get-runner))) "Gained 9 credits for use during the run")
+    (prompt-choice :runner "Yes") ; choose to trash Eve
+    (is (and (= 0 (count (:hand (get-corp)))) (= 1 (count (:discard (get-corp))))) "Corp hand empty and Eve in Archives")
+    (is (= 5 (:credit (get-runner))))
+    (is (= 0 (count (:hand (get-runner)))) "Lost card from Grip to brain damage")
+    (is (= 4 (:max-hand-size (get-runner))))
+    (is (= 1 (:brain-damage (get-runner))))))
+
+(deftest sure-gamble
+  "Sure Gamble"
+  (do-game
+    (new-game (default-corp) (default-runner))
+    (take-credits state :corp)
+    (is (= 5 (:credit (get-runner))))
+    (core/play state :runner {:card (first (:hand (get-runner)))})
+    (is (= 9 (:credit (get-runner))))))
+
+;Surge and virus counter flag tests
+(deftest surge-valid-target
+  "Add counters if target is a virus and had a counter added this turn"
+  (do-game
+    (new-game (default-corp)
+              (default-runner [(qty "Imp" 1) (qty "Surge" 1)]))
+    (take-credits state :corp)
+    (play-from-hand state :runner "Imp")
+    (let [imp (get-in @state [:runner :rig :program 0])]
+      (is (= 2 (get-in imp [:counter])))
+      (play-from-hand state :runner "Surge")
+      (prompt-select :runner imp)
+      (is (= 4 (get-in (refresh imp) [:counter]))))))
+
+(deftest surge-target-not-virus
+  "Don't fire surge if target is not a virus"
+  (do-game
+    (new-game (default-corp)
+              (default-runner [(qty "Security Testing" 1) (qty "Surge" 1)]))
+    (take-credits state :corp)
+    (play-from-hand state :runner "Security Testing")
+    (let [st (get-in @state [:runner :rig :resource 0])]
+      (play-from-hand state :runner "Surge")
+      (prompt-select :runner st)
+      (is (not (contains? st :counter))))))
+
+(deftest surge-target-no-token-this-turn
+  "Don't fire surge if target does not have virus counter flag set"
+  (do-game
+    (new-game (default-corp)
+              (default-runner [(qty "Imp" 1) (qty "Surge" 1)]))
+    (take-credits state :corp)
+    (play-from-hand state :runner "Imp")
+    (let [imp (get-in @state [:runner :rig :program 0])]
+      (is (= 2 (get-in imp [:counter])))
+      (take-credits state :runner 3)
+      (take-credits state :corp)
+      (play-from-hand state :runner "Surge")
+      (prompt-select :runner imp)
+      (is (= 2 (get-in (refresh imp) [:counter]))))))
+
+(deftest surge-target-gorman-drip
+  "Don't allow surging Gorman Drip, since it happens on the corp turn"
+  (do-game
+    (new-game (default-corp)
+              (default-runner [(qty "Gorman Drip v1" 1) (qty "Surge" 1)]))
+    (take-credits state :corp)
+    (play-from-hand state :runner "Gorman Drip v1")
+    (let [gd (get-in @state [:runner :rig :program 0])]
+      (is (= nil (get-in gd [:counter])))
+      (take-credits state :runner 3)
+      (take-credits state :corp)
+      (is (= 3 (get-in (refresh gd) [:counter])))
+      (play-from-hand state :runner "Surge")
+      (prompt-select :runner gd)
+      (is (= 3 (get-in (refresh gd) [:counter]))))))
+
+(deftest virus-counter-flag-on-enter
+  "Set counter flag when virus card enters play with counters"
+  (do-game
+    (new-game (default-corp) (default-runner [(qty "Surge" 1) (qty "Imp" 1) (qty "Crypsis" 1)]))
+    (take-credits state :corp)
+    (play-from-hand state :runner "Imp")
+    (let [imp (get-in @state [:runner :rig :program 0])]
+      (is (get-in imp [:added-virus-counter]) "Counter flag was not set on Imp"))))
+
+(deftest virus-counter-flag-on-add-prop
+  "Set counter flag when add-prop is called on a virus"
+  (do-game
+    (new-game (default-corp)
+              (default-runner [(qty "Crypsis" 1)]))
+    (take-credits state :corp)
+    (play-from-hand state :runner "Crypsis")
+    (let [crypsis (get-in @state [:runner :rig :program 0])]
+      (card-ability state :runner crypsis 2) ;click to add a virus counter
+      (is (= 1 (get-in (refresh crypsis) [:counter])) "Crypsis did not add a virus token")
+      (is (get-in (refresh crypsis) [:added-virus-counter] "Counter flag was not set on Crypsis")))))
+
+(deftest virus-counter-flag-clear-on-end-turn
+  "Clear the virus counter flag at the end of each turn"
+  (do-game
+    (new-game (default-corp)
+              (default-runner [(qty "Crypsis" 1)]))
+    (take-credits state :corp)
+    (play-from-hand state :runner "Crypsis")
+    (let [crypsis (get-in @state [:runner :rig :program 0])]
+      (card-ability state :runner crypsis 2) ;click to add a virus counter
+      (take-credits state :runner 2)
+      (take-credits state :corp 1)
+      (is (not (get-in (refresh crypsis) [:added-virus-counter])) "Counter flag was not cleared on Crypsis"))))


fix spelling

fix spelling

--- src/cljs/dbquery/commons.cljs
+++ src/cljs/dbquery/commons.cljs
@@ -57,6 +57,6 @@
 (defn error-text [e]
   (or (:response e) (get-in e [:parse-error :original-text])))

-(defn form-group [{:kesy[group-class label]} input]
+(defn form-group [{:keys[group-class label]} input]
   [:div.form-group {:class group-class}
    [:label label] input])


fix missing change in last commit.

fix missing change in last commit.

--- storm-core/src/clj/org/apache/storm/ui/core.clj
+++ storm-core/src/clj/org/apache/storm/ui/core.clj
@@ -145,7 +145,7 @@

 (defn event-log-link
   [topology-id component-id host port secure?]
-  (logviewer-link host (Utils/eventLogsFilename topology-id port) secure?))
+  (logviewer-link host (Utils/eventLogsFilename topology-id (str port)) secure?))

 (defn worker-log-link [host port topology-id secure?]
   (if (or (empty? host) (let [port_str (str port "")] (or (empty? port_str) (= "0" port_str))))


Code tweaks

Code tweaks

--- taxi-rides-clj/src/taxi_rides_clj/benchmark.clj
+++ taxi-rides-clj/src/taxi_rides_clj/benchmark.clj
@@ -147,7 +147,7 @@
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

 (defn run-benchmark [benchmark-fn filter-generators aggregations n-tries n-parallels]
-  (let [percentiles (partial percentiles [5 10 25 50 75 90 95])]
+  (let [percentiles (partial percentiles (vec (range 1 100)))]
     (doall (for [n-parallel                     n-parallels
                  [filter-name filter-generator] filter-generators
                  [aggregation-name aggregation] aggregations]
@@ -159,7 +159,7 @@
                    _         (u/my-println "Finished " [filter-name aggregation-name n-parallel] " in " took " ms, avg " avg " ms")

                    p-took    (->> results (map #(-> % :took (* 0.001) Math/round (* 0.001))) percentiles)
-                   p-hits    (->> results (map :hits) percentiles)]
+                   p-hits    (->> results (map :hits) (filter some?) percentiles)]
                {:n-parallel    n-parallel
                 :filter        filter-name
                 :aggs          aggregation-name
@@ -171,16 +171,20 @@
   (let [client       (make-client)
         benchmark-fn (fn [filter-generator aggregation]
                        (let [t-start (System/nanoTime)
-                             result  (->> (filter-generator) aggregation (run-query client))
+                             result  (try
+                                       (->> (filter-generator) aggregation (run-query client))
+                                       (catch java.io.IOException e nil))
                              t-end   (System/nanoTime)]
                          {:took (- t-end t-start)
                         ; :result result
-                          :hits (-> result :body :hits :total)}))]
+                          :hits (some-> result :body :hits :total)}))]
     (apply run-benchmark benchmark-fn args)))

 (comment
-  (do (println "")
-      (clojure.pprint/pprint (benchmark-es filters aggregations 50 [1]))))
+  (let [results (benchmark-es filters aggregations 500 [1 2 4])]
+    (spit "results_es.edn" (with-out-str (clojure.pprint/pprint results)))
+    (println "")
+    (clojure.pprint/pprint results)))

 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

@@ -221,7 +225,7 @@
                                                (clojure.string/replace #"doc\['([^']+)'\]\.value" "$1")
                                                (clojure.string/replace #"([a-z])-([a-z])"         "$1_$2")))))

-              gen-col-name (fn [field name interval] (format "%s_%s_%s" field name interval))
+              gen-col-name (fn [name] (format "%s_%s_%s" field name (:interval agg-data)))

               this-agg
               (if (group-by? agg-type)
@@ -233,14 +237,15 @@
                    :histogram
                    (let [interval (-> agg-data :interval float)]
                      [{:agg (format "FLOOR(%s / %.1f)" field interval)
-                       :col (gen-col-name field "hist" (:interval agg-data))}])
+                       :col (gen-col-name "hist")}])

                    :date_histogram
                    (let [_            (assert (= \d (-> agg-data :interval last)) "Only days are supported for now")
-                         interval     (-> agg-data :interval butlast (#(Float. (apply str %))))
+                         to-float     (fn [^String s] (Float. s))
+                         interval     (->> agg-data :interval butlast (apply str) to-float)
                          interval-div (if (= 1.0 interval) "" (format " / %.1f" interval))]
                      [{:agg (format "FLOOR(CAST(CAST(%s AS datetime) AS float)%s)" field interval-div)
-                       :col (gen-col-name field "datehist" (:interval agg-data))}]))}
+                       :col (gen-col-name "datehist")}]))}

                 {:metrics
                  (cond


grr, working on proper termination of stored and end

--- src/poky/protocol/custom.clj
+++ src/poky/protocol/custom.clj
@@ -7,7 +7,7 @@
 (def TRM-DATA-BLOCK (string :utf-8 :suffix "\r\n"))
 (def C (string :utf-8 :delimiters " "))
 (def K (string :utf-8 :delimiters " "))
-(def KV (string :utf-8 :prefix " " :suffix "\r\n"))
+(def V (string :utf-8 :delimiters " "))
 (def CR (string :utf-8 :delimiters ["\r\n"]))

 (defcodec SET ["SET" CR])
@@ -16,12 +16,9 @@

 (defcodec GET ["GET" CR])
 (defcodec GETS ["GETS" CR])
+
 (defcodec VALUE ["VALUE" CR CR])
-(defcodec END ["END\r\n"])
-
-; to test (decode GET-REPLY gets_test_b)
-; (decode GET-REPLY (encode GET-REPLY [["VALUE" "abc" "123"] ["VALUE" "abc" "123"]]))
-; (defcodec GET-REPLY (repeated VALUE :prefix :none :delimiters ["END\r\n"]))
+(defcodec END ["END"])

 ;VALUE <key> <flags> <bytes> [<cas unique>]\r\n
 ;<data block>\r\n
@@ -30,14 +27,8 @@

 (defcodec ERRC (string :utf-8))

-;(def sb (java.nio.ByteBuffer/wrap (.getBytes "STORED\r\nVALUE abc\r\n123\r\n")))
-;(defcodec X ["STORED" CR C CR CR "END" CR])
-;(def end_test_b (java.nio.ByteBuffer/wrap (.getBytes "END\r\n")))
-
 ;(def get_test_b (java.nio.ByteBuffer/wrap (.getBytes "VALUE abc\r\n123\r\n")))
-;(def gets_test_b (java.nio.ByteBuffer/wrap (.getBytes "VALUE abc\r\n123\r\nVALUE cde\r\n456\r\nEND\r\n")))
 ;(def value_test_b (java.nio.ByteBuffer/wrap (.getBytes "VALUE abc\r\n123\r\n")))
-;(def values_test_b (java.nio.ByteBuffer/wrap (.getBytes "VALUE abc\r\n123\r\nVALUE cde\r\n456\r\n")))

 (defcodec CMDS
           (header C


Add injections to keep myself from killing repls

--- project.clj
+++ project.clj
@@ -8,4 +8,6 @@
                  [org.clojure/tools.analyzer.jvm "0.1.0-SNAPSHOT"]
                  [org.clojure/tools.emitter.jvm  "0.0.1-SNAPSHOT"]
                  [org.clojure/tools.reader       "0.8.4"]
-                 ])
+                 ]
+  :injections [(set! *print-length* 10)
+               (set! *print-level*  10)])


Version 1.0.7-SNAPSHOT

Version 1.0.7-SNAPSHOT

--- project.clj
+++ project.clj
@@ -1,4 +1,4 @@
-(defproject com.rentpath/rp-util-clj "1.0.6"
+(defproject com.rentpath/rp-util-clj "1.0.7-SNAPSHOT"
   :description "Common utilities"
   :url "https://github.com/rentpath/rp-util-clj"
   :license {:name "Eclipse Public License"


lein-release plugin: preparing 0.2.3 release

--- project.clj
+++ project.clj
@@ -1,4 +1,4 @@
-(defproject de.otto/tesla-jetty "0.2.3-SNAPSHOT"
+(defproject de.otto/tesla-jetty "0.2.3"
   :description "basic microservice."
   :url "https://github.com/otto-de/tesla-jetty"
   :license {:name "Apache License 2.0"


queue and dequeue now use ref cursors

queue and dequeue now use ref cursors

--- src-cljs/core.cljs
+++ src-cljs/core.cljs
@@ -35,6 +35,14 @@

 (defn player-queue []
   (om/ref-cursor (:player-queue (om/root-cursor app-state))))
+
+(defn queue-track [track]
+  (om/transact! (player-queue) #(conj % track)))
+
+(defn dequeue-track [index]
+  (om/transact! (player-queue)
+                (fn [v] (vec (concat (subvec v 0 index)
+                                     (subvec v (inc index)))))))

 (defn mmss [seconds]
   (let [m (quot seconds 60)
@@ -63,8 +71,7 @@
             title (dom/span #js {:className "title"}
                             (str (get track "track") " - " (get track "title")))
             duration (dom/span #js {:className "duration"} (mmss (get track "length")))
-            button (dom/button #js {:onClick (fn [e] (put! enqueue @track))}
-                               "+")]
+            button (dom/button #js {:onClick #(queue-track @track)} "+")]
         (apply dom/div #js {:className "track"}
                (if (mobile?)
                  [title artist album duration button]
@@ -118,13 +125,13 @@
 (defn queue-track-view [track owner]
   (reify
     om/IRenderState
-    (render-state [this {:keys [dequeue]}]
+    (render-state [this {:keys [index]}]
       (dom/div #js {:className "track"}
                (dom/span #js {:className "artist"} (get track "artist"))
                (dom/span #js {:className "album"} (get track "album" ))
                (dom/span #js {:className "title"} (get track "title"))
                (dom/span #js {:className "duration"} (mmss (get track "length")))
-               (dom/button #js {:onClick (fn [e] (put! dequeue @track))}
+               (dom/button #js {:onClick #(dequeue-track index)}
                            "-")))))

 (defn queue-view [app owner]
@@ -156,11 +163,12 @@
                         (dom/button #js {:onClick
                                          (fn [e] (doall (map #(put! dequeue %)
                                                              (:player-queue @app))))}
-                                  "-"))
-               (om/build-all queue-track-view
-                             queue
-                             {:init-state {:dequeue dequeue}})
-             )))))
+                                    "-"))
+               (map #(om/build queue-track-view
+                             %1
+                             {:state {:index %2}})
+                    queue (range 0 999))
+               )))))

 (defn query-string-for-map [h]
   (string/join "&"
@@ -243,8 +251,8 @@
       (let [queue (om/observe owner (player-queue))
         bits (best-media-url (first queue))]
         (dom/div nil
-                 (dom/audio #js {:controls true
-                                 :autoPlay true
+                 (dom/audio #js {:controls "controls"
+                                 :autoPlay "true"
                                  :ref "player"
                                  :src bits
                                  })
@@ -268,7 +276,7 @@
                (om/build results-view app {:init-state state})
                (dom/h2 nil "queue")
                (om/build queue-view app {:init-state state})
-               (om/build player-view app {:init-state state})
+               (om/build player-view app )
                ))))

 (defn init []


simplified "add-todos" generator

simplified "add-todos" generator

--- test/unit/todos.cljs
+++ test/unit/todos.cljs
@@ -11,8 +11,8 @@
 (defmethod ct/report [::ct/default :my-shrunk]
   [m]
   (println "\nPROPERTY TEST FAILED"
-           "\nCase:" (with-out-str (cljs.pprint/pprint (:fail m)))
-           "\nShrunk:" (with-out-str (cljs.pprint/pprint (-> m :shrunk :smallest)))
+           "\nCase:" (pr-str (:fail m))
+           "\n\nShrunk:" (with-out-str (cljs.pprint/pprint (-> m :shrunk :smallest)))
            "\nNum tests:" (:num-tests m)
            "\nSeed:" (:seed m)))

@@ -40,21 +40,18 @@
   (apply distinct? (map :id @(:todos (:view-model app)))))

 ;;;;;;;;;;;;;;;;;;;;;;;; Generators
-(def gen-todo-title
-  (gen/such-that (complement clojure.string/blank?) gen/string-alphanumeric))
-
-(def gen-signal-add-todo
-  (gen/fmap #(-> [[:on-update-field %] :on-add]) gen-todo-title))
+; title is hardcoded, because we are not interested in testing different string values
+(def signals-add-todo
+  [[:on-update-field "some title"] :on-add])

 (def gen-signals-add-todos
-  (gen/not-empty
-    (gen/fmap
-      (partial apply concat)
-      (gen/vector gen-signal-add-todo))))
+  (->> gen/s-pos-int                                        ; the desired number of todos
+       (gen/fmap #(->> (take % (repeat signals-add-todo))
+                       (apply concat)))))

 #_(deftest debug
-    (doseq [signals (gen/sample gen-signals-add-todos 5)]
-      (println (count signals) (pr-str signals))))
+  (doseq [signals (gen/sample gen-signals-add-todos 10)]
+    (println (count signals) (pr-str signals))))

 ;;;;;;;;;;;;;;;;;;;;;;;; Tests
 (deftest property-tests


Updated Swedish time rules (#216)

Updated Swedish time rules (#216)


make path easier to use.  Note new usage docs.   Modify other docs in the process.

--- src/re_frame/middleware.cljs
+++ src/re_frame/middleware.cljs
@@ -11,14 +11,14 @@

 (defn pure
   "Acts as an adaptor, allowing handlers to be writen as pure functions.
-  The re-frame router will pass in an atom as the first parameter. This
-  middleware adapts that atom to be the value within the atom.
-  If you strip away the error/efficiency checks, this middleware is just doing:
+  The re-frame router passes the `app-db` atom as the first parameter to any handler.
+  This middleware adapts that atom to be the value within the atom.
+  If you strip away the error/efficiency checks, this middleware is doing:
      (reset! app-db (handler @app-db event-vec))
-  You don't have to use this middleare directly. Is supplied by default
-  when you use register-handler.
-  The only way to by-pass use of pure is to use the low level registration function
-  re-frame.handlers/register-handler-base"
+  You don't have to use this middleware directly. It is automatically applied to
+  your handler's middleware when you use \"register-handler\".
+  In fact, the only way to by-pass automatic use of \"pure\" in your middleware
+  is to use the low level registration function \"re-frame.handlers/register-handler-base\""
   [handler]
   (fn pure-handler
     [app-db event-vec]
@@ -28,11 +28,11 @@
           (warn "re-frame: Looks like \"pure\" is in the middleware pipeline twice. Ignoring.")
           (warn "re-frame: \"pure\" middleware not given a Ratom.  Got: " app-db))
         handler)    ;; turn this into a noop handler
-      (let [orig-db @app-db
-            new-db  (handler orig-db event-vec)]
+      (let [db      @app-db
+            new-db  (handler db event-vec)]
         (if (nil? new-db)
           (warn "re-frame: your pure handler returned nil. It should return the new db state.")
-          (if-not (identical? orig-db new-db)
+          (if-not (identical? db new-db)
             (reset! app-db new-db)))))))

@@ -54,7 +54,7 @@

 (defn trim-v
-  "Middleware which removes the first element of v which allows you to write
+  "Middleware which removes the first element of v, allowing you to write
   more asthetically pleasing handlers. No leading underscore on the event-v!
   Your handlers will look like this:
       (defn my-handler
@@ -69,30 +69,30 @@

 (defn path
   "A middleware factory which supplies a sub-tree of `db` to the handler.
-  Supplies a narrowed view.
-  Assumes \"pure\" is in the middleware pipeline prior.
-  Grafts the result back into db.
-  If a get-in of the path results in a nil, then \"default-fn\" will be called to supply a value.
-  XXX very like update-in. Should the name be more indicative of that closeness? "
-  ([p]
-    (path p nil))
-  ([p default-fn]
+  Works a bit like update-in. Supplies a narrowed data structure for the handler.
+  Afterwards, grafts the result of the handler back into db.
+  Usage:
+     (path :some :path)
+     (path [:some :path])
+     (path [:some :path] :to :here)
+     (path [:some :path] [:to] :here)
+  "
+  [& args]
+  (let [path   (flatten args)
+        _      (if (empty? path)
+                 (warn "re-frame: path middleware given no params. Probably a mistake."))]
     (fn middleware
       [handler]
       (fn path-handler
         [db v]
-        (if-not (vector? p)
-          (warn  "re-frame: \"path\" expected a vector, got: " p))
-        (let [val (get-in db p)
-              val (if (and (nil? val) (fn? default-fn)) (default-fn) val)]
-          (assoc-in db p (handler val v)))))))
+        (assoc-in db path (handler (get-in db path) v))))))

 (defn undoable
   "A Middleware factory which stores an undo checkpoint.
   \"explanation\" can be either a string or a function. If it is a
-  function then it must be:  (db event-vec) -> string.
-  \"explanation\" can be nil. in which case no
+  function then must be:  (db event-vec) -> string.
+  \"explanation\" can be nil. in which case \"\" is recorded.
   "
   [explanation]
   (fn middleware
@@ -117,7 +117,7 @@
   the same text, then highlight their background, and report them in a warning
   down the bottom.
   Almost any action (edit text, add new todo, remove a todo) requires a
-  complete reassesment of duplication errors and wanrings. Eg: that edit
+  complete reassesment of duplication errors and warnings. Eg: that edit
   update might have introduced a new duplicate or removed one. Same with a
   todo removal.
   And to perform this enrichment, a function has inspect all the todos,


better error messages

better error messages

--- src/clj/hospital_scheduler/routes.clj
+++ src/clj/hospital_scheduler/routes.clj
@@ -57,7 +57,7 @@
   [{:keys [start end patient doctor_id procedure_id descr]}]
   (if (collision? -1 start patient doctor_id)
     (response {:status 403
-               :body {:error (str "An event at " start " was already scheduled for the selected doctor")}})
+               :body {:error (str "An event at " start " was already scheduled for the selected doctor or patient")}})
     (do
       (insert-event! db start end patient doctor_id procedure_id descr)
       (response {:status 200


Prepend messages printed from cljs to make output clearer

--- src/clj_chrome_devtools/cljs/test.clj
+++ src/clj_chrome_devtools/cljs/test.clj
@@ -116,8 +116,8 @@
 (defn- read-console-log-messages []
   (loop []
     (let [msgs (automation/evaluate "clj_chrome_devtools_runner.get_printed()")]
-      (when-not (empty? msgs)
-        (println (str/join msgs)))
+      (doseq [m (mapcat #(str/split % #"\n") msgs)]
+        (println "[CLJS]" m))

       (when-not (some assert-test-result msgs)
         (Thread/sleep 100)


more work sticking docs into the db

more work sticking docs into the db

--- src-cljs/frontend/controllers/navigation.cljs
+++ src-cljs/frontend/controllers/navigation.cljs
@@ -246,6 +246,9 @@
      10000
      (fn [{:keys [docs]}]
        (when docs
+         ;; seems like maybe this should be where I stop. Why are we storing docs in the state?
+         ;; Makes it easier to tell which ones are "touched" docs.
+         (d/transact! (:db current-state) docs)
          (put! (get-in current-state [:comms :api]) [:touched-docs :success {:docs docs}]))))))

 (defmethod overlay-extra-post! :team-doc-viewer [previous-state current-state overlay]
@@ -256,6 +259,8 @@
    10000
    (fn [{:keys [docs]}]
      (when docs
+       ;; TODO: if absolute-doc-url ever pulls subdomain out of the db, this could break it
+       (d/transact! (:db current-state) docs)
        (put! (get-in current-state [:comms :api]) [:team-docs :success {:docs docs}]))))))

 (defmethod navigated-to :overlay


QP don't barf on FKs with no destination_id #574

--- src/metabase/driver/query_processor.clj
+++ src/metabase/driver/query_processor.clj
@@ -313,10 +313,11 @@
         ;; Look up the Foreign keys info if applicable.
         ;; Build a map of FK Field IDs -> Destination Field IDs
         field-id->dest-field-id (when (seq fk-field-ids)
-                                  (sel :many :field->field [ForeignKey :origin_id :destination_id], :origin_id [in fk-field-ids]))
+                                  (sel :many :field->field [ForeignKey :origin_id :destination_id], :origin_id [in fk-field-ids], :destination_id [not= nil]))

         ;; Build a map of Destination Field IDs -> Destination Fields
-        dest-field-id->field    (when (seq fk-field-ids)
+        dest-field-id->field    (when (and (seq fk-field-ids)
+                                           (seq (vals field-id->dest-field-id)))
                                   (sel :many :id->fields [Field :id :name :table_id :description :base_type :special_type], :id [in (vals field-id->dest-field-id)]))]

     ;; Add the :extra_info + :target to every Field. For non-FK Fields, these are just {} and nil, respectively.


CMR-2222: Added a upper-case reminder in the humanizer map.

--- ingest-app/src/cmr/ingest/services/humanizer_alias_cache.clj
+++ ingest-app/src/cmr/ingest/services/humanizer_alias_cache.clj
@@ -19,7 +19,9 @@
   (stl-cache/create-single-thread-lookup-cache))

 (defn- retrieve-humanizer-alias-map
-  "Returns the alias map like
+  "Returns the alias map like the following. Note: All the replacement_value are UPPER-CASED,
+   so when using this map to get all the non-humanized aliases for a given collection's platform,
+   tile, or instrument, they need to be UPPER-CASED as well.
    {\"platform\" {\"TERRA\" [\"AM-1\" \"am-1\" \"AM 1\"] \"OTHERPLATFORMS\" [\"otheraliases\"]}
     \"tiling_system_name\" {\"TILE\" [\"tile_1\" \"tile_2\"] \"OTHERTILES\" [\"otheraliases\"]}
     \"instrument\" {\"INSTRUMENT\" [\"instr1\" \"instr2\"] \"OTHERINSTRUMENTS\" [\"otheraliases\"]}}"


Use filename as title

Use filename as title

--- src/archi/core.clj
+++ src/archi/core.clj
@@ -188,11 +188,11 @@
      "
 "]))

-(defn wrap-html [svg styles scripts]
+(defn wrap-html [filename svg styles scripts]
   (html [:html
          [:head
           [:meta {:content "text-html; charset=utf-8" :http-equiv "Content-type"}]
-          [:title "Microsoft Supply Chain Architecture"]
+          [:title filename]
           styles]
          svg
          scripts]))
@@ -222,6 +222,6 @@
                   (remove-viewbox))
          styles [:style ""]
          scripts (make-scripts edges)
-         html (wrap-html svg styles scripts)]
+         html (wrap-html filename svg styles scripts)]
     (spit (str filename ".svg") svg)
     (spit (str filename ".html") html)))


panc: settings: remove unused gzipOutput default

--- panc/src/main/clojure/org/quattor/pan/settings.clj
+++ panc/src/main/clojure/org/quattor/pan/settings.clj
@@ -25,7 +25,6 @@
    :formatter #{(PanFormatter/getInstance), (DepFormatter/getInstance)}
    :output-dir (absolute-file)
    :include-path [(absolute-file)]
-   :gzipOutput false
    :deprecationWarnings CompilerOptions$DeprecationWarnings/OFF
    :annotationDirectory nil
    :annotationBaseDirectory nil


+hide-these-features

+hide-these-features

--- src/babel/html.clj
+++ src/babel/html.clj
@@ -165,6 +165,26 @@

 (def show-top true)
 (def show-true true)
+
+;; must be a set, not just a vector, so that contains? works as expected.
+(def hide-these-features (set [:comp-filled
+                               :a :b
+                               :activity
+                               :animate
+                               :buyable
+                               :drinkable
+                               :edible
+                               :futuro
+                               :imperfect
+                               :furniture
+                               :legible
+                               :mass
+                               :part-of-human-body
+                               :physical-object
+                               :place
+                               :present
+                               :speakable
+                               :artifact]))

 ;; TODO: use multimethod based on arg's type.
 (defn tablize [arg & [path serialized opts]]
@@ -438,21 +458,31 @@
               ""
               )
              " ")
-           (tablize (second tr)
-                    ;; set 'path' param for recursive call to tablize.
-                    ;; Path' = Path . current_feature
-                    (concat path (list (first tr)))
-                    serialized
-                    {:as-tree false})
+           (cond (= (first tr) :surface)
+                 "FOO"
+                 true
+                 (tablize (second tr)
+                          ;; set 'path' param for recursive call to tablize.
+                          ;; Path' = Path . current_feature
+                          (concat path (list (first tr)))
+                          serialized
+                          {:as-tree false}))
            "   	"
            "
"))
         ;; sorts the argument list in _arg__ by key name and remove uninteresting key-value pairs.
-        (remove #(or (= (first %) :aliases)
+        (remove #(or (contains? hide-these-features
+                                (first %))
+                     ;; TODO: all the below should go into hide-these-features.
+                     (= (first %) :aliases)
+                     (= (first %) :case)
                      (= (first %) :comment)
                      (= (first %) :comment-plaintext)
                      (= (first %) :extend)
+                     (= (first %) :pronoun)
+                     (= (first %) :propernoun)
                      (= (first %) :first)
                      (= (first %) :head-filled)
+                     (= (first %) :initial)
                      (= (first %) :phrasal)
                      (= (first %) :root)
                      (= (first %) :schema-symbol)


Add test for cdm

Add test for cdm

--- test/forma/hadoop/jobs/cdm_test.clj
+++ test/forma/hadoop/jobs/cdm_test.clj
@@ -1,5 +1,38 @@
 (ns forma.hadoop.jobs.cdm-test
   (:use cascalog.api
         forma.hadoop.jobs.cdm
-        [midje sweet cascalog]))
+        [midje sweet cascalog]
+        [forma.gfw.cdm :only (latlon->google-tile)]
+        [forma.utils :only (positions)])
+  (:require [forma.date-time :as date]
+            [forma.postprocess.output :as o]
+            [forma.reproject :as r]))

+(comment
+  (let [est-map {:est-start "2005-12-31"}
+        forma-src [["500" 28 8 1 1 [1 2 50]]]
+        thresh 50
+        t-res "16"
+        out-t-res "32"]
+        (convert-for-vizz est-map forma-src thresh t-res out-t-res) => (produces [1, 1, 16, 137])))
+
+(comment
+  (let [est-map {:est-start "2005-12-31"}
+        forma-src [["500" 28 8 1 1 [1 2 50]]]
+        thresh 50
+        t-res "16"
+        out-t-res "32"
+        epoch-period (date/datetime->period out-t-res "2000-01-01")
+        ts-start-period (date/datetime->period t-res (:est-start est-map))
+        z 16]
+    (<- [?x ?y ?z ?p]
+        (forma-src ?s-res ?mod-h ?mod-v ?s ?l ?prob-series)
+        (o/clean-probs ?prob-series :> ?clean-series)
+        (first-hit thresh ?clean-series :> ?first-hit-idx)
+        (+ ts-start-period ?first-hit-idx :> ?period)
+        (date/convert-period-res t-res out-t-res ?period :> ?period-new-res)
+        (- ?period-new-res epoch-period :> ?rp)
+        (min-period ?rp :> ?p)
+        (r/modis->latlon ?s-res ?mod-h ?mod-v ?s ?l :> ?lat ?lon)
+        (latlon->google-tile ?lat ?lon z :> ?x ?y)
+        (identity z :> ?z))))


start of smooth zooming

start of smooth zooming

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

--- plugins/SlideExplorer2/src/slide_explorer/view.clj
+++ plugins/SlideExplorer2/src/slide_explorer/view.clj
@@ -33,6 +33,26 @@
     ; (print '~expr)
     ; (println " -->" (pr-str ret#))
      ret#))
+
+;; ZOOMING
+
+(def ln2 (Math/log 2))
+
+(def zoom-levels
+  (zipmap
+    (map - (range 12))
+    (take 12 (iterate #(/ % 2) 1))))
+
+;(def zoom-lookup nil
+
+
+(defn log2 [x]
+  (/ (Math/log x) ln2))
+
+;(defn nearby-zoom-levels
+
+
+;; COORDINATES

 (defn pixel-rectangle
   "Converts the screen state coordinates to visible camera pixel coordinates."
@@ -164,16 +184,19 @@
                      :stroke {:color :yellow
                               :width (max 2.0 (* zoom 8))}}]))))

+
 (defn paint-screen [graphics screen-state overlay-tiles-atom]
   (let [original-transform (.getTransform graphics)
         zoom (:zoom screen-state)
+        scale (screen-state :scale 1.0)
         x-center (/ (screen-state :width) 2)
         y-center (/ (screen-state :height) 2)
         [tile-width tile-height] (:tile-dimensions screen-state)]
     (doto graphics
       (.setClip 0 0 (:width screen-state) (:height screen-state))
-      (.translate (- x-center (int (* (:x screen-state) zoom)))
-                  (- y-center (int (* (:y screen-state) zoom))))
+      (.translate (- x-center (int (* (:x screen-state) zoom scale)))
+                  (- y-center (int (* (:y screen-state) zoom scale))))
+      (.scale scale scale)
       (paint-tiles overlay-tiles-atom screen-state)
       (paint-stage-position screen-state)
       paint/enable-anti-aliasing
@@ -306,5 +329,16 @@
          :channels {"Default" {:min 200 :max 800 :gamma 1.0 :color Color/WHITE}})
   (swap! ss2 assoc :channels (:channels @ss)))

-
-
+(defn smooth-zoom-test []
+  (swap! ss assoc :scale 1.0 :zoom 1/128)
+  (Thread/sleep 5000)
+  (repeatedly 7
+          (fn []
+  (doseq [x (map #(Math/pow 2 %) (range 0 1.01 0.05))]
+    (Thread/sleep 5)
+    (swap! ss assoc :scale x))
+  (swap! ss update-in [:zoom] * 2)
+  (swap! ss assoc :scale 1)
+  ;(Thread/sleep 1000)
+            )))
+


added/changes some docstrings

added/changes some docstrings

--- src/main/clojure/clojure/data/xml.clj
+++ src/main/clojure/clojure/data/xml.clj
@@ -249,8 +249,8 @@
                             (.getEncoding stream) ")")))))

 (defn emit-stream
-  "Prints the given Element tree as XML text to *out*. See element-tree.
-  Options:
+  "Prints the given Element tree as XML text to stream.
+   Options:
     :indent <num>            Amount to increase indent depth each time
     :encoding <str>          Character encoding to use"
   [e ^java.io.Writer stream & {:as opts}]
@@ -265,7 +265,12 @@
     (.writeEndDocument writer)
     stream))

-(defn emit [e & {:as opts}]
+(defn emit
+  "Prints the given Element tree as XML text to *out*.
+   Options:
+    :indent <num>            Amount to increase indent depth each time
+    :encoding <str>          Character encoding to use"
+  [e & {:as opts}]
   (apply emit-stream e *out* opts))

 (defn indenting-transformer []
@@ -274,7 +279,11 @@
     (.setOutputProperty (javax.xml.transform.OutputKeys/METHOD) "xml")
     (.setOutputProperty "{http://xml.apache.org/xslt}indent-amount" "2")))

-(defn indent [e ^java.io.Writer stream & {:as opts}]
+(defn indent
+  "Uses emit-stream to emit XML and indents the result.  WARNING: this is slow
+   it will emit the XML and read it in again to indent it.  Intended for
+   debugging/testing only."
+  [e ^java.io.Writer stream & {:as opts}]
   (let [sw (java.io.StringWriter.)
         _ (apply emit-stream e sw opts)
         source (-> sw .toString java.io.StringReader. javax.xml.transform.stream.StreamSource.)


Bump core.async version (#181)

Bump core.async version (#181)

Fix core.async version. It's fallen out of sync with the main project.clj for dev, this fixes it for recent clojure versions again.

--- ext/async/project.clj
+++ ext/async/project.clj
@@ -8,4 +8,4 @@
             :url "https://opensource.org/licenses/MIT"}
   :pedantic? :abort
   :dependencies [[yada/core ~VERSION]
-                 [org.clojure/core.async "0.2.395"]])
+                 [org.clojure/core.async "0.3.443"]])


Remove debug log

Remove debug log

--- src/robinson/ui/components/robinson.clj
+++ src/robinson/ui/components/robinson.clj
@@ -2010,8 +2010,11 @@
 		  [:layer {:id :ui} [
             [:view {:style {:width "100%" :height "100%" :background-color (rcolor/color->rgb :black)}} [
               [:view {}
-                (for [{:keys [text color] :as log-item} (reverse (take 23 log))]
-                  (zc/csx [:text {:style {:color (rcolor/color->rgb color)}} [(str (get log-item :time 0) " "  text)]]))]]]]]]]]])))
+                ;; debug log
+                #_(for [{:keys [text color] :as log-item} (reverse (take 23 log))]
+                  (zc/csx [:text {:style {:color (rcolor/color->rgb color)}} [(str (get log-item :time 0) " "  text)]]))
+                (for [{:keys [text color]} (reverse (take 23 log))]
+                  (zc/csx [:text {:style {:color (rcolor/color->rgb color)}} [(str text)]]))]]]]]]]]])))

 (zc/def-component Robinson
   [this]


Don't update html/svg if same.

Don't update html/svg if same.

--- src/cbfg/core.cljs
+++ src/cbfg/core.cljs
@@ -313,13 +313,15 @@
           (when (> @event-delay 0) (<! (timeout @event-delay)))
           (when (< @event-delay 0) (<! step-ch)))
         (assign-positions @vis @root-actx vis-positions actx-ch-ch-infos nil)
-        (set-el-innerHTML (str el-prefix "-html")
-                          (apply str (flatten (vis-html-actx @vis @root-actx actx-ch-ch-infos))))
-        (set-el-innerHTML (str el-prefix "-svg")
-                          (apply str (flatten (vis-svg-actxs @vis @vis-positions deltas :curr))))
-        (when (> @event-delay 0) (<! (timeout @event-delay)))
-        (when (< @event-delay 0) (<! step-ch))
-        (recur (inc num-events) @vis @vis-positions nil nil)))
+        (let [vis-next-html (apply str (flatten (vis-html-actx @vis @root-actx actx-ch-ch-infos)))
+              vis-next-svg (apply str (flatten (vis-svg-actxs @vis @vis-positions deltas :curr)))]
+          (if (or (not= vis-next-html vis-last-html)
+                  (not= vis-next-svg vis-last-svg))
+            (set-el-innerHTML (str el-prefix "-html") vis-next-html)
+            (set-el-innerHTML (str el-prefix "-svg") vis-next-svg)
+            (when (> @event-delay 0) (<! (timeout @event-delay)))
+            (when (< @event-delay 0) (<! step-ch)))
+          (recur (inc num-events) @vis @vis-positions vis-next-html vis-next-svg))))
     (ago world w
          (reset! root-actx world)
          (let [in-ch (achan-buf world 100)


more merging..

more merging..

--- src/babel/generate.cljc
+++ src/babel/generate.cljc
@@ -172,7 +172,7 @@
                                  comp-paths)]
              (when (not (some empty? comp-bolts))
                (mapfn #(if true
-                         bolt-at
+                         bolt
                          nil))
                (add-comps bolt-at
                           model


trying to make deterministic/nondeterministic easier to configure

--- src/babel/generate.cljc
+++ src/babel/generate.cljc
@@ -22,12 +22,10 @@
 (def ^:const deterministic false)

 ;; deterministic generation:
-(def shufflefn
-                                        ;  shuffle
-  (fn [x] x))
-;  (if deterministic
-;    (fn [x] x))
-;  (shuffle x))
+(def ^:const shufflefn (fn [x] x))
+
+;; nondeterministic generation
+;; (def ^:const shufflefn shuffle)

 (def ^:const randomize-lexemes-before-phrases
   false)


logging do-defaults reveals further need for lazy evaluation

--- src/babel/generate.cljc
+++ src/babel/generate.cljc
@@ -309,7 +309,7 @@
      truncate-children max-total-depth top-level-spec)))

 (defn do-defaults [tree language-model]
-  (log/trace (str "calling do-defaults on tree:" ((:morph language-model) tree)))
+  (log/debug (str "calling do-defaults on tree:" ((:morph language-model) tree)))
   (if-let [default-fn (:default-fn language-model)]
     (let [result
           (default-fn tree)]


Allow sessions atom to survive resets

Allow sessions atom to survive resets

--- src/cylon/core.clj
+++ src/cylon/core.clj
@@ -12,7 +12,9 @@
 ;; See the License for the specific language governing permissions and
 ;; limitations under the License.

-(ns cylon.core
+(ns ^{:clojure.tools.namespace.repl/unload false
+      :clojure.tools.namespace.repl/load false}
+  cylon.core
   (:require
    [clojure.java.io :as io]
    [clojure.pprint :refer (pprint)]
@@ -212,9 +214,11 @@
   (start-session! [_ username]) ; return cookie map compatible with wrap-cookies
   (get-session [_ request]))

+(def sessions-atom (atom {}))
+
 (defrecord AtomBackedSessionStore [expiry-seconds]
   component/Lifecycle
-  (start [this] (assoc this :sessions (atom {})))
+  (start [this] (assoc this :sessions sessions-atom))
   (stop [this] (dissoc this :sessions))
   HttpSessionStore
   (start-session! [this username]


datamunging part3 (clojure)

datamunging part3 (clojure)

--- src/main/clojure/datamunging/datamunging1.clj
+++ src/main/clojure/datamunging/datamunging1.clj
@@ -4,7 +4,7 @@
 (defrecord Entry [id value1 value2])

 (defn read-lines-from [file-name] (.split (slurp file-name) "\n"))
-(defn split-lines [lines] (vec (map #(vec (.split (.trim %) "\\s+")) lines)))
+(defn split-each-line [lines] (vec (map #(vec (.split (.trim %) "\\s+")) lines)))
 (defn remove-non-digits [s] (.replaceAll s "\\*" ""))
 (defn parse-row [row]
   (let [key (first row)
@@ -12,60 +12,29 @@
         value2 (remove-non-digits (nth row 2))]
     (Entry. key (Integer/parseInt value1) (Integer/parseInt value2))
 ))
+(defn find-row-with-min-diff [columns-with-data]
+  (let [parsed-lines (map parse-row columns-with-data)]
+    (apply min-key #(Math/abs (- (:value1 %) (:value2 %))) parsed-lines)
+))
+(defn find-entity-with-min-diff [file-name filter-data extract-columns]
+  (let [columns-with-data (extract-columns (split-each-line (filter-data (read-lines-from file-name))))
+        row-with-min-values-diff (find-row-with-min-diff columns-with-data)]
+    (:id row-with-min-values-diff)
+))

 (deftest should-find-team-with-min-goall-diff
   (def football-file "/Users/dima/IdeaProjects/katas/src/main/scala/ru/katas/n4/football.dat")
   (defn remove-non-data [lines] (filter #(not (.contains % "----")) (drop 5 (drop-last 1 lines))))
   (defn take-columns-with-data [lines] (map #(vector (nth % 1) (nth % 6) (nth % 8)) lines))

-  (let [
-         columns-with-data (take-columns-with-data (split-lines (remove-non-data (read-lines-from football-file))))
-         parsed-lines (map parse-row columns-with-data)
-         row-with-min-values-diff (apply min-key #(Math/abs (- (:value1 %) (:value2 %))) parsed-lines)
-         team-with-min-goall-diff (:id row-with-min-values-diff)
-         ]
-    (is (= "Aston_Villa" team-with-min-goall-diff))
-    (is (= (Entry. "Aston_Villa" 46 47) row-with-min-values-diff))
-
-    (is (= (Entry. "Arsenal" 79 36) (nth parsed-lines 0)))
-    (is (= (Entry. "Leicester" 30, 64) (nth parsed-lines 19)))
-    (is (= 20 (count parsed-lines)))
-
-    (is (= (list "Arsenal" "79" "36") (nth columns-with-data 0)))
-    (is (= (list "Leicester" "30" "64") (nth columns-with-data 19)))
-    (is (= 20 (count columns-with-data)))
-
-    (is (= 20 (count (remove-non-data (read-lines-from football-file)))))
-    (is (= 27 (count (read-lines-from football-file))))
-))
+  (is (= "Aston_Villa" (find-entity-with-min-diff football-file remove-non-data take-columns-with-data)))
+)

 (deftest should-find-day-with-min-temperature-spread
   (def weather-file "/Users/dima/IdeaProjects/katas/src/main/scala/ru/katas/n4/weather.dat")
-
   (defn remove-non-data [lines] (drop 8 (drop-last 2 lines)))
   (defn take-columns-with-data [lines] (map #(vector (nth % 0) (nth % 1) (nth % 2)) lines))

-  (let [
-        columns-with-data (take-columns-with-data (split-lines (remove-non-data (read-lines-from weather-file))))
-        parsed-lines (map parse-row columns-with-data)
-        row-with-min-values-diff (apply min-key #(Math/abs (- (:value1 %) (:value2 %))) parsed-lines)
-        find-day-with-min-temperature-spread (:id row-with-min-values-diff)
-    ]
-
-    (is (= "14" find-day-with-min-temperature-spread))
-    (is (= (Entry. "14" 61 59) row-with-min-values-diff))
-
-    (is (= (Entry. "1" 88 59) (nth parsed-lines 0)))
-    (is (= (Entry. "9" 86 32) (nth parsed-lines 8)))
-    (is (= (Entry. "30" 90 45) (nth parsed-lines 29)))
-    (is (= 30 (count parsed-lines)))
-
-    (is (= (list "1" "88" "59") (nth columns-with-data 0)))
-    (is (= (list "9" "86" "32*") (nth columns-with-data 8)))
-    (is (= (list "30" "90" "45") (nth columns-with-data 29)))
-    (is (= 30 (count columns-with-data)))
-
-    (is (= 30 (count (remove-non-data (read-lines-from weather-file)))))
-    (is (= 40 (count (read-lines-from weather-file))))
-))
+  (is (= "14" (find-entity-with-min-diff weather-file remove-non-data take-columns-with-data)))
+)
 (run-tests)