use proper conventions for threading

use proper conventions for threading

--- src/clj_money/serialization.clj
+++ src/clj_money/serialization.clj
@@ -33,7 +33,7 @@
        users))

 (defn- realize-users
-  [storage context]
+  [context storage]
   (update-in context [:users] #(create-users storage %)))

 (defn- find-user
@@ -45,7 +45,7 @@
        first))

 (defn- resolve-user
-  [context model]
+  [model context]
   (update-in model [:user-id] #(:id (find-user context %))))

 (defn- create-entities
@@ -53,39 +53,40 @@
   (mapv (fn [attributes]
           (if (:id attributes)
             attributes
-            (entities/create storage (resolve-user context attributes))))
+            (entities/create storage (resolve-user attributes context))))
         entities))

 (defn- realize-entities
-  [storage context]
+  [context storage]
   (update-in context [:entities] #(create-entities storage context %)))

 (defn- find-entity
   [context entity-name]
-  (->> context
-       :entities
-       (filter #(or (nil? entity-name)
-                    (= (:name %) entity-name)))
+  (->> (:entities context)
+       (filter #(= (:name %) entity-name))
        first))

 (defn- resolve-entity
-  [context model]
-  (update-in model [:entity-id] #(:id (find-entity context %))))
+  [model context]
+  (update-in model [:entity-id] (fn [entity-name]
+                                  (if entity-name
+                                    (:id (find-entity context entity-name))
+                                    (-> context :entities first :id)))))

 (defn create-grants
   [storage context grants]
   (mapv (fn [attributes]
-          (grants/create storage (->> attributes
-                                      (resolve-user context)
-                                      (resolve-entity context))))
+          (grants/create storage (-> attributes
+                                     (resolve-user context)
+                                     (resolve-entity context))))
         grants))

 (defn- realize-grants
-  [storage context]
+  [context storage]
   (update-in context [:grants] #(create-grants storage context %)))

 (defn- resolve-parent
-  [storage account]
+  [account storage]
   (if (:parent-id account)
     (let [parent (accounts/find-by-name storage (:entity-id account) (:parent-id account))]
       (assoc account :parent-id (:id parent)))
@@ -99,17 +100,22 @@
        first))

 (defn- resolve-commodity
-  [context model]
-  (update-in model [:commodity-id] #(:id (find-commodity context %))))
+  [model context]
+  (update-in model [:commodity-id] (fn [ticker-symbol]
+                                     (if ticker-symbol
+                                       (:id (find-commodity context ticker-symbol))
+                                       (->> (:commodities context)
+                                            (filter #(= :currecy (:type %)))
+                                            first)))))

 (defn- create-account
   [storage context attributes]
   (if (:id attributes)
     attributes
-    (accounts/create storage (->> attributes
-                                       (resolve-entity context)
-                                       (resolve-commodity context)
-                                       (resolve-parent storage)))))
+    (accounts/create storage (-> attributes
+                                 (resolve-entity context)
+                                 (resolve-commodity context)
+                                 (resolve-parent storage)))))

 (defn- create-accounts
   "Creates the specified accounts.
@@ -127,7 +133,7 @@
     (mapv #(create-account storage context %) account-list)))

 (defn- realize-accounts
-  [storage context]
+  [context storage]
   (update-in context [:accounts] #(create-accounts storage context %)))

 (defn- find-account
@@ -138,7 +144,7 @@
        first))

 (defn- resolve-account
-  [context model]
+  [model context]
   (update-in model [:account-id] #(:id (find-account context %))))

 (defn- coerce-amount
@@ -147,12 +153,12 @@

 (defn- prepare-item
   [context item]
-  (->> item
-       (resolve-account context)
-       coerce-amount))
+  (-> item
+      (resolve-account context)
+      coerce-amount))

 (defn- prepare-items
-  [context transaction]
+  [transaction context]
   (update-in transaction [:items] (fn [items]
                                     (map #(prepare-item context %)
                                          items))))
@@ -161,17 +167,17 @@
   [storage context transactions]
   []
   (mapv (fn [attributes]
-         (transactions/create storage (->> attributes
-                                            (resolve-entity context)
-                                            (prepare-items context))))
-       transactions))
+          (transactions/create storage (-> attributes
+                                           (resolve-entity context)
+                                           (prepare-items context))))
+        transactions))

 (defn- realize-transactions
-  [storage context]
+  [context storage]
   (update-in context [:transactions] #(create-transactions storage context %)))

 (defn- resolve-transaction
-  [context model]
+  [model context]
   (let [trans-ref (:transaction-id model)]
     (assoc model :transaction-id (->> context
                                       :transactions
@@ -180,93 +186,120 @@
                                                     (:transaction-date trans-ref))
                                                  (= (:description %)
                                                     (:description trans-ref))))
-                                      first
-                                      :id))))
+                                      (map (juxt :id :transaction-date))
+                                      first))))

 (defn- resolve-image
-  [context model]
+  [model context]
   (assoc model :image-id (->> context
                               :images
                               (filter #(= (:original-filenamme %)
                                           (:image-id model)))
                               first)))

+(defn- create-attachment
+  [model storage]
+  (attachments/create storage model))
+
+(defn- rearrange-transaction-attributes
+  [attachment]
+  (assoc attachment :transaction-id (-> attachment :transaction-id first)
+                    :transaction-date (-> attachment :transaction-id second)))
+
 (defn- create-attachments
   [storage context attachments]
-  (mapv #(->> %
-              (resolve-transaction context)
-              (resolve-image context)
-              (attachments/create storage))
+  (mapv #(-> %
+             (resolve-transaction context)
+             rearrange-transaction-attributes
+             (resolve-image context)
+             (create-attachment storage)
+             throw-on-invalid)
         attachments))

 (defn- realize-attachments
-  [storage context]
+  [context storage]
   (update-in context [:attachments] #(create-attachments storage context %)))

 (defn- append-budget-items
-  [storage context items budget]
+  [budget storage context items]
   (assoc budget :items (->> items
-                            (map #(resolve-account context %))
+                            (map #(resolve-account % context))
                             (map #(assoc % :budget-id (:id budget)))
                             (mapv #(budgets/create-item storage %)))))

+(defn- create-budget
+  [model storage]
+  (budgets/create storage model))
+
 (defn- create-budgets
   [storage context budgets]
   (mapv (fn [attributes]
-          (->> attributes
-               (resolve-entity context)
-               (budgets/create storage)
-               (append-budget-items storage context (:items attributes))))
+          (-> attributes
+              (resolve-entity context)
+              (create-budget storage)
+              (append-budget-items storage context (:items attributes))))
         budgets))

 (defn- realize-budgets
-  [storage context]
+  [context storage]
   (update-in context [:budgets] #(create-budgets storage context %)))
+
+(defn- create-commodity
+  [model storage]
+  (commodities/create storage model))

 (defn- create-commodities
   [storage context commodities]
   (mapv (fn [attributes]
-          (->> attributes
-               (resolve-entity context)
-               (commodities/create storage)))
+          (-> attributes
+              (resolve-entity context)
+              (create-commodity storage)))
         commodities))

 (defn- realize-commodities
-  [storage context]
+  [context storage]
   (update-in context [:commodities] #(create-commodities storage context %)))
+
+(defn- create-price
+  [model storage]
+  (prices/create storage model))

 (defn- create-prices
   [storage context prices]
   (mapv (fn [attributes]
-          (->> attributes
-               (resolve-commodity context)
-               (prices/create storage)))
+          (-> attributes
+              (resolve-commodity context)
+              (create-price storage)))
         prices))

 (defn- realize-prices
-  [storage context]
+  [context storage]
   (update-in context [:prices] #(create-prices storage context %)))
+
+(defn- create-lot
+  [model storage]
+  (lots/create storage model))

 (defn- create-lots
   [storage context lots]
   (mapv (fn [attributes]
-          (->> attributes
-               (resolve-commodity context)
-               (resolve-account context)
-               (lots/create storage)))
+          (-> attributes
+              (resolve-commodity context)
+              (resolve-account context)
+              (create-lot storage)))
         lots))

 (defn- realize-lots
-  [storage context]
+  [context storage]
   (update-in context [:lots] #(create-lots storage context %)))

 (defn- find-lot
   [context attr]
   (let [{:keys [account-id
                 commodity-id
-                purchase-date]} (->> attr
-                                     (resolve-account context)
-                                     (resolve-commodity context))]
+                purchase-date]} (-> attr
+                                    (resolve-account context)
+                                    (resolve-commodity context))]
     (->> context
          :lots
          (filter #(and (= account-id (:account-id %))
@@ -275,7 +308,7 @@
          first)))

 (defn- resolve-lot
-  [context model]
+  [model context]
   (update-in model [:lot-id] #(:id (find-lot context %))))

 (defn- resolve-transaction-item-ids
@@ -295,43 +328,50 @@
         items))

 (defn- resolve-reconciliation-transaction-item-ids
-  [context reconciliation]
+  [reconciliation context]
   (update-in reconciliation
              [:item-ids]
              #(resolve-transaction-item-ids context
                                             (:account-id reconciliation)
                                             %)))

+(defn- create-reconciliation
+  [model storage]
+  (reconciliations/create storage model))
+
 (defn- create-reconciliations
   [storage context reconciliations]
   (mapv (fn [attributes]
-          (->> attributes
-               (resolve-account context)
-               (resolve-reconciliation-transaction-item-ids context)
-               (reconciliations/create storage)
-               throw-on-invalid))
+          (-> attributes
+              (resolve-account context)
+              (resolve-reconciliation-transaction-item-ids context)
+              (create-reconciliation storage)
+              throw-on-invalid))
         reconciliations))

 (defn- realize-reconciliations
-  [storage context]
+  [context storage]
   (update-in context [:reconciliations] #(create-reconciliations storage context %)))

 (defn- read-file
   [image]
   (update-in image [:body] #(read-bytes %)))

+(defn- create-image-from-file
+  [model storage]
+  (images/create storage (read-file model)))
+
 (defn- create-images
   [storage context images]
   (mapv (fn [attributes]
-          (->> attributes
-               (resolve-user context)
-               read-file
-               (images/create storage)
-               throw-on-invalid))
+          (-> attributes
+              (resolve-user context)
+              (create-image-from-file storage)
+              throw-on-invalid))
         images))

 (defn- realize-images
-  [storage context]
+  [context storage]
   (update-in context [:images] #(create-images storage context %)))

 (defn- find-image
@@ -341,21 +381,25 @@
        first))

 (defn- resolve-image
-  [context model]
+  [model context]
   (update-in model [:image-id] #(:id (find-image context %))))
+
+(defn- create-import
+  [model storage]
+  (imports/create storage model))

 (defn- create-imports
   [storage context imports]
   (mapv (fn [attributes]
-          (->> attributes
-               (resolve-user context)
-               (resolve-image context)
-               (imports/create storage)
-               throw-on-invalid))
+          (-> attributes
+              (resolve-user context)
+              (resolve-image context)
+              (create-import storage)
+              throw-on-invalid))
         imports))

 (defn- realize-imports
-  [storage context]
+  [context storage]
   (update-in context [:imports] #(create-imports storage context %)))

 (defn- get-commodity
@@ -374,7 +418,7 @@
     entity))

 (defn- resolve-default-commodity-ids
-  [storage context]
+  [context storage]
   (update-in context
              [:entities]
              #(map (partial resolve-default-commodity-id storage context) %)))
@@ -383,18 +427,18 @@
   "Realizes a test context"
   [storage-spec input]
   (with-storage [s storage-spec]
-  (->> input
-      (realize-users s)
-      (realize-images s)
-      (realize-imports s)
-      (realize-entities s)
-      (realize-grants s)
-      (realize-commodities s)
-      (resolve-default-commodity-ids s)
-      (realize-accounts s)
-      (realize-prices s)
-      (realize-lots s)
-      (realize-budgets s)
-      (realize-transactions s)
-      (realize-attachments s)
-      (realize-reconciliations s))))
+    (-> input
+        (realize-users s)
+        (realize-images s)
+        (realize-imports s)
+        (realize-entities s)
+        (realize-grants s)
+        (realize-commodities s)
+        (resolve-default-commodity-ids s)
+        (realize-accounts s)
+        (realize-prices s)
+        (realize-lots s)
+        (realize-budgets s)
+        (realize-transactions s)
+        (realize-attachments s)
+        (realize-reconciliations s))))


fixup! Move the second level div into each top-level component

--- src/cljs/comic_reader/main.cljs
+++ src/cljs/comic_reader/main.cljs
@@ -106,7 +106,7 @@
         :sites [site-list]
         :comics [comic-list]
         :read [reader]
-        nil ""
+        nil [:span ""]
         [four-oh-four]))))

 (defn ^:export run []


‘Preview’ binds comments to a preview field

--- src/cljs/hacker_agent/core.cljs
+++ src/cljs/hacker_agent/core.cljs
@@ -74,7 +74,7 @@
        (when kids
          [comment-list (r/wrap kids swap! data assoc :kids)])])))

-(defn story-list-item [story]
+(defn story-list-item-fn [story]
   (let [{:keys [by id title score url kids -updated?]} @story]
     (when (every? identity [by title score])
       [:div {:class (if -updated?
@@ -89,11 +89,20 @@
         [:a {:href (str "/#/items/" id)}
          (str (count kids) " threads")]
         " | "
-        [:span {:on-click #(base/bind! story [:preview]
-                                       (base/id->fbref id)
-                                       base/item-binder)
+        [:span {:on-click #(binding [base/closer-root [:story-list-item id]]
+                             (base/bind! story [:preview]
+                                         (base/id->fbref id)
+                                         base/item-binder))
                 :style {:cursor :pointer}}
          [:i "Preview"]]]])))
+
+(def story-list-item
+  (with-meta story-list-item-fn
+    {:component-will-unmount #(let [story (get (.. % -props -argv) 1)
+                                    id (@story :id)]
+                                (binding [base/closer-root [:story-list-item id]]
+                                  (base/close-channel! story [])
+                                  (swap! story dissoc :preview)))}))

 (defn top-stories [stories]
   [:ol.stories


Add init-data-sync! function

Add init-data-sync! function

This function allows creating a single atom representing a hacker base
item hierarchy (i.e. comments) that will be updated asynchronously.

--- src/cljs/hacker_agent/core.cljs
+++ src/cljs/hacker_agent/core.cljs
@@ -10,8 +10,10 @@
   (:import goog.History))

 (defonce hacker-root "https://hacker-news.firebaseio.com/v0")
+(defonce test-atom (atom {}))
 ;; -------------------------
 ;; Utils
+
 (defn snapshot->clj [snapshot]
   (js->clj (.val snapshot) :keywordize-keys true))

@@ -93,7 +95,31 @@
              (global-put! :max-item db))))
     fb))

-;; -------------------------
+(defn init-data-sync!
+  "Given vector PATH and atom DATA, create callbacks on firebase
+  channel FBC to update PATH in DATA"
+  [path data fbc]
+  (letfn [(handle-kid [k v child-path]
+            (let [items (doall (map #(hash-map % {}) v))]
+              (swap! data assoc-in child-path (into {} items))
+              (doseq [id v]
+                (init-data-sync! (conj child-path id) data (id->fb-chan id)))))]
+    (go-loop [msg (<! fbc)]
+      (let [[event key val] msg
+            child-path (conj path key)]
+        (case event
+          :child_added (if (= key :kids)
+                         (handle-kid key val child-path)
+                         (swap! data assoc-in child-path val))
+          :child_changed (if (= key :kids)
+                           (handle-kid key val child-path)
+                           (swap! data assoc-in child-path val))
+          ;; TODO: implement dissoc-in?
+          :child_removed (swap! data assoc-in child-path nil)
+          ))
+      (recur (<! fbc)))))
+
+;; ------------------------
 ;; Components

 (defmulti item #(:type (deref %)))


remove unused fns

remove unused fns

--- src/clojure/duratom/readers.clj
+++ src/clojure/duratom/readers.clj
@@ -37,16 +37,12 @@

 (defmethod print-method ObjectWithMeta
   [o ^Writer w]
-  (.write w "#iobj ")
   (let [coll (:o o)]
+    (.write w "#iobj ")
     (print-method [coll (meta coll)] w)))

-(defn- tuple->iobj
-  [[o meta-map]]
-  (with-meta o meta-map))
-
 (def meta-reader
-  {'iobj tuple->iobj})
+  {'iobj (partial apply with-meta)})

 (defmethod print-method PersistentQueue
   [o ^Writer w]


Removed -target-remove and -target-clear protocol methods and replaced them with composite fn's that do the same thing.

--- src/clojure/freactive/core.cljc
+++ src/clojure/freactive/core.cljc
@@ -885,9 +885,7 @@
   (-target-peek [this elem-idx])
   (-target-take [this elem-idx])
   (-target-count [this])
-  (-target-move [this elem-idx before-idx])
-  (-target-remove [this elem-idx])
-  (-target-clear [this]))
+  (-target-move [this elem-idx before-idx]))

 (defn target-init [this source] (-target-init this source))

@@ -901,9 +899,13 @@

 (defn target-move [this idx before-idx] (-target-move this idx before-idx))

-(defn target-remove [this idx] (-target-remove this idx))
-
-(defn target-clear [this] (-target-clear this))
+(defn target-remove [this idx]
+  (let [res (-target-take this idx)]
+    (dispose res)))
+
+(defn target-clear [this]
+  (dotimes [i (target-count this)]
+    (target-remove 0)))

 (defprotocol IProjection
   (-project [this target enqueue-fn]))
@@ -1100,11 +1102,7 @@
        (-target-count [this]
          (target-count target))
        (-target-move [this elem-idx before-idx]
-         (target-move target elem-idx before-idx))
-       (-target-remove [this elem-idx]
-         (target-remove target elem-idx))
-       (-target-clear [this]
-         (target-clear target)))
+         (target-move target elem-idx before-idx)))

      (defn pwrap [proj wrap-fn]
        (reify IProjection
@@ -1131,9 +1129,7 @@
            (target-take target j)))
        (-target-count [this]
          (target-count target))
-       (-target-move [this elem-idx before-idx])
-       (-target-remove [this elem-idx])
-       (-target-clear [this]))
+       (-target-move [this elem-idx before-idx]))

      (defn poffset [proj offset]
        (reify IProjection
@@ -1160,9 +1156,7 @@
            (target-take target j)))
        (-target-count [this]
          (target-count target))
-       (-target-move [this elem-idx before-idx])
-       (-target-remove [this elem-idx])
-       (-target-clear [this]))
+       (-target-move [this elem-idx before-idx]))

      (defn plimit [proj limit]
        (reify IProjection


Type hint for inspection objects.

Type hint for inspection objects.

--- src/clojure/parkour/inspect.clj
+++ src/clojure/parkour/inspect.clj
@@ -1,5 +1,6 @@
 (ns parkour.inspect
-  (:require [parkour (conf :as conf) (wrapper :as w)]
+  (:require [clojure.core.protocols :as ccp]
+            [parkour (conf :as conf) (wrapper :as w)]
             [parkour.inspect (mapred :as mr1) (mapreduce :as mr2)]))

 (defn records-seqable
@@ -9,9 +10,10 @@
 tuple as it is read, or `w/unwrap`-ing the key & value if not
 provided.  An explicit InputFormat `klass` and `paths` may be
 provided, which will be inferred from the `conf` if not."
+  {:tag 'java.io.Closeable}
   ([conf] (records-seqable conf w/unwrap-all))
   ([conf f]
-     (let [conf (conf/iguration conf)]
+     (let [conf (conf/ig conf)]
        (->> (or (.getClass conf "mapreduce.inputformat.class" nil)
                 (.getClass conf "mapred.input.format.class" nil))
             (records-seqable conf f))))


Optimize attribute prefix check

Optimize attribute prefix check

When converting kebab-case to camelCase for element attributes, we leave data-*
and aria-* attributes untouched.

Instead of constructing PersistentHashSet each time we check this, use a `case`
to test prefix imperatively.

--- src/om_tools/dom.cljx
+++ src/om_tools/dom.cljx
@@ -26,15 +26,15 @@
   [s]
   (str/replace s #"-(\w)" (comp str/upper-case second)))

-(defn opt-key-case
+(defn- opt-key-case
   "Converts attributes that are kebab-case and should be camelCase"
   [attr]
   (if (or (< (count attr) 5)
-          (#{"data-" "aria-"} (subs attr 0 5)))
+          (case (subs attr 0 5) ("data-" "aria-") true false))
     attr
     (camel-case attr)))

-(defn opt-key-alias
+(defn- opt-key-alias
   "Converts aliased attributes"
   [opt]
   (case opt


Added fork-join support.

Added fork-join support.

--- src/papaline/core.clj
+++ src/papaline/core.clj
@@ -40,7 +40,28 @@
                                          (when (:abort (ex-data e))
                                            (merge ctx (ex-data e)))))]
                              (if (and (not (:abort ctx)) out-chan)
-                               (>! out-chan ctx)
+
+                               (cond
+                                ;; the results are forked
+                                (:fork (meta (:args ctx)))
+                                (let [ctx (update-in ctx [:forks]
+                                                     #(conj (or % []) (count (:args ctx))))
+                                      ctx (update-in ctx [:fork-rets]
+                                                     #(conj (or % []) (atom [])))]
+                                  (doseq [forked-args (:args ctx)]
+                                    (>! out-chan (assoc ctx :args forked-args))))
+
+                                ;; this tasks requires join
+                                (:join (meta (:args ctx)))
+                                (do
+                                  (let [fork-rets (swap! (last (:fork-rets ctx)) conj (:args ctx))]
+                                    (when (= (last (:forks ctx)) (count fork-rets))
+                                      (>! out-chan (assoc ctx
+                                                     :forks (vec (drop-last (:forks ctx)))
+                                                     :fork-rets (vec (drop-last (:fork-rets ctx))))))))
+
+                                ;; normal linear
+                                :else (>! out-chan ctx))
                                (when (:wait ctx)
                                  (>! (:wait ctx) ctx)))))
                          (recur))
@@ -87,3 +108,14 @@
 (defn abort
   ([] (throw (ex-info "Aborted" {:abort true})))
   ([ret] (throw (ex-info "Aborted" {:abort true :ret ret}))))
+
+(defn- assoc-meta [v & args]
+  (with-meta v (apply (or (meta v) {}) args)))
+
+(defn fork [ret]
+  (when-not (sequential? ret)
+    (throw (IllegalArgumentException. "Only sequential value is forkable.")))
+  (assoc-meta ret :fork true))
+
+(defn join [ret]
+  (assoc-meta ret :join true))


Set title on index.html

Set title on index.html

--- src/pepa/web/html.clj
+++ src/pepa/web/html.clj
@@ -77,6 +77,7 @@
   (html5
    [:html
     [:head
+     [:title "Pepa"]
      [:style#style {:type "text/css"}]]
     [:body
      [:div#app]


Retracts now use clojure.pprint

Retracts now use clojure.pprint

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

--- src/conexp/contrib/retracts.clj
+++ src/conexp/contrib/retracts.clj
@@ -15,7 +15,7 @@
 			    restrict-concept,
 			    make-context,
 			    set-of)])
-  (:use [clojure.contrib.pprint :only (cl-format)]))
+  (:use [clojure.pprint :only (cl-format)]))

 (ns-doc "Package for computing retracts from formal contexts.")


working on converting lexicon to EDN

working on converting lexicon to EDN

--- src/babel/italiano/lexicon.cljc
+++ src/babel/italiano/lexicon.cljc
@@ -1,31 +1,48 @@
 ;; TODO: nouns do not need {:essere false}
 (ns babel.italiano.lexicon
-  (:refer-clojure :exclude [get-in merge])
+  (:refer-clojure :exclude [get-in])
   (:require
    [babel.encyclopedia :refer [sem-impl]]
    [babel.lexicon :refer [universals]]
+
+   ;; TODO: use dag_unify/unifyc instead:
+   ;; deprecate lexiconfn/unify.
    [babel.lexiconfn :refer [compile-lex if-then constrain-vals-if
                             filter-vals
                             map-function-on-map-vals
-                            rewrite-keys unify]] ;; TODO: use dag_unify/unifyc instead:
-   ;; deprecate lexiconfn/unify.
+                            rewrite-keys unify]]

    #?(:clj [clojure.tools.logging :as log])
    #?(:cljs [babel.logjs :as log])
    [babel.italiano.morphology :refer [exception-generator italian-specific-rules phonize]]
-   [babel.italiano.pos :refer [adjective agreement-noun cat-of-pronoun
-                               common-noun comparative countable-noun determiner
-                               drinkable-noun feminine-noun intransitive intransitivize
-                               intransitive-unspecified-obj
-                               masculine-noun non-comparative-adjective
-                               noun pronoun-acc pronoun-reflexive sentential-adverb
-                               transitive transitivize verb-aux verb-subjective]]
-   [dag_unify.core :refer [fail? get-in merge strip-refs]]))
+   [babel.italiano.pos :as ipos]
+   [dag_unify.core :refer [fail? get-in strip-refs]]))

 (def analyze-lexemes false)

 (def lexicon-source
-  {"Luisa"
+  (let [adjective ipos/adjective
+        agreement-noun ipos/agreement-noun
+        cat-of-pronoun ipos/cat-of-pronoun
+        common-noun ipos/common-noun
+        comparative ipos/comparative
+        countable-noun ipos/countable-noun
+        determiner ipos/determiner
+        intransitive ipos/intransitive
+        intransitive-unspecified-obj ipos/intransitive-unspecified-obj
+        masculine-noun ipos/masculine-noun
+        non-comparative-adjective ipos/non-comparative-adjective
+        preposition (let [shared (atom :top)]
+                      {:synsem {:sem {:obj shared}
+                                :subcat {:1 {:sem shared}}}})
+        pronoun-acc ipos/pronoun-acc
+        pronoun-reflexive ipos/pronoun-reflexive
+        sentential-adverb ipos/sentential-adverb
+        transitive ipos/transitive
+        verb-aux ipos/verb-aux
+        verb-subjective ipos/verb-subjective]
+
+    {"Luisa"
    {:synsem {:sem {:pred :luisa
                    :human true}
              :agr {:number :sing
@@ -42,34 +59,31 @@
    "a"
    ;; "a" as in "a casa"
    [
-    (let [location (atom {:place true})]
-      {:synsem {:cat :prep
-                :sem {:pred :a
-                      :obj location
-                      :comparative false}
-                :subcat {:1 {:cat :noun
-                             :case :acc
-                             :subcat '()
-                             :sem location}
-                         :2 '()}}})
+    {:unify [preposition]
+     :synsem {:cat :prep
+              :sem {:pred :a
+                    :obj {:place true}
+                    :comparative false}
+              :subcat {:1 {:cat :noun
+                           :case :acc
+                           :subcat '()}
+                       :2 '()}}}
      ;; "a" as in "a Roma"
-    (let [location (atom {:city true})]
-      {:synsem {:cat :prep
-                :sem {:pred :in
-                      :obj location}
-                :subcat {:1 {:cat :noun
-                             :sem location}
-                         :2 '()}}})
+    {:unify [preposition]
+     :synsem {:cat :prep
+              :sem {:pred :in
+                    :obj {:city true}}
+              :subcat {:1 {:cat :noun}
+                       :2 '()}}}

     ;; "a" as in "a mezzogiorno"
-    (let [time (atom {:time true})]
-      {:synsem {:cat :prep
-                :sem {:pred :a
-                      :obj time}
-                :subcat {:1 {:cat :verb
-                             :subcat '()}
-                         :2 {:cat :noun
-                             :sem time}}}})
+    {:unify [preposition]
+     :synsem {:cat :prep
+              :sem {:pred :a
+                    :obj {:time true}}
+              :subcat {:1 {:cat :noun
+                           :subcat '()}
+                       :2 '()}}}

     ;; e.g. "a ridere": tu hai fatto bene a ridere (you did well to laugh)"
 ;    (let [complement-semantics (atom {:pred :a
@@ -131,28 +145,22 @@
                            :place true}}}
    "affolato"
    [;; comparative
-    (let [is-place1 {:place true} ;; only places can be crowded.
-          is-place (atom is-place1)
+    (let [is-place {:synsem {:sem {:place true}}} ;; only places can be crowded.
           than-this (atom {:pred :di
                            :mod is-place})]
-      (unify adjective
-              comparative
-              {:synsem {:sem {:pred :affolato
-                              :arg1 is-place
-                              :arg2 is-place}
-                        :subcat {:1 {:cat :noun
-                                     :sem is-place}
-                                 :2 {:cat :prep
-                                     :sem than-this}}}})
+      {:unify [adjective comparative is-place]
+       :synsem {:sem {:pred :affolato
+                      :arg1 is-place
+                      :arg2 is-place}
+                :subcat {:1 {:cat :noun
+                             :sem is-place}
+                         :2 {:cat :prep
+                             :sem than-this}}}}
       ;; non-comparative
-      (unify adjective
-             {:synsem {:cat :adjective
-                       :sem {:pred :affolato
-                             :comparative false}}}
-             ;; TODO: make this sem-impl process happen generally with _adjective_.
-             {:synsem {:sem (sem-impl is-place1)}}))
-
-    ] ;; only places can be crowded.
+      {:unify [adjective is-place]
+       :synsem {:cat :adjective
+                :sem {:pred :affolato
+                      :comparative false}}})]

    "aggiungere" {:synsem {:cat :verb
                           :sem {:pred :add}}}
@@ -171,31 +179,29 @@
    [;; non-comparative:
     (let [subject-sem (atom {:human true}) ;; only humans can be tall.
           subject-agr (atom :top)]
-      (unify adjective
-             non-comparative-adjective
-             {:synsem {:cat :adjective
-                       :sem {:pred :alto
-                             :comparative false
-                             :arg1 subject-sem
-                             :human true}
-                       :subcat {:1 {:cat :det
-                                    :agr subject-agr
-                                    :sem subject-sem}
-                                :2 '()}}}))
+      {:unify [adjective non-comparative-adjective]
+       :synsem {:cat :adjective
+                :sem {:pred :alto
+                      :comparative false
+                      :arg1 subject-sem
+                      :human true}
+                :subcat {:1 {:cat :det
+                             :agr subject-agr
+                             :sem subject-sem}
+                         :2 '()}}})
     ;; comparative:
     (let [complement-complement-sem (atom {:human true}) ;; only humans can be tall.
           complement-sem (atom {:pred :di
                                :mod complement-complement-sem})
           subject-sem (atom {:human true})] ;; only humans can be tall.
-      (unify adjective
-             comparative
-             {:synsem {:sem {:pred :alto
-                             :arg1 subject-sem
-                             :arg2 complement-complement-sem}
-                       :subcat {:1 {:cat :noun
-                                    :sem subject-sem}
-                                :2 {:cat :prep
-                                    :sem complement-sem}}}}))]
+      {:unify [adjective comparative]
+       :synsem {:sem {:pred :alto
+                      :arg1 subject-sem
+                      :arg2 complement-complement-sem}
+                :subcat {:1 {:cat :noun
+                             :sem subject-sem}
+                         :2 {:cat :prep
+                             :sem complement-sem}}}})]

    "alzarsi" (let [subject-semantics (atom {:animate true})
                    subject-agr (atom :top)]
@@ -360,56 +366,49 @@
                                             :3plur "hanno"}}}]

      ;; 1. "avere": to possess something buyable
-     [(unify
-
-       ;; TODO: transitive should have: {:synsem {:subcat {:3 '()}}}
-       transitive
-       {:synsem {:subcat {:3 '()}}}
-       avere-common
-       {:note "avere (possess)"
-        :synsem {:sem {:pred :have
-                       :activity false
-                       :discrete false
-                       :subj {:human true}
-                       :obj {:buyable true}}}})
+     [{:unify [
+               ;; TODO: transitive should have: {:synsem {:subcat {:3 '()}}}
+               transitive
+               {:synsem {:subcat {:3 '()}}}
+               avere-common]
+       :note "avere (possess)"
+       :synsem {:sem {:pred :have
+                      :activity false
+                      :discrete false
+                      :subj {:human true}
+                      :obj {:buyable true}}}}

       ;; 2. "avere": to be in a relation with: e.g. "I have two children"
-      (unify
-       ;; TODO: transitive should have: {:synsem {:subcat {:3 '()}}}
-       transitive
-       {:synsem {:subcat {:3 '()}}}
-       avere-common
-       {:note "avere (relation)"
-        :synsem {:sem {:pred :have
-                       :activity false
-                       :discrete false
-                       :subj {:human :top}
-                       :obj {:human :top}}}})
+      {:unify [
+               ;; TODO: transitive should have: {:synsem {:subcat {:3 '()}}}
+               transitive
+               {:synsem {:subcat {:3 '()}}}
+               avere-common]
+       :note "avere (relation)"
+       :synsem {:sem {:pred :have
+                      :activity false
+                      :discrete false
+                      :subj {:human :top}
+                      :obj {:human :top}}}}

       ;; 3. avere: unspecified object
-      (unify
-       avere-common
-       verb-subjective
-       intransitive-unspecified-obj
-       {:note "avere (possess): unspecified object"
-        :synsem {:sem {:pred :have
-                       :activity false
-                       :discrete false
-                       :subj {:human true}}}})
+      {:unify [avere-common verb-subjective intransitive-unspecified-obj]
+       :note "avere (possess): unspecified object"
+       :synsem {:sem {:pred :have
+                      :activity false
+                      :discrete false
+                      :subj {:human true}}}}

       ;; 4. "avere" that takes a transitive verb: e.g. "io l'ho vista (i saw her)"
       (let [agr-of-obj-of-main-verb (atom :top)]
-        (unify
-         verb-aux
-         verb-subjective
-         avere-common
-        {:note "avere(aux): takes trans"
+        {:unify [verb-aux verb-subjective avere-common]
+         :note "avere(aux): takes trans"
          :synsem {:infl :present
                   :subcat {:2 {:agr agr-of-obj-of-main-verb
                                :reflexive false
                                :subcat {:2 {:agr agr-of-obj-of-main-verb
                                             :pronoun true}}
-                               :essere false}}}}))
+                               :essere false}}}})

       ;; 5. "avere" that takes an intransitive verb or a transitive verb within a VP
       ;;    with the object (e.g. "io ho dormito (i slept)" or "io ho [mangiato la pizza] (i ate the pizza)"
@@ -417,45 +416,39 @@
       ;; 1. subject that is the same as the subject of 2.
       ;; 2. an intransitive verb.
       (let [agr-of-subj-of-main-verb (atom :top)]
-        (unify
-         verb-aux
-         verb-subjective
-         avere-common
-         {:note "avere(aux): takes intrans"
-          :synsem {:infl :present
-                   :subcat {:1 {:agr agr-of-subj-of-main-verb}
-                            :2 {:essere false
-                                :reflexive false ;; in Italian, reflexive verbs are always essere=false.
-                                ;; this additional qualification here (:reflexive false) is not necessary
-                                ;; but is expected to reduce fails during generation.
-                                :agr agr-of-subj-of-main-verb
-                                :subcat {:1 {:agr agr-of-subj-of-main-verb}
-                                         :2 '()}}}}}))])
-
+        {:unify [verb-aux verb-subjective avere-common]
+         :note "avere(aux): takes intrans"
+         :synsem {:infl :present
+                  :subcat {:1 {:agr agr-of-subj-of-main-verb}
+                           :2 {:essere false
+                               :reflexive false ;; in Italian, reflexive verbs are always essere=false.
+                               ;; this additional qualification here (:reflexive false) is not necessary
+                               ;; but is expected to reduce fails during generation.
+                               :agr agr-of-subj-of-main-verb
+                               :subcat {:1 {:agr agr-of-subj-of-main-verb}
+                                        :2 '()}}}}})])
    "ballare" {:synsem {:cat :verb
                        :sem {:pred :dance}}}
    "bello"
    [;; non-comparative
-    (unify adjective
-           {:synsem {:sem {:pred :bello
-                           :comparative false
-                           }}}) ;; for now, no restrictions on what can be beautiful.
+    {:unify [adjective]
+     :synsem {:sem {:pred :bello
+                    :comparative false
+                    }}} ;; for now, no restrictions on what can be beautiful.

     ;; comparative
     (let [complement-complement-sem (atom :top) ;; for now no restrictions
           complement-sem (atom {:pred :di
                                :mod complement-complement-sem})
           subject-sem (atom :top)] ;; subject can be anything.
-      (unify adjective
-             comparative
-             {:synsem {:sem {:pred :bello
-                             :arg1 subject-sem
-                             :arg2 complement-complement-sem}
-                       :subcat {:1 {:cat :noun
-                                    :sem subject-sem}
-                                :2 {:cat :prep
-                                    :sem complement-sem}}}}))]
-
+      {:unify [adjective comparative]
+       :synsem {:sem {:pred :bello
+                      :arg1 subject-sem
+                      :arg2 complement-complement-sem}
+                :subcat {:1 {:cat :noun
+                             :sem subject-sem}
+                         :2 {:cat :prep
+                             :sem complement-sem}}}})]
    "bene"
    {:synsem {:cat :adverb
              :sem {:pred :bene}}}
@@ -482,15 +475,15 @@
                     :subj {:animate true}
                     :obj {:drinkable true}}}}
    "bianco"
-   (unify adjective
-          {:synsem {:cat :adjective
-                    :sem {:pred :bianco
-                          :comparative false
-                          :physical-object true
-                          :human false}}
-           :italiano {:masc {:plur "bianchi"}
-                      :fem {:plur "bianche"}
-                      :cat :adjective}})
+     {:unify [adjective]
+      :synsem {:cat :adjective
+               :sem {:pred :bianco
+                     :comparative false
+                     :physical-object true
+                     :human false}}
+      :italiano {:masc {:plur "bianchi"}
+                 :fem {:plur "bianche"}
+                 :cat :adjective}}
    "birra"
    {:synsem {:agr {:gender :fem}
              :cat :noun
@@ -513,13 +506,13 @@
    "brutto"
    ;; non-comparative
    ;; TODO: add comparative
-   (unify adjective
-          {:synsem {:cat :adjective
-                    :sem {:pred :brutto
-                          :comparative false
-                          }} ;; for now, no restrictions on what can be ugly.
-           :italiano {:cat :adjective}})
-
+     {:unify [adjective]
+      :synsem {:cat :adjective
+               :sem {:pred :brutto
+                     :comparative false
+                     }} ;; for now, no restrictions on what can be ugly.
+      :italiano {:cat :adjective}}
+
    "bucato"
    {:synsem {:cat :noun
              :agr {:gender :masc
@@ -614,13 +607,13 @@
     ]

    "cattivo"
-   (unify adjective
-          {:synsem {:cat :adjective
-                    :sem {:pred :cattivo
-                          :comparative false
-                          :human true;; TODO:should not need this because child => human.
-                          :child true}}
-           :italiano {:cat :adjective}})
+     {:unify [adjective]
+      :synsem {:cat :adjective
+               :sem {:pred :cattivo
+                     :comparative false
+                     :human true;; TODO:should not need this because child => human.
+                     :child true}}
+      :italiano {:cat :adjective}}

    ;; working on: "mi sono comprato un nuovo cellulare"
    "cellulare"
@@ -736,13 +729,13 @@
    "cittadino" {:synsem {:cat :adjective
                          :sem {:pred :local}}}

-   "colpire" (let [common {:italiano {:boot-stem1 "colpisc"}}]
-               [(merge common
-                       {:synsem {:cat :verb
-                                 :sem {:pred :hit}}})
-                (merge common
-                       {:synsem {:cat :verb
-                                 :sem {:pred :strike}}})])
+     "colpire" (let [common {:italiano {:boot-stem1 "colpisc"}}]
+                 [{:unify [common]
+                   :synsem {:cat :verb
+                            :sem {:pred :hit}}}
+                  {:unify [common]
+                   :synsem {:cat :verb
+                            :sem {:pred :strike}}}])
    "cominciare"
    [{:synsem {:cat :verb
               :essere false
@@ -794,23 +787,22 @@
           complement-sem (atom {:pred :di
                                 :mod complement-complement-sem})
           subject-sem (atom {:place true})]
-      (unify adjective
-             comparative
-             {:synsem {:sem {:pred :contento
-                             :arg1 subject-sem
-                             :arg2 complement-complement-sem}
-                       :subcat {:1 {:cat :noun
-                                    :sem subject-sem}
-                                :2 {:cat :prep
-                                    :sem complement-sem}}}})
-
+      {:unify [adjective comparative]
+       :synsem {:sem {:pred :contento
+                      :arg1 subject-sem
+                      :arg2 complement-complement-sem}
+                :subcat {:1 {:cat :noun
+                             :sem subject-sem}
+                         :2 {:cat :prep
+                             :sem complement-sem}}}}
+
       ;; non-comparative
-      (unify adjective
-             {:synsem {:cat :adjective
-                       :sem {:pred :contento
-                             :comparative false
-                             :human true}}}))]
-
+      {:unify [adjective]
+       :synsem {:cat :adjective
+                :sem {:pred :contento
+                      :comparative false
+                      :human true}}})]
+
    "contraccambiare" {:synsem {:sem {:pred :reciprocate}
                                :cat :verb}}

@@ -826,22 +818,21 @@
           complement-sem (atom {:pred :di
                                 :mod complement-complement-sem})
           subject-sem (atom {:human true})] ;; only humans can be short.
-      (unify adjective
-             comparative
-             {:synsem {:sem {:pred :corto
-                             :arg1 subject-sem
-                             :arg2 complement-complement-sem}
-                       :subcat {:1 {:cat :noun
-                                    :sem subject-sem}
-                                :2 {:cat :prep
-                                    :sem complement-sem}}}}))
+      {:unify [adjective comparative]
+       :synsem {:sem {:pred :corto
+                      :arg1 subject-sem
+                      :arg2 complement-complement-sem}
+                :subcat {:1 {:cat :noun
+                             :sem subject-sem}
+                         :2 {:cat :prep
+                             :sem complement-sem}}}})
     ;; non-comparative
-    (unify adjective
-           {:synsem {:cat :adjective
-                     :sem {:pred :corto
-                           :comparative false
-                           :human true}}
-            :italiano {:cat :adjective}})]
+    {:unify [adjective]
+     :synsem {:cat :adjective
+              :sem {:pred :corto
+                    :comparative false
+                    :human true}}
+     :italiano {:cat :adjective}}]

    "creare"  {:synsem {:cat :verb
                        :sem {:pred :create}}}
@@ -940,22 +931,22 @@
    "difficile"
    ;; non-comparative
    ;; TODO: add comparative
-   (unify adjective
-          {:synsem {:cat :adjective
-                    :sem {:pred :difficile
-                          :comparative false
-                          ;; "difficile" has a very specific list of things it can modify:
-                          :drinkable false
-                          :human false
-                          :animate false
-                          :buyable false
-                          :legible true
+     {:unify [adjective]
+      :synsem {:cat :adjective
+               :sem {:pred :difficile
+                     :comparative false
+                     ;; "difficile" has a very specific list of things it can modify:
+                     :drinkable false
+                     :human false
+                     :animate false
+                     :buyable false
+                     :legible true
                                         ;                             :activity true ;; TODO: cannot declare this as an activity because of some semantic implicature..
-                          :artifact true
-                          :physical-object true
-                          :edible false}}
-           :italiano {:cat :adjective
-                      :fem {:sing "difficile"}}})
+                     :artifact true
+                     :physical-object true
+                     :edible false}}
+      :italiano {:cat :adjective
+                 :fem {:sing "difficile"}}}

    "dipingere" {:synsem {:cat :verb
                          :sem {:pred :paint}}
@@ -967,11 +958,10 @@
                             :passato "detto"
                             :future-stem "dir"
                             :present {:2plur "dite"}}}]
-            [(unify shared-part-of-dire
-                    {:synsem {:sem {:pred :say}}})
-             (unify shared-part-of-dire
-                    {:synsem {:sem {:pred :tell}}})])
-
+            [{:unify [shared-part-of-dire]
+              :synsem {:sem {:pred :say}}}
+             {:unify [shared-part-of-dire]
+              :synsem {:sem {:pred :tell}}}])

    "diventare" {:synsem {:essere true
                          :cat :verb
@@ -996,13 +986,13 @@
                 :cat :noun
                 :sem {:pred :question}}}
    "domani"
-   (unify sentential-adverb
-          {:synsem {:cat :sent-modifier
-                    :sem {:pred :domani}
-                    :subcat {:1 {:infl :future
-                                 :sem {:tense :future}
-                                 :subcat '()}}}
-           :italiano "domani"})
+     {:unify [sentential-adverb]
+      :synsem {:cat :sent-modifier
+               :sem {:pred :domani}
+               :subcat {:1 {:infl :future
+                            :sem {:tense :future}
+                            :subcat '()}}}
+      :italiano "domani"}

    "donna"
    {:synsem {:agr {:gender :fem}
@@ -1020,12 +1010,12 @@
                             :sem time}
                         :2 '()}}})
    "dopodomani"
-   (unify sentential-adverb
-          {:synsem {:cat :sent-modifier
-                    :sem {:pred :dopodomani}
-                    :subcat {:1 {:infl :future
-                                 :sem {:tense :future}
-                                 :subcat '()}}}})
+     {:unify [sentential-adverb]
+      :synsem {:cat :sent-modifier
+               :sem {:pred :dopodomani}
+               :subcat {:1 {:infl :future
+                            :sem {:tense :future}
+                            :subcat '()}}}}
    "dormire"
    {:synsem {:cat :verb
              :essere false
@@ -1099,28 +1089,27 @@
                                      :3sing "sarebbe"
                                      :1plur "saremmo"
                                      :2plur "sareste"
-                                     :3plur "sarebbero"}}})]
+                                     :3plur "sarebbero"}}})]
      [;; essere: adjective
       ;; TODO: unify essere-adjective, essere-prepositional-phrase
       ;; and essere-intensifier into one lexical entry.
       (let [gender (atom :top)
             number (atom :top)]
-        (unify
-         essere-common
-         {:notes "essere-adjective"
-          :synsem {:cat :verb
-                   :sem {:pred :be
-                         :subj :top
-                         :obj :top}
-                   :subcat {:1 {:cat :noun
-                                :agr {:gender gender
-                                      :number number}}
-                            :2 {:cat :adjective
-                                :sem {:comparative false}
-                                :subcat {:1 :top
-                                         :2 '()}
-                                :agr {:gender gender
-                                      :number number}}}}}))
+        {:unify [essere-common]
+         :notes "essere-adjective"
+         :synsem {:cat :verb
+                  :sem {:pred :be
+                        :subj :top
+                        :obj :top}
+                  :subcat {:1 {:cat :noun
+                               :agr {:gender gender
+                                     :number number}}
+                           :2 {:cat :adjective
+                               :sem {:comparative false}
+                               :subcat {:1 :top
+                                        :2 '()}
+                               :agr {:gender gender
+                                     :number number}}}}})

       ;; essere: prepositional phrase
       (let [gender (atom :top)
@@ -1128,50 +1117,48 @@
             obj (atom {:pred :top
                        :place true})
             pred (atom :top)]
-        (unify
-         essere-common
-         {:notes "essere-prepositional-phrase"
-          :synsem {:cat :verb
-                   :aux false
-                   :sem {:pred pred
-                         :obj obj}
-                   ;; TODO: should not need agreement: should be covered by
-                   ;; essere-common.
-                   :subcat {:1 {:cat :noun
-                                :agr {:gender gender
-                                      :number number}}
-                            :2 {:cat :prep
-                                :subcat '()
-                                :sem {:pred pred
-                                      :obj obj}}
-                            :3 '()}}}))
+        {:unify [essere-common]
+         :notes "essere-prepositional-phrase"
+         :synsem {:cat :verb
+                  :aux false
+                  :sem {:pred pred
+                        :obj obj}
+                  ;; TODO: should not need agreement: should be covered by
+                  ;; essere-common.
+                  :subcat {:1 {:cat :noun
+                               :agr {:gender gender
+                                     :number number}}
+                           :2 {:cat :prep
+                               :subcat '()
+                               :sem {:pred pred
+                                     :obj obj}}
+                           :3 '()}}})

       ;; TODO: do we need this? maybe remove?
-      (unify essere-common {:notes "be"
-                            :synsem {:sem {:pred :be}}})
+      {:unify [essere-common]
+       :notes "be"
+       :synsem {:sem {:pred :be}}}

       ;; essere: copula ;; note that we don't enforce agreement the same here as we do in essere-adjective: TODO: try to make more consistent.
       (let [gender (atom :top)
             number (atom :top)
             human (atom :top)]
-        (unify
-         transitive
-         essere-common
-         {:notes "copula" ;; significant only for debugging.
-          :synsem {:cat :verb
-                   :subcat {:1 {:cat :noun
-                                :agr {:gender gender
-                                      :number number}}
-                            :2 {:cat :noun
-                                :pronoun {:not true} ;; accusative pronouns cause unbounded depth-first searches on the subject side. (TODO: not sure if this problem is still present)
-                                :def {:not :demonstrativo}
-                                :agr {:gender gender
-                                      :number number}}}
-                   :sem {:pred :be
-                         :activity false
-                         :discrete false
-                         :subj {:human human}
-                         :obj {:human human}}}}))
+        {:unify [transitive essere-common]
+         :notes "copula" ;; significant only for debugging.
+         :synsem {:cat :verb
+                  :subcat {:1 {:cat :noun
+                               :agr {:gender gender
+                                     :number number}}
+                           :2 {:cat :noun
+                               :pronoun {:not true} ;; accusative pronouns cause unbounded depth-first searches on the subject side. (TODO: not sure if this problem is still present)
+                               :def {:not :demonstrativo}
+                               :agr {:gender gender
+                                     :number number}}}
+                  :sem {:pred :be
+                        :activity false
+                        :discrete false
+                        :subj {:human human}
+                        :obj {:human human}}}})

       ;; essere: intensifier
       ;; this is for e.g "essere più alto di quelle donne belle (to be taller than those beautiful women)"
@@ -1199,11 +1186,9 @@
 ;                              :intensified true
 ;                              :obj comp-sem}}}))

-      (unify essere-common
-             verb-aux
-             verb-subjective
-             {:notes "essere-aux"
-              :italiano {:notes "essere-aux"}})])
+      {:unify [essere-common verb-aux verb-subjective]
+       :notes "essere-aux"
+       :italiano {:notes "essere-aux"}}])

    "evitare"  {:synsem {:cat :verb
                         :sem {:pred :avoid}}}
@@ -1226,28 +1211,28 @@
                                :1plur "facciamo"
                                :2plur "fate"
                                :3plur "fanno"}}}]
-     [(merge shared-part-of-fare
-             {:synsem {:sem {:pred :do}}})
-      (merge shared-part-of-fare
-             {:synsem {:sem {:pred :make}}})
-      (merge shared-part-of-fare
-             (let [subject-semantics (atom {:human true})
-                   subject-agr (atom :top)]
-               {:synsem {:cat :verb
-                         :essere true
-                         :sem {:pred :hurt-oneself
+     [{:unify [shared-part-of-fare]
+       :synsem {:sem {:pred :do}}}
+      {:unify [shared-part-of-fare]
+       :synsem {:sem {:pred :make}}}
+      (let [subject-semantics (atom {:human true})
+            subject-agr (atom :top)]
+        {:unify [shared-part-of-fare]
+         :synsem {:cat :verb
+                  :essere true
+                  :sem {:pred :hurt-oneself
+                        :reflexive true
+                        :subj subject-semantics
+                        :obj subject-semantics}
+                  :subcat {:1 {:agr subject-agr
+                               :sem subject-semantics}
+                           :2 {:agr subject-agr
+                               :pronoun true
                                :reflexive true
-                               :subj subject-semantics
-                               :obj subject-semantics}
-                         :subcat {:1 {:agr subject-agr
-                                      :sem subject-semantics}
-                                  :2 {:agr subject-agr
-                                      :pronoun true
-                                      :reflexive true
-                                      :sem subject-semantics}
-                                  :3 {:cat :adverb
-                                      :sem {:pred :bad}}}}}))])
-
+                               :sem subject-semantics}
+                           :3 {:cat :adverb
+                               :sem {:pred :bad}}}}})])
+
    "finestre" {:synsem {:agr {:gender :fem}
                         :cat :noun
                         :sem {:pred :window}}}
@@ -1282,12 +1267,12 @@
               :synsem {:sem {:pred :manage}
                        :cat :verb}}
    "giallo"
-   (unify adjective
-          {:synsem {:cat :adjective
-                    :sem {:pred :yellow
-                          :comparative false
-                          :physical-object true
-                          :human false}}})
+   {:unify [adjective]
+    :synsem {:cat :adjective
+             :sem {:pred :yellow
+                   :comparative false
+                   :physical-object true
+                   :human false}}}

    "giocare"  {:synsem {:cat :verb
                         :sem {;:obj {:games true}
@@ -1318,21 +1303,21 @@
    "guidare"  {:synsem {:cat :verb
                         :sem {:pred :guidare}}}
    "i"
-   (unify determiner
-          {:synsem {:cat :det
-                    :def :def
-                    :agr {:gender :masc
-                          :number :plur}}})
+   {:unify [determiner]
+    :synsem {:cat :det
+             :def :def
+             :agr {:gender :masc
+                   :number :plur}}}

    "idea" {:synsem {:agr {:gender :fem}
                 :cat :noun
                 :sem {:pred :idea}}}
    "il"
-   (unify determiner
-          {:synsem {:cat :det
-                    :def :def
-                    :agr {:gender :masc
-                          :number :sing}}})
+   {:unify [determiner]
+    :synsem {:cat :det
+             :def :def
+             :agr {:gender :masc
+                   :number :sing}}}

    "imparare"  {:synsem {:cat :verb
                          :sem {:pred :learn}}}
@@ -1504,10 +1489,11 @@
                                 :number :sing}
                           :sem {:pred :lei} ;; note: we don't specify human=true (english "it").
                           :subcat '()}}]
-     [(unify common
-             {:synsem {:sem {:human false}}})
-      (unify common
-             {:synsem {:sem {:human true}}})])
+     [{:unify [common]
+       :synsem {:sem {:human false}}}
+      {:unify [common]
+       :synsem {:sem {:human true}}}])
+
    "leggere"
    {:italiano {:passato "letto"}
     :synsem {:cat :verb
@@ -1604,10 +1590,10 @@
                                       :number :sing}
                                 :sem {:pred :lui} ;; note: we don't specify human=true (english "it").
                                 :subcat '()}}]
-           [(unify common
-                   {:synsem {:sem {:human false}}})
-            (unify common
-                   {:synsem {:sem {:human true}}})])
+           [{:unify [common]
+             :synsem {:sem {:human false}}}
+            {:unify [common]
+             :synsem {:sem {:human true}}}])

    "Luisa e io"
    [{:synsem {:cat :noun
@@ -1660,13 +1646,10 @@
               :sem {:pred :lie}}}

    "mezzogiorno"
-   (unify agreement-noun
-          common-noun
-          countable-noun
-          masculine-noun
-          {:synsem {:cat :noun
-                    :sem {:pred :noon
-                          :time true}}})
+   {:unify [agreement-noun common-noun countable-noun masculine-noun]
+    :synsem {:cat :noun
+             :sem {:pred :noon
+                   :time true}}}
    "mi"
    {:synsem {:cat :noun
                :pronoun true
@@ -1706,12 +1689,12 @@
    ;; non-comparative
    ;; TODO: add comparative
    "nero"
-   (unify adjective
-          {:synsem {:cat :adjective
-                    :sem {:pred :nero
-                          :comparative false
-                          :physical-object true
-                          :human false}}})
+   {:unify [adjective]
+    :synsem {:cat :adjective
+             :sem {:pred :nero
+                   :comparative false
+                   :physical-object true
+                   :human false}}}

    "noi"
    [{:synsem {:cat :noun
@@ -1767,11 +1750,11 @@
                    :sem {:pred :talk
                          :subj {:human true}}}}]
      (list
-      (unify common1 transitive
-             {:synsem {:sem {:obj {:speakable true}}}})
-      (unify common1 intransitive intransitive-unspecified-obj)
+      {:unify [common1 transitive]
+       :synsem {:sem {:obj {:speakable true}}}}
+      {:unify [common1 intransitive intransitive-unspecified-obj]}

-      (unify common2 intransitive intransitive-unspecified-obj)))
+      {:unify [common2 intransitive intransitive-unspecified-obj]}))

    "partire" {:synsem {:essere true
                        :cat :verb
@@ -1806,12 +1789,12 @@
                                :1plur "possiamo"
                                :2plur "potete"
                                :3plur "possono"}}}]
-     [(merge shared-part-of-potere
-             {:synsem {:sem {:pred :can}}})
-      (merge shared-part-of-potere
-             {:synsem {:sem {:pred :may}}})
-      (merge shared-part-of-potere
-             {:synsem {:sem {:pred :be-able-to}}})])
+     [{:unify [shared-part-of-potere]
+       :synsem {:sem {:pred :can}}}
+      {:unify [shared-part-of-potere]
+       :synsem {:sem {:pred :may}}}
+      {:unify [shared-part-of-potere]
+       :synsem {:sem {:pred :be-able-to}}}])

    "prendere" {:synsem {:cat :verb :sem {:pred :grab}}
                :italiano {:passato "preso"}}
@@ -1910,12 +1893,12 @@
    ;; non-comparative
    ;; TODO: add comparative
    "rosso"
-   (unify adjective
-          {:synsem {:cat :adjective
-                    :sem {:pred :rosso
-                          :comparative false
-                          :physical-object true
-                          :human false}}})
+   {:unify [adjective]
+    :synsem {:cat :adjective
+             :sem {:pred :rosso
+                   :comparative false
+                   :physical-object true
+                   :human false}}}

    "salire" (let [common {:synsem {:cat :verb}
                                    :essere true
@@ -1923,9 +1906,10 @@
                           :italiano {:italiano "salire"
                                      :present {:1sing "salgo"
                                                :3plur "salgono"}}}]
-             [(merge common {:synsem {:sem {:pred :get-on}}})
-              (merge common {:synsem {:sem {:pred :go-upstairs}}})])
-
+              [{:unify [common]
+                :synsem {:sem {:pred :get-on}}}
+               {:unify [common]
+                :synsem {:sem {:pred :go-upstairs}}}])

    "scappare"  {:synsem {:cat :verb
                          :sem {:pred :escape}}}
@@ -1972,18 +1956,23 @@
    "sgridare" {:synsem {:cat :verb
                         :sem {:subj {:human true}
                               :pred :scold}}}
-   "si" (map #(merge % pronoun-reflexive)
+     "si" [{:unify [pronoun-reflexive]
+
              ;; feminine singular
-             [{:synsem {:agr {:person :3rd
-                              :gender :fem
-                              :number :sing}}}
-              ;; masculine singular
-              {:synsem {:agr {:person :3rd
-                              :gender :masc
-                              :number :sing}}}
-              ;; plural: unspecified gender
-              {:synsem {:agr {:person :3rd
-                              :number :plur}}}])
+            :synsem {:agr {:person :3rd
+                           :gender :fem
+                           :number :sing}}}
+
+           {:unify [pronoun-reflexive]
+            ;; masculine singular
+            :synsem {:agr {:person :3rd
+                           :gender :masc
+                           :number :sing}}}
+
+           ;; plural: unspecified gender
+           {:unify [pronoun-reflexive]
+            :synsem {:agr {:person :3rd
+                           :number :plur}}}]

    "sistemare" {:synsem {:cat :verb
                          :sem {:pred :organize}}}
@@ -2151,8 +2140,10 @@
                           :italiano {:italiano "uscire"
                                      :boot-stem1 "esc"
                                      :boot-stem2 "usc"}}]
-              [(merge common {:synsem {:sem {:pred :go-out}}})
-               (merge common {:synsem {:sem {:pred :exit}}})])
+              [{:unify [common]
+                :synsem {:sem {:pred :go-out}}}
+               {:unify [common]
+                :synsem {:sem {:pred :exit}}}])
    "vedere"
    {:synsem {:cat :verb
              :sem {:pred :see}}
@@ -2268,12 +2259,33 @@
    ":top-noun" {:synsem {:cat :noun}
                 :top true}

-   })
-
-
+
+     }))
+
+(def lexicon-source-unify
+  (zipmap
+   (sort (keys lexicon-source))
+   (map (fn [k]
+          (let [vals (get lexicon-source k)
+                vals (cond (seq? vals)
+                           vals
+                           (vector? vals)
+                           vals
+                           true [vals])]
+            (map (fn [v]
+                   (reduce unify
+                           (cons
+                            (dissoc v :unify)
+                            (map (fn [each-unify-arg]
+                                   (cond (fn? each-unify-arg)
+                                         (each-unify-arg)
+                                         true each-unify-arg))
+                                 (:unify v)))))
+                 vals)))
+        (sort (keys lexicon-source)))))

 ;; see TODOs in lexiconfn/compile-lex (should be more of a pipeline as opposed to a argument-position-sensitive function.
-(def lexicon (-> (compile-lex lexicon-source
+(def lexicon (-> (compile-lex lexicon-source-unify
                               exception-generator
                               ;; TODO: rewrite phonize as (constrain-val-if)(one or more)
                               phonize
@@ -2287,11 +2299,11 @@
                     (get universals (get-in val [:synsem :sem :pred]))))

                  ;; TODO: refactor this; it's very monolithic currently:
-                 intransitivize
+                 ipos/intransitivize

                  ;; if verb does specify a [:sem :obj], then fill it in with subcat info.
                  ;; TODO: refactor this; it's very monolithic currently:
-                 transitivize
+                 ipos/transitivize

                  (constrain-vals-if
                   (fn [val]
@@ -2320,7 +2332,7 @@
                   ;; in such cases, don't apply agreement-noun.

                   (fn [val]
-                    (unify val agreement-noun)))
+                    (unify val ipos/agreement-noun)))

                  (constrain-vals-if
                   (fn [val]


+mezzogiorno

+mezzogiorno

--- src/babel/italiano/lexicon.cljc
+++ src/babel/italiano/lexicon.cljc
@@ -1585,6 +1585,11 @@
     {:synsem {:cat :verb
               :sem {:pred :lie}}}

+   "mezzogiorno"
+   {:synsem {:cat :noun
+             :sem {:pred :noon
+                   :time true}}}
+
     "mi"
     [{:synsem {:cat :noun
                :pronoun true


whitespace

whitespace

--- src/babel/italiano/lexicon.cljc
+++ src/babel/italiano/lexicon.cljc
@@ -2054,7 +2054,6 @@
                    :agr {:gender :fem ;; 'un' can be feminine in the case where next word is an adjective (e.g. "alta")
                          ;; and we tokenize "un'alta donna" as [un] [alta] [donna].
                          :number :sing}}}]
-
    "una"
     {:synsem {:cat :det
               :def :indef


add new ":top" and ":top-noun" lexemes

add new ":top" and ":top-noun" lexemes

--- src/babel/italiano/lexicon.cljc
+++ src/babel/italiano/lexicon.cljc
@@ -2097,7 +2097,12 @@
                                    :3sing "vuole"
                                    :1plur "vogliamo"
                                    :2plur "volete"
-                                   :3plur "vogliono"}}}})
+                                   :3plur "vogliono"}}}
+
+   ":top" {:synsem :top}
+   ":top-noun" {:synsem {:cat :noun}}
+
+   })

 ;; see TODOs in lexiconfn/compile-lex (should be more of a pipeline as opposed to a argument-position-sensitive function.
 (def lexicon (-> (compile-lex lexicon-source


add timeouts

add timeouts

--- src/tabby/net.clj
+++ src/tabby/net.clj
@@ -96,8 +96,7 @@
   "Returns a function that will handle the handshake for incoming connections."
   [state]
   (fn [s info]
-    (d/let-flow
-     [handshake (s/take! s)]
+    (d/let-flow [handshake (s/take! s 100)]
      (-> ((condp = (:type handshake)
             :peering-handshake connect-peer-socket!
             :table-tennis connect-table-tennis-socket
@@ -117,7 +116,7 @@
   (if (stream-open? (:socket peer))
     [id peer]
     (-> (d/let-flow [socket (client (:hostname peer) (:port peer))
-                     _ (s/put! socket {:src (:id state) :type :peering-handshake})]
+                     _ (s/try-put! socket {:src (:id state) :type :peering-handshake} 100)]
           (s/connect socket (:rx-stream state) {:downstream? false})
           [id (assoc peer :socket socket)])
         (d/catch (fn [ex]
@@ -156,7 +155,7 @@
     (if (stream-closed? socket)
       (dissoc-in state [:clients client] :socket)
       (do
-        (s/put! socket (dissoc p :client-dst))
+        (s/try-put! socket (dissoc p :client-dst) 100)
         state))))

 (defn- send-pkt
@@ -222,8 +221,10 @@
 (defn start-server!
   "Starts the server listening."
   [server port]
-  (swap! server assoc :election-timeout (utils/random-election-timeout @server))
-  (swap! server (fn [x] (f/become-follower x nil)))
+  (swap! server
+         (fn [s]
+           (-> (assoc s :election-timeout (utils/random-election-timeout s))
+               (f/become-follower nil))))
   (tcp/start-server
    (fn [s info]
      ((connection-handler server) (wrap-duplex-stream protocol s) info))


Rename table route to view

Rename table route to view

--- src/tesq/core.clj
+++ src/tesq/core.clj
@@ -98,7 +98,7 @@
   [:nav :ul :li] (e/clone-for
 				  [item (list-tables)]
 				  [:li :a] (e/content (prettify item))
-				  [:li :a] (e/set-attr :href (str "/table/" item))
+				  [:li :a] (e/set-attr :href (str "/view/" item))
 				  [:li] (e/add-class (if (= table item)"active"))
 				  )
   [:#content] (e/html-content (table->html table)))
@@ -106,7 +106,7 @@

 (defroutes routes
-  (GET "/table/:table" [table] (main-template table))
+  (GET "/view/:table" [table] (main-template table))
   (resources "/")
   (not-found "Page not found"))


Conversion from numbers should be millis

This provides more accuracy. It is a tricky decision to decide between
seconds and millis, but it is thought that millis will become more
idiomatic (due to improved accuracy).

--- src/tick/core.clj
+++ src/tick/core.clj
@@ -174,7 +174,7 @@
   Number
   (day [n] (DayOfWeek/of n))
   (month [n] (Month/of n))
-  (instant [n] (Instant/ofEpochSecond n))
+  (instant [n] (Instant/ofEpochMilli n))
   (year [n] (Year/of n))

   LocalDate


naming fix

naming fix

--- src/selmer/parser.clj
+++ src/selmer/parser.clj
@@ -197,7 +197,7 @@
 ;; Compile-time parsing of tags. Accumulates a transient vector
 ;; before returning the persistent vector of INodes (TextNode, FunctionNode)

-(defn add-text-node [template buf rdr]
+(defn add-node [template buf rdr]
   (let [template (if-let [text (not-empty (.toString buf))]
                    (conj! template (TextNode. text))
                    template)]
@@ -213,7 +213,7 @@
             (if (and (open-tag? ch rdr) (some #{(peek-rdr rdr)} [*tag-second* *filter-open*]))
               ;; We hit a tag so we append the buffer content to the template
               ;; and empty the buffer, then we proceed to parse the tag
-              (recur (add-text-node template buf rdr) (read-char rdr))
+              (recur (add-node template buf rdr) (read-char rdr))
               (do
                 ;; Default case, here we append the character and
                 ;; read the next char


Added test for non-beginning null terminator.

--- test/carmine/test/core.clj
+++ test/carmine/test/core.clj
@@ -262,6 +262,8 @@
     (is (= " " (wc (r/get k))))
     (wc (r/set k (byte-array 0)))
     (is (= 0 (second (wc (r/get k)))))
+    (wc (r/set k "Foobar\u0000"))
+    (is (= "Foobar\u0000" (wc (r/get k))))
     (is (thrown? Exception (wc (r/set k "\u0000Foobar"))))))

 (clean-up!) ; Leave with a fresh db


expose lucene score to client

expose lucene score to client

--- src/sledge/server.clj
+++ src/sledge/server.clj
@@ -91,7 +91,9 @@
         num-rows 50
         project (if-let [f (get p "_fields" ) ]
                   #(select-keys % (map keyword (str/split f #",")))
-                  #(assoc % "_links" (media-links %)))]
+                  #(assoc %
+                     "_score" (:_score (meta %))
+                     "_links" (media-links %)))]
     (distinct (map project
                    (clucy/search search/index query num-rows)))))


Minor cleanup

Minor cleanup

--- src/snergly/core.cljs
+++ src/snergly/core.cljs
@@ -126,10 +126,9 @@

 (defmethod read :default
   [{:keys [state] :as env} key params]
-  (let [st @state]
-    (if-let [[_ value] (find st key)]
+    (if-let [value (@state key)]
       {:value value}
-      {:value :not-found})))
+      {:value :not-found}))

 (defmulti produce-maze-value (fn [k v s] k))


Improve distance-shading color allocation.

Based on running some experiments, I've learned that
it's very rare for the maximum distance in a distances run
to be more than 80% of the number of cells in the grid.
And with my previous setting, I pretty frequently saw the
shading get to the darkest shade too soon.  This (80% of
the total number of cells as the expected maximum distance)
should be a much better setting.

--- src/snergly/core.cljs
+++ src/snergly/core.cljs
@@ -50,7 +50,7 @@
   ;; 2. Choose the max-distance to pass in differently based on what algorithm
   ;;    was used to generate the maze, in which case I need to do some tests
   ;;    to see what the max distance is for different algorithms.
-  (grid/grid-annotate-cells maze {:color (grid/xform-values #(util/color-cell (/ (grid/grid-size maze) 2) % color-family) distances)}))
+  (grid/grid-annotate-cells maze {:color (grid/xform-values #(util/color-cell (* (grid/grid-size maze) 0.8) % color-family) distances)}))

 (defn annotate-grid-flat [maze distances color-family]
   (grid/grid-annotate-cells maze {:color (grid/xform-values #(util/color-cell % % color-family) distances)}))


remove debugging print

remove debugging print

--- src/chat/client/dispatcher.cljs
+++ src/chat/client/dispatcher.cljs
@@ -356,5 +356,4 @@

 (defmethod sync/event-handler :chat/notify-message
   [[_ message]]
-  (println "Got notification " message)
   (notify/notify {:msg (:content message)}))


Fixed interpolator, made cleaning conditional on not being 100% good or bad series

--- src/clj/forma/trends/filter.clj
+++ src/clj/forma/trends/filter.clj
@@ -82,7 +82,7 @@
   "calculate a linear interpolation between `x1` and `x2` with the specified
   `length` between them."
   [x1 x2 length]
-  (let [delta (/ (- x2 x1) (dec length))]
+  (let [delta (/ (- x2 x1) length)]
     (vec
      (for [n (range length)]
        (float (+ x1 (* n delta)))))))
@@ -130,8 +130,8 @@
             (map #(for [[m n] % :while (bad-set n)] m)
                  [m-coll r-coll])))))

-(defn act-on-good
-  "apply function `func` to all non-nil values within a collection `coll`"
+(defn apply-to-valid
+  "apply function `f` to all valid (non-nil) values within a collection `coll`"
   [f coll]
   (f (filter (complement nil?) coll)))

@@ -142,7 +142,7 @@
   `neutralize-ends` will return the original time-series. `bad-set` is a set of
   `reli-coll` values that indicate unreliable pixels."
   [bad-set reli-coll val-coll]
-  (let [avg (act-on-good u/coll-avg
+  (let [avg (apply-to-valid u/coll-avg
                          (mask bad-set reli-coll val-coll))]
     (replace-index-set (bad-ends bad-set reli-coll)
                        avg
@@ -160,16 +160,18 @@
   passable values, presumably interchangeable.  If this assumption is
   not true, then an adjustment will have to be made to this function."
   [bad-set good-set quality-coll value-coll]
-  (when (seq (filter bad-set quality-coll))
-    (let [bad-end-set (bad-ends bad-set quality-coll)
-          new-qual (replace-index-set bad-end-set
-                                      (first good-set)
-                                      quality-coll)
-          new-vals (neutralize-ends bad-set
-                                    quality-coll
-                                    value-coll)
-          good-seq (positions (complement bad-set)
-                              new-qual)]
-      (vec (flatten [(map (partial stretch-ts new-vals)
-                          (partition 2 1 good-seq))
-                     (nth new-vals (last good-seq))])))))
+  (let [qual-set (set quality-coll)]
+    (cond (empty? (seq (clojure.set/intersection good-set qual-set))) nil
+          (empty? (clojure.set/difference qual-set good-set)) value-coll
+          :else (let [bad-end-set (bad-ends bad-set quality-coll)
+                      new-qual (replace-index-set bad-end-set
+                                                  (first good-set)
+                                                  quality-coll)
+                      new-vals (neutralize-ends bad-set
+                                                quality-coll
+                                                value-coll)
+                      good-seq (positions (complement bad-set)
+                                          new-qual)]
+                  (vec (flatten [(map (partial stretch-ts new-vals)
+                                      (partition 2 1 good-seq))
+                                 (nth new-vals (last good-seq))]))))))


Extracted a macro to remove common validation.

--- src/clj/freefrog/governance.clj
+++ src/clj/freefrog/governance.clj
@@ -20,16 +20,16 @@
      (assoc anchor-circle :lead-link
             {:name lead-link-name :email lead-link-email}))))

-(defn- add-if [map key value]
+(defn- assoc-if [map key value]
   (if value
     (assoc map key value)
     map))

 (defn- make-role [purpose domains accountabilities]
   (-> {}
-      (add-if :purpose purpose)
-      (add-if :domains domains)
-      (add-if :accountabilities accountabilities)))
+      (assoc-if :purpose purpose)
+      (assoc-if :domains domains)
+      (assoc-if :accountabilities accountabilities)))

 (defn add-role
   "Adds a role to a circle.  The role may not conflict with an existing role.
@@ -67,17 +67,20 @@
     (throw (IllegalArgumentException. "No role specified to update")))
   (validate-role-exists circle role-name))

-(defn rename-role
+(defmacro updatefn [name docstring args & body]
+  `(defn ~name ~docstring ~args
+     (validate-updates ~(first args) ~(second args))
+     ~@body))
+
+(updatefn rename-role
   "Rename a role in the given circle."
   [circle role-name new-name]
-  (validate-updates circle role-name)
   (update-in circle [:roles]
              s/rename-keys {role-name new-name}))

-(defn update-role-purpose
+(updatefn update-role-purpose
   "Update the purpose of a role in the given circle."
   [circle role-name new-purpose]
-  (validate-updates circle role-name)
   (if (empty? new-purpose)
     (update-in circle [:roles role-name]
                dissoc :purpose)
@@ -87,17 +90,15 @@
 (defn- get-domains [circle role-name]
   (get-in circle [:roles role-name :domains]))

-(defn- validate-domain-not-present [circle role-name domain]
-  (if (contains? (get-domains circle role-name) domain)
-    (throw (IllegalArgumentException.
-             (format "Domain '%s' already exists on role '%s'" domain
-                     role-name)))))
+(defn- validate-domain [presence-fn err-msg circle role-name domain]
+  (if (presence-fn (get-domains circle role-name) domain)
+    (throw (IllegalArgumentException. (format err-msg domain role-name)))))

-(defn add-domain
+(updatefn add-domain
   "Add a domain to a role in the given circle."
   [circle role-name domain]
-  (validate-updates circle role-name)
-  (validate-domain-not-present circle role-name domain)
+  (validate-domain contains? "Domain '%s' already exists on role '%s'"
+                   circle role-name domain)

   (let [domains (get-domains circle role-name)
         circle (if domains
@@ -105,17 +106,12 @@
                  (update-in circle [:roles role-name] assoc :domains #{}))]
     (update-in circle [:roles role-name :domains] conj domain)))

-(defn- validate-domain-present [circle role-name domain]
-  (if-not (contains? (get-domains circle role-name) domain)
-    (throw (IllegalArgumentException.
-             (format "Domain '%s' doesn't exist on role '%s'" domain
-                     role-name)))))
-
-(defn remove-domain
+(updatefn remove-domain
   "Remove a domain from a role in the given circle."
   [circle role-name domain]
-  (validate-updates circle role-name)
-  (validate-domain-present circle role-name domain)
+  (validate-domain (comp not contains?)
+                   "Domain '%s' doesn't exist on role '%s'"
+                   circle role-name domain)
   (let [result (update-in circle [:roles role-name :domains] disj domain)]
     (if (empty? (get-domains result role-name))
       (update-in result [:roles role-name] dissoc :domains)


identify chosen ice when using Cortez Chip

--- src/clj/game/cards-hardware.clj
+++ src/clj/game/cards-hardware.clj
@@ -89,10 +89,18 @@
                                        :effect (effect (play-instant target))}}}}}

    "Cortez Chip"
-   {:abilities [{:label "increase cost to rez a piece of ice by 2 [Credits]"
-                 :prompt "Choose a piece of ice" :choices {:req #(and (not (:rezzed %)) (= (:type %) "ICE"))}
-                 :effect (effect (update! (assoc card :cortez-target target))
-                                 (trash (get-card state card) {:cause :ability-cost}))}]
+   {:abilities [{:prompt "Choose a piece of ICE" :choices {:req #(and (not (:rezzed %)) (= (:type %) "ICE"))}
+                 :effect (req (let [ice target
+                                    serv (cond
+                                          (= (second (:zone ice)) :hq) "HQ"
+                                          (= (second (:zone ice)) :rd) "R&D"
+                                          (= (second (:zone ice)) :archives) "Archives"
+                                          :else (join " " ["Server" (last (butlast (:zone ice)))]))]
+                                (update! state side (assoc card :cortez-target ice))
+                                (trash state side (get-card state card) {:cause :ability-cost})
+                                (system-msg state side
+                                  (str "increases the cost to rez the ICE at position "
+                                    (ice-index state ice) " of " serv " by 2 [Credits] until the end of the turn"))))}]
     :trash-effect {:effect (effect (register-events {:pre-rez {:req (req (= (:cid target) (:cid (:cortez-target card))))
                                                                :effect (effect (rez-cost-bonus 2))}
                                                      :runner-turn-ends {:effect (effect (unregister-events card))}


verify signed badge

verify signed badge

--- src/clj/salava/badge/verify.clj
+++ src/clj/salava/badge/verify.clj
@@ -3,7 +3,12 @@
             [salava.core.http :as http]
             [salava.core.time :refer [iso8601-to-unix-time unix-time]]
             [clojure.tools.logging :as log]
-            #_[clj-http.client :as client]))
+            [salava.core.util :refer [get-db]]
+            [yesql.core :refer [defqueries]]
+            [salava.badge.parse :refer [str->badge]]
+            [clojure.data.json :as json]))
+
+(defqueries "sql/badge/main.sql")

 (defn url? [s]
   (not (clojure.string/blank? (re-find #"^http" (str s)))))
@@ -36,33 +41,74 @@
       (log/error "failed to get assertion url " assertion-url " Message: "(.getMessage e) )
       {:status 500})))

-(defn verify-badge [ctx asr user-id]
+(defn- assertion-jws [b signature]
+  (log/info "fetching assertion from signature")
+  (try
+    (str->badge {:id (:user_id b) :emails [(:email b)]} signature)
+    (catch Exception e
+      (log/error (.getMessage e))
+      {:status 500 :message (.getMessage e)})))
+
+(defn revoked? [badge-id revocation-list]
+  (filter #(if (map? %) (= badge-id (:id %)) (= badge-id %)) revocation-list))
+
+(defn verify-badge [ctx badge_id user-id]
   (log/info "Badge verification initiated:")
-  (let [asr-response (assertion asr)
+  (let [badge (b/get-badge ctx badge_id user-id)
+        asr (if (clojure.string/blank? (:assertion_url badge)) (get-assertion-jws {:id badge_id} (into {:result-set-fn first :row-fn :assertion_jws} (get-db ctx))) (:assertion_url badge))
         result {}]
-    (case (:status asr-response)
-      410 (assoc result
-            :assertion-status 410
-            :revoked? true)
-      500 (assoc result :assertion-status 500
-            :badge-status "Broken url, badge can't be verified")
-      200 (let [asr-data (:body asr-response)
-                badge-data (fetch-json-data (:badge asr-data))
-                badge-image (if (map? (:image badge-data)) (fetch-image (get-in badge-data [:image :id])) (fetch-image (:image badge-data)))
-                badge-criteria (if (and (map? (:criteria badge-data))(contains? (:criteria badge-data) :id))
-                                 (fetch-url (get-in badge-data [:criteria :id]))
-                                 (if (url? (:criteria badge-data)) (fetch-url (:criteria badge-data)) {:status 800}))
-                badge-issuer (if (and (map? (:issuer badge-data)) (contains? (:issuer badge-data) :id))
-                               (fetch-url (get-in badge-data [:issuer :id]))
-                               (if (url? (:issuer badge-data)) (fetch-url (:issuer badge-data)) {:status 800}))
-                revoked? (or (= (:status asr-response) 410) (:revoked asr-data))
-                expired? (and (:expires asr-data) (< (iso8601-to-unix-time (:expires asr-data)) (unix-time)))]
+    (if (url? asr)
+      (let [asr-response (assertion asr)]
+        (case (:status asr-response)
+          410 (assoc result
+                :assertion-status 410
+                :revoked? true)
+          500 (assoc result :assertion-status 500
+                :asr asr
+                :badge-status "Broken assertion url, badge can't be verified")
+          200 (let [asr-data (:body asr-response)
+                    badge-data (fetch-json-data (:badge asr-data))
+                    badge-image (if (map? (:image badge-data)) (fetch-image (get-in badge-data [:image :id])) (fetch-image (:image badge-data)))
+                    badge-criteria (if (and (map? (:criteria badge-data))(contains? (:criteria badge-data) :id))
+                                     (fetch-url (get-in badge-data [:criteria :id]))
+                                     (if (url? (:criteria badge-data)) (fetch-url (:criteria badge-data)) {:status 800}))
+                    badge-issuer (if (and (map? (:issuer badge-data)) (contains? (:issuer badge-data) :id))
+                                   (fetch-url (get-in badge-data [:issuer :id]))
+                                   (if (url? (:issuer badge-data)) (fetch-url (:issuer badge-data)) {:status 800}))
+                    revoked? (or (= (:status asr-response) 410) (:revoked asr-data))
+                    expired? (and (:expires asr-data) (< (iso8601-to-unix-time (:expires asr-data)) (unix-time)))]

-            (assoc result :assertion-status 200
-              :assertion asr-data
-              :badge-image-status (:status badge-image)
-              :badge-criteria-status (:status badge-criteria)
-              :badge-issuer-status (:status badge-issuer)
-              :revoked? revoked?
-              :expired? expired?
-              )))))
+                (assoc result :assertion-status 200
+                  :assertion asr-data
+                  :asr asr
+                  :badge-image-status (:status badge-image)
+                  :badge-criteria-status (:status badge-criteria)
+                  :badge-issuer-status (:status badge-issuer)
+                  :revoked? revoked?
+                  :expired? expired?
+                  ))))
+      (let [jws-response (assertion-jws badge asr)
+            badge-id (or (:id (json/read-str (:assertion_json jws-response) :key-fn keyword)) (:uid (json/read-str (:assertion_json jws-response) :key-fn keyword)))
+            revocation-list-url (:revocation_list_url (first (get-in jws-response [:badge :issuer])))
+            revocation-list (if revocation-list-url (:revokedAssertions (fetch-json-data revocation-list-url)))
+            revoked (revoked? badge-id revocation-list)
+            revocation-reason (:revocationReason (first revoked))]
+        (if (= 500 (:status jws-response))
+          (assoc result :assertion-status 500
+            :asr asr
+            :badge-status (:message jws-response))
+          (assoc result :assertion-status 200
+            :assertion (json/read-str (:assertion_json jws-response) :key-fn keyword )
+            :asr asr
+            :badge-image-status 200
+            :badge-criteria-status 200
+            :badge-issuer-status 200
+            :revoked? (not (empty? revoked))
+            :revocation_reason revocation-reason
+            :expired? (if (:expires_on jws-response) (< (:expires_on jws-response) (unix-time)))
+            )
+          )
+        )
+      )
+    )
+  )


Use reagent/wrap for passing state around

--- src/cljs/hacker_agent/core.cljs
+++ src/cljs/hacker_agent/core.cljs
@@ -72,7 +72,7 @@
          [comment-list (vec kids)])])))

 (defn story-list-item [story]
-  (let [{:keys [by id title score url kids]} story]
+  (let [{:keys [by id title score url kids]} @story]
     (when (every? identity [by title score])
       [:div
        [:p [:a {:href url} title]]
@@ -88,30 +88,27 @@
                 :style {:cursor :pointer}}
          [:i "Preview"]]]])))

-(defn top-stories [state]
-  (let [{top-stories :top-stories} state
-        selected-story (get-in state [:current-item])]
-    [:ol
-     (for [[index entry] (into (sorted-map) top-stories)]
-       (let [id (entry :id)]
-         (if (= id (:id selected-story))
-           ^{:key index} [:li
-                          [story-list-item entry]
-                          [comment-list (vec (:kids selected-story))]]
-           ^{:key index} [:li [story-list-item entry]])))]))
+(defn top-stories [stories]
+  [:ol
+   (for [[index entry] (into (sorted-map) @stories)]
+     ^{:key index}
+     [:li [story-list-item
+           (r/wrap entry
+                   swap! stories assoc index)]])])

 ;; -------------------------
 ;; Views
-(defmulti page :render-view)
+(defmulti page #(:render-view (deref %)))

 (defmethod page nil [_]
   [:div "Invalid/Unknown route"])

 (defmethod page :main [state]
-  [top-stories state])
+  [top-stories (r/wrap (:top-stories @state)
+                       swap! app-state assoc :top-stories)])

 (defmethod page :item [state]
-  (when-let [entry (get-in state [:current-item])]
+  (when-let [entry (get-in @state [:current-item])]
     (case (:type entry)
       "story" [story entry]
       "comment" [comment entry]
@@ -120,7 +117,7 @@
 (defn main-page [state]
   [:div
    [nav]
-   (page @state)])
+   (page state)])

 ;; -------------------------
 ;; Routes


Smaller chart

Smaller chart

--- src/cljs/mokkameister/core.cljs
+++ src/cljs/mokkameister/core.cljs
@@ -75,7 +75,8 @@
 (defn chart []
   (if-let [chart-data (get-in @state [:stats :month-stats])]
     (let [month-count (map :count chart-data)]
-      [:pre.chart (js/chart (clj->js month-count))])))
+      [:pre.chart (js/chart (clj->js month-count)
+                            (clj->js {:width 85}))])))

 (defn trigger-alarm! [message]
   (swap! state #(assoc % :alarm message))


Don't connect the websocket until it makes sense

--- src/cljs/retroboard/client.cljs
+++ src/cljs/retroboard/client.cljs
@@ -33,8 +33,8 @@
                    (fn [e]
                      (let [msg (reader/read-string (.-message e))]
                        (put! incoming msg))))
-    (.open ws ws-url)
-    {:to-send to-send :incoming (pub incoming :cmd) :websocket ws}))
+    {:to-send to-send :incoming (pub incoming :cmd) :websocket ws
+     :connect (fn [] (.open ws ws-url))}))

 (defn create-environment
   ([& [initial-actions]]
@@ -307,17 +307,18 @@
     (will-mount [_]
       (let [action-chan (chan)
             eid (:id app)]
-        (error-handler app)
         (when eid
+          ((get-in app [:connection :connect]))
+          (error-handler app)
           (put! (get-in (if (om/rendering?) app @app) [:connection :to-send])
-                {:cmd :register :action eid}))
-        (sub (get-in app [:connection :incoming]) :cmds action-chan)
-        (go (let [actions (:commands (<! action-chan))]
-              (om/update! app :connected :connected)
-              (user/add-board eid)
-              (go-loop [actions actions]
-                       (om/transact! app :state (partial apply-actions actions))
-                       (recur (:commands (<! action-chan))))))))
+                {:cmd :register :action eid})
+          (sub (get-in app [:connection :incoming]) :cmds action-chan)
+          (go (let [actions (:commands (<! action-chan))]
+                (om/update! app :connected :connected)
+                (user/add-board eid)
+                (go-loop [actions actions]
+                         (om/transact! app :state (partial apply-actions actions))
+                         (recur (:commands (<! action-chan)))))))))
     om/IRenderState
     (render-state [this state]
       (let [connection (om/value (:connection app))


turn off reflection warnings

turn off reflection warnings

--- src/clojure/flambo/function.clj
+++ src/clojure/flambo/function.clj
@@ -5,7 +5,7 @@
             [clojure.tools.logging :as log])
   (:import [scala Tuple2]))

-(set! *warn-on-reflection* true)
+(set! *warn-on-reflection* false)

 (defn- serfn? [f]
   (= (type f) :serializable.fn/serializable-fn))