implement :rigid? option, refactor

implement :rigid? option, refactor

rigid?, default true, means that the user can only choose one of the
suggestions

setting it to false allows the user to choose arbitrary text or a
suggestion

--- src/re_com/typeahead.cljs
+++ src/re_com/typeahead.cljs
@@ -20,6 +20,8 @@
   [{:name :model            :required true                   :type "string | atom"    :validate-fn string-or-atom?    :description "text of the input (can be atom or value)"}
    {:name :on-change        :required true                   :type "string -> nil"    :validate-fn fn?                :description [:span [:code ":change-on-blur?"] " controls when it is called. Passed the current input string"] }
    {:name :data-source      :required true                   :type "async fn"         :validate-fn fn?                :description [:span [:code ":data-source"] " populates the suggestions. Should be a 2 argument function taking a search query and a callback, and should call the callback with the search query and a vector of suggestions."]}
+   {:name :render-suggestion :required false                 :type "component"        :validate-fn fn?                :description "override the rendering of the suggestion items by passing a component fn."}
+   {:name :rigid?           :required false :default true    :type "boolean | atom"                                   :description "Set to `false` will allow the user to choose arbitrary text input rather than a suggestion from `data-source`."}
    {:name :status           :required false                  :type "keyword"          :validate-fn input-status-type? :description [:span "validation status. " [:code "nil/omitted"] " for normal status or one of: " input-status-types-list]}
    {:name :status-icon?     :required false :default false   :type "boolean"                                          :description [:span "when true, display an icon to match " [:code ":status"] " (no icon for nil)"]}
    {:name :status-tooltip   :required false                  :type "string"           :validate-fn string?            :description "displayed in status icon's tooltip"}
@@ -60,24 +62,39 @@

 (defn- select-prev
   [{:as state :keys [suggestions]}]
-  (update state :selected-index #(-> % (or 0) dec (wrap (count suggestions)))))
+  (cond-> state
+    (not-empty suggestions)
+    (update :selected-index #(-> % (or -1) inc (wrap (count suggestions))))))

 (defn- select-next
   [{:as state :keys [suggestions]}]
-  (update state :selected-index #(-> % (or -1) inc (wrap (count suggestions)))))
+  (cond-> state
+    (not-empty suggestions)
+    (update :selected-index #(-> % (or -1) inc (wrap (count suggestions))))))

 (defn- select-set
   [state i]
   (assoc state :selected-index i))

+(defn- choice-made
+  [{:as state :keys [on-change]} choice]
+  (when on-change (on-change choice))
+  (-> state
+      (assoc :model choice :input-text "")
+      (dissoc :suggestions)))
+
 (defn- select-choose
-  [{:as state :keys [suggestions selected-index on-change]}]
-  (let [[search suggestion :as selected] (nth suggestions selected-index)]
-    (when on-change
-      (on-change suggestion))
-    (-> state
-        (assoc :model suggestion :input-text "")
-        (dissoc :suggestions))))
+  [{:as state :keys [suggestions selected-index on-change rigid? input-text]}]
+  (cond
+
+    (and (not rigid?) (not selected-index))
+    (choice-made state input-text)
+
+    selected-index
+    (let [[search suggestion :as selected] (nth suggestions selected-index)]
+      (choice-made state suggestion))
+
+    true state))

 (defn- select-reset
   [state]
@@ -108,22 +125,24 @@
 (defn- handle-search-results
   [state-atom c-sugg]
   (go-loop []
-    (let [[search suggestions] (<! c-sugg)]
-      (when (= search (:input-text @state-atom))
+    (let [[search suggestions] (<! c-sugg)
+          {:keys [input-text]} @state-atom]
+      (when (= search input-text)
         (swap! state-atom #(-> %
                                (assoc :suggestions suggestions :waiting? false)
                                select-reset))))
     (recur)))

 (defn- make-typeahead-state
-  [on-change]
+  [{:as args :keys [on-change rigid?]}]
   (let [c-input (chan)]
     (assoc typeahead-state-initial
-           :on-change on-change
+           :on-change  on-change
+           :rigid?     rigid?
+           :c-input    c-input
+           :c-search   (debounce c-input 250) ;; FIXME hard-coded
            :c-keypress (chan)
-           :c-input c-input
-           :c-search (debounce c-input 250) ;; FIXME hard-coded
-           :c-sugg (chan))))
+           :c-sugg     (chan))))

 (def ^:private keys-by-code
   {40 :down
@@ -155,9 +174,9 @@

 (defn- typeahead
   "Returns markup for a typeahead text input"
-  [& {:keys [data-source on-change] :as args}]
+  [& {:keys [data-source on-change rigid?] :as args}]
   {:pre [(validate-args-macro typeahead-args-desc args "typeahead")]}
-  (let [{:as state :keys [ c-search c-sugg c-input c-keypress ]} (make-typeahead-state on-change)
+  (let [{:as state :keys [ c-search c-sugg c-input c-keypress ]} (make-typeahead-state args)
         state-atom (reagent/atom state)
         input-text-model (reagent/cursor state-atom [:input-text])]
     (handle-search-results state-atom c-sugg)
@@ -192,7 +211,7 @@
                   :on-key-down #(on-key-down state-atom %)}]
           (if (or (not-empty suggestions) waiting?)
             [v-box
-             :class "rc-typeahead-suggestions"
+             :class "rc-typeahead-suggestions-container"
              :children [(when waiting?
                           [box :align :center :child [throbber :size :small :class "rc-typeahead-throbber"]])
                         (for [[ i s ] (map vector (range) suggestions)
@@ -202,7 +221,7 @@
                            :child (if render-suggestion
                                     (render-suggestion s)
                                     s)
-                           :class (str "rc-typeahead-suggestions-item"
+                           :class (str "rc-typeahead-suggestion"
                                        (when selected? " active"))
                            :attr {:on-mouse-over #(swap! state-atom select-set i)
                                   :on-mouse-down #(do (.preventDefault %) (swap! state-atom select-choose))}])]])]]))))


Added support for gap in h-box and v-box

--- src/re_demo/popovers.cljs
+++ src/re_demo/popovers.cljs
@@ -64,17 +64,17 @@

 [popover
-  :direction   XXXX
-  :anchor      [button XXXX]
-  :showing?     XXXX             ;; optional, if supplied use it otherwise create one
+  :direction   :x
+  :anchor      [button :x]
+  :showing?    :x             ;; optional, if supplied use it otherwise create one

-  :popover  {:title  XXXXX
-             :body }
-  :pop-title    XXXXXX
-  :pop-body      XXXX
-  :pop-close-button?
-  :pop-width
-  :pop-height
+  :popover  {:title  :x
+             :body   :x}
+  :pop-title   :x
+  :pop-body    :x
+  :pop-close-button? :x
+  :pop-width   :x
+  :pop-height  :x
  ]


Revise docstring

Revise docstring

--- src/grafter/rdf.clj
+++ src/grafter/rdf.clj
@@ -58,7 +58,7 @@
   "Add an RDF statement to the target datasink.  Datasinks must
   implement `grafter.rdf.protocols/ITripleWriteable`.

-  Datasinks include sesame RDF repositories, connections and anything
+  Datasinks include RDF4j RDF repositories, connections and anything
   built by rdf-writer.

   Takes an optional string/URI to use as a graph."


CMR-2815 updates granule and collection validation tests

--- access-control-app/int_test/cmr/access_control/int_test/permission_check_test.clj
+++ access-control-app/int_test/cmr/access_control/int_test/permission_check_test.clj
@@ -22,6 +22,16 @@
                 (e/grant-all-ingest (u/conn-context) "prov1guid")
                 (f))
               (fixtures/grant-all-group-fixture ["prov1guid"]))
+
+(def provider-acl-for-catalog-item
+  "A provider ACL that grants create to guest to facilitate catalog-item creation"
+  {:legacy_guid "ABCD-EFG-HIJK-LMNOP"
+   :group_permissions [{:group_id "REPLACEME"
+                        :permissions ["read" "update" "create" "delete"],}
+                       {:user_type "guest"
+                        :permissions ["read" "update" "create" "delete"]}]
+   :provider_identity {:provider_id "PROV1"
+                       :target "CATALOG_ITEM_ACL"}})

 (deftest invalid-params-test
   (are [params errors]
@@ -119,7 +129,10 @@
         create-acl #(:concept_id (ac/create-acl (u/conn-context) % {:token token}))
         update-acl #(ac/update-acl (u/conn-context) %1 %2 {:token token})
         get-collection-permissions #(get-permissions %1 coll1)
-        get-granule-permissions #(get-permissions %1 gran1)]
+        get-granule-permissions #(get-permissions %1 gran1)
+        ;; required to create catalog item acl
+        _ (create-acl (assoc-in provider-acl-for-catalog-item [:group_permissions 0 :group_id] user1-group))
+        _ (u/wait-until-indexed)]

     (testing "no permissions granted"
       (are [user permissions]
@@ -223,7 +236,7 @@

 (deftest collection-catalog-item-identifier-access-value-test
   ;; tests ACLs which grant access to collections based on their access value
-  (let [token (e/login (u/conn-context) "user1" [])
+  (let [token (e/login-guest (u/conn-context))
         save-access-value-collection (fn [short-name access-value]
                                          (u/save-collection {:entry-title (str short-name " entry title")
                                                              :short-name short-name
@@ -240,7 +253,9 @@
         coll4 (save-access-value-collection "coll4" nil)
         create-acl #(:concept_id (ac/create-acl (u/conn-context) % {:token token}))
         update-acl #(ac/update-acl (u/conn-context) %1 %2 {:token token})
-        get-coll-permissions #(get-permissions :guest coll1 coll2 coll3 coll4)]
+        get-coll-permissions #(get-permissions :guest coll1 coll2 coll3 coll4)
+        ;; required to create catalog item acl
+        _ (create-acl provider-acl-for-catalog-item)]
     (u/wait-until-indexed)

     (testing "no permissions granted"
@@ -309,7 +324,7 @@

 (deftest collection-catalog-item-identifier-temporal-test
   ;; tests ACLs that grant access based on a collection's temporal range
-  (let [token (e/login (u/conn-context) "user1" [])
+  (let [token (e/login-guest (u/conn-context))
         save-temporal-collection (fn [short-name start-year end-year]
                                      (u/save-collection {:entry-title (str short-name " entry title")
                                                          :short-name short-name
@@ -329,7 +344,9 @@
                                   :no-temporal true})
         create-acl #(:concept_id (ac/create-acl (u/conn-context) % {:token token}))
         update-acl #(ac/update-acl (u/conn-context) %1 %2 {:token token})
-        get-coll-permissions #(get-permissions :guest coll1 coll2 coll3 coll4)]
+        get-coll-permissions #(get-permissions :guest coll1 coll2 coll3 coll4)
+        ;; required to create catalog item acl
+        _ (create-acl provider-acl-for-catalog-item)]
     (u/wait-until-indexed)
     (is (= {coll1 []
             coll2 []
@@ -399,7 +416,10 @@
         coll1 (save-prov1-collection "coll1")
         gran1 (save-granule coll1)
         create-acl #(:concept_id (ac/create-acl (u/conn-context) % {:token token}))
-        update-acl #(ac/update-acl (u/conn-context) %1 %2 {:token token})]
+        update-acl #(ac/update-acl (u/conn-context) %1 %2 {:token token})
+        ;; required to create catalog item acl
+        _ (create-acl (assoc-in provider-acl-for-catalog-item [:group_permissions 0 :group_id] created-group-concept-id))
+        _ (u/wait-until-indexed)]

     (testing "no permissions granted"
       (are [user permissions]
@@ -466,7 +486,9 @@
         gran1 (save-granule coll1)
         gran2 (save-granule coll2)
         create-acl #(:concept_id (ac/create-acl (u/conn-context) % {:token token}))
-        update-acl #(ac/update-acl (u/conn-context) %1 %2 {:token token})]
+        update-acl #(ac/update-acl (u/conn-context) %1 %2 {:token token})
+        ;; required to create catalog item acl
+        _ (create-acl (assoc-in provider-acl-for-catalog-item [:group_permissions 0 :group_id] created-group-concept-id))]

     (u/wait-until-indexed)

@@ -565,6 +587,9 @@
         ;; high access value
         gran3 (save-granule coll1 {:access-value 10})
         create-acl #(:concept_id (ac/create-acl (u/conn-context) % {:token token}))
+        ;; required to create catalog item acl
+        _ (create-acl (assoc-in provider-acl-for-catalog-item [:group_permissions 0 :group_id] created-group-concept-id))
+        _ (u/wait-until-indexed)
         ;; guest read coll1 granules with undefined access value
         acl1 (create-acl {:group_permissions [{:permissions [:read]
                                                :user_type :guest}]
@@ -616,7 +641,9 @@
         gran3 (save-granule coll1 {:temporal {:single-date-time "1999-01-01T00:00:00Z"}})

         create-acl #(:concept_id (ac/create-acl (u/conn-context) % {:token token}))
-
+        ;; required to create catalog item acl
+        _ (create-acl (assoc-in provider-acl-for-catalog-item [:group_permissions 0 :group_id] created-group-concept-id))
+        _ (u/wait-until-indexed)
         acl1 (create-acl {:group_permissions [{:permissions [:read]
                                                :user_type :guest}]
                           :catalog_item_identity {:name "prov1 granules between 2000 and 2011"


clean up

clean up

--- test/cljs/searchbot/chart/parsets.cljs
+++ test/cljs/searchbot/chart/parsets.cljs
@@ -45,18 +45,18 @@
                                                                 {:key "304" :doc_count 21}]}}]}}]}}})

 (def sample-parsets-data
-  [{:request "/favicon.ico", :verb "get", :response "200", :value 2201}
-   {:request "/favicon.ico", :verb "get", :response "304", :value 13}
-   {:request "/favicon.ico", :verb "get", :response "206", :value 9}
-   {:request "/favicon.ico", :verb "head", :response "200", :value 222}
-   {:request "/hackday08/randomtags.py", :verb "post", :response "200", :value 1934}
-   {:request "/hackday08/randomtags.py", :verb "post", :response "500", :value 1}
-   {:request "/reset.css", :verb "get", :response "200", :value 1458}
-   {:request "/reset.css", :verb "get", :response "304", :value 52}
-   {:request "/style2.css", :verb "get", :response "200", :value 1449}
-   {:request "/style2.css", :verb "get", :response "304", :value 48}
-   {:request "/images/jordan-80.png", :verb "get", :response "200", :value 1392}
-   {:request "/images/jordan-80.png", :verb "get", :response "304", :value 21}])
+  [{:request "/favicon.ico" :verb "get" :response "200" :value 2201}
+   {:request "/favicon.ico" :verb "get" :response "304" :value 13}
+   {:request "/favicon.ico" :verb "get" :response "206" :value 9}
+   {:request "/favicon.ico" :verb "head" :response "200" :value 222}
+   {:request "/hackday08/randomtags.py" :verb "post" :response "200" :value 1934}
+   {:request "/hackday08/randomtags.py" :verb "post" :response "500" :value 1}
+   {:request "/reset.css" :verb "get" :response "200" :value 1458}
+   {:request "/reset.css" :verb "get" :response "304" :value 52}
+   {:request "/style2.css" :verb "get" :response "200" :value 1449}
+   {:request "/style2.css" :verb "get" :response "304" :value 48}
+   {:request "/images/jordan-80.png" :verb "get" :response "200" :value 1392}
+   {:request "/images/jordan-80.png" :verb "get" :response "304" :value 21}])

 (def sample-es-agg-resp-with-sub
   {:took 19 :timed_out false :_shards {:total 3 :successful 3 :failed 0}
@@ -108,15 +108,15 @@
     :sum_bytes {:value 3.541888535E9}}})

 (def sample-parsets-data-with-sub
-  [{:request "/files/logstash/logstash-1.0.17-monolithic.jar", :verb "get", :response "200", :value 3114356684}
-   {:request "/files/logstash/logstash-1.0.17-monolithic.jar", :verb "get", :response "206", :value 35668889}
-   {:request "/files/logstash/logstash-1.0.17-monolithic.jar", :verb "get", :response "304", :value 193}
-   {:request "/files/logstash/logstash-1.0.17-monolithic.jar", :verb "head", :response "200", :value 634}
-   {:request "/images/web/2009/banner.png", :verb "get", :response "200", :value 72668621}
-   {:request "/images/web/2009/banner.png", :verb "get", :response "304", :value 2987}
-   {:request "/files/logstash/logstash-1.0.12-monolithic.jar", :verb "get", :response "200", :value 37853629}
-   {:request "/files/logstash/logstash-1.0.14-monolithic.jar", :verb "get", :response "200", :value 34408788}
-   {:request "/files/logstash/logstash-1.0.6-monolithic.jar", :verb "get", :response "200", :value 33826430}])
+  [{:request "/files/logstash/logstash-1.0.17-monolithic.jar" :verb "get" :response "200" :value 3114356684}
+   {:request "/files/logstash/logstash-1.0.17-monolithic.jar" :verb "get" :response "206" :value 35668889}
+   {:request "/files/logstash/logstash-1.0.17-monolithic.jar" :verb "get" :response "304" :value 193}
+   {:request "/files/logstash/logstash-1.0.17-monolithic.jar" :verb "head" :response "200" :value 634}
+   {:request "/images/web/2009/banner.png" :verb "get" :response "200" :value 72668621}
+   {:request "/images/web/2009/banner.png" :verb "get" :response "304" :value 2987}
+   {:request "/files/logstash/logstash-1.0.12-monolithic.jar" :verb "get" :response "200" :value 37853629}
+   {:request "/files/logstash/logstash-1.0.14-monolithic.jar" :verb "get" :response "200" :value 34408788}
+   {:request "/files/logstash/logstash-1.0.6-monolithic.jar" :verb "get" :response "200" :value 33826430}])

 (deftest handle-agg-resp-test
   (is (= sample-parsets-data


cleanup

cleanup

--- kafka-clj/src/kafka_clj/client.clj
+++ kafka-clj/src/kafka_clj/client.clj
@@ -73,6 +73,7 @@
              (do
                (if (> (count v) 0)
                  (do
+                   ;(prn "Sending buffered messages " v)
                    (try (send-messages producer conf v) (catch Exception e (error e e)))))
                 (recur))))


Minor changes helping with last rebase.

Minor changes helping with last rebase.

--- src/postal/message.clj
+++ src/postal/message.clj
@@ -47,12 +47,11 @@
   ([addr ^String charset]
    (if (instance? InternetAddress addr)
      addr
-     (let [a (try (InternetAddress. addr)
-                  (catch Exception _))]
-       (if a
-         (InternetAddress. (.getAddress a)
-                           (.getPersonal a)
-                           charset)))))
+     (when-let [^InternetAddress a (try (InternetAddress. addr)
+                                        (catch Exception _))]
+       (InternetAddress. (.getAddress a)
+                         (.getPersonal a)
+                         charset))))
   ([^String addr ^String name-str ^String charset]
    (try (InternetAddress. addr name-str charset)
         (catch Exception _))))
@@ -87,7 +86,7 @@
       (sequential? addrs)
       (doseq [addr addrs]
         (add-recipient! jmsg rtype addr charset)))
-      :otherwise
+    :otherwise
       (add-recipient! jmsg rtype addrs charset))
   jmsg)

@@ -169,30 +168,30 @@
                        (Session/getInstance props)))]
      (make-jmessage msg session)))
   ([msg session]
-     (let [standard [:from :reply-to :to :cc :bcc
-                     :date :subject :body :message-id
-                     :user-agent :sender]
-           charset (or (:charset msg) default-charset)
-           jmsg (proxy [MimeMessage] [^Session session]
-                  (updateMessageID []
-                    (.setHeader
-                     ^MimeMessage this
-                     "Message-ID" ((:message-id msg message-id)))))]
-       (doto ^MimeMessage jmsg
-         (add-recipients! Message$RecipientType/TO (:to msg) charset)
-         (add-recipients! Message$RecipientType/CC (:cc msg) charset)
-         (add-recipients! Message$RecipientType/BCC (:bcc msg) charset)
-         (.setFrom (let [{:keys [from sender]} msg]
-                     ^InternetAddress
-                     (make-address (or from sender) charset)))
-         (.setReplyTo (when-let [reply-to (:reply-to msg)]
-                        (make-addresses reply-to charset)))
-         (.setSubject (:subject msg) ^String charset)
-         (.setSentDate (or (:date msg) (make-date)))
-         (.addHeader "User-Agent" (:user-agent msg (user-agent)))
-         (add-extra! (apply dissoc msg standard))
-         (add-body! (:body msg) charset)
-         (.saveChanges)))))
+   (let [standard [:from :reply-to :to :cc :bcc
+                   :date :subject :body :message-id
+                   :user-agent :sender]
+         charset (or (:charset msg) default-charset)
+         jmsg (proxy [MimeMessage] [^Session session]
+                (updateMessageID []
+                  (.setHeader
+                   ^MimeMessage this
+                   "Message-ID" ((:message-id msg message-id)))))]
+     (doto ^MimeMessage jmsg
+       (add-recipients! Message$RecipientType/TO (:to msg) charset)
+       (add-recipients! Message$RecipientType/CC (:cc msg) charset)
+       (add-recipients! Message$RecipientType/BCC (:bcc msg) charset)
+       (.setFrom (let [{:keys [from sender]} msg]
+                   ^InternetAddress
+                   (make-address (or from sender) charset)))
+       (.setReplyTo (when-let [reply-to (:reply-to msg)]
+                      (make-addresses reply-to charset)))
+       (.setSubject (:subject msg) ^String charset)
+       (.setSentDate (or (:date msg) (make-date)))
+       (.addHeader "User-Agent" (:user-agent msg (user-agent)))
+       (add-extra! (apply dissoc msg standard))
+       (add-body! (:body msg) charset)
+       (.saveChanges)))))

 (defn make-fixture [from to & {:keys [tag]}]
   (let [uuid (str (UUID/randomUUID))


Fix wrong headers parsing when no headers are received.

--- src/postal/parser.cljc
+++ src/postal/parser.cljc
@@ -118,7 +118,6 @@
                    (assoc frame :headers (assoc (:headers frame)
                                                 (keyword (str/lower (read-header-key reader)))
                                                 (read-header-value reader))))))
-
       (= parsing :body)
       (do
         (reader/read-char reader)
@@ -128,8 +127,8 @@

       (= parsing :complete)
       (frames/frame (:command frame)
-                    (:headers frame)
-                    (:body frame))
+                    (:headers frame {})
+                    (:body frame ""))

       (= chr-in ::continue)
       (recur (reader/read-char reader)


Test for handling unknown input in get-output-format

--- test/emender_jenkins/rest_api_test.clj
+++ test/emender_jenkins/rest_api_test.clj
@@ -410,3 +410,10 @@
             "application/json" nil
             "application/json" :other)))

+(deftest test-get-output-format-default
+    "Check the function emender-jenkins.rest-api/get-output-format."
+    (testing "the function emender-jenkins.rest-api/get-output-format."
+        (are [x y] (= x (get-output-format y))
+            :json nil
+            :json :other)))
+


some formatting cleanup in pages.clj

some formatting cleanup in pages.clj

--- src/pronouns/pages.clj
+++ src/pronouns/pages.clj
@@ -8,8 +8,7 @@
   [:b pronoun])

 (defn render-sentence [& content]
-  [:p [:span.sentence content]]
-)
+  [:p [:span.sentence content]])

 (defn subject-example
   [subject]
@@ -21,7 +20,10 @@

 (defn posessive-determiner-example
   [subject possessive-determiner]
-  (render-sentence (wrap-pronoun (s/capitalize subject)) " brought " (wrap-pronoun possessive-determiner) " frisbee."))
+  (render-sentence (wrap-pronoun (s/capitalize subject))
+                   " brought "
+                   (wrap-pronoun possessive-determiner)
+                   " frisbee."))

 (defn possessive-pronoun-example
   [possessive-pronoun]
@@ -29,7 +31,10 @@

 (defn reflexive-example
   [subject reflexive]
-  (render-sentence (wrap-pronoun (s/capitalize subject)) " threw the frisbee to " (wrap-pronoun reflexive) "."))
+  (render-sentence (wrap-pronoun (s/capitalize subject))
+                   " threw the frisbee to "
+                   (wrap-pronoun reflexive)
+                   "."))

 (defn title-block [title]
   [:div {:class "title"}


added disqus

added disqus

--- src/publisher/core.clj
+++ src/publisher/core.clj
@@ -6,6 +6,7 @@
             [hiccup.core :as hiccup]
             [clojure.string :as string])
   (:import [java.io File]
+           [java.util Calendar Date]
            [java.net URLEncoder URLDecoder]))

 (defn files-in-directory [directory-path]
@@ -17,11 +18,44 @@

 (def directory "/Users/jukka/Downloads/kuntotiedot/68356_kiinteistojen_kuntotiedot_Vaahterakuja-Vaskivuori")

+(def facebook-sdk [[:div {:id "fb-root"}]
+                   [:script "(function(d, s, id) {
+  var js, fjs = d.getElementsByTagName(s)[0];
+  if (d.getElementById(id)) return;
+  js = d.createElement(s); js.id = id;
+  js.src = \"//connect.facebook.net/fi_FI/sdk.js#xfbml=1&version=v2.3\";
+  fjs.parentNode.insertBefore(js, fjs);
+}(document, 'script', 'facebook-jssdk'));"]])
+
+(def like-button [:div {:class "fb-like"
+                        :data-href="https://developers.facebook.com/docs/plugins/"
+                        :data-layout="standard"
+                        :data-action="like"
+                        :data-show-faces="true"
+                        :data-share="true"}])
+
+(def disqus "

+
+Please enable JavaScript to view the comments powered by Disqus.")
+
 (defn page [& content]
   (hiccup/html [:html
                 [:head
                  [:title "Kuntotiedot"]]
-                [:body content]]))
+                [:body (concat facebook-sdk
+                               content)]]))
+
+

 (defn fix-file-name [file-name]
   (-> file-name
@@ -30,6 +64,24 @@
 (defn file-name [file]
   (-> (.getName file)
       (fix-file-name)))
+
+(defn date-to-map [date]
+  (let [calendar (Calendar/getInstance)]
+    (.setTime calendar date)
+    {:year (.get calendar Calendar/YEAR)
+     :month (+ 1 (.get calendar Calendar/MONTH))
+     :day (.get calendar Calendar/DAY_OF_MONTH)
+     :hour (.get calendar Calendar/HOUR_OF_DAY)
+     :minute (.get calendar Calendar/MINUTE)
+     :second (.get calendar Calendar/SECOND)}))
+
+(defn date-string [{:keys [year month day]}]
+  (str day "." month "." year))
+
+
+
+(defn last-modified-date [file]
+  (date-to-map (Date. (.lastModified file))))

 (defn app []
   (compojure/routes (compojure/GET "/" [] (page [:ul (for [file (.listFiles (File. directory))]
@@ -47,7 +99,14 @@
                     (compojure/GET "/:folder/:file" [folder file] (page [:a {:href (str "/get/" folder "/" file)}
                                                                          (-> file
                                                                              (URLDecoder/decode)
-                                                                             (fix-file-name))]))))
+                                                                             (fix-file-name))
+                                                                         " "
+                                                                         (-> (str directory "/" (URLDecoder/decode folder) "/" (URLDecoder/decode file))
+                                                                             (File.)
+                                                                             (last-modified-date)
+                                                                             (date-string))]
+                                                                        like-button
+                                                                        disqus))))

 (def handler (app))


DM | Check that recipient has received amount in transaction journey test

--- test/freecoin/journey/transactions.clj
+++ test/freecoin/journey/transactions.clj
@@ -32,11 +32,10 @@
       (k/visit (str (routes/absolute-path (c/create-config) :sso-callback) "?code=" auth-code))
       (kc/check-and-follow-redirect "to account page")))

+(def sign-in sign-up)
+
 (defn sign-out [state]
-  (k/visit state (routes/absolute-path (c/create-config) :sign-out))
-  ;; TODO: May need to follow redirect to actually
-  ;; sign out...
-  )
+  (k/visit state (routes/absolute-path (c/create-config) :sign-out)))

 (facts "Participant can send freecoins to another account"
        (let [memory (atom {})]
@@ -59,4 +58,8 @@

              (kc/check-and-follow-redirect "to sender's account page")
              (kc/check-page-is :account [ks/account-page-body] :uid (kh/recall memory :sender-uid))
-             (kc/selector-includes-content [ks/account-page--balance] "-10"))))
+             (kc/selector-includes-content [ks/account-page--balance] "-10")
+
+             (sign-in "recipient")
+             (kc/check-page-is :account [ks/account-page-body] :uid (kh/recall memory :recipient-uid))
+             (kc/selector-includes-content [ks/account-page--balance] "10"))))


adding placement

adding placement

--- src/aws/provider.clj
+++ src/aws/provider.clj
@@ -26,7 +26,7 @@
     [trammel.core :refer (defconstrainedrecord)]
     [celestial.provider :refer (wait-for wait-for-ssh)]
     [celestial.core :refer (Vm)]
-    [celestial.common :refer (import-logging )]
+    [celestial.common :refer (import-logging)]
     [celestial.persistency.systems :as s]
     [celestial.model :refer (translate vconstruct)]))

@@ -49,7 +49,8 @@

 (defn creation-keys [aws]
   (clojure.set/subset? (into #{} (keys aws))
-    #{:volumes :min-count :max-count :instance-type :key-name}))
+    #{:volumes :min-count :max-count :instance-type
+      :key-name :placement :security-groups}))

 (defn create-instance
    "creates instance from aws"
@@ -57,7 +58,7 @@
    {:pre [(creation-keys aws)]}
    (let [inst (merge (dissoc aws :volumes) {:image-id (image-id machine)})
          {:keys [reservation]} (with-ctx ec2/run-instances inst)]
-     (get-in reservation  [:instances 0 :instance-id])))
+     (get-in reservation [:instances 0 :instance-id])))

 (defconstrainedrecord Instance [endpoint spec user]
   "An Ec2 instance"
@@ -118,10 +119,15 @@

 (def defaults {:aws {:min-count 1 :max-count 1}})

+(defn map-key [m from to]
+  (dissoc-in* (assoc-in m to (get-in m from)) from))
+
 (defn aws-spec
   "creates an ec2 spec"
   [{:keys [aws machine] :as spec}]
-  (merge-with merge (dissoc-in* spec [:aws :endpoint]) defaults))
+  (cond-> (merge-with merge (dissoc-in* spec [:aws :endpoint]) defaults)
+    :availability-zone
+      (map-key [:aws :availability-zone] [:aws :placement :availability-zone])))

 (defmethod translate :aws [{:keys [aws machine] :as spec}]
   [(aws :endpoint) (aws-spec spec) (or (machine :user) "root")])


fix typos

fix typos

--- src/babel/writer.clj
+++ src/babel/writer.clj
@@ -46,10 +46,10 @@

         target-language-sentence (engine/generate spec target-language-model :enrich true)

-        target-language-sentence (if (:morph-walk-tree (if (future? target-language-model)
-                                                         @target-language-model
-                                                         target-langauge-model))
-                                   (:morph-walk-tree target-language-sentence))
+ ;       target-language-sentence (if (:morph-walk-tree (if (future? target-language-model)
+ ;                                                        @target-language-model
+ ;                                                        target-language-model))
+ ;                                  (:morph-walk-tree target-language-sentence))

         target-language-sentence (let [subj (get-in target-language-sentence
                                                     [:synsem :sem :subj] :notfound)]
@@ -69,10 +69,10 @@
         source-language-sentence (engine/generate (get-in target-language-sentence
                                                           [:synsem :sem] :top)
                                                   source-language-model :enrich true)
-        source-language-sentence (if (:morph-walk-tree (if (future? source-language-model)
-                                                         @source-language-model
-                                                         source-langauge-model))
-                                   (:morph-walk-tree source-language-sentence))
+;        source-language-sentence (if (:morph-walk-tree (if (future? source-language-model)
+;                                                         @source-language-model
+;                                                         source-language-model))
+;                                   (:morph-walk-tree source-language-sentence))

         semantics (strip-refs (get-in target-language-sentence [:synsem :sem] :top))
         debug (log/debug (str "semantics of resulting expression: " semantics))


Normalize the order of returned data from read function.

--- src/bytebuf/spec.clj
+++ src/bytebuf/spec.clj
@@ -54,7 +54,7 @@
       (read [_ buff pos]
         (loop [index pos result {} pairs data]
           (if-let [[fieldname type] (first pairs)]
-            (let [[readeddata readedbytes] (read type buff index)]
+            (let [[readedbytes readeddata] (read type buff index)]
               (recur (+ index readedbytes)
                      (assoc result fieldname readeddata)
                      (rest pairs)))
@@ -87,7 +87,7 @@
     (read [_ buff pos]
       (loop [index pos result [] types types]
         (if-let [type (first types)]
-          (let [[readeddata readedbytes] (read type buff index)]
+          (let [[readedbytes readeddata] (read type buff index)]
             (recur (+ index readedbytes)
                    (conj result readeddata)
                    (rest types)))
@@ -120,8 +120,8 @@

      IReadableSpec
      (read [_ buff pos]
-       [(buffer/read-int buff pos)
-        (Integer/BYTES)])
+       [(Integer/BYTES)
+        (buffer/read-int buff pos)])

      IWritableSpec
      (write [_ buff pos value]
@@ -143,8 +143,8 @@

      IReadableSpec
      (read [_ buff pos]
-       [(buffer/read-long buff pos)
-        (Long/BYTES)])
+       [(Long/BYTES)
+        (buffer/read-long buff pos)])

      IWritableSpec
      (write [_ buff pos value]


Make Reaction a little smaller

Make Reaction a little smaller

--- src/reagent/ratom.cljs
+++ src/reagent/ratom.cljs
@@ -359,9 +359,8 @@
   (._handle-change this sender old new))

-(deftype Reaction [f ^:mutable state ^:mutable ^boolean dirty?
-                   ^:mutable watching ^:mutable watches
-                   ^:mutable auto-run on-set on-dispose ^boolean nocache?]
+(deftype Reaction [f ^:mutable state ^:mutable ^boolean dirty? ^boolean nocache?
+                   ^:mutable watching ^:mutable watches ^:mutable auto-run]
   IAtom
   IReactiveAtom

@@ -376,10 +375,10 @@

   IReset
   (-reset! [a newval]
-    (assert (ifn? on-set) "Reaction is read only.")
+    (assert (fn? (.-on-set a)) "Reaction is read only.")
     (let [oldval state]
       (set! state newval)
-      (on-set oldval newval)
+      (.on-set a oldval newval)
       (notify-w a oldval newval)
       newval))

@@ -408,15 +407,16 @@
     nil)

   (_update-watching [this derefed]
-    (let [wg watching]
-      (set! watching derefed)
-      (doseq [w derefed]
+    (let [der (if (zero? (arr-len derefed)) nil derefed)
+          wg watching]
+      (set! watching der)
+      (doseq [w der]
         (when (or (nil? wg)
                   (== -1 (.indexOf wg w)))
           (-add-watch w this handle-reaction-change)))
       (doseq [w wg]
-        (when (or (nil? derefed)
-                  (== -1 (.indexOf derefed w)))
+        (when (or (nil? der)
+                  (== -1 (.indexOf der w)))
           (-remove-watch w this))))
     nil)

@@ -490,8 +490,8 @@
       (set! dirty? true)
       (doseq [w wg]
         (remove-watch w this))
-      (when-not (nil? on-dispose)
-        (on-dispose s)))
+      (when-not (nil? (.-on-dispose this))
+        (.on-dispose this s)))
     nil)

   IEquiv
@@ -505,8 +505,7 @@

 (defn make-reaction [f & {:keys [auto-run on-set on-dispose]}]
-  (let [reaction (Reaction. f nil true nil nil
-                            nil nil nil false)]
+  (let [reaction (Reaction. f nil true false nil nil nil)]
     (._set-opts reaction {:auto-run auto-run
                           :on-set on-set
                           :on-dispose on-dispose})


Detect new data avia par no

Detect new data avia par no

--- src/clj_simple_chart/eurostat/data/avia_par_no.clj
+++ src/clj_simple_chart/eurostat/data/avia_par_no.clj
@@ -113,6 +113,8 @@
                 (name)
                 (read-string)))

+(def max-year-kw (keyword (str max-year)))
+
 (test/is (= 2016 max-year))

 (defn add-item [a b]
@@ -177,13 +179,15 @@
                        (sort-by :date)
                        (vec)))

+(test/is (= "2017-06" (:date (last data-monthly))))
+
 (csvmap/write-csv "data/eurostat/avia-par-no-pas-carried.csv"
                   {:columns (vec (distinct (concat regular-columns (reverse (sort (keys (first data)))))))
-                   :data    (reverse (sort-by #(:2016 %) data))})
+                   :data    (reverse (sort-by max-year-kw data))})

 (csvmap/write-csv "data/eurostat/avia-par-no-pas-carried-grouped.csv"
                   {:columns (vec (distinct (concat regular-columns (reverse (sort (keys (first data-grouped)))))))
-                   :data    (reverse (sort-by #(:2016 %) data-grouped))})
+                   :data    (reverse (sort-by max-year-kw data-grouped))})

 #_(csvmap/write-csv "data/eurostat/avia-par-no-pas-carried-monthly.csv"
                     {:columns (reverse (sort (keys (first data-monthly))))


Made alert in error-handler instead of .log js/console

--- src/kmg/client.cljs
+++ src/kmg/client.cljs
@@ -32,7 +32,8 @@
   ".recommendation-completed-title" (ef/content (:media/title media)))

 (defn error-handler [{:keys [status status-text]}]
-  (.log js/console (str "somthing bad happened: " status " " status-text)))
+  (js/alert (str "somthing bad happened: " status " " status-text))
+  #_(.log js/console (str "somthing bad happened: " status " " status-text)))

 (defn recommendation-list [data]
   (ef/at "#inner-content" (ef/content (map recommendation data))))


Fleshed out inverse-document-frequency-test.

--- project/analyze-data/test/analyze_data/tf_idf/inverse_document_frequency_test.clj
+++ project/analyze-data/test/analyze_data/tf_idf/inverse_document_frequency_test.clj
@@ -17,7 +17,16 @@
   (is (= (Math/log 5)
          (test-ns/inverse-document-frequency-math 5 1))))

-; TODO: flesh out this test
 (deftest inverse-document-frquency-test
-  (is (= {"a" (Math/log 2), "b" 0.0}
-         (test-ns/inverse-document-frequency [{"a" 5 "b" 1} {"b" 1}]))))
+  (is (= {}
+         (test-ns/inverse-document-frequency []))
+      "empty map when no documents")
+  (is (= {"a" (Math/log 1)}
+         (test-ns/inverse-document-frequency [{"a" 1}]))
+      "log(1) when single document containing term")
+  (is (= {"a" (Math/log 2)}
+         (test-ns/inverse-document-frequency [{"a" 1} {}]))
+      "log(2) when two documents and only one contains term")
+  (is (= {"a" (Math/log 2) "b" 0.0}
+         (test-ns/inverse-document-frequency [{"a" 1 "b" 1} {"b" 1}]))
+      "handles multiple terms"))


Add Find Form

Add Find Form

--- src/lens/routes.clj
+++ src/lens/routes.clj
@@ -34,9 +34,16 @@
     :links
     {:self {:href "/"}
      :lens/all-study-events {:href "/study-events"}
-     :lens/all-forms {:href "/forms"}}
+     :lens/all-forms {:href "/forms"}
+     :lens/all-snapshots {:href "/snapshots"}}
     :forms
-    {:lens/query
+    {:lens/find-form
+     {:action "/find-form"
+      :method "GET"
+      :params
+      {:id
+       {:type :string}}}
+     :lens/query
      {:action "/query"
       :method "GET"
       :title "Query"
@@ -244,6 +251,20 @@
        (->> (api/item-groups form)
             (sort-by :item-group/rank)
             (render-embedded-item-groups (timeout 100)))}})
+    (ring-resp/not-found
+     {:links {:up {:href "/forms"}}
+      :error "Form not found."})))
+
+(defn form-bare [db id]
+  (if-let [form (api/form db id)]
+    (ring-resp/response
+     {:id (:form/id form)
+      :alias (:form/alias form)
+      :name (:name form)
+      :type :form
+      :links
+      {:up {:href "/forms"}
+       :self {:href (str "/forms/" id)}}})
     (ring-resp/not-found
      {:links {:up {:href "/forms"}}
       :error "Form not found."})))
@@ -530,6 +551,8 @@

    (GET "/forms/:id" [db id] (form db id))

+   (GET "/find-form" [db id] (form-bare db id))
+
    (GET "/forms/:id/count" [db id] (form-count db id))

    (POST "/forms/:id/search-item-groups" [db id query]


[Fix] resutlt print

[Fix] resutlt print

--- src/clj_elm/core.clj
+++ src/clj_elm/core.clj
@@ -192,15 +192,15 @@
 (defn cross-validate
   ([dataset L k]
    {:pre [(instance? DataSet dataset) (integer? k) (integer? L)]}
-   (let [norm-dataset (atom (DataSet. (:classes dataset) (data/normalize (:features dataset))))
-         numd (count (:classes @norm-dataset)) ; number of data
+   (let [norm-dataset (DataSet. (:classes dataset) (data/normalize (:features dataset)))
+         numd (count (:classes norm-dataset)) ; number of data
          groupn (quot numd k)]                ; number of one group's element
      (->> (take k (iterate #(+ % groupn) 0))
           (pmap #(let [eva (_cross-validate norm-dataset % (+ % (dec groupn)) L)]
                    (dorun [(print-exp-data eva) (flush)])
-                   (:Accuracy eva)))
-          (reduce +)
-          (* (/ 1 k))))))
+                   eva))
+          (reduce +-exp)
+          (exp-result)))))

 (defn -main [& args]
   (if (= (count args) 8)
@@ -214,5 +214,8 @@
       (printfl "Fin data concat\n")
       (reset! dataset (data/shuffle-dataset @dataset))
       (printfl "Fin data shuffle\n")
-      (printfl (str (cross-validate @dataset (read-string (nth args 6)) (read-string (nth args 7))) "\n"))
+      (let [result (cross-validate @dataset (read-string (nth args 6)) (read-string (nth args 7)))]
+        (printfl "Final result:\n")
+        (print-exp-data result)
+        (flush))
       (System/exit 0))))


Pass IDs on to default-main

Pass IDs on to default-main

--- src/adzerk/boot_cljs.clj
+++ src/adzerk/boot_cljs.clj
@@ -177,7 +177,7 @@
         prev       (atom nil)]
     (assert-cljs-dependency!)
     (comp
-      (default-main)
+      (default-main :ids ids)
       (core/with-pre-wrap fileset
         (info "Compiling ClojureScript...\n")
         (let [diff          (fs-diff! prev fileset)


Sometimes I forget what I'm doing

Sometimes I forget what I'm doing

--- src/themis/predicates.clj
+++ src/themis/predicates.clj
@@ -23,8 +23,7 @@
    (length-between? t 0 high))
   ([t low high]
    (let [length (count t)]
-     (and (>= length low)
-          (<= length high)))))
+     (<= low length high))))

 (defn is-in? [t & items]
   (and (some #{t} items)


improve diagnostics

improve diagnostics

--- src/babel/lexiconfn.cljc
+++ src/babel/lexiconfn.cljc
@@ -267,9 +267,12 @@
                                                  :2 '()}}}))]
           (if (fail? result)
             (throw (exception (str "fail when trying to create common-noun from lexical-entry: " lexical-entry
-                                   "subcat: " (get-in lexical-entry [:synsem :subcat]) "; "
-                                   "subcat emptyness: " (empty? (get-in lexical-entry [:synsem :subcat])))))
-
+                                   "fail-path: "
+                                   (dag_unify.core/fail-path lexical-entry
+                                                             (unify agreement-noun
+                                                                    common-noun
+                                                                    {:synsem {:pronoun false
+                                                                              :subcat {:1 {:cat :det}}}})))))
             result))
         true
         lexical-entry))


Fix clojure test

Fix clojure test

--- src/test/clojure/rx/lang/clojure/blocking_test.clj
+++ src/test/clojure/rx/lang/clojure/blocking_test.clj
@@ -36,7 +36,7 @@
   (testing "returns one element"
     (is (= 1 (b/single (rx/return 1)))))
   (testing "throw if empty"
-    (is (thrown? java.lang.IllegalArgumentException (b/single (rx/empty)))))
+    (is (thrown? java.util.NoSuchElementException (b/single (rx/empty)))))
   (testing "throw if many"
     (is (thrown? java.lang.IllegalArgumentException (b/single (rx/seq->o [1 2])))))
   (testing "rethrows errors"


fix the fix, only parse the environment variable if the default is a number #6

--- src/bitfondue/config.clj
+++ src/bitfondue/config.clj
@@ -7,7 +7,9 @@
   (let [env-val (env env-key)]
     (if (nil? env-val)
       env-default-val
-      env-val)))
+      (if (number? env-default-val)
+        (read-string env-val)
+        env-val))))

 (def database
   (env :database-url))
@@ -29,4 +31,4 @@
    :port 587})

 (def ssl
-  {:ssl-port (read-string (env-default :ssl-port 443))})
+  {:ssl-port (env-default :ssl-port 443)})


Escape html fragments.

Escape html fragments.

--- src/uuuurrrrllll/core.clj
+++ src/uuuurrrrllll/core.clj
@@ -5,7 +5,8 @@
             [compojure.core :refer [defroutes routes GET POST]]
             [ring.adapter.jetty :as jetty]
             [ring.middleware.json :refer [wrap-json-body
-                                          wrap-json-response]])
+                                          wrap-json-response]]
+            [hiccup.util :refer [escape-html]])
   (:use [hiccup.core]))

@@ -48,7 +49,7 @@
    :body (html [:body
                 [:ul
                  (for [k (seq (wb/keys-in bucket))]
-                   (let [v (get-url k)]
+                   (let [v (escape-html (get-url k))]
                      [:li [:a {:href v} v]]))]])})

 (defroutes app


make duplicate keys a blocking error

make duplicate keys a blocking error

--- src/terraboot/core.clj
+++ src/terraboot/core.clj
@@ -14,7 +14,7 @@
           (fn [a b]
             (if (map? a)
               (do (when-let [dups (seq (set/intersection (set (keys a)) (set (keys b))))]
-                    (prn "Duplicate keys: " dups))
+                    (throw (Exception. (str "Duplicate keys: " dups))))
                   (merge-with ((first mfns) (rest mfns)) a b))
               b)))
         (merge-in*


indenting

indenting

--- src/celestial/common.clj
+++ src/celestial/common.clj
@@ -23,8 +23,6 @@
 (defn get* [& keys]
   (get-in config keys))

-
-
 (defn slurp-edn [file] (read-string (slurp file)))

 (defn import-logging []


remove missed extension stuff

remove missed extension stuff

--- src/chat/server/sync.clj
+++ src/chat/server/sync.clj
@@ -12,7 +12,6 @@
             [chat.server.digest :as digest]
             [clojure.set :refer [difference intersection]]
             [chat.shared.util :refer [valid-nickname? valid-tag-name?]]
-            [chat.server.extensions :refer [handle-thread-change]]
             [chat.server.email-digest :as email]
             [braid.common.schema :refer [new-message-valid?]]
             [braid.common.notify-rules :as notify-rules]
@@ -141,13 +140,6 @@
                     false))))
           (?data :mentioned-user-ids)))))

-(defn notify-extensions
-  "Notify extensions about a thread changing if they're interested"
-  [msg]
-  (let [exts (db/extensions-watching (msg :thread-id))]
-    (doseq [ext exts]
-      (handle-thread-change ext msg))))
-
 (defn notify-users [new-message]
   (let [subscribed-user-ids (->>
                               (db/get-users-subscribed-to-thread
@@ -203,8 +195,7 @@
           (when-let [cb ?reply-fn]
             (cb :braid/ok))
           (broadcast-thread (new-message :thread-id) [])
-          (notify-users new-message)
-          (notify-extensions new-message))
+          (notify-users new-message))
         (do
           (timbre/warnf "Malformed new message: %s" (pr-str new-message))
           (when-let [cb ?reply-fn]


Minor perf improvement: use UNION ALL to populate tx_lookup in a single INSERT.

--- src/datomish/db.cljc
+++ src/datomish/db.cljc
@@ -308,13 +308,29 @@
            (<? (<exec ["CREATE INDEX IF NOT EXISTS idx_tx_lookup_added ON tx_lookup (added0)"])))

         (p :join
-           ;; Fast, only one table walk: lookup by exact eav.
-           (p :join-eav
-              (<? (<exec [(str "INSERT INTO tx_lookup SELECT t.e0, t.a0, t.v0, t.tx0, t.added0 + 2, t.value_type_tag0, t.index_avet0, t.index_vaet0, t.index_fulltext0, t.unique_value0, t.sv, t.svalue_type_tag, d.rowid, d.e, d.a, d.v, d.tx, d.value_type_tag FROM tx_lookup AS t LEFT JOIN datoms AS d ON t.e0 = d.e AND t.a0 = d.a AND t.sv = d.v AND t.svalue_type_tag = d.value_type_tag AND t.sv IS NOT NULL")])))
-
-           ;; Slower, but still only one table walk: lookup old value by ea.
-           (p :join-ea
-              (<? (<exec [(str "INSERT INTO tx_lookup SELECT t.e0, t.a0, t.v0, t.tx0, t.added0 + 2, t.value_type_tag0, t.index_avet0, t.index_vaet0, t.index_fulltext0, t.unique_value0, t.sv, t.svalue_type_tag, d.rowid, d.e, d.a, d.v, d.tx, d.value_type_tag FROM tx_lookup AS t, datoms AS d WHERE t.sv IS NULL AND t.e0 = d.e AND t.a0 = d.a")]))))
+           (<?
+              (<exec
+                ;; First is fast, only one table walk: lookup by exact eav.
+                ;; Second is slower, but still only one table walk: lookup old value by ea.
+                ["INSERT INTO tx_lookup
+
+                 SELECT t.e0, t.a0, t.v0, t.tx0, t.added0 + 2, t.value_type_tag0, t.index_avet0, t.index_vaet0, t.index_fulltext0, t.unique_value0, t.sv, t.svalue_type_tag, d.rowid, d.e, d.a, d.v, d.tx, d.value_type_tag
+                 FROM tx_lookup AS t
+                 LEFT JOIN datoms AS d
+                 ON t.e0 = d.e AND
+                    t.a0 = d.a AND
+                    t.sv = d.v AND
+                    t.svalue_type_tag = d.value_type_tag AND
+                    t.sv IS NOT NULL
+
+                 UNION ALL
+                 SELECT t.e0, t.a0, t.v0, t.tx0, t.added0 + 2, t.value_type_tag0, t.index_avet0, t.index_vaet0, t.index_fulltext0, t.unique_value0, t.sv, t.svalue_type_tag, d.rowid, d.e, d.a, d.v, d.tx, d.value_type_tag
+                 FROM tx_lookup AS t,
+                      datoms AS d
+                 WHERE t.sv IS NULL AND
+                       t.e0 = d.e AND
+                       t.a0 = d.a
+                 "])))

         (p :insert-transaction
            (p :insert-transaction-added


Ditch the clojure core compile imp'l

Ditch the clojure core compile imp'l

--- src/oxcart.clj
+++ src/oxcart.clj
@@ -8,7 +8,7 @@
 ;;   notice, or any other, from this software.

 (ns oxcart
-  (:refer-clojure :exclude [eval macroexpand-1 macroexpand load])
+  (:refer-clojure :exclude [eval macroexpand-1 macroexpand load compile])
   (:require [clojure.tools.analyzer.jvm :as ana.jvm]
             [clojure.tools.analyzer
              :refer [macroexpand-1


Evidence of duplicate insertion

Evidence of duplicate insertion

--- src/todomvc/rules.cljs
+++ src/todomvc/rules.cljs
@@ -65,6 +65,13 @@
   [:ui/visibility-filter [[e a v]] (= v :done)]
   [:todo/done [[e a v]] (= e ?e)]
   =>
+  (insert! [?e :todo/visible :tag]))
+
+(defrule todo-is-visible-when-a-friday
+  [:exists [:today/is-friday]]
+  [:todo/title [[e a v]] (= ?e e)]
+  =>
+  (println "BOOM")
   (insert! [?e :todo/visible :tag]))

 ;(defrule show-active
@@ -213,6 +220,7 @@

 (def facts
   (apply concat
+    [[(random-uuid) :today/is-friday :tag]]
     (map->tuple (toggle-tx (random-uuid) true))
     (map->tuple (visibility-filter-tx (random-uuid) :all))
     (mapv map->tuple (repeatedly 5 #(todo-tx (random-uuid) "TODO" nil)))))
@@ -228,9 +236,10 @@
 ;(println "Done count: " (query session find-done-count))

-;(cljs.pprint/pprint (entity session (:db/id (first (clara-tups->maps all-done)))))
-
-;(cljs.pprint/pprint (find-by-attribute session :ui/visibility-filter))
+(cljs.pprint/pprint (entity session (:db/id (first (clara-tups->maps all-done)))))
+(cljs.pprint/pprint  all-done)
+
+(cljs.pprint/pprint (find-by-attribute session :ui/visibility-filter))

 (defn entities-where
   "Returns hydrated entities matching an attribute-only or an attribute-value query"
@@ -239,4 +248,4 @@
   ([session a v e] (map #(entity session (:db/id %)) (qave session a v e))))

 ;(cljs.pprint/pprint (map #(entity session (:db/id %)) (qav session :todo/done :done)))
-;(cljs.pprint/pprint (entities-where session :todo/visible :tag))
+(cljs.pprint/pprint (entities-where session :todo/visible :tag))


change `cljs.closure/build-modules` to return updated sorted module sequence using `cljs.closure/add-cljs-base-module` and `clj.closure/sort-modules`

--- src/clj/cljs/closure.clj
+++ src/clj/cljs/closure.clj
@@ -659,13 +659,14 @@
                            (when (some #{entry} (:provides source))
                              source))
                         sources)))
-        base-module (JSModule. "cljs_base")
         [sources' modules]
         (reduce
-          (fn [[sources modules] [name module-desc]]
+          (fn [[sources ret] [name module-desc]]
             (let [{:keys [entries output-to depends-on]} module-desc
                   js-module (JSModule. (clojure.core/name name))
                   [sources' module-sources]
+                  ;; compute inputs for a closure module
+                  ;; as well as sources difference
                   (reduce
                     (fn [[sources ret] entry-sym]
                       (if-let [entry (find-entry sources entry-sym)]
@@ -676,13 +677,17 @@
                           (IllegalArgumentException.
                             (str "Could not find namespace " entry-sym)))))
                     [sources []] entries)]
+              ;; add inputs to module
               (doseq [^SourceFile module-source module-sources]
                 (.add js-module module-source))
-              [sources' (conj modules js-module)]))
-          [sources [base-module]] (:modules opts))]
-    ;; add anything left to base
+              [sources'
+               (conj ret
+                 [name (assoc module-desc :closure-module js-module)])]))
+          [sources []] (sort-modules (add-cljs-base-module (:modules opts))))
+        cljs-base-closure-module (get-in modules [:cljs-base :closure-module])]
+    ;; add anything left to :cljs-base module
     (doseq [^SourceFile source sources']
-      (.add base-module source))
+      (.add ^JSModule cljs-base-closure-module source))
     modules))

 (comment
@@ -692,22 +697,23 @@
      :output-to "out/hello.js"
      :source-map true})

-  (build-modules
-    [(map->javascript-file
-       (ana/parse-ns 'cljs.core (io/file "out/cljs/core.js") nil))
-     (map->javascript-file
-       (ana/parse-ns 'cljs.reader (io/file "out/cljs/reader.js") nil))]
-    {:optimizations :advanced
-     :output-dir "out"
-     :cache-analysis true
-     :modules
-     {:core
-      {:output-to "out/modules/core.js"
-       :entries '#{cljs.core}}
-      :landing
-      {:output-to "out/modules/reader.js"
-       :entries '#{cljs.reader}
-       :depends-on #{:core}}}})
+  (let [modules
+        (build-modules
+          [(map->javascript-file
+             (ana/parse-ns 'cljs.core (io/file "out/cljs/core.js") nil))
+           (map->javascript-file
+             (ana/parse-ns 'cljs.reader (io/file "out/cljs/reader.js") nil))]
+          {:optimizations  :advanced
+           :output-dir     "out"
+           :cache-analysis true
+           :modules        {:core
+                            {:output-to "out/modules/core.js"
+                             :entries   '#{cljs.core}}
+                            :landing
+                            {:output-to  "out/modules/reader.js"
+                             :entries    '#{cljs.reader}
+                             :depends-on #{:core}}}})]
+    modules)
   )

 (defn optimize


add lines & mappings fields to JavaScriptFile. pass along build options to cljs.compiler/compile-root so it can detect :source-map

--- src/clj/cljs/closure.clj
+++ src/clj/cljs/closure.clj
@@ -253,7 +253,7 @@
                     s
                     (slurp (io/reader (-url this))))))

-(defrecord JavaScriptFile [foreign ^URL url provides requires]
+(defrecord JavaScriptFile [foreign ^URL url provides requires lines mappings]
   IJavaScript
   (-foreign? [this] foreign)
   (-url [this] url)
@@ -261,14 +261,20 @@
   (-requires [this] requires)
   (-source [this] (slurp (io/reader url))))

-(defn javascript-file [foreign ^URL url provides requires]
-  (JavaScriptFile. foreign url (map name provides) (map name requires)))
+(defn javascript-file
+  ([foreign ^URL url provides requires]
+     (javascript-file foreign url provides requires nil nil))
+  ([foreign ^URL url provides requires lines mappings]
+     (JavaScriptFile. foreign url (map name provides) (map name requires) lines mappings)))

 (defn map->javascript-file [m]
-  (javascript-file (:foreign m)
-                   (to-url (:file m))
-                   (:provides m)
-                   (:requires m)))
+  (javascript-file
+    (:foreign m)
+    (to-url (:file m))
+    (:provides m)
+    (:requires m)
+    (:lines m)
+    (:mappings m)))

 (defn read-js
   "Read a JavaScript file returning a map of file information."
@@ -376,7 +382,7 @@
   [^File src-dir opts]
   (let [out-dir (output-directory opts)]
     (map compiled-file
-         (comp/compile-root src-dir out-dir))))
+         (comp/compile-root src-dir out-dir opts))))

 (defn path-from-jarfile
   "Given the URL of a file within a jar, return the path of the file


CLJS-1041: Google Closure Modules :foreign-libs support

--- src/clj/cljs/closure.clj
+++ src/clj/cljs/closure.clj
@@ -664,12 +664,12 @@
    be augmented with a :closure-module entry holding the Closure JSModule."
   [sources opts]
   (let [find-entry (fn [sources entry]
-                     (let [entry (name (comp/munge entry))]
-                       (some
-                         (fn [source]
-                           (when (some #{entry} (:provides source))
-                             source))
-                        sources)))
+                     (some
+                       (fn [source]
+                         (when (some #{(name entry) (name (comp/munge entry))}
+                                 (:provides source))
+                           source))
+                       sources))
         [sources' modules]
         (reduce
           (fn [[sources ret] [name {:keys [entries output-to depends-on] :as module-desc}]]
@@ -804,8 +804,10 @@
   "Use the Closure Compiler to optimize one or more Closure JSModules. Returns
    a dependency sorted list of module name and description tuples."
   [opts & sources]
-  {:pre [(and (contains? opts :modules)
-              (not (contains? opts :output-to)))]}
+  ;; the following pre-condition can't be enabled
+  ;; lein-cljsbuild adds :output-to?
+  #_{:pre [(and (contains? opts :modules)
+                (not (contains? opts :output-to)))]}
   (let [closure-compiler (make-closure-compiler)
         ^List externs (load-externs opts)
         compiler-options (make-options opts)


AssertionError is not a subclass of Exception, apparently - we weren't catching assertion errors thrown by the changeset linking library.

--- src/clj/medusa/alert.clj
+++ src/clj/medusa/alert.clj
@@ -36,7 +36,7 @@
         (send-email (str "Alert for " metric_name " (" detector_name ") on " date)
                     (str "Alert details: " alert-url "\n\n" "Changeset for " buildid ": " changeset-url)
                     (concat subscribers foreign_subscribers ["dev-telemetry-alerts@lists.mozilla.org"])))
-      (catch Exception e ; could not find revisions for the given build date
+      (catch Throwable e ; could not find revisions for the given build date
         (log/error e "Retrieving changeset failed")
         (send-email (str "Alert for " metric_name " (" detector_name ") on " date)
                     (str "Alert details: " alert-url)


Flattened import of packages from dir structure

--- src/cljs/go/compiler.clj
+++ src/cljs/go/compiler.clj
@@ -87,7 +87,10 @@
       (let [ss (string/replace (str s) #"\/(.)" ".$1") ; Division is special
             ss (apply str (map #(if (reserved %) (str % "_") %)
                                (string/split ss #"(?<=\.)|(?=\.)")))
-            ms (clojure.lang.Compiler/munge ss)]
+            ms (string/split (clojure.lang.Compiler/munge ss) #"\.")
+            ms (if (butlast ms)
+                 (str (string/join "_"(butlast ms)) "." (last ms))
+                 (str (last ms)))]
         (if (symbol? s)
           (symbol ms)
           ms)))))
@@ -792,9 +795,9 @@
   (emitln "import (")
   (emitln "\t" (wrap-in-double-quotes "js"))
   (when-not (= name 'cljs.core)
-    (emitln "\t" (wrap-in-double-quotes "cljs.core")))
+    (emitln "\t" (wrap-in-double-quotes "cljs_core") " " (wrap-in-double-quotes "cljs/core")))
   (doseq [lib (distinct (into (vals requires) (vals uses)))]
-    (emitln "\t" (wrap-in-double-quotes (munge lib))))
+    (emitln "\t" (wrap-in-double-quotes (string/replace (munge lib) "." "_")) " " (wrap-in-double-quotes (string/replace (munge lib) "." "/"))))
   (emitln ")"))

 (defmethod emit* :deftype*


Trying to avoid double coercions and use of untyped nil

--- src/cljs/go/compiler.clj
+++ src/cljs/go/compiler.clj
@@ -435,9 +435,12 @@
       (emits "[]interface{}{" (comma-sep items) "}"))))

 (defmethod emit* :constant
-  [{:keys [form env]}]
+  [{:keys [form env tag]}]
   (when-not (= :statement (:context env))
-    (emit-wrap env (emit-constant form))))
+    (binding [*go-return-tag* (when (and (go-needs-coercion? tag *go-return-tag*)
+                                         (not (nil? form)))
+                                *go-return-tag*)]
+      (emit-wrap env (emit-constant form)))))

 (defn truthy-constant? [{:keys [op form]}]
   (and (#{:constant :list :vector :set :map} op) form))
@@ -771,39 +774,42 @@
                              (> arity (:max-fixed-arity info)))
         coerce? (and (or (:field info) (:binding-form? info) (= :invoke (:op f)))
                      (not (or fn? (= 'function (:tag info)))))
-        static-field-receiver? (-> expr :args first :target :info :type)]
-    (emit-wrap env
-      (cond
-       opt-not?
-       (emits "!(" (first args) ")")
-
-       protocol ;; needs to take the imported name of protocols into account, very lenient now, assumes any type implements it.
-       (let [pimpl (str (-> info :name name munge go-public) "_Arity" (count args))]
-         (emits (if (and (= (go-type tag) "interface{}")
-                         (not static-field-receiver?))
-                  (str (emit-str (first args)) ".(" (go-type-fqn protocol) ")")
-                  (first args) )
-                "." pimpl "(" (comma-sep (rest args)) ")"))
-
-       keyword?
-       (emits f ".X_invoke_Arity" arity "(" (comma-sep args) ")")
-
-       variadic-invoke
-       (emits f ".X_invoke_ArityVariadic(" (comma-sep args) ")")
-
-       native?
-       (emits f "(" (comma-sep args)  ")")
-
-       (and has-primitives? tags-match?)
-       (emits f ".Arity" arity primitive-sig "(" (comma-sep args) ")")
-
-       :else
-       (emits f (when coerce? ".(CljsCoreIFn)") ".X_invoke_Arity" arity "(" (comma-sep args) ")"))
-
-      ;; this is somewhat optimistic, the analyzer tags the expression based on the body of the fn, not the actual return type.
-      (when-not (or native? has-primitives?
-                    (= :statement (:context env)))
-        (emits (go-unbox-no-emit (:tag expr) nil))))))
+        static-field-receiver? (-> expr :args first :target :info :type)
+        ret-tag (:tag expr)]
+    (binding [*go-return-tag* (when (go-needs-coercion? ret-tag *go-return-tag*)
+                                *go-return-tag*)]
+      (emit-wrap env
+        (cond
+         opt-not?
+         (emits "!(" (first args) ")")
+
+         protocol ;; needs to take the imported name of protocols into account, very lenient now, assumes any type implements it.
+         (let [pimpl (str (-> info :name name munge go-public) "_Arity" (count args))]
+           (emits (if (and (= (go-type tag) "interface{}")
+                           (not static-field-receiver?))
+                    (str (emit-str (first args)) ".(" (go-type-fqn protocol) ")")
+                    (first args) )
+                  "." pimpl "(" (comma-sep (rest args)) ")"))
+
+         keyword?
+         (emits f ".X_invoke_Arity" arity "(" (comma-sep args) ")")
+
+         variadic-invoke
+         (emits f ".X_invoke_ArityVariadic(" (comma-sep args) ")")
+
+         native?
+         (emits f "(" (comma-sep args)  ")")
+
+         (and has-primitives? tags-match?)
+         (emits f ".Arity" arity primitive-sig "(" (comma-sep args) ")")
+
+         :else
+         (emits f (when coerce? ".(CljsCoreIFn)") ".X_invoke_Arity" arity "(" (comma-sep args) ")"))
+
+        ;; this is somewhat optimistic, the analyzer tags the expression based on the body of the fn, not the actual return type.
+        (when-not (or native? has-primitives?
+                      (= :statement (:context env)))
+          (emits (go-unbox-no-emit ret-tag nil)))))))

 (defn normalize-goog-ctor [ctor]
   (let [parts (string/split (-> ctor :info :name str) #"\.")


Fix path in trip component to use LatLng

--- src/cljs/gtfve/maps.cljs
+++ src/cljs/gtfve/maps.cljs
@@ -154,7 +154,9 @@
         path (->> stop-times
                   (map :stop-time/stop)
                   (map (juxt :stop/latitude
-                             :stop/longitude)))]
+                             :stop/longitude))
+                  (map (fn [[lat lng]]
+                         (Maps.LatLng. lat lng))))]
     ;; TODO: add markers
     [:span
      [r-map-object Maps.PolyLine (merge default-polyline-opts {:path path}) gmap]]))


Experiment more with meta-errors

Experiment more with meta-errors

--- src/clojush/evaluate.clj
+++ src/clojush/evaluate.clj
@@ -674,7 +674,7 @@
                          (< e (max p1e p2e)) 2
                          :else 3)))
                 (vec (repeat (count (:errors ind)) 3)))
-              (if (and (:parent1-errors ind)
+              #_(if (and (:parent1-errors ind)
                        (:parent2-errors ind))
                 (vec (for [[e p1e p2e] (mapv #(vector %1 %2 %3)
                                              (:errors ind)
@@ -685,6 +685,20 @@
                          (< e (max p1e p2e)) 1
                          :else 2)))
                 (vec (repeat (count (:errors ind)) 2)))
+              (if (and (:parent1-errors ind)
+                       (:parent2-errors ind))
+                (vec (for [[e p1e p2e] (mapv #(vector %1 %2 %3)
+                                             (:errors ind)
+                                             (:parent1-errors ind)
+                                             (:parent2-errors ind))]
+                       (cond
+                         (zero? e) 0
+                         (< e (min p1e p2e)) 1
+                         (= e (min p1e p2e)) 2
+                         (< e (max p1e p2e)) 3
+                         (= e (max p1e p2e)) 4
+                         :else 5)))
+                (vec (repeat (count (:errors ind)) 5)))
               ;
               (= cat :error-neglect)
               #_(if (and (:parent1-errors ind) (:parent2-errors ind))


Made todo demo a bit cleaner

Made todo demo a bit cleaner

By making the spacing a bit nicer

--- src/webapp/framework/client/components/main_view.cljs
+++ src/webapp/framework/client/components/main_view.cljs
@@ -41,7 +41,8 @@
                         [new-value  "ACTIVE"]  ))))

-                (div {} (str "Show: " (read-ui app [:show])))
+                (div {:style {:padding "10px" :backgoundColor "white"}})
+
                 (realtime select
                                 id, item, item_status
                           from
@@ -68,7 +69,7 @@
                                                      (go (sql "update  coils_todo_items   set item_status = 'ACTIVE' where id = ?" [item-id]  ))
                                                    )))})

-                           (div {:className (if (= (<-- :item_status) "COMPLETED") "completed" "item")} (str (<-- :item)))
+                           (div {:style {:width   "50%"} :className (if (= (<-- :item_status) "COMPLETED") "completed" "item")} (str (<-- :item)))
                            (button {:className   "destroy"
                                  :style {:width   "10%"}
                                  :onClick


A bit about paging

A bit about paging

--- test/layzee/integration/paging_search_examples.clj
+++ test/layzee/integration/paging_search_examples.clj
@@ -9,9 +9,19 @@
             [layzee.adapters.logging :refer :all]))

 (facts "How to collect search results in pages"
-       (fact "for example, searching for mentions in small pages"
-             (let [search-results (search/by-keyword settings/twitter-bearer-token "@iamkey" {:count 20 :page-size 5})]
-               (println search-results)
-               (count search-results) => 20)
-             )
-       )+       (future-fact "for example, searching for mentions in small pages"
+             (let [search-results (search/by-keyword settings/twitter-bearer-token "@iamkey" {:limit 3 :page-size 1})]
+               ;;(println search-results)
+               (count search-results) => 20)))
+
+(defn- page
+  ":fn-producer -- the source, :fn-stop -- how we tell we're finished, :result -- collects the results"
+  ([fn-producer fn-stop result]
+     (if (apply fn-stop [result])
+       result
+         (recur fn-producer fn-stop (concat (apply fn-producer []) result)))))
+
+(facts "How to page arbitrary sequences"
+       (fact "for example, collect 20 results 5 at a time"
+             (let [result (page #(range 5) #(<= 20 (count %)) '())]
+               (count result) => 20)))


proc changed

proc changed

--- src/webdriver/proc.clj
+++ src/webdriver/proc.clj
@@ -1,7 +1,8 @@
 (ns webdriver.proc
   (:require [clojure.java.io :as io])
   (:import java.lang.Runtime
-           java.lang.IllegalThreadStateException))
+           java.lang.IllegalThreadStateException
+           java.io.IOException))

 (defmacro exec [& args]
   `(.exec (Runtime/getRuntime) ~@args))
@@ -37,10 +38,14 @@
   (-> proc .destroy))

 (defn read-out [proc]
-  (-> proc .getInputStream slurp))
+  (try
+    (-> proc .getInputStream slurp)
+    (catch IOException _)))

 (defn read-err [proc]
-  (-> proc .getErrorStream slurp))
+  (try
+    (-> proc .getErrorStream slurp)
+    (catch IOException _)))

 (defmacro with-proc [proc args & body]
   `(let [~proc (apply run ~args)]


Cleanup omnibus.log namespace form

Cleanup omnibus.log namespace form

--- src/omnibus/log.clj
+++ src/omnibus/log.clj
@@ -18,8 +18,7 @@
 ;;

 (ns omnibus.log
-  (:use [clojure.contrib.logging :only [log]])
-  (:require [clojure.contrib.string :as str])
+  (:use (clojure.contrib (logging :only [log])))
   (:gen-class))

 (defn log-sh-result


OO: Add hyphen->camel-case transformer The one that comes with inflections library is broken in CLJS

--- src/hatti/utils.cljs
+++ src/hatti/utils.cljs
@@ -1,6 +1,5 @@
 (ns hatti.utils
-  (:require [clojure.string :refer [split join]]
-            [clojure.string :refer [join lower-case split]]
+  (:require [clojure.string :refer [join lower-case split upper-case replace]]
             [goog.string.format]
             [goog.string]
             [inflections.core :refer [plural]]))
@@ -70,3 +69,11 @@
    (if case-sensitive?
      (substring? substring string)
      (substring? (lower-case substring) (lower-case string)))))
+
+(defn hyphen->camel-case
+  [source-string]
+  (js/console.log source-string)
+  (replace source-string
+           #"(-)(.)"
+           #(let [[_ _ letter-to-uppercase] %]
+              (upper-case letter-to-uppercase))))


CMR-3795: Added reference to info.

CMR-3795: Added reference to info.

--- common-app-lib/src/cmr/common_app/services/search/validators/max_number_of_conditions.clj
+++ common-app-lib/src/cmr/common_app/services/search/validators/max_number_of_conditions.clj
@@ -1,7 +1,7 @@
 (ns cmr.common-app.services.search.validators.max-number-of-conditions
   "Validates that a query does not contain more than the configured maximum number of conditions"
   (require [cmr.common-app.services.search.query-model]
-           [cmr.common.log :refer [debug]]
+           [cmr.common.log :refer [debug info]]
            [cmr.common.config :refer [defconfig]]))

 (defconfig max-number-of-conditions


ordering and equality properties

ordering and equality properties

--- src/latte/subset.clj
+++ src/latte/subset.clj
@@ -18,11 +18,11 @@
   such as dependent pairs and sigma-types."

   (:refer-clojure :exclude [and or not set])
-
+
   (:require [latte.core :as latte :refer [defterm defthm forall assume have proof lambda]])

   (:require [latte.prop :as p :refer [<=> and or not]])
-
+
   (:require [latte.equal :as eq :refer [equal]])
   )

@@ -43,11 +43,101 @@
     (==> (elem T x s1)
          (elem T x s2))))

+(defthm subseteq-refl
+  "The subset relation is reflexive."
+  [[T :type] [s (set T)]]
+  (subseteq T s s))
+
+(proof subseteq-refl :script
+  (assume [x T
+           H (elem T x s)]
+    (have a (elem T x s) :by H)
+    (have b (==> (elem T x s)
+                 (elem T x s)) :discharge [H (a)])
+    (have c (subseteq T s s) :discharge [x (b)])
+    (qed c)))
+
+(defthm subseteq-trans
+  "The subset relation is transitive."
+  [[T :type] [s1 (set T)] [s2 (set T)] [s3 (set T)]]
+  (==> (subseteq T s1 s2)
+       (subseteq T s2 s3)
+       (subseteq T s1 s3)))
+
+(proof subseteq-trans :script
+  (assume [H1 (subseteq T s1 s2)
+           H2 (subseteq T s2 s3)]
+    (assume [x T]
+      (have a (==> (elem T x s1)
+                   (elem T x s2)) :by (H1 x))
+      (have b (==> (elem T x s2)
+                   (elem T x s3)) :by (H2 x))
+      (have c (==> (elem T x s1)
+                   (elem T x s3)) :by ((p/impl-trans (elem T x s1)
+                                                     (elem T x s2)
+                                                     (elem T x s3)) (a) (b)))
+      (have d (subseteq T s1 s3) :discharge [x (c)]))
+    (qed d)))
+
 (defterm seteq
   "Equality on sets."
   [[T :type] [s1 (set T)] [s2 (set T)]]
   (and (subseteq T s1 s2)
        (subseteq T s2 s1)))
+
+(defthm seteq-refl
+  "Set equality is reflexive."
+  [[T :type] [s (set T)]]
+  (seteq T s s))
+
+(proof seteq-refl :script
+  (have a (subseteq T s s) :by (subseteq-refl T s))
+  (have b (and (subseteq T s s)
+               (subseteq T s s))
+        :by ((p/and-intro (subseteq T s s)
+                          (subseteq T s s)) (a) (a)))
+  (qed b))
+
+(defthm seteq-sym
+  "Set equality is symmetric."
+  [[T :type] [s1 (set T)] [s2 (set T)]]
+  (==> (seteq T s1 s2)
+       (seteq T s2 s1)))
+
+(proof seteq-sym :script
+  (assume [H (seteq T s1 s2)]
+    (have a (subseteq T s1 s2) :by ((p/and-elim-left (subseteq T s1 s2)
+                                                       (subseteq T s2 s1)) H))
+    (have b (subseteq T s2 s1) :by ((p/and-elim-right (subseteq T s1 s2)
+                                                        (subseteq T s2 s1)) H))
+    (have c (seteq T s2 s1) :by ((p/and-intro (subseteq T s2 s1)
+                                              (subseteq T s1 s2)) (b) (a)))
+    (qed c)))
+
+(defthm seteq-trans
+  "Set equality is transitive."
+  [[T :type] [s1 (set T)] [s2 (set T)] [s3 (set T)]]
+  (==> (seteq T s1 s2)
+       (seteq T s2 s3)
+       (seteq T s1 s3)))
+
+(proof seteq-trans :script
+  (assume [H1 (seteq T s1 s2)
+           H2 (seteq T s2 s3)]
+    (have a1 (subseteq T s1 s2) :by ((p/and-elim-left (subseteq T s1 s2)
+                                                      (subseteq T s2 s1)) H1))
+    (have b1 (subseteq T s2 s3) :by ((p/and-elim-left (subseteq T s2 s3)
+                                                      (subseteq T s3 s2)) H2))
+    (have c1 (subseteq T s1 s3) :by ((subseteq-trans T s1 s2 s3) (a1) (b1)))
+    (have a2 (subseteq T s2 s1) :by ((p/and-elim-right (subseteq T s1 s2)
+                                                       (subseteq T s2 s1)) H1))
+    (have b2 (subseteq T s3 s2) :by ((p/and-elim-right (subseteq T s2 s3)
+                                                       (subseteq T s3 s2)) H2))
+    (have c2 (subseteq T s3 s1) :by ((subseteq-trans T s3 s2 s1) (b2) (a2)))
+    (have d (seteq T s1 s3) :by ((p/and-intro (subseteq T s1 s3)
+                                              (subseteq T s3 s1)) (c1) (c2)))
+    (qed d)))
+

 (defterm union
   "Set union."


test refactor: where possible, moved hosts to be local vars

--- libs/axiom-cljs/test/axiom_cljs/macros_test.cljs
+++ libs/axiom-cljs/test/axiom_cljs/macros_test.cljs
@@ -22,9 +22,6 @@
 (fact defview-1
       (defonce published1 (atom nil))
       (reset! published1 nil)
-      (defonce host {:pub (fn [ev]
-                            (swap! published1 conj ev))
-                     :sub (fn [key f])})
       (defview my-tweets [user]
         [:tweetlog/tweeted user tweet]))

@@ -35,7 +32,10 @@
 "When called for the first time, the function will send a `:reg` event with key according to the parameters,
 and return an empty sequence with a meta field `:pending` indicating that the function should be consulted again later."
 (fact defview-3
-      (let [res (my-tweets host "alice")]
+      (let [host {:pub (fn [ev]
+                         (swap! published1 conj ev))
+                  :sub (fn [key f])}
+            res (my-tweets host "alice")]
         (is (= res []))
         (is (= (-> res meta :pending) true))
         (is (= @published1 [{:kind :reg
@@ -48,10 +48,6 @@
       (defonce ps2 (ax/pubsub :name))
       (defonce published2 (atom nil))
       (reset! published2 nil)
-      (defonce host2 {:sub (:sub ps2)
-                      :pub #(swap! published2 conj %)
-                      :time (constantly 12345)
-                      :identity (atom "alice")})
       (defonce my-atom2 (atom nil))
       (defview my-tweets2 [user]
         [:tweetlog/tweeted user tweet]
@@ -65,71 +61,87 @@
 with the `:ts` and `:change` fields omitted.
 The values are the accumulated `:change` of all matching events."
 (fact defview-5
-      (reset! my-atom2 {})
-      (is (= (my-tweets2 host2 "alice") [])) ;; Make the inital call that returns an empty collection
-      ((:pub ps2)
-       {:kind :fact
-        :name "tweetlog/tweeted"
-        :key "alice"
-        :data ["hello"]
-        :ts 1000
-        :change 1
-        :readers #{}
-        :writers #{"alice"}})
-      ((:pub ps2)
-       {:kind :fact
-        :name "tweetlog/tweeted"
-        :key "alice"
-        :data ["world"]
-        :ts 2000
-        :change 1
-        :readers #{}
-        :writers #{"alice"}})
-      ((:pub ps2)
-       {:kind :fact
-        :name "tweetlog/tweeted"
-        :key "alice"
-        :data ["world"]
-        :ts 3000
-        :change 1
-        :readers #{}
-        :writers #{"alice"}})
-      (is (contains? @my-atom2 ["alice"]))
-      (is (= (get-in @my-atom2 [["alice"]
-                                {:kind :fact
-                                 :name "tweetlog/tweeted"
-                                 :key "alice"
-                                 :data ["hello"]
-                                 :readers #{}
-                                 :writers #{"alice"}}]) 1))
-      (is (= (get-in @my-atom2 [["alice"]
-                                {:kind :fact
-                                 :name "tweetlog/tweeted"
-                                 :key "alice"
-                                 :data ["world"]
-                                 :readers #{}
-                                 :writers #{"alice"}}]) 2)))
+      (let [host {:sub (:sub ps2)
+                  :pub #(swap! published2 conj %)
+                  :time (constantly 12345)
+                  :identity (atom "alice")}]
+        (reset! my-atom2 {})
+        (is (= (my-tweets2 host "alice") [])) ;; Make the inital call that returns an empty collection
+        ((:pub ps2)
+         {:kind :fact
+          :name "tweetlog/tweeted"
+          :key "alice"
+          :data ["hello"]
+          :ts 1000
+          :change 1
+          :readers #{}
+          :writers #{"alice"}})
+        ((:pub ps2)
+         {:kind :fact
+          :name "tweetlog/tweeted"
+          :key "alice"
+          :data ["world"]
+          :ts 2000
+          :change 1
+          :readers #{}
+          :writers #{"alice"}})
+        ((:pub ps2)
+         {:kind :fact
+          :name "tweetlog/tweeted"
+          :key "alice"
+          :data ["world"]
+          :ts 3000
+          :change 1
+          :readers #{}
+          :writers #{"alice"}})
+        (is (contains? @my-atom2 ["alice"]))
+        (is (= (get-in @my-atom2 [["alice"]
+                                  {:kind :fact
+                                   :name "tweetlog/tweeted"
+                                   :key "alice"
+                                   :data ["hello"]
+                                   :readers #{}
+                                   :writers #{"alice"}}]) 1))
+        (is (= (get-in @my-atom2 [["alice"]
+                                  {:kind :fact
+                                   :name "tweetlog/tweeted"
+                                   :key "alice"
+                                   :data ["world"]
+                                   :readers #{}
+                                   :writers #{"alice"}}]) 2))))

 "The view function returns, for a given combination of arguments, a collection of all data elements with a positive total count.
 In our case, both \"hello\" and \"world\" tweets are taken (in some order)."
 (fact defview-6
-      (is (= (count (my-tweets2 host2 "alice")) 2))
-      (is (= (-> (my-tweets2 host2 "alice")
-                 meta :pending) false)))
+      (let [host {:sub (:sub ps2)
+                  :pub #(swap! published2 conj %)
+                  :time (constantly 12345)
+                  :identity (atom "alice")}]
+        (is (= (count (my-tweets2 host "alice")) 2))
+        (is (= (-> (my-tweets2 host "alice")
+                   meta :pending) false))))

 "Each element in the returned collection is a *value map*, a map in which the keys correspond to the symbols in the fact pattern provided in the view definition.
 In our case these are `:user` and `:tweet`.
 The values are their corresponding values in each event."
 (fact defview-7a
-      (doseq [result (my-tweets2 host2 "alice")]
-        (is (= (:user result) "alice"))
-        (is (contains? #{"hello" "world"} (:tweet result)))))
+      (let [host {:sub (:sub ps2)
+                  :pub #(swap! published2 conj %)
+                  :time (constantly 12345)
+                  :identity (atom "alice")}]
+        (doseq [result (my-tweets2 host "alice")]
+          (is (= (:user result) "alice"))
+          (is (contains? #{"hello" "world"} (:tweet result))))))

 "Along with the data fields, each value map also contains the `:-readers` and `:-writers` of the corresponding events."
 (fact defview-7b
-      (doseq [result (my-tweets2 host2 "alice")]
-        (is (= (:-readers result) #{}))
-        (is (= (:-writers result) #{"alice"}))))
+      (let [host {:sub (:sub ps2)
+                  :pub #(swap! published2 conj %)
+                  :time (constantly 12345)
+                  :identity (atom "alice")}]
+        (doseq [result (my-tweets2 host "alice")]
+          (is (= (:-readers result) #{}))
+          (is (= (:-writers result) #{"alice"})))))

 "Elements with zero or negative count values are not shown."
 (fact defview-8
@@ -148,7 +160,11 @@
                                  :data ["world"]
                                  :readers #{}
                                  :writers #{"alice"}}] -1)
-      (is (= (count (my-tweets2 host2 "alice")) 0)))
+      (let [host {:sub (:sub ps2)
+                  :pub #(swap! published2 conj %)
+                  :time (constantly 12345)
+                  :identity (atom "alice")}]
+        (is (= (count (my-tweets2 host "alice")) 0))))

 [[:section {:title "Event-Emitting Functions"}]]
 "A view provides functions that allow users to emit event for creating, updating and deleting facts."
@@ -165,17 +181,21 @@
 Parameters already given to the view function (e.g., `:user \"alice\"` in the following example) should be omitted."
 (fact defview-ev-1a
       (reset! published2 [])
-      (let [{:keys [add]} (meta (my-tweets2 host2 "alice"))]
+      (let [host {:sub (:sub ps2)
+                  :pub #(swap! published2 conj %)
+                  :time (constantly 12345)
+                  :identity (atom "alice")}
+            {:keys [add]} (meta (my-tweets2 host "alice"))]
         (is (fn? add))
         (add {:tweet "Hola!"})
         (is (= @published2
                [{:kind :fact
-                  :name "tweetlog/tweeted"
-                  :key "alice"
-                  :data ["Hola!"]
-                  :ts 12345
-                  :change 1
-                  :writers #{"alice"}
+                 :name "tweetlog/tweeted"
+                 :key "alice"
+                 :data ["Hola!"]
+                 :ts 12345
+                 :change 1
+                 :writers #{"alice"}
                  :readers #{}}]))))

 "The `:readers` and `:writers` sets in newly-added facts are controlled by the optional `:readers` and `:writers` keyword arguments in the view definition.
@@ -226,9 +246,6 @@
       (defonce my-atom3 (atom nil))
       (defonce published3 (atom nil))
       (reset! published3 nil)
-      (defonce host3 {:pub #(swap! published3 conj %)
-                      :sub (fn [key f])
-                      :time (constantly 23456)})
       (defview my-tweets3 [user]
         [:tweetlog/tweeted user tweet]
         :store-in my-atom3)
@@ -239,18 +256,21 @@
                                  :data ["hello"]
                                  :readers #{}
                                  :writers #{"alice"}}] 3)
-      (let [valmap (first (my-tweets3 host3 "alice"))]
+      (let [host {:pub #(swap! published3 conj %)
+                  :sub (fn [key f])
+                  :time (constantly 23456)}
+            valmap (first (my-tweets3 host "alice"))]
         (is (fn? (:del! valmap)))
         ((:del! valmap))
         (is (= @published3
                [{:kind :fact
-                  :name "tweetlog/tweeted"
-                  :key "alice"
-                  :data ["hello"]
-                  :ts 23456
-                  :change -3
-                  :readers #{}
-                  :writers #{"alice"}}]))))
+                 :name "tweetlog/tweeted"
+                 :key "alice"
+                 :data ["hello"]
+                 :ts 23456
+                 :change -3
+                 :readers #{}
+                 :writers #{"alice"}}]))))

 "A `:swap!` function provides a way to update a value map.
 It takes a function (and optionally arguments) that is applied to the value map, and emits an [atomic update](cloudlog-events.html#atomic-updates)
@@ -259,9 +279,6 @@
       (defonce my-atom4 (atom nil))
       (defonce published4 (atom nil))
       (reset! published4 nil)
-      (defonce host4 {:pub #(swap! published4 conj %)
-                      :sub (fn [key f])
-                      :time (constantly 34567)})
       (defview my-tweets4 [user]
         [:tweetlog/tweeted user tweet ts]
         :store-in my-atom4)
@@ -272,19 +289,22 @@
                                  :data ["hello" 12345]
                                  :readers #{}
                                  :writers #{"alice"}}] 3)
-      (let [valmap (first (my-tweets4 host4 "alice"))]
+      (let [host {:pub #(swap! published4 conj %)
+                  :sub (fn [key f])
+                  :time (constantly 34567)}
+            valmap (first (my-tweets4 host "alice"))]
         (is (fn? (:swap! valmap)))
         ((:swap! valmap) assoc :tweet "world")
         (is (= @published4
                [{:kind :fact
-                  :name "tweetlog/tweeted"
-                  :key "alice"
-                  :removed ["hello" 12345]
-                  :data ["world" 12345]
-                  :ts 34567
-                  :change 3
-                  :readers #{}
-                  :writers #{"alice"}}]))))
+                 :name "tweetlog/tweeted"
+                 :key "alice"
+                 :removed ["hello" 12345]
+                 :data ["world" 12345]
+                 :ts 34567
+                 :change 3
+                 :readers #{}
+                 :writers #{"alice"}}]))))

 [[:section {:title "Filtering"}]]
 "Views can define client-side filtering for facts."
@@ -293,41 +313,40 @@
 We define such filtering using an optional `:when` key in `defview`."
 (fact defview-filt
       (defonce my-atom5 (atom nil))
-      (defonce ps5 (ax/pubsub :name))
-      (defonce host5 {:sub (:sub ps5)
-                      :pub (constantly nil)})
       (defview hashtags-only [user]
         [:tweetlog/tweeted user tweet]
         :store-in my-atom5
         :when (re-matches #".*#[a-zA-Z0-9]+.*" tweet))
       (reset! my-atom5 {})
-      (is (= (hashtags-only host5 "alice") [])) ;; Initial call to view function
-      ((:pub ps5)
-       {:kind :fact
-        :name "tweetlog/tweeted"
-        :key "alice"
-        :data ["No hashtags here..."]
-        :ts 1000
-        :change 1
-        :readers #{}
-        :writers #{"alice"}})
-      ((:pub ps5)
-       {:kind :fact
-        :name "tweetlog/tweeted"
-        :key "alice"
-        :data ["This one hash #hashtags..."]
-        :ts 2000
-        :change 1
-        :readers #{}
-        :writers #{"alice"}})
-      (is (= (count (@my-atom5 ["alice"])) 1)))
+      (let [ps5 (ax/pubsub :name)
+            host {:sub (:sub ps5)
+                  :pub (constantly nil)}]
+        (is (= (hashtags-only host "alice") [])) ;; Initial call to view function
+        ((:pub ps5)
+         {:kind :fact
+          :name "tweetlog/tweeted"
+          :key "alice"
+          :data ["No hashtags here..."]
+          :ts 1000
+          :change 1
+          :readers #{}
+          :writers #{"alice"}})
+        ((:pub ps5)
+         {:kind :fact
+          :name "tweetlog/tweeted"
+          :key "alice"
+          :data ["This one hash #hashtags..."]
+          :ts 2000
+          :change 1
+          :readers #{}
+          :writers #{"alice"}})
+        (is (= (count (@my-atom5 ["alice"])) 1))))

 [[:section {:title "Sorting"}]]
 "The optional keyword argument `:order-by` directs the view function to sort the elements it returns according to the given expression.
 The expression can rely on symbols from the fact pattern, and must result in a [comparable expression](https://clojure.org/guides/comparators)."
 (fact defview-sort
       (defonce my-atom6 (atom nil))
-      (defonce host6 {:sub (fn [key f])})
       (defview my-sorted-tweets [user]
         [:tweetlog/tweeted user tweet timestamp]
         :store-in my-atom6
@@ -358,7 +377,8 @@
                :data ["my third tweet" 3000]
                :readers #{}
                :writers #{"alice"}}] 1)
-      (let [tweets-in-order (for [result (my-sorted-tweets host6 "alice")]
+      (let [host {:sub (fn [key f])}
+            tweets-in-order (for [result (my-sorted-tweets host "alice")]
                               (:tweet result))]
         (is (= tweets-in-order ["my third tweet"
                                 "my second tweet"
@@ -406,7 +426,7 @@
         (is (= (-> result meta :pending) true)))
       (is (= @published7
              [{:kind :reg
-                :name "tweetlog/timeline!"
+               :name "tweetlog/timeline!"
                :key "SOMEUUID1"}
               {:kind :fact
                :name "tweetlog/timeline?"
@@ -472,58 +492,58 @@
 [[:section {:title "Filtering and Sorting"}]]
 "Filtering and sorting work exactly as with `defview`."
 (fact defquery-filt
-      (defonce ps8 (ax/pubsub :name))
-      (defonce host8 {:pub (fn [ev])
-                      :sub (:sub ps8)
-                      :identity (atom "alice")
-                      :uuid (constantly "SOMEUUID")
-                      :time (constantly 12345)})
       (defonce my-atom8 (atom nil))
       (defquery tweets-by-authors-that-begin-in-b [user]
         [:tweetlog/timeline user -> author tweet]
         :store-in my-atom8
         :when (str/starts-with? author "b")
         :order-by tweet)
-      (tweets-by-authors-that-begin-in-b host8 "alice") ;; Start listenning...
-      ((:pub ps8)
-                {:kind :fact
-                 :name "tweetlog/timeline!"
-                 :key "SOMEUUID"
-                 :data ["bob" "D"]
-                 :ts 1000
-                 :change 1
-                 :writers #{"XXYY"}
-                 :readers #{}})
-      ((:pub ps8)
-                {:kind :fact
-                 :name "tweetlog/timeline!"
-                 :key "SOMEUUID"
-                 :data ["charlie" "C"] ;; Dropped
-                 :ts 2000
-                 :change 1
-                 :writers #{"XXYY"}
-                 :readers #{}})
-      ((:pub ps8)
-                {:kind :fact
-                 :name "tweetlog/timeline!"
-                 :key "SOMEUUID"
-                 :data ["boaz" "B"]
-                 :ts 3000
-                 :change 1
-                 :writers #{"XXYY"}
-                 :readers #{}})
-      ((:pub ps8)
-                {:kind :fact
-                 :name "tweetlog/timeline!"
-                 :key "SOMEUUID"
-                 :data ["bob" "A"]
-                 :ts 4000
-                 :change 1
-                 :writers #{"XXYY"}
-                 :readers #{}})
-      (let [results (tweets-by-authors-that-begin-in-b host8 "alice")]
-        (is (= (count results) 3))
-        (is (= (->> results
-                    (map :tweet))
-               ["A" "B" "D"]))))
-
+      (let [ps8 (ax/pubsub :name)
+            host8 {:pub (fn [ev])
+                   :sub (:sub ps8)
+                   :identity (atom "alice")
+                   :uuid (constantly "SOMEUUID")
+                   :time (constantly 12345)}]
+        (tweets-by-authors-that-begin-in-b host8 "alice") ;; Start listenning...
+        ((:pub ps8)
+         {:kind :fact
+          :name "tweetlog/timeline!"
+          :key "SOMEUUID"
+          :data ["bob" "D"]
+          :ts 1000
+          :change 1
+          :writers #{"XXYY"}
+          :readers #{}})
+        ((:pub ps8)
+         {:kind :fact
+          :name "tweetlog/timeline!"
+          :key "SOMEUUID"
+          :data ["charlie" "C"] ;; Dropped
+          :ts 2000
+          :change 1
+          :writers #{"XXYY"}
+          :readers #{}})
+        ((:pub ps8)
+         {:kind :fact
+          :name "tweetlog/timeline!"
+          :key "SOMEUUID"
+          :data ["boaz" "B"]
+          :ts 3000
+          :change 1
+          :writers #{"XXYY"}
+          :readers #{}})
+        ((:pub ps8)
+         {:kind :fact
+          :name "tweetlog/timeline!"
+          :key "SOMEUUID"
+          :data ["bob" "A"]
+          :ts 4000
+          :change 1
+          :writers #{"XXYY"}
+          :readers #{}})
+        (let [results (tweets-by-authors-that-begin-in-b host8 "alice")]
+          (is (= (count results) 3))
+          (is (= (->> results
+                      (map :tweet))
+                 ["A" "B" "D"])))))
+


create image dir when not exists

create image dir when not exists

--- iwaswhere-web/src/clj/iwaswhere_web/upload.clj
+++ iwaswhere-web/src/clj/iwaswhere_web/upload.clj
@@ -27,9 +27,11 @@
             "OK"))
         binary-post-fn
         (fn [dir filename req]
-          (let [filename (str f/data-path "/" dir "/" filename)]
+          (let [filename (str f/data-path "/" dir "/" filename)
+                file (java.io.File. filename)]
+            (io/make-parents file)
             (log/info :server/upload-cmp req)
-            (io/copy (:body req) (java.io.File. filename)))
+            (io/copy (:body req) file))
           "OK")
         app
         (routes


setting path in cookies

setting path in cookies

--- src/ontrail/core.clj
+++ src/ontrail/core.clj
@@ -179,8 +179,8 @@
               {:status 301
                :headers {"Content-Type" "text/html"
                          "Location" redirect-location}
-               :cookies {"authToken" {:value authToken :max-age (* 60 60 24 2 365) }
-                         "authUser" {:value authUser :max-age  (* 60 60 24 2 365) }}
+               :cookies {"authToken" {:value authToken :max-age (* 60 60 24 2 365) :path "/" }
+                         "authUser" {:value authUser :max-age  (* 60 60 24 2 365) :path "/" }}
                :body ""
                })
             {:status 301


Fix reflection warning

Fix reflection warning

--- ring-core/src/ring/middleware/session/cookie.clj
+++ ring-core/src/ring/middleware/session/cookie.clj
@@ -72,7 +72,7 @@
       secret-key)
     (secure-random-bytes 16)))

-(defn- serialize [x]
+(defn- ^String serialize [x]
   {:post [(= x (edn/read-string %))]}
   (pr-str x))


Send empty string back on 404

Send empty string back on 404

--- src/qcast/server.clj
+++ src/qcast/server.clj
@@ -114,7 +114,7 @@
     (let [res (response/resource-response "index.html" {:root "public"})]
       (response/content-type res "text/html")))
   (route/resources "/")
-  (route/not-found "Not found"))
+  (route/not-found nil))

 (defn- site []
   (routes