Schedule page (and minor fixes)

Schedule page (and minor fixes)

--- src/cljs/elevent_client/core.cljs
+++ src/cljs/elevent_client/core.cljs
@@ -144,6 +144,7 @@
          event-activities-explore-page
          event-activity-page
          event-activity-edit-page
+         event-schedule-page
          event-attendees-page
          event-attendee-page
          organizations-page
@@ -197,6 +198,10 @@
 (defroute event-activity-add-route
   "/events/:EventId/activities/add" [EventId]
   (reset! current-page [#'event-activity-edit-page (int EventId)]))
+
+(defroute event-schedule-route
+  "/events/:EventId/schedule" [EventId]
+  (reset! current-page [#'event-schedule-page (int EventId)]))

 (defroute event-activity-route
   "/events/:EventId/activities/:ActivityId" [EventId ActivityId]
@@ -427,7 +432,8 @@
                           event-activities-breadcrumbs]
             "attendees" [["Attendees" (event-attendees-route env)]
                          env
-                         event-attendees-breadcrumbs]))
+                         event-attendees-breadcrumbs]
+            "schedule" [["Schedule" (event-schedule-route)] env nil]))

         events-breadcrumbs
         (fn [env fragment]
@@ -560,7 +566,6 @@
             (:Name event)]
            [:div.meta
             [:strong "Date:"]
-            " "
             (let [start (from-string (:StartDate event))
                   end   (from-string (:EndDate   event))]
               (str (unparse datetime-formatter start)
@@ -568,12 +573,11 @@
                      (str " to " (unparse datetime-formatter end)))))]
            [:div.meta
             [:strong "Venue:"]
-            " "
             (:Venue event)]
            [:div.description
             (:Description event)]
            [:div.extra
-            [:a.ui.right.floated.button {:href (event-activities-route)}
+            [:a.ui.right.floated.button {:href (event-schedule-route event)}
              "Your activities"
              [:i.right.chevron.icon]]]]])]]]
     [:div.ui.dimmer {:class (when (empty? @events) "active")}
@@ -766,72 +770,71 @@
                                                            (from-string end-time))))
                                      #(reset-form!))))]
         (when (seq event)
-          [:div.ui.page.grid
-           [:div.sixteen.wide.column
-            [:div.ui.segment
-             [:div.ui.vertical.segment
-              [:h2.ui.header
-               (:Name event)]]
-             [:div.ui.vertical.segment
-              [:h2.ui.header
-               "Add activity"]
-              [:form.ui.form
-               [:div.one.field
-                [:div.required.field {:class (when (and Name (:Name errors))
-                                               "error")}
-                 [:label "Name"]
-                 [input-atom :text (r/wrap Name swap! form assoc :Name)]]]
-               [:div.two.fields
-                [:div.field
-                 [:label "Location"]
-                 [input-atom :text (r/wrap Location swap! form assoc :Location)]]
-                [:div.field {:class (when (and EnrollmentCap (:EnrollmentCap errors))
-                                      "error")}
-                 [:label "Enrollment Cap"]
-                 [input-atom :text (r/wrap EnrollmentCap swap! form assoc :EnrollmentCap)]]]
-               [:div.two.fields =
-                [:div.required.field {:class (when (and StartTime (:StartTime errors))
-                                               "error")}
-                 [:label "Start Time"]
-                 [input-atom :datetime-local
-                  (r/wrap StartTime swap! form assoc :StartTime)
-                  #(or % (unparse (:date-hour-minute formatters) (now))) ; todo: date inputs clear on input
-                  #(unparse (:date-hour-minute formatters) (from-string %))]]
-                [:div.required.field {:class (when (and EndTime (:EndTime errors))
-                                               "error")}
-                 [:label "End Time"]
-                 [input-atom :datetime-local
-                  (r/wrap EndTime swap! form assoc :EndTime)
-                  #(or % (unparse (:date-hour-minute formatters) (now)))
-                  #(unparse (:date-hour-minute formatters) (from-string %))]]]
+          [:div.sixteen.wide.column
+           [:div.ui.segment
+            [:div.ui.vertical.segment
+             [:h2.ui.header
+              (:Name event)]]
+            [:div.ui.vertical.segment
+             [:h2.ui.header
+              "Add activity"]
+             [:form.ui.form
+              [:div.one.field
+               [:div.required.field {:class (when (and Name (:Name errors))
+                                              "error")}
+                [:label "Name"]
+                [input-atom :text (r/wrap Name swap! form assoc :Name)]]]
+              [:div.two.fields
                [:div.field
-                [:label "Description"]
-                [input-atom :textarea
-                 (r/wrap Description swap! form assoc :Description)]]
-               [:button.ui.primary.button {:class (when (seq errors) "disabled")
-                                           :type :submit
-                                           :on-click #(create-activity @form)}
-                "Add"]]]
-             [:div.ui.vertical.segment
-              [:h2.ui.header
-               "Activities"]
-              [:table.ui.table
-               [:thead
-                [:tr
-                 [:th "Start Time"]
-                 [:th "End Time"]
-                 [:th "Activity"]
-                 [:th "Location"]]]
-               [:tbody
-                (for [activity activities]
-                  ^{:key (:ActivityId activity)}
-                  [:tr
-                   [:td (let [start (from-string (:StartTime activity))]
-                          (unparse datetime-formatter start))]
-                   [:td (let [end   (from-string (:EndTime   activity))]
-                          (unparse datetime-formatter end))]
-                   [:td (:Name activity)]
-                   [:td (:Location activity)]])]]]]]])))))
+                [:label "Location"]
+                [input-atom :text (r/wrap Location swap! form assoc :Location)]]
+               [:div.field {:class (when (and EnrollmentCap (:EnrollmentCap errors))
+                                     "error")}
+                [:label "Enrollment Cap"]
+                [input-atom :text (r/wrap EnrollmentCap swap! form assoc :EnrollmentCap)]]]
+              [:div.two.fields =
+               [:div.required.field {:class (when (and StartTime (:StartTime errors))
+                                              "error")}
+                [:label "Start Time"]
+                [input-atom :datetime-local
+                 (r/wrap StartTime swap! form assoc :StartTime)
+                 #(or % (unparse (:date-hour-minute formatters) (now))) ; todo: date inputs clear on input
+                 #(unparse (:date-hour-minute formatters) (from-string %))]]
+               [:div.required.field {:class (when (and EndTime (:EndTime errors))
+                                              "error")}
+                [:label "End Time"]
+                [input-atom :datetime-local
+                 (r/wrap EndTime swap! form assoc :EndTime)
+                 #(or % (unparse (:date-hour-minute formatters) (now)))
+                 #(unparse (:date-hour-minute formatters) (from-string %))]]]
+              [:div.field
+               [:label "Description"]
+               [input-atom :textarea
+                (r/wrap Description swap! form assoc :Description)]]
+              [:button.ui.primary.button {:class (when (seq errors) "disabled")
+                                          :type :submit
+                                          :on-click #(create-activity @form)}
+               "Add"]]]
+            [:div.ui.vertical.segment
+             [:h2.ui.header
+              "Activities"]
+             [:table.ui.table
+              [:thead
+               [:tr
+                [:th "Start Time"]
+                [:th "End Time"]
+                [:th "Activity"]
+                [:th "Location"]]]
+              [:tbody
+               (for [activity activities]
+                 ^{:key (:ActivityId activity)}
+                 [:tr
+                  [:td (let [start (from-string (:StartTime activity))]
+                         (unparse datetime-formatter start))]
+                  [:td (let [end   (from-string (:EndTime   activity))]
+                         (unparse datetime-formatter end))]
+                  [:td (:Name activity)]
+                  [:td (:Location activity)]])]]]]])))))

 (defn event-page [event-id]
   (let [event (into {} (seq (d/entity @events-db event-id)))
@@ -864,88 +867,87 @@
                                   @attendees-db
                                   event-id)))]
     (when (seq event)
-      [:div.ui.page.grid
-       [:div.sixteen.wide.column
-        [:div.ui.segment
-         [:div.ui.vertical.segment
-          [:h2.ui.dividing.header
-           (:Name event)]
-          [:div.ui.right.floated.small.labeled.icon.button
-           [:i.edit.icon]
-           "Edit"]
-          [:div
-           [:b "Date: "]
-           (when (and (:StartDate event)
-                      (:EndDate event))
-             (let [start (from-string (:StartDate event))
-                   end   (from-string (:EndDate   event))]
-               (str (unparse datetime-formatter start)
-                    (when (after? end start)
-                      (str " to "
-                           (unparse datetime-formatter end))))))]
-          [:div
-           [:b "Venue: "] (:Venue event)]
-          [:p (:Description event)]]
-         [:div.ui.vertical.segment
-          [:h2.ui.header
-           "Activities"]
-          [:table.ui.table
-           [:thead
-            [:tr
-             [:th "Start"]
-             [:th "End"]
-             [:th "Activity"]
-             [:th "Location"]]]
-           [:tbody
-            (for [activity activities]
-                ^{:key (:ActivityId activity)}
-                [:tr
-                 [:td {:noWrap true}
-                  (when activity
-                    (unparse datetime-formatter
-                             (from-string (:StartTime activity))))]
-                 [:td {:noWrap true}
-                  (when activity
-                    (unparse datetime-formatter
-                             (from-string (:EndTime activity))))]
-                 [:td (:Name activity)]
-                 [:td (:Location activity)]])]
-           [:tfoot
-            [:tr
-             [:th {:colSpan "4"}
-              [:a.ui.right.floated.small.labeled.icon.button
-               {:href (event-activity-add-route event)}
-               [:i.edit.icon]
-               "Edit"]]]]]]
-         [:div.ui.vertical.segment
-          [:h2.ui.header
-           "Attendees"
-           [:a.ui.right.floated.small.button
-            {:href (event-attendees-route event)}
-            "View"]]
-          [:table.ui.table
-           [:thead
-            [:tr
-             [:th "Name"]
-             [:th]]]
-           [:tbody
-            (for [attendee attendees]
-              ^{:key (:AttendeeId attendee)}
-              [:tr
-               [:td (str (:FirstName attendee) " " (:LastName attendee))]
-               [:td [:a.ui.right.floated.small.labeled.button
-                     {:href (event-attendee-route {:EventId (:EventId event)
-                                                   :AttendeeId (:AttendeeId attendee)})
-                      :class (when (:CheckinTime attendee) :green)}
-                     (if (:CheckinTime attendee)
-                       "Checked in"
-                       "Check in")]]])]
-           [:tfoot
-            [:tr
-             [:th {:colSpan "4"}
-              [:div.ui.right.floated.small.labeled.icon.button
-               [:i.edit.icon]
-               "Edit"]]]]]]]]])))
+      [:div.sixteen.wide.column
+       [:div.ui.segment
+        [:div.ui.vertical.segment
+         [:h2.ui.dividing.header
+          (:Name event)]
+         [:div.ui.right.floated.small.labeled.icon.button
+          [:i.edit.icon]
+          "Edit"]
+         [:div
+          [:b "Date: "]
+          (when (and (:StartDate event)
+                     (:EndDate event))
+            (let [start (from-string (:StartDate event))
+                  end   (from-string (:EndDate   event))]
+              (str (unparse datetime-formatter start)
+                   (when (after? end start)
+                     (str " to "
+                          (unparse datetime-formatter end))))))]
+         [:div
+          [:b "Venue: "] (:Venue event)]
+         [:p (:Description event)]]
+        [:div.ui.vertical.segment
+         [:h2.ui.header
+          "Activities"]
+         [:table.ui.table
+          [:thead
+           [:tr
+            [:th "Start"]
+            [:th "End"]
+            [:th "Activity"]
+            [:th "Location"]]]
+          [:tbody
+           (for [activity activities]
+             ^{:key (:ActivityId activity)}
+             [:tr
+              [:td {:noWrap true}
+               (when activity
+                 (unparse datetime-formatter
+                          (from-string (:StartTime activity))))]
+              [:td {:noWrap true}
+               (when activity
+                 (unparse datetime-formatter
+                          (from-string (:EndTime activity))))]
+              [:td (:Name activity)]
+              [:td (:Location activity)]])]
+          [:tfoot
+           [:tr
+            [:th {:colSpan "4"}
+             [:a.ui.right.floated.small.labeled.icon.button
+              {:href (event-activity-add-route event)}
+              [:i.edit.icon]
+              "Edit"]]]]]]
+        [:div.ui.vertical.segment
+         [:h2.ui.header
+          "Attendees"
+          [:a.ui.right.floated.small.button
+           {:href (event-attendees-route event)}
+           "View"]]
+         [:table.ui.table
+          [:thead
+           [:tr
+            [:th "Name"]
+            [:th]]]
+          [:tbody
+           (for [attendee attendees]
+             ^{:key (:AttendeeId attendee)}
+             [:tr
+              [:td (str (:FirstName attendee) " " (:LastName attendee))]
+              [:td [:a.ui.right.floated.small.labeled.button
+                    {:href (event-attendee-route {:EventId (:EventId event)
+                                                  :AttendeeId (:AttendeeId attendee)})
+                     :class (when (:CheckinTime attendee) :green)}
+                    (if (:CheckinTime attendee)
+                      "Checked in"
+                      "Check in")]]])]
+          [:tfoot
+           [:tr
+            [:th {:colSpan "4"}
+             [:div.ui.right.floated.small.labeled.icon.button
+              [:i.edit.icon]
+              "Edit"]]]]]]]])))

 (defn event-attendee-page [event-id attendee-id]
   (let [check-in-or-out
@@ -1042,93 +1044,92 @@
                                                                     ;(reset! checked-in false)
                                                                     (callback))))))]
           (when (seq event)
-            [:div.ui.page.grid
-             [:div.sixteen.wide.column
-              [:div.ui.segment
-               [:div
-                [:div.ui.vertical.segment
-                 [:h1.ui.header
-                  (str (:FirstName @attendee) " " (:LastName @attendee))]]
-                [:div.ui.vertical.segment
-                 [:div.ui.divided.items
-                  [:div.item
-                   [:div.content
-                    [:a.header
-                     {:href (event-route event)}
-                     (:Name event)]
-                    [:div.meta
-                     [:b "Date: "]
-                     (when event
-                       (let [start (from-string (:StartDate event))
-                             end   (from-string (:EndDate   event))]
-                         (str (unparse datetime-formatter start)
-                              (when (after? end start)
-                                (str " to " (unparse datetime-formatter end))))))]
-                    [:div.meta
-                     [:b "Venue: "]
-                     (:Venue event)]
-                    [:div.description
-                     (:Description event)]
-                    [:div.extra
-                     [:div.ui.right.floated.button
-                      {:on-click #(if (:CheckinTime @attendee)
-                                    (check-out attendee-id)
-                                    (check-in attendee-id))}
-                      @button-text]]]]]]
-                [:div.ui.vertical.segment
-                 [:h3.ui.header
-                  "Attendee Info"]
-                 [:table.ui.definition.table.attendee-info
-                  [:tbody
-                   [:tr
-                    [:td "Email"]
-                    [:td (:Email @attendee)]]]]]
-                [:div.ui.vertical.segment
-                 [:h3.ui.header
-                  "Attendee Schedule"]
-                 [:table.ui.table
-                  [:thead
-                   [:tr
-                    [:th "Start"]
-                    [:th "End"]
-                    [:th "Activity"]
-                    [:th "Location"]
-                    [:th]]]
-                  [:tbody
-                   (for [[schedule-id activity-id] attendee-activities]
-                     ^{:key schedule-id}
-                     (let [activity
-                           (when activity-id
-                             (d/entity @activities-db activity-id))
-                           schedule
-                           (when schedule-id
-                             (d/entity @schedules-db schedule-id))]
-                       (let
-                         [checked-in (atom (not (nil? (:CheckinTime schedule))))
-                          checking-in (atom false)]
-                         [:tr
-                          [:td {:noWrap true}
-                           (when activity
-                             (unparse datetime-formatter
-                                      (from-string (:StartTime activity))))]
-                          [:td {:noWrap true}
-                           (when activity
-                             (unparse datetime-formatter
-                                      (from-string (:EndTime activity))))]
-                          [:td (:Name activity)]
-                          [:td (:Location activity)]
-                          [:td.right.aligned {:noWrap true}
-                           [:div.ui.button
-                            {:on-click (fn []
-                                         (reset! checking-in true)
-                                         (if @checked-in
-                                           (activity-check-out schedule-id checked-in #(reset! checking-in false))
-                                           (activity-check-in schedule-id checked-in #(reset! checking-in false))))}
-                            (if @checking-in
-                              [:i.spinner.loading.icon] ; todo: not working
-                              (if @checked-in
-                                "Check out"
-                                "Check in"))]]])))]]]]]]]))))))
+            [:div.sixteen.wide.column
+             [:div.ui.segment
+              [:div
+               [:div.ui.vertical.segment
+                [:h1.ui.header
+                 (str (:FirstName @attendee) " " (:LastName @attendee))]]
+               [:div.ui.vertical.segment
+                [:div.ui.divided.items
+                 [:div.item
+                  [:div.content
+                   [:a.header
+                    {:href (event-route event)}
+                    (:Name event)]
+                   [:div.meta
+                    [:b "Date: "]
+                    (when event
+                      (let [start (from-string (:StartDate event))
+                            end   (from-string (:EndDate   event))]
+                        (str (unparse datetime-formatter start)
+                             (when (after? end start)
+                               (str " to " (unparse datetime-formatter end))))))]
+                   [:div.meta
+                    [:b "Venue: "]
+                    (:Venue event)]
+                   [:div.description
+                    (:Description event)]
+                   [:div.extra
+                    [:div.ui.right.floated.button
+                     {:on-click #(if (:CheckinTime @attendee)
+                                   (check-out attendee-id)
+                                   (check-in attendee-id))}
+                     @button-text]]]]]]
+               [:div.ui.vertical.segment
+                [:h3.ui.header
+                 "Attendee Info"]
+                [:table.ui.definition.table.attendee-info
+                 [:tbody
+                  [:tr
+                   [:td "Email"]
+                   [:td (:Email @attendee)]]]]]
+               [:div.ui.vertical.segment
+                [:h3.ui.header
+                 "Attendee Schedule"]
+                [:table.ui.table
+                 [:thead
+                  [:tr
+                   [:th "Start"]
+                   [:th "End"]
+                   [:th "Activity"]
+                   [:th "Location"]
+                   [:th]]]
+                 [:tbody
+                  (for [[schedule-id activity-id] attendee-activities]
+                    ^{:key schedule-id}
+                    (let [activity
+                          (when activity-id
+                            (d/entity @activities-db activity-id))
+                          schedule
+                          (when schedule-id
+                            (d/entity @schedules-db schedule-id))]
+                      (let
+                        [checked-in (atom (not (nil? (:CheckinTime schedule))))
+                         checking-in (atom false)]
+                        [:tr
+                         [:td {:noWrap true}
+                          (when activity
+                            (unparse datetime-formatter
+                                     (from-string (:StartTime activity))))]
+                         [:td {:noWrap true}
+                          (when activity
+                            (unparse datetime-formatter
+                                     (from-string (:EndTime activity))))]
+                         [:td (:Name activity)]
+                         [:td (:Location activity)]
+                         [:td.right.aligned {:noWrap true}
+                          [:div.ui.button
+                           {:on-click (fn []
+                                        (reset! checking-in true)
+                                        (if @checked-in
+                                          (activity-check-out schedule-id checked-in #(reset! checking-in false))
+                                          (activity-check-in schedule-id checked-in #(reset! checking-in false))))}
+                           (if @checking-in
+                             [:i.spinner.loading.icon] ; todo: not working
+                             (if @checked-in
+                               "Check out"
+                               "Check in"))]]])))]]]]]]))))))

 (defn event-register-page [event-id]
   (let [form (atom {:Email (get-in @session [:user :Email])
@@ -1195,6 +1196,115 @@
                {:type :submit :on-click #(register @form)}
                "Register"]]]]])))))

+(defn event-schedule-page [event-id]
+  (let [event (into {} (seq (d/entity @events-db event-id)))
+
+        scheduled-activities
+        (d/q '[:find ?schedule-id ?activity-id
+               :in $activities $schedules ?event-id ?user-id
+               :where
+               [$activities ?activity-id :EventId ?event-id]
+               [$schedules  ?schedule-id :UserId     ?user-id]
+               [$schedules  ?schedule-id :ActivityId ?activity-id]]
+             @activities-db
+             @schedules-db
+             event-id
+             (get-in @session [:user :UserId]))
+
+        event-activities
+        (d/q '[:find ?activity-id
+               :in $ ?event-id
+               :where
+               [?activity-id :EventId ?event-id]]
+             @activities-db
+             event-id)
+
+        unscheduled-activities
+        (set/difference event-activities (into #{} (map #(vector (second %))
+                                                    scheduled-activities)))
+
+        add-activity!
+        (fn [user-id activity-id]
+          (schedules-endpoint :create
+                              {:ActivityId activity-id
+                               :UserId     user-id}
+                              nil))
+
+        remove-activity!
+        (fn [schedule]
+          (schedules-endpoint :delete schedule nil))]
+    (when (seq event)
+   [:div.sixteen.wide.column
+    [:div.ui.segment
+     [:div.ui.vertical.segment
+      [:h2.ui.header
+       (str (get-in @session [:user :FirstName]) "'s Schedule for " (:Name event))]]
+     [:div.ui.vertical.segment
+      [:table.ui.table
+       [:thead
+        [:tr
+         [:th "Start"]
+         [:th "End"]
+         [:th "Activity"]
+         [:th "Location"]
+         [:th]]]
+       [:tbody
+        (for [[schedule-id activity-id] scheduled-activities]
+          ^{:key schedule-id}
+          (let [activity
+                (when activity-id
+                         (d/entity @activities-db activity-id))]
+            [:tr
+             [:td {:noWrap true}
+              (when activity
+                (unparse datetime-formatter
+                         (from-string (:StartTime activity))))]
+             [:td {:noWrap true}
+              (when activity
+                (unparse datetime-formatter
+                         (from-string (:EndTime activity))))]
+             [:td (:Name activity)]
+             [:td (:Location activity)]
+             [:td.right.aligned {:noWrap true}
+              [:div.ui.button
+               {:on-click #(remove-activity!
+                             (d/entity @schedules-db
+                                       schedule-id))}
+               [:i.red.remove.icon] "Remove"]]]))]
+       [:tfoot
+        [:tr
+         [:th {:colSpan "6"}
+          [:div.ui.small.labeled.icon.button
+           [:i.print.icon] "Print"]]]]]]
+     [:div.ui.vertical.segment
+      [:div.ui.divided.items
+       (for [[activity-id] unscheduled-activities]
+         ^{:key activity-id}
+         (let [activity
+               (when activity-id
+                 (d/entity @activities-db activity-id))]
+           [:div.item
+            [:div.content
+             [:a.header (:Name activity)]
+             [:div.meta (:Location activity)]
+             [:div (str (when activity
+                          (unparse datetime-formatter
+                                   (from-string
+                                     (:StartTime activity))))
+                        " - "
+                        (when activity
+                          (unparse datetime-formatter
+                                   (from-string
+                                     (:EndTime activity)))))]
+             [:div.description
+              (:Description activity)]
+             [:div.extra
+              [:div.ui.right.floated.primary.button
+               {:on-click #(add-activity! (get-in @session [:user :UserId])
+                                          (:ActivityId activity))}
+               "Add"
+               [:i.right.chevron.icon]]]]]))]]]])))
+
 (defn sign-in-page []
   (let [form (atom {})
         validator (validation-set (format-of :email :format #"@")


Clean up errors left over from client refactor

When I broke it into multiple namespaces, I didn't fix the names of all
the pieces that moved.

--- src/clojure/frereth_cp/client.clj
+++ src/clojure/frereth_cp/client.clj
@@ -18,6 +18,7 @@
             [clojure.spec.alpha :as s]
             [clojure.tools.logging :as log]
             [frereth-cp.client.cookie :as cookie]
+            [frereth-cp.client.hello :as hello]
             [frereth-cp.client.state :as state]
             [frereth-cp.schema :as schema]
             [frereth-cp.shared :as shared]
@@ -25,7 +26,6 @@
             [frereth-cp.shared.crypto :as crypto]
             [frereth-cp.shared.constants :as K]
             [frereth-cp.util :as util]
-            #_[com.stuartsierra.component :as cpt]
             [manifold.deferred :as deferred]
             [manifold.stream :as strm])
   (:import clojure.lang.ExceptionInfo
@@ -131,11 +131,11 @@
                                     text
                                     vouch
                                     work-area]
-                             :as this} (clientextension-init this)
+                             :as this} (state/clientextension-init this)
                             {:keys [::shared/packet
                                     ::shared/packet-nonce]} packet-management
                             _ (throw (RuntimeException. "this Component nonce isn't updated"))
-                            short-term-nonce (update-client-short-term-nonce
+                            short-term-nonce (state/update-client-short-term-nonce
                                               packet-nonce)
                             working-nonce (::shared/working-nonce work-area)]
                         (b-t/uint64-pack! working-nonce K/client-nonce-prefix-length
@@ -323,7 +323,7 @@
     ;; But it probably should, since this is very
     ;; explicitly place-oriented programming working
     ;; with mutable state.
-    (send wrapper do-build-hello)
+    (send wrapper hello/do-build-hello)
     (if (await-for timeout wrapper)
       (cope-with-successful-hello-creation wrapper chan->server timeout)
       (throw (ex-info (str "Timed out after " timeout


Run indent mode on cut/paste

Run indent mode on cut/paste

--- src/clojure/nightcode/editors.clj
+++ src/clojure/nightcode/editors.clj
@@ -413,7 +413,7 @@

               (and (or (.isControlDown e) (.isMetaDown e))
                 (contains? #{KeyEvent/VK_V KeyEvent/VK_X} (.getKeyCode e)))
-              (->> (get-parinfer-state text-area true)
+              (->> (get-parinfer-state text-area false)
                    (refresh-content! text-area)
                    (mwm/update-edit-history! edit-history))))
           (keyTyped [this e] nil)


Add/remove threading to clean up code

Add/remove threading to clean up code

--- src/clojure/nightcode/sandbox.clj
+++ src/clojure/nightcode/sandbox.clj
@@ -13,8 +13,7 @@
   (let [home (System/getProperty "user.home")
         dir (get-dir)]
     (when (and home dir)
-      (->> (apply io/file home dir dirs)
-           .getCanonicalPath))))
+      (.getCanonicalPath (apply io/file home dir dirs)))))

 (defn get-env
   []
@@ -92,6 +91,6 @@

 (defn update-permission-map!
   [k path]
-  (when-let [old-path (utils/read-pref k)]
-    (remove-from-permission-map! old-path))
+  (some-> (utils/read-pref k)
+          remove-from-permission-map!)
   (add-to-permission-map! path))


Cleanup.

Cleanup.

--- src/redis/internal.clj
+++ src/redis/internal.clj
@@ -7,6 +7,14 @@
            [java.net Socket]))

+(defstruct server :host :port :db :timeout :socket)
+
+(def *server* (struct-map server
+                :host     "127.0.0.1"
+                :port     6379
+                :db       0
+                :timeout  5000
+                :socket   nil))

 (def *cr* 0x0d)
 (def *lf* 0x0a)
@@ -17,21 +25,6 @@
 (defn- trim [#^String s] (.trim s))
 (defn- parse-int [#^String s] (Integer/parseInt s))
 (defn- char-array [len] (make-array Character/TYPE len))
-
-(def *default-host* "127.0.0.1")
-(def *default-port* 6379)
-(def *default-db* 0)
-(def *default-timeout* 5)
-
-
-(defstruct server :host :port :db :timeout :socket)
-
-(def *server* (struct-map server
-                :host     *default-host*
-                :port     *default-port*
-                :db       *default-db*
-                :timeout  *default-timeout* ;; not yet used
-                :socket   nil))

 (defn connect-to-server
   "Create a Socket connected to server"
@@ -39,6 +32,7 @@
   (let [{:keys [host port timeout]} server
         socket (Socket. #^String host #^Integer port)]
     (doto socket
+      (.setSoTimeout timeout)
       (.setTcpNoDelay true)
       (.setKeepAlive true))))

@@ -95,9 +89,6 @@
 ;;
 ;; Reply dispatching
 ;;
-
-
-
 (defn reply-type
   ([#^BufferedReader reader]
      (char (.read reader))))


Macht Name zu Saldo

Macht Name zu Saldo

--- src/hello_world/core.clj
+++ src/hello_world/core.clj
@@ -38,7 +38,7 @@
        (if name
   (str "Nice to meet you, " name "! \n" "

")
          (str "<form>"
-              "Name: <input name='name' type='text'>"
+              "MGM ID: <input name='saldo' type='text'>"
               "<input type='submit'>"
               "</form>"))
        (if saldo


Working operation propagation\!

Working operation propagation\!

--- src/tree/messaging.clj
+++ src/tree/messaging.clj
@@ -15,17 +15,20 @@

 (defprotocol IOperation
   (affects-key [op] "Which key this affects--currently must be a single key")
-  (apply-op [op tree] "Applies the operation to the tree"))
+  (apply-op-to-vector [op v] "Applies the operation to the vector")
+  (apply-op-to-tree [op tree] "Applies the operation to the tree"))

 (defrecord InsertOp [key]
   IOperation
   (affects-key [_] key)
-  (apply-op [_ tree] (core/insert tree key)))
+  (apply-op-to-vector [_ v] (core/-insertion-into-sorted-vector v key))
+  (apply-op-to-tree [_ tree] (core/insert tree key)))

 (defrecord DeleteOp [key]
   IOperation
   (affects-key [_] key)
-  (apply-op [_ tree] (core/delete tree key)))
+  (apply-op-to-vector [_ v] (core/-deletion-from-sorted-vector v key))
+  (apply-op-to-tree [_ tree] (core/delete tree key)))

 (defn enqueue
   "When enqueing "
@@ -33,7 +36,7 @@
    (let [deferred-ops (atom [])
          msg-buffers-propagated (enqueue tree msgs deferred-ops)]
      (reduce (fn [tree op]
-               (apply-op op tree))
+               (apply-op-to-tree op tree))
              msg-buffers-propagated
              @deferred-ops)))
   ([tree msgs deferred-ops]
@@ -123,7 +126,7 @@
     )
   )

-(clojure.pprint/pprint
+#_(clojure.pprint/pprint
   (-> (apply core/b-tree (range 30))
       (core/flush-tree) :tree
       (enqueue [(->InsertOp -1)])
@@ -148,7 +151,150 @@
 ;; scan for all "interesting" operations
 ;; apply those operations

+;;TODO we'll need to totally redo `apply-ops-in-path`
+;;luckily, here's the scoop on the algorithm:
+;;The idea is that once we've found a path, we now have a vector of data and
+;;the operations we've found along the path. All we need to do is combine those
+;;operations into the data-vector and we can finish our queries on the combined
+;;vector.
+;;
+;;You may think that you could just apply every operation on the path to the vector.
+;;This would only work for point queries--if you tried to do any sort of range query,
+;;you'd see anomalies like operations in the root node appearing in every datanode
+;;in the tree! So, we need to prune down all those operations into only the ones we
+;;should apply to this data node.
+;;
+;;The idea here is that we need to apply every operation which affects a key less
+;;than or equal to the data node's largest key to this node, while not applying
+;;operations which are less than or equal to its left sibling.
+;;
+;;Although the data-node may not have a direct left sibling, one of its parents
+;;could, so we must find the biggest left sibling's last key.
+;;
+;;We also need a special case to determine if we're the rightmost node, in which
+;;case we cannot ignore operations for keys bigger than our own.
+;;every
+
+(defn apply-ops-in-path
+  "Takes time proportional to the # of operations to apply them directly
+   to the data node at the bottom. Each insert will be lg time into the data
+   node, and there are at most lg_b(n)*op-buf-max operations to be applied.
+
+   Returns a sorted vector which is the flushed version of the path's terminus
+
+   TODO We could reduce this to only do ops of interest"
+  [path]
+  (let [ops (->> path
+                 (into [] (comp (filter core/index-node?)
+                                (map :op-buf)))
+                 (rseq) ; highest node should be last in seq
+                 (apply catvec)
+                 (sort-by affects-key)) ;must be a stable sort
+        this-node-index (-> path pop peek)
+        parent (-> path pop pop peek)
+        is-first? (zero? this-node-index)
+        ;;We'll need to find the smallest last-key of the left siblings along the path
+        [left-sibs-on-path is-last?]
+        (loop [path path
+               is-last? true
+               left-sibs []]
+          (if (= 1 (count path)) ; are we at the root?
+            [left-sibs is-last?]
+            (let [this-node-index (-> path pop peek)
+                  parent (-> path pop pop peek)
+                  is-first? (zero? this-node-index)
+                  local-last? (= (-> parent :children count dec)
+                                   this-node-index)]
+              (if is-first?
+                (recur (pop (pop path)) (and is-last? local-last?) left-sibs)
+                (recur (pop (pop path))
+                       (and is-last? local-last?)
+                       (conj left-sibs
+                             (nth (:children parent)
+                                  (dec this-node-index))))))))
+        left-sibs-min-last (when (seq left-sibs-on-path)
+                             (->> left-sibs-on-path
+                                  (map core/last-key)
+                                  (apply max)))
+        left-sib-filter (if left-sibs-min-last
+                          (drop-while #(>= 0 (core/compare (affects-key %)
+                                                           left-sibs-min-last)))
+                          identity)
+        data-node (peek path)
+        my-last (core/last-key data-node)
+        right-side-filter (if is-last?
+                            identity
+                            (take-while #(>= 0 (core/compare (affects-key %) my-last))))
+        correct-ops (into [] (comp left-sib-filter right-side-filter) ops)
+
+        ;;We include op if leq my left, and not if leq left's left
+        ;;TODO we can't apply all ops, we should ensure to only apply ops whose keys are in the defined range, unless we're the last sibling
+        ]
+   ; (println "left-sibs-min-last" left-sibs-min-last)
+   ; (println "is-last?" is-last?)
+   ; (println "expanding data node" data-node "with ops" correct-ops)
+    (reduce (fn [v op]
+              (apply-op-to-vector op v))
+            (:children data-node)
+            correct-ops)))
+
+#_(clojure.pprint/pprint
+  (-> (core/insert (apply core/b-tree (range 6)) -1)
+      (core/flush-tree) :tree
+      (enqueue [(->InsertOp -1)])
+      (enqueue [(->InsertOp -2)])
+      (enqueue [(->InsertOp 50)])
+      (enqueue [(->InsertOp -4)])
+      (enqueue [(->InsertOp -5)]) ; tree is totally filled up here
+  ;    (enqueue [(->InsertOp -8)])
+      ))
+
+
 (defn lookup
   [tree key]
-  )
-
+  (let [path (pop (pop (core/lookup-path tree key)))
+        expanded (apply-ops-in-path path)
+        i (Collections/binarySearch expanded key core/compare)]
+    (println expanded)
+    (when-not (neg? i)
+      (nth expanded i))))
+
+(comment
+  (def my-tree (-> (apply core/b-tree (range 30))
+      (core/flush-tree) :tree
+      (enqueue [(->InsertOp 8.3)])
+      (enqueue [(->InsertOp 6.7)])
+      (enqueue [(->InsertOp 10.5)])
+      (enqueue [(->InsertOp 10.6)])
+      ;(enqueue [(->InsertOp -5)]) ; tree is totally filled up here
+  ;    (enqueue [(->InsertOp -8)])
+      ))
+  (do (clojure.pprint/pprint my-tree)
+  (lookup-fwd-iter my-tree -100))
+  (lookup my-tree 50))
+
+(defn forward-iterator
+  "Takes the result of a search and returns an iterator going
+   forward over the tree. Does lg(n) backtracking sometimes."
+  [path]
+  (assert (core/data-node? (peek path)))
+  (let [first-elements (apply-ops-in-path path)
+        next-elements (lazy-seq
+                        (when-let [succ (core/right-successor (pop path))]
+                          (forward-iterator succ)))]
+    (concat first-elements next-elements)))
+
+(defn lookup-fwd-iter
+  [tree key]
+  (let [path (pop (pop (core/lookup-path tree key)))]
+    (when path
+      (drop-while (fn [e]
+                    (neg? (core/compare e key)))
+                  (forward-iterator path)))))
+
+;;TODO implement the op-buf handling in delete in the core.clj
+;;op-buf should be sorted first by key, then by ops/order: use a sorted-map w/ vector vals; this would simplify in-buffer operator merging
+;;
+;;TODO needs testing--nothing is generatively shown to be working
+;;
+;;Should have both b & op-buf-size parameterizable--annoying refactor


Extract start/stop duplication.

Extract start/stop duplication.

--- src/klangmeister/instruments.cljs
+++ src/klangmeister/instruments.cljs
@@ -24,13 +24,17 @@
 (def sin-osc (partial oscillator "sine"))
 (def saw (partial oscillator "sawtooth"))

+(defn from [osc start stop]
+  (doto osc
+    (.start start)
+    (.stop stop)))
+
 (defn bell! [midi start dur]
   (let [freq (music/equal-temperament midi)
         start (+ start (.-currentTime context))
         harmonic (fn [n proportion]
                    (doto (sin-osc (* n freq))
-                     (.start start)
-                     (.stop (+ start 1.5))
+                     (from start (+ start 1.5))
                      (connect (perc start 0.01 (* 0.05 proportion) proportion)
                               (.-destination context))))]
     (doseq [h [1.0 2.0 3.0 4.1 5.2]
@@ -42,6 +46,5 @@
         start (+ start (.-currentTime context))
         envelope (perc start 0.1 0.8 0.5)]
     (doto (saw freq)
-      (.start start)
-      (.stop (+ start 1.5))
+      (from start (+ start 1.5))
       (connect envelope (.-destination context)))))


Assert in separate function

Assert in separate function

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

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

 (defn count [strand dna-string]
-  (let [allowed-nucleotide #{\A \T \C \G \U}]
-    (when (not (allowed-nucleotide strand))
-       (throw (Exception. "invalid nucleotide"))))
-
+  (assert-allowed-strand strand)
   (let [dna (nucleotide-counts dna-string)]
     (get (nucleotide-counts dna-string) strand 0)))


fixed code to get joint angles, language and volume

--- src/main/clojure/naojure/core.clj
+++ src/main/clojure/naojure/core.clj
@@ -380,13 +380,17 @@
 (defn get-joint-angles
   "Return a map of the current joint angles for a robot"
   [robot]
-  (zipmap joint-names
-          (call-service robot :motion "getAngles"
-                      ["Body" true])))
+  (-> (call-service robot :motion "getAngles"
+                    ["Body" Boolean/TRUE])
+      (.get)
+      (zipmap joint-names)))
+
 (defn get-body-names
   "Return names of joints in the specified chain"
   [robot name]
-  (call-service robot :motion "getBodyNames"  [name]))
+  (->
+   (call-service robot :motion "getBodyNames"  [name])
+   (.get)))

 ;; broken - can't construct variant holding array of values
 (defn set-joint-angles
@@ -407,17 +411,23 @@
 (defn get-robot-position
   "Get the current position of the robot using the sensors if true"
   [robot use-sensors]
-  (call-service robot :motion "getRobotPosition"  [use-sensors]))
+  (->
+   (call-service robot :motion "getRobotPosition"  [use-sensors])
+   (.get)))

 (defn get-position
   "Get the current 6D position (x, y, z, wx, wy, wz) of named component, using the sensors if use-sensors is true"
   [robot name space use-sensors]
-  (call-service robot :motion "getPosition" [name space use-sensors]))
+  (->
+   (call-service robot :motion "getPosition" [name space use-sensors])
+   (.get)))

 (defn get-sensor-names
   "Get the names of the available sensors"
   [robot]
-  (call-service robot :motion "getSensorNames"))
+  (->
+   (call-service robot :motion "getSensorNames")
+   (.get)))

 ; text to speech
 (defn say
@@ -428,7 +438,9 @@
 (defn get-language
   "Get the currently defined text-to-speech language"
   [robot]
-  (call-service robot :tts "getLanguage"))
+  (->
+   (call-service robot :tts "getLanguage")
+   (.get)))

 (defn set-language
   "Set the language the robot should use"
@@ -438,7 +450,9 @@
 (defn get-volume
   "Get the current volume for the robot"
   [robot]
-  (call-service robot :tts "getVolume"))
+  (->
+   (call-service robot :tts "getVolume")
+   (.get)))

 (defn set-volume
   "Set the volume used by the robot"


Removes empty file

Removes empty file


Clarify that sequence of trip reports is lazy.

--- project/scrape-trs/src/scrape_trs/core.clj
+++ project/scrape-trs/src/scrape_trs/core.clj
@@ -25,7 +25,7 @@
   list-page: page (as a string) that lists trip reports

   Scrape all trip reports from the list-page, paging through pagination if
-  necessary, and return a sequence of scrape-trs.protocol/TripReport
+  necessary, and return a lazy sequence of scrape-trs.protocol/TripReport
   instances."
   [url list-page]
   (let [implementation (get-implementation url)


also :force-library-injection in development builds

currently sometimes required for missing polyfill detection since
closure changed the system to always include all polyfills and
just letting :advanced remove the unused ones.

fixes #870

--- src/main/shadow/build/closure.clj
+++ src/main/shadow/build/closure.clj
@@ -2521,6 +2521,7 @@
               ;; these are all used by the closure library itself
               #{"es6/array/findindex"
                 "es6/util/arrayfromiterator"
+                "es6/util/arrayfromiterable"
                 "es6/util/makeiterator"
                 "es6/string/trimstart"
                 "util/checkstringargs"
@@ -2538,7 +2539,8 @@
                 "es6/array/find"})
             goog-injected-libs
             shadow-js-injected-libs
-            classpath-js-injected-libs))]
+            classpath-js-injected-libs
+            (set (get-in state [:compiler-options :force-library-injection]))))]

     (if (or (not (seq all))
             (= all (:polyfill-libs state)))


properly invalidate closure conversion caches on config change

--- src/main/shadow/build/closure.clj
+++ src/main/shadow/build/closure.clj
@@ -1190,6 +1190,11 @@
              (SourceMap$LocationMapping. resource-name (.getAbsolutePath file)))
            (into [])))))

+(def cache-affecting-options
+  [[:compiler-options :source-map-use-fs-paths]
+   [:compiler-options :rewrite-polyfills]
+   [:js-options]])
+
 (defn convert-sources*
   "takes a list of :js sources and rewrites them to using closure
    partial compiles must supply the cached sources so closure doesn't complain about things
@@ -1459,8 +1464,14 @@
             (do (io/make-parents cache-index-file)
                 {}))

+        cache-options
+        (->> cache-affecting-options
+             (map #(get-in state %))
+             (into []))
+
         cache-files
-        (if (not= SHADOW-CACHE-KEY (:SHADOW-CACHE-KEY cache-index))
+        (if (or (not= SHADOW-CACHE-KEY (:SHADOW-CACHE-KEY cache-index))
+                (not= cache-options (:CACHE-OPTIONS cache-index)))
           ;; invalidate all cache when the timestamp of this file has changed
           []
           ;; compare each cache key
@@ -1519,6 +1530,7 @@
                                          :num-files (count recompile-sources)}]
             (-> cache-index
                 (assoc :SHADOW-CACHE-KEY SHADOW-CACHE-KEY
+                       :CACHE-OPTIONS cache-options
                        :polyfill-js (:polyfill-js state)
                        :injected-libs (::injected-libs state))
                 (util/reduce->
@@ -1767,8 +1779,14 @@
             (do (io/make-parents cache-index-file)
                 {}))

+        cache-options
+        (->> cache-affecting-options
+             (map #(get-in state %))
+             (into []))
+
         cache-files
-        (if (not= SHADOW-CACHE-KEY (:SHADOW-CACHE-KEY cache-index))
+        (if (or (not= SHADOW-CACHE-KEY (:SHADOW-CACHE-KEY cache-index))
+                (not= cache-options (:CACHE-OPTIONS cache-index)))
           ;; invalidate all cache when the timestamp of this file has changed
           []
           ;; compare each cache key
@@ -1812,7 +1830,9 @@
                   (cache/write-file cache-file output)

                   (assoc idx resource-id cache-key)))
-              (assoc cache-index :SHADOW-CACHE-KEY SHADOW-CACHE-KEY)
+              (assoc cache-index
+                :SHADOW-CACHE-KEY SHADOW-CACHE-KEY
+                :CACHE-OPTIONS cache-options)
               recompile-sources)))]

     (when need-compile?


CMR-735: Fixing find-collection-atom-links so if no collection concept ids are passed in it won't try to query elastic.

--- src/cmr/search/results_handlers/atom_links_results_handler.clj
+++ src/cmr/search/results_handlers/atom_links_results_handler.clj
@@ -28,9 +28,11 @@
 (defn find-collection-atom-links
   "Returns a mapping of collection-concept-ids and its atom links for the given collection-concept-ids"
   [context collection-concept-ids]
-  (let [collection-links-query (q/query {:concept-type :collection
-                                         :condition (q/string-conditions :concept-id collection-concept-ids true)
-                                         :page-size :unlimited
-                                         :result-format :atom-links})
-        result (qe/execute-query context collection-links-query)]
-    (into {} (:items result))))
+  (if (seq collection-concept-ids)
+    (let [collection-links-query (q/query {:concept-type :collection
+                                           :condition (q/string-conditions :concept-id collection-concept-ids true)
+                                           :page-size :unlimited
+                                           :result-format :atom-links})
+          result (qe/execute-query context collection-links-query)]
+      (into {} (:items result)))
+    {}))


prefer node-status and tidy up and fix a couple of accidental bugs that slipped in

--- src/overtone/sc/node.clj
+++ src/overtone/sc/node.clj
@@ -17,8 +17,6 @@
   [node err-msg]
   (let [full-err-msg (str "inactive node modification attempted for node "
                           (with-out-str (pr node))
-                          " with state "
-                          @(:status node)
                           (when-not (empty? err-msg)
                             (str " whilst " err-msg)))]
     (condp = *inactive-node-modification-error*
@@ -197,18 +195,19 @@
   "Returns true if n is a running synth node."
   [n]
   (and (node? n)
-       (= :live @(:status n))))
+       (= :live (node-status n))))

 (defn node-paused?
   "Returns true if n is a paused synth node."
   [n]
   (and (node? n)
-       (= :paused @(:status n))))
+       (= :paused (node-status n))))

 (defn node-loading?
   "Returns true if n is a loading synth node."
   [n]
-  (and (node? n) (= :loading @(:status n))))
+  (and (node? n)
+       (= :loading (node-status n))))

 (defn node-active?
   "Returns true if n is an active synth node."
@@ -216,8 +215,8 @@
   (or (node-live? n)
       (node-paused? n)))

-(defn- ensure-node-active!
-  ([node] (ensure-node-active! ""))
+(defn ensure-node-active!
+  ([node] (ensure-node-active! node ""))
   ([node err-msg]
      (when (node? node)
        (node-block-until-ready node))
@@ -390,7 +389,7 @@
   "Set control values for a node."
   [node name-values]
   (ensure-connected!)
-  (ensure-node-active! node "controlling node")
+  (ensure-node-active! node (str "controlling the following values: " name-values ))
   (apply snd "/n_set" (to-sc-id node) (floatify (stringify (idify name-values))))
   node)

@@ -511,7 +510,9 @@
    *block-node-until-ready?* to false."
   [node]
   (when *block-node-until-ready?*
-    (deref! (:loaded? node) 20 (str "blocking until the following node has completed loading: " (with-out-str (pr node))) )))
+    (deref! (:loaded? node) (str
+                             "blocking until the following node has completed loading: "
+                             (with-out-str (pr node))))))

 (extend java.lang.Long
   ISynthNode


Fix test.

Fix test.

--- test/cli4clj/test/cli_tests.clj
+++ test/cli4clj/test/cli_tests.clj
@@ -167,7 +167,7 @@
               (with-out-str
                 (cli/start-cli {:cmds {:a {:fn (fn [arg] (inc arg))}
                                    :b {:fn (fn [summand1 summand2] (+ summand1 summand2))}}})))]
-    (test/is (= (cli-tests/expected-string ["2" (str "5" cli/*line-sep*)]) out))))
+    (test/is (= (cli-tests/expected-string ["" "2" (str "5" cli/*line-sep*)]) out))))


Fix typo

Fix typo

--- src/zaffre/terminal.cljc
+++ src/zaffre/terminal.cljc
@@ -11,7 +11,7 @@
   (alter-group-pos! [this group-id pos-fn] "Change the [x y] position of a layer group. `x` and `y` are mesured in pixels from the upper left corner of the screen.")
   (alter-group-font! [this group-id font-fn] "Changes the font for a layer group. `font-fn` is a function that takes one argument: one of :linux :macosx or :windows, and returns a font.")
   (put-chars! [this layer-id characters] "Changes the characters in a layer. `characters` is a sequence where each element is a map and must have these keys: :c - a character or keyword, :x int, column, :y int row, :fg [r g b], :bg [r g b] where r,g,b are ints from 0-255.")
-  (replace-chars! [this layer-id characters] "Replaces the characters in a layer. `characters is an array of arrays where each element is a map and must have these keys: :c - character or keyword, :fg [r g b] :bg [r g b] where r,g,b are ints from 0-355.")
+  (replace-chars! [this layer-id characters] "Replaces the characters in a layer. `characters is an array of arrays where each element is a map and must have these keys: :c - character or keyword, :fg [r g b] :bg [r g b] where r,g,b are ints from 0-255.")
   (set-fg! [this layer-id x y fg] "Changes the foreground color of a character in a layer.")
   (set-bg! [this layer-id x y bg] "Changes the background color of a character in a layer.")
   (assoc-shader-param! [this k v] "Changes the value of a uniform variable in the post-processing shader.")


Dictionary type is shown on statistic and user statistic page

--- src/zg/html_renderer.clj
+++ src/zg/html_renderer.clj
@@ -252,26 +252,29 @@
                     [:tr [:th "User name"]
                          [:th "Changes made"]]
                     (for [stat statistic]
-                        [:tr [:td [:a {:href (str "user?name=" (:user stat))} (:user stat)]]
+                        [:tr [:td (user-href (:user stat) mode)]
                              [:td (:cnt stat)]]
                     )
-                ]
+                ] ; </table>
                 [:br]
                 [:table {:class "table table-stripped table-hover" :style "width:auto"}
                     [:tr [:th "Word"]
+                         [:th "Dictionary"]
                          [:th "Added at"]
                          [:th "Added by"]]
                     (for [change changes]
                         [:tr [:td (:word change)]
+                             [:td (if (= (:dictionary change) "w") "whitelist" "blacklist")]
                              [:td (:datetime change)]
-                             [:td [:a {:href (str "user?name=" (:user change))} (:user change)]]])
-                ]
+                             [:td (user-href (:user change) mode)]])
+                ] ; </table>
                 (render-html-footer)
             ] ; </div class="container">
         ] ; </body>
     ))

 (defn render-user-info
+    "Render page containing info about one selected user."
     [user-name changes url-prefix title mode]
     (page/xhtml
         (render-html-header nil url-prefix title)
@@ -283,11 +286,13 @@
                 [:br]
                 [:table {:class "table table-stripped table-hover" :style "width:auto"}
                     [:tr [:th "Word"]
+                         [:th "Dictionary"]
                          [:th "Added at"]]
                     (for [change changes]
                         [:tr [:td (:word change)]
+                             [:td (if (= (:dictionary change) "w") "whitelist" "blacklist")]
                              [:td (:datetime change)]])
-                ]
+                ] ; </table>
                 (render-html-footer)
             ] ; </div class="container">
         ] ; </body>


CMR-3967 Update test comments

CMR-3967 Update test comments

--- umm-spec-lib/test/cmr/umm_spec/test/validation/related_url.clj
+++ umm-spec-lib/test/cmr/umm_spec/test/validation/related_url.clj
@@ -347,14 +347,14 @@
        :errors ["[http://ingrid.ldgo.columbia.edu/SOURCES/.IGOSS/.fsu/|u|u+|u|v/dods] is not a valid URL"]}])))

 (deftest dif-valid-url-types
- (testing "Valid URL Types to convert to"
+ (testing "DIF hard-coded conversion table contains valid combinations"
   (doseq [url-type (vals dif-util/dif-url-content-type->umm-url-types)]
    (h/assert-valid (coll/map->UMM-C {:RelatedUrls [(merge
                                                     url-type
                                                     {:URL "https://www.foo.com"})]})))))

 (deftest echo10-valid-url-types
- (testing "Valid URL Types to convert to"
+ (testing "ECHO10 hard-coded conversion table contains valid combinations"
   (doseq [url-type (vals echo10-url/online-resource-type->related-url-types)]
    (h/assert-valid (coll/map->UMM-C {:RelatedUrls [(merge
                                                     url-type


CMR-2362: Fixed broken test.

CMR-2362: Fixed broken test.

--- metadata-db-app/test/cmr/metadata_db/test/services/concept_service.clj
+++ metadata-db-app/test/cmr/metadata_db/test/services/concept_service.clj
@@ -24,6 +24,7 @@
    :metadata "xml here"
    :format "echo10"
    :revision-id 1
+   :transaction-id 1
    :extra-fields {:entry-title "ET-1"
                   :entry-id "EID-1"}})

@@ -151,7 +152,7 @@
         ;; went through
         (is (= [expired-2]
                (for [concept (c/get-expired-concepts db {:provider-id "PROV1"} :collection)]
-                 (dissoc concept :revision-date :transaction-id))))
+                 (dissoc concept :revision-date))))

         ;; run it again, this time without the conflict...
         (cs/delete-expired-concepts {:system {:db db}} {:provider-id "PROV1"} :collection)


CMR-6537-4 updated json handler

CMR-6537-4 updated json handler

--- search-app/src/cmr/search/results_handlers/subscriptions_json_results_handler.clj
+++ search-app/src/cmr/search/results_handlers/subscriptions_json_results_handler.clj
@@ -38,3 +38,4 @@
 (defmethod qs/search-results->response [:subscription :json]
   [context query results]
   (json/generate-string (select-keys results [:hits :took :items])))
+


CMR-5369 Adds variable keyword search test for set-name and coll assocs

--- system-int-test/test/cmr/system_int_test/search/variable/variable_search_test.clj
+++ system-int-test/test/cmr/system_int_test/search/variable/variable_search_test.clj
@@ -71,10 +71,15 @@
              nil :variable {} {:url-extension "atom"}))))))

 (deftest search-for-variables-test
-  (let [variable1 (variables/ingest-variable-with-attrs {:native-id "VAR1"
+  (let [token (e/login (s/context) "user1")
+        variable1 (variables/ingest-variable-with-attrs {:native-id "VAR1"
                                                          :Alias "Alias1"
                                                          :Name "Variable1"
                                                          :LongName "Measurement1"
+                                                         :Sets [{:Name "TESTSETNAME"
+                                                                 :Type "Science"
+                                                                 :Size 2
+                                                                 :Index 2}]
                                                          :provider-id "PROV1"})
         variable2 (variables/ingest-variable-with-attrs {:native-id "var2"
                                                          :Alias "Alias2"
@@ -85,15 +90,32 @@
                                                          :Alias "Alias3"
                                                          :Name "a subsitute for variable2"
                                                          :LongName "variable1"
+                                                         :Sets [{:Name "TESTSETNAME"
+                                                                 :Type "Science"
+                                                                 :Size 2
+                                                                 :Index 2}]
                                                          :provider-id "PROV2"})
         variable4 (variables/ingest-variable-with-attrs {:native-id "special-variable"
                                                          :Alias "v.other"
                                                          :Name "v.other"
                                                          :LongName "m.other"
                                                          :provider-id "PROV2"})
+
+        [coll1 coll2 coll3] (doall (for [n (range 1 4)]
+                                     (d/ingest-umm-spec-collection
+                                      "PROV1"
+                                      (data-umm-c/collection n {})
+                                      {:token token})))
+
+        var1-assoc-colls [{:concept-id (:concept-id coll1)}]
+        var3-assoc-colls [{:concept-id (:concept-id coll3)}]
         prov1-variables [variable1 variable2]
         prov2-variables [variable3 variable4]
         all-variables (concat prov1-variables prov2-variables)]
+
+    (index/wait-until-indexed)
+    (au/associate-by-concept-ids token (:concept-id variable1) var1-assoc-colls)
+    (au/associate-by-concept-ids token (:concept-id variable3) var3-assoc-colls)
     (index/wait-until-indexed)

     (are3 [expected-variables query]
@@ -315,6 +337,22 @@
       "By keyword match both variable_name and measurement"
       [variable1 variable3]
       {:keyword "variable1"}
+
+      "By keyword match associated collection"
+      [variable1]
+      {:keyword (:concept-id coll1)}
+
+      "By keyword match associated collection, no match"
+      []
+      {:keyword (:concept-id coll2)}
+
+      "By keyword match set name"
+      [variable1 variable3]
+      {:keyword "TESTSETNAME"}
+
+      "By keyword match set name, no match"
+      []
+      {:keyword "WRONGSETNAME"}

       "By keyword match tokenized variable_name and measurement"
       [variable2 variable3]


Add to and rearrange sandbox values

Add to and rearrange sandbox values

--- src/nightmod/sandbox.clj
+++ src/nightmod/sandbox.clj
@@ -7,22 +7,25 @@

 (def tester
   [(jail-test/blacklist-objects
-     [clojure.lang.Compiler clojure.lang.Ref clojure.lang.Reflector
-      clojure.lang.Namespace clojure.lang.RT
-      java.io.ObjectInputStream])
+     [clojure.lang.Compiler clojure.lang.Namespace
+      clojure.lang.Ref clojure.lang.Reflector clojure.lang.RT
+      java.io.ObjectInputStream java.lang.Thread])
    (jail-test/blacklist-packages
      ["java.lang.reflect"
       "java.security"
       "java.util.concurrent"
       "java.awt"])
    (jail-test/blacklist-symbols
-    '#{alter-var-root eval catch
-       load-string load-reader addMethod ns-resolve resolve find-var
-       *read-eval* ns-publics ns-unmap set! ns-map ns-interns the-ns
-       push-thread-bindings pop-thread-bindings future-call agent send
-       send-off pmap pcalls pvals in-ns System/out System/in System/err
-       with-redefs-fn Class/forName
-       set-screen! setScreen app! postRunnable})
+    '#{alter-var-root resolve find-var with-redefs-fn
+       *read-eval* set! eval catch
+       addMethod forName
+       load load-file load-string load-reader
+       ns-resolve ns-publics ns-unmap ns-map ns-interns the-ns in-ns
+       push-thread-bindings pop-thread-bindings future future-call
+       agent send send-off
+       pmap pvalues pcalls
+       System/out System/in System/err
+       set-screen! setScreen app! app})
    (jail-test/blacklist-nses '[clojure.main])
    (jail-test/blanket "clojail")])


CL + CW | #117 | Change regex pattern for dashboard safen routes ignoring fragment part

--- src/objective8/utils.clj
+++ src/objective8/utils.clj
@@ -106,8 +106,8 @@
       ((regex-checker #"/objectives/\d+/writers") target)
       ((regex-checker #"/objectives/\d+/writers/invitation") target)
       ((regex-checker #"/objectives/\d+/writer-invitations/\d+") target)
-      ((regex-checker #"/objectives/\d+/dashboard/questions(?:\?(?:(?:(?:[a-zA-Z-]*=[a-zA-Z0-9-|%2F]*)&?)+)?)?(?:#[a-zA-Z-]*)?") target)
-      ((regex-checker #"/objectives/\d+/dashboard/comments(?:\?(?:(?:(?:[a-zA-Z-]*=[a-zA-Z0-9-|%2F]*)&?)+)?)?(?:#[a-zA-Z-]*)?") target)))
+      ((regex-checker #"/objectives/\d+/dashboard/questions(?:\?(?:(?:(?:[a-zA-Z-]*=[a-zA-Z0-9-|%2F]*)&?)+)?)?") target)
+      ((regex-checker #"/objectives/\d+/dashboard/comments(?:\?(?:(?:(?:[a-zA-Z-]*=[a-zA-Z0-9-|%2F]*)&?)+)?)?") target)))

 (defn safen-fragment [fragment]
   (or ((regex-checker #"comments") fragment)


Fix notification for new mentions, always include the author name if present.

--- src/oc/email/content.clj
+++ src/oc/email/content.clj
@@ -616,16 +616,26 @@
         comment? (:interaction-id notification)
         entry-publisher (:entry-publisher notification)
         user-id (:user-id notification)
-        author (:author notification)]
-    (if mention?
-      (if comment?
-        (str "You were mentioned in a comment")
-        (str "You were mentioned in a post"))
-      (if (= (:user-id entry-publisher) user-id)
-        (if (seq author)
-          (str (:name author) " commented on your post")
-          (str "There is a new comment on your post"))
-        (str (:name author) " replied to a thread")))))
+        author (:author notification)
+        entry-author? (= (:user-id entry-publisher) user-id)
+        author-name? (seq (:name author))]
+    (cond (and mention?
+               comment?)
+          (if author-name?
+            (str (:name author) " mentioned you in a comment")
+            "You were mentioned in a comment")
+          mention?
+          (if author-name?
+            (str (:name author) " mentioned you in a post")
+            "You were mentioned in a post")
+          entry-author?
+          (if (seq (:name author))
+            (str (:name author) " commented on your post")
+            "There is a new comment on your post")
+          :else
+          (if (seq (:name author))
+            (str (:name author) " replied to a thread")
+            "There is a new reply on a thread" ))))

 (defn notify-team-intro [msg]
   (let [notification (:notification msg)]


db-spec with connection pool

db-spec with connection pool

--- src/ruuvi/database/connection.clj
+++ src/ruuvi/database/connection.clj
@@ -22,5 +22,7 @@
     (HikariDataSource. config)
   ))

+(defn- make-db-spec [db-spec]
+  (assoc db-spec :pool {:datasource (make-hikari-pool db-spec)})
+  )

-


move specs

move specs

--- test/expound/alpha_test.cljc
+++ test/expound/alpha_test.cljc
@@ -22,6 +22,14 @@
 (use-fixtures :once
   test-utils/check-spec-assertions
   test-utils/instrument-all)
+
+;; Missing onyx specs
+(s/def :trigger/materialize any?)
+(s/def :trigger/pre-evictor any?)
+(s/def :trigger/post-evictor any?)
+(s/def :flow/short-circuit any?)
+(s/def :onyx.core/params?
+  (s/coll-of any? :kind vector?))

 (def any-printable-wo-nan (gen/such-that (complement test-utils/contains-nan?) gen/any-printable))

@@ -1484,14 +1492,6 @@
    (is (not= form
              (mutate form mutate-path)))))

-;; Missing onyx specs
-(s/def :trigger/materialize any?)
-(s/def :trigger/pre-evictor any?)
-(s/def :trigger/post-evictor any?)
-(s/def :flow/short-circuit any?)
-(s/def :onyx.core/params?
-  (s/coll-of any? :kind vector?))
-
 #?(:clj
    (deftest real-spec-tests-mutated-valid-value
      (checking


Adjust for formatted types in view

Adjust for formatted types in view

--- src/mars_ogler/views.clj
+++ src/mars_ogler/views.clj
@@ -17,7 +17,7 @@
      cam-name [:span.at " at "] [:span.marstime taken-marstime] " on Sol " sol]
     "Earth Date:  " [:span.takendate taken-utc] [:br]
     "Released " lag " later at " [:span.releasedate released] [:br]
-    w [:span.x " x "] h " pixels | Type " type " | ID: " id]])
+    w [:span.x " x "] h " " type " | ID: " id]])

 (defn pics
   [{:keys [cams page per-page sorting thumbs]


Metabot improvements :ghost: #2154

Metabot improvements :ghost: #2154

--- src/metabase/metabot.clj
+++ src/metabase/metabot.clj
@@ -253,5 +253,3 @@
   (log/info "Stopping MetaBot...  🤖")
   (reset! websocket-monitor-thread-id nil)
   (disconnect-websocket!))
-
-(start-metabot!)


addded {:deprecated "..."} to deprecated macros

--- src/midje/semi_sweet.clj
+++ src/midje/semi_sweet.clj
@@ -106,6 +106,7 @@
   "Defines a list of names as functions that have no implementation yet. They will
    throw Errors if ever called.
    DEPRECATED: Prefer `unfinished`."
+  {:deprecated "1.3-alpha2"}
   [& names] (unfinished* names))

@@ -141,6 +142,7 @@
   "Creates an fake map that a function will not be called.
    Example: (not-called f))
    DEPRECATED: Prefer `:times 0` annotation to `fake`, ex. (provided (f) => 4 :times 0))"
+  {:deprecated "1.3-alpha2"}
   [var-sym & overrides]
   (make-fake-map var-sym
                  `{:call-text-for-failures (str '~var-sym " was called.")


Put error label in a scroll pane

Put error label in a scroll pane

--- src/nightmod/screens.clj
+++ src/nightmod/screens.clj
@@ -7,6 +7,7 @@

 (declare nightmod main-screen blank-screen overlay-screen)

+(def ^:const border-space 5)
 (def ^:const templates ["arcade" "platformer"
                         "orthogonal-rpg" "isometric-rpg"
                         "barebones-2d" "barebones-3d"])
@@ -86,29 +87,34 @@
   (fn [screen entities]
     (update! screen :camera (orthographic) :renderer (stage))
     (let [ui-skin (skin "uiskin.json")]
-      [(-> [(text-button "Home" ui-skin :set-name "home")
+      [(-> (label "" ui-skin
+                  :set-wrap true
+                  :set-alignment (bit-or (align :left) (align :bottom)))
+           (scroll-pane (style :scroll-pane nil nil nil nil nil))
+           (assoc :id :error :x border-space :y border-space))
+       (-> [(text-button "Home" ui-skin :set-name "home")
             (text-button "Restart" ui-skin :set-name "restart")
             (text-button "Files" ui-skin :set-name "files")]
            (vertical :pack)
-           (assoc :id :menu :x 5))
-       (-> (label "" ui-skin :set-wrap true)
-           (assoc :id :error :x 5 :y 5))]))
+           (assoc :id :menu :x border-space))]))
   :on-render
   (fn [screen entities]
     (->> (for [e entities]
            (case (:id e)
-             :error (doto e
-                      (label! :set-text (or (some-> @u/error .toString) ""))
-                      (label! :pack))
+             :error (let [l (-> e (scroll-pane! :get-children) first)]
+                      (label! l :set-text (or (some-> @u/error .toString) ""))
+                      e)
              e))
          (render! screen)))
   :on-resize
-  (fn [screen entities]
-    (height! screen (:height screen))
+  (fn [{:keys [width height] :as screen} entities]
+    (height! screen height)
     (for [e entities]
       (case (:id e)
-        :menu (assoc e :y (- (:height screen) (vertical! e :get-height)))
-        :error (assoc e :width (:width screen))
+        :menu (assoc e :y (- height
+                             (vertical! e :get-height)
+                             border-space))
+        :error (assoc e :width width :height height)
         e)))
   :on-ui-changed
   (fn [screen entities]


[#1834] Remove print

[#1834] Remove print

--- backend/test/akvo/lumen/endpoints_test.clj
+++ backend/test/akvo/lumen/endpoints_test.clj
@@ -26,7 +26,6 @@
         (let [r (h (get* "/env" {"auth" "keycloak"}))]
           (is (= 200 (:status r)))
           (let [rb (body-kw r)
-                _ (clojure.pprint/pprint rb) ;; "Inspect" CI
                 ks [:authClientId :authProvider :authURL :flowApiUrl
                     :lumenDeploymentColor :lumenDeploymentEnvironment
                     :lumenDeploymentVersion :piwikSiteId :sentryDSN :tenant]


turn the filename base portion of a filename to a keyword

--- src/cljs/infinitelives/pixi/resources.cljs
+++ src/cljs/infinitelives/pixi/resources.cljs
@@ -76,6 +76,15 @@

 (defn get-texture [key scale]
   (scale (key @!textures)))
+
+
+(defn url-keyword [url]
+  (-> url
+      (.split "/")
+      last
+      (.split ".")
+      first
+      keyword))

 ;; setup a pixi texture keyed by the tail of its filename


Changed EL-gfp-model computation again to use EL-gfp-model-interpretation

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

--- src/conexp/contrib/dl/languages/EL_gfp.clj
+++ src/conexp/contrib/dl/languages/EL_gfp.clj
@@ -29,7 +29,7 @@
     (illegal-argument "No base semantics defined for " (print-str dl-expression) "."))
   ;; compute gfp-model and interpret target
   (let [[tbox, target] (expression-term dl-expression)]
-    (interpret (gfp-model tbox model) target)))
+    (EL-gfp-model-interpretation model [tbox target])))

 ;;; subsumption


[#2097] Add logs

[#2097] Add logs

--- backend/src/akvo/lumen/lib/visualisation/maps.clj
+++ backend/src/akvo/lumen/lib/visualisation/maps.clj
@@ -4,6 +4,7 @@
             [akvo.lumen.lib.visualisation.map-config :as map-config]
             [akvo.lumen.lib.visualisation.map-metadata :as map-metadata]
             [akvo.lumen.lib.transformation.engine :as engine]
+            [clojure.tools.logging :as log]
             [akvo.lumen.util :as util]
             [cheshire.core :as json]
             [clj-http.client :as client]
@@ -107,11 +108,13 @@

 (defn create-raster [tenant-conn windshaft-url raster-id]
   (let [{:keys [raster_table metadata]} (raster-by-id tenant-conn {:id raster-id})
-        headers (headers tenant-conn)
+        headers* (headers tenant-conn)
         url (format "%s/layergroup" windshaft-url)
         map-config (map-config/build-raster raster_table (:min metadata) (:max metadata))
+          _ (log/warn :map-config map-config)
+          _ (log/warn :headers headers)
         layer-group-id (-> (client/post url {:body (json/encode map-config)
-                                             :headers headers
+                                             :headers headers*
                                              :content-type :json})
                            :body json/decode (get "layergroupid"))
         layer-meta (map-metadata/build tenant-conn raster_table {:layerType "raster"} nil)]


Beef up some ugen machinery docstrings

Beef up some ugen machinery docstrings

--- src/overtone/sc/ugen.clj
+++ src/overtone/sc/ugen.clj
@@ -34,13 +34,21 @@
 (def INF Float/POSITIVE_INFINITY)

 (defn normalize-ugen-name
-  "Normalizes SuperCollider and overtone-style names to squeezed lower-case."
+  "Normalizes both SuperCollider and overtone-style names to squeezed lower-case.
+
+  This produces strings that may be used to represent unique ugen keys that can be
+  generated from both SC and Overtone names.
+
+  (normalize-ugen-name \"SinOsc\")  ;=> \"sinosc\"
+  (normalize-ugen-name \"sin-osc\") ;=> \"sinosc\""
   [n]
   (.replaceAll (.toLowerCase (str n)) "[-|_]" ""))

 (defn overtone-ugen-name
   "A basic camelCase to with-dash name converter tuned to convert SuperCollider
-  names to Overtone names. Most likely needs improvement."
+  names to Overtone names. Most likely needs improvement.
+
+  (overtone-ugen-name \"SinOsc\") ;=> \"sin-osc\""
   [n]
   (let [n (.replaceAll n "([a-z])([A-Z])" "$1-$2")
         n (.replaceAll n "([A-Z])([A-Z][a-z])" "$1-$2")
@@ -48,13 +56,17 @@
         n (.toLowerCase n)]
     n))

-(defn- derived? [spec]
+(defn- derived?
+  "Determines whether the supplied ugen spec is derived from another ugen spec.
+
+   This means that the ugen needs to inherit some properties from its parent.
+   (The ugen spec's parent is specified using the key :extends)"
+  [spec]
   (contains? spec :extends))

 (defn- derive-ugen-specs
-  "Merge the ugen spec maps to give children their parent's attributes.
-
-  Recursively reduces the specs to support arbitrary levels of derivation."
+  "Merge the specified ugen spec maps to give children their parent's attributes
+   by recursively reducing the specs to support arbitrary levels of derivation."
   ([specs] (derive-ugen-specs specs {} 0))
   ([children adults depth]
      ;; Make sure a bogus UGen doesn't spin us off into infinity... ;-)
@@ -352,7 +364,13 @@
       (doc/with-arg-defaults)
       (doc/with-full-doc)))

-(defn- specs-from-namespaces [namespaces]
+(defn- specs-from-namespaces
+  "Gathers all ugen spec metadata (stored in the vars spec and specs-collide)
+  from the specified namespaces into a single vector of maps.
+
+  Takes a seq of namespace endings (see UGEN-NAMESPACES) and returns a vector
+  of maps containing ugen metadata."
+  [namespaces]
   (reduce (fn [mem ns]
             (let [full-ns (symbol (str "overtone.sc.ugen." ns))
                   _ (require [full-ns :only '[specs specs-collide]])


Fix lint error

Fix lint error

--- backend/specs/akvo/lumen/specs/visualisation/maps/layer.clj
+++ backend/specs/akvo/lumen/specs/visualisation/maps/layer.clj
@@ -41,10 +41,10 @@

 (defn valid-hex? [s] (try
                        (Color/decode s)
-                       true
                        (catch Exception e false)))

 (s/def ::layer.point-color-mapping.s/color valid-hex?)
+
 (s/def ::point-color-mapping-item (s/keys :req-un [::layer.point-color-mapping.s/op
                                                    ::layer.point-color-mapping.s/value
                                                    ::layer.point-color-mapping.s/color]))


remove unneeded fn

remove unneeded fn

--- test/metabase/test_utils.clj
+++ test/metabase/test_utils.clj
@@ -23,18 +23,10 @@
 (defn test-setup
   {:expectations-options :before-run}
   []
-  (set-test-logging-level)
+  ;; Disable debug logging since it clutters up our output
+  (.setLevel (org.apache.log4j.Logger/getLogger "metabase") org.apache.log4j.Level/INFO)
   (setup-test-db)
   (start-jetty))
-
-
-;; ## Logging Setup
-
-(defn set-test-logging-level
-  "Disable debug logging since it clutters up our output."
-  []
-  (.setLevel (org.apache.log4j.Logger/getLogger "metabase") org.apache.log4j.Level/INFO))
-

 ;; ## DB Setup
 ;; WARNING: BY RUNNING ANY UNIT TESTS THAT REQUIRE THIS FILE OR BY RUNNING YOUR ENTIRE TEST SUITE YOU WILL EFFECTIVELY BE WIPING OUT YOUR DATABASE.


Cleanup test generator code

Cleanup test generator code

--- test/onyx/log/generators.clj
+++ test/onyx/log/generators.clj
@@ -41,43 +41,40 @@
   "Generates additional reactions that may be generated by the process.
   e.g. when the task lifecycle is ready, it signals via :signal-ready"
   [entry old new diff peer-id]
-  (cond (#{:kill-job :submit-job
-           :prepare-join-cluster :accept-join-cluster :leave-cluster} (:fn entry))
+  (cond (#{:kill-job :submit-job :prepare-join-cluster
+           :accept-join-cluster :leave-cluster} (:fn entry))
     (let [old-allocation (peer->allocated-job (:allocations old) peer-id)
           new-allocation (peer->allocated-job (:allocations new) peer-id)]
       (if (and new-allocation (not= old-allocation new-allocation))
         [peer-id [(create-log-entry :signal-ready {:id peer-id})]]))))
+
+(def base-peer-state
+  {:messenger messenger
+   :opts {:onyx.peer/try-join-once?
+          (:onyx.peer/try-join-once? (:opts messenger) true)}})

 (defn apply-entry [replica entries entry]
   (let [new-replica (extensions/apply-log-entry entry replica)
         diff (extensions/replica-diff entry replica new-replica)
         peers (active-peers new-replica entry)
         peer-reactions (keep (fn [peer-id]
-                               (if-let [reactions (extensions/reactions
-                                                    entry
-                                                    replica
-                                                    new-replica
-                                                    diff
-                                                    {:messenger messenger
-                                                     :id peer-id
-                                                     :opts {:onyx.peer/try-join-once?
-                                                            (:onyx.peer/try-join-once? (:opts messenger) true)}})]
-                                 (when (seq reactions)
-                                   [peer-id reactions])))
+                               (if-let [reactions (seq (extensions/reactions entry replica new-replica diff (assoc base-peer-state :id peer-id)))]
+                                 [peer-id reactions]))
                              peers)
-        side-effects (keep (partial generate-side-effects entry replica new-replica diff)
+        side-effects (keep (fn [peer-id]
+                             (generate-side-effects entry replica new-replica diff peer-id))
                            peers)
         new (concat peer-reactions side-effects)
         ; it does not matter that multiple reactions are processed
         ; together because they may be processed interleaved depending on
         ; the choice of peer queue being popped
         unapplied (reduce (fn [new-entries [peer-id reactions]]
-                            (-> new-entries
-                                (update-in [peer-id :queue]
-                                           (fn [queue]
-                                             (-> queue
-                                                 vec
-                                                 (into reactions))))))
+                            (update-in new-entries
+                                       [peer-id :queue]
+                                       (fn [queue]
+                                         (-> queue
+                                             vec
+                                             (into reactions)))))
                           entries
                           new)]
     (vector new-replica diff unapplied)))


Fix pulse test.

Fix pulse test.

--- test/onyx/log/pulse_test.clj
+++ test/onyx/log/pulse_test.clj
@@ -3,6 +3,7 @@
             [onyx.extensions :as extensions]
             [onyx.log.entry :refer [create-log-entry]]
             [onyx.messaging.dummy-messenger]
+            [onyx.monitoring.no-op-monitoring :refer [no-op-monitoring-agent]]
             [onyx.plugin.core-async :refer [take-segments!]]
             [onyx.test-helper :refer [load-config]]
             [onyx.api :as api]
@@ -60,7 +61,10 @@

 (def reactions (rep-reactions old-replica new-replica diff {:id d-id}))

-(extensions/fire-side-effects! read-entry old-replica new-replica diff {:log (:log env) :id a-id})
+(def state {:log (:log env) :id a-id
+            :monitoring (no-op-monitoring-agent)})
+
+(extensions/fire-side-effects! read-entry old-replica new-replica diff state)

 (def conn (zk/connect (:zookeeper/address (:env-config config))))


Popup with full timestamp when mouse over on fromNow timestamp

--- web-app/src/cljs/potato/core.cljs
+++ web-app/src/cljs/potato/core.cljs
@@ -615,7 +615,7 @@
             (om.dom/a {:href "#"} ""))))))

 (defn display-time [time]
-  (om.dom/time #js {:dateTime time} (.fromNow (js/moment time))))
+  (om.dom/time #js {:dateTime time :title (-> (js/moment time) (.format "LLLL"))} (.fromNow (js/moment time))))

 ;;; ISeqable for NodeList from https://groups.google.com/forum/#!topic/clojure/unHrE3amqNs
 (extend-type js/NodeList


Add more tests.

Add more tests.

--- test/promesa/core_tests.cljc
+++ test/promesa/core_tests.cljc
@@ -141,6 +141,63 @@
            p2 (p/then p1 inc)
            p3 (p/then p2 inc)]
        (t/is @p3 4))))
+
+(t/deftest chaining-using-map
+  #?(:cljs
+     (t/async done
+       (let [p1 (future-ok 200 2)
+             p2 (p/map inc p1)
+             p3 (p/map inc p2)]
+         (p/then p3 (fn [v]
+                      (t/is (= v 4))
+                      (done)))))
+     :clj
+     (let [p1 (future-ok 200 2)
+           p2 (p/map inc p1)
+           p3 (p/map inc p2)]
+       (t/is @p3 4))))
+
+(t/deftest chaining-using-mapcat
+  #?(:cljs
+     (t/async done
+       (let [p1 (future-ok 200 2)
+             inc #(p/resolved (inc %))
+             p2 (p/mapcat inc p1)
+             p3 (p/mapcat inc p2)]
+         (p/then p3 (fn [v]
+                      (t/is (= v 4))
+                      (done)))))
+     :clj
+     (let [p1 (future-ok 200 2)
+           inc #(p/resolved (inc %))
+           p2 (p/mapcat inc p1)
+           p3 (p/mapcat inc p2)]
+       (t/is @p3 4))))
+
+(t/deftest canclel-scheduled-task
+  #?(:cljs
+     (t/async done
+       (let [value (volatile! nil)
+             c1 (p/schedule 1000 #(vreset! value 1))
+             c2 (p/schedule 1000 #(vreset! value 2))]
+         (p/cancel! c1)
+         (p/schedule 1200
+                     (fn []
+                       (t/is (= @value 2))
+                       (t/is (realized? c2))
+                       (t/is (not (realized? c1)))
+                       (t/is (p/cancelled? c1))
+                       (done)))))
+     :clj
+     (let [value (volatile! nil)
+           c1 (p/schedule 1000 #(vreset! value 1))
+           c2 (p/schedule 1000 #(vreset! value 2))]
+       (p/cancel! c1)
+       @(p/schedule 1200 (constantly nil))
+       (t/is (realized? c2))
+       (t/is (not (realized? c1)))
+       (t/is (p/cancelled? c1))
+       (t/is (= @value 2)))))

 (t/deftest chaining-using-chain
   #?(:cljs


Fix definition of git-branch/remove-out-dir.

Using a partial leaves *out-dir* unbound. Immutability ftw.

--- src/incise/deploy/workflows/git_branch.clj
+++ src/incise/deploy/workflows/git_branch.clj
@@ -64,7 +64,8 @@
                                    "HEAD")]
     (commit-info *repo* commit)))

-(def remove-out-dir (partial remove-prefix-from-path *out-dir*))
+(defn remove-out-dir [afile]
+  (remove-prefix-from-path *out-dir* afile))

 (defn move-to-work-dir
   "Move the given file to the working tree directory."


Still throw exceptions on nil keys

Still throw exceptions on nil keys

--- src/main/clojure/clojure/data/json_new.clj
+++ src/main/clojure/clojure/data/json_new.clj
@@ -22,9 +22,11 @@

 (defn- default-write-key-fn
   [x]
-  (if (instance? clojure.lang.Named x)
-    (name x)
-    (str x)))
+  (cond (instance? clojure.lang.Named x)
+        (name x)
+        (nil? x)
+        (throw (Exception. "JSON object properties may not be nil"))
+        :else (str x)))

 (defn- default-value-fn [k v] v)


undo series typeahead because of bug, series does not get stored

--- src/cljs/conference_rating/add_conference_page/add_conference_page.cljs
+++ src/cljs/conference_rating/add_conference_page/add_conference_page.cljs
@@ -41,7 +41,7 @@

 (def conference-form-template
   [:div
-   (form-input "Series" [conference-series-component])
+   (form-input "Series" [:input {:field :text :id :series :class "form-control" :placeholder "Name of the conference series, e.g. EuroClojure for the EuroClojure 2015 conference"}])
    (form-input "Name" [:input {:field :text :id :name :class "form-control" :placeholder "Name of the conference"}])
    [:div {:class "row"}
     [:div {:class "col-md-6"} (form-input "From" [:div {:field :datepicker :id :from-date :date-format "yyyy/mm/dd" :inline false :auto-close? true}])]


fix merge conflict

fix merge conflict

--- src/replikativ/crdt.cljc
+++ src/replikativ/crdt.cljc
@@ -5,3 +5,5 @@
 (defrecord SimpleGSet [elements])

 (defrecord SimpleORMap [adds removals])
+
+(defrecord LWW [register])


Comment out specs

Comment out specs

--- src/spectrace/trace.cljc
+++ src/spectrace/trace.cljc
@@ -2,25 +2,29 @@
   (:require [clojure.spec.alpha :as s]
             [spectrace.specs :as specs]))

-(s/def ::spec any?)
-(s/def ::path (s/coll-of (s/or :keyword keyword? :int integer?)))
-(s/def ::val any?)
-(s/def ::in (s/coll-of (s/or :keyword keyword? :int integer?)))
-(s/def ::pred any?)
-(s/def ::spec-name keyword?)
-
-(s/def ::state
-  (s/keys :req-un [::spec ::path ::val ::in ::pred]
-          :opt-un [::spec-name]))
-
-(s/def ::fail (s/fspec :args (s/cat) :ret any?))
-(s/def ::succ (s/fspec :args (s/cat :state ::state :fail ::fail) :ret any?))
-
-(s/fdef step*
-  :args (s/cat :state ::state
-               :succ  ::succ
-               :fail  ::fail)
-  :ret ::state)
+#_(do
+
+  (s/def ::spec any?)
+  (s/def ::path (s/coll-of (s/or :keyword keyword? :int integer?)))
+  (s/def ::val any?)
+  (s/def ::in (s/coll-of (s/or :keyword keyword? :int integer?)))
+  (s/def ::pred any?)
+  (s/def ::spec-name keyword?)
+
+  (s/def ::state
+    (s/keys :req-un [::spec ::path ::val ::in ::pred]
+            :opt-un [::spec-name]))
+
+  (s/def ::fail (s/fspec :args (s/cat) :ret any?))
+  (s/def ::succ (s/fspec :args (s/cat :state ::state :fail ::fail) :ret any?))
+
+  (s/fdef step*
+          :args (s/cat :state ::state
+                       :succ  ::succ
+                       :fail  ::fail)
+          :ret ::state)
+
+)

 (defmulti step* (fn [state succ fail] (first (:spec state))))
 (defmethod step* :default [{:keys [spec]} _ _]


[#149] Allow to reclaim ressource when calling close-listener (@mpenet)

--- src/taoensso/carmine.clj
+++ src/taoensso/carmine.clj
@@ -323,7 +323,7 @@

 (declare close-listener)

-(defrecord Listener [connection handler state]
+(defrecord Listener [connection handler state future]
   java.io.Closeable
   (close [this] (close-listener this)))

@@ -349,20 +349,19 @@
          state-atom#   (atom ~initial-state)
          {:as conn# in# :in} (conns/make-new-connection
                               (assoc (conns/conn-spec ~conn-spec)
-                                :listener? true))]
-
-     (future-call ; Thread to long-poll for messages
-      (bound-fn []
-        (while true ; Closes when conn closes
-          (let [reply# (protocol/get-unparsed-reply in# {})]
-            (try
-              (@handler-atom# reply# @state-atom#)
-              (catch Throwable t#
-                (timbre/error t# "Listener handler exception")))))))
+                                     :listener? true))
+         future# (future-call ; Thread to long-poll for messages
+                  (bound-fn []
+                    (while true ; Closes when conn closes
+                      (let [reply# (protocol/get-unparsed-reply in# {})]
+                        (try
+                          (@handler-atom# reply# @state-atom#)
+                          (catch Throwable t#
+                            (timbre/error t# "Listener handler exception")))))))]

      (protocol/with-context conn# ~@body
        (protocol/execute-requests (not :get-replies) nil))
-     (Listener. conn# handler-atom# state-atom#)))
+     (Listener. conn# handler-atom# state-atom# future#)))

 (defmacro with-open-listener
   "Evaluates body within the context of given listener's preexisting persistent
@@ -371,7 +370,9 @@
   `(protocol/with-context (:connection ~listener) ~@body
      (protocol/execute-requests (not :get-replies) nil)))

-(defn close-listener [listener] (conns/close-conn (:connection listener)))
+(defn close-listener [listener]
+  (conns/close-conn (:connection listener))
+  (future-cancel (:future listener)))

 (defmacro with-new-pubsub-listener
   "A wrapper for `with-new-listener`.


Fix underscores in namespace

Fix underscores in namespace

--- test/clj/puppetlabs/trapperkeeper/services/webserver/jetty9_service_override_settings_test.clj
+++ test/clj/puppetlabs/trapperkeeper/services/webserver/jetty9_service_override_settings_test.clj
@@ -1,4 +1,4 @@
-(ns puppetlabs.trapperkeeper.services.webserver.jetty9_service_override_settings_test
+(ns puppetlabs.trapperkeeper.services.webserver.jetty9-service-override-settings-test
   (:require [clojure.test :refer :all]
             [puppetlabs.http.client.sync :as http-client]
             [puppetlabs.trapperkeeper.app :refer [get-service]]


Fixes some code in a comment.

Fixes some code in a comment.

--- system-int-test/test/cmr/system_int_test/virtual_product_test.clj
+++ system-int-test/test/cmr/system_int_test/virtual_product_test.clj
@@ -30,7 +30,7 @@
 (comment
   (do
     (dev-sys-util/reset)
-    (doseq [p virtual-product-providers]
+    (doseq [p vp/virtual-product-providers]
       (ingest/create-provider (str p "_guid") p)))

   (dissoc (first isc) :revision-id :native-id :concept-id :entry-id)


Tests for settings.handlers.delete-user.

--- test/lunchlotto/settings/handlers_test.clj
+++ test/lunchlotto/settings/handlers_test.clj
@@ -4,9 +4,17 @@
   (:require [lunchlotto.settings.handlers :as handlers]
             [lunchlotto.settings.models :as models]))

-(deftest settings-page
+(deftest show-settings
   (testing "successfully render settings page"
     (with-redefs [models/find-user-by-id (fn [_ _])]
       (let [{:keys [:status :body]} (handlers/show-settings {})]
         (is (= 200 status))
         (is (.contains body "Settings"))))))
+
+(deftest delete-user
+  (testing "successfully delete account"
+    (with-redefs [models/delete-user (fn [_ _])]
+      (let [{:keys [:status :headers :flash]} (handlers/delete-user {})]
+        (is (= 302 status))
+        (is (= {"Location" "/"} headers))
+        (is (= "Your account has been deleted." flash))))))


Add note about possibility of testing for boxed values.

--- test/com/nomistech/clojure_the_language/clojure_numerics_test.clj
+++ test/com/nomistech/clojure_the_language/clojure_numerics_test.clj
@@ -30,6 +30,10 @@

 (fact "We can produce unboxed values"
   ;; **** Is there a way to make a test of this?
+
+  ;; Glenjamin> nomiskatz: you could probably write a java class method with
+  ;; overloading to test the primitives?
+
   (byte 2)
   (short 2)
   (int 2)


Whitespace.

Whitespace.

--- test/com/nomistech/clojure_the_language/clojure_numerics_test.clj
+++ test/com/nomistech/clojure_the_language/clojure_numerics_test.clj
@@ -286,23 +286,29 @@
 (def max-long-plus-1 9223372036854775808N)

 (fact "About the 'ordinary' arithmetic operators"
+  ;;
   (fact "Throw exceptions on overflow"
     (inc Long/MAX_VALUE)
     => (throws ArithmeticException "integer overflow"))
+  ;;
   (fact "We can avoid overflow exceptions by coercing to BigInt first"
     (inc (bigint Long/MAX_VALUE))
     => max-long-plus-1)
+  ;;
   (fact "Do not demote from BigInt"
     (type (- max-long-plus-1 Long/MAX_VALUE))
     => clojure.lang.BigInt))

 (fact "About the xxxx' operators"
+  ;;
   (fact "Auto-promote"
     (inc' Long/MAX_VALUE)
     => max-long-plus-1)
+  ;;
   (fact "Do not promote if unnecessary"
     (type (inc' 1))
     => Long)
+  ;;
   (fact "Do not demote"
     (type (dec' (inc' Long/MAX_VALUE)))
     => clojure.lang.BigInt))
@@ -310,9 +316,11 @@
 (def boxed-max-long Long/MAX_VALUE)

 (fact "About the unchecked-xxxx operators"
+  ;;
   (fact "Don't check for overflow"
     (unchecked-inc Long/MAX_VALUE)
     => Long/MIN_VALUE)
+  ;;
   (fact "Only do what you expect on longs, not Longs"
     ;; The doc strings for unchecked operations only define what happens
     ;; for (unboxed) longs, not for (boxed) Longs.


(SERVER-1103) Move try/catch wrapper in test-error-during-init test

This commit moves the try/catch wrapper looking for an exception to be
thrown in the `test-error-during-init` test to be wrapped around the
whole `with-app-with-config` call rather than just the inner `run-app`
call.  The exception could otherwise be thrown before the `run-app` call
is reached if the `create-pool-instance!` call in the test were to occur
quickly enough during initialization.

--- test/unit/puppetlabs/services/jruby/jruby_puppet_service_test.clj
+++ test/unit/puppetlabs/services/jruby/jruby_puppet_service_test.clj
@@ -47,16 +47,16 @@
                    (fn [& _] (throw (Exception. "42")))]
        (let [got-expected-exception (atom false)]
          (logging/with-test-logging
-          (bootstrap/with-app-with-config
-           app
-           default-services
-           (jruby-service-test-config 1)
-           (try
-             (tk/run-app app)
-             (catch Exception e
-               (let [cause (stacktrace/root-cause e)]
-                 (is (= (.getMessage cause) "42"))
-                 (reset! got-expected-exception true))))))
+          (try
+            (bootstrap/with-app-with-config
+             app
+             default-services
+             (jruby-service-test-config 1)
+             (tk/run-app app))
+            (catch Exception e
+              (let [cause (stacktrace/root-cause e)]
+                (is (= (.getMessage cause) "42"))
+                (reset! got-expected-exception true)))))
          (is (true? @got-expected-exception)
              "Did not get expected exception."))))))