refactored facts -> fact

refactored facts -> fact

--- integration/org/domaindrivenarchitecture/pallet/servertest/instantiate_aws_servertest.clj
+++ integration/org/domaindrivenarchitecture/pallet/servertest/instantiate_aws_servertest.clj
@@ -26,7 +26,7 @@
       [org.domaindrivenarchitecture.pallet.crate.config :as config]
       [org.domaindrivenarchitecture.pallet.crate.init :as init]
       [org.domaindrivenarchitecture.pallet.crate.servertest :as servertest]
-      [org.domaindrivenarchitecture.pallet.servertest.facts.netstat :as netstat-res]
+      [org.domaindrivenarchitecture.pallet.servertest.fact.netstat :as netstat-res]
       [org.domaindrivenarchitecture.pallet.servertest.test.netstat :as netstat-test])
   (:gen-class :main true))


Revert "feat: cached jts (for gml)"

Revert "feat: cached jts (for gml)"

This reverts commit d1e4489a95eb7f33a34ccf50a3a6445c54fae0d9.

--- src/main/clojure/pdok/featured/feature.clj
+++ src/main/clojure/pdok/featured/feature.clj
@@ -1,7 +1,6 @@
 (ns pdok.featured.feature
   (:refer-clojure :exclude [type])
   (:require [clojure.string :as str]
-            [clojure.core.cache :as cache]
             [clojure.java.io :as io]
             [clojure.java.jdbc :as j]
             [pdok.postgres :as pg]
@@ -62,7 +61,7 @@
 (def gml3-parser (GML3Parser.))

 (defn gml3-as-jts [gml]
-  (locking gml3-parser (.toJTSGeometry ^GML3Parser gml3-parser gml)))
+  (.toJTSGeometry ^GML3Parser gml3-parser gml))

 (def wkt-writer (WKTWriter.))

@@ -84,16 +83,9 @@

 (defmulti as-jts (fn [obj] (lower-case (get obj "type"))))
 (defmethod as-jts :default [_] nil)
-
-(def gml->jts-cache (atom (cache/fifo-cache-factory {} :threshold 15000)))
 (defmethod as-jts "gml" [obj]
  (when-let [gml (get obj "gml")]
-   (if (cache/has? @gml->jts-cache gml)
-     (cache/lookup @gml->jts-cache gml)
-     (let [jts (gml3-as-jts gml)
-           _ (swap! gml->jts-cache #(cache/miss % gml jts))]
-       jts))))
-
+  (gml3-as-jts gml)))
 (defmethod as-jts "jts" [obj]
   (get obj "jts"))


missing refer

missing refer

--- src/pc/views/blog/product_hunt_wake_up_call.clj
+++ src/pc/views/blog/product_hunt_wake_up_call.clj
@@ -1,5 +1,6 @@
 (ns pc.views.blog.product-hunt-wake-up-call
   (:require [ring.middleware.anti-forgery :refer (wrap-anti-forgery)]
+            [pc.views.common :refer (cdn-path)]
             [pc.views.blog.common :as common]))

 (defn product-hunt-wake-up-call []


remove runtime-eval from UI for now

remove runtime-eval from UI for now

need to work out more kinks so it becomes actually usable

--- src/main/shadow/cljs/ui/pages/inspect.cljs
+++ src/main/shadow/cljs/ui/pages/inspect.cljs
@@ -981,7 +981,7 @@
       (when object
         (ui-object-inspect object))

-      (ui-runtime-eval runtime))))
+      #_ (ui-runtime-eval runtime))))

 (def ui-runtime-tap-page (fc/factory RuntimeTapPage {}))


Increase quest icon size

Increase quest icon size

--- src/braid/client/quests/styles.cljs
+++ src/braid/client/quests/styles.cljs
@@ -4,10 +4,11 @@
             [braid.client.ui.styles.vars :as vars]
             [braid.client.ui.styles.mixins :as mixins]))

-(def quest-icon-size (rem 2))
+(def quest-icon-size (rem 2.5))

 (defn quests-header [header-text header-height]
   [:&
+
    [:.quests-header
     {:position "relative"}

@@ -93,7 +94,7 @@

          [:p
           {:margin 0
-           :width (em 18)}]]
+           :width (em 20)}]]

         [:.actions
          {:align-self "center"}


Refactor several pallet fns out of circle, so they can be used w/ the rails node

--- src/circle/backend/nodes/circle.clj
+++ src/circle/backend/nodes/circle.clj
@@ -22,7 +22,8 @@
             [pallet.thread-expr :as thread-expr]
             [circle.sh :as sh]
             [circle.backend.ssh :as ssh]
-            [circle.backend.nodes :as nodes])
+            [circle.backend.nodes :as nodes]
+            [circle.backend.pallet :as circle-pallet])
   (:use [arohner.utils :only (inspect)]))

 ;; this is our "memoized" circle box
@@ -38,24 +39,6 @@
                       :username "ubuntu"
                       :public-key (slurp "www.id_rsa.pub")
                       :private-key (slurp "www.id_rsa")}))
-
-(defmacro user-code
-  "Runs a seq of stevedore commands as the non-sudo user"
-  [session & cmds]
-  `(let [cmds# (stevedore/with-script-language :pallet.stevedore.bash/bash
-                (clojure.string/join ";" (map (fn [c#]
-                                                (stevedore/emit-script [c#])) (quote ~cmds))))]
-    (-> ~session
-        (exec-script/exec-checked-script
-         "rvm cmd"
-         ("sudo" "-i" "-u" (unquote (-> ~session :user :username)) "bash" "-c" (unquote (format "\"%s\"" cmds#)))))))
-
-(defn install-rvm-profile [session]
-  (-> session
-      (remote-file/remote-file "~/rvm.sed" :local-file "pallet/ruby/rvm.sed" :no-versioning true)
-      (exec-script/exec-checked-script
-       "Installing RVM in the profile"
-       (sudo "-i" "-u" ~(-> session :user :username) bash "-c" "\"sed -f rvm.sed ~/.bashrc > ~/.bashrc-new && mv ~/.bashrc-new ~/.bashrc\""))))

 ;; The configuration to build the circle box from scratch
 (def circle-raw-group
@@ -93,8 +76,8 @@
                                 (sudo "REALLY_GEM_UPDATE_SYSTEM=true" gem update --system)))

                              (rvm/rvm)
-                             (install-rvm-profile)
-                             (user-code
+                             (circle-pallet/install-rvm-profile)
+                             (circle-pallet/user-code
                               (source "~/.bashrc") ;; make sure RVM is loaded
                               (rvm install jruby)
                               (rvm use jruby)


extract images/search

extract images/search

--- src/clj/clj_money/models/images.clj
+++ src/clj/clj_money/models/images.clj
@@ -27,12 +27,19 @@
                                 ::body-hash
                                 ::body]))

+(defn search
+  ([storage-spec criteria]
+   (search storage-spec criteria {}))
+  ([storage-spec criteria options]
+   (with-storage [s storage-spec]
+     (select-images s criteria options))))
+
 (defn- find-by-hash
   [storage user-id hash]
-  (first (select-images storage
-                        {:user-id user-id
-                         :body-hash hash}
-                        {:limit 1})))
+  (first (search storage
+                 {:user-id user-id
+                  :body-hash hash}
+                 {:limit 1})))

 (defn- body-hash-is-unique?
   [storage {:keys [body-hash user-id]}]


Moved beta-dict creation back into let

Moved beta-dict creation back into let

--- src/clj/forma/hadoop/jobs/forma.clj
+++ src/clj/forma/hadoop/jobs/forma.clj
@@ -158,13 +158,13 @@
   "query to end all queries: estimate the probabilities for each
   period after the training period."
   [eco-beta-src dynamic-src static-src]
-  (<- [?s-res ?mod-h ?mod-v ?s ?l ?prob-series]
-      (dynamic-src ?s-res ?pd ?mod-h ?mod-v ?s ?l ?val ?neighbor-val)
-      (static-src ?s-res ?mod-h ?mod-v ?s ?l _ _ ?eco _)
-      (log/beta-dict eco-beta-src :> ?beta-dict)
-      (apply-betas [?beta-dict] ?eco ?val ?neighbor-val :> ?prob)
-      (log/mk-timeseries ?pd ?prob :> ?prob-series)
-      (:distinct false)))
+  (let [beta-dict (log/beta-dict eco-beta-src)]
+    (<- [?s-res ?mod-h ?mod-v ?s ?l ?prob-series]
+        (dynamic-src ?s-res ?pd ?mod-h ?mod-v ?s ?l ?val ?neighbor-val)
+        (static-src ?s-res ?mod-h ?mod-v ?s ?l _ _ ?eco _)
+        (apply-betas [beta-dict] ?eco ?val ?neighbor-val :> ?prob)
+        (log/mk-timeseries ?pd ?prob :> ?prob-series)
+      (:distinct false))))

 (comment
   (let [m {:est-start "2005-12-31"


add product desc in search results

add product desc in search results

--- src/clj/ikea_clojure_cup/search.clj
+++ src/clj/ikea_clojure_cup/search.clj
@@ -2,37 +2,1541 @@
   (:require [org.httpkit.client :as http-kit]
             [hickory.core :as hick]
             [hickory.select :as s]
-            [clojure.string :as cu]))
+            [clojure.string :as cs]
+            [clojure.pprint :refer [pprint]]))

 (def ikea-domain "http://www.ikea.com")

 (defn search [region query]
-  (let [url (format "%s/%s/en/search/?query=%s" ikea-domain region query)
-        response1 (http-kit/get url)
-        site-htree (-> @response1 :body hick/parse hick/as-hickory)
-        hick-products (s/select (s/child (s/class "productContainer")
-                                         (s/class "parentContainer")
-                                         (s/class "productPadding")
-                                         (s/tag :a)) site-htree)]
-    (reduce (fn [v m]
-          (let [product-id (-> m :attrs :href (cu/split #"/") last)
-                content (:content m)
-                image-src (-> (filter (fn [{:keys [type tag]}] (and (= :element type) (= :img tag))) content)
-                              first
-                              :attrs
-                              :src)
-                product-name (-> (filter (fn [{:keys [type tag attrs]}] (and (= :element type)
-                                                                             (= :span tag)
-                                                                             (= "prodName prodNameTro" (:class attrs)))) content)
-                                 first
-                                 :content
-                                 first)]
-            (conj v {:id product-id
-                     :image-src (str ikea-domain image-src)
-                     :name product-name})))
-        []
-        hick-products)))
+  (when-not (cs/blank? query)
+    (let [url (format "%s/%s/en/search/?query=%s" ikea-domain region query)
+          response1 (http-kit/get url)
+          site-htree (-> @response1 :body hick/parse hick/as-hickory)
+          hick-products (s/select (s/child (s/class "productContainer")
+                                           (s/class "parentContainer")
+                                           (s/class "productPadding")
+                                           (s/tag :a)) site-htree)]
+      (reduce (fn [v m]
+                (let [product-id (-> m :attrs :href (cs/split #"/") last)
+                      content (:content m)
+                      image-src (-> (filter (fn [{:keys [type tag]}] (and (= :element type) (= :img tag))) content)
+                                    first
+                                    :attrs
+                                    :src)
+                      product-name (-> (filter (fn [{:keys [type tag attrs]}] (and (= :element type)
+                                                                                (= :span tag)
+                                                                                (= "prodName prodNameTro" (:class attrs)))) content)
+                                       first
+                                       :content
+                                       first
+                                       )
+                      product-desc-divs (mapcat :content (filter (fn [{:keys [type tag attrs]}] (and (= :element type)
+                                                                                (= :div tag)))
+                                                                 content))
+                      product-desc (filter (fn [{:keys [type attrs]}] (= type :element) (= "prodDesc" (:class attrs))) product-desc-divs)]
+                  (conj v {:id product-id
+                           :image-src (str ikea-domain image-src)
+                           :name product-name
+                           :desc (-> product-desc first :content first)})))
+              []
+              hick-products))))

 (comment
-  (search "au" "kitchen"))
+  (search "au" "billy"))

+(def products-sample
+[{:type :element,
+  :attrs
+  {:href "/au/en/catalog/products/80279814/",
+   :onclick "irwStatTopProductClicked();"},
+  :tag :a,
+  :content
+  ["\r\n\t\t\t\r\n\t\t"
+   {:type :element,
+    :attrs
+    {:id "imgThmbProduct1",
+     :src "/PIAimages/0252388_PE391190_S2.JPG",
+     :border "0",
+     :alt
+     "BILLY Height extension unit Width: 80 cm Depth: 28 cm Height: 35 cm",
+     :class "prodImg"},
+    :tag :img,
+    :content nil}
+   "\r\n\t\t\r\n\t\t\r\n\t\t"
+   {:type :element,
+    :attrs {:id "txtNameProduct1", :class "prodName prodNameTro"},
+    :tag :span,
+    :content ["BILLY"]}
+   "\r\n\t\t"
+   {:type :element,
+    :attrs nil,
+    :tag :div,
+    :content
+    ["\r\n\t\t\t"
+     {:type :element,
+      :attrs
+      {:id "txtDescrProduct1",
+       :style "display:inline;",
+       :class "prodDesc"},
+      :tag :span,
+      :content ["Height extension unit \r\n\t\t\t\t\r\n\t\t\t"]}
+     "\r\n\t\t\t\r\n\t\t"]}
+   "\r\n\t\t\r\n\t\t\t"
+   {:type :element,
+    :attrs
+    {:id "txtPriceProduct1", :class "prodPrice", :style "clear:both;"},
+    :tag :span,
+    :content ["\r\n\t\t\t\t$40\t\t\t\t\r\n\t\t\t"]}
+   "\r\n\t\t\t\t\r\n\t\t"
+   {:type :element,
+    :attrs {:id "comparisonContainer", :style "display: none"},
+    :tag :div,
+    :content
+    ["\r\n\t\t\t"
+     {:type :element,
+      :attrs nil,
+      :tag :span,
+      :content ["\r\n\t\t\t\tUnit price\r\n\t\t\t"]}
+     "\r\n\t\t\t"
+     {:type :element,
+      :attrs {:class "packagepricevaluebold", :id "comparisonPrice"},
+      :tag :span,
+      :content nil}
+     "\r\n\t\t"]}
+   "\r\n\t\t \r\n\t\t"]}
+ {:type :element,
+  :attrs
+  {:href "/au/en/catalog/products/90263855/",
+   :onclick "irwStatTopProductClicked();"},
+  :tag :a,
+  :content
+  ["\r\n\t\t\t\r\n\t\t"
+   {:type :element,
+    :attrs
+    {:id "imgThmbProduct2",
+     :src "/PIAimages/0252390_PE391192_S2.JPG",
+     :border "0",
+     :alt
+     "BILLY Height extension unit Width: 80 cm Depth: 28 cm Height: 35 cm",
+     :class "prodImg"},
+    :tag :img,
+    :content nil}
+   "\r\n\t\t\r\n\t\t\r\n\t\t"
+   {:type :element,
+    :attrs {:id "txtNameProduct2", :class "prodName prodNameTro"},
+    :tag :span,
+    :content ["BILLY"]}
+   "\r\n\t\t"
+   {:type :element,
+    :attrs nil,
+    :tag :div,
+    :content
+    ["\r\n\t\t\t"
+     {:type :element,
+      :attrs
+      {:id "txtDescrProduct2",
+       :style "display:inline;",
+       :class "prodDesc"},
+      :tag :span,
+      :content ["Height extension unit \r\n\t\t\t\t\r\n\t\t\t"]}
+     "\r\n\t\t\t\r\n\t\t"]}
+   "\r\n\t\t\r\n\t\t\t"
+   {:type :element,
+    :attrs
+    {:id "txtPriceProduct2", :class "prodPrice", :style "clear:both;"},
+    :tag :span,
+    :content ["\r\n\t\t\t\t$40\t\t\t\t\r\n\t\t\t"]}
+   "\r\n\t\t\t\t\r\n\t\t"
+   {:type :element,
+    :attrs {:id "comparisonContainer", :style "display: none"},
+    :tag :div,
+    :content
+    ["\r\n\t\t\t"
+     {:type :element,
+      :attrs nil,
+      :tag :span,
+      :content ["\r\n\t\t\t\tUnit price\r\n\t\t\t"]}
+     "\r\n\t\t\t"
+     {:type :element,
+      :attrs {:class "packagepricevaluebold", :id "comparisonPrice"},
+      :tag :span,
+      :content nil}
+     "\r\n\t\t"]}
+   "\r\n\t\t \r\n\t\t"]}
+ {:type :element,
+  :attrs
+  {:href "/au/en/catalog/products/20263854/",
+   :onclick "irwStatTopProductClicked();"},
+  :tag :a,
+  :content
+  ["\r\n\t\t\t\r\n\t\t"
+   {:type :element,
+    :attrs
+    {:id "imgThmbProduct3",
+     :src "/PIAimages/0252393_PE391191_S2.JPG",
+     :border "0",
+     :alt
+     "BILLY Height extension unit Width: 80 cm Depth: 28 cm Height: 35 cm",
+     :class "prodImg"},
+    :tag :img,
+    :content nil}
+   "\r\n\t\t\r\n\t\t\r\n\t\t"
+   {:type :element,
+    :attrs {:id "txtNameProduct3", :class "prodName prodNameTro"},
+    :tag :span,
+    :content ["BILLY"]}
+   "\r\n\t\t"
+   {:type :element,
+    :attrs nil,
+    :tag :div,
+    :content
+    ["\r\n\t\t\t"
+     {:type :element,
+      :attrs
+      {:id "txtDescrProduct3",
+       :style "display:inline;",
+       :class "prodDesc"},
+      :tag :span,
+      :content ["Height extension unit \r\n\t\t\t\t\r\n\t\t\t"]}
+     "\r\n\t\t\t\r\n\t\t"]}
+   "\r\n\t\t\r\n\t\t\t"
+   {:type :element,
+    :attrs
+    {:id "txtPriceProduct3", :class "prodPrice", :style "clear:both;"},
+    :tag :span,
+    :content ["\r\n\t\t\t\t$30\t\t\t\t\r\n\t\t\t"]}
+   "\r\n\t\t\t\t\r\n\t\t"
+   {:type :element,
+    :attrs {:id "comparisonContainer", :style "display: none"},
+    :tag :div,
+    :content
+    ["\r\n\t\t\t"
+     {:type :element,
+      :attrs nil,
+      :tag :span,
+      :content ["\r\n\t\t\t\tUnit price\r\n\t\t\t"]}
+     "\r\n\t\t\t"
+     {:type :element,
+      :attrs {:class "packagepricevaluebold", :id "comparisonPrice"},
+      :tag :span,
+      :content nil}
+     "\r\n\t\t"]}
+   "\r\n\t\t \r\n\t\t"]}
+ {:type :element,
+  :attrs
+  {:href "/au/en/catalog/products/80279791/",
+   :onclick "irwStatTopProductClicked();"},
+  :tag :a,
+  :content
+  ["\r\n\t\t\t\r\n\t\t"
+   {:type :element,
+    :attrs
+    {:id "imgThmbProduct4",
+     :src "/PIAimages/0252265_PE391057_S2.JPG",
+     :border "0",
+     :alt "BILLY Bookcase Width: 40 cm Depth: 28 cm Height: 106 cm",
+     :class "prodImg"},
+    :tag :img,
+    :content nil}
+   "\r\n\t\t\r\n\t\t\r\n\t\t"
+   {:type :element,
+    :attrs {:id "txtNameProduct4", :class "prodName prodNameTro"},
+    :tag :span,
+    :content ["BILLY"]}
+   "\r\n\t\t"
+   {:type :element,
+    :attrs nil,
+    :tag :div,
+    :content
+    ["\r\n\t\t\t"
+     {:type :element,
+      :attrs
+      {:id "txtDescrProduct4",
+       :style "display:inline;",
+       :class "prodDesc"},
+      :tag :span,
+      :content ["Bookcase \r\n\t\t\t\t\r\n\t\t\t"]}
+     "\r\n\t\t\t\r\n\t\t"]}
+   "\r\n\t\t\r\n\t\t\t"
+   {:type :element,
+    :attrs
+    {:id "txtPriceProduct4", :class "prodPrice", :style "clear:both;"},
+    :tag :span,
+    :content ["\r\n\t\t\t\t$49\t\t\t\t\r\n\t\t\t"]}
+   "\r\n\t\t\t\t\r\n\t\t"
+   {:type :element,
+    :attrs {:id "comparisonContainer", :style "display: none"},
+    :tag :div,
+    :content
+    ["\r\n\t\t\t"
+     {:type :element,
+      :attrs nil,
+      :tag :span,
+      :content ["\r\n\t\t\t\tUnit price\r\n\t\t\t"]}
+     "\r\n\t\t\t"
+     {:type :element,
+      :attrs {:class "packagepricevaluebold", :id "comparisonPrice"},
+      :tag :span,
+      :content nil}
+     "\r\n\t\t"]}
+   "\r\n\t\t \r\n\t\t"]}
+ {:type :element,
+  :attrs
+  {:href "/au/en/catalog/products/00263831/",
+   :onclick "irwStatTopProductClicked();"},
+  :tag :a,
+  :content
+  ["\r\n\t\t\t\r\n\t\t"
+   {:type :element,
+    :attrs
+    {:id "imgThmbProduct5",
+     :src "/PIAimages/0252260_PE391060_S2.JPG",
+     :border "0",
+     :alt "BILLY Bookcase Width: 40 cm Depth: 28 cm Height: 106 cm",
+     :class "prodImg"},
+    :tag :img,
+    :content nil}
+   "\r\n\t\t\r\n\t\t\r\n\t\t"
+   {:type :element,
+    :attrs {:id "txtNameProduct5", :class "prodName prodNameTro"},
+    :tag :span,
+    :content ["BILLY"]}
+   "\r\n\t\t"
+   {:type :element,
+    :attrs nil,
+    :tag :div,
+    :content
+    ["\r\n\t\t\t"
+     {:type :element,
+      :attrs
+      {:id "txtDescrProduct5",
+       :style "display:inline;",
+       :class "prodDesc"},
+      :tag :span,
+      :content ["Bookcase \r\n\t\t\t\t\r\n\t\t\t"]}
+     "\r\n\t\t\t\r\n\t\t"]}
+   "\r\n\t\t\r\n\t\t\t"
+   {:type :element,
+    :attrs
+    {:id "txtPriceProduct5", :class "prodPrice", :style "clear:both;"},
+    :tag :span,
+    :content ["\r\n\t\t\t\t$49\t\t\t\t\r\n\t\t\t"]}
+   "\r\n\t\t\t\t\r\n\t\t"
+   {:type :element,
+    :attrs {:id "comparisonContainer", :style "display: none"},
+    :tag :div,
+    :content
+    ["\r\n\t\t\t"
+     {:type :element,
+      :attrs nil,
+      :tag :span,
+      :content ["\r\n\t\t\t\tUnit price\r\n\t\t\t"]}
+     "\r\n\t\t\t"
+     {:type :element,
+      :attrs {:class "packagepricevaluebold", :id "comparisonPrice"},
+      :tag :span,
+      :content nil}
+     "\r\n\t\t"]}
+   "\r\n\t\t \r\n\t\t"]}
+ {:type :element,
+  :attrs
+  {:href "/au/en/catalog/products/60263833/",
+   :onclick "irwStatTopProductClicked();"},
+  :tag :a,
+  :content
+  ["\r\n\t\t\t\r\n\t\t"
+   {:type :element,
+    :attrs
+    {:id "imgThmbProduct6",
+     :src "/PIAimages/0252255_PE391058_S2.JPG",
+     :border "0",
+     :alt "BILLY Bookcase Width: 40 cm Depth: 28 cm Height: 106 cm",
+     :class "prodImg"},
+    :tag :img,
+    :content nil}
+   "\r\n\t\t\r\n\t\t\r\n\t\t"
+   {:type :element,
+    :attrs {:id "txtNameProduct6", :class "prodName prodNameTro"},
+    :tag :span,
+    :content ["BILLY"]}
+   "\r\n\t\t"
+   {:type :element,
+    :attrs nil,
+    :tag :div,
+    :content
+    ["\r\n\t\t\t"
+     {:type :element,
+      :attrs
+      {:id "txtDescrProduct6",
+       :style "display:inline;",
+       :class "prodDesc"},
+      :tag :span,
+      :content ["Bookcase \r\n\t\t\t\t\r\n\t\t\t"]}
+     "\r\n\t\t\t\r\n\t\t"]}
+   "\r\n\t\t\r\n\t\t\t"
+   {:type :element,
+    :attrs
+    {:id "txtPriceProduct6", :class "prodPrice", :style "clear:both;"},
+    :tag :span,
+    :content ["\r\n\t\t\t\t$39\t\t\t\t\r\n\t\t\t"]}
+   "\r\n\t\t\t\t\r\n\t\t"
+   {:type :element,
+    :attrs {:id "comparisonContainer", :style "display: none"},
+    :tag :div,
+    :content
+    ["\r\n\t\t\t"
+     {:type :element,
+      :attrs nil,
+      :tag :span,
+      :content ["\r\n\t\t\t\tUnit price\r\n\t\t\t"]}
+     "\r\n\t\t\t"
+     {:type :element,
+      :attrs {:class "packagepricevaluebold", :id "comparisonPrice"},
+      :tag :span,
+      :content nil}
+     "\r\n\t\t"]}
+   "\r\n\t\t \r\n\t\t"]}
+ {:type :element,
+  :attrs
+  {:href "/au/en/catalog/products/00279785/",
+   :onclick "irwStatTopProductClicked();"},
+  :tag :a,
+  :content
+  ["\r\n\t\t\t\r\n\t\t"
+   {:type :element,
+    :attrs
+    {:id "imgThmbProduct7",
+     :src "/PIAimages/0252339_PE391166_S2.JPG",
+     :border "0",
+     :alt "BILLY Bookcase Width: 40 cm Depth: 28 cm Height: 202 cm",
+     :class "prodImg"},
+    :tag :img,
+    :content nil}
+   "\r\n\t\t\r\n\t\t\r\n\t\t"
+   {:type :element,
+    :attrs {:id "txtNameProduct7", :class "prodName prodNameTro"},
+    :tag :span,
+    :content ["BILLY"]}
+   "\r\n\t\t"
+   {:type :element,
+    :attrs nil,
+    :tag :div,
+    :content
+    ["\r\n\t\t\t"
+     {:type :element,
+      :attrs
+      {:id "txtDescrProduct7",
+       :style "display:inline;",
+       :class "prodDesc"},
+      :tag :span,
+      :content ["Bookcase \r\n\t\t\t\t\r\n\t\t\t"]}
+     "\r\n\t\t\t\r\n\t\t"]}
+   "\r\n\t\t\r\n\t\t\t"
+   {:type :element,
+    :attrs
+    {:id "txtPriceProduct7", :class "prodPrice", :style "clear:both;"},
+    :tag :span,
+    :content ["\r\n\t\t\t\t$69\t\t\t\t\r\n\t\t\t"]}
+   "\r\n\t\t\t\t\r\n\t\t"
+   {:type :element,
+    :attrs {:id "comparisonContainer", :style "display: none"},
+    :tag :div,
+    :content
+    ["\r\n\t\t\t"
+     {:type :element,
+      :attrs nil,
+      :tag :span,
+      :content ["\r\n\t\t\t\tUnit price\r\n\t\t\t"]}
+     "\r\n\t\t\t"
+     {:type :element,
+      :attrs {:class "packagepricevaluebold", :id "comparisonPrice"},
+      :tag :span,
+      :content nil}
+     "\r\n\t\t"]}
+   "\r\n\t\t \r\n\t\t"]}
+ {:type :element,
+  :attrs
+  {:href "/au/en/catalog/products/70263837/",
+   :onclick "irwStatTopProductClicked();"},
+  :tag :a,
+  :content
+  ["\r\n\t\t\t\r\n\t\t"
+   {:type :element,
+    :attrs
+    {:id "imgThmbProduct8",
+     :src "/PIAimages/0252338_PE391165_S2.JPG",
+     :border "0",
+     :alt "BILLY Bookcase Width: 40 cm Depth: 28 cm Height: 202 cm",
+     :class "prodImg"},
+    :tag :img,
+    :content nil}
+   "\r\n\t\t\r\n\t\t\r\n\t\t"
+   {:type :element,
+    :attrs {:id "txtNameProduct8", :class "prodName prodNameTro"},
+    :tag :span,
+    :content ["BILLY"]}
+   "\r\n\t\t"
+   {:type :element,
+    :attrs nil,
+    :tag :div,
+    :content
+    ["\r\n\t\t\t"
+     {:type :element,
+      :attrs
+      {:id "txtDescrProduct8",
+       :style "display:inline;",
+       :class "prodDesc"},
+      :tag :span,
+      :content ["Bookcase \r\n\t\t\t\t\r\n\t\t\t"]}
+     "\r\n\t\t\t\r\n\t\t"]}
+   "\r\n\t\t\r\n\t\t\t"
+   {:type :element,
+    :attrs
+    {:id "txtPriceProduct8", :class "prodPrice", :style "clear:both;"},
+    :tag :span,
+    :content ["\r\n\t\t\t\t$69\t\t\t\t\r\n\t\t\t"]}
+   "\r\n\t\t\t\t\r\n\t\t"
+   {:type :element,
+    :attrs {:id "comparisonContainer", :style "display: none"},
+    :tag :div,
+    :content
+    ["\r\n\t\t\t"
+     {:type :element,
+      :attrs nil,
+      :tag :span,
+      :content ["\r\n\t\t\t\tUnit price\r\n\t\t\t"]}
+     "\r\n\t\t\t"
+     {:type :element,
+      :attrs {:class "packagepricevaluebold", :id "comparisonPrice"},
+      :tag :span,
+      :content nil}
+     "\r\n\t\t"]}
+   "\r\n\t\t \r\n\t\t"]}
+ {:type :element,
+  :attrs
+  {:href "/au/en/catalog/products/30263839/",
+   :onclick "irwStatTopProductClicked();"},
+  :tag :a,
+  :content
+  ["\r\n\t\t\t\r\n\t\t"
+   {:type :element,
+    :attrs
+    {:id "imgThmbProduct9",
+     :src "/PIAimages/0252341_PE391168_S2.JPG",
+     :border "0",
+     :alt "BILLY Bookcase Width: 40 cm Depth: 28 cm Height: 202 cm",
+     :class "prodImg"},
+    :tag :img,
+    :content nil}
+   "\r\n\t\t\r\n\t\t\r\n\t\t"
+   {:type :element,
+    :attrs {:id "txtNameProduct9", :class "prodName prodNameTro"},
+    :tag :span,
+    :content ["BILLY"]}
+   "\r\n\t\t"
+   {:type :element,
+    :attrs nil,
+    :tag :div,
+    :content
+    ["\r\n\t\t\t"
+     {:type :element,
+      :attrs
+      {:id "txtDescrProduct9",
+       :style "display:inline;",
+       :class "prodDesc"},
+      :tag :span,
+      :content ["Bookcase \r\n\t\t\t\t\r\n\t\t\t"]}
+     "\r\n\t\t\t\r\n\t\t"]}
+   "\r\n\t\t\r\n\t\t\t"
+   {:type :element,
+    :attrs
+    {:id "txtPriceProduct9", :class "prodPrice", :style "clear:both;"},
+    :tag :span,
+    :content ["\r\n\t\t\t\t$59\t\t\t\t\r\n\t\t\t"]}
+   "\r\n\t\t\t\t\r\n\t\t"
+   {:type :element,
+    :attrs {:id "comparisonContainer", :style "display: none"},
+    :tag :div,
+    :content
+    ["\r\n\t\t\t"
+     {:type :element,
+      :attrs nil,
+      :tag :span,
+      :content ["\r\n\t\t\t\tUnit price\r\n\t\t\t"]}
+     "\r\n\t\t\t"
+     {:type :element,
+      :attrs {:class "packagepricevaluebold", :id "comparisonPrice"},
+      :tag :span,
+      :content nil}
+     "\r\n\t\t"]}
+   "\r\n\t\t \r\n\t\t"]}
+ {:type :element,
+  :attrs
+  {:href "/au/en/catalog/products/20279789/",
+   :onclick "irwStatTopProductClicked();"},
+  :tag :a,
+  :content
+  ["\r\n\t\t\t\r\n\t\t"
+   {:type :element,
+    :attrs
+    {:id "imgThmbProduct10",
+     :src "/PIAimages/0252362_PE391155_S2.JPG",
+     :border "0",
+     :alt "BILLY Bookcase Width: 80 cm Depth: 28 cm Height: 202 cm",
+     :class "prodImg"},
+    :tag :img,
+    :content nil}
+   "\r\n\t\t\r\n\t\t\r\n\t\t"
+   {:type :element,
+    :attrs {:id "txtNameProduct10", :class "prodName prodNameTro"},
+    :tag :span,
+    :content ["BILLY"]}
+   "\r\n\t\t"
+   {:type :element,
+    :attrs nil,
+    :tag :div,
+    :content
+    ["\r\n\t\t\t"
+     {:type :element,
+      :attrs
+      {:id "txtDescrProduct10",
+       :style "display:inline;",
+       :class "prodDesc"},
+      :tag :span,
+      :content ["Bookcase \r\n\t\t\t\t\r\n\t\t\t"]}
+     "\r\n\t\t\t\r\n\t\t"]}
+   "\r\n\t\t\r\n\t\t\t"
+   {:type :element,
+    :attrs
+    {:id "txtPriceProduct10",
+     :class "prodPrice",
+     :style "clear:both;"},
+    :tag :span,
+    :content ["\r\n\t\t\t\t$95\t\t\t\t\r\n\t\t\t"]}
+   "\r\n\t\t\t\t\r\n\t\t"
+   {:type :element,
+    :attrs {:id "comparisonContainer", :style "display: none"},
+    :tag :div,
+    :content
+    ["\r\n\t\t\t"
+     {:type :element,
+      :attrs nil,
+      :tag :span,
+      :content ["\r\n\t\t\t\tUnit price\r\n\t\t\t"]}
+     "\r\n\t\t\t"
+     {:type :element,
+      :attrs {:class "packagepricevaluebold", :id "comparisonPrice"},
+      :tag :span,
+      :content nil}
+     "\r\n\t\t"]}
+   "\r\n\t\t \r\n\t\t"]}
+ {:type :element,
+  :attrs
+  {:href "/au/en/catalog/products/20263849/",
+   :onclick "irwStatTopProductClicked();"},
+  :tag :a,
+  :content
+  ["\r\n\t\t\t\r\n\t\t"
+   {:type :element,
+    :attrs
+    {:id "imgThmbProduct11",
+     :src "/PIAimages/0252347_PE391171_S2.JPG",
+     :border "0",
+     :alt "BILLY Bookcase Width: 80 cm Depth: 28 cm Height: 202 cm",
+     :class "prodImg"},
+    :tag :img,
+    :content nil}
+   "\r\n\t\t\r\n\t\t\r\n\t\t"
+   {:type :element,
+    :attrs {:id "txtNameProduct11", :class "prodName prodNameTro"},
+    :tag :span,
+    :content ["BILLY"]}
+   "\r\n\t\t"
+   {:type :element,
+    :attrs nil,
+    :tag :div,
+    :content
+    ["\r\n\t\t\t"
+     {:type :element,
+      :attrs
+      {:id "txtDescrProduct11",
+       :style "display:inline;",
+       :class "prodDesc"},
+      :tag :span,
+      :content ["Bookcase \r\n\t\t\t\t\r\n\t\t\t"]}
+     "\r\n\t\t\t\r\n\t\t"]}
+   "\r\n\t\t\r\n\t\t\t"
+   {:type :element,
+    :attrs
+    {:id "txtPriceProduct11",
+     :class "prodPrice",
+     :style "clear:both;"},
+    :tag :span,
+    :content ["\r\n\t\t\t\t$95\t\t\t\t\r\n\t\t\t"]}
+   "\r\n\t\t\t\t\r\n\t\t"
+   {:type :element,
+    :attrs {:id "comparisonContainer", :style "display: none"},
+    :tag :div,
+    :content
+    ["\r\n\t\t\t"
+     {:type :element,
+      :attrs nil,
+      :tag :span,
+      :content ["\r\n\t\t\t\tUnit price\r\n\t\t\t"]}
+     "\r\n\t\t\t"
+     {:type :element,
+      :attrs {:class "packagepricevaluebold", :id "comparisonPrice"},
+      :tag :span,
+      :content nil}
+     "\r\n\t\t"]}
+   "\r\n\t\t \r\n\t\t"]}
+ {:type :element,
+  :attrs
+  {:href "/au/en/catalog/products/80263851/",
+   :onclick "irwStatTopProductClicked();"},
+  :tag :a,
+  :content
+  ["\r\n\t\t\t\r\n\t\t"
+   {:type :element,
+    :attrs
+    {:id "imgThmbProduct12",
+     :src "/PIAimages/0252367_PE391149_S2.JPG",
+     :border "0",
+     :alt "BILLY Bookcase Width: 80 cm Depth: 28 cm Height: 202 cm",
+     :class "prodImg"},
+    :tag :img,
+    :content nil}
+   "\r\n\t\t\r\n\t\t\r\n\t\t"
+   {:type :element,
+    :attrs {:id "txtNameProduct12", :class "prodName prodNameTro"},
+    :tag :span,
+    :content ["BILLY"]}
+   "\r\n\t\t"
+   {:type :element,
+    :attrs nil,
+    :tag :div,
+    :content
+    ["\r\n\t\t\t"
+     {:type :element,
+      :attrs
+      {:id "txtDescrProduct12",
+       :style "display:inline;",
+       :class "prodDesc"},
+      :tag :span,
+      :content ["Bookcase \r\n\t\t\t\t\r\n\t\t\t"]}
+     "\r\n\t\t\t\r\n\t\t"]}
+   "\r\n\t\t\r\n\t\t\t"
+   {:type :element,
+    :attrs
+    {:id "txtPriceProduct12",
+     :class "prodPrice",
+     :style "clear:both;"},
+    :tag :span,
+    :content ["\r\n\t\t\t\t$69\t\t\t\t\r\n\t\t\t"]}
+   "\r\n\t\t\t\t\r\n\t\t"
+   {:type :element,
+    :attrs {:id "comparisonContainer", :style "display: none"},
+    :tag :div,
+    :content
+    ["\r\n\t\t\t"
+     {:type :element,
+      :attrs nil,
+      :tag :span,
+      :content ["\r\n\t\t\t\tUnit price\r\n\t\t\t"]}
+     "\r\n\t\t\t"
+     {:type :element,
+      :attrs {:class "packagepricevaluebold", :id "comparisonPrice"},
+      :tag :span,
+      :content nil}
+     "\r\n\t\t"]}
+   "\r\n\t\t \r\n\t\t"]}
+ {:type :element,
+  :attrs
+  {:href "/au/en/catalog/products/40279806/",
+   :onclick "irwStatTopProductClicked();"},
+  :tag :a,
+  :content
+  ["\r\n\t\t\t\r\n\t\t"
+   {:type :element,
+    :attrs
+    {:id "imgThmbProduct13",
+     :src "/PIAimages/0252430_PE391215_S2.JPG",
+     :border "0",
+     :alt
+     "BILLY Extra shelf Width: 76 cm Depth: 26 cm Thickness: 2 cm",
+     :class "prodImg"},
+    :tag :img,
+    :content nil}
+   "\r\n\t\t\r\n\t\t\r\n\t\t"
+   {:type :element,
+    :attrs {:id "txtNameProduct13", :class "prodName prodNameTro"},
+    :tag :span,
+    :content ["BILLY"]}
+   "\r\n\t\t"
+   {:type :element,
+    :attrs nil,
+    :tag :div,
+    :content
+    ["\r\n\t\t\t"
+     {:type :element,
+      :attrs
+      {:id "txtDescrProduct13",
+       :style "display:inline;",
+       :class "prodDesc"},
+      :tag :span,
+      :content ["Extra shelf \r\n\t\t\t\t\r\n\t\t\t"]}
+     "\r\n\t\t\t\r\n\t\t"]}
+   "\r\n\t\t\r\n\t\t\t"
+   {:type :element,
+    :attrs
+    {:id "txtPriceProduct13",
+     :class "prodPrice",
+     :style "clear:both;"},
+    :tag :span,
+    :content ["\r\n\t\t\t\t$10\t\t\t\t\r\n\t\t\t"]}
+   "\r\n\t\t\t\t\r\n\t\t"
+   {:type :element,
+    :attrs {:id "comparisonContainer", :style "display: none"},
+    :tag :div,
+    :content
+    ["\r\n\t\t\t"
+     {:type :element,
+      :attrs nil,
+      :tag :span,
+      :content ["\r\n\t\t\t\tUnit price\r\n\t\t\t"]}
+     "\r\n\t\t\t"
+     {:type :element,
+      :attrs {:class "packagepricevaluebold", :id "comparisonPrice"},
+      :tag :span,
+      :content nil}
+     "\r\n\t\t"]}
+   "\r\n\t\t \r\n\t\t"]}
+ {:type :element,
+  :attrs
+  {:href "/au/en/catalog/products/80265299/",
+   :onclick "irwStatTopProductClicked();"},
+  :tag :a,
+  :content
+  ["\r\n\t\t\t\r\n\t\t"
+   {:type :element,
+    :attrs
+    {:id "imgThmbProduct14",
+     :src "/PIAimages/0252423_PE391213_S2.JPG",
+     :border "0",
+     :alt
+     "BILLY Extra shelf Width: 76 cm Depth: 26 cm Thickness: 2 cm",
+     :class "prodImg"},
+    :tag :img,
+    :content nil}
+   "\r\n\t\t\r\n\t\t\r\n\t\t"
+   {:type :element,
+    :attrs {:id "txtNameProduct14", :class "prodName prodNameTro"},
+    :tag :span,
+    :content ["BILLY"]}
+   "\r\n\t\t"
+   {:type :element,
+    :attrs nil,
+    :tag :div,
+    :content
+    ["\r\n\t\t\t"
+     {:type :element,
+      :attrs
+      {:id "txtDescrProduct14",
+       :style "display:inline;",
+       :class "prodDesc"},
+      :tag :span,
+      :content ["Extra shelf \r\n\t\t\t\t\r\n\t\t\t"]}
+     "\r\n\t\t\t\r\n\t\t"]}
+   "\r\n\t\t\r\n\t\t\t"
+   {:type :element,
+    :attrs
+    {:id "txtPriceProduct14",
+     :class "prodPrice",
+     :style "clear:both;"},
+    :tag :span,
+    :content ["\r\n\t\t\t\t$10\t\t\t\t\r\n\t\t\t"]}
+   "\r\n\t\t\t\t\r\n\t\t"
+   {:type :element,
+    :attrs {:id "comparisonContainer", :style "display: none"},
+    :tag :div,
+    :content
+    ["\r\n\t\t\t"
+     {:type :element,
+      :attrs nil,
+      :tag :span,
+      :content ["\r\n\t\t\t\tUnit price\r\n\t\t\t"]}
+     "\r\n\t\t\t"
+     {:type :element,
+      :attrs {:class "packagepricevaluebold", :id "comparisonPrice"},
+      :tag :span,
+      :content nil}
+     "\r\n\t\t"]}
+   "\r\n\t\t \r\n\t\t"]}
+ {:type :element,
+  :attrs
+  {:href "/au/en/catalog/products/90286753/",
+   :onclick "irwStatTopProductClicked();"},
+  :tag :a,
+  :content
+  ["\r\n\t\t\t\r\n\t\t"
+   {:type :element,
+    :attrs
+    {:id "imgThmbProduct15",
+     :src "/PIAimages/20466_PE105614_S2.JPG",
+     :border "0",
+     :alt
+     "BILLY Extra shelf Width: 76 cm Depth: 26 cm Max. load/shelf: 10 kg",
+     :class "prodImg"},
+    :tag :img,
+    :content nil}
+   "\r\n\t\t\r\n\t\t\r\n\t\t"
+   {:type :element,
+    :attrs {:id "txtNameProduct15", :class "prodName prodNameTro"},
+    :tag :span,
+    :content ["BILLY"]}
+   "\r\n\t\t"
+   {:type :element,
+    :attrs nil,
+    :tag :div,
+    :content
+    ["\r\n\t\t\t"
+     {:type :element,
+      :attrs
+      {:id "txtDescrProduct15",
+       :style "display:inline;",
+       :class "prodDesc"},
+      :tag :span,
+      :content ["Extra shelf \r\n\t\t\t\t\r\n\t\t\t"]}
+     "\r\n\t\t\t\r\n\t\t"]}
+   "\r\n\t\t\r\n\t\t\t"
+   {:type :element,
+    :attrs
+    {:id "txtPriceProduct15",
+     :class "prodPrice",
+     :style "clear:both;"},
+    :tag :span,
+    :content ["\r\n\t\t\t\t$10\t\t\t\t\r\n\t\t\t"]}
+   "\r\n\t\t\t\t\r\n\t\t"
+   {:type :element,
+    :attrs {:id "comparisonContainer", :style "display: none"},
+    :tag :div,
+    :content
+    ["\r\n\t\t\t"
+     {:type :element,
+      :attrs nil,
+      :tag :span,
+      :content ["\r\n\t\t\t\tUnit price\r\n\t\t\t"]}
+     "\r\n\t\t\t"
+     {:type :element,
+      :attrs {:class "packagepricevaluebold", :id "comparisonPrice"},
+      :tag :span,
+      :content nil}
+     "\r\n\t\t"]}
+   "\r\n\t\t \r\n\t\t"]}
+ {:type :element,
+  :attrs
+  {:href "/au/en/catalog/products/00265302/",
+   :onclick "irwStatTopProductClicked();"},
+  :tag :a,
+  :content
+  ["\r\n\t\t\t\r\n\t\t"
+   {:type :element,
+    :attrs
+    {:id "imgThmbProduct16",
+     :src "/PIAimages/0252420_PE391212_S2.JPG",
+     :border "0",
+     :alt
+     "BILLY Extra shelf Width: 76 cm Depth: 26 cm Thickness: 2 cm",
+     :class "prodImg"},
+    :tag :img,
+    :content nil}
+   "\r\n\t\t\r\n\t\t\r\n\t\t"
+   {:type :element,
+    :attrs {:id "txtNameProduct16", :class "prodName prodNameTro"},
+    :tag :span,
+    :content ["BILLY"]}
+   "\r\n\t\t"
+   {:type :element,
+    :attrs nil,
+    :tag :div,
+    :content
+    ["\r\n\t\t\t"
+     {:type :element,
+      :attrs
+      {:id "txtDescrProduct16",
+       :style "display:inline;",
+       :class "prodDesc"},
+      :tag :span,
+      :content ["Extra shelf \r\n\t\t\t\t\r\n\t\t\t"]}
+     "\r\n\t\t\t\r\n\t\t"]}
+   "\r\n\t\t\r\n\t\t\t"
+   {:type :element,
+    :attrs
+    {:id "txtPriceProduct16",
+     :class "prodPrice",
+     :style "clear:both;"},
+    :tag :span,
+    :content ["\r\n\t\t\t\t$10\t\t\t\t\r\n\t\t\t"]}
+   "\r\n\t\t\t\t\r\n\t\t"
+   {:type :element,
+    :attrs {:id "comparisonContainer", :style "display: none"},
+    :tag :div,
+    :content
+    ["\r\n\t\t\t"
+     {:type :element,
+      :attrs nil,
+      :tag :span,
+      :content ["\r\n\t\t\t\tUnit price\r\n\t\t\t"]}
+     "\r\n\t\t\t"
+     {:type :element,
+      :attrs {:class "packagepricevaluebold", :id "comparisonPrice"},
+      :tag :span,
+      :content nil}
+     "\r\n\t\t"]}
+   "\r\n\t\t \r\n\t\t"]}
+ {:type :element,
+  :attrs
+  {:href "/au/en/catalog/products/S49020501/",
+   :onclick "irwStatTopProductClicked();"},
+  :tag :a,
+  :content
+  ["\r\n\t\t\t\r\n\t\t"
+   {:type :element,
+    :attrs
+    {:id "imgThmbProduct17",
+     :src "/PIAimages/0255285_PE399413_S2.JPG",
+     :border "0",
+     :alt "BILLY Bookcase Width: 160 cm Depth: 28 cm Height: 202 cm",
+     :class "prodImg"},
+    :tag :img,
+    :content nil}
+   "\r\n\t\t\r\n\t\t\r\n\t\t"
+   {:type :element,
+    :attrs {:id "txtNameProduct17", :class "prodName prodNameTro"},
+    :tag :span,
+    :content ["BILLY"]}
+   "\r\n\t\t"
+   {:type :element,
+    :attrs nil,
+    :tag :div,
+    :content
+    ["\r\n\t\t\t"
+     {:type :element,
+      :attrs
+      {:id "txtDescrProduct17",
+       :style "display:inline;",
+       :class "prodDesc"},
+      :tag :span,
+      :content ["Bookcase \r\n\t\t\t\t\r\n\t\t\t"]}
+     "\r\n\t\t\t\r\n\t\t"]}
+   "\r\n\t\t\r\n\t\t\t"
+   {:type :element,
+    :attrs
+    {:id "txtPriceProduct17",
+     :class "prodPrice",
+     :style "clear:both;"},
+    :tag :span,
+    :content ["\r\n\t\t\t\t$138\t\t\t\t\r\n\t\t\t"]}
+   "\r\n\t\t\t\t\r\n\t\t"
+   {:type :element,
+    :attrs {:id "comparisonContainer", :style "display: none"},
+    :tag :div,
+    :content
+    ["\r\n\t\t\t"
+     {:type :element,
+      :attrs nil,
+      :tag :span,
+      :content ["\r\n\t\t\t\tUnit price\r\n\t\t\t"]}
+     "\r\n\t\t\t"
+     {:type :element,
+      :attrs {:class "packagepricevaluebold", :id "comparisonPrice"},
+      :tag :span,
+      :content nil}
+     "\r\n\t\t"]}
+   "\r\n\t\t \r\n\t\t"]}
+ {:type :element,
+  :attrs
+  {:href "/au/en/catalog/products/S19020550/",
+   :onclick "irwStatTopProductClicked();"},
+  :tag :a,
+  :content
+  ["\r\n\t\t\t\r\n\t\t"
+   {:type :element,
+    :attrs
+    {:id "imgThmbProduct18",
+     :src "/PIAimages/0255321_PE399434_S2.JPG",
+     :border "0",
+     :alt "BILLY Bookcase Width: 160 cm Depth: 28 cm Height: 202 cm",
+     :class "prodImg"},
+    :tag :img,
+    :content nil}
+   "\r\n\t\t\r\n\t\t\r\n\t\t"
+   {:type :element,
+    :attrs {:id "txtNameProduct18", :class "prodName prodNameTro"},
+    :tag :span,
+    :content ["BILLY"]}
+   "\r\n\t\t"
+   {:type :element,
+    :attrs nil,
+    :tag :div,
+    :content
+    ["\r\n\t\t\t"
+     {:type :element,
+      :attrs
+      {:id "txtDescrProduct18",
+       :style "display:inline;",
+       :class "prodDesc"},
+      :tag :span,
+      :content ["Bookcase \r\n\t\t\t\t\r\n\t\t\t"]}
+     "\r\n\t\t\t\r\n\t\t"]}
+   "\r\n\t\t\r\n\t\t\t"
+   {:type :element,
+    :attrs
+    {:id "txtPriceProduct18",
+     :class "prodPrice",
+     :style "clear:both;"},
+    :tag :span,
+    :content ["\r\n\t\t\t\t$190\t\t\t\t\r\n\t\t\t"]}
+   "\r\n\t\t\t\t\r\n\t\t"
+   {:type :element,
+    :attrs {:id "comparisonContainer", :style "display: none"},
+    :tag :div,
+    :content
+    ["\r\n\t\t\t"
+     {:type :element,
+      :attrs nil,
+      :tag :span,
+      :content ["\r\n\t\t\t\tUnit price\r\n\t\t\t"]}
+     "\r\n\t\t\t"
+     {:type :element,
+      :attrs {:class "packagepricevaluebold", :id "comparisonPrice"},
+      :tag :span,
+      :content nil}
+     "\r\n\t\t"]}
+   "\r\n\t\t \r\n\t\t"]}
+ {:type :element,
+  :attrs
+  {:href "/au/en/catalog/products/S79023414/",
+   :onclick "irwStatTopProductClicked();"},
+  :tag :a,
+  :content
+  ["\r\n\t\t\t\r\n\t\t"
+   {:type :element,
+    :attrs
+    {:id "imgThmbProduct19",
+     :src "/PIAimages/0255409_PE399478_S2.JPG",
+     :border "0",
+     :alt "BILLY Bookcase Width: 160 cm Depth: 28 cm Height: 202 cm",
+     :class "prodImg"},
+    :tag :img,
+    :content nil}
+   "\r\n\t\t\r\n\t\t\r\n\t\t"
+   {:type :element,
+    :attrs {:id "txtNameProduct19", :class "prodName prodNameTro"},
+    :tag :span,
+    :content ["BILLY"]}
+   "\r\n\t\t"
+   {:type :element,
+    :attrs nil,
+    :tag :div,
+    :content
+    ["\r\n\t\t\t"
+     {:type :element,
+      :attrs
+      {:id "txtDescrProduct19",
+       :style "display:inline;",
+       :class "prodDesc"},
+      :tag :span,
+      :content ["Bookcase \r\n\t\t\t\t\r\n\t\t\t"]}
+     "\r\n\t\t\t\r\n\t\t"]}
+   "\r\n\t\t\r\n\t\t\t"
+   {:type :element,
+    :attrs
+    {:id "txtPriceProduct19",
+     :class "prodPrice",
+     :style "clear:both;"},
+    :tag :span,
+    :content ["\r\n\t\t\t\t$190\t\t\t\t\r\n\t\t\t"]}
+   "\r\n\t\t\t\t\r\n\t\t"
+   {:type :element,
+    :attrs {:id "comparisonContainer", :style "display: none"},
+    :tag :div,
+    :content
+    ["\r\n\t\t\t"
+     {:type :element,
+      :attrs nil,
+      :tag :span,
+      :content ["\r\n\t\t\t\tUnit price\r\n\t\t\t"]}
+     "\r\n\t\t\t"
+     {:type :element,
+      :attrs {:class "packagepricevaluebold", :id "comparisonPrice"},
+      :tag :span,
+      :content nil}
+     "\r\n\t\t"]}
+   "\r\n\t\t \r\n\t\t"]}
+ {:type :element,
+  :attrs
+  {:href "/au/en/catalog/products/S79020496/",
+   :onclick "irwStatTopProductClicked();"},
+  :tag :a,
+  :content
+  ["\r\n\t\t\t\r\n\t\t"
+   {:type :element,
+    :attrs
+    {:id "imgThmbProduct20",
+     :src "/PIAimages/0255304_PE399419_S2.JPG",
+     :border "0",
+     :alt
+     "BILLY Bookcase Depth: 28 cm Width right: 215 cm Width left: 135 cm",
+     :class "prodImg"},
+    :tag :img,
+    :content nil}
+   "\r\n\t\t\r\n\t\t\r\n\t\t"
+   {:type :element,
+    :attrs {:id "txtNameProduct20", :class "prodName prodNameTro"},
+    :tag :span,
+    :content ["BILLY"]}
+   "\r\n\t\t"
+   {:type :element,
+    :attrs nil,
+    :tag :div,
+    :content
+    ["\r\n\t\t\t"
+     {:type :element,
+      :attrs
+      {:id "txtDescrProduct20",
+       :style "display:inline;",
+       :class "prodDesc"},
+      :tag :span,
+      :content ["Bookcase \r\n\t\t\t\t\r\n\t\t\t"]}
+     "\r\n\t\t\t\r\n\t\t"]}
+   "\r\n\t\t\r\n\t\t\t"
+   {:type :element,
+    :attrs
+    {:id "txtPriceProduct20",
+     :class "prodPrice",
+     :style "clear:both;"},
+    :tag :span,
+    :content ["\r\n\t\t\t\t$386\t\t\t\t\r\n\t\t\t"]}
+   "\r\n\t\t\t\t\r\n\t\t"
+   {:type :element,
+    :attrs {:id "comparisonContainer", :style "display: none"},
+    :tag :div,
+    :content
+    ["\r\n\t\t\t"
+     {:type :element,
+      :attrs nil,
+      :tag :span,
+      :content ["\r\n\t\t\t\tUnit price\r\n\t\t\t"]}
+     "\r\n\t\t\t"
+     {:type :element,
+      :attrs {:class "packagepricevaluebold", :id "comparisonPrice"},
+      :tag :span,
+      :content nil}
+     "\r\n\t\t"]}
+   "\r\n\t\t \r\n\t\t"]}
+ {:type :element,
+  :attrs
+  {:href "/au/en/catalog/products/S19020545/",
+   :onclick "irwStatTopProductClicked();"},
+  :tag :a,
+  :content
+  ["\r\n\t\t\t\r\n\t\t"
+   {:type :element,
+    :attrs
+    {:id "imgThmbProduct21",
+     :src "/PIAimages/0255343_PE399441_S2.JPG",
+     :border "0",
+     :alt
+     "BILLY Bookcase Depth: 28 cm Width right: 215 cm Width left: 135 cm",
+     :class "prodImg"},
+    :tag :img,
+    :content nil}
+   "\r\n\t\t\r\n\t\t\r\n\t\t"
+   {:type :element,
+    :attrs {:id "txtNameProduct21", :class "prodName prodNameTro"},
+    :tag :span,
+    :content ["BILLY"]}
+   "\r\n\t\t"
+   {:type :element,
+    :attrs nil,
+    :tag :div,
+    :content
+    ["\r\n\t\t\t"
+     {:type :element,
+      :attrs
+      {:id "txtDescrProduct21",
+       :style "display:inline;",
+       :class "prodDesc"},
+      :tag :span,
+      :content ["Bookcase \r\n\t\t\t\t\r\n\t\t\t"]}
+     "\r\n\t\t\t\r\n\t\t"]}
+   "\r\n\t\t\r\n\t\t\t"
+   {:type :element,
+    :attrs
+    {:id "txtPriceProduct21",
+     :class "prodPrice",
+     :style "clear:both;"},
+    :tag :span,
+    :content ["\r\n\t\t\t\t$509\t\t\t\t\r\n\t\t\t"]}
+   "\r\n\t\t\t\t\r\n\t\t"
+   {:type :element,
+    :attrs {:id "comparisonContainer", :style "display: none"},
+    :tag :div,
+    :content
+    ["\r\n\t\t\t"
+     {:type :element,
+      :attrs nil,
+      :tag :span,
+      :content ["\r\n\t\t\t\tUnit price\r\n\t\t\t"]}
+     "\r\n\t\t\t"
+     {:type :element,
+      :attrs {:class "packagepricevaluebold", :id "comparisonPrice"},
+      :tag :span,
+      :content nil}
+     "\r\n\t\t"]}
+   "\r\n\t\t \r\n\t\t"]}
+ {:type :element,
+  :attrs
+  {:href "/au/en/catalog/products/S59023410/",
+   :onclick "irwStatTopProductClicked();"},
+  :tag :a,
+  :content
+  ["\r\n\t\t\t\r\n\t\t"
+   {:type :element,
+    :attrs
+    {:id "imgThmbProduct22",
+     :src "/PIAimages/0255416_PE399485_S2.JPG",
+     :border "0",
+     :alt
+     "BILLY Bookcase Depth: 28 cm Width right: 215 cm Width left: 135 cm",
+     :class "prodImg"},
+    :tag :img,
+    :content nil}
+   "\r\n\t\t\r\n\t\t\r\n\t\t"
+   {:type :element,
+    :attrs {:id "txtNameProduct22", :class "prodName prodNameTro"},
+    :tag :span,
+    :content ["BILLY"]}
+   "\r\n\t\t"
+   {:type :element,
+    :attrs nil,
+    :tag :div,
+    :content
+    ["\r\n\t\t\t"
+     {:type :element,
+      :attrs
+      {:id "txtDescrProduct22",
+       :style "display:inline;",
+       :class "prodDesc"},
+      :tag :span,
+      :content ["Bookcase \r\n\t\t\t\t\r\n\t\t\t"]}
+     "\r\n\t\t\t\r\n\t\t"]}
+   "\r\n\t\t\r\n\t\t\t"
+   {:type :element,
+    :attrs
+    {:id "txtPriceProduct22",
+     :class "prodPrice",
+     :style "clear:both;"},
+    :tag :span,
+    :content ["\r\n\t\t\t\t$509\t\t\t\t\r\n\t\t\t"]}
+   "\r\n\t\t\t\t\r\n\t\t"
+   {:type :element,
+    :attrs {:id "comparisonContainer", :style "display: none"},
+    :tag :div,
+    :content
+    ["\r\n\t\t\t"
+     {:type :element,
+      :attrs nil,
+      :tag :span,
+      :content ["\r\n\t\t\t\tUnit price\r\n\t\t\t"]}
+     "\r\n\t\t\t"
+     {:type :element,
+      :attrs {:class "packagepricevaluebold", :id "comparisonPrice"},
+      :tag :span,
+      :content nil}
+     "\r\n\t\t"]}
+   "\r\n\t\t \r\n\t\t"]}
+ {:type :element,
+  :attrs
+  {:href "/au/en/catalog/products/10279817/",
+   :onclick "irwStatTopProductClicked();"},
+  :tag :a,
+  :content
+  ["\r\n\t\t\t\r\n\t\t"
+   {:type :element,
+    :attrs
+    {:id "imgThmbProduct23",
+     :src "/PIAimages/0252372_PE391182_S2.JPG",
+     :border "0",
+     :alt
+     "BILLY Height extension unit Width: 40 cm Depth: 28 cm Height: 35 cm",
+     :class "prodImg"},
+    :tag :img,
+    :content nil}
+   "\r\n\t\t\r\n\t\t\r\n\t\t"
+   {:type :element,
+    :attrs {:id "txtNameProduct23", :class "prodName prodNameTro"},
+    :tag :span,
+    :content ["BILLY"]}
+   "\r\n\t\t"
+   {:type :element,
+    :attrs nil,
+    :tag :div,
+    :content
+    ["\r\n\t\t\t"
+     {:type :element,
+      :attrs
+      {:id "txtDescrProduct23",
+       :style "display:inline;",
+       :class "prodDesc"},
+      :tag :span,
+      :content ["Height extension unit \r\n\t\t\t\t\r\n\t\t\t"]}
+     "\r\n\t\t\t\r\n\t\t"]}
+   "\r\n\t\t\r\n\t\t\t"
+   {:type :element,
+    :attrs
+    {:id "txtPriceProduct23",
+     :class "prodPrice",
+     :style "clear:both;"},
+    :tag :span,
+    :content ["\r\n\t\t\t\t$25\t\t\t\t\r\n\t\t\t"]}
+   "\r\n\t\t\t\t\r\n\t\t"
+   {:type :element,
+    :attrs {:id "comparisonContainer", :style "display: none"},
+    :tag :div,
+    :content
+    ["\r\n\t\t\t"
+     {:type :element,
+      :attrs nil,
+      :tag :span,
+      :content ["\r\n\t\t\t\tUnit price\r\n\t\t\t"]}
+     "\r\n\t\t\t"
+     {:type :element,
+      :attrs {:class "packagepricevaluebold", :id "comparisonPrice"},
+      :tag :span,
+      :content nil}
+     "\r\n\t\t"]}
+   "\r\n\t\t \r\n\t\t"]}
+ {:type :element,
+  :attrs
+  {:href "/au/en/catalog/products/70263861/",
+   :onclick "irwStatTopProductClicked();"},
+  :tag :a,
+  :content
+  ["\r\n\t\t\t\r\n\t\t"
+   {:type :element,
+    :attrs
+    {:id "imgThmbProduct24",
+     :src "/PIAimages/0252373_PE391184_S2.JPG",
+     :border "0",
+     :alt
+     "BILLY Height extension unit Width: 40 cm Depth: 28 cm Height: 35 cm",
+     :class "prodImg"},
+    :tag :img,
+    :content nil}
+   "\r\n\t\t\r\n\t\t\r\n\t\t"
+   {:type :element,
+    :attrs {:id "txtNameProduct24", :class "prodName prodNameTro"},
+    :tag :span,
+    :content ["BILLY"]}
+   "\r\n\t\t"
+   {:type :element,
+    :attrs nil,
+    :tag :div,
+    :content
+    ["\r\n\t\t\t"
+     {:type :element,
+      :attrs
+      {:id "txtDescrProduct24",
+       :style "display:inline;",
+       :class "prodDesc"},
+      :tag :span,
+      :content ["Height extension unit \r\n\t\t\t\t\r\n\t\t\t"]}
+     "\r\n\t\t\t\r\n\t\t"]}
+   "\r\n\t\t\r\n\t\t\t"
+   {:type :element,
+    :attrs
+    {:id "txtPriceProduct24",
+     :class "prodPrice",
+     :style "clear:both;"},
+    :tag :span,
+    :content ["\r\n\t\t\t\t$25\t\t\t\t\r\n\t\t\t"]}
+   "\r\n\t\t\t\t\r\n\t\t"
+   {:type :element,
+    :attrs {:id "comparisonContainer", :style "display: none"},
+    :tag :div,
+    :content
+    ["\r\n\t\t\t"
+     {:type :element,
+      :attrs nil,
+      :tag :span,
+      :content ["\r\n\t\t\t\tUnit price\r\n\t\t\t"]}
+     "\r\n\t\t\t"
+     {:type :element,
+      :attrs {:class "packagepricevaluebold", :id "comparisonPrice"},
+      :tag :span,
+      :content nil}
+     "\r\n\t\t"]}
+   "\r\n\t\t \r\n\t\t"]}
+ {:type :element,
+  :attrs
+  {:href "/au/en/catalog/products/10263859/",
+   :onclick "irwStatTopProductClicked();"},
+  :tag :a,
+  :content
+  ["\r\n\t\t\t\r\n\t\t"
+   {:type :element,
+    :attrs
+    {:id "imgThmbProduct25",
+     :src "/PIAimages/0306654_PE427146_S2.JPG",
+     :border "0",
+     :alt
+     "BILLY Height extension unit Width: 40 cm Depth: 28 cm Height: 35 cm",
+     :class "prodImg"},
+    :tag :img,
+    :content nil}
+   "\r\n\t\t\r\n\t\t\r\n\t\t"
+   {:type :element,
+    :attrs {:id "txtNameProduct25", :class "prodName prodNameTro"},
+    :tag :span,
+    :content ["BILLY"]}
+   "\r\n\t\t"
+   {:type :element,
+    :attrs nil,
+    :tag :div,
+    :content
+    ["\r\n\t\t\t"
+     {:type :element,
+      :attrs
+      {:id "txtDescrProduct25",
+       :style "display:inline;",
+       :class "prodDesc"},
+      :tag :span,
+      :content ["Height extension unit \r\n\t\t\t\t\r\n\t\t\t"]}
+     "\r\n\t\t\t\r\n\t\t"]}
+   "\r\n\t\t\r\n\t\t\t"
+   {:type :element,
+    :attrs
+    {:id "txtPriceProduct25",
+     :class "prodPrice",
+     :style "clear:both;"},
+    :tag :span,
+    :content ["\r\n\t\t\t\t$20\t\t\t\t\r\n\t\t\t"]}
+   "\r\n\t\t\t\t\r\n\t\t"
+   {:type :element,
+    :attrs {:id "comparisonContainer", :style "display: none"},
+    :tag :div,
+    :content
+    ["\r\n\t\t\t"
+     {:type :element,
+      :attrs nil,
+      :tag :span,
+      :content ["\r\n\t\t\t\tUnit price\r\n\t\t\t"]}
+     "\r\n\t\t\t"
+     {:type :element,
+      :attrs {:class "packagepricevaluebold", :id "comparisonPrice"},
+      :tag :span,
+      :content nil}
+     "\r\n\t\t"]}
+   "\r\n\t\t \r\n\t\t"]}])


Add merit functionality.

Add merit functionality.

--- src/clj/made_merits/routes/home.clj
+++ src/clj/made_merits/routes/home.clj
@@ -12,10 +12,11 @@
 (defn merits-page []
   (layout/render "merits.html" {:users (db/get-users) :merits (db/get-merits)}))

-(defn add-merits [id reason]
-  (layout/render "merits.html" {:users (db/get-users)}))
+(defn add-merits [merit_id user_id]
+  (db/add-merit-to-user {:merit_id merit_id :user_id user_id })
+  (layout/render "merits.html" {:users (db/get-users) :merits (db/get-merits)}))

 (defroutes home-routes
   (GET "/" [] (home-page))
   (GET "/merits" [] (merits-page))
-  (POST "/merits" [id reason] (add-merits id reason)))
+  (POST "/merits" [merit_id user_id] (add-merits merit_id user_id)))


Fix typo in https.clj.

Fix typo in https.clj.

--- src/clj/org/openforis/ceo/https.clj
+++ src/clj/org/openforis/ceo/https.clj
@@ -67,6 +67,6 @@
       "package-cert" (package-certificate domain (or certbot-dir "/etc/letsencrypt"))
       (println "Valid options are:"
                "\n  certbot-init domain [certbot-dir]    to initialize certbot"
-               "\n  package-cert domian [certbot-dir]    to repackage certificates after an update"))
+               "\n  package-cert domain [certbot-dir]    to repackage certificates after an update"))
     (println "You must provide a domain to create an SSL key."))
   (shutdown-agents))


fix not updating a component when rum/static is enabled, switches back to .forceUpdate, resolves #221

--- src/rum/core.cljs
+++ src/rum/core.cljs
@@ -210,7 +210,7 @@
     (build-ctor render mixins display-name)))

 (defn request-render [comp]
-  (.setState comp (.-state comp)))
+  (.forceUpdate comp))

 (defn mount
   "Add element to the DOM tree. Idempotent. Subsequent mounts will just update element."
@@ -333,7 +333,7 @@
         (add-watch local-state key
                    (fn [_ _ p n]
                      (when (not= p n)
-                       (.setState component (.-state component)))))
+                       (.forceUpdate component))))
         (assoc state key local-state)))}))

@@ -374,7 +374,7 @@
                (add-watch ref key
                           (fn [_ _ p n]
                             (when (not= p n)
-                              (.setState comp (.-state comp)))))))
+                              (.forceUpdate comp))))))
            [dom (assoc next-state :rum.reactive/refs new-reactions)]))))
    :will-unmount
    (fn [state]


work on new listing format

work on new listing format


saving comment

saving comment

--- dev-resources/tools/repl/brepl/connect.cljs
+++ dev-resources/tools/repl/brepl/connect.cljs
@@ -4,4 +4,4 @@
 (ns brepl.connect
   (:require [clojure.browser.repl]))

-;;(repl/connect "http://localhost:9000/repl")
+;;(repl/connect "http://localhost:9000/repl")


little fixes

little fixes

--- test/com/billpiel/mem_tracer/core_test.clj
+++ test/com/billpiel/mem_tracer/core_test.clj
@@ -147,11 +147,11 @@
               (mt/add-trace-ns! 'com.billpiel.mem-tracer.test.ns1)

               (fact "remove-all-traces! works"
-                    (mt/remove-all-traces)
+                    (mt/remove-all-traces!)
                     (com.billpiel.mem-tracer.test.ns1/func1 :a)

                     (mt/deref-workspace!)
-                    => {:children [] :depth 0 :id "root10" :traced []})
+                    => {:children [] :depth 0 :id "root10" :traced #{}})

               (mtt/untrace-ns* 'com.billpiel.mem-tracer.test.ns1)))


parseInt user_id

parseInt user_id

--- src/word_keeper/frontend.clj
+++ src/word_keeper/frontend.clj
@@ -20,14 +20,16 @@

 (defn action-signin [req]
   (let [user-data (authorize (-> req :session :request-token)
-                                                 (-> req :params :oauth_verifier))]
+                             (-> req :params :oauth_verifier))
+        user_id (:user_id user-data)
+        screen_name (:screen_name user-data)]
     (if (contains? user-data :user_id)
       (do
-        (if (nil? (find-twitter-user (:user_id user-data)))
-          (create-twitter-user! (:user_id user-data) (:screen_name user-data)))
+        (if (nil? (find-twitter-user (Integer/parseInt user_id)))
+          (create-twitter-user! (Integer/parseInt user_id)  screen_name))
         {:status 200
          :headers {"Content-Type" "text/plain"}
-         :body (str "Signed in as " (:screen_name user-data))})
+         :body (str "Signed in as " screen_name)})
       {:status 200
        :headers {"Content-Type" "text/plain"}
        :body ("Something went wrong")})))


Switch to peers in set coll. Observer has changed.

--- test/onyx/log/accept_join_cluster_test.clj
+++ test/onyx/log/accept_join_cluster_test.clj
@@ -1,6 +1,7 @@
 (ns onyx.log.accept-join-cluster-test
   (:require [onyx.extensions :as extensions]
             [onyx.log.entry :refer [create-log-entry]]
+            [clojure.set :as s]
             [onyx.system]
             [midje.sweet :refer :all]))

@@ -18,7 +19,7 @@

 (def old-replica {:pairs {:a :b :b :c :c :a}
                   :accepted {:a :d}
-                  :peers [:a :b :c]
+                  :peers #{:a :b :c}
                   :job-scheduler :onyx.job-scheduler/greedy})

 (let [new-replica (f old-replica)
@@ -26,7 +27,9 @@
   (fact (get-in new-replica [:pairs :a]) => :d)
   (fact (get-in new-replica [:pairs :d]) => :b)
   (fact (get-in new-replica [:accepted]) => {})
-  (fact (last (get-in new-replica [:peers])) => :d)
+  (fact (s/difference (get-in new-replica [:peers])
+                      (:peers old-replica))
+        => #{:d})
   (fact diff => {:observer :a :subject :d})
   (fact (rep-reactions old-replica new-replica diff {}) => nil))

@@ -36,7 +39,7 @@

 (def rep-reactions (partial extensions/reactions entry))

-(def old-replica {:pairs {} :accepted {:a :d} :peers [:a]
+(def old-replica {:pairs {} :accepted {:a :d} :peers #{:a}
                   :job-scheduler :onyx.job-scheduler/greedy})

 (let [new-replica (f old-replica)
@@ -44,7 +47,9 @@
   (fact (get-in new-replica [:pairs :d]) => :a)
   (fact (get-in new-replica [:pairs :a]) => :d)
   (fact (get-in new-replica [:accepted]) => {})
-  (fact (last (get-in new-replica [:peers])) => :d)
+  (fact (s/difference (get-in new-replica [:peers])
+                      (:peers old-replica))
+        => #{:d})
   (fact diff => {:observer :a :subject :d})
   (fact (rep-reactions old-replica new-replica diff {}) => nil))


Do not start up full peer. Implement all message types.

--- test/onyx/messaging/messaging_gen_test.clj
+++ test/onyx/messaging/messaging_gen_test.clj
@@ -53,67 +53,100 @@
           (throw e))))))

-(defn test-send-commands [env peer-group commands]
+(defn test-send-commands [peer-group commands]
   (let [received (atom {})]
     (with-redefs [netty/create-server-handler (create-server-handler-mock received)]
-      (let [peers (onyx.api/start-peers 2 peer-group)]
+
+      (let [server-port 53001
+            recv-messenger (component/start (netty-tcp-sockets peer-group))
+            send-messenger (component/start (netty-tcp-sockets peer-group))]
+
         (try
-          (let [server-port 53001
-                _ (while (and (nil? @(:started-peer (first peers)))
-                              (nil? @(:started-peer (second peers))))
-                    (println "Waiting for full startup"))
-                recv-peer @(:started-peer (first peers))
-                send-peer @(:started-peer (second peers))
-                recv-messenger (:messenger recv-peer)]
-            (let [_ (ext/open-peer-site recv-messenger {:onyx.messaging/bind-addr "127.0.0.1"
-                                                        :netty/port server-port})
-                  send-messenger (:messenger send-peer)
-                  send-link (ext/connect-to-peer send-messenger nil {:netty/external-addr "127.0.0.1"
-                                                                     :netty/port server-port})]
-              (reduce (fn [_ command]
-                        (case (:command command)
-                          :messages (ext/send-messages send-messenger nil send-link (:payload command))
-                          :complete (ext/internal-complete-message send-messenger nil (:payload command) send-link)
-                          :retry (ext/internal-retry-message send-messenger nil (:payload command) send-link)
-                          :acks (ext/internal-ack-messages send-messenger nil send-link (:payload command))))
-                      nil commands)
-              (Thread/sleep 3000)
-              @received))
+          (let [_ (ext/open-peer-site recv-messenger {:onyx.messaging/bind-addr "127.0.0.1"
+                                                      :netty/port server-port})
+                send-link (ext/connect-to-peer send-messenger nil {:netty/external-addr "127.0.0.1"
+                                                                   :netty/port server-port})]
+            (reduce (fn [_ command]
+                      (case (:command command)
+                        :messages (ext/send-messages send-messenger nil send-link (:payload command))
+                        :complete (ext/internal-complete-message send-messenger nil (:payload command) send-link)
+                        :retry (ext/internal-retry-message send-messenger nil (:payload command) send-link)
+                        :acks (ext/internal-ack-messages send-messenger nil send-link (:payload command))))
+                    nil commands)
+
+            (Thread/sleep 5000)
+            (ext/close-peer-connection send-messenger nil send-link)
+            @received)
           (finally
-            (doseq [peer peers]
-              (onyx.api/shutdown-peer peer))))))))
+            (component/stop recv-messenger)
+            (component/stop send-messenger)))))))
+
+(def gen-segment
+  (gen/hash-map :some-key gen/any-printable))
+
+(def uuid-gen
+  (gen/fmap (fn [_]
+              (java.util.UUID/randomUUID))
+            (gen/return nil)))
+
+(def gen-messages
+  (gen/hash-map :command
+                (gen/return :messages)
+                :payload
+                (gen/such-that not-empty
+                               (gen/vector
+                                 (gen/fmap
+                                   map->Leaf
+                                   (gen/hash-map
+                                     :id uuid-gen
+                                     :acker-id uuid-gen
+                                     :completion-id uuid-gen
+                                     :message gen-segment
+                                     :ack-val gen/int))))))
+
+(def gen-acks
+  (gen/hash-map :command
+                (gen/return :acks)
+                :payload
+                (gen/such-that not-empty
+                               (gen/vector
+                                 (gen/hash-map
+                                   :id uuid-gen
+                                   :completion-id uuid-gen
+                                   :ack-val gen/int)))))
+
+(def gen-completion
+  (gen/hash-map :command
+                (gen/return :complete)
+                :payload
+                uuid-gen))
+
+(def gen-retry
+  (gen/hash-map :command
+                (gen/return :retry)
+                :payload
+                uuid-gen))
+
+(def gen-command
+  (gen/one-of [gen-messages gen-acks gen-completion gen-retry]))
+
+#_(deftest messenger-gen-test
+  (let [peer-group (onyx.api/start-peer-group peer-config)]
+    (try
+      (checking "all generated messages are received"
+                (times 500)
+                [commands (gen/vector gen-command)]
+                (println "Commands " commands)
+                (let [grouped-model (group-by :command commands)
+                      model-results (zipmap (keys grouped-model)
+                                            (map (fn [v] (set (flatten (map :payload v))))
+                                                 (vals grouped-model)))]
+                  (is
+                    (= model-results
+                       (into {}
+                             (map (juxt key (comp set val))
+                                  (test-send-commands peer-group commands)))))))
+
+      (finally (onyx.api/shutdown-peer-group peer-group)))))

-(deftest start-on-messenger-test
-  (let [env (onyx.api/start-env env-config)
-        peer-group (onyx.api/start-peer-group peer-config)
-        commands [{:command :messages
-                   :payload [(map->Leaf {:id #uuid "010a1688-47ff-4055-8da5-1f02247351e1"
-                                         :acker-id #uuid "bf8fd5fc-30fd-424c-af6a-0b32568581a4"
-                                         :completion-id #uuid "7ad37c45-ce67-4fd4-8850-f3ec58ede0bf"
-                                         :message {}
-                                         :ack-val 729233382010058362})]}
-                  {:command :retry
-                   :payload #uuid "8665d0eb-7905-4a5f-8704-28f7e67d369c"}
-
-                  {:command :complete
-                   :payload #uuid "2982b77a-849e-4964-8020-a2cee50756e7"}
-
-                  {:command :acks
-                   :payload [{:id #uuid "e2ba38dd-b523-4e63-ba74-645fb91c231a"
-                             :completion-id #uuid "b57f7be1-f2f9-4d0f-aa02-939b3d48dc23"
-                             :ack-val 3323130347050513529}]}]
-        grouped-model (group-by :command commands)
-        model-results (zipmap (keys grouped-model)
-                              (map (fn [v] (sort (flatten (map :payload v))))
-                                   (vals grouped-model)))]
-    (try
-      (is
-        (= model-results
-           (into {}
-                 (map (juxt key (comp sort val))
-                      (test-send-commands env peer-group commands)))))
-      (finally (onyx.api/shutdown-peer-group peer-group)
-               (onyx.api/shutdown-env env)))))
-
-


Avoid dropping keyspace, as CQL problem is resolved now.

--- test/clojurewerkz/cassaforte/test_helper.clj
+++ test/clojurewerkz/cassaforte/test_helper.clj
@@ -8,10 +8,6 @@
 (defn initialize-cql
   [f]
   (cc/connect! "127.0.0.1")
-  (with-thrift-exception-handling
-    (cql/execute "DROP KEYSPACE CassaforteTest1"))
-  (with-thrift-exception-handling
-    (cql/execute "CREATE KEYSPACE CassaforteTest1 WITH strategy_class = 'SimpleStrategy' AND strategy_options:replication_factor = 1;"))
   (cql/set-keyspace! "CassaforteTest1")
   (f))


Update jruby_sinatra.clj

Update jruby_sinatra.clj

Fix typo

--- src/leiningen/new/jruby_sinatra.clj
+++ src/leiningen/new/jruby_sinatra.clj
@@ -18,7 +18,7 @@
     (main/info "Generating fresh 'lein new' jruby-sinatra project" (:sanitized data))
     (->files data
              ; Dotfiles
-             [".gitignote" (render "gitignore")]
+             [".gitignore" (render "gitignore")]
              [".ruby-version" (render "ruby-version" data)]
              [".ruby-gemset" (render "ruby-gemset" data)]
              [".pryrc" (render "ruby/pryrc")]
@@ -32,4 +32,4 @@
              ["app/application_controller.rb" (render "ruby/application_controller.rb")]
              ["app/init.rb" (render "ruby/init.rb")]
              ["config/warble.rb" (render "ruby/warble.rb")])
-    (main/info "All done! Croon away I say.")))+    (main/info "All done! Croon away I say.")))


more descriptive outout file in unified-mode

--- src/adzerk/boot_cljs.clj
+++ src/adzerk/boot_cljs.clj
@@ -12,7 +12,7 @@
   '[[org.clojure/clojurescript "0.0-2411"]])

 (def cljsc-output-filename
-  "df3ee125-976d-4f56-b7b5-6dc12c35fd18.js")
+  "cljsc-output-c4afbd925.js")

 (defn output-path-for [unified-mode f]
   (if-not unified-mode


CMR-2897 Documents ACL API route functions

--- access-control-app/src/cmr/access_control/api/routes.clj
+++ access-control-app/src/cmr/access_control/api/routes.clj
@@ -248,12 +248,14 @@
       api-response))

 (defn search-for-acls
+  "Returns a Ring response with ACL search results for the given params."
   [context headers params]
   (mt/extract-header-mime-type #{mt/json mt/any} headers "accept" true)
   (-> (acl-service/search-for-acls context params)
       cr/search-response))

 (defn get-permissions
+  "Returns a Ring response with the requested permission check results."
   [request-context params]
   (let [params (update-in params [:concept_id] util/seqify)]
     (validate-get-permission-params params)


Use multimethods, syncing before work, currently does NOT work

--- src/main/clojure/clj_print/core.clj
+++ src/main/clojure/clj_print/core.clj
@@ -112,6 +112,7 @@
       :request (HashPrintRequestAttributeSet. (into-array PrintRequestAttribute s))
       nil)))

+;; TODO: Validate attrs here?
 (defn- make-doc
   "Returns a javax.print.Doc object for the print data in this
    job map. SimpleDoc will throw an IllegalArgumentException if
@@ -159,39 +160,46 @@
 ;;  :attrs #{(Copies. 5) MediaTray/MAIN}
 ;;  :listener SimpleJobListener}

-(defprotocol ISpoolable
-  "This protocol defines a contract that states the
-   responsibilities of any implementation that wishes
-   to be considered 'spoolable,' which implies that it
-   can be queued for later processing such that it is
-   another process' resonsibility to handle the ISpoolable
-   and block until it has been processed. For an implementation
-   to be spoolable, it must be able to do the following:"
-  (submit [this]) ;; Submit the job
-  (add-listener [this listener])) ;; Attach an event listener that
+;; (defprotocol ISpoolable
+;;   "This protocol defines a contract that states the
+;;    responsibilities of any implementation that wishes
+;;    to be considered 'spoolable,' which implies that it
+;;    can be queued for later processing such that it is
+;;    another process' resonsibility to handle the ISpoolable
+;;    and block until it has been processed. For an implementation
+;;    to be spoolable, it must be able to do the following:"
+;;   (submit [this]) ;; Submit the job
+;;   (add-listener [this listener]))
+;; Attach an event listener that
                                   ;; returns a value when the process is complete

-(defrecord JobSpec [doc printer job attrs]
-  ISpoolable
-  (submit [this]
-    (cond
-     (:doc this) (let [{{obj :obj} :doc} this
-                       {:keys [^DocPrintJob job attrs]} this]
-                   (.. job (print @obj (make-set attrs :request))))
-     (:docs this) (let [{docs :docs ^PrintService printer :printer} this]
-                    (for [d docs]
-                      [(make-doc d) (.. printer createPrintJob)]))
-     :else nil))
-  (add-listener [this listener]
-    (if-let [{^DocPrintJob job :job} this]
+;; (defrecord JobSpec [doc printer job attrs]
+;;   ISpoolable
+;;   (submit [this]
+;;     (let [{{obj :obj} :doc} this
+;;           {:keys [^DocPrintJob job attrs]} this]
+;;       (.. job (print @obj (make-set attrs :request)))))
+;;   (add-listener [this listener]
+;;     (if-let [{^DocPrintJob job :job} this]
+;;       (do (doto job (.addPrintJobListener listener))
+;;           (assoc this :listener listener))
+;;       (throw IllegalStateException "No DocPrintJob keyed at :job."))))
+
+(defn submit [jobspec]
+  (let [{{obj :obj} :doc} jobspec
+        {:keys [^DocPrintJob job attrs]}jobspec]
+    (.. job (print @obj (make-set attrs :request)))))
+
+(defn add-listener [jobspec listener]
+    (if-let [{^DocPrintJob job :job} jobspec]
       (do (doto job (.addPrintJobListener listener))
-          (assoc this :listener listener))
-      (throw IllegalStateException "No DocPrintJob keyed at :job."))))
-
-(defn job-seq [job-map]
-  (let [{docs :docs ^PrintService printer :printer} job-map]
-    (for [d docs]
-      [(make-doc d) (.. printer createPrintJob)])))
+          (assoc jobspec :listener listener))
+      (throw IllegalStateException "No DocPrintJob keyed at :job.")))
+
+;; (defn job-seq [job-map]
+;;   (let [{docs :docs ^PrintService printer :printer} job-map]
+;;     (for [d docs]
+;;       [(make-doc d) (.. printer createPrintJob)])))

 ;; TODO: SEE http://oobaloo.co.uk/clojure-from-callbacks-to-sequences!!!
 ;;
@@ -209,42 +217,88 @@
 ;;             job (.. printer createPrintJob)]
 ;;         (submit spec)))))

-;; TODO: Need to be able to ensure that the PrintService does not
-;; process incoming jobs until it has finished processing the MultiDoc
-;; (all calls to print on DocPrintJob objects dispensed by it should
-;; block until the the current job signals completion/no more events).
-
-(defn make-job
-  "Returns a JobSpec map that is the result of
-   assoc'ing required values to it. The values are:
-
-   1. A SimpleDoc object (wrapped in a Delay) made from
-   the map keyed at :doc.
-   2. A DocPrintJob object that is retrieved from the
-   PrintService.
-
-   The following defaults are also assoc'd to the job-spec
-   if no values are supplied for them:
-
-   1. The default system printer.
-   2. An attribute set with the single attribute MediaTray/MAIN.
-   3. A basic PrintJobListener that prints any events that occur
-   on the DocPrintJob."
-  {:since "0.0.1"}
-  [spec]
-  (if (:doc spec)
-    (let [{{doc-attrs :attrs} :doc} spec
-          {:keys [doc ^PrintService printer attrs ^PrintJobtListener listener]
-           :or {printer (printer :default)
-                attrs #{MediaTray/MAIN}}} spec
-          maybe-listen #(if listener (add-listener % listener) %)]
-      (if (and (valid-attrs? doc-attrs :doc)
-               (valid-attrs? attrs :job))
-        (-> (map->JobSpec {:doc (assoc doc :obj (make-doc doc))
-                           :printer printer
-                           :attrs attrs
-                           :job (.. printer createPrintJob)})
-            maybe-listen)))))
+;; TODO: Make this polymorphic using multimethods to prevent having to
+;; create a record type (need to do some performance testing on this,
+;; but for now I think it would be better to develop generically and
+;; then adopt using records as needed
+(defmulti job
+  (fn [spec] (let [{:keys [doc docs]} spec]
+              (or doc docs))))
+
+(defmethod job :doc [spec]
+  (let [{{doc-attrs :attrs} :doc} spec
+        {:keys [doc ^PrintService printer attrs ^PrintJobtListener listener]
+         :or {printer (printer :default)
+              attrs #{MediaTray/MAIN}}} spec
+              maybe-listen #(if listener (add-listener % listener) %)]
+    (if (and (valid-attrs? doc-attrs :doc)
+             (valid-attrs? attrs :job))
+      (-> {:doc (assoc doc :obj (make-doc doc))
+           :printer printer
+           :attrs attrs
+           :job (.. printer createPrintJob)}
+          maybe-listen))))
+
+(defmethod job :docs [spec]
+  (let [{docs :docs} spec
+        {:keys [doc ^PrintService printer attrs ^PrintJobtListener listener]
+         :or {printer (printer :default)
+              attrs #{MediaTray/MAIN}}} spec
+              maybe-listen #(if listener (add-listener % listener) %)]
+    (println "In :docs")
+    (if (and (every? #(valid-attrs? (:attrs %) :doc) docs)
+             (valid-attrs? attrs :job))
+      (-> {:docs (map #(assoc % :obj (make-doc %)) docs)
+           :printer printer
+           :attrs attrs
+           :job (.. printer createPrintJob)}
+          maybe-listen))))
+
+;; (defn make-job
+;;   "Returns a JobSpec map that is the result of
+;;    assoc'ing required values to it. The values are:
+
+;;    1. A SimpleDoc object (wrapped in a Delay) made from
+;;    the map keyed at :doc.
+;;    2. A DocPrintJob object that is retrieved from the
+;;    PrintService.
+
+;;    The following defaults are also assoc'd to the job-spec
+;;    if no values are supplied for them:
+
+;;    1. The default system printer.
+;;    2. An attribute set with the single attribute MediaTray/MAIN.
+;;    3. A basic PrintJobListener that prints any events that occur
+;;    on the DocPrintJob."
+;;   {:since "0.0.1"}
+;;   [spec]
+;;   (cond
+;;    (:doc spec) (let [{{doc-attrs :attrs} :doc} spec
+;;                      {:keys [doc ^PrintService printer attrs ^PrintJobtListener listener]
+;;                       :or {printer (printer :default)
+;;                            attrs #{MediaTray/MAIN}}} spec
+;;                            maybe-listen #(if listener (add-listener % listener) %)]
+;;                  (if (and (valid-attrs? doc-attrs :doc)
+;;                           (valid-attrs? attrs :job))
+;;                    (-> {:doc (assoc doc :obj (make-doc doc))
+;;                         :printer printer
+;;                         :attrs attrs
+;;                         :job (.. printer createPrintJob)}
+;;                        maybe-listen)))
+;;    (:docs spec) (let [{docs :docs} spec
+;;                      {:keys [doc ^PrintService printer attrs ^PrintJobtListener listener]
+;;                       :or {printer (printer :default)
+;;                            attrs #{MediaTray/MAIN}}} spec
+;;                            maybe-listen #(if listener (add-listener % listener) %)]
+;;                   (println "In :docs")
+;;                   (if (and (every? #(valid-attrs? (:attrs %) :doc) docs)
+;;                            (valid-attrs? attrs :job))
+;;                    (-> {:docs (map #(assoc % :obj (make-doc %)) docs)
+;;                         :printer printer
+;;                         :attrs attrs
+;;                         :job (.. printer createPrintJob)}
+;;                        maybe-listen)))
+;;    :else nil))

 (defn -main [& args]
   (if (seq args)


devcards.core -> dc

devcards.core -> dc

--- src/main/devcards_om_next/core.cljs
+++ src/main/devcards_om_next/core.cljs
@@ -99,11 +99,9 @@
 (defrecord OmNextDevcard [main-obj opts]
   dc/IDevcard
   (-devcard [this devcard-opts]
-    (let [card (devcards.core/add-environment-defaults
+    (let [card (dc/add-environment-defaults
                  (assoc devcard-opts
                         :main-obj main-obj
                         :options (merge opts
-                                        (devcards.core/assert-options-map (:options devcard-opts)))))
-         element (js/React.createElement OmNextNode
-                                         #js {"card" card})]
-      element)))
+                                        (dc/assert-options-map (:options devcard-opts)))))]
+      (js/React.createElement OmNextNode #js {"card" card}))))


Show available codecs when there is no match.

--- core/src/immutant/codecs.clj
+++ core/src/immutant/codecs.clj
@@ -130,7 +130,8 @@
     (if-let [codec (.forContentType codecs (name name-or-content-type))]
       codec
       (throw (IllegalArgumentException.
-               (str "Can't find codec for: " name-or-content-type))))))
+               (format "Can't find codec for: %s. Available codecs: %s"
+                 name-or-content-type (codec-set)))))))

 (defn encode
   "Encodes `data` using the codec for `encoding`.


Known -> know

Known -> know

--- src/aurora/language.cljs
+++ src/aurora/language.cljs
@@ -1,8 +1,6 @@
 (ns aurora.language
   (:require [aurora.btree :as btree])
   (:require-macros [aurora.macros :refer [apush set!!]]))
-
-;; TODO what do we do if `fields` is not the same set of fields as the fact?

 (defn keymap [from-fields to-fields]
   (let [keymap (make-array (alength to-fields))]
@@ -60,20 +58,20 @@

   (def kn (knowledge))

-  (.get-or-create-index kn "known" "heights" #js ["name" "height"])
+  (.get-or-create-index kn "know" "heights" #js ["name" "height"])

-  (.add-facts kn "known" "heights" #js ["name" "height"] #js [#js ["chris" "short"] #js ["rob" "spade hands"]])
+  (.add-facts kn "know" "heights" #js ["name" "height"] #js [#js ["chris" "short"] #js ["rob" "spade hands"]])

-  (.get-or-create-index kn "known" "heights" #js ["name" "height"])
+  (.get-or-create-index kn "know" "heights" #js ["name" "height"])

-  (.get-or-create-index kn "known" "heights" #js ["height" "name"])
+  (.get-or-create-index kn "know" "heights" #js ["height" "name"])

   (.-kind->name->fields->index kn)

-  (.add-facts kn "known" "heights" #js ["name" "height"] #js [#js ["jamie" "just right"]])
+  (.add-facts kn "know" "heights" #js ["name" "height"] #js [#js ["jamie" "just right"]])

-  (.get-or-create-index kn "known" "heights" #js ["name" "height"])
+  (.get-or-create-index kn "know" "heights" #js ["name" "height"])

-  (.get-or-create-index kn "known" "heights" #js ["height" "name"])
+  (.get-or-create-index kn "know" "heights" #js ["height" "name"])

   )


Store different facts in different sets

Store different facts in different sets

--- src/aurora/language.cljs
+++ src/aurora/language.cljs
@@ -259,9 +259,9 @@

 ;; FLOW PLAN

-(defrecord FlowPlan [node->flow flow->node])
-
-(defn flow-plan->flow-state [{:keys [node->flow]}]
+(defrecord FlowPlan [node->flow flow->node memory->shape->node kind->shape])
+
+(defn flow-plan->flow-state [{:keys [node->flow] :as plan}]
   (let [node->state (into-array (for [_ node->flow] nil))
         node->out-nodes (into-array (for [_ node->flow] #js []))
         node->facts (into-array (for [_ node->flow] #js []))
@@ -285,34 +285,51 @@
                 Lookup (lookup-update! (:index-node flow) (:key-ixes flow) (:val-ixes flow))))))
     (FlowState. node->state node->out-nodes node->facts node->update! trace plan)))

-(defn memory->node [memory]
-  (case memory
-    :known 0
-    :pretended 1
-    :remembered 2
-    :forgotten 3))
-
-(defn memory->nodes [memory]
-  (case memory
-    :known [0]
-    :pretended [1]
-    :remembered [2]
-    :forgotten [3]
-    :known&pretended [0 1]))
-
 (def empty-flow-plan
-  (FlowPlan. [(Union. #{}) (Union. #{}) (Union. #{}) (Union. #{})] {}))
-
-(defn add-output [flow-plan node memory]
-  (update-in flow-plan [:node->flow (memory->node memory) :nodes] conj node))
+  (FlowPlan. [] {} {} {}))
+
+(defn add-flow-without-memo [{:keys [node->flow flow->node] :as flow-plan} flow]
+  (let [node (count node->flow)
+        node->flow (conj node->flow flow)
+        flow->node (assoc flow->node flow node)]
+    [(assoc flow-plan :node->flow node->flow :flow->node flow->node) node]))

 (defn add-flow [{:keys [node->flow flow->node] :as flow-plan} flow]
-  (if-let [node (flow->node flow)]
+  (if-let [node (get flow->node flow)]
     [flow-plan node]
-    (let [node (count node->flow)
-          node->flow (conj node->flow flow)
-          flow->node (assoc flow->node flow node)]
-      [(FlowPlan. node->flow flow->node) node])))
+    (add-flow-without-memo flow-plan flow)))
+
+(defn memory! [memory]
+  (assert (#{:known|pretended :remembered :forgotten} memory) (pr-str memory)))
+
+(defn add-memory [{:keys [node->flow memory->shape->node] :as flow-plan} memory shape]
+  (memory! memory)
+  (let [[flow-plan node] (add-flow-without-memo flow-plan (Union. #{}))
+        memory->shape->node (assoc-in memory->shape->node [memory shape] node)]
+    (assoc flow-plan :memory->shape->node memory->shape->node)))
+
+(defn add-shape [flow-plan kind shape]
+  (case kind
+    :pretended (-> flow-plan
+                   (add-memory :known|pretended shape)
+                   (update-in [:kind->shape kind] #(conj (or % #{}) shape)))
+    :known (-> flow-plan
+               (add-memory :known|pretended shape)
+               (add-memory :remembered shape)
+               (add-memory :forgotten shape)
+               (update-in [:kind->shape kind] #(conj (or % #{}) shape)))))
+
+(defn get-memory [{:keys [memory->shape->node]} memory shape]
+  (memory! memory)
+  (or (get-in memory->shape->node [memory shape])
+      (assert false (str "No node for " (pr-str memory) " " (pr-str shape)))))
+
+(defn add-input [flow-plan output-node memory shape]
+  (update-in flow-plan [:node->flow output-node :nodes] conj (get-memory flow-plan memory shape)))
+
+(defn add-output [flow-plan input-node memory shape]
+  (update-in flow-plan [:node->flow (get-memory flow-plan memory shape) :nodes] conj input-node))
+

 ;; IXES

@@ -452,7 +469,7 @@

 ;; CLAUSES

-(defrecord Recall [memory pattern]) ;; memory is one of :known :pretended :remembered :forgotten :known&pretended
+(defrecord Recall [memory pattern]) ;; memory is one of :known|pretended :remembered :forgotten
 (defrecord Compute [pattern])
 (defrecord Output [memory pattern]) ;; memory is one of :pretended :remembered :forgotten

@@ -465,9 +482,9 @@
 (defn add-clause [plan nodes vars clause]
   (condp = (type clause)
     Recall (let [{:keys [memory pattern]} clause
-                 [plan node-a] (add-flow plan (FilterMap. (memory->nodes memory) (pattern->filter pattern)))
-                 [plan node-b] (add-flow plan (FilterMap. [node-a] (pattern->deconstructor pattern)))]
-             [plan [node-b] (pattern->vars pattern)])
+                 [plan node] (add-flow plan (FilterMap. #{} (pattern->deconstructor pattern)))
+                 plan (add-input plan node memory (.-shape pattern))]
+             [plan [node] (pattern->vars pattern)])
     Compute (let [{:keys [pattern]} clause]
               (condp = (.-shape pattern)
                 Let (when (every? (set vars) (:vars pattern))
@@ -482,7 +499,11 @@
     Output (let [{:keys [memory pattern]} clause
                  _ (assert (every? (set vars) (pattern->vars pattern)))
                  [plan output-node] (add-flow plan (FilterMap. nodes (pattern->constructor vars pattern)))
-                 plan (add-output plan output-node memory)]
+                 output-memory (case memory
+                                 :pretended :known|pretended
+                                 :remembered :remembered
+                                 :forgotten :forgotten)
+                 plan (add-output plan output-node output-memory (.-shape pattern))]
              [plan nodes vars])))

 (comment
@@ -588,76 +609,87 @@
   (deffact edge "[x] has an edge to [y]")
   (deffact connected "[x] is connected to [y]")

-  (let [plan (add-rules empty-flow-plan
-                        [(Rule. [(Recall. :known&pretended (->edge 'x 'y))
-                                 (Output. :pretended (->connected 'x 'y))])
-                         (Rule. [(Recall. :known&pretended (->edge 'x 'y))
-                                 (Recall. :known&pretended (->connected 'y 'z))
-                                 (Output. :pretended (->connected 'x 'z))])])
+  (let [plan (-> empty-flow-plan
+                 (add-shape :known edge)
+                 (add-shape :pretended connected)
+                 (add-rules [(Rule. [(Recall. :known|pretended (->edge 'x 'y))
+                                     (Output. :pretended (->connected 'x 'y))])
+                             (Rule. [(Recall. :known|pretended (->edge 'x 'y))
+                                     (Recall. :known|pretended (->connected 'y 'z))
+                                     (Output. :pretended (->connected 'x 'z))])]))
         state (flow-plan->flow-state plan)]
-    (apush* (aget (:node->facts state) 0) #js [(->edge 0 1) (->edge 1 2) (->edge 2 3) (->edge 3 1)])
+    (add-facts state :known|pretended edge #js [(->edge 0 1) (->edge 1 2) (->edge 2 3) (->edge 3 1)])
     (time (fixpoint! state))
-    (persistent! (aget (:node->state state) 1)))
-
-  (let [plan (add-rules empty-flow-plan
-                        [(Rule. [(Recall. :known&pretended (->edge 'x 'y))
-                                 (Output. :pretended (->connected 'x 'y))])
-                         (Rule. [(Recall. :known&pretended (->edge 'x 'y))
-                                 (Recall. :known&pretended (->connected 'y 'z))
-                                 (Output. :pretended (->connected 'x 'z))])])
+    (get-facts state :known|pretended connected))
+
+  (enable-console-print!)
+
+  (let [plan (-> empty-flow-plan
+                 (add-shape :known edge)
+                 (add-shape :pretended connected)
+                 (add-rules [(Rule. [(Recall. :known|pretended (->edge 'x 'y))
+                                     (Output. :pretended (->connected 'x 'y))])
+                             (Rule. [(Recall. :known|pretended (->edge 'x 'y))
+                                     (Recall. :known|pretended (->connected 'y 'z))
+                                     (Output. :pretended (->connected 'x 'z))])]))
         state (flow-plan->flow-state plan)]
-    (apush* (aget (:node->facts state) 0) (into-array (for [i (range 100)]
-                                                        (->edge i (inc i)))))
+    (add-facts state :known|pretended edge (into-array (for [i (range 100)] (->edge i (inc i)))))
     (js/console.time "new")
     (fixpoint! state)
     (js/console.timeEnd "new")
-    (persistent! (aget (:node->state state) 1)))
+    (get-facts state :known|pretended connected))
   ;; 5 => 1 ms
   ;; 10 => 8 ms
   ;; 50 => 1093 ms
   ;; 100 => 11492 ms

-  (let [plan (add-rules empty-flow-plan
-                        [(Rule. [(Recall. :known&pretended (->edge 'x 'y))
-                                 (Compute. (->Let 'z '[x y] "x + y"))
-                                 (Output. :pretended (->connected 'z 'z))])])
+  (let [plan (-> empty-flow-plan
+                 (add-shape :known edge)
+                 (add-shape :pretended connected)
+                 (add-rules [(Rule. [(Recall. :known|pretended (->edge 'x 'y))
+                                     (Compute. (->Let 'z '[x y] "x + y"))
+                                     (Output. :pretended (->connected 'z 'z))])]))
         state (flow-plan->flow-state plan)]
-    (apush* (aget (:node->facts state) 0) (into-array (for [i (range 100)]
-                                                        (->edge i (inc i)))))
+    (add-facts state :known|pretended edge (into-array (for [i (range 100)]
+                                                         (->edge i (inc i)))))
     (fixpoint! state)
-    (persistent! (aget (:node->state state) 1)))
+    (get-facts state :known|pretended connected))
   )

 ;; TIME AND CHANGE

-(defn add-facts [state memory facts]
-  (let [arr (aget (:node->facts state) (memory->node memory))]
+(defn add-facts [state memory shape facts]
+  (memory! memory)
+  (let [node (get-memory (:plan state) memory shape)
+        arr (aget (:node->facts state) node)]
     (doseq [fact facts]
       (apush arr fact))
     state))

-(defn get-facts [state memory]
-  (if-let [facts (aget (:node->state state) (memory->node memory))]
-    (let [facts (persistent! facts)]
-      (aset (:node->state state) (memory->node memory) (transient facts))
-      facts)
-    #{}))
+(defn get-facts [state memory shape]
+  (memory! memory)
+  (let [node (get-memory (:plan state) memory shape)
+        facts (persistent! (aget (:node->state state) node))]
+    (aset (:node->state state) node (transient facts))
+    facts))

 ;; TODO make this incremental
+;; TODO wasteful to do the persistent/transient dance when there are no remembered/forgotten facts
 (defn tick
   ([plan] (tick plan (flow-plan->flow-state plan)))
   ([plan state]
-   (let [known (transient (get-facts state :known))
-         remembered (get-facts state :remembered)
-         forgotten (get-facts state :forgotten)
-         new-state (flow-plan->flow-state plan)]
-     (doseq [fact remembered]
-       (when (not (contains? forgotten fact))
-         (conj!! known fact)))
-     (doseq [fact forgotten]
-       (when (not (contains? remembered fact))
-         (disj!! known fact)))
-     (add-facts new-state :known (persistent! known))
+   (let [new-state (flow-plan->flow-state plan)]
+     (doseq [shape (get-in plan [:kind->shape :known])]
+       (let [known (transient (get-facts state :known|pretended shape))
+             remembered (get-facts state :remembered shape)
+             forgotten (get-facts state :forgotten shape)]
+         (doseq [fact remembered]
+           (when (not (contains? forgotten fact))
+             (conj!! known fact)))
+         (doseq [fact forgotten]
+           (when (not (contains? remembered fact))
+             (disj!! known fact)))
+         (add-facts new-state :known|pretended shape (persistent! known))))
      new-state)))

 (defn tick&fixpoint [plan state]
@@ -668,56 +700,25 @@

 (defn rules->plan [rules]
   (add-rules empty-flow-plan rules))
-

 (comment
   (deffact edge "[x] has an edge to [y]")
   (deffact connected "[x] is connected to [y]")

-  (let [plan (add-rules empty-flow-plan
-                        [(Rule. [(Recall. :known&pretended (->edge 'x 'y))
-                                 (Output. :remembered (->connected 'x 'y))])
-                         (Rule. [(Recall. :known&pretended (->edge 'x 'y))
-                                 (Recall. :known&pretended (->connected 'y 'z))
-                                 (Output. :remembered (->connected 'x 'z))])])
+  (let [plan (-> empty-flow-plan
+                 (add-shape :known edge)
+                 (add-shape :known connected)
+                 (add-rules
+                  [(Rule. [(Recall. :known|pretended (->edge 'x 'y))
+                           (Output. :remembered (->connected 'x 'y))])
+                   (Rule. [(Recall. :known|pretended (->edge 'x 'y))
+                           (Recall. :known|pretended (->connected 'y 'z))
+                           (Output. :remembered (->connected 'x 'z))])]))
         state-0 (flow-plan->flow-state plan)]
-    (add-facts state-0 :known #js [(->edge 0 1) (->edge 1 2) (->edge 2 3) (->edge 3 1)])
+    (add-facts state-0 :known|pretended edge #js [(->edge 0 1) (->edge 1 2) (->edge 2 3) (->edge 3 1)])
   (fixpoint! state-0)
   (for [state (take 5 (iterate #(tick&fixpoint plan %) state-0))]
-    (count (get-facts state :known))))
-
-  (let [rules [(Rule. [
-                       (aurora.language.Recall. :known&pretended, (js/aurora.language.fact :http/response #js ['content "google" 'some]))
-                       (aurora.language.Output. :remembered (js/aurora.language.fact "1df7454c_069e_40ab_b117_b8d43212b473" #js ['value74]))
-                       (aurora.language.Output. :forgotten (js/aurora.language.fact "1df7454c_069e_40ab_b117_b8d43212b473" #js ['value]))
-                       (aurora.language.Recall. :known&pretended, (js/aurora.language.fact "1df7454c_069e_40ab_b117_b8d43212b473" #js ['value]))
-                       (aurora.language.Compute. (->Let 'value74  #{'value} "value + \"hey\""))])]
-        plan (add-rules empty-flow-plan rules)
-        state (flow-plan->flow-state plan)]
-    (add-facts state :known [(fact. "1df7454c_069e_40ab_b117_b8d43212b473" #js ["Click me"])])
-    (add-facts state :pretended [(fact. :http/response #js ["yo" "google" 1234])])
-    (fixpoint! state)
-    (-> state
-        (get-facts :known)
-        first
-        (.-values))
-  )
-
-  (let [rules [(Rule. [
-                       (aurora.language.Recall. :known&pretended, (js/aurora.language.fact :http/response #js ['content "google" 'tim]))
-                       (aurora.language.Output. :remembered (js/aurora.language.fact "1df7454c_069e_40ab_b117_b8d43212b473" #js ['value74]))
-                       (aurora.language.Output. :forgotten (js/aurora.language.fact "1df7454c_069e_40ab_b117_b8d43212b473" #js ['value]))
-                       (aurora.language.Recall. :known&pretended, (js/aurora.language.fact "1df7454c_069e_40ab_b117_b8d43212b473" #js ['value]))
-                       (aurora.language.Compute. (->Let 'value74  #{'value 'content} "value + \" hey \" + content"))])]
-        plan (add-rules empty-flow-plan rules)
-        state (flow-plan->flow-state plan)]
-    (add-facts state :known [(fact. "1df7454c_069e_40ab_b117_b8d43212b473" #js ["Click me"])])
-    (add-facts state :pretended [(fact. :http/response #js ["yo" "google" 1234])])
-    (fixpoint! state)
-    (map #(.-values %)
-         (-> state
-             (get-facts :remembered)))
-    )
+    (count (get-facts state :known|pretended connected))))
   )

 ;; RESOLVE