Some refactoring and docstrings.

Some refactoring and docstrings.

--- src/ajaxify/main.cljs
+++ src/ajaxify/main.cljs
@@ -10,12 +10,18 @@
   (. jquery-object (html)))

 (defn main-text-from-load-container
+  "Extract the contents of the #mainText div from the container
+   it was loaded in. Removes the outer <div> tags (so they're
+   not duplicated."
   [container]
   (-> container
     (.find main-text-id)
     (html)))

-(defn load-content [anchor]
+(defn load-content
+  "Load the main text referred to by the anchor that the user clicked.
+   Updates the #mainText div asynchronously."
+  [anchor]
   (let [anchors-href (.attr anchor "href")
         to-load (str anchors-href " " main-text-id)
         load-container (js/jQuery "<span>")
@@ -26,16 +32,29 @@
           (.html main-text-element new-main-text)
           (.fadeIn main-text-element "fast"))))))))

-(defn current-page-relative-href []
+(defn current-page-relative-href
+  "Extract the relative URL of the current page.
+   e.g. (current-page-relative-href) on
+   http://web.mit.edu/rahulraj/www/index.html
+   returns 'index.html'."
+  []
   (let [location (.location js/window)
         url location/href
         parts (.split url "/")]
     (last parts)))

-(defn parent [jquery-object]
+(defn parent
+  "Get the parent of a JQuery object. Similar to html,
+   puts a facade around a no-argument method."
+  [jquery-object]
   (. jquery-object (parent)))

-(defn restyle-anchors [clicked-anchor]
+(defn restyle-anchors
+  "On any given page, the current page in the nav area
+   should be bolded and not an anchor, while the remaining
+   items in nav are anchors. When a new page is loaded, this
+   function updates the nav list items to reflect this."
+  [clicked-anchor]
   (let [current-page-href (current-page-relative-href)
         current-page-anchor (js/jQuery (str "<a href=" current-page-href ">"))
         current-page-list-item (js/jQuery "#currentPage")
@@ -51,15 +70,22 @@
     (site/removeEvents)
     (site/addHoverEventsToAnchors))))

-(defn update-history [clicked-anchor]
+(defn update-history
+  "Update the history so the URL is still valid,
+   given the clicked anchor (which is now Ajaxy)
+   TODO make the back button work too."
+  [clicked-anchor]
   (let [new-href (.attr clicked-anchor "href")]
     (.pushState js/history {} "State" new-href)))

-(defn ^:export on-anchor-click [anchor]
+(defn ^:export on-anchor-click
+  "Called on click of an anchor (the anchor is passed in)"
+  [anchor]
   ; TODO Use the History API to make back/forward work again.
-  (load-content anchor)
-  (restyle-anchors anchor)
-  (update-history anchor))
+  (doto anchor
+    (load-content)
+    (restyle-anchors)
+    (update-history)))

 (defn ^:export main
   "Entry point for the Clojurescript, to be called on load"


Use the correct options calling wunderboss' subscribe.

--- messaging/src/immutant/messaging.clj
+++ messaging/src/immutant/messaging.clj
@@ -305,7 +305,7 @@
     (.subscribe ^Topic (:destination topic) (name subscription-name)
       (message-handler f (:decode? options true))
       codecs/codecs
-      (o/extract-options options Topic$UnsubscribeOption))))
+      (o/extract-options options Topic$SubscribeOption))))

 (o/set-valid-options! subscribe
   (conj (o/opts->set Topic$SubscribeOption) :decode?))


fix glitchy scroll

fix glitchy scroll

--- src/name_bazaar/ui/components/infinite_list.cljs
+++ src/name_bazaar/ui/components/infinite_list.cljs
@@ -81,7 +81,8 @@
         "⌃"]])))

 (defn infinite-list []
-  (let [container-ref (r/atom nil)]
+  (let [container-ref (r/atom nil)
+        load-disabled? (r/atom false)]
     (fn [{:keys [:initial-load-limit :next-load-limit :offset :loading? :loading-spinner-delegate
                  :collapsed-item-height :on-infinite-load :on-initial-load :on-next-load
                  :total-count :no-items-element] :as props}
@@ -100,23 +101,26 @@
               {:class "infinite-list"
                :element-height @(subscribe [:infinite-list/items-heights (count list-items) collapsed-item-height])
                :use-window-as-scroll-container true
-               :infinite-load-begin-edge-offset 0
-               :is-infinite-loading (and loading? (not all-items-loaded?))
+               :infinite-load-begin-edge-offset -250
+               :is-infinite-loading (and loading?
+                                         (not all-items-loaded?)
+                                         (not @load-disabled?))
                :on-infinite-load (fn []
                                    (when (and (not loading?)
-                                              (not all-items-loaded?))
+                                              (not all-items-loaded?)
+                                              (not @load-disabled?))
+                                     (reset! load-disabled? true) ;; To prevent too many firings
+                                     (js/setTimeout #(reset! load-disabled? false) 300)
                                      (if (and (zero? offset)
                                               (empty? list-items))
-                                       (do
-                                         (when (fn? on-infinite-load)
-                                           (on-infinite-load 0 initial-load-limit))
-                                         (when on-initial-load
-                                           (on-initial-load 0 initial-load-limit)))
+                                       (when (fn? on-infinite-load)
+                                         (on-infinite-load 0 initial-load-limit))
                                        (let [next-offset (if (zero? offset) initial-load-limit (+ offset next-load-limit))]
-                                         (when (fn? on-initial-load)
-                                           (on-infinite-load next-offset next-load-limit))
-                                         (when (fn? on-next-load)
-                                           (on-next-load next-offset next-load-limit))))))
+                                         (when (= next-offset (count list-items))
+                                           (when (fn? on-initial-load)
+                                             (on-infinite-load next-offset next-load-limit))
+                                           (when (fn? on-next-load)
+                                             (on-next-load (min next-offset total-count) next-load-limit)))))))
                :loading-spinner-delegate (when (and loading? (not all-items-loaded?))
                                            loading-spinner-delegate)}
               (dissoc props :initial-load-limit :next-load-limit :offset :loading? :loading-spinner-delegate


Missed a branch on key-lt

Missed a branch on key-lt

--- src/aurora/btree.cljs
+++ src/aurora/btree.cljs
@@ -89,7 +89,8 @@
                        (< a b))
                   (< (typeof a) (typeof b)))
             true
-            false))))))
+            false))
+        false))))

 (defn ^boolean key-gt [as bs]
   (== 1 (key-compare as bs)))


Split correctly

Split correctly

--- src/aurora/btree.cljs
+++ src/aurora/btree.cljs
@@ -81,8 +81,8 @@
                 (set! (.-lower right-node) (.-lower (aget children (+ median 1))))))
             (set! (.-keys right-node) (.slice keys (+ median 1)))
             (set! (.-vals right-node) (.slice vals (+ median 1)))
-            (.splice keys median (+ median 1))
-            (.splice vals median (+ median 1))
+            (.splice keys median (alength keys))
+            (.splice vals median (alength vals))
             (when-not (nil? children)
               (let [right-children (.slice children (+ median 1))]
                 (dotimes [ix (alength right-children)]
@@ -90,12 +90,13 @@
                     (set! (.-parent child) right-node)
                     (set! (.-parent-ix child) ix)))
                 (set! (.-children right-node) right-children)
-                (.splice children median (+ median 2))))
-            (.valid! this (js/Math.floor (/ max-keys 2)) max-keys)
-            (.valid! right-node (js/Math.floor (/ max-keys 2)) max-keys)
+                (.splice children (+ median 1) (alength children))))
+            #_(.valid! this (js/Math.floor (/ max-keys 2)) max-keys)
+            #_(.valid! right-node (js/Math.floor (/ max-keys 2)) max-keys)
             (.insert! parent parent-ix median-key median-val right-node max-keys)))
   (valid! [this min-keys max-keys]
-          (assert (>= (count keys) min-keys) (pr-str keys min-keys))
+          (when (instance? Node parent) ;; root is allowed to have less keys
+            (assert (>= (count keys) min-keys) (pr-str keys min-keys)))
           (assert (<= (count keys) max-keys) (pr-str keys max-keys))
           (assert (= (count keys)) (inc (count children)))
           (assert (= (count keys) (count (set keys))))
@@ -107,8 +108,8 @@
               (assert (= lower (aget keys 0)) (pr-str lower keys))
               (assert (= upper (aget keys (- (alength keys) 1)))))
             (do
-              (assert (= lower (.-lower (aget children 0))))
-              (assert (= upper (.-upper (aget children (- (alength children) 1)))))
+              (assert (= lower (.-lower (aget children 0))) (pr-str lower (.-lower (aget children 0))))
+              (assert (= upper (.-upper (aget children (- (alength children) 1)))) (pr-str upper (.-upper (aget children (- (alength children) 1)))))
               (assert (every? #(> (aget keys %) (.-upper (aget children %))) (range (count keys))))
               (assert (every? #(< (aget keys %) (.-lower (aget children (inc %)))) (range (count keys))))
               (dotimes [i (count children)] (.valid! (aget children i) min-keys max-keys))))))
@@ -213,9 +214,6 @@
     (.assoc! tree :e 1)
     (.assoc! tree :f 1)
     (.assoc! tree :g 1)
-    (.assoc! tree :h 1)
-    (.assoc! tree :i 1)
-    (.assoc! tree :j 1)
     (js/console.log tree)
     (.valid! tree)
     tree)


don't throw exception if no lexical complement

--- src/babel/forest.cljc
+++ src/babel/forest.cljc
@@ -252,8 +252,8 @@
                          (str " " (string/join "," (map morph (take 5 complement-candidate-lexemes))) ".. and "
                               (- (count complement-candidate-lexemes) 5) " more."))]
                 (log/error message)
-                (throw (exception message)))
-
+;                (throw (exception message)))
+)
               (do (log/trace (str "add-complement after adding complement: "
                                   (string/join ","
                                                (map (fn [each]


Added more producers

Added more producers

--- src/catalog/vubis.clj
+++ src/catalog/vubis.clj
@@ -131,7 +131,8 @@

 (def producer-raw-to-producer
   "Mapping between producer-raw and producer"
-  {1   "DBH, Marburg"
+  {0   "Anderer/unbekannter Produzent"
+   1   "Blista, Marburg"
    2   "BBH, Berlin"
    4   "NBH, Hamburg"
    5   "BBH, München"
@@ -139,39 +140,47 @@
    7   "Blindenhörbücherei des Saarlandes"
    8   "SBH, Stuttgart"
    9   "EBS, Marburg"
+   10  "CFB, Hamburg"
    11  "DKBB, Bonn"
    13  "SBS, Zürich"
    24  "DZB, Leipzig"
    25  "CAB, Landschlacht"
    26  "Reformierte Blindenpflege Zürich"
+   30  "VzFB, Hannover"
+   31  "BBI, Wien"
    32  "Paderborn"
+   33  "Zollikofen"
+   34  "CBD, Wernigerode"
    40  "BIT, München"
    50  "BSVÖ, Wien"
-   100 "SBS, Zürich"
-   101 "Blista, Marburg"
-   102 "DZB, Leipzig"
-   103 "Paderborn"
-   104 "VzFB, Hannover"
-   105 "BIT, München"
-   106 "BBI, Wien"
-   107 "EBS, Wernigerode"
-   108 "Zollikofen"
+   103 "Planer-Regis, Berkenthin"
    109 "ONCE, Madrid"
-   110 "SZB, St. Gallen"
-   111 "RNIB, London"
-   112 "Velen Integrationsspiel"
-   113 "Monza"
-   114 "IKS, Kassel"
-   115 "DBB, Kopenhagen"
-   116 "AVH, Paris"
+   112 "Freunde blinder und sehbehinderter Kinder, Hamburg"
+   113 "The Princeton Braillists, Princeton"
+   115 "Nota, Kopenhagen"
    117 "VA, Melbourne"
    118 "SALB, Grahamstown"
-   119 "ABWA"
-   120 "Braillists, Princeton"
+   119 "Visability, Victoria Park"
    121 "Bartkowski, München"
-   122 "Freunde blinder und sehbehinderter Kinder, Hamburg"
    123 "Braille-Kinderbücher, Düren"
-   124 "Berlin, Anderes Sehen"})
+   124 "Berlin, Anderes Sehen"
+   128 "IKS, Kassel"
+   140 "Velen Integrationsspiele, Neuwied"
+   153 "Vogel, Hamburg"
+   154 "Alexander Reuss, Schwetzingen/Strassburg"
+   159 "Blindenunterrichtsanstalt, Frankfurt"
+   242 "SZB, St. Gallen"
+   248 "B. Lang, Freiburt im Üechtland"
+   250 "Blindenunterichtsanstalt, Ilzach"
+   305 "RNIB, London"
+   350 "Biblioteca Italiana per Ciechi, Monza"
+   401 "American Braille Press, Paris"
+   402 "American Foundation for Overseas Blind, Paris"
+   404 "Association pour nos Aveugles, Paris"
+   405 "AVH, Paris"
+   407 "Institut Nationale des Jounes Aveugles, Paris"
+   490 "Stamperia Nazionale Braille, Florenz"
+   508 "American Printing House for the Blind, Louisville"})

 (def genre-code-to-genre
   "Mapping between genre-code and genre. Used for movies"


Trim names

Trim names

--- src/catalog/vubis.clj
+++ src/catalog/vubis.clj
@@ -175,7 +175,10 @@
   "Change a name from 'name, surname' to 'surname name'"
   [name]
   (when name
-    (string/join " " (reverse (string/split name #",")))))
+    (->> (string/split name #",")
+         reverse
+         (string/join " ")
+         string/trim)))

 (defn clean-raw-item
   "Return a proper production based on a raw item, i.e.


Check SNAPSHOT dependencies before push to travis

When starting a release, checks that there are no snapshot dependencies.

Closes #8

--- src/leiningen/pallet_release/release.clj
+++ src/leiningen/pallet_release/release.clj
@@ -82,8 +82,9 @@
   (lein/test project)
   (println)
   (git/release-start new-version)
+  (lein/update-versions project old-version new-version)
+  (lein/pom)                        ; checks for snapshot dependencies
   (update-release-notes old-version new-version)
-  (lein/update-versions project old-version new-version)
   (spit ".pallet-release" new-version)
   (println)
   (println (release-notes new-version))


Empty state for no projects

Empty state for no projects

--- src-cljs/frontend/components/pages/projects.cljs
+++ src-cljs/frontend/components/pages/projects.cljs
@@ -15,7 +15,7 @@

 (defn- table [projects]
   (om/build table/table
-            {:rows (filter #(< 0 (count (:followers %))) projects)
+            {:rows projects
              :columns [{:header "Project"
                         :cell-fn #(vcs-url/repo-name (:vcs_url %))}

@@ -51,6 +51,19 @@
                                             "Select your GitHub "
                                             (when bitbucket-enabled? "or Bitbucket ")
                                             "organization (or username) to view your projects.")}))))
+
+(defn- no-projects-available [org]
+  (component no-projects-available
+    (empty-state/empty-state {:icon (html [:i.material-icons "book"])
+                              :heading (html
+                                        [:span
+                                         [:b (:name org)]
+                                         " has no projects building on CircleCI"])
+                              :subheading "Let's fix that by adding a new project."
+                              :action (html
+                                       [:a.btn.btn-primary
+                                        {:href (routes/v1-add-projects)}
+                                        "Add Project"])})))

 (defn- organization-ident
   "Builds an Om Next-like ident for an organization."
@@ -114,8 +127,11 @@
                   "github" [:i.octicon.octicon-mark-github]
                   "bitbucket" [:i.fa.fa-bitbucket]
                   nil)])
-              (if (:projects selected-org)
-                (table (:projects selected-org))
+              (if-let [projects (:projects selected-org)]
+                (if-let [projects-with-followers
+                         (seq (filter #(< 0 (count (:followers %))) projects))]
+                  (table projects-with-followers)
+                  (no-projects-available selected-org))
                 (html [:div.loading-spinner common/spinner])))
              (no-org-selected available-orgs (vcs-utils/bitbucket-enabled? user)))]])))))


remove cancel button from not-run workflows

--- src-cljs/frontend/components/pieces/run_row.cljs
+++ src-cljs/frontend/components/pieces/run_row.cljs
@@ -36,8 +36,7 @@
     :run-status/needs-setup :status-class/setup-needed
     :run-status/on-hold :status-class/on-hold))

-(def ^:private cancelable-statuses #{:run-status/not-run
-                                     :run-status/running
+(def ^:private cancelable-statuses #{:run-status/running
                                      :run-status/on-hold})

 (def ^:private rerunnable-statuses #{:run-status/succeeded


.suspended-notice class, for easier webdriver testing.

--- src-cljs/frontend/components/project/common.cljs
+++ src-cljs/frontend/components/project/common.cljs
@@ -177,11 +177,10 @@
       (let [org-name (:org_name plan)
             plan-path (routes/v1-org-settings-subpage {:org org-name :subpage "billing"})]
         (html
-         [:div
-          [:div.alert {:class "alert-danger"}
-           (list org-name
-                 "'s plan has been suspended! "
-                 (if (plan-model/admin? plan)
-                   (list "Please " [:a {:href plan-path} "update your billing info "]
-                         " in order to continue using paid containers.")
-                   (list "Please ask an administrator to update your billing info.")))]])))))
+         [:div.alert.alert-danger.suspended-notice
+          (list org-name
+                "'s plan has been suspended! "
+                (if (plan-model/admin? plan)
+                  (list "Please " [:a {:href plan-path} "update your billing info "]
+                        " in order to continue using paid containers.")
+                  (list "Please ask an administrator to update your billing info.")))])))))


missing exclamation mark

missing exclamation mark

--- src/clj/hsm/views.clj
+++ src/clj/hsm/views.clj
@@ -228,8 +228,8 @@
   analytics.load('eqMNHeqB0Ukx8AWah4nKiwFwaxbeJlGg');
   analytics.page();}}();
 ")
-(format`
-"function(){window.jstag=function(e){var t=!1,n=window,r=document,i='/js/io',s=Array.prototype.slice,o=e.url||'';return n.jstag||{load:function(){var e,s=r.getElementsByTagName('script')[0];return t=!0,'JSON'in n&&Array.prototype.forEach||(i+='w'),r.getElementById(i)?this:(e=r.createElement('script'),e.id=i,e.src=o+i+'.min.js',s.parentNode.insertBefore(e,s),this)},_q:[],_c:e,bind:function(e){this._q.push([e,s.call(arguments,1)])},ready:function(){this._q.push(['ready',s.call(arguments)])},send:function(){return t||this.load(),this._q.push(['ready','send',s.call(arguments)]),this},ts:(new Date).getTime()}
+(format
+"!function(){window.jstag=function(e){var t=!1,n=window,r=document,i='/js/io',s=Array.prototype.slice,o=e.url||'';return n.jstag||{load:function(){var e,s=r.getElementsByTagName('script')[0];return t=!0,'JSON'in n&&Array.prototype.forEach||(i+='w'),r.getElementById(i)?this:(e=r.createElement('script'),e.id=i,e.src=o+i+'.min.js',s.parentNode.insertBefore(e,s),this)},_q:[],_c:e,bind:function(e){this._q.push([e,s.call(arguments,1)])},ready:function(){this._q.push(['ready',s.call(arguments)])},send:function(){return t||this.load(),this._q.push(['ready','send',s.call(arguments)]),this},ts:(new Date).getTime()}
 }({cid:'report',url:'//%s/',path:'',idpath:''});jstag.send({data:1});}();" (if is-dev? "dev.strck.hackersome.com" "strck.hackersome.com"))
           )
         ])


shorted version on footer

shorted version on footer

--- src/clj/hsm/views.clj
+++ src/clj/hsm/views.clj
@@ -9,6 +9,8 @@
     [hsm.conf           :refer [languages]]))

 (def VERSION (try (slurp "VERSION") (catch Throwable t)))
+
+(def SHORTVERSION (try (subs VERSION 0 8) (catch Throwable t VERSION) ))

 (defhtml row-fluid
   [& content]
@@ -127,7 +129,7 @@
           [:div.col-lg-10.col-lg-offset-1
           [:p "Designed, built and made in Amsterdam with all the love by" [:a {:href "http://twitter.com/bahadircambel"} "@bcambel"]]
           [:p
-            "Running version  " [:a {:href (str "https://github.com/bcambel/hackersome/commit/" VERSION)} (str "@" VERSION)]]
+            "Running version  " [:a {:href (str "https://github.com/bcambel/hackersome/commit/" VERSION)} (str "@" SHORTVERSION)]]
           [:p "Code licensed under " [:a {:href "https://github.com/bcambel/hackersome/blob/development/LICENSE"} :MIT]]
           [:hr]
           [:p


Added write-index

Added write-index

--- src/clj_git/index.clj
+++ src/clj_git/index.clj
@@ -1,5 +1,6 @@
 (ns clj-git.index
   (:use clj-message-digest.core)
+  (:use clojure.java.io)
   (:use clj-git.util)
   (:use clj-git.repo)
   (:use clj-git.file)
@@ -42,6 +43,13 @@
             (wchars (hex-bytes (sha-1-hex (byte-array (.toByteArray out)))))
           ))
     out))
+
+(defn write-index
+  ( [index-struct] (write-index index-struct (str (git-root) "index")))
+  ( [index-struct filepath]
+    (with-open [wrtr (output-stream filepath)]
+      (doseq [b (byte-seq (build-index index-struct))]
+        (.write wrtr b)))))

 ;TODO Check validation bits to ensure correct parsing
 (defn read-index


Added dragging

Added dragging

Signed-off-by: Christian Romney <78cb0763aa1664e7dd86fd558ae466f67ab17826@pointslope.com>

--- src/cljs/svg/app.cljs
+++ src/cljs/svg/app.cljs
@@ -1,7 +1,14 @@
 (ns svg.app
-  (:require [reagent.core :as r :refer [atom]]))
+  (:require [reagent.core :as r :refer [atom]]
+            [goog.string :as gstring]
+            [goog.string.format]
+            [goog.fx :as fx]
+            [goog.fx.Dragger.EventType]
+            [goog.events]
+            [goog.events.EventType]
+            [goog.math :as gmath]))

-(defonce app-db (atom {:x 300 :y 100 :radius 10 :fill nil :clicks 0}))
+(defonce app-db (atom {:x 360 :y 360 :radius 50 :fill nil :clicks 0}))

 (defonce history (atom {:states []}))

@@ -51,9 +58,51 @@
             :r @r :style {:fill @fill}
             :onClick (fn [e] (swap! score inc))}])

+(defn make-constraint
+  "Creates a function that keeps a supplied number within the set bounds"
+  [minimum maximum]
+  (fn [num]
+    (let [local-max (if (<= num maximum) num maximum)]
+      (if (<= minimum local-max) local-max minimum))))
+
+(def draggable-circle-component
+  (with-meta circle-component
+    {:component-did-mount
+     (fn [this]
+       (let [node (r/dom-node this)
+             canvas (-> node .-parentNode)
+             x-constraint (->> canvas .-clientWidth (make-constraint 0))
+             y-constraint (->> canvas .-clientHeight (make-constraint 0))]
+
+         (goog.events/listen
+          node
+          goog.events.EventType/MOUSEDOWN
+          (fn [e]
+            (let [drag (fx/Dragger. node)]
+
+              ;; Drag event handler
+              (.addEventListener
+               drag
+               goog.fx.Dragger.EventType/DRAG
+               (fn [b]
+                 (let [dx (-> b .-dragger .-deltaX)
+                       dy (-> b .-dragger .-deltaY)
+                       x (x-constraint
+                          (+ dx (:x @app-db)))
+                       y (y-constraint
+                          (+ dy (:y @app-db)))]
+                   (swap! app-db assoc :x x :y y))))
+
+              ;; Drag end
+              (.addEventListener drag goog.fx.Dragger.EventType/END #(.dispose drag))
+
+              ;; Initialize
+              (.startDrag drag e))))))}))
+
+
 (defn range-component [v min max title]
   [:div {:class "form-group"}
-   [:label {:for title} title]
+   [:label {:for title} title [:small " [ " @v " ] "]]
    [:input {:type "range"
             :class "form-control"
             :name title
@@ -84,7 +133,7 @@
             [:option {:value c :key c} c])]]))))

 (defn svg-component [circle]
-  [:svg {:width "720" :height "720"}
+  [:svg {:width "720" :height "720" :id "canvas" :style {:outline "1px solid black"}}
    circle])

 (defn app-component []
@@ -93,15 +142,15 @@
         radius (r/cursor app-db [:radius])
         fill (r/cursor app-db [:fill])
         clicks (r/cursor app-db [:clicks])
-        circle [circle-component x y radius fill clicks]]
+        circle [draggable-circle-component x y radius fill clicks]]
     (fn []
       [:div {:id "wrapper"}
        [:div {:id "controls" :class "col-md-3"}
         [history-component app-db]
         [click-count-component clicks]
-        [range-component x 300 700 "CX"]
-        [range-component y 100 500 "CY"]
-        [range-component radius 10 100 "Size"]
+        [range-component x 0 720 "CX"]
+        [range-component y 0 720 "CY"]
+        [range-component radius 1 100 "Size"]
         [select-component]]
        [:div {:class "col-md-9"}
         [svg-component circle]]])))


more examples

more examples

--- src/codemash/core.clj
+++ src/codemash/core.clj
@@ -6,11 +6,11 @@
     your ears if  you listen for to long.
     Ears are useful, volume down, avoid ear phones if possible.

-  Mission:
-    * Create instruments
-    * Use instruments
-    * Manupliate instruments live
-    * Maybe Music?
+  Musical Mission:
+    * Create instruments new heard before.
+    * Use instruments for greater good.
+    * Bend/Manupliate instruments live.
+    * Maybe Music...
 "
   (:use overtone.live)
   (:require [codemash.graphs :as graph]))
@@ -38,11 +38,10 @@
 ;; play{d=Duty;f=d.kr(1/[1,2,4],0,Dseq([0,3,7,12,17]+24,inf));GVerb.ar(Blip.ar(f.midicps*[1,4,8],LFNoise1.kr(1/4,3,4)).sum,200,8)}

 (defsynth pop [freq 300]
-  (let [sin1 (* 1.1 (sin-osc freq))
-        sin2 (sin-osc freq)
-        sin3 (* 0.9 (sin-osc freq))
-        src (mix [sin1 sin2 sin3])]
-    (out 0 (* amp (pan2 src)))))
+  (let [src (sin-osc freq)]
+    (out 0 src)))
+
+(show-graphviz-synth pop)

 (def p (pop))

@@ -52,18 +51,44 @@

 ;;UGENS - Unit generators (Sweet shop)

-(defsynth foo [freq 200 dur 0.5]
-  (let [src (saw [freq (* freq 1.01) (* 0.99 freq)])
-        low (sin-osc (/ freq 2))
-        filt (lpf src (line:kr (* 10 freq) freq 10))
-        env (env-gen (perc 0.1 dur) :action FREE)]
-    (out 0 (pan2 (* 0.8 low env filt)))))
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;Busses - Wiring synths         ;;
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
-(defonce tri-bus (audio-bus)) ;;Audio busses are just ids preallocated at boot.
+(defsynth ding [freq 880 dur 0.2 level 0.25 pan 0.0 out-bus 0]
+  (let [amp  (env-gen:ar (env-perc) :action FREE :time-scale dur)
+        snd (* (sin-osc:ar freq ) amp level)]
+    (out out-bus (pan2:ar snd pan))))
+
+(defsynth tick [freq 880 dur 0.1 level 0.25 pan 0.0 out-bus 0]
+  (let [amp (env-gen (env-perc) :action FREE :time-scale dur)
+        snd (lpf:ar (white-noise:ar) freq)]
+    (out out-bus (pan2:ar (* snd amp level) pan))))
+
+(defsynth woody-beep [freq 300 out-bus 0 dur 0.4]
+  (let [tri (* 0.5 (lf-tri:ar freq))
+        sin (sin-osc:ar (* 1 freq))
+        sin2 (sin-osc:ar (* 1.01 freq))
+        wood (bpf:ar (* (white-noise:ar) (line:kr 5 0 0.02)) freq 0.02)
+        src (mix [sin sin2 tri wood])
+        src (free-verb src)
+        env (env-gen:ar (env-perc :release 0.25) :action FREE :time-scale dur)]
+    (out out-bus (pan2 (* env src)))))
+
+(woody-beep :freq 400)
+
+(kill woody-beep)
+(show-graphviz-synth ding)
+
+(ding)
+(tick)
+
+;;Samples
+
+(def subby-s (freesound-sample))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;Busses - Wiring synths ;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;;Audio busses are just ids preallocated at boot.
+(defonce tri-bus (audio-bus))
 (defonce sin-bus (audio-bus))

 (println sin-bus)
@@ -75,35 +100,28 @@

 (defonce main-g  (group "main"))
 (defonce early-g (group "early" :head main-g))
-(defonce lateroot-g (group "late"  :after early-g))
-
-(def tri-synth-inst (tri-synth [:tail early-g] tri-bus))
-(def sin-synth-inst (sin-synth [:tail early-g] sin-bus))
-
-(defsynth modulated-vol-tri [vol-bus 0 freq 220]
-  (out 0 (pan2 (* (in:kr vol-bus) (lf-tri freq)))))
+(defonce late-g  (group "late"  :after early-g))
+
+(def tri-synth-inst (tri-synth [:tail early-g] :out-bus tri-bus))
+(def sin-synth-inst (sin-synth [:tail early-g] :out-bus sin-bus))

 (defsynth modulated-freq-tri [freq-bus 0 mid-freq 220 freq-amp 55]
   (let [freq (+ mid-freq (* (in:kr freq-bus) freq-amp))]
     (out 0 (pan2 (lf-tri freq)))))

 (comment
-  (def mvt (modulated-vol-tri [:tail lateroot-g] sin-bus))
-  (def mft (modulated-freq-tri [:tail lateroot-g] sin-bus)))
+  (def mft (modulated-freq-tri [:tail late-g] sin-bus)))

 (comment
-  (ctl mft :freq-bus tri-bus))
+  (ctl mft :freq-bus sin-bus))

 (comment
   (ctl tri-synth-inst :freq 0.5))

 (comment
-  (ctl mvt :vol-bus tri-bus))
-
-(comment
   (do
-    (kill mft)
-    (kill mvt)))
+    (kill mft))
+  )

 ;;;;;;;;;;;;;;;
 ;;Instruments;;
@@ -111,7 +129,12 @@

 ;;Sampled
 (comment (require 'overtone.inst.sampled-piano))
-(require '[overtone.inst.piano])
+(require '[overtone.inst.piano :as piano])
+
+(require '[overtone.inst.sampled-piano :as s-piano])
+
+(piano/piano :note 50)
+(s-piano/sampled-piano :note 50)

 ;;Processing GUI
 (require '[quil.core :as q :refer [defsketch]])
@@ -119,8 +142,6 @@
 ;;;;;;;;;;
 ;;Timing;;
 ;;;;;;;;;;
-
-(require '[overtone.synth.timing :as timing])

 (defonce timing-g (group "codemash timing" :tgt (foundation-safe-pre-default-group)))

@@ -142,24 +163,119 @@
 (defsynth divider [div 32 in-bus 0 out-bus 0]
   (out:kr out-bus (pulse-divider (in:kr in-bus) div)))

-(defonce root-count   (counter [:head timing-g] :in-bus root-trigger-bus :out-bus root-count-bus))
 (defonce root-trigger (trigger [:head timing-g] :rate 100 :in-bus root-trigger-bus))
-(defonce beat-trigger (divider [:after root-count] :div current-beat :in-bus root-trigger-bus :out-bus beat-trigger-bus))
+(defonce root-count   (counter [:after root-trigger] :in-bus root-trigger-bus :out-bus root-count-bus))
+(defonce beat-trigger (divider [:after root-trigger] :div current-beat :in-bus root-trigger-bus :out-bus beat-trigger-bus))
 (defonce beat-count   (counter [:after beat-trigger] :in-bus beat-trigger-bus :out-bus beat-count-bus))
 (defsynth get-beat [] (send-trig (in:kr beat-trigger-bus) count-trigger-id (+ (in:kr beat-count-bus) 1)))

-(get-beat)
-
+(defonce beat (get-beat [:after beat-count]))

 (require '[overtone.inst.drum :as drum])
 (on-trigger count-trigger-id (fn [x] (drum/kick)) ::beat-watch)

-(ctl beat-trigger :div 60)
+(ctl beat-trigger :div 10)
 (ctl root-trigger :rate 100)

 (comment (remove-event-handler ::beat-watch))

-;; Timing and Buffers
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;Building Sequencer with buffers;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(def beats-g (group "beats"))
+
+(def kick-s (load-sample "~/Workspace/music/samples/sliced-p5/kick.aif"))
+
+(defonce kick-sequencer-buffer (buffer 8))
+
+(sample-player kick-s)
+
+(defsynth mono-sequencer
+  [buf 0 rate 1 out-bus 0 beat-num 0 sequencer 0 numsteps 8 amp 1]
+  (let [cnt      (in:kr beat-count-bus)
+        beat-trg (in:kr beat-trigger-bus)
+        bar-trg  (and (buf-rd:kr 1 sequencer cnt)
+                      (= beat-num (mod cnt numsteps))
+                      beat-trg)
+        vol      (set-reset-ff bar-trg)]
+    (out
+     out-bus (* vol
+                amp
+                (pan2
+                 (rlpf
+                  (scaled-play-buf 1 buf rate bar-trg)
+                  (demand bar-trg 0 (dbrown 200 20000 50 INF))
+                  (lin-lin:kr (lf-tri:kr 0.01) -1 1 0.1 0.9)))))))
+
+
+(def kicks
+  (doall
+   (for [x (range 8)]
+     (mono-sequencer [:tail beats-g] :buf kick-s :beat-num x
+                     :sequencer kick-sequencer-buffer))))
+
+(buffer-write! kick-sequencer-buffer [1 0 0 0 0 1 0 0])
+
+(defonce tom-sequencer-buffer (buffer 8))
+(defonce tom-s (load-sample "~/Workspace/music/samples/sliced-p5/tom.aif"))
+
+(def toms
+  (doall
+   (for [x (range 8)]
+     (mono-sequencer [:tail beats-g] :buf tom-s :beat-num x
+                     :sequencer tom-sequencer-buffer))))
+
+(buffer-write! tom-sequencer-buffer [0 0 1 0 0 0 1 0])
+
+(defonce shake-sequencer-buffer (buffer 8))
+(defonce shake-s (load-sample "~/Workspace/music/samples/sliced-p5/shaker.aif"))
+
+(def shakes
+  (doall (for [x (range 8)]
+           (mono-sequencer [:tail beats-g] :buf shake-s :beat-num x
+                           :sequencer shake-sequencer-buffer))))
+
+(buffer-write! shake-sequencer-buffer [0 1 0 0 0 0 0 0])
+
+(defonce shake2-s (load-sample "~/Workspace/music/samples/sliced-p5/double-shake.aif"))
+(defonce shake2-sequencer-buffer (buffer 8))
+
+(def shakes2
+  (doall
+   (for [x (range 8)] (mono-sequencer [:tail beats-g] :buf shake2-s :beat-num x
+                                      :sequencer shake2-sequencer-buffer))))
+
+(buffer-write! shake2-sequencer-buffer [0 0 0 1 0 0 0 0])
+
+(defonce shake2d-s (load-sample "~/Workspace/music/samples/sliced-p5/double-shake-deep.aif"))
+(defonce shake2d-sequencer-buffer (buffer 8))
+
+(def shakes2d
+  (doall
+   (for [x (range 8)] (mono-sequencer [:tail beats-g] :buf shake2d-s :beat-num x
+                     :sequencer shake2d-sequencer-buffer))))
+
+(buffer-write! shake2d-sequencer-buffer [0 0 0 0 0 0 0 1])
+
+
+(defonce shake1-s      (load-sample "~/Workspace/music/samples/sliced-p5/single-shake.aif"))
+
+(defonce shake1-sequencer-buffer (buffer 8))
+
+(def shakes1
+  (doall
+   (for [x (range 8)] (mono-sequencer [:tail beats-g] :buf shake1-s :beat-num x
+                     :sequencer shake1-sequencer-buffer))))
+
+(buffer-write! shake1-sequencer-buffer [0 0 0 0 1 0 0 0])
+
+
+(stop)
+
+;;;;;;;;;;;;;;;;;;;;;;;
+;; Timing and Buffers;;
+;;;;;;;;;;;;;;;;;;;;;;;

 (require '[codemash.timing :as time])

@@ -209,22 +325,94 @@
 (kill mid)
 (stop)

-;;;;;;;;;;;;;;;;;;;;;;;;
-;;Creating a Sequencer;;
-;;;;;;;;;;;;;;;;;;;;;;;;
-
-(def b (buffer 256))
-
-;;Samples
+;;;;;;;;;;;;;;;;;;;;;;;
+;; Timing AND Buffers;;
+;;;;;;;;;;;;;;;;;;;;;;;
+
+(def score-b         (buffer 128))
+(def duration-b      (buffer 128))
+(def bass-duration-b (buffer 128))
+(def bass-notes-b    (buffer 128))
+
+(def score [:F4 :F4 :F4 :F4 :F4 :F4 :F4
+            :G4 :G4 :G4 :G4 :G4 :G4 :G4 :G4 :G4 :G4 :G4 :G4 :G4 :G4 :G4 :G4
+            :BB4 :BB4 :BB4 :BB4 :BB4 :BB4
+            :D#4 :D#4 :D#4])
+
+(def duration     [1/7])
+
+(def score (concat
+            (map #(+ -5  (note %)) score)
+            (map #(+ -5  (note %)) score)
+            (map #(+ -10 (note %)) score)
+            (map #(+ -5  (note %)) score)
+            (map #(+ -1  (note %)) score)))
+
+(defsynth woody-beep [duration-bus 0 beat-count-bus 0 offset-bus 0 amp 1 out-bus 0]
+  (let [cnt    (in:kr beat-count-bus)
+        offset (buf-rd:kr 1 offset-bus cnt)
+        durs   (buf-rd:kr 1 duration-bus cnt)
+        trig (t-duty:kr (dseq durs INFINITE))
+        freq (demand:kr trig 0 (drand offset INFINITE))
+        freq (midicps freq)
+
+        env (env-gen:ar (env-asr :release 0.25 :sustain 0.8) trig)
+        tri (* 0.5 (lf-tri:ar freq))
+        sin (sin-osc:ar (* 1 freq))
+        sin2 (sin-osc:ar (* 1.01 freq))
+        wood (bpf:ar (* (white-noise:ar) (line:kr 5 0 0.02)) freq 0.02)
+        src (mix [sin sin2 tri wood])
+        src (free-verb src)]
+    (out:ar out-bus (* amp env (pan2 src)))))
+
+    (def w  (woody-beep :duration-bus duration-b :beat-count-bus beat-count-bus :offset-bus score-b :amp 4))
+
+(defsynth deep-saw [freq 100 beat-count-bus 0 offset-bus 0 duration-bus 0 out-bus 0 amp 1 pan 0]
+  (let [cnt    (in:kr beat-count-bus)
+        offset (buf-rd:kr 1 offset-bus cnt)
+        durs   (buf-rd:kr 1 duration-bus cnt)
+        trig (t-duty:kr (dseq durs INFINITE))
+        freq (demand:kr trig 0 (drand offset INFINITE))
+        freq (midicps freq)
+
+        saw1 (lf-saw:ar (* 0.5 freq))
+        saw2 (lf-saw:ar (* 0.25 freq))
+        sin1 (sin-osc freq)
+        sin2 (sin-osc (* 1.01 freq))
+        src (mix [saw1 saw2 sin1 sin2])
+        env (env-gen:ar (env-asr) trig)
+        src (lpf:ar src)
+        src (free-verb src 0.33 1 1)]
+    (out out-bus (* amp [src src]))))
+
+(def ps (deep-saw 100 :duration-bus bass-duration-b :beat-count-bus beat-count-bus :offset-bus bass-notes-b :amp 0.9))
+
+(ctl ps :damp 1)
+(ctl ps :room 1)
+
+(kill ps)
+
+(buffer-write! bass-duration-b (take 32 (cycle [(/ 1 3.5)])))
+(buffer-write! bass-notes-b (take 32 (cycle (map note [:F2 :F2 :G3 :G2 :G3 :BB2 :BB2 :G2 :G2]))))
+
+(buffer-write! bass-notes-b (take 32 (cycle (map #(+ 0 (note %)) [:F2 :F2 :G3 :G2 :G3 :BB2 :BB2 :G2 :G2]))))
+
+(buffer-write! score-b (take 128 (cycle (map note score))))
+(buffer-write! duration-b (take 128 (cycle duration)))
+
+(ctl root-trigger :rate 100)
+(ctl beat-trigger :div 30)

 ;;Hardware (External devices)

 (midi-connected-devices)

-(on-event
- [:midi :note-on]
- (fn [e] (when-let [drum (drum-kit (:note e))] (drum)))
- ::drumkit)
+(on-event [:midi :note-on]
+          (fn [m]
+            (buffer-write! music-buffer (map midi->hz
+                                             (map (fn [midi-note] (+ -12 midi-note))
+                                                  (repeat 256 (:note m))))))
+          ::phat-bass-keyboard)

 (comment
   (remove-event-handler ::drumkit))


fixes to get code compiling

fixes to get code compiling

--- src/main/clojure/com/contentjon/udev.clj
+++ src/main/clojure/com/contentjon/udev.clj
@@ -28,7 +28,7 @@
   (.udev_device_unref library device))

 (defn garbage-collected-ref [key obj]
-  (add-ref key object)
+  (add-ref key obj)
   (reify Object
     (finalize [_] (unref key obj))))

@@ -57,5 +57,6 @@
   (map first (enum-seq enumeration)))

 (defn in-class [enumeration & classes]
-  (doseq [class classes]
-    (.udev_enumerate_add_match_subsystem library enumeration class)))
+  (doseq [clazz classes]
+    (.udev_enumerate_add_match_subsystem library enumeration clazz))
+  enumeration)


(SERVER-876) Remove alignment in let block in master_core_test

--- test/unit/puppetlabs/services/master/master_core_test.clj
+++ test/unit/puppetlabs/services/master/master_core_test.clj
@@ -71,14 +71,14 @@
 (deftest code-id-injection-test
   (testing "code_id is calculated and added to the catalog request."
     (let [handler (fn ([req] {:request req}))
-          app     (build-ring-handler handler "1.2.3" (constantly "foo-is-my-codeid"))
-          resp    (app {:request-method :get
-                        :uri "/v3/catalog/bar"})]
+          app (build-ring-handler handler "1.2.3" (constantly "foo-is-my-codeid"))
+          resp (app {:request-method :get
+                     :uri "/v3/catalog/bar"})]
       (is (= "foo-is-my-codeid" (get-in resp [:request :params "code_id"])))))
   (testing "code_id is not added to non-catalog requests"
     (let [handler (fn ([req] {:request req}))
           app (build-ring-handler handler "1.2.3" (constantly "foo-is-my-codeid"))
-          request     (partial app-request app)]
+          request (partial app-request app)]
       (doseq [[method paths]
               {:get ["node"
                      "environment"


spec errors are hard to explain

spec errors are hard to explain

--- src/main/shadow/cljs/devtools/errors.clj
+++ src/main/shadow/cljs/devtools/errors.clj
@@ -2,6 +2,7 @@
   (:require [clojure.repl :as repl]
             [clojure.string :as str]
             [clojure.spec.alpha :as s]
+            [clojure.pprint :refer (pprint)]
             [shadow.cljs.closure :as closure]
             [shadow.cljs.build :as build]
             [shadow.cljs.ns-form :as ns-form]
@@ -61,27 +62,51 @@
   (write-msg w e)
   (ex-format w (.getCause e)))

-(defn spec-explain [data]
-  (with-out-str (s/explain-out data)))
+(defn spec-explain [w {::s/keys [problems value spec] :as data}]
+  ;; FIXME: meh, no idea how to make spec errors easier to read
+  #_(doseq [[in problems]
+            (group-by :in problems)
+
+            [val problems]
+            (group-by :val problems)]
+
+      (.write w (str "Value\n  "))
+      (.write w (str (pr-str val)))
+      (.write w "\nDid not conform to spec:\n")
+      (doseq [{:keys [via path pred reason] :as problem} problems]
+        (.write w "spec: ")
+        (.write w (pr-str (s/abbrev pred)))
+        (.write w "\n")
+        ))
+  (.write w (with-out-str (s/explain-out (select-keys data [::s/problems])))))

 (defmethod ex-data-format ::ns-form/invalid-ns
   [w e {:keys [config] :as data}]
   (.write w "Invalid namespace declaration\n")
-  (.write w (spec-explain data)))
+  (spec-explain w data))

 (defmethod ex-data-format ::comp/config
   [w e {:keys [config] :as data}]
   (.write w "Invalid configuration\n")
-  (.write w (spec-explain data)))
+  (spec-explain w data))

 (defmethod ex-data-format ::build/missing-ns
   [w e data]
   (write-msg w e))

 (defmethod ex-data-format ::s/problems
-  [w e {::s/keys [problems value] :as data}]
-  (.write w (.getMessage e))
-  (.write w (spec-explain data)))
+  [w e {::s/keys [problems value spec] :as data}]
+  (let [msg (.getMessage e)
+
+        [_ fdef :as x]
+        (re-find #"Call to ([^ ]+) did not conform to spec:" msg)]
+    ;; macroexpand errors already contain the explain message
+    (if-not x
+      (.write w (str msg "\n"))
+      (.write w (format "Call to %s did not conform to spec\n" fdef)))
+
+    (spec-explain w data)
+    ))

 (defmethod ex-data-format ::closure/errors
   [w e {:keys [errors] :as data}]


Added support to load log level from user config (#600)

--- src/main/shadow/cljs/devtools/server.clj
+++ src/main/shadow/cljs/devtools/server.clj
@@ -387,7 +387,9 @@
   ([sys-config]
    (if (runtime/get-instance)
      ::already-running
-     (do (log/set-level! (get-in sys-config [:log :level] :info))
+     (do (log/set-level! (or (get-in sys-config [:log :level])
+                             (get-in sys-config [:user-config :log :level])
+                             :info))
          (let [app
                (merge
                  {:dev-http


Supports :includes for defcluster

Supports :includes for defcluster

--- src/control/core.clj
+++ src/control/core.clj
@@ -6,7 +6,7 @@

 (def ^:dynamic *enable-color* true)
 (def ^{:dynamic true} *enable-logging* true)
-(def ^:dynamic  *debug* false)
+(def ^:dynamic *debug* false)
 (def ^:private bash-reset "\033[0m")
 (def ^:private bash-bold "\033[1m")
 (def ^:private bash-redbold "\033[1;31m")
@@ -133,9 +133,9 @@
         rt))))

 ;;All tasks defined in control file
-(def tasks (atom (hash-map)))
+(defonce tasks (atom (hash-map)))
 ;;All clusters defined in control file
-(def clusters (atom (hash-map)))
+(defonce clusters (atom (hash-map)))

 (def ^:private system-functions
   #{(symbol "scp") (symbol "ssh") (symbol "rsync") (symbol "call") (symbol "exists?")})
@@ -164,7 +164,7 @@
     (if (not (vector? arguments))
       (throw (IllegalArgumentException. "Task must have arguments even if []")))
     (if *debug*
-      (prn new-body))
+      (prn name "new-body:" new-body))
     `(swap! tasks
             assoc
             ~name
@@ -225,43 +225,50 @@
 (defn do-begin [args]
   (when-exit (< (count args) 2)
              "Please offer cluster and task name"
-             (let [clusterName (keyword (first args))
-                   taskName (keyword (second args))
-                   args (next (next args))
-                   cluster (clusterName @clusters)
+             (let [cluster-name (keyword (first args))
+                   task-name (keyword (second args))
+                   task-args (next (next args))
+                   cluster (cluster-name @clusters)
                    parallel (:parallel cluster)
                    user (:user cluster)
                    addresses (:addresses cluster)
                    clients (:clients cluster)
-                   task (taskName @tasks)
+                   task (task-name @tasks)
+                   includes (:includes cluster)
+                   debug (:debug cluster)
                    log (:log cluster)]
                (when-exit (nil? task)
-                          (str "No task named " (name taskName)))
+                          (str "No task named " (name task-name)))
                (when-exit (and (empty? addresses)
                                (empty? clients))
                           (str "Empty clients for cluster "
-                               (name clusterName)))
+                               (name cluster-name)))
                (let [task-arg-count (- (arg-count task) 3)]
-                 (when-exit (not= task-arg-count (count args))
+                 (when-exit (not= task-arg-count (count task-args))
                             (str "Task "
-                                 (name taskName)
+                                 (name task-name)
                                  " just needs "
                                  task-arg-count
                                  " arguments")))
-               (binding [*enable-logging* (if (nil? log) true log)]
+               (binding [*enable-logging* (if (nil? log) true log)
+                         *debug* debug]
                  (if *enable-logging*
                    (println  (str bash-bold
                                   "Performing "
-                                  (name clusterName)
+                                  (name cluster-name)
                                   bash-reset
                                   (if parallel
                                     " in parallel"))))
                  (let [map-fn (if parallel pmap map)
-                       a (doall (map-fn (fn [addr] [addr (perform addr user cluster task taskName args)])
+                       a (doall (map-fn (fn [addr] [addr (perform addr user cluster task task-name task-args)])
                                         addresses))
-                       c (doall (map-fn (fn [cli] [(:host cli) (perform (:host cli) (:user cli) cluster task taskName args)])
+                       c (doall (map-fn (fn [cli] [(:host cli) (perform (:host cli) (:user cli) cluster task task-name task-args)])
                                         clients))]
-                   (into {} (concat a c)))))))
+                   (merge (into {} (concat a c))
+                          (when includes
+                            (if (coll? includes)
+                              (mapcat #(do-begin (cons % (next args))) includes)
+                              (do-begin (cons (name includes) (next args)))))))))))

 (defn begin []
   (do-begin *command-line-args*)


Prepping for application of indentation errors

--- src/aeolian/composer.clj
+++ src/aeolian/composer.clj
@@ -23,6 +23,9 @@

 (defn adjust-for-method-length [metric]
 	nil)
+
+(defn adjust-for-indentation [metric]
+	nil)
 	; (let [method-length (parser/method-length-from-metric metric)]
 	; 	(if (> method-length 1)
 	; 		(str "\n%%MIDI control 7 " (+ (* 2 method-length) 50)))))
@@ -30,8 +33,9 @@
 (defn metric-to-note [metric]
 	(let [
 				raw-note (build-note (parser/line-length-from-metric metric))
-				final-note-bits (cons (adjust-for-method-length metric)
-														(cons (adjust-for-complexity metric) (list raw-note)))
+				final-note-bits (cons (adjust-for-indentation metric)
+													(cons (adjust-for-method-length metric)
+														(cons (adjust-for-complexity metric) (list raw-note))))
 				final-note (apply str (interpose "\n" (filter #(not (nil? %)) final-note-bits)))
 				]


Improve metronome capabilities.

Improve metronome capabilities.

Simplify tracking of start point; remove now-unnecessary atom.
Add tracking of phrases as well as beats and bars.
Allow adjusting phrase and bar start without nudging beat phase.

--- src/afterglow/rhythm.clj
+++ src/afterglow/rhythm.clj
@@ -6,66 +6,75 @@
   (:require [overtone.at-at :refer [now]]
             [clojure.math.numeric-tower :refer [round floor]]))

-(defonce ^{:private true}
-  _PROTOCOLS_
-  (defprotocol IMetronome
-    (metro-start [metro] [metro start-beat]
-      "Returns the start time of the metronome. Also restarts the metronome at
-     'start-beat' if given.")
-    (metro-bar-start [metro] [metro start-bar]
-      "Returns the bar-start time of the metronome. Also restarts the metronome at
-     'start-bar' if given.")
-    (metro-tick [metro]
-      "Returns the duration of one metronome 'tick' in milleseconds.")
-    (metro-tock [metro]
-      "Returns the duration of one bar in milliseconds.")
-    (metro-beat [metro] [metro beat]
-      "Returns the next beat number or the timestamp (in milliseconds) of the
+(defprotocol IMetronome
+  (metro-start [metro] [metro start-beat]
+    "Returns the start time of the metronome. Also restarts the
+     metronome at start-beat if given.")
+  (metro-bar-start [metro start-bar]
+    "Restarts the metronome at start-bar, keeping the beat phase
+    unchanged in case it is being synced to an external source.")
+  (metro-phrase-start [metro start-phrase]
+    "Restarts the metronome at start-phrase, keeping the beat phase
+    unchanged in case it is being synced to an external source.")
+  (metro-tick [metro]
+    "Returns the duration of one beat in milleseconds.")
+  (metro-tock [metro]
+    "Returns the duration of one bar in milliseconds.")
+  (metro-ding [metro]
+    "Returns the duration of one phrase in milliseconds.")
+  (metro-beat [metro] [metro beat]
+    "Returns the next beat number or the timestamp (in milliseconds) of the
      given beat.")
-    (metro-beat-phase [metro] [metro phase]
-      "Returns the distance traveled into the current beat [0.0, 1.0), or
+  (metro-beat-phase [metro] [metro phase]
+    "Returns the distance traveled into the current beat [0.0, 1.0), or
        adjusts the phase to match the one supplied.")
-    (metro-bar [metro] [metro  bar]
-      "Returns the next bar number or the timestamp (in milliseconds) of the
+  (metro-bar [metro] [metro bar]
+    "Returns the next bar number or the timestamp (in milliseconds) of the
      given bar")
-    (metro-bar-phase [metro] [metro phase]
-      "Returns the distance traveled into the current bar [0.0, 1.0), or
+  (metro-bar-phase [metro] [metro phase]
+    "Returns the distance traveled into the current bar [0.0, 1.0), or
        adjusts the phase to match the one supplied.")
-    (metro-bpb [metro] [metro new-bpb]
-      "Get the current beats per bar or change it to new-bpb")
-    (metro-bpm [metro] [metro new-bpm]
-      "Get the current bpm or change the bpm to 'new-bpm'.")
-    (metro-snapshot [metro]
-      "Take a snapshot of the current beat, bar, and phase state.")))
-
-
-                                        ; Rhythm
-
-                                        ; * a resting heart rate is 60-80 bpm
-                                        ; * around 150 induces an excited state
-
-
-                                        ; A rhythm system should let us refer to time in terms of rhythmic units like beat, bar, measure,
-                                        ; and it should convert these units to real time units (ms) based on the current BPM and signature settings.
+  (metro-phrase [metro] [metro phrase]
+    "Returns the next phrase number or the timestamp (in milliseconds)
+     of the given phrase")
+  (metro-phrase-phase [metro] [metro phase]
+    "Returns the distance traveled into the current phrase [0.0, 1.0),
+       or adjusts the phase to match the one supplied.")
+  (metro-bpb [metro] [metro new-bpb]
+    "Get the current beats per bar or change it to new-bpb")
+  (metro-bpp [metro] [metro new-bpp]
+    "Get the current bars per phrase, or change it to new-bpp")
+  (metro-bpm [metro] [metro new-bpm]
+    "Get the current bpm or change the bpm to new-bpm.")
+  (metro-snapshot [metro]
+    "Take a snapshot of the current beat, bar, phrase, and phase state.")
+  (metro-marker [metro]
+    "Returns the current time as phrase.bar.beat"))
+
+
+;; Rhythm
+
+;; * a resting heart rate is 60-80 bpm
+;; * around 150 induces an excited state
+
+;; A rhythm system should let us refer to time in terms of rhythmic units
+;; like beat, bar, measure, and it should convert these units to real time
+;; units (ms) based on the current BPM and signature settings.

 (defn beat-ms
   "Convert 'b' beats to milliseconds at the given 'bpm'."
   [b bpm] (* (/ 60000.0 bpm) b))

-                                        ;(defn bar-ms
-                                        ;  "Convert b bars to milliseconds at the current bpm."
-                                        ;  ([] (bar 1))
-                                        ;  ([b] (* (bar 1) (first @*signature) b)))
-
 (defn- marker-number
-  "Helper function to calculate the beat or bar number in effect at a given moment, given a
-  starting point and beat or bar interval."
+  "Helper function to calculate the beat, bar, or phrase number in
+  effect at a given moment, given a starting point and beat, bar,
+  or phrase interval."
   [instant start interval]
   (inc (long (/ (- instant start) interval))))

 (defn- marker-phase
-  "Helper function to calculate the beat or bar phase at a given moment, given a
-  starting point and beat interval."
+  "Helper function to calculate the beat, bar, or phrase phase at a
+  given moment, given a starting point and beat interval."
   [instant start interval]
   (let [marker-ratio (/ (- instant start) interval)]
     (- (double marker-ratio) (long marker-ratio))))
@@ -79,21 +88,33 @@
 (defprotocol ISnapshot
   (snapshot-beat-phase [snapshot] [snapshot beat-ratio]
     "Determine the phase with respect to a multiple or fraction of beats.
-Calling this with a beat-ratio of 1 (the default if not provided) is
-equivalent to beat-phase, a beat-ratio of bpb is equivalent to
-bar-phase (unless the bar start has been moved away from the beat
-start), 1/2 oscillates twice as fast as 1, 3/4 oscillates 4 times
-every three beats... Phases range from [0-1).")
+    Calling this with a beat-ratio of 1 (the default if not provided)
+    is equivalent to beat-phase, a beat-ratio of bpb is equivalent to
+    bar-phase (unless the bar start has been moved away from the beat
+    start), 1/2 oscillates twice as fast as 1, 3/4 oscillates 4 times
+    every three beats... Phases range from [0-1).")
   (snapshot-bar-phase [snapshot] [snapshot bar-ratio]
     "Determine the phase with respect to a multiple or fraction of bars.
-Calling this with a beat-ratio of 1 (the default if not provided) is
-equivalent to bar-phase, 1/2 oscillates twice as fast as 1, 3/4
-oscillates 4 times every three bars... Phases range from [0-1).")
+    Calling this with a beat-ratio of 1 (the default if not provided) is
+    equivalent to bar-phase, 1/2 oscillates twice as fast as 1, 3/4
+    oscillates 4 times every three bars... Phases range from [0-1).")
   (snapshot-beat-within-bar [snapshot]
     "Returns the beat number relative to the start of the bar: The down
-beat is 1, and the range goes up to the beats-per-bar of the metronome.")
+    beat is 1, and the range goes up to the beats-per-bar of the metronome.")
   (snapshot-down-beat? [snapshot]
-    "True if the current beat is the first beat in the current bar."))
+    "True if the current beat is the first beat in the current bar.")
+  (snapshot-phrase-phase [snapshot] [snapshot phrase-ratio]
+    "Determine the phase with respect to a multiple or fraction of
+    phrases. Calling this with a phrase-ratio of 1 (the default if
+    not provided) is equivalent to phrase-phase, 1/2 oscillates twice
+    as fast as 1, 3/4 oscillates 4 times every three bars... Phases
+    range from [0-1).")
+  (snapshot-bar-within-phrase [snapshot]
+    "Returns the bar number relative to the start of the phrase:
+    Ranges from 1 to the bars-per-phrase of the metronome.")
+  (snapshot-phrase-start? [snapshot]
+    "True if the current beat is the first beat in the current
+    phrase."))

 (defn- enhanced-phase
   "Calculate a phase with respect to multiples or fractions of a
@@ -111,7 +132,7 @@
           adjusted-phase (* base-phase denominator)]
       (- (double adjusted-phase) (long adjusted-phase))))

-(defrecord MetronomeSnapshot [start bar-start bpm bpb instant beat bar beat-phase bar-phase]
+(defrecord MetronomeSnapshot [start bpm bpb bpp instant beat bar phrase beat-phase bar-phase phrase-phase]
   ISnapshot
   (snapshot-beat-phase [snapshot]
     (snapshot-beat-phase snapshot 1))
@@ -123,120 +144,106 @@
     (enhanced-phase bar bar-phase bar-ratio))
   (snapshot-beat-within-bar [snapshot]
     (let [beat-size (/ 1 bpb)]
-      (inc (floor (/ (snapshot-bar-phase snapshot 1) beat-size)))))
+      (inc (int (floor (/ (snapshot-bar-phase snapshot 1) beat-size))))))
   (snapshot-down-beat? [snapshot]
     (let [beat-size (/ 1 bpb)]
-      (zero? (floor (/ (snapshot-bar-phase snapshot 1) beat-size))))))
-
-(deftype Metronome [start bar-start bpm bpb]
-
+      (zero? (floor (/ (snapshot-bar-phase snapshot 1) beat-size)))))
+  (snapshot-phrase-phase [snapshot phrase-ratio]
+    (enhanced-phase phrase phrase-phase phrase-ratio))
+  (snapshot-bar-within-phrase [snapshot]
+    (let [phrase-size (/ 1 bpp)]
+      (inc (int (floor (/ (snapshot-phrase-phase snapshot 1) phrase-size))))))
+  (snapshot-phrase-start? [snapshot]
+    (let [phrase-size (/ 1 bpp)]
+      (zero? (floor (/ (snapshot-phrase-phase snapshot 1) phrase-size))))))
+
+(defrecord Metronome [start bpm bpb bpp]
   IMetronome
   (metro-start [metro] @start)
   (metro-start [metro start-beat]
-    (let [new-start (round (- (now) (* start-beat (metro-tick metro))))]
-      (reset! start new-start)
-      (reset! bar-start new-start)  ; Keep phases consistent
-      new-start))
-  (metro-bar-start [metro] @bar-start)
+    (let [new-start (round (- (now) (* (dec start-beat) (metro-tick metro))))]
+      (reset! start new-start)))
   (metro-bar-start [metro start-bar]
-    (let [new-bar-start (round (- (now) (* start-bar (metro-tock metro))))]
-      (reset! bar-start new-bar-start)
-      (reset! start new-bar-start)  ; Keep phases consistent
-      new-bar-start))
-  (metro-tick  [metro] (beat-ms 1 @bpm))
-  (metro-tock  [metro] (beat-ms @bpb @bpm))
-  (metro-beat  [metro] (marker-number (now) @start (metro-tick metro)))
-  (metro-beat  [metro b] (+ (* b (metro-tick metro)) @start))
+    (let [phase (metro-beat-phase metro)
+          shift (* (metro-tick metro) (if (> phase 0.5) (dec phase) phase))
+          new-bar-start (round (+ shift (- (now) (* (dec start-bar) (metro-tock metro)))))]
+      (reset! start new-bar-start)))
+  (metro-phrase-start [metro start-phrase]
+    (let [phase (metro-beat-phase metro)
+          shift (* (metro-tick metro) (if (> phase 0.5) (dec phase) phase))
+          new-phrase-start (round (+ shift (- (now) (* (dec start-phrase) (metro-ding metro)))))]
+      (reset! start new-phrase-start)))
+
+  (metro-tick [metro] (beat-ms 1 @bpm))
+  (metro-tock [metro] (beat-ms @bpb @bpm))
+  (metro-ding [metro] (beat-ms (* @bpb @bpp) @bpm))
+
+  (metro-beat [metro] (marker-number (now) @start (metro-tick metro)))
+  (metro-beat [metro b] (+ (* b (metro-tick metro)) @start))
   (metro-beat-phase [metro]
     (marker-phase (now) @start (metro-tick metro)))
   (metro-beat-phase [metro phase]
     (let [delta (- phase (metro-beat-phase metro))
           shift (round (* (metro-tick metro) (if (> delta 0.5) (dec delta)
                                                  (if (< delta -0.5) (inc delta) delta))))]
-      (swap! start - shift)
-      (swap! bar-start - shift)))
-  (metro-bar   [metro] (marker-number (now) @bar-start (metro-tock metro)))
-  (metro-bar   [metro b] (+ (* b (metro-tock metro)) @bar-start))
+      (swap! start - shift)))
+
+  (metro-bar [metro] (marker-number (now) @start (metro-tock metro)))
+  (metro-bar [metro b] (+ (* b (metro-tock metro)) @start))
   (metro-bar-phase [metro]
-    (marker-phase (now) @bar-start (metro-tock metro)))
+    (marker-phase (now) @start (metro-tock metro)))
   (metro-bar-phase [metro phase]
     (let [delta (- phase (metro-bar-phase metro))
           shift (round (* (metro-tock metro) (if (> delta 0.5) (dec delta)
                                                  (if (< delta -0.5) (inc delta) delta))))]
-      (swap! start - shift)
-      (swap! bar-start - shift)))
-  (metro-bpm   [metro] @bpm)
-  (metro-bpm   [metro new-bpm]
-    (let [cur-beat      (metro-beat metro)
-          cur-bar       (metro-bar metro)
-          new-tick      (beat-ms 1 new-bpm)
-          new-tock      (* @bpb new-tick)
-          new-start     (round (- (metro-beat metro cur-beat) (* new-tick cur-beat)))
-          new-bar-start (round (- (metro-bar metro cur-bar) (* new-tock cur-bar)))]
+      (swap! start - shift)))
+
+  (metro-phrase [metro] (marker-number (now) @start (metro-ding metro)))
+  (metro-phrase [metro b] (+ (* b (metro-ding metro)) @start))
+  (metro-phrase-phase [metro]
+    (marker-phase (now) @start (metro-ding metro)))
+  (metro-phrase-phase [metro phase]
+    (let [delta (- phase (metro-phrase-phase metro))
+          shift (round (* (metro-ding metro) (if (> delta 0.5) (dec delta)
+                                                 (if (< delta -0.5) (inc delta) delta))))]
+      (swap! start - shift)))
+
+  (metro-bpm [metro] @bpm)
+  (metro-bpm [metro new-bpm]
+    (let [cur-beat (metro-beat metro)
+          new-tick (beat-ms 1 new-bpm)
+          new-start (round (- (metro-beat metro cur-beat) (* new-tick cur-beat)))]
       (reset! start new-start)
-      (reset! bar-start new-bar-start)
       (reset! bpm new-bpm))
     [:bpm new-bpm])
-  (metro-bpb   [metro] @bpb)
-  (metro-bpb   [metro new-bpb]
-    (let [cur-bar       (metro-bar metro)
-          new-tock      (beat-ms new-bpb @bpm)
-          new-bar-start (- (metro-bar metro cur-bar) (* new-tock cur-bar))]
-      (reset! bar-start new-bar-start)
+  (metro-bpb [metro] @bpb)
+  (metro-bpb [metro new-bpb]
+    (let [cur-bar (metro-bar metro)
+          new-tock (beat-ms new-bpb @bpm)
+          new-start (- (metro-bar metro cur-bar) (* new-tock cur-bar))]
+      (reset! start new-start)
       (reset! bpb new-bpb)))
   (metro-snapshot [metro]
-    (let [instant    (now)
-          beat       (marker-number instant @start (metro-tick metro))
-          bar        (marker-number instant @bar-start (metro-tock metro))
+    (let [instant (now)
+          beat (marker-number instant @start (metro-tick metro))
+          bar (marker-number instant @start (metro-tock metro))
+          phrase (marker-number instant @start (metro-ding metro))
           beat-phase (marker-phase instant @start (metro-tick metro))
-          bar-phase  (marker-phase instant @bar-start (metro-tock metro))]
-      (MetronomeSnapshot. @start @bar-start @bpm @bpb instant beat bar beat-phase bar-phase)))
-
-  clojure.lang.ILookup
-  (valAt [this key] (.valAt this key nil))
-  (valAt [this key not-found]
-    (cond (= key :start) @start
-          (= key :bpm) @bpm
-          :else not-found))
-
-  clojure.lang.IFn
-  (invoke [this] (metro-beat this))
-  (invoke [this arg]
-    (cond
-      (number? arg) (metro-beat this arg)
-      (= :bpm arg) (metro-bpm this) ;; (bpm this) fails.
-      :else (throw (Exception. (str "Unsupported metronome arg: " arg)))))
-  (invoke [this _ new-bpm] (metro-bpm this new-bpm)))
+          bar-phase (marker-phase instant @start (metro-tock metro))
+          phrase-phase (marker-phase instant @start (metro-ding metro))]
+      (MetronomeSnapshot. @start @bpm @bpb @bpp instant beat bar phrase beat-phase bar-phase phrase-phase)))
+  (metro-marker [metro]
+    (let [snap (metro-snapshot metro)]
+      (str (:phrase snap) "." (snapshot-bar-within-phrase snap) "." (snapshot-beat-within-bar snap)))))

 (defn metronome
-  "A metronome is a beat management function.  Tell it what BPM you want,
-  and it will output beat timestamps accordingly.  Call the returned function
-  with no arguments to get the next beat number, or pass it a beat number
-  to get the timestamp to play a note at that beat.
-
-  Metronome also works with bars. Set the number of beats per bar using
-  metro-bpb (defaults to 4). metro-bar returns a timestamp that can be used
-  to play a note relative to a specified bar.
-
-  (def m (metronome 128))
-  (m)          ; => <next beat number>
-  (m 200)      ; => <timestamp of beat 200>
-  (m :bpm)     ; => return the current bpm val
-  (m :bpm 140) ; => set bpm to 140"
-  [bpm]
+  "A metronome is a beat management tool. Tell it what BPM you want,
+  and it will compute beat, bar, and phrase timestamps accordingly.
+  See the IMetronome interface for full details."
+  [bpm & {:keys [bpb bpp] :or {bpb 4 bpp 8}}]
   (let [start (atom (now))
-        bar-start (atom @start)
-        bpm   (atom bpm)
-        bpb   (atom 4)]
-    (Metronome. start bar-start bpm bpb)))
-
-                                        ;== Grooves
-                                        ;
-                                        ; A groove represents a pattern of velocities and timing modifications that is
-                                        ; applied to a sequence of notes to adjust the feel.
-                                        ;
-                                        ; * swing
-                                        ; * jazz groove, latin groove
-                                        ; * techno grooves (hard on beat one)
-                                        ; * make something more driving, or more layed back...
-
+        bpm (atom bpm)
+        bpb (atom bpb)
+        bpp (atom bpp)]
+    (Metronome. start bpm bpb bpp)))
+


CLJS-1051: :modules validation, :output-to should be unique

--- src/clj/cljs/closure.clj
+++ src/clj/cljs/closure.clj
@@ -822,6 +822,11 @@
   ;; lein-cljsbuild adds :output-to?
   #_{:pre [(and (contains? opts :modules)
                 (not (contains? opts :output-to)))]}
+  (assert (= (count (:modules opts))
+             (count (into #{}
+                      (map (comp :output-to second)
+                        (:modules opts)))))
+    "Each :output-to of :modules must be unique")
   (let [closure-compiler (make-closure-compiler)
         ^List externs (load-externs opts)
         compiler-options (make-options opts)


expose fine grained control of analyzer warnings in `cljs.closure/build`

--- src/clj/cljs/closure.clj
+++ src/clj/cljs/closure.clj
@@ -969,12 +969,16 @@
                    *assert* (not= (:elide-asserts opts) true)
                    ana/*load-tests* (not= (:load-tests opts) false)
                    ana/*cljs-warnings*
-                   (let [enabled? (true? (opts :warnings true))]
-                     (merge ana/*cljs-warnings*
-                            {:unprovided enabled?
-                             :undeclared-var enabled?
-                             :undeclared-ns enabled?
-                             :undeclared-ns-form enabled?}))]
+                   (let [warnings (opts :warnings true)]
+                     (merge
+                       ana/*cljs-warnings*
+                       (if (or (true? warnings)
+                               (false? warnings))
+                         (zipmap
+                           [:unprovided :undeclared-var
+                            :undeclared-ns :undeclared-ns-form]
+                           (repeat warnings))
+                         warnings)))]
            (let [compiled (-compile source all-opts)

                  ; the constants_table.js file is not used directly here, is picked up by


Create bench macro

Create bench macro

--- src/clj_gatling/core.clj
+++ src/clj_gatling/core.clj
@@ -6,11 +6,18 @@
             [clojure-csv.core :as csv])
   (:gen-class))

+(defmacro bench [expr]
+  `(let [start# (System/currentTimeMillis)
+         result# ~expr]
+      {:result result# :start start# :end (System/currentTimeMillis) }))
+
+(defn request [id]
+  (println (str "Simulating request for " id))
+  (Thread/sleep (rand 1000)))
+
 (defn process [id]
-  (let [start (System/currentTimeMillis)]
-    (println (str "Doing some heavy calculation for " id))
-    (Thread/sleep (rand 1000))
-    {:id id :start start :end (System/currentTimeMillis)}))
+  (let [bench-result (bench (request id))]
+    {:id id :start (:start bench-result) :end (:end bench-result)}))

 (defn run-simulation [threads]
   (println (str "Run simulation with " threads " threads"))


rename fns for clarity

rename fns for clarity

--- src/clj_money/import.clj
+++ src/clj_money/import.clj
@@ -162,33 +162,33 @@
                  (fnil inc 0))
       update-progress))

-(defmulti process-record
+(defmulti import-record
   (fn [_ record]
     (-> record meta :record-type)))

-(defmethod process-record :declaration
+(defmethod import-record :declaration
   [context {:keys [record-type record-count]}]
   (-> context
       (assoc-in [:progress record-type :total] record-count)
       update-progress))

-(defmethod process-record :account
+(defmethod import-record :account
   [context account]
   (import-account context account))

-(defmethod process-record :transaction
+(defmethod import-record :transaction
   [context transaction]
   (import-transaction context transaction))

-(defmethod process-record :budget
+(defmethod import-record :budget
   [context budget]
   (import-budget context budget))

-(defmethod process-record :price
+(defmethod import-record :price
   [context price]
   (import-price context price))

-(defmethod process-record :commodity
+(defmethod import-record :commodity
   [context commodity]
   (import-commodity context commodity))

@@ -199,10 +199,10 @@
   [record-type]
   (reportable-record-types record-type))

-(defn process-callback
+(defn process-record
   "Top-level callback processing

-  This function calls the multimethod process-record
+  This function calls the multimethod import-record
   to dispatch to the correct import logic for the
   record-type.

@@ -212,7 +212,7 @@
   (let [{:keys [record-type ignore?]} (meta record)]
     (swap! context #(cond-> %
                       (not ignore?)
-                      (process-record record)
+                      (import-record record)

                       (report-progress? record-type)
                       (inc-and-update-progress record-type)))))
@@ -236,5 +236,5 @@
           [input source-type] (prepare-input s (:image-id impt))]
       (transactions/with-delayed-balancing s (-> @context :entity :id)
         (doseq [record (read-source source-type input)]
-          (process-callback context record)))
+          (process-record context record)))
       (:entity @context))))


Add family-uniformity and clone-distance meta-errors

--- src/clojush/evaluate.clj
+++ src/clojush/evaluate.clj
@@ -220,6 +220,25 @@
                                0
                                1)))))))
               ;
+              (= cat :family-uniformity)
+              (if (not (:print-history argmap))
+                (throw
+                  (Exception.
+                    ":print-history must be true for :family-variation"))
+                (if (or (empty? (:parent-uuids ind))
+                        (empty? (rest (:history ind))))
+                  1
+                  (let [siblings (filter #(and (= (first (:parent-uuids ind))
+                                                  (first (:parent-uuids %)))
+                                               (not (empty? (rest (:history %))))) ; new random sibs don't count
+                                         evaluated-population)]
+                    (if (some (fn [sib]
+                                (not= (first (:history sib))
+                                      (second (:history sib))))
+                              siblings)
+                      0
+                      1))))
+              ;
               (= cat :case-family-variation)
               (if (not (:print-history argmap))
                 (throw
@@ -282,6 +301,20 @@
                                      siblings)
                                0
                                1)))))))
+              ;
+              (= cat :clone-distance)
+              (/ 1 (let [limit 100]
+                     (loop [step 1
+                            genomes (list (:genome ind))]
+                       (if (>= step limit)
+                         step
+                         (let [child (produce-child-genome-by-autoconstruction
+                                       (first genomes)
+                                       (first genomes)
+                                       argmap)]
+                           (if (some #{child} (set genomes))
+                             step
+                             (recur (inc step) (cons child genomes))))))))
               ;
               (= cat :reproductive-infidelity)
               (let [g (:genome ind)]


Experiment more with meta-errors

Experiment more with meta-errors

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


add date time stamp to test screenshot files

--- src/crison/main.clj
+++ src/crison/main.clj
@@ -2,6 +2,7 @@
   (:require [clojure.edn :refer [read-string]]
             [clj-time.core :as t]
             [clj-time.format :as f]
+            [clj-time.local :as l]
             [environ.core :refer [env]]
             [clojure.test :refer :all]
             ;[taoensso.truss :as truss :refer (have have! have?)]
@@ -12,8 +13,13 @@
 (System/setProperty "phantomjs.binary.path" (env :phantom-path))

 (def driver (wc/new-webdriver {:browser :phantomjs}))
+(def built-in-formatter (f/formatters :basic-date-time))

-(def f-date (f/unparse-local (f/formatter "Y-MM-dd") (t/today)))
+(defn formatlocal [n offset]
+  (let [nlocal (t/to-time-zone n (t/time-zone-for-offset offset))]
+    (f/unparse (f/formatter-local "yyyy-MM-dd_hh:mm")
+               nlocal)))
+(def f-date (formatlocal (t/now) -0))

 (defn title [] (wc/title driver))

@@ -57,7 +63,7 @@

 (defmethod decode :default [x] (? x))

-(def screenshot-file (str "screenshot_test.png"))
+(def screenshot-file (str f-date "-screenshot_test.png"))
 (defn take-screenshot
   [driver]
   (is (string? (wc/get-screenshot driver :base64)))


Cleaned up new votes work

Cleaned up new votes work

--- src/poller.clj
+++ src/poller.clj
@@ -47,10 +47,9 @@
         pg-spec (heroku-db-spec (env/env :database-url))
         last-timestanp (atom 1388285552490)]
     (endlessly poll-interval
-      (let [new-votes (->> @last-timestanp
-                        (poll pg-spec)
-                        split-by-conv)]
-        (println "polling:" new-votes)
+      (let [new-votes (poll pg-spec @last-timestanp)
+            split-votes (split-by-conv new-votes)]
+        (println "polling:" split-votes)
         (swap! last-timestanp (fn [_] (:created (last new-votes))))))))


Update projects deps

Update projects deps

cljs and cljs-ajax to latest version

--- src/discuss/core.cljs
+++ src/discuss/core.cljs
@@ -18,7 +18,7 @@
 (defn ^:export main []
   (lib/log (str "Loaded " config/project " " config/version))
   (com/init-with-references!))
-(main)
+;; (main)

 ;; Register
 (defn register-view


More log tidying.

More log tidying.

--- src/depends/core.clj
+++ src/depends/core.clj
@@ -66,12 +66,13 @@
 ;              (do
 ;                (log/info (str "Writing dependencies to Neo4J..."))
 ;                (svg/write-dependencies dependencies)))
+            (log/info "Complete.")
             nil)
           (finally  ; Don't forget to unmount TrueVFS
-            (log/info "Complete.")
             (try
               (net.java.truevfs.access.TVFS/umount)
               (catch java.util.ServiceConfigurationError sce
                 (comment "Ignore this exception because TrueVFS is noisy as crap.")))))))
   (catch Exception e
+    (log/error e)
     (aviso/write-exception e))))


fix for deprecated Exp.Components.Svg. Now Expo.Svg

--- src/graphics/svg.cljs
+++ src/graphics/svg.cljs
@@ -21,7 +21,7 @@
    "Defs"
    "Stop"])

-(def wrap-svg (partial aget expo "Components" "Svg"))
+(def wrap-svg (partial aget expo "Svg"))

 (defn wrap-svg-component [name]
   (partial element (wrap-svg name)))


Added 2 keys in app-state

Added 2 keys in app-state

--- src/hatti/shared.cljs
+++ src/hatti/shared.cljs
@@ -67,6 +67,8 @@
                  :chart-data {}}
     :dataset-info {}
     :data []
+    :data-to-be-deleted []
+    :selected-table-rows []
     :status {:total-records 0 :loading? true}
     :languages {:current nil :all []}
     :api-url "//api.ona.io/api/v1/"}))


5 second heartbeat

5 second heartbeat

--- src/jepsen/voltdb.clj
+++ src/jepsen/voltdb.clj
@@ -74,7 +74,7 @@
        ; isolated nodes with requests *before* they kill themselves
        ; but low enough that a new majority is elected and performs
        ; some operations.
-       [:heartbeat {:timeout 10}] ; seconds
+       [:heartbeat {:timeout 5}] ; seconds
        [:commandlog {:enabled true, :synchronous true, :logsize 128}
         [:frequency {:time 2}]]]))) ; milliseconds


Swap map -> pmap in main loop.

Swap map -> pmap in main loop.

--- src/luhnybin/core.clj
+++ src/luhnybin/core.clj
@@ -86,6 +86,6 @@
     (->> nil
       (make-reader (or (first args) *in*))
       (line-seq)
-      (map #(mask-line % (process-line %) \X))
+      (pmap #(mask-line % (process-line %) \X))
       (map println))))


Reformatting and Heroku prep.

Reformatting and Heroku prep.

--- src/notes/handler.clj
+++ src/notes/handler.clj
@@ -8,16 +8,17 @@
         [hiccup.util]
         [ring.util.response]
         [clojure.data])
-  (:require [clojure.string :as s]
-            [compojure.handler :as handler]
-            [compojure.route :as route]
-            [clojure.java.io :as io]
-            [monger.core :as mg]
-            [monger.collection :as mc]
-            [monger.query :as mq]
-            [monger.joda-time])
-  (:import [org.joda.time DateTime DateTimeZone]
-           [org.bson.types ObjectId]))
+(:require [clojure.string :as s]
+          [compojure.handler :as handler]
+          [compojure.route :as route]
+          [clojure.java.io :as io]
+          [monger.core :as mg]
+          [monger.collection :as mc]
+          [monger.query :as mq]
+          [monger.joda-time]
+          [ring.adapter.jetty :as jetty])
+(:import [org.joda.time DateTime DateTimeZone]
+         [org.bson.types ObjectId]))

 (def uid "mongo")
 (def pwd "secret")
@@ -31,64 +32,67 @@

 (defn find-notes []
   (mq/with-collection "notes"
-    (mq/find {})
-    (mq/sort {:ts -1})))
+                      (mq/find {})
+                      (mq/sort {:ts -1})))

 (defn delete-note! [id]
   (mc/remove-by-id "notes" (ObjectId. id)))

 (defn front-page [notes]
   (html
-    (html5
-      [:head [:title "Notes"]
-       (include-css "css/bootstrap.min.css")
-       (include-css "css/notes.css")
-       (include-css "css/jquery-ui-1.10.2.custom.min.css")]
+   (html5
+    [:head [:title "Notes"]
+     (include-css "css/bootstrap.min.css")
+     (include-css "css/notes.css")
+     (include-css "css/jquery-ui-1.10.2.custom.min.css")]

-      [:body [:div.navbar.navbar-fixed-top [:div.navbar-inner [:div.container (link-to {:class "brand"} "#" "Notes!")]]]
+    [:body [:div.navbar.navbar-fixed-top [:div.navbar-inner [:div.container (link-to {:class "brand"} "#" "Notes!")]]]

-       [:header
-        [:div.container (image {:id "note"} "img/note.png")
-         [:div#header-txt [:h1 "Notes!"]
-         [:p.lead [:small " Create and read awesome notes, right here!"]]]]]
+     [:header
+      [:div.container (image {:id "note"} "img/note.png")
+       [:div#header-txt [:h1 "Notes!"]
+        [:p.lead [:small " Create and read awesome notes, right here!"]]]]]

-       [:div.container
-        [:div.row-fluid
-         [:div.span4 [:div#add-note.affix-top {:data-spy "affix", :data-offset-top "215"}
-                                                    (form-to [:post "./"]
-                                                      [:fieldset [:label "Heading"]
-                                                       (text-field :heading )
-                                                       [:label "Note"]
-                                                       (text-area {:rows 5} :body )
-                                                       [:button.btn {:type "submit"} "Create Note!"]])]]
+     [:div.container
+      [:div.row-fluid
+       [:div.span4 [:div#add-note.affix-top {:data-spy "affix", :data-offset-top "215"}
+                    (form-to [:post "./"]
+                             [:fieldset [:label "Heading"]
+                              (text-field :heading )
+                              [:label "Note"]
+                              (text-area {:rows 5} :body )
+                              [:button.btn {:type "submit"} "Create Note!"]])]]

-         [:div.span8 (for [{:keys [_id, heading, body, added? ts]} notes]
-           [(if added? :div#added.note :div.note) [:div.row-fluid [:div.span11 [:legend (escape-html heading)]]
-                                      [:div.span1 [:div.del (form-to [:delete "./"] (hidden-field :id _id) [:button.btn.btn-mini.btn-link {:type "submit"} [:i.icon-remove ]])]]]
+       [:div.span8 (for [{:keys [_id, heading, body, added? ts]} notes]
+                     [(if added? :div#added.note :div.note) [:div.row-fluid [:div.span11 [:legend (escape-html heading)]]
+                                                             [:div.span1 [:div.del (form-to [:delete "./"] (hidden-field :id _id) [:button.btn.btn-mini.btn-link {:type "submit"} [:i.icon-remove ]])]]]
                       [:div (s/replace (escape-html body) #"\n" "<br>")]
                       [:p.text-info [:small ts]]])]]]

-      [:footer
-       [:div.container
-        [:p.muted.credit "By " (link-to "http://www.citerus.se/" "Citerus") " " [:i.icon-star-empty ]
-                                " Styling support by " (link-to "http://twitter.github.com/bootstrap/index.html" "Bootstrap. ") [:i.icon-star-empty ]
-                                " Icons by " (link-to "http://glyphicons.com/" "Glyphicons")]]]
-       (include-js "js/jquery-1.9.1.min.js", "js/jquery-ui-1.10.2.custom.min.js", "js/bootstrap.min.js", "js/notes.js")])))
+     [:footer
+      [:div.container
+       [:p.muted.credit "By " (link-to "http://www.citerus.se/" "Citerus") " " [:i.icon-star-empty ]
+        " Styling support by " (link-to "http://twitter.github.com/bootstrap/index.html" "Bootstrap. ") [:i.icon-star-empty ]
+        " Icons by " (link-to "http://glyphicons.com/" "Glyphicons")]]]
+     (include-js "js/jquery-1.9.1.min.js", "js/jquery-ui-1.10.2.custom.min.js", "js/bootstrap.min.js", "js/notes.js")])))

 (defroutes app-routes
   (GET "/" [] (front-page (find-notes)))
   (POST "/" [heading body]
-    (do
-      (save-note! {:heading heading :body body :ts (DateTime.)})
-      (let [notes (find-notes)]
-        (front-page (cons (assoc (first notes) :added? true) (rest notes))))))
+        (do
+          (save-note! {:heading heading :body body :ts (DateTime.)})
+          (let [notes (find-notes)]
+            (front-page (cons (assoc (first notes) :added? true) (rest notes))))))
   (DELETE "/" [id]
-    (do
-      (delete-note! id)
-      (front-page (find-notes))))
+          (do
+            (delete-note! id)
+            (front-page (find-notes))))
   (route/resources "/")
   (route/not-found "Not Found"))

 (def app
-  (handler/site app-routes))+  (handler/site app-routes))
+
+(defn -main [port]
+  (jetty/run-jetty app {:port (Integer. port)}))


Fix how the screen is updated

Fix how the screen is updated

--- src/play_clj/core.clj
+++ src/play_clj/core.clj
@@ -45,8 +45,9 @@

 (defn ^:private reset-changed!
   [e-atom e-old e-new]
-  (when (not= e-old e-new)
-    (compare-and-set! e-atom e-old e-new)))
+  (when (and (not= e-old e-new)
+             (compare-and-set! e-atom e-old e-new))
+    e-new))

 (defn ^:private normalize
   [entities]
@@ -72,34 +73,33 @@
                                      #(normalize (func screen-map old-entities))
                                      (meta func))
                                    (wrapper screen)
-                                   (reset-changed! entities old-entities)))))
-        total-time (atom 0)]
-    ; update screen when either the screen or entities are changed
-    (add-watch screen :changed (fn [_ _ old-screen new-screen]
-                                 (update-screen! new-screen)))
-    (add-watch entities :changed (fn [_ _ _ new-entities]
-                                   (update-screen! @screen new-entities)))
-    ; return a map with all values related to the screen
+                                   (reset-changed! entities old-entities)
+                                   (update-screen! @screen)))))
+        update-fn! (fn [func args]
+                     (doto (apply swap! screen func args)
+                       update-screen!))]
     {:screen screen
      :entities entities
      :options options
      :show (fn []
-             (swap! screen assoc
-                    :total-time 0
-                    :update-fn! #(apply swap! screen %1 %2)
-                    :execute-fn! execute-fn!
-                    :on-timer on-timer
-                    :input-listeners (input-listeners options execute-fn!)
-                    :ui-listeners (ui-listeners options execute-fn!))
+             (update-fn! assoc
+                         [:total-time 0
+                          :update-fn! update-fn!
+                          :execute-fn! execute-fn!
+                          :on-timer on-timer
+                          :input-listeners (input-listeners options execute-fn!)
+                          :ui-listeners (ui-listeners options execute-fn!)])
              (execute-fn! on-show)
              (->> (contact-listener @screen options execute-fn!)
                   (swap! screen assoc :contact-listener)))
      :render (fn [d]
-               (swap! total-time + d)
-               (execute-fn! on-render :delta-time d :total-time @total-time))
+               (swap! screen #(assoc % :total-time (+ (:total-time %) d)))
+               (execute-fn! on-render :delta-time d))
      :hide #(execute-fn! on-hide)
      :pause #(execute-fn! on-pause)
-     :resize #(execute-fn! on-resize :width %1 :height %2)
+     :resize (fn [w h]
+               (execute-fn! on-resize :width w :height h)
+               (update-screen! @screen))
      :resume #(execute-fn! on-resume)}))

 (defmacro defscreen
@@ -119,6 +119,7 @@
       :on-render ; the screen must be rendered (many times per second)
       (fn [screen entities]
         (println (:delta-time screen)) ; time (ms) elapsed since last frame
+        (println (:total-time screen)) ; time (ms) elapsed since :on-show
         entities)
       :on-hide ; the screen was replaced
       (fn [screen entities]
@@ -438,22 +439,23 @@

     (set-screen! my-game main-screen text-screen)"
   [^Game game-object & screen-objects]
-  (let [add-inputs! (fn []
-                      (input! :set-input-processor (InputMultiplexer.))
-                      (doseq [{:keys [screen]} screen-objects]
-                        (doseq [[_ listener] (:input-listeners @screen)]
-                          (add-input! listener))))
-        run-fn! (fn [k & args]
+  (let [run-fn! (fn [k & args]
                   (doseq [screen screen-objects]
                     (apply (get screen k) args)))]
-    (.setScreen game-object (reify Screen
-                              (show [this] (run-fn! :show) (add-inputs!))
-                              (render [this d] (run-fn! :render d))
-                              (hide [this] (run-fn! :hide))
-                              (pause [this] (run-fn! :pause))
-                              (resize [this w h] (run-fn! :resize w h))
-                              (resume [this] (run-fn! :resume))
-                              (dispose [this])))))
+    (.setScreen game-object
+      (reify Screen
+        (show [this]
+          (input! :set-input-processor (InputMultiplexer.))
+          (run-fn! :show)
+          (doseq [{:keys [screen]} screen-objects]
+            (doseq [[_ listener] (:input-listeners @screen)]
+              (add-input! listener))))
+        (render [this d] (run-fn! :render d))
+        (hide [this] (run-fn! :hide))
+        (pause [this] (run-fn! :pause))
+        (resize [this w h] (run-fn! :resize w h))
+        (resume [this] (run-fn! :resume))
+        (dispose [this])))))

 (defn set-screen-wrapper!
   "Sets a function that wraps around all screen functions, allowing you to


Make reference frame and depth datum top-level

Previous commits only defined these values when generating a random
value.

This commit allows these reference values to be use from the REPL.

--- src/test_utils/fracture_diagnostics.cljc
+++ src/test_utils/fracture_diagnostics.cljc
@@ -520,11 +520,15 @@
        typical-location-in-ft
        (vec (map #(length-as % :m) typical-location-in-ft))))))

+(def well-reference-frames-xy [:project :well-head :absolute-state-plane])
+
 (defn rand-well-reference-frame-xy []
-  (rand-nth [:project :well-head :absolute-state-plane]))
+  (rand-nth well-reference-frames-xy))
+
+(def depth-datums [:ground-level :kelly-bushing :sea-level])

 (defn rand-depth-datum []
-  (rand-nth [:ground-level :kelly-bushing :sea-level]))
+  (rand-nth depth-datums))

 (defn typical-kelly-bushing-elevation []
   (tuc/draw-normal 30.48 (/ 1.00 3.00)))


CMR-2365: Added comments.

CMR-2365: Added comments.

--- metadata-db-app/src/cmr/metadata_db/services/concept_service.clj
+++ metadata-db-app/src/cmr/metadata_db/services/concept_service.clj
@@ -378,6 +378,9 @@
           (validate-concept-revision-id db provider tombstone previous-revision)
           (let [revisioned-tombstone (->> (set-or-generate-revision-id db provider tombstone previous-revision)
                                           (try-to-save db provider))]
+            ;; skip publication flag is only set for tag association when its associated collection
+            ;; revision is force deleted. In this case, the tag association is no longer needed to
+            ;; be indexed, so we don't publish the deletion event.
             (when-not skip-publication
               (ingest-events/publish-event
                 context (ingest-events/concept-delete-event revisioned-tombstone)))


Put cancel-pause on the right path

Put cancel-pause on the right path

--- src/exploud/web.clj
+++ src/exploud/web.clj
@@ -264,7 +264,7 @@
                (response "Pause registered and will take effect after the next task finishes" "text/plain" 200))
              (response "No deployment is in progress" "text/plain" 409))))

-   (DELETE "/application/:application/:environment/pause"
+   (DELETE "/applications/:application/:environment/pause"
            [application environment]
            (let [parameters {:application application
                              :environment environment


Print return value of function application with arguments

--- src/mbeanz/core.clj
+++ src/mbeanz/core.clj
@@ -59,7 +59,7 @@
                             (map #(keyword (.getType %)))
                             (map list args)
                             (map cast-type))]
-        (apply jmx/invoke bean-name operation typed-args))
+        (println (apply jmx/invoke bean-name operation typed-args)))
       (println (jmx/invoke bean-name operation)))
     (System/exit 0)))


Extract the source_date from the source_edition

when importing from ABACUS

--- src/mdr2/abacus.clj
+++ src/mdr2/abacus.clj
@@ -47,6 +47,15 @@
    :idVorstufe [:MetaData :sbs :idVorstufe text]
    })

+(defn source-date
+  "Extract the source date from a raw `production` by taking the last
+  segment of the `:source_edition`"
+  [{source_edition :source_edition}]
+  (-> source_edition
+      (string/split #"/")
+      last
+      (->> (re-find #"\d{4}"))))
+
 (defn clean-raw-production
   "Return a proper production based on a raw production, i.e. drop
   `:mvl_only`, `:command` and `:idVorstufe` and add `:production_type`
@@ -59,6 +68,7 @@
     (-> raw-production
         (dissoc :mvl_only :command :idVorstufe)
         (assoc :production_type production_type)
+        (assoc :source_date (source-date raw-production))
         (cond-> (= production_type "periodical")
           (assoc :periodical_number idVorstufe)))))


reformat

reformat

--- src/funcgo/core.clj
+++ src/funcgo/core.clj
@@ -22,7 +22,7 @@
 Operand     = Literal        (*| OperandName | MethodExpr | '(' Expression ')' *)
 Literal     = BasicLit       (*| CompositeLit | FunctionLit *)
 BasicLit    = int_lit        (*| float_lit | imaginary_lit | rune_lit | string_lit *)
-int_lit     = decimal_lit   (*| octal_lit | hex_lit .*)
+int_lit     = decimal_lit    (*| octal_lit | hex_lit .*)
 decimal_lit = #'[1-9][0-9]*'

 identifier     = #'[\\p{L}_][\\p{L}_\\p{Digit}]*'  (* letter { letter | unicode_digit } *)
@@ -38,7 +38,7 @@

 (defn funcgo-parse [fgo]
-  (insta/transform {
-                    :PackageClause (fn [identifier & import-decl] (str "(ns " (second identifier) ")"))
-                    }
-                   (funcgo-parser fgo)))+  (insta/transform
+   {
+    :PackageClause (fn [identifier & import-decl] (str "(ns " (second identifier) ")")) }
+   (funcgo-parser fgo)))


Add comments

Add comments

--- lein-template/src/leiningen/new/modular/website.clj
+++ lein-template/src/leiningen/new/modular/website.clj
@@ -8,21 +8,44 @@

 {{! "We change the delimiters to avoid conflicting with nested destructuring in the code below" }}
 {{=<% %>=}}
-(defn index []
+
+(defn index
+  "Define a Liberator resource map for the index (home) page of the website"
+  []
   {:available-media-types #{"text/html"}
-   :handle-ok (fn [{{routes :modular.bidi/routes} :request}]
-                (html
-                 [:head
-                  [:title "Welcome"]]
-                 [:body
-                  [:h1 "Hello World! from <% name %>"]
-                  [:h2 "Links"]
-                  [:p [:a {:href (path-for routes ::main)} "Home"]]
-                  ]))})
+   :handle-ok
+   (fn [{{routes :modular.bidi/routes} ; it is common to destructure the
+                                       ; bidi route structure from the
+                                       ; request
+         :request}]
+     (html
+      [:head
+       [:title "Welcome"]]
+      [:body
+       [:h1 "Hello World! from <% name %>"]
+       [:h2 "Links"]
+       [:p [:a {:href (path-for routes ::main)} "Home"]]
+       ]))})
+
+;; Consider the component below. It is defined by defrecord.
+;; It satisfies 2 protocols: modular.bidi.WebService and modular.ring.RingHandler
+
+;; To satisfy modular.bidi.WebSerivce a component must provide the following:
+;;   ring-handler-map: A map between keywords and Ring handlers
+;;   routes: A bidi route structure, where terminals are keywords
+;;              - these keywords correspond to the keys in ring-handler-map
+;;   uri-context: Usually an empty string, but acts as a prefix to the route structure
+
+;; By also satisfying the RingHandler protocol, this component can be
+;; made a direct dependency of a Ring-compatible web server like
+;; http-kit or Jetty. Whether this is the only web-serving component in
+;; an application, or one of many (composed together by a router),
+;; depends on the system's dependency map defined in system.clj
+
+;; Finally there is the constructor, a function which creates an
+;; instance of the component record.

 (defrecord Website []
-  ;; Components such as this provide routes and handlers under an
-  ;; optional uri prefix (called the uri-context)
   WebService
   (ring-handler-map [_]
     {::main (-> (index) resource)})
@@ -31,11 +54,6 @@

   (uri-context [_] "")

-  ;; By satisfying the RingHandler protocol, this component can be made
-  ;; a direct dependency of a Ring-compatible web server like http-kit
-  ;; or Jetty. Whether this is the only web-serving component in an
-  ;; application, or one of many (composed together by a router),
-  ;; depends on the system's dependency map defined in system.clj
   RingHandler
   (ring-handler [this] (as-ring-handler this)))


WIP: add default configuracion map.

WIP: add default configuracion map.