delaney.clj: refactored (defmethod dsymbol String [code] ...)

--- clojure/org/gavrog/clojure/delaney.clj
+++ clojure/org/gavrog/clojure/delaney.clj
@@ -227,37 +227,36 @@

 (defmulti dsymbol class)

+(defn- parse-numbers [str]
+  (map #(Integer/parseInt %) (-> str s/trim (s/split #"\s+"))))
+
+(defn- parse-number-lists [str]
+  (map parse-numbers (-> str s/trim (s/split #","))))
+
+(defn- extract [data free]
+  (let [step (fn [[_ free] val]
+               [[(first free), val] (disj free (first free) val)])]
+    (rest (map first (reductions step [nil (into #{} free)] data)))))
+
 (defmethod dsymbol String [code]
-  (let [items (fn [str]
-                (map #(Integer/parseInt %) (-> str s/trim (s/split #"\s+"))))
-        extract (fn [a elms f]
-                  (let [step (fn [[acc todo] val]
-                               (let [D (first todo)]
-                                 [(conj acc [D, val])
-                                  (reduce disj todo (f D val))]))]
-                    (first (reduce step [[] (into #{} elms)] a))))
-        parts (-> code s/trim
+  (let [parts (-> code s/trim
                 (s/replace #"^<" "") (s/replace #">$" "") (s/split #":"))
         data (if (re-matches #"\d+.\d+" (first parts)) (rest parts) parts)
-        [size d] (items (first data))
+        [size d] (parse-numbers (first data))
         dim (or d 2)
-        gluings (map items (-> data (nth 1) s/trim (s/split #",")))
+        gluings (parse-number-lists (nth data 1))
+        spins (parse-number-lists (nth data 2))
         d-set (reduce (fn [sym i]
-                        (reduce #(glue %1 i (first %2) (second %2))
+                        (reduce (fn [ds [D E]] (glue ds i D E))
                                 sym
-                                (extract (nth gluings i)
-                                         (range 1 (inc size))
-                                         vector)))
+                                (extract (nth gluings i) (range 1 (inc size)))))
                       (DSymbol. 0 0 {} {})
                       (range 0 (inc dim)))
-        spins (map items (-> data (nth 2) s/trim (s/split #",")))
         d-sym (reduce (fn [sym i]
-                        (reduce #(spin %1 i (inc i) (first %2) (second %2))
+                        (reduce (fn [ds [D v]] (spin ds i (inc i) D v))
                                 sym
-                                (extract (nth spins i)
-                                         (elements d-set)
-                                         (fn [D m]
-                                           (orbit d-set [i (inc i)] D)))))
+                                (zipmap (orbit-reps d-set [i (inc i)])
+                                        (nth spins i))))
                       d-set
                       (range 0 dim))]
     d-sym))


refactor ingestion, de-quoting

refactor ingestion, de-quoting

--- src/markov/core.clj
+++ src/markov/core.clj
@@ -13,6 +13,22 @@
   (str/replace sentence #"\"" "")
   )

+(defn gen-ngram
+  ([sentence n]
+   (gen-ngram sentence n [])
+   )
+
+  ([sentence n acc]
+   (if-let [s (seq sentence)]
+      (recur (rest sentence) n (conj sentence (take n s)))
+      acc
+     )
+   ))
+
+(defn print-document [doc]
+      (doseq [sentence doc] (println sentence)))
+
+
 (defn get-corpus [corpus-name]
    (let [session (client/connect ["127.0.0.1"] {:keyspace "markov" :protocol-version 2})]
       (println "Get Corpus : Connected to 127.0.0.1 - " corpus-name)
@@ -23,8 +39,9 @@
   "I don't do a whole lot ... yet."
   [& args]
       (def results (get-corpus "treasure_island"))
+      (def document (map de-quote (map :sentence_text results)))
       (println (str "Result size : " (count results)))
- ;     (doseq [sentence results] (println  (de-quote (:sentence_text sentence))))
+;      (print-document document)
      )


Asteroid fragments are non-overlapping, also asteroids are faster.

--- Clojure/clojuroids.clj
+++ Clojure/clojuroids.clj
@@ -159,11 +159,16 @@
     (/ (apply + radii) (count radii)))

 (defn split-asteroid [asteroid]
-    (let [current-radius (average (:radii asteroid))]
+    (let [
+        current-radius (average (:radii asteroid))
+        a (rand (* Math/PI 2.0))
+        xo (* current-radius (Math/cos a) 0.5)
+        yo (* current-radius (Math/sin a) 0.5)
+        ]
         (filter (fn [ast] (>= (average (:radii ast)) smallest-asteroid))
             [
-                (generate-asteroid (:x asteroid) (:y asteroid) (* current-radius 0.6))
-                (generate-asteroid (:x asteroid) (:y asteroid) (* current-radius 0.4))
+                (generate-asteroid (+ (:x asteroid) xo) (+ (:y asteroid) yo) (* current-radius 0.6))
+                (generate-asteroid (- (:x asteroid) xo) (- (:y asteroid) yo) (* current-radius 0.4))
             ])))

 (defn filter-collisions [bullets asteroids]
@@ -187,8 +192,8 @@
         {
             :x x
             :y y
-            :xv (rand 10)
-            :yv (rand 10)
+            :xv (myrand -20 20)
+            :yv (myrand -20 20)
             :a 0.0
             :av (rand)
             :radii (take 10 (repeatedly #(myrand (* radius 0.5) (* radius 1.5))))


Shave 2 seconds off of launch time :racing_car:

--- src/metabase/db.clj
+++ src/metabase/db.clj
@@ -185,13 +185,17 @@
                (.rollback (jdbc/get-connection nested-transaction-connection))
                (log/error (u/format-color 'red "[ERROR] %s" (.getMessage e)))))))))

+(def ^{:arglists '([])} ^DatabaseFactory database-factory
+  "Return an instance of the Liquibase `DatabaseFactory`. This is done on a background thread at launch because otherwise it adds 2 seconds to startup time."
+  (partial deref (future (DatabaseFactory/getInstance))))
+
 (defn- conn->liquibase
   "Get a `Liquibase` object from JDBC CONN."
   (^Liquibase []
    (conn->liquibase (jdbc-details)))
   (^Liquibase [conn]
    (let [^JdbcConnection liquibase-conn (JdbcConnection. (jdbc/get-connection conn))
-         ^Database       database       (.findCorrectDatabaseImplementation (DatabaseFactory/getInstance) liquibase-conn)]
+         ^Database       database       (.findCorrectDatabaseImplementation (database-factory) liquibase-conn)]
      (Liquibase. changelog-file (ClassLoaderResourceAccessor.) database))))

 (defn migrate!


Catch domain and schedule changes

Catch domain and schedule changes

--- slackbot/src/org/teamweek/slackbot.clj
+++ slackbot/src/org/teamweek/slackbot.clj
@@ -1,5 +1,6 @@
 (ns org.teamweek.slackbot
   (:require [clojure.core.async :as async]
+            [clojure.string :as str]
             [datomic.api :as d]
             [aleph.http :as http]
             [manifold.stream :as stream]
@@ -243,25 +244,35 @@
                                         schedule))
         (do (log/info "Skipping scheduling for" domain))))))

-(defn schedule-new [schduler db-before db-after]
+(defn schedule-new [scheduler db-conn db-before db-after]
   (let [new-domains (d/q '[:find [?new-domains ...]
                            :in $db-before $db-after
                            :where
                            [$db-after ?team :team/domain ?new-domains]
                            [(missing? $db-before ?team :team/domain)]]
                          db-before db-after)]
-    (prn "New domains:" new-domains)))
-
-(defn schedule-removed [scheduler db-before db-after]
+    (when-not (empty? new-domains)
+      (log/info "New domains to schedule" (str/join ", " new-domains)))
+    (doseq [domain new-domains]
+      (if-let [schedule (:team/schedule (d/entity db-after [:team/domain domain]))]
+        (do (log/infof "Scheduling new domain %s with cron %s" domain schedule)
+            (schedule-questionnaire-job scheduler db-conn domain schedule))
+        (do (log/infof "Skipping scheduler for domain %s" domain))))))
+
+(defn schedule-removed [scheduler db-conn db-before db-after]
   (let [removed-domains (d/q '[:find [?removed-domains ...]
                                :in $ $db-after
                                :where
                                [$ ?team :team/domain ?removed-domains]
                                [(missing? $db-after ?team :team/domain)]]
                              db-before db-after)]
-    (prn "Removed domains:" removed-domains)))
-
-(defn schedule-updates [scheduler db-before db-after]
+    (when-not (empty? removed-domains)
+      (log/info "Domains removed" (str/join ", " removed-domains)))
+    (doseq [domain removed-domains]
+      (log/info "Unscheduling" domain)
+      (scheduler/delete-job scheduler (jobs/key (str "jobs." domain))))))
+
+(defn schedule-updates [scheduler db-conn db-before db-after]
   (let [updated-crons (d/q '[:find ?domain ?schedule-after
                              :in $db-before $db-after
                              :where
@@ -270,7 +281,15 @@
                              [$db-after  ?team :team/schedule ?schedule-after]
                              [(not= ?schedule-before ?schedule-after)]]
                            db-before db-after)]
-    (prn "Updated crons:" updated-crons)))
+    (when-not (empty? updated-crons)
+      (log/info "Updated schedules" (pr-str updated-crons)))
+    (doseq [[domain new-schedule] updated-crons]
+      (log/info "Unscheduling" domain)
+      (scheduler/delete-job scheduler (jobs/key (str "jobs." domain)))
+      (if-not (empty? new-schedule)
+        (do (log/infof "Scheduling domain %s with schedule %s" domain new-schedule)
+            (schedule-questionnaire-job scheduler db-conn domain new-schedule))
+        (do (log/info "Skipping scheduler for domain" domain))))))

 (defn listen-for-team-updates [scheduler db-conn]
   (let [queue (d/tx-report-queue db-conn)]
@@ -278,13 +297,9 @@
       (let [{:keys [db-before
                     db-after
                     tx-data]} (.take queue)]
-        ;; No figure out if we need to
-        ;; add/remove a scheduled job
-        ;; or update the cron job for some
-        (schedule-new scheduler db-before db-after)
-        (schedule-removed scheduler db-before db-after)
-        (schedule-updates scheduler db-before db-after)
-        (println "============================================")))))
+        (schedule-new scheduler db-conn db-before db-after)
+        (schedule-removed scheduler db-conn db-before db-after)
+        (schedule-updates scheduler db-conn db-before db-after)))))

 (defn -main [db-uri]
   (log/merge-config! {:level :info


fix invalid watch key failure

fix invalid watch key failure

--- boot/worker/src/boot/watcher.clj
+++ boot/worker/src/boot/watcher.clj
@@ -95,7 +95,9 @@
                        (cond
                          (and dir? (= :create etype)) (doreg service changed)
                          (not dir?) (.offer queue (.getPath changed)))))
-                   (and watch-key (.reset watch-key) (recur))))))
+                 (if-not (.reset watch-key)
+                   (util/dbug "failed to reset watch key %s\n" (.watchable watch-key)))
+                 (recur)))))
       Thread. .start)
     service))


IndexedSeq reduce was broken for some wrapped objs. Fixed.

--- src/cljs/cljs/core.cljs
+++ src/cljs/cljs/core.cljs
@@ -261,16 +261,18 @@
   (-rest [_] (if (lt- (inc i) (.length a))
                (IndexedSeq. a (inc i))
                (list)))
+  ICounted
+  (-count [_] (.length a))

   ISequential
   IEquiv
   (-equiv [coll other] (equiv-sequential coll other))

   IReduce
-  (-reduce [_ f]
-    (ci-reduce a f (aget a i) (inc i)))
-  (-reduce [_ f start]
-    (ci-reduce a f start i)))
+  (-reduce [coll f]
+    (ci-reduce coll f (aget a i) (inc i)))
+  (-reduce [coll f start]
+    (ci-reduce coll f start i)))

 (defn prim-seq [prim i]
   (when-not (= 0 (.length prim))


fix bizarro file reader

fix bizarro file reader

--- src/cljs/cljs/core.cljs
+++ src/cljs/cljs/core.cljs
@@ -230,7 +230,10 @@
       ;;(prn js)
       (.eval jse (str "print(" js ")"))))

-  (with-open [r (PushbackReader. (clojure.java.io/reader "src/cljs/cljs/core.cljs"))]
-    (dorun (map-indexed #(do jseval (take-while identity (repeatedly #(read r false nil))))))
-    (jseval '(ifirst (irest (cons 1 (cons 2 nil))))))
+  (with-open [r (java.io.PushbackReader. (clojure.java.io/reader "src/cljs/cljs/core.cljs"))]
+    (doseq [f (take-while identity (repeatedly (fn []  (read r false nil))))]
+      (jseval f)))
+
+  (jseval '(ifirst (irest (cons 1 (cons 2 nil)))))
+
   )


replaced `condp =` with `case`

replaced `condp =` with `case`

--- src/cljx/cats/core.cljx
+++ src/cljx/cats/core.cljx
@@ -234,7 +234,7 @@
     (throw (IllegalArgumentException. "bindings has to be a vector with even number of elements.")))
   (->> (reverse (partition 2 bindings))
        (reduce (fn [acc [l r]]
-                 (condp = l
+                 (case l
                    :let  `(let ~r ~acc)
                    :when `(bind (guard ~r)
                                 (fn [~(gensym)] ~acc))


- removed utils namespaces, moved to core - some fixes after static analysis (kibit, bikeshed, eastwood) - two bugs in signal functions fixed

--- src/clojure2d/utils.clj
+++ src/clojure2d/utils.clj
@@ -1,7 +0,0 @@
-(ns clojure2d.utils
-  (:require [clojure.string :as s]
-            [clojure.java.io :as io]))
-
-(set! *warn-on-reflection* true)
-(set! *unchecked-math* true)
-


[PATCH] Fixed issue #8: "Not found" message should be printed only once for all channels.

--- src/clouseau/server.clj
+++ src/clouseau/server.clj
@@ -20,8 +20,16 @@
     (let [result (jdbc/query (second product) (str "select description from packages where name='" package "';"))
           desc   (:description (first result))]
         (if (not desc)
-            [:div {:class "alert alert-danger"} "Not found"]
-            [:div {:class "alert alert-success"} (.replaceAll desc "\n" "
")])))
+            nil
+            (.replaceAll desc "\n" "
"))))
+
+(defn read-package-descriptions
+    [products package]
+    (zipmap
+        (for [product products]
+            (first product))
+        (for [product products]
+            (read-description product package))))

 (defn read-ccs-description
     [package]
@@ -82,15 +90,25 @@
         ] ; /.container-fluid
 ]);

+(defn render-description
+    [description]
+    (if-not description
+        [:div {:class "alert alert-danger"} "Not found"]
+        [:div {:class "alert alert-success"} description]))
+
+(defn package?
+    [package]
+    (and package (not (empty? package))))
+
 (defn html-renderer
-    [products package ccs-description]
+    [products package package-descriptions ccs-description products-without-descriptions]
     (page/xhtml
         (render-html-header package)
         [:body
             [:div {:class "container"}
                 (render-navigation-bar-section package)

-                (if (and package (not (empty? package)))
+                (if (package? package)
                     (form/form-to [:post "/"]
                         [:div {:class "label label-primary"} "Description provided by CCS"]
                         [:br]
@@ -102,13 +120,20 @@
                         [:br]
                     ))

-                (if (and package (not (empty? package)))
-                    [:table {:class "table table-stripped"}
-                        (for [product products]
-                            [:div [:div {:class "label label-primary"} (first product)]
-                                  (read-description product package)]
-                        )
-                    ])
+                (if (package? package)
+                    (for [product products]
+                        [:div
+                            [:div {:class "label label-primary" :style "margin-right:3px"} (first product)]
+                            [:div {:class "alert alert-success"} (get package-descriptions (first product))]]
+     ;                       (render-description (first products-per-description))]
+                    )
+                )
+                (if (and (package? package) products-without-descriptions)
+                    [:div
+                    (for [product products-without-descriptions]
+                        [:div {:class "label label-primary" :style "margin-right:3px"} product])
+                        [:div {:class "alert alert-danger"} "Not found"]]
+                    )
                 (render-footer)
             ] ;

         ] ;
@@ -118,22 +143,43 @@
     [parameter]
     (and parameter (not (empty? parameter))))

-(defn perform-normal-processing
+(defn log-request-information
     [request]
     (println "time:        " (.toString (new java.util.Date)))
     (println "addr:        " (request :remote-addr))
     (println "params:      " (request :params))
     (println "user-agent:  " ((request :headers) "user-agent"))
-    (println "")
+    (println ""))
+
+(defn get-products-without-descriptions
+    [products package-descriptions]
+   ; (sort
+        (for [product products :when (not (get package-descriptions (first product)))]
+            (first product)));)
+
+(defn get-products-with-descriptions
+    [products package-descriptions]
+    (sort
+        (for [product products :when (get package-descriptions (first product))]
+            (first product))))
+
+(defn process
+    [package new-description]
+    (if (and (not-empty-parameter? package) (not-empty-parameter? new-description))
+        (store-ccs-description package new-description))
+    (let [ccs-description               (read-ccs-description package)
+          package-descriptions          (read-package-descriptions products/products package)
+          products-without-descriptions (get-products-without-descriptions products/products package-descriptions)]
+        (-> (http-response/response (html-renderer products/products package package-descriptions ccs-description products-without-descriptions))
+            (http-response/content-type "text/html"))))
+
+(defn perform-normal-processing
+    [request]
+    (log-request-information request)
     (let [params              (request :params)
-          uri                 (request :uri)
           package             (get params "package")
           new-description     (get params "new-description")]
-          (if (and (not-empty-parameter? package) (not-empty-parameter? new-description))
-              (store-ccs-description package new-description))
-          (let [ccs-description (read-ccs-description package)]
-              (-> (http-response/response (html-renderer products/products package ccs-description))
-                  (http-response/content-type "text/html")))))
+          (process package new-description)))

 (defn return-file
     [file-name content-type]
@@ -152,5 +198,5 @@
             "/bootstrap.min.css" (return-file "bootstrap.min.css" "text/css")
             "/smearch.css"       (return-file "smearch.css" "text/css")
             "/bootstrap.min.js"  (return-file "bootstrap.min.js" "application/javascript")
-            (perform-normal-processing request))))
-
+            "/"                  (perform-normal-processing request))))
+


Added exclusions to project.clj

Added exclusions to project.clj

--- web-app/project.clj
+++ web-app/project.clj
@@ -6,11 +6,10 @@
   :min-lein-version   "2.5.0"

   :dependencies [[org.clojure/clojure       "1.7.0"]
-                 [figwheel                  "0.5.0-1"]
-                 [figwheel-sidecar          "0.5.0-1"]
+                 ;;[figwheel                  "0.5.0-1"]
+                 ;;[figwheel-sidecar          "0.5.0-1"]
                  [http-kit "2.1.8"]
-                 [weasel "0.7.0"]
-                 [com.cemerick/piggieback "0.2.1"]
+                 ;;[weasel "0.7.0"]
                  [org.clojure/clojurescript "1.7.189" :exclusions [org.apache.ant/ant]]
                  [org.omcljs/om             "0.8.8"] ; ClojureScript interface to Facebook's React
                  [cljs-http                 "0.1.30"] ; A ClojureScript HTTP library
@@ -18,8 +17,13 @@
                  [cljsjs/moment             "2.9.0-0"]] ; Moment.js

   :plugins      [[lein-cljsbuild            "1.1.2"] ; Leiningen plugin to make ClojureScript development easy
-                 [lein-figwheel             "0.5.0-1"]
-                 [cider/cider-nrepl         "0.11.0-SNAPSHOT"]]
+                 [lein-figwheel             "0.5.0-1" :exclusions [org.clojure/clojure
+                                                                   org.clojure/tools.reader
+                                                                   ring/ring-core
+                                                                   commons-fileupload
+                                                                   clj-time]]
+                 [cider/cider-nrepl         "0.11.0-SNAPSHOT" :exclusions [org.clojure/clojure
+                                                                           org.clojure/tools.nrepl]]]

   :clean-targets ^{:protect false} ["resources/public/js"]

@@ -28,7 +32,18 @@
                  :init-ns potato.dev}

   :profiles {:dev {:dependencies [[com.cemerick/piggieback "0.2.1"]
-                                  [figwheel-sidecar "0.5.0-1"]]
+                                  [figwheel-sidecar "0.5.0-1" :exclusions [http-kit
+                                                                           org.clojure/tools.reader
+                                                                           org.clojure/core.async
+                                                                           org.clojure/tools.analyzer.jvm
+                                                                           org.clojure/tools.analyzer
+                                                                           org.clojure/core.memoize
+                                                                           org.clojure/core.cache
+                                                                           org.clojure/data.priority-map
+                                                                           org.ow2.asm/asm-all
+                                                                           commons-fileupload
+                                                                           ring/ring-core
+                                                                           joda-time]]]
                    :source-paths ["cljs_src" "src/cljs" "env/dev/cljs"]}}

   :cljsbuild {:builds


Removed add-classpath

Removed add-classpath

--- examples/simple.clj
+++ examples/simple.clj
@@ -1,7 +1,4 @@
 ;; processing test
-
-;; you can add processing's JAR via add-classpath
-(add-classpath "file:///h:/bin/dev/processing/lib/core.jar")

 (clojure/ns p5-example
 			(:use rosado.processing)


Increase heartbeat channel size.

Increase heartbeat channel size.

--- src/onyx/information_model.cljc
+++ src/onyx/information_model.cljc
@@ -1441,7 +1441,7 @@
              :optional? true
              :added "0.12.0"
              :restrictions ["Parameter must be a power of 2."]
-             :default 524288}
+             :default 1048576}

             :onyx.messaging/term-buffer-size.segment
             {:doc "Segment messenger buffer size. Used to send segments to downstream peers. Maximum segment size is dictated by this buffer size, where the maximum segment size = term-buffer-size.segment / 8. The default size will allow for segments of approximately 262,144 bytes after protocol message headers are accountered for. Adjust this parameter (carefully) if you wish to tune throughput vs memory usage. Note that each peer may have a term buffer to each downstream peer, and thus you should expect up to n^2 of these buffers, each of 3 * term-buffer-size.segment size in bytes."


Fixes #409.

Fixes #409.

--- src/onyx/information_model.cljc
+++ src/onyx/information_model.cljc
@@ -12,21 +12,24 @@
              :restrictions ["Must be unique across all catalog entries."
                             "Value cannot be `:none`."
                             "Value cannot be `:all`."]
-             :optional? false}
+             :optional? false
+             :added "0.8.0"}

             :onyx/type
             {:doc "The role that this task performs. `:input` reads data. `:function` applies a transformation. `:output` writes data."
              :type :keyword
              :tags [:task]
              :choices [:input :function :output]
-             :optional? false}
+             :optional? false
+             :added "0.8.0"}

             :onyx/batch-size
             {:doc "The number of segments a peer will wait to read before processing them all in a batch for this task. Segments will be processed when either `:onyx/batch-size` segments have been received at this peer, or `:onyx/batch-timeout` milliseconds have passed - whichever comes first. This is a knob that is used to tune throughput and latency, and it goes hand-in-hand with `:onyx/batch-timeout`."
              :type :integer
              :tags [:latency :throughput]
              :restrictions ["Value must be greater than 0."]
-             :optional? false}
+             :optional? false
+             :added "0.8.0"}

             :onyx/batch-timeout
             {:doc "The number of milliseconds a peer will wait to read more segments before processing them all in a batch for this task. Segments will be processe when either `:onyx/batch-timeout` milliseconds passed, or `:onyx/batch-size` segments have been read - whichever comes first. This is a knob that is used to tune throughput and latency, and it goes hand-in-hand with `:onyx/batch-size`."
@@ -35,27 +38,31 @@
              :tags [:latency :throughput]
              :restrictions ["Value must be greater than 0."]
              :default 50
-             :optional? true}
+             :optional? true
+             :added "0.8.0"}

             :onyx/doc
             {:doc "A docstring for this catalog entry."
              :type :string
              :tags [:documentation]
-             :optional? true}
+             :optional? true
+             :added "0.8.0"}

             :onyx/max-peers
             {:doc "The maximum number of peers that will ever be assigned to this task concurrently."
              :type :integer
              :tags [:aggregation :grouping]
              :restrictions ["Value must be greater than 0."]
-             :optional? true}
+             :optional? true
+             :added "0.8.0"}

             :onyx/min-peers
             {:doc "The minimum number of peers that will be concurrently assigned to execute this task before it begins. If the number of peers working on this task falls below its initial count due to failure or planned departure, the choice of `:onyx/flux-policy` defines the strategy for what to do."
              :type :integer
              :tags [:aggregation :grouping]
              :restrictions ["Value must be greater than 0."]
-             :optional? true}
+             :optional? true
+             :added "0.8.0"}

             :onyx/n-peers
             {:doc "A convenience parameter which expands to `:onyx/min-peers` and `:onyx/max-peers` set to the same value. This is useful if you want to specify exactly how many peers should concurrently execute this task - no more, and no less."
@@ -64,7 +71,8 @@
              :restrictions ["Value must be greater than 0."
                             "`:onyx/min-peers` cannot also be defined for this catalog entry."
                             "`:onyx/max-peers` cannot also be defined for this catalog entry."]
-             :optional? true}
+             :optional? true
+             :added "0.8.0"}

             :onyx/language
             {:doc "Designates the language that the function denoted by `:onyx/fn` is implemented in."
@@ -72,7 +80,8 @@
              :tags [:interoperability]
              :choices [:clojure :java]
              :default :clojure
-             :optional? true}
+             :optional? true
+             :added "0.8.0"}

             :onyx/restart-pred-fn
             {:doc "A fully-qualified namespaced keyword pointing to function which takes an exception as a parameter, returning a boolean indicating whether the peer that threw this exception should restart its task."
@@ -80,13 +89,15 @@
              :choices :any
              :tags [:fault-tolerance]
              :restrictions ["Must resolve to a function on the classpath at runtime."]
-             :optional? true}
+             :optional? true
+             :added "0.8.0"}

             :onyx/params
             {:doc "A vector of keys to obtain from the task map, and inject into the parameters of the function defined in :onyx/fn."
              :type :vector
              :tags [:function]
-             :optional? true}
+             :optional? true
+             :added "0.8.0"}

             :onyx/medium
             {:doc "Denotes the kind of input or output communication or storage that is being read from or written to (e.g. `:kafka` or `:web-socket`). This is currently does not affect any functionality, and is reserved for the future."
@@ -94,7 +105,8 @@
              :tags [:plugin]
              :choices :any
              :required-when ["`:onyx/type` is set to `:input`"
-                             "`:onyx/type` is set to `:output`"]}
+                             "`:onyx/type` is set to `:output`"]
+             :added "0.8.0"}

             :onyx/plugin
             {:doc "When `:onyx/language` is set to `:clojure`, this is a fully qualified, namespaced keyword pointing to a function that takes the Event map and returns a Record implementing the Plugin interfaces. When `:onyx/language` is set to `:java`, this is a keyword pointing to a Java class that is constructed with the Event map. This class must implement the interoperability interfaces."
@@ -103,7 +115,8 @@
              :choices :any
              :restrictions ["Namespaced keyword required unless :onyx/language :java is set, in which case a non-namespaced keyword is required."]
              :required-when ["`:onyx/type` is set to `:input`"
-                             "`:onyx/type` is set to `:output`"]}
+                             "`:onyx/type` is set to `:output`"]
+             :added "0.8.0"}

             :onyx/pending-timeout
             {:doc "The duration of time, in milliseconds, that a segment that enters an input task has to be fully acknowledged and processed. That is, this segment, and any subsequent segments that it creates in downstream tasks, must be fully processed before this timeout occurs. If the segment is not fully processed, it will automatically be retried."
@@ -112,7 +125,8 @@
              :tags [:input :plugin :latency :fault-tolerance]
              :units :milliseconds
              :optionally-allowed-when ["`:onyx/type` is set to `:input`"
-                                       "Value must be greater than 0."]}
+                                       "Value must be greater than 0."]
+             :added "0.8.0"}

             :onyx/input-retry-timeout
             {:doc "The duration of time, in milliseconds, that the input task goes dormant between checking which segments should expire from its internal pending pool. When segments expire, they are automatically retried."
@@ -121,7 +135,8 @@
              :tags [:input :plugin :latency :fault-tolerance]
              :units :milliseconds
              :optionally-allowed-when ["`:onyx/type` is set to `:input`"
-                                       "Value must be greater than 0."]}
+                                       "Value must be greater than 0."]
+             :added "0.8.0"}

             :onyx/max-pending
             {:doc "The maximum number of segments that a peer executing an input task will allow in its internal pending message pool. If this pool is filled to capacity, it will not accept new segments - exhibiting backpressure to upstream message produces."
@@ -130,7 +145,8 @@
              :tags [:input :plugin :latency :backpressure :fault-tolerance]
              :units :segments
              :optionally-allowed-when ["`:onyx/type` is set to `:input`"
-                                       "Value must be greater than 0."]}
+                                       "Value must be greater than 0."]
+             :added "0.8.0"}

             :onyx/fn
             {:doc "A fully qualified, namespaced keyword that points to a function on the classpath. This function takes at least one argument - an incoming segment, and returns either a segment or a vector of segments. This function may not return `nil`. This function can be parameterized further through a variety of techniques."
@@ -138,7 +154,8 @@
              :tags [:function]
              :required-when ["`:onyx/type` is set to `:function`"]
              :optionally-allowed-when ["`:onyx/type` is set to `:input`"
-                                       "`:onyx/type` is set to `:output`"]}
+                                       "`:onyx/type` is set to `:output`"]
+             :added "0.8.0"}

             :onyx/group-by-key
             {:doc "The key, or vector of keys, to group incoming segments by. Keys that hash to the same value will always be sent to the same virtual peer."
@@ -146,7 +163,8 @@
              :tags [:aggregation :grouping :windows]
              :optionally-allowed-when ["`:onyx/type` is set to `:function` or `:output`"]
              :restrictions ["Cannot be defined when `:onyx/group-by-fn` is defined."
-                            "`:onyx/flux-policy` must also be defined in this catalog entry."]}
+                            "`:onyx/flux-policy` must also be defined in this catalog entry."]
+             :added "0.8.0"}

             :onyx/group-by-fn
             {:doc "A fully qualified, namespaced keyword that points to a function on the classpath. This function takes a single argument, a segment, as a parameter. The value that the function returns will be hashed. Values that hash to the same value will always be sent to the same virtual peer."
@@ -154,14 +172,16 @@
              :tags [:aggregation :grouping :windows :function]
              :optionally-allowed-when ["`:onyx/type` is set to `:function` or `:output`"]
              :restrictions ["Cannot be defined when `:onyx/group-by-key` is defined."
-                            "`:onyx/flux-policy` must also be defined in this catalog entry."]}
+                            "`:onyx/flux-policy` must also be defined in this catalog entry."]
+             :added "0.8.0"}

             :onyx/bulk?
             {:doc "Boolean value indicating whether the function in this catalog entry denoted by `:onyx/fn` should take a single segment, or the entire batch of segments that were read as a parameter. When set to `true`, this function's return value is ignored. The segments are identically propogated to the downstream tasks."
              :type :boolean
              :default false
              :tags [:function]
-             :optionally-allowed-when ["`:onyx/type` is set to `:function`"]}
+             :optionally-allowed-when ["`:onyx/type` is set to `:function`"]
+             :added "0.8.0"}

             :onyx/flux-policy
             {:doc "The policy that should be used when a task with grouping enabled loses a peer. Losing a peer means that the consistent hashing used to pin the same hashed values to the same peers will be altered. Using the `:kill` flux policy will kill the job. This is useful for jobs that cannot tolerate an altered hashing strategy. Using `:continue` will allow the job to continue running. With `:kill` and `:continue`, new peers will never be added to this job. The final policy is `:recover`, which is like `:continue`, but will allow peers to be added back to this job to meet the `:onyx/min-peers` number of peers working on this task concurrently."
@@ -170,13 +190,15 @@
              :tags [:aggregation :grouping :windows]
              :restrictions ["`:onyx/min-peers` or `:onyx/n-peers` must also be defined for this catalog entry. If `:recover` is used, then `:onyx/max-peers` or `:onyx/n-peers`` must also be defined. "]
              :optionally-allowed-when ["`:onyx/type` is set to `:function` or `:output`"
-                                       "`:onyx/group-by-key` or `:onyx/group-by-fn` is set."]}
+                                       "`:onyx/group-by-key` or `:onyx/group-by-fn` is set."]
+             :added "0.8.0"}

             :onyx/uniqueness-key
             {:doc "The key of incoming segments that indicates global uniqueness. This is used by the Windowing feature to detect duplicated processing of segments. An example of this would be an `:id` key for segments representing users, assuming `:id` is globally unique in your system. An example of a bad uniqueness-key would be `:first-name` as two or more users may have their first names in common."
              :type :any
              :tags [:aggregation :windows]
-             :required-when ["A Window is defined on this task."]}
+             :required-when ["A Window is defined on this task."]
+             :added "0.8.0"}

             :onyx/deduplicate?
             {:doc "Does not deduplicate segments using the `:onyx/uniqueness-key`, which is otherwise required when using windowed tasks. Often useful if your segments do not have a unique key that you can use to filter incoming replayed or duplicated segments."
@@ -184,7 +206,8 @@
              :default true
              :tags [:aggregation :windows]
              :optionally-allowed-when ["A window is defined on this task."]
-             :required-when ["A Window is defined on this task and there is no possible :onyx/uniqueness-key to on the segment to deduplicate with."]}}}
+             :required-when ["A Window is defined on this task and there is no possible :onyx/uniqueness-key to on the segment to deduplicate with."]
+             :added "0.8.0"}}}

    :flow-conditions-entry
    {:summary "Flow conditions are used for isolating logic about whether or not segments should pass through different tasks in a workflow, and support a rich degree of composition with runtime parameterization."
@@ -193,47 +216,54 @@
             {:doc "The source task from which segments are being sent."
              :type :keyword
              :optional? false
-             :restrictions ["Must name a task in the workflow."]}
+             :restrictions ["Must name a task in the workflow."]
+             :added "0.8.0"}

             :flow/to
             {:doc "The destination task where segments will arrive. If set to `:all`, all downstream tasks will receive this segment. If set to `:none`, no downstream tasks will receive this segment. Otherwise it must name a vector of keywords indicating downstream tasks. The order of keywords is irrelevant."
              :type [:keyword [:keyword]]
              :choices [[:any] :all :none]
              :optional? false
-             :restrictions ["When the value is a vector of keyword, every keyword must name a task in the workflow."]}
+             :restrictions ["When the value is a vector of keyword, every keyword must name a task in the workflow."]
+             :added "0.8.0"}

             :flow/predicate
             {:doc "When denoted as a keyword, this must be a fully qualified, namespaced keyword pointing to a function on the classpath at runtime. This function takes at least 4 arguments - the Event map, the old segment before `:onyx/fn` was applied, the new segment after `:onyx/fn` was applied, and the sequence of new segments generated by the old semgent. If the old segment generated exactly one segment, and not a sequence of segments, the value of the last parameter will be a collection with only the new segment in it.

                   When denoted as a vector of keywords, the first value in the vector  may either be the keyword `:and`, `:or`, or `:not`, or be a keyword as described above. In the latter case, any subsequent values must be keywords that resolve to keys in the flow condition entries map. The values of these keys are resolved and passed as additional parameters to the function. In the former case, the result of the function (which may again be wrapped with a vector to nest logical operators or parameters), is applied with the designated logical operator. This yields predicate composition."
              :type [:keyword [:keyword]]
-             :optional? false}
+             :optional? false
+             :added "0.8.0"}

             :flow/exclude-keys
             {:doc "If any of the keys are present in the segment, they will be `dissoc`ed from the segment before it is sent downstream. This is useful when values in the segment are present purely for the purpose of making a decision about which downstream tasks it should be sent to."
              :type [[:keyword]]
-             :optional? true}
+             :optional? true
+             :added "0.8.0"}

             :flow/short-circuit?
             {:doc "When multiple flow condition entry predicates evaluated to true, the tasks in `:flow/to` are set unioned. If this behavior is undesirable, and you want exactly the tasks in this flow condition's `:flow/to` key to be used, plus any previously matched flow conditions `:flow/to` values. Setting `:flow/short-circuit?` to `true` will force the matcher to stop executing and immediately return with the values that it matched."
              :type :boolean
              :optional? true
              :default false
-             :restrictions ["Any entry that has :flow/short-circuit? set to true must come before any entries for an task that have it set to false or nil."]}
+             :restrictions ["Any entry that has :flow/short-circuit? set to true must come before any entries for an task that have it set to false or nil."]
+             :added "0.8.0"}

             :flow/thrown-exception?
             {:doc "If an exception is thrown from an Onyx transformation function, you can capture it from within your flow conditions by setting this value to `true`. If an exception is thrown, only flow conditions with `:flow/thrown-exception?` set to `true` will be evaluated. The value that is normally the segment which is sent to the predicate will be the exception object that was thrown. Note that exceptions don't serialize. This feature is meant to be used in conjunction with Post-transformations and Actions for sending exception values to downstream tasks."
              :type :boolean
              :optional? true
              :default false
-             :restrictions ["Exception flow conditions must have `:flow/short-circuit?` set to `true`"]}
+             :restrictions ["Exception flow conditions must have `:flow/short-circuit?` set to `true`"]
+             :added "0.8.0"}

             :flow/post-transform
             {:doc "A fully qualified, namespaced keyword that points to a function on the classpath at runtime. This function is invoked when an exception is thrown processing a segment in `:onyx/fn` and this flow condition's predicate evaluates to `true`. The function takes 3 parameters - the Event map, the segment that causes the exception to be thrown, and the exception object. The return value of this function is sent to the downstream tasks instead of trying to serialize the exception. The return value must be a segment or sequence of segments, and must serialize."
              :type :keyword
              :optional? true
              :default nil
-             :restrictions ["`:flow/thrown-exception?` must be set to `true`."]}
+             :restrictions ["`:flow/thrown-exception?` must be set to `true`."]
+             :added "0.8.0"}

             :flow/action
             {:doc "Names a side effect to perform in response to processing this segment. If set to `:retry`, this segment will be immediately, forcibly retried from the root input task from which it eminated. This segment will not be sent to any downstream tasks."
@@ -241,12 +271,14 @@
              :choices [:retry]
              :optional? true
              :default nil
-             :restrictions ["Any flow condition clauses with `:flow/action` set to `:retry` must also have `:flow/short-circuit?` set to `true`, and `:flow/to` set to `:none`."]}
+             :restrictions ["Any flow condition clauses with `:flow/action` set to `:retry` must also have `:flow/short-circuit?` set to `true`, and `:flow/to` set to `:none`."]
+             :added "0.8.0"}

             :flow/doc
             {:doc "A docstring for this flow condition."
              :type :string
-             :optional? true}}}
+             :optional? true
+             :added "0.8.0"}}}

    :window-entry
    {:summary "Windows allow you to group and accrue data into possibly overlapping buckets. Windows are intimately related to the Triggers feature."
@@ -255,86 +287,102 @@
             {:doc "A unique identifier for this window."
              :type :keyword
              :optional? false
-             :restrictions ["Must be unique across all Window entries."]}
+             :restrictions ["Must be unique across all Window entries."]
+             :added "0.8.0"}

             :window/task
             {:doc "The task that this window will be applied to."
              :type :keyword
              :optional? false
-             :restrictions ["Must name a task in the workflow."]}
+             :restrictions ["Must name a task in the workflow."]
+             :added "0.8.0"}

             :window/type
             {:doc "The type of Window to use. See the User Guide for what each type means."
              :type :keyword
              :choices [:fixed :sliding :global :session]
-             :optional? false}
+             :optional? false
+             :added "0.8.0"}

             :window/aggregation
             {:doc "If this value is a keyword, it is a fully qualified, namespaced keyword pointing to a symbol on the classpath at runtime. This symbol must be a map with keys as further specified by the information model. Onyx comes with a handful of aggregations built in, such as `:onyx.windowing.aggregation/min`. See the User Guide for the full list. Users can also implement their own aggregations.

                   If this value is a vector, it contain two values: a keyword as described above, and another keyword which represents the key to aggregate over."
              :type [:keyword [:keyword]]
-             :optional? false}
+             :optional? false
+             :added "0.8.0"}

             :window/window-key
             {:doc "The key of the incoming segments to window over. This key can represent any totally ordered domain, for example `:event-time`."
              :type :any
              :required-when ["`:window/type` is set to `:fixed`"
                              "`:window/type` is set to `:sliding`"
-                             "`:window/type` is set to `:session`"]}
+                             "`:window/type` is set to `:session`"]
+             :added "0.8.0"}

             :window/min-key
             {:doc "A globally minimum value that values of `:window/window-key` will never be less than. This is used for calculating materialized aggregates for windows in a space efficient manner."
              :type :integer
              :optional? true
-             :default 0}
+             :default 0
+             :added "0.8.0"}

             :window/session-key
             {:doc "The key of the incoming segments to calculate a session window over. This key can represent any totally ordered domain, e.g. `:event-time`"
              :type :any
-             :optional? true}
+             :optional? true
+             :added "0.8.0"}

             :window/range
             {:doc "The span of time, or other totally ordered domain, that this window will capture data within."
              :type [:unit]
              :optional? false
-             :required-when ["The `:window/type` is `:fixed` or `:sliding`."]}
+             :required-when ["The `:window/type` is `:fixed` or `:sliding`."]
+             :added "0.8.0"}

             :window/slide
             {:doc "To offset of time, or other totally ordered domain, to wait before starting a new window after the previous window."
              :type [:unit]
-             :required-when ["The `:window/type` is `:sliding`."]}
+             :required-when ["The `:window/type` is `:sliding`."]
+             :added "0.8.0"}

             :window/init
             {:doc "The initial value to be used for the aggregate, if required. Some aggregates require this, such as the Minimum aggregate. Others, such as the Conj aggregate, do not, as empty vector makes a suitable initial value."
              :type :any
-             :required-when ["The `:window/aggregation` has no predefined initial value."]}
+             :required-when ["The `:window/aggregation` has no predefined initial value."]
+             :added "0.8.0"}

             :window/timeout-gap
             {:doc "The duration of dormant activity that constitutes a session window being closed."
              :type :unit
-             :required-when ["The `window/type` is `:session`."]}
+             :required-when ["The `window/type` is `:session`."]
+             :added "0.8.0"}

             :window/doc
             {:doc "A docstring for this window."
              :type :string
-             :optional? true}}}
+             :optional? true
+             :added "0.8.0"}}}

    :state-aggregation
    {:summary "Onyx provides the ability to perform stateful updates for segments calculated over windows. For example, a grouping task may accumulate incoming values for a number of keys over windows of 5 minutes."
     :link nil
     :model {:aggregation/init {:doc "Fn (window) to initialise the state."
                                :type :function
-                               :optional? true}
+                               :optional? true
+                               :added "0.8.0"}
             :aggregation/fn {:doc "Fn (state, window, segment) to generate a serializable state machine update."
                              :type :function
-                             :optional? false}
+                             :optional? false
+                             :added "0.8.0"}
             :aggregation/apply-state-update {:doc "Fn (state, entry) to apply state machine update entry to a state."
                                              :type :function
-                                             :optional? false}
+                                             :optional? false
+                                             :added "0.8.0"}
             :aggregation/super-aggregation-fn {:doc "Fn (state-1, state-2, window) to combine two states in the case of two windows being merged, e.g. session windows."
                                                :type :function
-                                               :optional? true}}}
+                                               :optional? true
+                                               :added "0.8.0"}}}
    :trigger-entry
    {:summary "Triggers are a feature that interact with Windows. Windows capture and bucket data over time. Triggers let you release the captured data over a variety stimuli."
     :link nil
@@ -342,48 +390,56 @@
             {:doc "The name of a `:window/id` window to fire the trigger against."
              :type :keyword
              :optional? false
-             :restrictions ["Must name a `:window/id` in the window entries."]}
+             :restrictions ["Must name a `:window/id` in the window entries."]
+             :added "0.8.0"}

             :trigger/refinement
             {:doc "The refinement mode to use when firing the trigger against a window. When set to `:accumulating`, the window contents remain. When set to `:discarding`, the window contents are destroyed, resetting the window to the initial aggregation value. The initial value is set lazily so expired windows do not unnecessarily consume memory."
              :type :keyword
              :choices [:accumulating :discarding]
-             :optional? false}
+             :optional? false
+             :added "0.8.0"}

             :trigger/on
             {:doc "The event to trigger in reaction to, such as a segment with a special feature, or on a timer. See the User Guide for the full list of prepackaged Triggers."
              :type :keyword
-             :optional? false}
+             :optional? false
+             :added "0.8.0"}

             :trigger/sync
             {:doc "A fully qualified, namespaced keyword pointing to a function on the classpath at runtime. This function takes the window contents as its argument. Its return value is ignored. This function is invoked when the trigger fires, and is used to do any arbitrary action with the window contents, such as sync them to a database."
              :type :keyword
-             :optional? false}
+             :optional? false
+             :added "0.8.0"}

             :trigger/period
             {:doc "A timer trigger sleeps for a duration of `:trigger/period`. When it is done sleeping, the `:trigger/sync` function is invoked with its usual arguments. The trigger goes back to sleep and repeats itself."
              :type :keyword
              :required-when ["`:trigger/on` is `:timer`"]
              :choices [:milliseconds :seconds :minutes :hours :days]
-             :optional? true}
+             :optional? true
+             :added "0.8.0"}

             :trigger/threshold
             {:doc "A segment trigger will fire every threshold of segments."
              :required-when ["`:trigger/on` is `:segments`"]
              :type [:integer :elements]
              :example [5 :elements]
-             :optional? true}
+             :optional? true
+             :added "0.8.0"}

             :trigger/fire-all-extents?
             {:doc "When set to `true`, if any particular extent fires in reaction to this trigger, all extents also fire."
              :type :boolean
              :optional? true
-             :default false}
+             :default false
+             :added "0.8.0"}

             :trigger/doc
             {:doc "A docstring for this trigger."
              :type :string
-             :optional? true}}}
+             :optional? true
+             :added "0.8.0"}}}

    :lifecycle-entry
    {:summary "Lifecycles are a feature that allow you to control code that executes at particular points during task execution on each peer. Lifecycles are data driven and composable."
@@ -392,497 +448,591 @@
             {:doc "The task that this lifecycle applies to."
              :type :keyword
              :optional? false
-             :restrictions ["Must be a task defined in the workflow."]}
+             :restrictions ["Must be a task defined in the workflow."]
+             :added "0.8.0"}

             :lifecycle/calls
             {:doc "A fully qualified, namespaced keyword pointing to a symbol on the classpath at runtime. This symbol must be a map with keys further specified by the information model. The keys in this map denote the concrete functions to invoke at execution time."
              :type :keyword
-             :optional? false}
+             :optional? false
+             :added "0.8.0"}

             :lifecycle/doc
             {:doc "A docstring for this lifecycle."
              :type :string
-             :optional? true}}}
+             :optional? true
+             :added "0.8.0"}}}

    :lifecycle-calls
    {:summary "Lifecycle calls are related to lifecycles. They consist of a map of functions that are used when resolving lifecycle entries to their corresponding functions."
     :link nil
     :model {:lifecycle/doc {:doc "A docstring for these lifecycle calls."
                             :type :string
-                            :optional? true}
+                            :optional? true
+                            :added "0.8.0"}
+
             :lifecycle/start-task? {:doc "A function that takes two arguments - an event map, and the matching lifecycle map. Must return a boolean value indicating whether to start the task or not. If false, the process backs off for a preconfigured amount of time and calls this task again. Useful for lock acquisition. This function is called prior to any processes inside the task becoming active."
                                     :type :function
-                                    :optional? true}
+                                    :optional? true
+                                    :added "0.8.0"}
+
             :lifecycle/before-task-start {:doc "A function that takes two arguments - an event map, and the matching lifecycle map. Must return a map that is merged back into the original event map. This function is called after processes in the task are launched, but before the peer listens for incoming segments from other peers."
                                           :type :function
-                                          :optional? true}
+                                          :optional? true
+                                          :added "0.8.0"}
+
             :lifecycle/before-batch {:doc "A function that takes two arguments - an event map, and the matching lifecycle map. Must return a map that is merged back into the original event map. This function is called prior to receiving a batch of segments from the reading function."
                                      :type :function
-                                     :optional? true}
+                                     :optional? true
+                                     :added "0.8.0"}
+
             :lifecycle/after-read-batch {:doc "A function that takes two arguments - an event map, and the matching lifecycle map. Must return a map that is merged back into the original event map. This function is called immediately after a batch of segments has been read by the peer. The segments are available in the event map by the key `:onyx.core/batch`."
                                          :type :function
-                                         :optional? true}
+                                         :optional? true
+                                         :added "0.8.0"}
+
             :lifecycle/after-batch {:doc "A function that takes two arguments - an event map, and the matching lifecycle map. Must return a map that is merged back into the original event map. This function is called immediately after a batch of segments has been procesed by the peer, but before the batch is acked."
                                     :type :function
-                                    :optional? true}
+                                    :optional? true
+                                    :added "0.8.0"}
+
             :lifecycle/after-task-stop {:doc "A function that takes two arguments - an event map, and the matching lifecycle map. Must return a map that is merged back into the original event map. This function is called before the peer relinquishes its task. No more segments will be received."
                                         :type :function
-                                        :optional? true}
+                                        :optional? true
+                                        :added "0.8.0"}
+
             :lifecycle/after-ack-segment {:doc "A function that takes four arguments - an event map, a message id, the return of an input plugin ack-segment call, and the matching lifecycle map. May return a value of any type which will be discarded. This function is whenever a segment at the input task has been fully acked."
                                           :type :function
-                                          :optional? true}
+                                          :optional? true
+                                          :added "0.8.0"}
+
             :lifecycle/after-retry-segment {:doc "A function that takes four arguments - an event map, a message id, the return of an input plugin ack-segment call, and the matching lifecycle map. May return a value of any type which will be discarded. This function is whenever a segment at the input task has been pending for greater than pending-timeout time and will be retried."
                                             :type :function
-                                            :optional? true}}}
+                                            :optional? true
+                                            :added "0.8.0"}}}

    :peer-config
    {:summary "All options available to configure the virtual peers and development environment."
     :link nil
     :model {:onyx/id
-	    {:doc "The ID for the cluster that the peers will coordinate via. Provides a way to provide strong, multi-tenant isolation of peers."
-	     :type [:one-of [:string :uuid]]
-	     :optional? false}
-
-	    :onyx.peer/job-scheduler
-	    {:doc "Each running Onyx instance is configured with exactly one job scheduler. The purpose of the job scheduler is to coordinate which jobs peers are allowed to volunteer to execute."
-	     :type :keyword
-	     :choices [:onyx.job-scheduler/percentage :onyx.job-scheduler/balanced :onyx.job-scheduler/greedy]
-	     :optional? false}
-
-	    :zookeeper/address
+            {:doc "The ID for the cluster that the peers will coordinate via. Provides a way to provide strong, multi-tenant isolation of peers."
+             :type [:one-of [:string :uuid]]
+             :optional? false
+             :added "0.8.0"}
+
+            :onyx.peer/job-scheduler
+            {:doc "Each running Onyx instance is configured with exactly one job scheduler. The purpose of the job scheduler is to coordinate which jobs peers are allowed to volunteer to execute."
+             :type :keyword
+             :choices [:onyx.job-scheduler/percentage :onyx.job-scheduler/balanced :onyx.job-scheduler/greedy]
+             :optional? false
+             :added "0.8.0"}
+
+            :zookeeper/address
             {:doc "The addresses of the ZooKeeper servers to use for coordination e.g. 192.168.1.1:2181,192.168.1.2:2181"
              :type :string
-             :optional? false}
+             :optional? false
+             :added "0.8.0"}

             :onyx.peer/inbox-capacity
             {:doc "Maximum number of messages to try to prefetch and store in the inbox, since reading from the log happens asynchronously."
              :type :integer
              :unit :messages
              :default 1000
-             :optional? true}
+             :optional? true
+             :added "0.8.0"}

             :onyx.peer/outbox-capacity
             {:doc "Maximum number of messages to buffer in the outbox for writing, since writing to the log happens asynchronously."
              :type :integer
              :unit :messages
              :default 1000
-             :optional? true}
+             :optional? true
+             :added "0.8.0"}

             :onyx.peer/retry-start-interval
             {:doc "Number of ms to wait before trying to reboot a virtual peer after failure."
              :type :integer
              :unit :milliseconds
              :default 2000
-             :optional? true}
+             :optional? true
+             :added "0.8.0"}

             :onyx.peer/join-failure-back-off
             {:doc "Number of ms to wait before trying to rejoin the cluster after a previous join attempt has aborted."
              :type :integer
              :unit :milliseconds
              :default 250
-             :optional? true}
+             :optional? true
+             :added "0.8.0"}

             :onyx.peer/drained-back-off
             {:doc "Number of ms to wait before trying to complete the job if all input tasks have been exhausted."
              :type :integer
              :unit :milliseconds
              :default 400
-             :optional? true}
+             :optional? true
+             :added "0.8.0"}

             :onyx.peer/peer-not-ready-back-off
             {:doc "Number of ms to back off and wait before retrying the call to `start-task?` lifecycle hook if it returns false."
              :type :integer
              :unit :milliseconds
              :default 500
-             :optional? true}
+             :optional? true
+             :added "0.8.0"}

             :onyx.peer/job-not-ready-back-off
             {:doc "Number of ms to back off and wait before trying to discover configuration needed to start the subscription after discovery failure."
              :type :integer
              :unit :milliseconds
              :optional? true
-             :default 500}
+             :default 500
+             :added "0.8.0"}

             :onyx.peer/fn-params
             {:doc "A map of keywords to vectors. Keywords represent task names, vectors represent the first parameters to apply to the function represented by the task. For example, `{:add [42]}` for task `:add` will call the function underlying `:add` with `(f 42 <segment>)` This will apply to any job with this task name."
              :type :map
              :optional? true
-             :default {}}
+             :default {}
+             :added "0.8.0"}

             :onyx.peer/backpressure-check-interval
             {:doc "Number of ms between checking whether the virtual peer should notify the cluster of backpressure-on/backpressure-off."
              :type :integer
              :unit :milliseconds
              :optional? true
-             :default 10}
+             :default 10
+             :added "0.8.0"}

             :onyx.peer/backpressure-low-water-pct
             {:doc "Percentage of messaging inbound-buffer-size that constitutes a low water mark for backpressure purposes."
              :type :integer
              :optional? true
-             :default 30}
+             :default 30
+             :added "0.8.0"}

             :onyx.peer/backpressure-high-water-pct
             {:doc "Percentage of messaging inbound-buffer-size that constitutes a high water mark for backpressure purposes."
              :type :integer
              :optional? true
-             :default 60}
+             :default 60
+             :added "0.8.0"}

             :onyx.windowing/min-value
             {:doc "A default strict miminum value that `:window/window-key` can ever be. Note, this is generally best configured individually via :window/min-value in the task map."
              :type :integer
              :optional? true
-             :default 0}
+             :default 0
+             :added "0.8.0"}

             :onyx.zookeeper/backoff-base-sleep-time-ms
             {:doc "Initial amount of time to wait between ZooKeeper connection retries"
              :unit :milliseconds
              :optional? true
              :type :integer
-             :default 1000}
+             :default 1000
+             :added "0.8.0"}

             :onyx.zookeeper/backoff-max-sleep-time-ms
             {:doc "Maximum amount of time in ms to sleep on each retry"
              :unit :milliseconds
              :optional? true
              :type :integer
-             :default 30000}
+             :default 30000
+             :added "0.8.0"}

             :onyx.zookeeper/backoff-max-retries
             {:doc "Maximum number of times to retry connecting to ZooKeeper"
              :optional? true
              :type :integer
-             :default 5}
+             :default 5
+             :added "0.8.0"}

             :onyx.zookeeper/prepare-failure-detection-interval
             {:doc "Number of ms to wait between checking if the peer that joins this peer via prepare has failed. This value is used within a loop to periodically detect a false-positive case where a ZooKeeper ephemeral node is still present even though the process has (recently died). This value is only used within the prepare phase of joining a peer, and is not used for the normal failure detection path when a peer has fully joined the cluster."
              :unit :milliseconds
              :optional? true
              :type :integer
-             :default 1000}
+             :default 1000
+             :added "0.8.3"}

             :onyx.messaging/inbound-buffer-size
             {:doc "Number of messages to buffer in the core.async channel for received segments."
              :optional? true
              :type :integer
-             :default 50000}
+             :default 50000
+             :added "0.8.0"}

             :onyx.messaging/completion-buffer-size
             {:doc "Number of messages to buffer in the core.async channel for completing messages on an input task."
              :optional? true
              :type :integer
-             :default 10000}
+             :default 10000
+             :added "0.8.0"}

             :onyx.messaging/release-ch-buffer-size
             {:doc "Number of messages to buffer in the core.async channel for released completed messages."
              :optional? true
              :type :integer
-             :default 10000}
+             :default 10000
+             :added "0.8.0"}

             :onyx.messaging/retry-ch-buffer-size
             {:doc "Number of messages to buffer in the core.async channel for retrying timed-out messages."
              :optional? true
              :type :integer
-             :default 10000}
+             :default 10000
+             :added "0.8.0"}

             :onyx.messaging/peer-link-gc-interval
             {:doc "The interval in milliseconds to wait between closing idle peer links."
              :unit :milliseconds
              :optional? true
              :type :integer
-             :default 90000}
+             :default 90000
+             :added "0.8.0"}

             :onyx.messaging/peer-link-idle-timeout
             {:doc "The maximum amount of time that a peer link can be idle (not looked up in the state atom for usage) before it is eligible to be closed. The connection will be reopened from scratch the next time it is needed."
              :unit :milliseconds
              :optional? true
              :type :integer
-             :default 60000}
+             :default 60000
+             :added "0.8.0"}

             :onyx.messaging/ack-daemon-timeout
             {:doc "Number of milliseconds that an ack value can go without being updates on a daemon before it is eligible to time out."
              :unit :milliseconds
              :optional? true
              :type :integer
-             :default 480000}
+             :default 480000
+             :added "0.8.0"}

             :onyx.messaging/ack-daemon-clear-interval
             {:doc "Number of milliseconds to wait for process to periodically clear out ack-vals that have timed out in the daemon."
              :unit :milliseconds
              :optional? true
              :type :integer
-             :default 15000}
+             :default 15000
+             :added "0.8.0"}

             :onyx.messaging/decompress-fn
             {:doc "The Clojure function to use for messaging decompression. Receives one argument - a byte array. Must return the decompressed value of the byte array."
              :optional? true
              :type :function
-             :default 'onyx.compression.nippy/decompress}
+             :default 'onyx.compression.nippy/decompress
+             :added "0.8.0"}

             :onyx.messaging/compress-fn
             {:doc "The Clojure function to use for messaging compression. Receives one argument - a sequence of segments. Must return a byte array representing the segment seq."
              :optional? true
              :type :function
-             :default 'onyx.compression.nippy/compress}
+             :default 'onyx.compression.nippy/compress
+             :added "0.8.0"}

             :onyx.messaging/impl
             {:doc "The messaging protocol to use for peer-to-peer communication."
              :optional? false
              :type :keyword
-             :choices [:aeron]}
+             :choices [:aeron]
+             :added "0.8.0"}

             :onyx.messaging/bind-addr
             {:doc "An IP address to bind the peer to for messaging. Defaults to `nil`. When `nil`, Onyx binds to it's external IP to the result of calling `http://checkip.amazonaws.com`."
              :optional? false
              :type :string
-             :default nil}
+             :default nil
+             :added "0.8.0"}

             :onyx.messaging/external-addr
             {:doc "An IP address to advertise to other peers. Useful in case of firewalling, port forwarding, etc, where the interface/IP that is bound is different to the address that other peers should connect to."
              :optional? true
              :type :string
-             :default nil}
+             :default nil
+             :added "0.8.0"}

             :onyx.messaging/peer-port
             {:doc "Port that peers should use to communicate."
              :optional? false
              :type :integer
-             :default nil}
+             :default nil
+             :added "0.8.0"}

             :onyx.messaging/allow-short-circuit?
             {:doc "A boolean denoting whether to allow virtual peers to short circuit networked messaging when colocated with the other virtual peer. Short circuiting allows for direct transfer of messages to a virtual peer's internal buffers, which improves performance where possible. This configuration option is primarily for use in perfomance testing, as peers will not generally be able to short circuit messaging after scaling to many nodes."
              :optional? true
              :type :boolean
-             :default true}
+             :default true
+             :added "0.8.0"}

             :onyx.messaging.aeron/embedded-driver?
             {:doc "A boolean denoting whether an Aeron media driver should be started up with the environment. See [Aeron Media Driver](../../src/onyx/messaging/aeron_media_driver.clj) for an example for how to start the media driver externally."
              :optional? true
              :type :boolean
-             :default true}
+             :default true
+             :added "0.8.0"}

             :onyx.messaging.aeron/subscriber-count
             {:doc "The number of Aeron subscriber threads that receive messages for the peer-group.  As peer-groups are generally configured per-node (machine), this setting can bottleneck receive performance if many virtual peers are used per-node, or are receiving and/or de-serializing large volumes of data. A good guidline is is `num cores = num virtual peers + num subscribers`, assuming virtual peers are generally being fully utilised."
              :optional? true
              :type :integer
-             :default 2}
+             :default 2
+             :added "0.8.0"}

             :onyx.messaging.aeron/write-buffer-size
             {:doc "Size of the write queue for the Aeron publication. Writes to this queue will currently block once full."
              :optional? true
              :type :integer
-             :default 1000}
+             :default 1000
+             :added "0.8.0"}

             :onyx.messaging.aeron/poll-idle-strategy
             {:doc "The Aeron idle strategy to use between when polling for new messages. Currently, two choices `:high-restart-latency` and `:low-restart-latency` can be chosen. low-restart-latency may result in lower latency message, at the cost of higher CPU usage or potentially reduced throughput."
              :optional? true
              :type :keyword
              :default :high-restart-latency
-             :choices [:high-restart-latency :low-restart-latency]}
+             :choices [:high-restart-latency :low-restart-latency]
+             :added "0.8.0"}

             :onyx.messaging.aeron/offer-idle-strategy
             {:doc "The Aeron idle strategy to use between when offering messages to another peer. Currently, two choices `:high-restart-latency` and `:low-restart-latency` can be chosen. low-restart-latency may result in lower latency message, at the cost of higher CPU usage or potentially reduced throughput."
              :optional? true
              :type :keyword
              :default :high-restart-latency
-             :choices [:high-restart-latency :low-restart-latency]}
+             :choices [:high-restart-latency :low-restart-latency]
+             :added "0.8.0"}

             :onyx.messaging.aeron/publication-creation-timeout
             {:doc "Timeout after a number of ms on attempting to create an Aeron publication"
              :optional? true
              :type :integer
-             :default 1000}
+             :default 1000
+             :added "0.8.0"}
+
             :onyx.peer/state-log-impl
             {:doc "Choice of state persistence implementation."
              :optional? true
              :type :keyword
              :default :bookkeeper
-             :choices [:bookkeeper]}
+             :choices [:bookkeeper]
+             :added "0.8.0"}

             :onyx.bookkeeper/read-batch-size
             {:doc "Number of bookkeeper ledger entries to read at a time when recovering state. Effective batch read of state entries is write-batch-size * read-batch-size."
              :optional? true
              :type :integer
-             :default 50}
+             :default 50
+             :added "0.8.0"}

             :onyx.bookkeeper/write-batch-size
             {:doc "Number of state persistence writes to batch into a single BookKeeper ledger entry."
              :optional? true
              :type :integer
-             :default 20}
+             :default 20
+             :added "0.8.0"}

             :onyx.bookkeeper/write-batch-timeout
             {:doc "Maximum amount of time to wait while batching BookKeeper writes, before writing the batch to BookKeeper. In case of a full batch read, timeout will not be hit."
              :unit :milliseconds
              :optional? true
              :type :integer
-             :default 50}
+             :default 50
+             :added "0.8.0"}

             :onyx.bookkeeper/ledger-ensemble-size
             {:doc "The number of BookKeeper instances over which entries will be striped. For example, if you have an ledger-ensemble-size of 3, and a ledger-quorum-size of 2, the first write will be written to server1 and server2, the second write will be written to server2, and server3, etc."
              :optional? true
              :type :integer
-             :default 3}
+             :default 3
+             :added "0.8.0"}

             :onyx.bookkeeper/ledger-quorum-size
             {:doc "The number of BookKeeper instances over which entries will be written to. For example, if you have an ledger-ensemble-size of 3, and a ledger-quorum-size of 2, the first write will be written to server1 and server2, the second write will be written to server2, and server3, etc."
              :optional? true
              :type :integer
-             :default 3}
+             :default 3
+             :added "0.8.0"}

             :onyx.bookkeeper/ledger-id-written-back-off
             {:doc "Number of milliseconds to back off (sleep) after writing BookKeeper ledger id to the replica."
              :optional? true
              :type :integer
              :unit :milliseconds
-             :default 50}
+             :default 50
+             :added "0.8.0"}

             :onyx.bookkeeper/ledger-password
             {:doc "Password to use for Onyx state persisted to BookKeeper ledgers. Highly recommended this is changed on cluster wide basis."
              :optional? true
              :type :string
-             :default "INSECUREDEFAULTPASSWORD"}
+             :default "INSECUREDEFAULTPASSWORD"
+             :added "0.8.0"}

             :onyx.bookkeeper/client-throttle
             {:doc "Tunable write throttle for BookKeeper ledgers."
              :optional? true
              :type :integer
-             :default 30000}
+             :default 30000
+             :added "0.8.0"}

             :onyx.bookkeeper/write-buffer-size
             {:doc "Size of the buffer to which BookKeeper ledger writes are buffered via."
              :optional? true
              :type :integer
-             :default 10000}
+             :default 10000
+             :added "0.8.0"}

             :onyx.bookkeeper/client-timeout
             {:doc "BookKeeper client timeout."
              :optional? true
              :type :integer
              :unit :milliseconds
-             :default 60000}
+             :default 60000
+             :added "0.8.0"}

             :onyx.peer/state-filter-impl
             {:doc "Choice of uniqueness key filtering implementation."
              :optional? true
              :type :keyword
              :default :rocksdb
-             :choices [:rocksdb]}
+             :choices [:rocksdb]
+             :added "0.8.0"}

             :onyx.rocksdb.filter/base-dir
             {:doc "Temporary directory to persist uniqueness filtering data."
              :optional? true
              :type :string
-             :default "/tmp/rocksdb_filter"}
-
+             :default "/tmp/rocksdb_filter"
+             :added "0.8.0"}

             :onyx.rocksdb.filter/bloom-filter-bits
             {:doc "Number of bloom filter bits to use per uniqueness key value"
              :optional? true
              :type :integer
-             :default 10}
+             :default 10
+             :added "0.8.0"}

             :onyx.rocksdb.filter/compression
             {:doc "Whether to use compression in rocksdb filter. It is recommended that `:none` is used unless your uniqueness keys are large and compressible."
              :optional? true
              :type :string
              :choices [:bzip2 :lz4 :lz4hc :none :snappy :zlib]
-             :default :none}
+             :default :none
+             :added "0.8.0"}

             :onyx.rocksdb.filter/block-size
             {:doc "RocksDB block size. May worth being tuned depending on the size of your uniqueness-key values."
              :optional? true
              :type :integer
-             :default 4096}
+             :default 4096
+             :added "0.8.0"}
+
             :onyx.rocksdb.filter/peer-block-cache-size
             {:doc "RocksDB block cache size in bytes. Larger caches reduce the chance that the peer will need to check for the prescence of a uniqueness key on disk. Defaults to 100MB."
              :optional? true
              :type :integer
-             :default 104857600}
+             :default 104857600
+             :added "0.8.0"}

             :onyx.rocksdb.filter/num-buckets
             {:doc "Number of rotating filter buckets to use. Buckets are rotated every `:onyx.rocksdb.filter/num-ids-per-bucket`, with the oldest bucket being discarded if num-buckets already exist."
              :optional? true
              :type :integer
-             :default 10}
+             :default 10
+             :added "0.8.0"}

             :onyx.rocksdb.filter/num-ids-per-bucket
             {:doc "Number of uniqueness key values that can exist in a RocksDB filter bucket."
              :optional? true
              :type :integer
-             :default 10000000}
+             :default 10000000
+             :added "0.8.0"}
+
             :onyx.rocksdb.filter/rotation-check-interval-ms
             {:doc "Check whether filter bucket should be rotated every interval ms"
              :optional? true
              :type :integer
-             :default 50}}}
-:env-config
-{:summary "All options available to configure the node environment."
- :link nil
- :model {:zookeeper/server?
-         {:doc "Bool to denote whether to startup a local, in-memory ZooKeeper. **Important: for TEST purposes only.**"
-          :type :boolean
-          :optional? true}
-
-         :zookeeper.server/port
-         {:doc "Port to use for the local in-memory ZooKeeper"
-          :type :integer
-          :required-when ["The `:zookeeper/server?` is `true`."]}
-
-         :onyx/id
-         {:doc "The ID for the cluster that the peers will coordinate via. Provides a way to provide strong, multi-tenant isolation of peers."
-          :type [:one-of [:string :uuid]]
-          :required-when ["`:onyx.bookkeeper/server?` is `true`."]
-          :optional? true}
-
-         :zookeeper/address
-         {:doc "The addresses of the ZooKeeper servers to use for coordination e.g. 192.168.1.1:2181,192.168.1.2:2181"
-          :type :string
-          :optional? false}
-
-         :onyx.bookkeeper/server?
-         {:doc "Bool to denote whether to startup a BookKeeper instance on this node, for use in persisting Onyx state information."
-          :type :boolean
-          :default false
-          :optional? true}
-
-         :onyx.bookkeeper/delete-server-data?
-         {:doc "Bool to denote whether to delete all BookKeeper server instance data on environment shutdown. Set to true when using BookKeeper for unit/integration test runs."
-          :type :boolean
-          :default false
-          :optional? true}
-
-         :onyx.bookkeeper/local-quorum?
-         {:doc "Bool to denote whether to startup a full quorum of BookKeeper instances on this node. **Important: for TEST purposes only.**"
-          :default false
-          :type :boolean
-          :required-when ["The `:onyx.bookkeeper/server?` is `true` and `:onyx.bookkeeper/local-quorum?` is `true`"]
-          :optional? true}
-
-         :onyx.bookkeeper/local-quorum-ports
-         {:doc "Ports to use for the local BookKeeper quorum."
-          :type :vector
-          :default [3196 3197 3198]
-          :required-when ["The `:onyx.bookkeeper/server?` is `true` and `:onyx.bookkeeper/local-quorum?` is `true`"]
-          :optional? true}
-
-         :onyx.bookkeeper/port
-         {:doc "Port to startup this node's BookKeeper instance on."
-          :type :integer
-          :default 3196
-          :required-when ["The `:onyx.bookkeeper/server?` is `true` and `:onyx.bookkeeper/local-quorum?` is `false`"]}
-
-         :onyx.bookkeeper/base-journal-dir
-         {:doc "Directory to store BookKeeper's journal in. It is recommended that this is altered to somewhere fast, preferably on a different disk to the BookKeeper ledger."
-          :type :string
-          :default "/tmp/bookkeeper_journal"
-          :optional? true}
-
-         :onyx.bookkeeper/base-ledger-dir
-         {:doc "Directory to store BookKeeper's ledger in. It is recommended that this is altered to somewhere fast, preferably on a different disk to the BookKeeper journal"
-          :type :string
-          :default "/tmp/bookkeeper_ledger"
-          :optional? true}}}})
+             :default 50
+             :added "0.8.0"}}}
+
+   :env-config
+   {:summary "All options available to configure the node environment."
+    :link nil
+    :model {:zookeeper/server?
+            {:doc "Bool to denote whether to startup a local, in-memory ZooKeeper. **Important: for TEST purposes only.**"
+             :type :boolean
+             :optional? true
+             :added "0.8.0"}
+
+            :zookeeper.server/port
+            {:doc "Port to use for the local in-memory ZooKeeper"
+             :type :integer
+             :required-when ["The `:zookeeper/server?` is `true`."]
+             :added "0.8.0"}
+
+            :onyx/id
+            {:doc "The ID for the cluster that the peers will coordinate via. Provides a way to provide strong, multi-tenant isolation of peers."
+             :type [:one-of [:string :uuid]]
+             :required-when ["`:onyx.bookkeeper/server?` is `true`."]
+             :optional? true
+             :added "0.8.0"}
+
+            :zookeeper/address
+            {:doc "The addresses of the ZooKeeper servers to use for coordination e.g. 192.168.1.1:2181,192.168.1.2:2181"
+             :type :string
+             :optional? false
+             :added "0.8.0"}
+
+            :onyx.bookkeeper/server?
+            {:doc "Bool to denote whether to startup a BookKeeper instance on this node, for use in persisting Onyx state information."
+             :type :boolean
+             :default false
+             :optional? true
+             :added "0.8.0"}
+
+            :onyx.bookkeeper/delete-server-data?
+            {:doc "Bool to denote whether to delete all BookKeeper server instance data on environment shutdown. Set to true when using BookKeeper for unit/integration test runs."
+             :type :boolean
+             :default false
+             :optional? true
+             :added "0.8.0"}
+
+            :onyx.bookkeeper/local-quorum?
+            {:doc "Bool to denote whether to startup a full quorum of BookKeeper instances on this node. **Important: for TEST purposes only.**"
+             :default false
+             :type :boolean
+             :required-when ["The `:onyx.bookkeeper/server?` is `true` and `:onyx.bookkeeper/local-quorum?` is `true`"]
+             :optional? true
+             :added "0.8.0"}
+
+            :onyx.bookkeeper/local-quorum-ports
+            {:doc "Ports to use for the local BookKeeper quorum."
+             :type :vector
+             :default [3196 3197 3198]
+             :required-when ["The `:onyx.bookkeeper/server?` is `true` and `:onyx.bookkeeper/local-quorum?` is `true`"]
+             :optional? true
+             :added "0.8.0"}
+
+            :onyx.bookkeeper/port
+            {:doc "Port to startup this node's BookKeeper instance on."
+             :type :integer
+             :default 3196
+             :required-when ["The `:onyx.bookkeeper/server?` is `true` and `:onyx.bookkeeper/local-quorum?` is `false`"]
+             :added "0.8.0"}
+
+            :onyx.bookkeeper/base-journal-dir
+            {:doc "Directory to store BookKeeper's journal in. It is recommended that this is altered to somewhere fast, preferably on a different disk to the BookKeeper ledger."
+             :type :string
+             :default "/tmp/bookkeeper_journal"
+             :optional? true
+             :added "0.8.0"}
+
+            :onyx.bookkeeper/base-ledger-dir
+            {:doc "Directory to store BookKeeper's ledger in. It is recommended that this is altered to somewhere fast, preferably on a different disk to the BookKeeper journal"
+             :type :string
+             :default "/tmp/bookkeeper_ledger"
+             :optional? true
+             :added "0.8.0"}}}})

 (def model-display-order
   {:catalog-entry


Rename parameter in limit-params for clarity

--- cortex/src/cortex/optimise/descent.clj
+++ cortex/src/cortex/optimise/descent.clj
@@ -272,11 +272,11 @@
           (> (swap! num-steps* inc) n)))))

 (defn limit-params
-  [terminate? cutoff params]
+  [terminate? cutoff target]
   (fn [state]
     (or (terminate? state)
         (<= (m/distance (- (:params state)
-                           params))
+                           target))
             cutoff))))

 (defn limit-value


Dashboard: Open document via double-click

--- src-cljs/pepa/workflows/dashboard.cljs
+++ src-cljs/pepa/workflows/dashboard.cljs
@@ -174,10 +174,10 @@
 (defn ^:private click-loop! [state owner]
   (go-loop []
     (when-let [click (<! (om/get-state owner :clicks))]
-      (println "got click:" (pr-str click))
-      ;; TODO: handle double-click
-      (om/update-state! owner :selection (fn [selection]
-                                           (selection/click selection click)))
+      (if (= :double (::type click))
+        (nav/navigate! (nav/document-route {:id (:element click)}))
+        (om/update-state! owner :selection (fn [selection]
+                                             (selection/click selection click))))
       (recur))))

 ;; (defn on-document-click [state owner document])


Spans

Spans

--- src-cljs/main/githubcomments/core.cljs
+++ src-cljs/main/githubcomments/core.cljs
@@ -9,16 +9,22 @@
                                            render-user-content-markdown]]))

 (defn comment-to-li-tag [comment]
+  (prn comment)
   (html [:li.github-comment {:id (str "comment-" (:id comment))}
          [:div.github-comment-metadata
           (let [user (:user comment)]
-            (list [:a {:href (:html_url user)}
-                   [:img.github-avatar {:src (:avatar_url user)}]]
-                  [:a {:href (:html_url user)}
-                   [:p.github-comment-author (:login user)]]))]
-         [:div.github-comment-content (:body_html comment)]
-         [:div.github-comment-footer
-          [:a {:href (:html_url comment)} "View on GitHub"]]]))
+            [:p
+             [:a {:href (:html_url user)}
+              [:img.github-avatar {:src (:avatar_url user)}]]
+             [:a {:href (:html_url user)}
+              [:span.github-comment-author (:login user)]]
+             " commented at "
+             [:span.github-comment-date (:created_at comment)]
+             " on "
+             [:span.github-comment-commit
+              [:a {:href (:html_url comment)}
+               (subs (:commit_id comment) 0 7)]]])]
+         [:div.github-comment-content (:body_html comment)]]))

 (defn comments-to-ul [comments]
   (html [:ul (for [comment (take 10 comments)]


testing set action creation

testing set action creation

--- test/celestial/test/proxpect.clj
+++ test/celestial/test/proxpect.clj
@@ -1,7 +1,7 @@
 (ns celestial.test.proxpect
   (:use
     [proxmox.remote :only (prox-get)]
-    [proxmox.provider :only (vzctl)]
+    [proxmox.provider :only (vzctl enable-features)]
     expectations.scenarios)
   (:import
     [proxmox.provider Container])
@@ -18,12 +18,8 @@
   (stubbing [prox-get "stopped"]
     (expect java.lang.AssertionError (vzctl ct "nfs:on"))))

-
-; TODO move to expectations
-#_(deftest feature-enable
-  (let [action (atom "")
-        prox (reify Openvz
-               (vzctl [this a] (reset! action a))
-               (unmount [this]))]
-    (enable-features prox {:vmid 1 :features ["nfs:on"]})
-    (is (= @action "set 1 --features \"nfs:on\" --save"))))
+(scenario
+   (enable-features ct {:vmid 1 :features ["nfs:on"]})
+   (expect
+     (interaction (vzctl ct "set 1 --features \"nfs:on\" --save"))))
+


adding round

adding round

--- src/complex/pencil.cljc
+++ src/complex/pencil.cljc
@@ -138,6 +138,9 @@
 (def c-coords
   #(mapv n/coords %))

+(defn round [x]
+  (/ (int (* 100 x)) 100))
+
 (comment
   (require '[complex.pencil] :reload)
   (in-ns 'complex.pencil)
@@ -149,4 +152,14 @@
    [[0 2] [1 2] :infinity]
    [[0 3] [1 3] :infinity]
    [[0 4] [1 4] :infinity]]
+
+  (mapv c-coords
+        (generate-pencil [:up {:delta 1 :num-steps 4 :center [1 1]}]))
+  [[[1 2] [2 2] :infinity]
+   [[2 4] [3 4] :infinity]
+   [[3 6] [4 6] :infinity]
+   [[4 8] [5 8] :infinity]]
+
+  (mapv c-coords
+        (generate-pencil [:around {:delta 30 :num-steps 5}]))
   )


Update route docstrings

Update route docstrings

--- src/compojure/route.clj
+++ src/compojure/route.clj
@@ -13,7 +13,8 @@
 (defn files
   "A route for serving static files from a directory. Accepts the following
   keys:
-    :root - the root path where the files are stored. Defaults to 'public'."
+    :root       - the root path where the files are stored, defaults to 'public'
+    :mime-types - an optional map of file extensions to mime types"
   [path & [options]]
   (-> (GET (add-wildcard path) {{file-path :*} :route-params}
         (let [options (merge {:root "public"} options)]
@@ -23,7 +24,8 @@
 (defn resources
   "A route for serving resources on the classpath. Accepts the following
   keys:
-    :root - the root prefix to get the resources from. Defaults to 'public'."
+    :root       - the root prefix path of the resources, defaults to 'public'
+    :mime-types - an optional map of file extensions to mime types"
   [path & [options]]
   (-> (GET (add-wildcard path) {{resource-path :*} :route-params}
         (let [root (:root options "public")]


Remove debug println statement

Remove debug println statement

--- src/quil/applet.clj
+++ src/quil/applet.clj
@@ -234,7 +234,6 @@
         target            (if (empty? output-file) target :none)
         setup-fn          (fn []
                             (let [size-vec (concat size [renderer] output-file)]
-                              (println size-vec)
                               (apply applet-set-size size-vec))
                             (when-let [f (:setup options)]
                               (f)))


little extra space on the default max-height

--- src/datafrisk/core.cljs
+++ src/datafrisk/core.cljs
@@ -207,7 +207,7 @@
          (when visible?
            [:div {:style {:padding "10px"
                           ;; TODO Make the max height and width adjustable
-                          :max-height "300px"
+                          :max-height "400px"
                           :max-width "800px"
                           :height "100%"
                           :box-sizing "border-box"


Improve language select menu

Improve language select menu

--- desktop/src/nightweb_desktop/utils.clj
+++ desktop/src/nightweb_desktop/utils.clj
@@ -28,15 +28,15 @@
   (write-pref :update true))

 (defn change-lang
-  [lang-name]
-  (reset! lang lang-name)
-  (reset! lang-strings (-> (or (get lang-files lang-name)
-                               (get lang-files "English"))
-                           java.io/resource
-                           .toString
-                           xml/parse
-                           :content))
-  (write-pref :lang lang-name))
+  [lang-pref]
+  (let [lang-name (if (contains? lang-files lang-pref) lang-pref "English")]
+    (reset! lang lang-name)
+    (reset! lang-strings (-> (get lang-files lang-name)
+                             java.io/resource
+                             .toString
+                             xml/parse
+                             :content))
+    (write-pref :lang lang-name)))

 (change-lang @lang)


Working dna.clj

Working dna.clj

--- clojure/nucleotide-count/dna.clj
+++ clojure/nucleotide-count/dna.clj
@@ -1,7 +1,13 @@
 (ns dna)

+(defn nucleotide-counts [dna-string]
+  (let [empty {\A 0, \T 0, \C 0, \G 0}]
+    (merge-with + empty (frequencies dna-string))))
+
 (defn count [strand dna-string]
-  0)
+  (let [allowed-nucleotide [\A \T \C \G \U]]
+    (if (not (some #{strand} allowed-nucleotide))
+       (throw (Exception. "invalid nucleotide"))))

-(defn nucleotide-counts [dna-string]
-  {})+  (let [dna (nucleotide-counts dna-string)]
+    (get (nucleotide-counts dna-string) strand 0)))