Changing the virtual product test to only run with the real database.

--- system-int-test/test/cmr/system_int_test/bootstrap/virtual_products_test.clj
+++ system-int-test/test/cmr/system_int_test/bootstrap/virtual_products_test.clj
@@ -9,6 +9,7 @@
             [cmr.system-int-test.utils.ingest-util :as ingest]
             [cmr.system-int-test.utils.search-util :as search]
             [cmr.system-int-test.utils.virtual-product-util :as vp]
+            [cmr.system-int-test.system :as s]
             [cmr.umm.granule :as umm-g]
             [cmr.virtual-product.config :as vp-config]))

@@ -37,12 +38,12 @@
   ;; turn off virtual products using eval-in-dev-sys so that it works
   ;; with integration tests when the CMR is running in another process
   (eval-in-dev-sys
-   '(cmr.virtual-product.config/set-virtual-products-enabled! false))
+    '(cmr.virtual-product.config/set-virtual-products-enabled! false))
   ;; run the test itself
   (f)
   ;; turn on virtual products again
   (eval-in-dev-sys
-   '(cmr.virtual-product.config/set-virtual-products-enabled! true)))
+    '(cmr.virtual-product.config/set-virtual-products-enabled! true)))

 (use-fixtures :each virtual-products-fixture)

@@ -60,85 +61,87 @@
 ;; process before checking for virtual products.

 (deftest virtual-product-bootstrap
-  (let [source-collections (vp/ingest-source-collections)
-        ;; Ingest the virtual collections. For each virtual collection associate it with the source
-        ;; collection to use later.
-        vp-colls (reduce (fn [new-colls source-coll]
-                           (into new-colls (map #(assoc % :source-collection source-coll)
-                                                (vp/ingest-virtual-collections [source-coll]))))
-                         []
-                         source-collections)
-        source-granules (doall (for [source-coll source-collections
-                                     :let [{:keys [provider-id entry-title]} source-coll]
-                                     granule-ur (vp-config/sample-source-granule-urs
-                                                 [provider-id entry-title])]
-                                 (vp/ingest-source-granule provider-id
-                                                           (dg/granule source-coll {:granule-ur granule-ur}))))
-        all-expected-granule-urs (concat (mapcat vp/source-granule->virtual-granule-urs source-granules)
-                                         (map :granule-ur source-granules))]
-    (index/wait-until-indexed)
-
-    (testing "Only source granules exist (virtual products system is disabled)"
-      (assert-matching-granule-urs
-       (map :granule-ur source-granules)
-       (search/find-refs :granule {:page-size 50})))
-
-    (bootstrap-and-index)
-
-    (testing "Find all granules"
-      (assert-matching-granule-urs
-       all-expected-granule-urs
-       (search/find-refs :granule {:page-size 50})))
-
-    (testing "Find all granules in virtual collections"
-      (doseq [vp-coll vp-colls
-              :let [{:keys [provider-id source-collection]} vp-coll
-                    source-short-name (get-in source-collection [:product :short-name])
-                    vp-short-name (get-in vp-coll [:product :short-name])]]
+  (s/only-with-real-database
+    (let [source-collections (vp/ingest-source-collections)
+          ;; Ingest the virtual collections. For each virtual collection associate it with the source
+          ;; collection to use later.
+          vp-colls (reduce (fn [new-colls source-coll]
+                             (into new-colls (map #(assoc % :source-collection source-coll)
+                                                  (vp/ingest-virtual-collections [source-coll]))))
+                           []
+                           source-collections)
+          source-granules (doall (for [source-coll source-collections
+                                       :let [{:keys [provider-id entry-title]} source-coll]
+                                       granule-ur (vp-config/sample-source-granule-urs
+                                                    [provider-id entry-title])]
+                                   (vp/ingest-source-granule provider-id
+                                                             (dg/granule source-coll {:granule-ur granule-ur}))))
+          all-expected-granule-urs (concat (mapcat vp/source-granule->virtual-granule-urs source-granules)
+                                           (map :granule-ur source-granules))]
+      (index/wait-until-indexed)
+
+      (testing "Only source granules exist (virtual products system is disabled)"
         (assert-matching-granule-urs
-         (map #(vp-config/generate-granule-ur provider-id source-short-name vp-short-name %)
-              (vp-config/sample-source-granule-urs
-               [provider-id (:entry-title source-collection)]))
-         (search/find-refs :granule {:entry-title (:entry-title vp-coll)
-                                     :page-size 50}))))))
+          (map :granule-ur source-granules)
+          (search/find-refs :granule {:page-size 50})))
+
+      (bootstrap-and-index)
+
+      (testing "Find all granules"
+        (assert-matching-granule-urs
+          all-expected-granule-urs
+          (search/find-refs :granule {:page-size 50})))
+
+      (testing "Find all granules in virtual collections"
+        (doseq [vp-coll vp-colls
+                :let [{:keys [provider-id source-collection]} vp-coll
+                      source-short-name (get-in source-collection [:product :short-name])
+                      vp-short-name (get-in vp-coll [:product :short-name])]]
+          (assert-matching-granule-urs
+            (map #(vp-config/generate-granule-ur provider-id source-short-name vp-short-name %)
+                 (vp-config/sample-source-granule-urs
+                   [provider-id (:entry-title source-collection)]))
+            (search/find-refs :granule {:entry-title (:entry-title vp-coll)
+                                        :page-size 50})))))))

 ;; Verify that latest revision ids of virtual granules and the corresponding source granules
 ;; are in sync as various ingest operations are performed on the source granules
 (deftest deleted-virtual-granules
-  (let [[ast-coll] (vp/ingest-source-collections
-                    [(assoc
-                      (dc/collection
-                       {:entry-title "ASTER L1A Reconstructed Unprocessed Instrument Data V003"
-                        :short-name "AST_L1A"})
-                      :provider-id "LPDAAC_ECS")])
-        vp-colls   (vp/ingest-virtual-collections [ast-coll])
-        s-granules (doall
-                    (for [n (range 10)]
-                      (vp/ingest-source-granule
-                       "LPDAAC_ECS"
-                       (dg/granule ast-coll {:granule-ur (format "SC:AST_L1A.003:%d" n)
-                                             :revision-id 5}))))
-        _          (bootstrap-and-index)
-        v-granules (mapcat #(:refs
-                             (search/find-refs :granule
-                                               {:entry-title (:entry-title %)
-                                                :page-size 50}))
-                           vp-colls)
-        verify     (fn []
-                     (doseq [gran v-granules]
-                       (is (:deleted (ingest/get-concept (:id gran) 12)))))]
-
-    (is (not (empty? v-granules)))
-
-    (testing "after deleting source granules"
-      (doseq [granule s-granules]
-        (ingest/delete-concept (d/item->concept granule) {:revision-id 12}))
-      (bootstrap-and-index)
-      (verify))
-
-    (testing "bootstrapping should be idempotent"
-      (bootstrap-and-index)
-      (verify))))
+  (s/only-with-real-database
+    (let [[ast-coll] (vp/ingest-source-collections
+                       [(assoc
+                          (dc/collection
+                            {:entry-title "ASTER L1A Reconstructed Unprocessed Instrument Data V003"
+                             :short-name "AST_L1A"})
+                          :provider-id "LPDAAC_ECS")])
+          vp-colls   (vp/ingest-virtual-collections [ast-coll])
+          s-granules (doall
+                       (for [n (range 10)]
+                         (vp/ingest-source-granule
+                           "LPDAAC_ECS"
+                           (dg/granule ast-coll {:granule-ur (format "SC:AST_L1A.003:%d" n)
+                                                 :revision-id 5}))))
+          _          (bootstrap-and-index)
+          v-granules (mapcat #(:refs
+                                (search/find-refs :granule
+                                                  {:entry-title (:entry-title %)
+                                                   :page-size 50}))
+                             vp-colls)
+          verify     (fn []
+                       (doseq [gran v-granules]
+                         (is (:deleted (ingest/get-concept (:id gran) 12)))))]
+
+      (is (not (empty? v-granules)))
+
+      (testing "after deleting source granules"
+        (doseq [granule s-granules]
+          (ingest/delete-concept (d/item->concept granule) {:revision-id 12}))
+        (bootstrap-and-index)
+        (verify))
+
+      (testing "bootstrapping should be idempotent"
+        (bootstrap-and-index)
+        (verify)))))

 ;; The following test is copied directly from the other virtual
 ;; product test.
@@ -146,64 +149,65 @@
 ;; TODO: Refactor this somehow.

 (deftest ast-granule-umm-matchers-test
-  (let [[ast-coll] (vp/ingest-source-collections
-                    [(assoc
-                      (dc/collection
-                       {:entry-title "ASTER L1A Reconstructed Unprocessed Instrument Data V003"
-                        :short-name "AST_L1A"})
-                      :provider-id "LPDAAC_ECS")])
-        vp-colls (vp/ingest-virtual-collections [ast-coll])
-        psa1 (dg/psa "TIR_ObservationMode" ["ON"])
-        psa2 (dg/psa "SWIR_ObservationMode" ["ON"])
-        psa3 (dg/psa "VNIR1_ObservationMode" ["ON"])
-        psa4 (dg/psa "VNIR2_ObservationMode" ["ON"])]
-    (are [granule-attrs expected-granule-urs]
-        (let [_ (d/ingest "LPDAAC_ECS" (dg/granule ast-coll granule-attrs))
-              _ (bootstrap-and-index)
-              src-granule-ur (:granule-ur granule-attrs)
-              query-param {"attribute[]" (format "string,%s,%s"
-                                                 vp-config/source-granule-ur-additional-attr-name
-                                                 src-granule-ur)
-                           :page-size 20}
-              refs (search/find-refs :granule query-param)]
-          (assert-matching-granule-urs expected-granule-urs refs))
-
-      {:granule-ur "SC:AST_L1A.003:2006227720"
-       :product-specific-attributes [psa4]}
-      []
-
-      {:granule-ur "SC:AST_L1A.003:2006227721"
-       :product-specific-attributes [psa1]}
-      ["SC:AST_05.003:2006227721" "SC:AST_08.003:2006227721" "SC:AST_09T.003:2006227721"]
-
-      {:granule-ur "SC:AST_L1A.003:2006227722"
-       :product-specific-attributes [psa1 psa2 psa3 psa4]}
-      ["SC:AST_05.003:2006227722" "SC:AST_08.003:2006227722" "SC:AST_09T.003:2006227722"]
-
-      {:granule-ur "SC:AST_L1A.003:2006227724"
-       :product-specific-attributes [psa3 psa4]
-       :data-granule (umm-g/map->DataGranule
-                      {:day-night "DAY"
-                       :production-date-time "2014-09-26T11:11:00Z"})}
-      ["SC:AST14DEM.003:2006227724" "SC:AST14OTH.003:2006227724" "SC:AST14DMO.003:2006227724"]
-
-      {:granule-ur "SC:AST_L1A.003:2006227725"
-       :product-specific-attributes [psa2 psa3 psa4]
-       :data-granule (umm-g/map->DataGranule
-                      {:day-night "DAY"
-                       :production-date-time "2014-09-26T11:11:00Z"})}
-      ["SC:AST14DMO.003:2006227725" "SC:AST_09.003:2006227725"
-       "SC:AST_09XT.003:2006227725" "SC:AST14DEM.003:2006227725"
-       "SC:AST_07.003:2006227725"   "SC:AST14OTH.003:2006227725"
-       "SC:AST_07XT.003:2006227725"]
-
-      {:granule-ur "SC:AST_L1A.003:2006227726"
-       :product-specific-attributes [psa1 psa2 psa3 psa4]
-       :data-granule (umm-g/map->DataGranule
-                      {:day-night "DAY"
-                       :production-date-time "2014-09-26T11:11:00Z"})}
-      ["SC:AST_09XT.003:2006227726" "SC:AST14DEM.003:2006227726"
-       "SC:AST_08.003:2006227726"   "SC:AST_05.003:2006227726"
-       "SC:AST14OTH.003:2006227726" "SC:AST_07.003:2006227726"
-       "SC:AST_09.003:2006227726"   "SC:AST_09T.003:2006227726"
-       "SC:AST_07XT.003:2006227726" "SC:AST14DMO.003:2006227726"])))
+  (s/only-with-real-database
+    (let [[ast-coll] (vp/ingest-source-collections
+                       [(assoc
+                          (dc/collection
+                            {:entry-title "ASTER L1A Reconstructed Unprocessed Instrument Data V003"
+                             :short-name "AST_L1A"})
+                          :provider-id "LPDAAC_ECS")])
+          vp-colls (vp/ingest-virtual-collections [ast-coll])
+          psa1 (dg/psa "TIR_ObservationMode" ["ON"])
+          psa2 (dg/psa "SWIR_ObservationMode" ["ON"])
+          psa3 (dg/psa "VNIR1_ObservationMode" ["ON"])
+          psa4 (dg/psa "VNIR2_ObservationMode" ["ON"])]
+      (are [granule-attrs expected-granule-urs]
+           (let [_ (d/ingest "LPDAAC_ECS" (dg/granule ast-coll granule-attrs))
+                 _ (bootstrap-and-index)
+                 src-granule-ur (:granule-ur granule-attrs)
+                 query-param {"attribute[]" (format "string,%s,%s"
+                                                    vp-config/source-granule-ur-additional-attr-name
+                                                    src-granule-ur)
+                              :page-size 20}
+                 refs (search/find-refs :granule query-param)]
+             (assert-matching-granule-urs expected-granule-urs refs))
+
+           {:granule-ur "SC:AST_L1A.003:2006227720"
+            :product-specific-attributes [psa4]}
+           []
+
+           {:granule-ur "SC:AST_L1A.003:2006227721"
+            :product-specific-attributes [psa1]}
+           ["SC:AST_05.003:2006227721" "SC:AST_08.003:2006227721" "SC:AST_09T.003:2006227721"]
+
+           {:granule-ur "SC:AST_L1A.003:2006227722"
+            :product-specific-attributes [psa1 psa2 psa3 psa4]}
+           ["SC:AST_05.003:2006227722" "SC:AST_08.003:2006227722" "SC:AST_09T.003:2006227722"]
+
+           {:granule-ur "SC:AST_L1A.003:2006227724"
+            :product-specific-attributes [psa3 psa4]
+            :data-granule (umm-g/map->DataGranule
+                            {:day-night "DAY"
+                             :production-date-time "2014-09-26T11:11:00Z"})}
+           ["SC:AST14DEM.003:2006227724" "SC:AST14OTH.003:2006227724" "SC:AST14DMO.003:2006227724"]
+
+           {:granule-ur "SC:AST_L1A.003:2006227725"
+            :product-specific-attributes [psa2 psa3 psa4]
+            :data-granule (umm-g/map->DataGranule
+                            {:day-night "DAY"
+                             :production-date-time "2014-09-26T11:11:00Z"})}
+           ["SC:AST14DMO.003:2006227725" "SC:AST_09.003:2006227725"
+            "SC:AST_09XT.003:2006227725" "SC:AST14DEM.003:2006227725"
+            "SC:AST_07.003:2006227725"   "SC:AST14OTH.003:2006227725"
+            "SC:AST_07XT.003:2006227725"]
+
+           {:granule-ur "SC:AST_L1A.003:2006227726"
+            :product-specific-attributes [psa1 psa2 psa3 psa4]
+            :data-granule (umm-g/map->DataGranule
+                            {:day-night "DAY"
+                             :production-date-time "2014-09-26T11:11:00Z"})}
+           ["SC:AST_09XT.003:2006227726" "SC:AST14DEM.003:2006227726"
+            "SC:AST_08.003:2006227726"   "SC:AST_05.003:2006227726"
+            "SC:AST14OTH.003:2006227726" "SC:AST_07.003:2006227726"
+            "SC:AST_09.003:2006227726"   "SC:AST_09T.003:2006227726"
+            "SC:AST_07XT.003:2006227726" "SC:AST14DMO.003:2006227726"]))))


Clean up video example

Clean up video example

--- src/overtone/examples/getting_started/video.clj
+++ src/overtone/examples/getting_started/video.clj
@@ -1,32 +1,31 @@
-(ns overtone.examples.getting-started.video
-  "Examples used in the video 'Quick Intro to Live Programming in Overtone'"
+(ns overtone.examples.getting-started.video
+  "Examples used in the video 'Quick Intro to Live Programming in Overtone'
+   http://vimeo.com/22798433"
     (:use [overtone.live]
           [overtone.inst.sampled-piano]))

-; use the sampled piano
-; note: The piano samples take a long time to download, but
-; it will only happen once.
+;; use the sampled piano
+;; note: The piano samples take a long time to download, but
+;; it will only happen once.
 (def piano sampled-piano)

-; play some notes on our piano
+; play some notes on our piano
 (piano)
 (piano 72)

-; this is one possible implementation of play-chord,
-; it was not shown in the video
-
-(defn play-chord [a-chord]
+;; this is one possible implementation of play-chord,
+;; it was not shown in the video
+(defn play-chord [a-chord]
   (doseq [note a-chord] (piano note)))

-; play a chord progression on our piano
+;; play a chord progression on our piano
 (let [time (now)]
   (at time (play-chord (chord :D3 :major7)))
   (at (+ 2000 time) (play-chord (chord :A3 :major)))
   (at (+ 3000 time) (play-chord (chord :D3 :major7)))
   (at (+ 4300 time) (play-chord (chord :F3 :major7))))

-; here's a different function that encapsulates the above
-;
+;; here's a different function that encapsulates the above
 (defn play-progression [chords]
   (if (empty? chords) nil
     (doseq []
@@ -34,46 +33,44 @@
       (Thread/sleep 2000)
       (play-progression (rest chords)))))

-; define a simple instrument. in the video, sam uses :action :free,
-; but that causes a ugen error on my system
-
+;; define a simple instrument. in the video, sam uses :action :free,
+;; but this is now :action FREE
 (definst beep [note 60]
   (let [sound-src (sin-osc (midicps note))
-        env (env-gen (perc 0.01 1.0) :action 0)] ; sam uses :free
+        env       (env-gen (perc 0.01 1.0) :action FREE)] ; sam uses :free
     (* sound-src env)))

-; admire our beep
+;; admire our beep :-)
 (beep)

-; beep across a wide range of sounds
+;; beep across a wide range of sounds
 (for [i (range 110)] (at (+ (now) (* i 20)) (beep i)))

-; model a plucked string. this is really cool!
+;; model a plucked string. this is really cool!
 (definst plucked-string [note 60 amp 0.8 dur 2 decay 30 coef 0.3 gate 1]
-  (let [freq (midicps note)
-        noize (* 0.8 (white-noise))
-        dly   (/ 1.0 freq)
-        plk   (pluck noize gate dly dly decay coef)
-        dist  (distort plk)
-        filt  (rlpf dist (* 12 freq) 0.6)
-        clp   (clip2 filt 0.8)
+  (let [freq   (midicps note)
+        noize  (* 0.8 (white-noise))
+        dly    (/ 1.0 freq)
+        plk    (pluck noize gate dly dly decay coef)
+        dist   (distort plk)
+        filt   (rlpf dist (* 12 freq) 0.6)
+        clp    (clip2 filt 0.8)
         reverb (free-verb clp 0.4 0.8 0.2)]
     (* amp (env-gen (perc 0.0001 dur)) reverb)))

-; note: the underscores are rests
+;; note: the underscores are rests
 (def reich-degrees [:vi :vii :i+ :_ :vii :_ :i+ :vii :vi :_ :vii :_])
 (def pitches (degrees->pitches reich-degrees :diatonic :C4))

-; temporal recursion: create a function that takes:
-; 1) time to play a note
-; 2) list of notes to play
-; 3) seperation of notes
-;
-; Armed with these parameters, we check if the note is a rest,
-; if it isn't, schedule it to be played. then, we schedule
-; a recursive call to be made to our function again at the new time,
-; calculated by adding the current time plus the separation.
-
+;; temporal recursion: create a function that takes:
+;; 1) time to play a note
+;; 2) list of notes to play
+;; 3) seperation of notes
+;;
+;; Armed with these parameters, we check if the note is a rest,
+;; if it isn't, schedule it to be played. then, we schedule
+;; a recursive call to be made to our function again at the new time,
+;; calculated by adding the current time plus the separation.
 (defn play
   [time notes sep]
   (let [note (first notes)]
@@ -82,11 +79,11 @@
     (let [next-time (+ time sep)]
       (apply-at next-time play [next-time (rest notes) sep]))))

-; play some pitches
+;; play some pitches
 (play (now) pitches 200)

-; cycle through some pitches
-; this will loop indefinitely.
+;; cycle through some pitches
+;; this will loop indefinitely.
 (let [t (+ 500 (now))]
   (play t (cycle pitches) 100)
   (play t (cycle pitches) 102))


CMR-2454 throw service error for SOAP faults

--- transmit-lib/src/cmr/transmit/echo/soap/core.clj
+++ transmit-lib/src/cmr/transmit/echo/soap/core.clj
@@ -53,8 +53,10 @@
           (200, 201) [status response]
           401 (cmr.common.services.errors/throw-service-error :unauthorized response)
           404 (cmr.common.services.errors/throw-service-error :not-found response)
+          ;; soap-services returns all SOAP errors as 500.  Check if it is a SOAP error and if so,
+          ;; extract the fault string from the XML.  If not, add the entire response to the exception
           500 (if-let [fault-msg (xp/value-of response "/Envelope/Body/Fault/faultstring")]
-                (cmr.common.services.errors/internal-error! fault-msg)
+                (cmr.common.services.errors/throw-service-error :soap-fault fault-msg)
                 (cmr.common.services.errors/internal-error! response))
           503 (cmr.common.services.errors/throw-service-error :unavailable response)
           (cmr.common.services.errors/internal-error! response))))


mark which CSS files loaded successfully

--- support/src/figwheel/client/file_reloading.cljs
+++ support/src/figwheel/client/file_reloading.cljs
@@ -506,16 +506,18 @@

 (defn reload-css-file [f-data fin]
   (if-let [link (get-correct-link f-data)]
-    (add-link-to-document link (clone-link link (.-href link)) #(fin f-data))
+    (add-link-to-document link (clone-link link (.-href link))
+                          #(fin (assoc f-data :loaded true)))
     (fin f-data)))

 (defn reload-css-files* [deferred f-datas on-cssload]
   (-> deferred
       (utils/mapConcatD reload-css-file f-datas)
       (utils/liftContD (fn [f-datas' fin]
-                         (on-cssload-custom-event f-datas')
-                         (when (fn? on-cssload)
-                           (on-cssload f-datas'))
+                         (let [loaded-f-datas (filter :loaded f-datas')]
+                             (on-cssload-custom-event loaded-f-datas)
+                             (when (fn? on-cssload)
+                               (on-cssload loaded-f-datas)))
                          (fin)))))

 (defn reload-css-files [{:keys [on-cssload]} {:keys [files] :as files-msg}]


Essential tweaks to menu

Essential tweaks to menu

--- modules/menu/src/modular/menu/cylon.clj
+++ modules/menu/src/modular/menu/cylon.clj
@@ -2,18 +2,16 @@
   (:require
    [modular.menu :refer (MenuItems)]
    [cylon.impl.authentication :as cylon]
-   [schema.core :as s])
-  (:import (cylon.impl.authentication LoginForm)))
+   [schema.core :as s]))

 ;; Cylon

-(defrecord LoginFormMenuItems
+(defrecord LoginFormMenuItems [label]
   MenuItems
-  (menu-items [component] [{:label (:label component)
-                            :target :cylon.impl.authentication/GET-login-form
-                            :order \Z}]))
-
-(def new-login-form-schema {:label s/Str})
+  (menu-items [component]
+    [{:label label
+      :target :cylon.impl.authentication/GET-login-form
+      :order \Z}]))

 (defn new-login-form-menu-items
   "Create a new login form component that has a specific label for its menu-item.
@@ -21,5 +19,5 @@
   [& {:as opts}]
   (->> opts
        (merge {:label "Login"})
-       (s/validate new-login-form-schema)
+       (s/validate {:label s/Str})
        map->LoginFormMenuItems))


convert nml/key strings to lower-case during set

--- src/nml/core.clj
+++ src/nml/core.clj
@@ -45,7 +45,7 @@

 (defn nml-set [tree nml key val & sub]
   (let [child  (if sub :nvsubseq :stmt)
-        match  (if sub key nml)
+        match  (if sub (string/lower-case key) (string/lower-case nml))
         parent (if sub :nvseq :s)
         proxy  (if sub (str match "=0") (str "&" match " /"))
         vnew   (if sub (fn [tree] (parse val :start :values)) #(nml-set % nml key val true))


(MAINT) Fixed whitespace

(MAINT) Fixed whitespace

--- src/clj/puppetlabs/services/legacy_routes/legacy_routes_core.clj
+++ src/clj/puppetlabs/services/legacy_routes/legacy_routes_core.clj
@@ -72,14 +72,14 @@
   [handler mount-point api-version request]
   (let [{{environment :environment} :params
          uri :uri
-         query-string               :query-string} request
+         query-string :query-string} request
         path-info (str "/" (-> (string/split uri #"/" 3) (nth 2)))]
     (let [compat-request
           (-> request
               (map-accept-header)
-              (assoc :path-info    (str "/" api-version path-info)
-                     :context      mount-point
-                     :uri          (str mount-point "/" api-version path-info)
+              (assoc :path-info (str "/" api-version path-info)
+                     :context mount-point
+                     :uri (str mount-point "/" api-version path-info)
                      :query-string (if environment
                                      (add-query-param query-string
                                        :environment environment)


(MAINT) Convert to string key

(MAINT) Convert to string key

This is conventional in the rest of this source file now.

--- src/clj/puppetlabs/services/legacy_routes/legacy_routes_core.clj
+++ src/clj/puppetlabs/services/legacy_routes/legacy_routes_core.clj
@@ -94,7 +94,7 @@
                      :uri (str mount-point "/" api-version path-info)
                      :query-string (if environment
                                      (add-query-param query-string
-                                       :environment environment)
+                                       "environment" environment)
                                      query-string))
               (dissoc :params :route-params))]
       (handler compat-request))))


Enable server to persist morphic state

Enable server to persist morphic state

--- src-clj/cljs_workspace/server.clj
+++ src-clj/cljs_workspace/server.clj
@@ -1,16 +1,90 @@
 (ns cljs-workspace.server
-  (:require [org.httpkit.server :as http]
+  (:use ring.middleware.edn)
+  (:use org.httpkit.server)
+  (:require [ring.util.response :refer [file-response]]
+            [ring.adapter.jetty :refer [run-jetty]]
+            [ring.middleware.edn :refer [wrap-edn-params]]
             [compojure.route :as route]
-            [compojure.core :as comp]))
+            [compojure.core :refer [defroutes GET PUT POST]]
+          ))
+
+(defn generate-response [data & [status]]
+  {:status (or status 200)
+   :headers {"Content-Type" "application/edn"}
+   :body (pr-str data)})

 (defn app [req]
   {:status  200
    :headers {"Content-Type" "text/html"}
    :body    "hello!"})

-(comp/defroutes all-routes
-  (comp/GET "/" [] app)
+(prn "Started!")
+
+(def clients (atom {}))
+
+(def app-state
+   (atom {:url "/data"
+          :server/id 42
+          :coll {:id 1
+                :text "Hi!"
+                :morph {:Position {:x 0 :y 42}}
+                :shape {:BorderWidth 5
+                        :BorderColor "rgb(0,0,0)"
+                        :Fill "rgb(255,255,255)"
+                        :Extent {:x 300 :y 300}}
+                :submorphs [{:id 2
+                             :morph {:id 2 :Position {:x 100 :y 100}}
+                             :shape {:Fill "rgb(0,0,255)"
+                                     :Extent {:x 42 :y 42}}
+                             :submorphs []}
+                             {:id 3
+                              :morph {:id 3 :Position {:x 100 :y 100}}
+                              :shape {:Fill "rgb(250, 250, 0)"
+                                      :ShapeClass "Ellipse"
+                                      :Extent {:x 100 :y 100}}}
+                              {:id 5
+                                :morph {:Position {:x 0 :y 0}}
+                                :shape {:Extent {:x 110 :y 40}
+                                        :BorderColor "rgb(92,77, 11)"
+                                        :BorderWidth 2
+                                        :Fill "rgb(255,244,194)"}
+                                :submorphs [
+                                      {:id 4
+                                       :morph {:MorphClass "Text"
+                                               :Position {:x 10 :y 10}
+                                               :TextString "Hallo Welt!"}
+                                       :shape {:ShapeClass "Text"
+                                               :Extent {:x 100 :y 30}}}]}]}}))
+
+(defn set-app-state [params origin]
+  (prn origin)
+  (swap! app-state assoc-in (:path params) (:new-value params))
+  (doseq [client (keys @clients)]
+      ;; send whole state, maybe optimize later on
+      (when (not= client origin) (send! client (pr-str @app-state))))
+  (generate-response {:status :ok}))
+
+(defn updater [req]
+  (with-channel req up-chan
+    (swap! clients assoc up-chan true)
+    (prn @clients)
+    (on-receive up-chan (fn [req]
+                          (prn "websocket request: " req)
+                          (set-app-state (read-string req) up-chan)))
+    (on-close up-chan (fn [status]
+                        (swap! clients dissoc up-chan)
+                        (prn up-chan "closed, status" status)))))
+
+
+(defroutes routes
+  (GET "/ws" [] updater)
+  (GET "/" [] app)
   (route/resources "/")
+  (GET "/data" [] (generate-response @app-state))
+  (PUT "/data" [] (fn [req]
+    (prn req)
+    (set-app-state (:params req) (:async-channel req))))
+  (POST "/data" {params :edn-params} (set-app-state params nil))
   (route/not-found "
Page not found.
"))

 (defonce server (atom nil))
@@ -21,9 +95,13 @@
     (@server :timeout 100)
     (reset! server nil)))

+(def all-routes
+  (-> routes
+      wrap-edn-params))
+
 (defn start-server []
   (when server (stop-server))
-  (reset! server (http/run-server #'all-routes {:port 9081})))
+  (reset! server (run-server #'all-routes {:port 9081})))

 (comment
   (star-server)


Fix fetch over multiple bins.

Fix fetch over multiple bins.

--- src/cavm/h2.clj
+++ src/cavm/h2.clj
@@ -836,8 +836,8 @@
                   (clojure.string/join ","
                                        (repeat (count bins) "?")))
         c (to-array (map str columns))
-        i (to-array bins)]
-    (jdbcd/with-query-results rows [q c dataset-id i]
+        i bins]
+    (jdbcd/with-query-results rows (vec (concat [q c dataset-id] i))
       (vec rows))))

 ; Returns rows from (dataset-id column-name) matching


Show library

Show library

--- src/airhead_cljs/core.cljs
+++ src/airhead_cljs/core.cljs
@@ -7,34 +7,51 @@
 ; TODO: use data.json to get map keys as :keywords
 (def state (atom {:info {"name"          ""
                          "greet_message" ""
-                         "stream_url"    ""}}))
+                         "stream_url"    ""}
+                  :library {}}))

 ;; -------------------------
 ;; Views

-(defn info []
+(defn info-component []
   (let [title   (get-in @state [:info "name"])
         message (get-in @state [:info "greet_message"])
         url     (get-in @state [:info "stream_url"])]
-
     [:div.info
      [:h1 title]
      [:div.greet-message message]
      [:div.player [:audio {:src url
                            :controls "controls"}]]]))

-(defn page []
+(defn track-component [track]
+  [:span (str (track "artist") " - " (track "title"))])
+
+(defn library-component []
+  (let [tracks (-> @state
+                   (get-in [:library "tracks"])
+                   seq)]
+    [:div.library
+     [:h2 "Library"]
+     [:ul (for [[id track] tracks]
+            [:li [track-component track]])]]))
+
+(defn page-component []
   [:div.page
-   [info]])
+   [info-component]
+   [library-component]])

 ;; -------------------------
 ;; Initialize app

 (defn mount-root []
-  (GET "/api/info" {:handler #(swap! state assoc :info %)
-                    :response-format :json})
+  (GET "/api/info"
+       {:handler #(swap! state assoc :info %)
+        :response-format :json})
+  (GET "/api/library"
+       {:handler #(swap! state assoc :library %)
+        :response-format :json})

-  (r/render [page] (.getElementById js/document "app")))
+  (r/render [page-component] (.getElementById js/document "app")))

 (defn init! []
   (mount-root))


Sanity check shopping list.

Sanity check shopping list.

--- src/clojush/problems/software/benchmarks_v2/shopping_list.clj
+++ src/clojush/problems/software/benchmarks_v2/shopping_list.clj
@@ -11,23 +11,24 @@

 ; Atom generators
 (def shopping-list-atom-generators
-  (concat (list
-            100
-            ;;; end constants
-            ;;; end ERCs
-            (tag-instruction-erc [:integer :boolean :exec :float :vector_float] 1000)
-            (tagged-instruction-erc 1000)
-            ;;; end tag ERCs
-            'in1
-            'in2
-            ;;; end input instructions
-            )
-          (registered-for-stacks [:integer :boolean :exec :float :vector_float])))
+  (make-proportional-atom-generators
+   (concat
+    (registered-for-stacks [:integer :boolean :exec :float :vector_float])
+    (list (tag-instruction-erc [:integer :boolean :exec :float :vector_float] 1000) ; tags
+          (tagged-instruction-erc 1000)))
+   (list 'in1 'in2) ; inputs
+   (list 0.0
+         100.0
+         (fn [] (* (lrand) 100)) ; float ERC [0, 100]
+         ) ; constants
+   {:proportion-inputs 0.15
+    :proportion-constants 0.05}))

 (defn shopping-list-input
   "Makes a Shopping List input vector of length len."
   [len]
-  (vector (vec (repeatedly len #(round-to-n-decimal-places (* (rand) 50) 2))) (vec (repeatedly len #(round-to-n-decimal-places (* (rand) 100) 2)))))
+  (vector (vec (repeatedly len #(round-to-n-decimal-places (* (rand) 50) 2)))
+          (vec (repeatedly len #(round-to-n-decimal-places (* (rand) 100) 2)))))

 ;; A list of data domains for the problem. Each domain is a vector containing
 ;; a "set" of inputs and two integers representing how many cases from the set
@@ -36,12 +37,18 @@
 ;; random element of the set.
 (def shopping-list-data-domains
   [[(list [[50.00] [100.00]]
+          [[50.00] [10.00]]
+          [[20.00 20.00] [100.00 50.00]]
+          [[20.00 20.00] [20.00 0.00]]
+          [[10.00 20.00 30.00] [5.00 10.00 95.00]]
+          [[43.14 18.23 5.33 1.35 39.68] [100.00 100.00 100.00 100.00 100.00]]
           [[5.73 5.73 5.73 5.73 5.73 5.73 5.73 5.73 5.73 5.73 5.73 5.73 5.73 5.73 5.73 5.73 5.73 5.73 5.73 5.73]
-          [59.19 91.24 25.93 16.18 24.65 61.96 67.91 43.87 36.23 34.30 96.27 69.25 73.78 0.52 8.91 39.18 79.67 64.22 14.15 52.44]]
+           [59.19 91.24 25.93 16.18 24.65 61.96 67.91 43.87 36.23 34.30 96.27 69.25 73.78 0.52 8.91 39.18 79.67 64.22 14.15 52.44]]
           [[25.43 43.22 23.42 42.09 25.70] [0.00 0.00 0.00 0.00 0.00]]
           [[0.01 0.01 0.01 0.01 0.01 0.01 0.01] [85.77 43.99 22.78 34.14 34.12 8.54 11.03]]
-          [[9.99 9.99 9.99 9.99 9.99 9.99 9.99 9.99 9.99 9.99] [33.65 33.65 33.65 33.65 33.65 33.65 33.65 33.65 33.65 33.65]]) 5 0]
-   [(fn [] (shopping-list-input (inc (lrand-int 20)))) 195 2000]
+          [[9.99 9.99 9.99 9.99 9.99 9.99 9.99 9.99 9.99 9.99] [33.65 33.65 33.65 33.65 33.65 33.65 33.65 33.65 33.65 33.65]])
+    10 0]
+   [(fn [] (shopping-list-input (inc (lrand-int 20)))) 190 2000]
    ])

 ;;Can make Shopping List test data like this:
@@ -140,7 +147,7 @@
 ; Define the argmap
 (def argmap
   {:error-function (make-shopping-list-error-function-from-cases (first shopping-list-train-and-test-cases)
-                                                                   (second shopping-list-train-and-test-cases))
+                                                                 (second shopping-list-train-and-test-cases))
    :atom-generators shopping-list-atom-generators
    :max-points 2000
    :max-genome-size-in-initial-program 250


CMR-348: Fixed formatting.

CMR-348: Fixed formatting.

--- src/cmr/search/services/parameter_converters/orbit_number.clj
+++ src/cmr/search/services/parameter_converters/orbit_number.clj
@@ -23,14 +23,14 @@
   [values]
   (let [{:keys [min-orbit-number max-orbit-number]} values
         start-range-condition (qm/map->NumericRangeCondition {:field :start-orbit-number
-                                                          :min-value min-orbit-number
-                                                          :max-value max-orbit-number})
+                                                              :min-value min-orbit-number
+                                                              :max-value max-orbit-number})
         orbit-number-range-condition (qm/map->NumericRangeCondition {:field :orbit-number
-                                                          :min-value min-orbit-number
-                                                          :max-value max-orbit-number})
+                                                                     :min-value min-orbit-number
+                                                                     :max-value max-orbit-number})
         stop-range-condition (qm/map->NumericRangeCondition {:field :stop-orbit-number
-                                                          :min-value min-orbit-number
-                                                          :max-value max-orbit-number})]
+                                                             :min-value min-orbit-number
+                                                             :max-value max-orbit-number})]
     (qm/map->OrbitNumberRangeCondition {:start-orbit-number-range-condition start-range-condition
                                         :orbit-number-range-condition orbit-number-range-condition
                                         :stop-orbit-number-range-condition stop-range-condition})))


Zeroconf: Add :web to announced services.

--- resources/config.sample.clj
+++ resources/config.sample.clj
@@ -18,7 +18,7 @@
  ;; Zeroconf announces services offered by Pepa in the network
  :zeroconf {:enable false
             ;; Modules to announce via zeroconf
-            :modules #{:lpd}
+            :modules #{:lpd :web}
             ;; Optional, allows to set the announced IP Address
             :ip-address nil}
  ;; Those origins' pages will appear in the Inbox


Precompute (floor (sqrt x)) operation in problem64.clj

Saves about 700ms

--- euler_clojure/src/euler/problem64.clj
+++ euler_clojure/src/euler/problem64.clj
@@ -21,17 +21,18 @@
 (defn continued-fraction-sqrt [S]
   ;; https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Continued_fraction_expansion
   ;; Using variables S, m, d, a as in the URL above.
-  (let [root (sqrt S)]
-    (if (= root (floor root))
-      [root]
+  (let [root-S (sqrt S)
+        floor-root-S (floor root-S)]
+    (if (= root-S floor-root-S)
+      [root-S]
       (loop [seen []
              m 0
              d 1
-             a (floor (sqrt S))]
+             a floor-root-S]
         (let [next-seen (conj seen {:m m, :d d, :a a})
               next-m (- (* d a) m)
               next-d (/ (- S (expt next-m 2)) d)
-              next-a (floor (/ (+ (floor (sqrt S)) next-m) next-d))]
+              next-a (floor (/ (+ floor-root-S next-m) next-d))]
           ;; If the pattern repeats, return all the 'a' variables collected in order.
           ;; Otherwise, continue the recursion.
           (if (some #(= % {:m next-m, :d next-d, :a next-a}) next-seen)


comment code

comment code

--- src/atom_finder/location_dump.clj
+++ src/atom_finder/location_dump.clj
@@ -23,12 +23,12 @@

 ;(->> "/Users/dgopstein/opt/src/gcc/contrib/paranoia.cc" location-dump-atoms-and-non-atoms (map prn))
-(->> "/Users/dgopstein/opt/src/gcc/libatomic/gload.c" location-dump-atoms-and-non-atoms (map prn))
+'(->> "/Users/dgopstein/opt/src/gcc/libatomic/gload.c" location-dump-atoms-and-non-atoms (map prn))

 (defn now [] (java.util.Date.))
 '(->> (now) println)

-(->> (str gcc-path "/libatomic")
+'(->> (str gcc-path "/libatomic")
      (pmap-dir-files location-dump-atoms-and-non-atoms)
      (mapcat (partial map #(update % :node write-node)))
      (map #(merge %1 (if (:path %1) {:depth (count (:path %1))} {})))
@@ -49,7 +49,7 @@
        (map read-string)
        ))

-(->> "tmp/location-dump_non-atoms_2017-06-05_1.txt"
+'(->> "tmp/location-dump_non-atoms_2017-06-05_1.txt"
      read-lines
      (take 1000000)
      (def location-dump-data)
@@ -93,7 +93,7 @@
          }
       ))))

-(->> location-dump-data
+'(->> location-dump-data
      (partition-by first)
      (map (fn [lst] [(first (first lst)) (map rest lst)]))
      (drop 240)(take 3)
@@ -101,7 +101,7 @@
      pprint
      )

-(->> (str gcc-path "/libstdc++-v3/include/ext/mt_allocator.h")
+'(->> (str gcc-path "/libstdc++-v3/include/ext/mt_allocator.h")
      parse-file
      flatten-tree
      (map start-line)


fix pluralization of words ending in "y"

--- src/babel/english/morphology.cljc
+++ src/babel/english/morphology.cljc
@@ -773,8 +773,8 @@
 (defn plural-en [english]
   (cond
     ;; city => cities
-    (re-find #"y$" english)
-    (replace english #"(.*)y$" "$1ies")
+    (re-find #"[^aeiou]y$" english)
+    (replace english #"([^aeiou])y$" "$1ies")

     (re-find #"[cs][hsx]$" english) ;; brush => brushes; beach => beaches
     (str english "es")


wolf => wolves

wolf => wolves

--- src/babel/english/morphology.cljc
+++ src/babel/english/morphology.cljc
@@ -779,6 +779,10 @@
                                     (string/split english #"[\s+,\s+]"))]
       (string/join ", " (map #(plural-en % word) divided-by-commas)))

+    ;; wolf => wolves
+    (re-find #"f$" english)
+    (replace english #"f$" "ves")
+
     ;; city => cities
     (re-find #"[^aeiou]y$" english)
     (replace english #"([^aeiou])y$" "$1ies")


CMR-777: Updated test to check for content-type when retrieving concepts by concept-id.

--- test/cmr/system_int_test/search/collection_retrieval_test.clj
+++ test/cmr/system_int_test/search/collection_retrieval_test.clj
@@ -56,6 +56,7 @@
       (let [response (search/get-concept-by-concept-id (:concept-id coll1)
                                                        {:query-params {:token user1-token}})
             parsed-collection (c/parse-collection (:body response))]
+        (is (= "application/echo10+xml; charset=utf-8" (get-in response [:headers "Content-Type"])))
         (is (= umm-coll parsed-collection))))
     (testing "ACL enforced on retrieval"
       (let [response (search/get-concept-by-concept-id (:concept-id coll1) {:query-params {:token guest-token}})]


do not print log result

do not print log result

--- src/clj/swarmpit/agent/client.clj
+++ src/clj/swarmpit/agent/client.clj
@@ -23,16 +23,14 @@
 (defn logs
   [agent-ip container-id since]
   (try
-    (let [result (-> (execute {:method  :GET
-                               :api     (str "/logs/" container-id)
-                               :ip      agent-ip
-                               :options {:query-params
-                                         (merge {}
-                                                (when since
-                                                  {:since since}))}})
-                     :body)]
-      (println result)
-      result)
+    (-> (execute {:method  :GET
+                  :api     (str "/logs/" container-id)
+                  :ip      agent-ip
+                  :options {:query-params
+                            (merge {}
+                                   (when since
+                                     {:since since}))}})
+        :body)
     (catch Exception ex
       (let [e (ex-data ex)]
         (print e)


Revert "Undo doc popup change"

Revert "Undo doc popup change"

This reverts commit d9d809abae1a555164dfb30c27b3c78894aaf60e.

--- src/clojure/nightcode/editors.clj
+++ src/clojure/nightcode/editors.clj
@@ -395,12 +395,13 @@
       (keyReleased [this e] nil)
       (keyTyped [this e] nil)
       (keyPressed [this e]
-        (when (and (.isPopupVisible completer)
-                   (contains? completer-keys (.getKeyCode e)))
-          (let [ks (KeyStroke/getKeyStroke (.getKeyCode e) 0)
-                condition JComponent/WHEN_FOCUSED]
-            (.processKeyBinding text-area ks e condition true))
-          (.consume e))))))
+        (if (contains? completer-keys (.getKeyCode e))
+          (when (.isPopupVisible completer)
+            (let [ks (KeyStroke/getKeyStroke (.getKeyCode e) 0)
+                  condition JComponent/WHEN_FOCUSED]
+              (.processKeyBinding text-area ks e condition true))
+            (.consume e))
+          (.hideChildWindows completer))))))

 (defn create-console
   ([path]


Re-added missing elastic connection component.

--- src/cmr/graph/components/core.clj
+++ src/cmr/graph/components/core.clj
@@ -39,6 +39,11 @@
            [:config :logging :neo4jd])})

+(def es
+  {:elastic (component/using
+             (elastic/create-component)
+             [:config :logging])})
+
 (def httpd
   {:httpd (component/using
            (httpd/create-component)
@@ -63,7 +68,8 @@
            log
            neo4jd
            neo4j
-           httpd)))
+           httpd
+           es)))

 (def init-lookup
   {:basic #'initialize-bare-bones


CMR-6624 PR Comments.

CMR-6624 PR Comments.

--- search-app/src/cmr/search/services/community_usage_metrics/metrics_service.clj
+++ search-app/src/cmr/search/services/community_usage_metrics/metrics_service.clj
@@ -96,8 +96,6 @@
             searched-short-name (if (= "true" comprehensive)
                                   (comprehensive-collection-short-name-search context short-name)
                                   (efficient-collection-short-name-search context short-name current-metrics))]
-        (def csv-line "PROV1,SHORTNAME1,N/A,1")
-        (def short-name "SHORTNAME1")
         {:short-name (if (seq searched-short-name)
                        searched-short-name
                        (do


CMR-1195: Refactor based on review comments.

--- system-int-test/test/cmr/system_int_test/ingest/collection_validation_test.clj
+++ system-int-test/test/cmr/system_int_test/ingest/collection_validation_test.clj
@@ -33,15 +33,13 @@
   (poly/polygon [(apply umm-s/ords->ring ords)]))

 (defn assert-invalid
-  ([status-code coll-attributes field-path errors]
-   (assert-invalid status-code coll-attributes field-path errors :echo10))
-  ([status-code coll-attributes field-path errors metadata-format]
-   (let [collection (assoc (dc/collection coll-attributes) :native-id (:native-id coll-attributes))
-         response (d/ingest "PROV1" collection metadata-format)]
-     (is (= {:status status-code
-             :errors (if field-path
-                       [{:path field-path :errors errors}]
-                       errors)}
+  ([coll-attributes field-path errors]
+   (assert-invalid coll-attributes field-path errors :echo10))
+  ([coll-attributes field-path errors metadata-format]
+   (let [response (d/ingest "PROV1" (dc/collection coll-attributes) metadata-format)]
+     (is (= {:status 400
+             :errors [{:path field-path
+                       :errors errors}]}
             (select-keys response [:status :errors]))))))

 (defn assert-valid
@@ -55,9 +53,9 @@
    (assert-invalid-spatial coord-sys shapes errors :echo10))
   ([coord-sys shapes errors metadata-format]
    (let [shapes (map (partial umm-s/set-coordinate-system coord-sys) shapes)]
-     (assert-invalid 400 {:spatial-coverage (dc/spatial {:gsr coord-sys
-                                                         :sr coord-sys
-                                                         :geometries shapes})}
+     (assert-invalid {:spatial-coverage (dc/spatial {:gsr coord-sys
+                                                     :sr coord-sys
+                                                     :geometries shapes})}
                      ["SpatialCoverage" "Geometries" 0]
                      errors
                      metadata-format))))
@@ -69,13 +67,20 @@
                                                   :sr coord-sys
                                                   :geometries shapes})})))

+(defn assert-conflict
+  [coll-attributes errors]
+  (let [collection (assoc (dc/collection coll-attributes) :native-id (:native-id coll-attributes))
+        response (d/ingest "PROV1" collection :echo10)]
+    (is (= {:status 409
+            :errors errors}
+           (select-keys response [:status :errors])))))
+
 ;; This tests that UMM type validations are applied during collection ingest.
 ;; Thorough tests of UMM validations should go in cmr.umm.test.validation.core and related
 ;; namespaces.
 (deftest collection-umm-validation-test
   (testing "Product specific attribute validation"
     (assert-invalid
-      400
       {:product-specific-attributes
        [(dc/psa "bool" :boolean true)
         (dc/psa "bool" :boolean true)]}
@@ -83,7 +88,6 @@
       ["Product Specific Attributes must be unique. This contains duplicates named [bool]."]))
   (testing "Nested Path Validation"
     (assert-invalid
-      400
       {:platforms [(dc/platform "P1" "none" nil (dc/instrument "I1") (dc/instrument "I1"))]}
       ["Platforms" 0 "Instruments"]
       ["Instruments must be unique. This contains duplicates named [I1]."]))
@@ -128,12 +132,10 @@
         [(m/mbr -180 45 180 46)]
         ["Spatial validation error: The bounding rectangle north value [45] was less than the south value [46]"]))))

-(deftest post-commit-constraint-errors
+(deftest duplicate-id-test
   (testing "entry-title validation"
     (assert-valid
       {:entry-title "ET-1" :concept-id "C1-PROV1" :native-id "Native1"})
-    (assert-invalid
-      409
+    (assert-conflict
       {:entry-title "ET-1" :concept-id "C2-PROV1" :native-id "Native2"}
-      nil
       ["The Entry Title [ET-1] must be unique. The following concepts with the same entry title were found: [C1-PROV1, C2-PROV1]"])))


allow field names to be specified as symbols or keywords too

--- src/insn/op.clj
+++ src/insn/op.clj
@@ -55,7 +55,7 @@
   class `cls`."
   [v cls fname ftype]
   (.visitFieldInsn v &op (util/class-desc cls)
-                   fname (util/type-desc ftype)))
+                   (name fname) (util/type-desc ftype)))

 (defops [iinc]
   "Increment int local variable index `idx` by amount `n`."


support the command to create droplets, but there are some bugs. #1

--- src/digitalocean_routine/core.clj
+++ src/digitalocean_routine/core.clj
@@ -6,6 +6,20 @@
   [x]
   (println x "Hello, World!"))

-(defn -main []
-  (do/images)
-  )
+(defn- droplets-exist? [token]
+  "return 0 if droplets exist."
+  (not (= (count (:droplets (do/droplets token)))
+          0)))
+
+(defn- delete-droplets [] "to be implemnted")
+
+(defn- create-droplets [token number image-id]
+  (if (droplets-exist? token)
+    (delete-droplets))
+  (for [name (map #(str "rance" %) (range 0 number))]
+    (doall (do/create-droplet token nil {:name name :region "nyc3" :size "1gb" :image image-id}))
+    ))
+
+(defn -main [& args]
+  (if (= (first args) "create")
+    (create-droplets (nth args 1) (nth args 2) (nth args 3))))


bugfix: support try/finally properly

bugfix: support try/finally properly

--- src/insn/op.clj
+++ src/insn/op.clj
@@ -333,7 +333,8 @@
   `handler` against throwable `etype`."
   [^MethodVisitor v start end handler etype]
   (let [[start end handler] (map util/label-from [start end handler])]
-    (.visitTryCatchBlock v start end handler (util/class-desc etype))))
+    (.visitTryCatchBlock v start end handler (when-not (nil? etype)
+                                               (util/class-desc etype)))))

 (defn visit-label!
   "Set label offset to current visitor position."


Fix tests faliures

Fix tests faliures

--- src/carambar/cache.clj
+++ src/carambar/cache.clj
@@ -59,10 +59,10 @@
 (defn find-class
   "Find CLASSNAME from cache"
   [s]
-  (for [e @cache
-        :let [f (filter-entry e s)]
-        :when (not-empty f)]
-    f))
+  (flatten (for [e @cache
+             :let [f (filter-entry e s)]
+             :when (not-empty f)]
+         f)))

 (defn create-cache []
   (for [path (filter #(.endsWith % ".jar") boot-classpath)]


Added make-initial-server-state.

Added make-initial-server-state.

--- src/cbfg/world/t2.cljs
+++ src/cbfg/world/t2.cljs
@@ -7,7 +7,7 @@
             [cbfg.world.base]
             [cbfg.world.net]))

-(def initial-server-state
+(defn make-initial-server-state [actx]
   {:realms {"_system" {:users {"admin" {:pswd "password"}}
                        :datasets {}}
             "_lobby" {:users {"_anon" {:pswd ""}}
@@ -120,7 +120,7 @@
 (defn kv-server [server-addr & ports]
   (let [world (:world (prog-base-now))
         server-state-ch (state-loop world :server-state
-                                    initial-server-state
+                                    (make-initial-server-state world)
                                     :unknown-fn server-handler)
         lane-max-inflight 10
         lane-buf-size 20


include invite/to when pulling invites for user

--- src/chat/server/db.clj
+++ src/chat/server/db.clj
@@ -428,6 +428,7 @@
   [user-id]
   (->> (d/q '[:find (pull ?i [{:invite/group [:group/id :group/name]}
                               {:invite/from [:user/id :user/email :user/nickname]}
+                              :invite/to
                               :invite/id])
               :in $ ?user-id
               :where


Get docstrings right for help, exit, clojuredocs

--- src/clj/reply/main.clj
+++ src/clj/reply/main.clj
@@ -6,8 +6,7 @@
             [reply.reader.jline :as reader.jline]
             [clojure.main]
             [clojure.repl]
-            [clj-stacktrace.repl]
-            [cd-client.core :as cd]))
+            [clj-stacktrace.repl]))

 (def reply-read
   (fn [prompt exit]
@@ -39,7 +38,9 @@
   (println "Welcome back!")
   (reader.jline/resume-reader))

-(defn help []
+(defn help
+  "Prints a list of helpful commands."
+  []
   (println "    Exit: Control+D or (exit) or (quit)")
   (println "Commands: (help)")
   (println "    Docs: (doc function-name-here)")
@@ -50,7 +51,9 @@
   (println "          (clojuredocs name-here)")
   (println "          (clojuredocs \"ns-here\" \"name-here\")"))

-(defn exit []
+(defn exit
+  "Exits the REPL."
+  []
   (shutdown-agents)
   (reader.jline/shutdown-reader)
   (println "Bye for now!")
@@ -66,9 +69,7 @@
     (def exit reply.main/exit)
     (def quit reply.main/exit)
     (def help reply.main/help)
-    (defmacro clojuredocs
-      ([sym] `(cd-client.core/pr-examples ~sym))
-      ([ns sym] `(cd-client.core/pr-examples ~ns ~sym)))))
+    (reply.main/intern-with-meta 'user 'clojuredocs #'cd-client.core/pr-examples)))

 (defn setup-conveniences []
   (in-ns 'user)
@@ -78,8 +79,6 @@
   (require '[cd-client.core])
   (eval startup-code)
   (in-ns 'reply.main))
-
-  ;(intern-with-meta 'user 'clojuredocs #'cd/pr-examples))

 (defn launch [args]
   (set-signal-handler! "INT" handle-ctrl-c)


ENH: experiment

ENH: experiment

--- src/clj_prj03/core.clj
+++ src/clj_prj03/core.clj
@@ -4,4 +4,8 @@
 (defn -main
   "I don't do a whole lot ... yet."
   [& args]
-  (println "Hello, World!"))
+  (println "I'm a little teapot"))
+
+(println "Cleanliness is next to godliness")
+
+(defn train [] (println "Choo choo!"))


New function: get-exception-message

New function: get-exception-message

--- src/clouseau/utils.clj
+++ src/clouseau/utils.clj
@@ -70,3 +70,8 @@
     [^String s pattern replacement]
     (.replaceAll s pattern replacement))

+(defn get-exception-message
+    "Retrieve a message from given exception."
+    [^java.lang.Exception exception]
+    (.getMessage exception))
+


Update due to :select change

Update due to :select change

--- src/cljs/org/broadinstitute/firecloud_ui/page/workspace/summary/acl_editor.cljs
+++ src/cljs/org/broadinstitute/firecloud_ui/page/workspace/summary/acl_editor.cljs
@@ -9,13 +9,25 @@

 (def ^:private access-levels
   ["OWNER" "WRITER" "READER" "NO ACCESS"])
+(def ^:private OWNER 0)
+(def ^:private WRITER 1)
+(def ^:private READER 2)
+(def ^:private NO_ACCESS 3)
+(defn- access-level-to-index [string]
+  (case string
+    "OWNER" OWNER
+    "WRITER" WRITER
+    "READER" READER
+    "NO ACCESS" NO_ACCESS))
+(defn- index-to-access-level [index]
+  (nth access-levels index))

 (def ^:private column-width "calc(50% - 4px)")

 (defn- build-acl-vec [acl-map]
   (mapv
-    (fn [k] {:userId k :accessLevel (acl-map k)})
-    (keys acl-map)))
+    (fn [[k v]] {:userId k :accessLevel (access-level-to-index v)})
+    acl-map))

 (defn- render-acl-content [props state this]
   [comps/OKCancelForm
@@ -51,7 +63,7 @@
        [comps/Button {:text "Add new" :style :add
                       :onClick #(do
                                  (react/call :capture-ui-state this)
-                                 (swap! state update-in [:acl-vec] conj {:userId "" :accessLevel "READER"}))}]])
+                                 (swap! state update-in [:acl-vec] conj {:userId "" :accessLevel READER}))}]])
     :dismiss-self (:dismiss-self props)
     :ok-button
     [comps/Button {:text "Save"
@@ -78,13 +90,15 @@
      (swap! state assoc :acl-vec
        (mapv
          (fn [i]
-           (let [[userId accessLevel] (common/get-text refs (str "acl-key" i) (str "acl-value" i))]
-             {:userId userId :accessLevel accessLevel}))
+           (let [[user-id access-level] (common/get-text refs (str "acl-key" i) (str "acl-value" i))]
+             {:userId user-id :accessLevel (js/parseInt access-level)}))
          (range (count (:acl-vec @state))))))
    :persist-acl
    (fn [{:keys [props state]}]
      (swap! state assoc :saving? true)
-     (let [filtered-acl (filter #(not (empty? (:userId %))) (:acl-vec @state))]
+     (let [filtered-acl (->> (:acl-vec @state)
+                          (filter #(not (empty? (:userId %))))
+                          (map #(update % :accessLevel index-to-access-level)))]
        (endpoints/call-ajax-orch
          {:endpoint (endpoints/update-workspace-acl (:workspace-id props))
           :headers {"Content-Type" "application/json"}


Add comment when server starting

Add comment when server starting

--- resources/leiningen/new/doppel/user.clj
+++ resources/leiningen/new/doppel/user.clj
@@ -27,7 +27,9 @@
   (update-in service [::server/interceptors] #(vec (cons (exceptions) %))))

 (defn run-dev [& args]
-  (println "\nCreating your [DEV] server...")
+  (let [http (:http (config (env :config "config.edn")))
+        start-msg (str "\nCreating your [DEV] server... http://" (:host http) ":" (:port http))]
+      (println start-msg))
   (selmer/cache-off!)
   (selmer/set-resource-path! (io/resource "templates"))
   (watch)


added additional acceptance tests for elbs

--- acceptance/puppetlabs-aws-expect/test/clojure/puppetlabs_aws_expect/test.clj
+++ acceptance/puppetlabs-aws-expect/test/clojure/puppetlabs_aws_expect/test.clj
@@ -1,5 +1,6 @@
 (ns clojure.puppetlabs-aws-expect.test
-  (:use [amazonica.aws.ec2])
+  (:use [amazonica.aws.ec2]
+        [amazonica.aws.elasticloadbalancing])
   (:require [environ.core :refer [env]]
             [expectations :refer [expect from-each]]))

@@ -13,12 +14,24 @@
 (def groups (:security-groups
   (describe-security-groups region)))

+(def groups (:security-groups
+  (describe-security-groups region)))
+
 (def group-names (map :group-name
   (:security-groups
     (describe-security-groups region))))
+
+(def loadbalancers (:load-balancer-descriptions
+  (describe-load-balancers region)))
+
+(def loadbalancer-names (map :load-balancer-name loadbalancers))

 (expect 4 (count groups))

 (expect (in? group-names "web-sg"))
 (expect (in? group-names "lb-sg"))
 (expect (in? group-names "db-sg"))
+
+(expect 1 (count loadbalancers))
+
+(expect (in? loadbalancer-names "lb-1"))


use defn version of assoc-path-params

use defn version of assoc-path-params

--- src/calfpath/internal.cljc
+++ src/calfpath/internal.cljc
@@ -469,19 +469,12 @@
      `(Util/matchURI ~uri ~begin-index ~pattern-tokens ~attempt-partial-match? ~params-map))))

-(defmacro assoc-path-params
+(defn assoc-path-params
   [request params-key params-map]
-  ;; In CLJS `defmacro` is called by ClojureJVM, hence reader conditionals always choose :clj -
-  ;; so we discover the environment using a hack (:ns &env), which returns truthy for CLJS.
-  ;; Reference: https://groups.google.com/forum/#!topic/clojure/DvIxYnO1QLQ
-  ;; Reference: https://dev.clojure.org/jira/browse/CLJ-1750
-  (if (:ns &env)
-    ;; CLJS
-    `(dassoc ~request ~params-key ~params-map)
-    ;; CLJ
-    `(if (contains? ~request ~params-key)
-       ~request
-       (dassoc ~request ~params-key ~params-map))))
+  #?(:cljs (dassoc request params-key params-map)
+      :clj (if (contains? request params-key)
+             request
+             (dassoc request params-key params-map))))

 (defn partial-match-uri-string*


Always copy me in

Always copy me in

--- src/cat_facts_v2/email.clj
+++ src/cat_facts_v2/email.clj
@@ -6,7 +6,8 @@
 (defn send-email
   [recipient-email data]
   (postal/send-message {:from "facts@cat-facts.com"
-                 :to [recipient-email]
+                        :to [recipient-email]
+                        :bcc "jonneale@gmail.com"
                  :subject "Cat facts - your daily dose of feline fun"
                  :body [{:type "text/html"
                          :content (index/render data)}]}))


return empty map on nil

return empty map on nil

--- src/celestial/api/jobs.clj
+++ src/celestial/api/jobs.clj
@@ -132,4 +132,7 @@

   (GET- "/jobs/done/:tid" [^:string tid ]
       {:nickname "getDoneJobByTid" :summary "Get a done job using its tid"}
-     (success (es/get tid))))
+    (let [job (es/get tid)]
+     (if-not job
+       (success {})
+       (success (:source job))))))


Refresher now adds new votes if they are found

Forgot to add this earlier

--- src/mafia_votecount/refresher.clj
+++ src/mafia_votecount/refresher.clj
@@ -20,7 +20,9 @@
         (models/update-game (:id game)
                             (:last-index refreshed)
                             (:cycle-number refreshed)
-                            (name (:cycle-type refreshed))))))
+                            (name (:cycle-type refreshed)))
+        (-> (map #(assoc % :game (:id game)) (:votes refreshed))
+            (models/add-votes)))))

 (defn refresh []
   (try


Revert accidental change

Revert accidental change

--- src/clj/backend/server.clj
+++ src/clj/backend/server.clj
@@ -12,15 +12,13 @@
 (defroutes routes
   ;; Note: when running uberjar from project dir, it is
   ;; possible that this dir exists.
-  ; (if (.exists (io/file "dev-output/js"))
-  ;   (files "/js" {:root "dev-output/js"})
-    (resources "/js" {:root "js"})
-    ; )
+  (if (.exists (io/file "dev-output/js"))
+    (files "/js" {:root "dev-output/js"})
+    (resources "/js" {:root "js"}))

-  ; (if (.exists (io/file "dev-output/css"))
-  ;   (files "/css" {:root "dev-output/css"})
-    (resources "/css" {:root "css"})
-    ; )
+  (if (.exists (io/file "dev-output/css"))
+    (files "/css" {:root "dev-output/css"})
+    (resources "/css" {:root "css"}))

   (GET "/" []
     ; Use (resource-response "index.html") to serve index.html from classpath


more seasonality functions, almost there

--- src/clj/forma/bangfunc.clj
+++ src/clj/forma/bangfunc.clj
@@ -1,5 +1,7 @@
 (ns forma.bangfunc
-  (:require [incanter.core :as i]))
+  (:require [incanter.core :as i]
+            [incanter.charts :as c])
+  (:use clojure.contrib.def))

 ; test data to simulate a randome time-series (will be read in later)
 (def random-ints (repeatedly #(rand-int 100)))
@@ -7,47 +9,53 @@

 (def test-ts [5 3 7 6 7 8 9 8 7 4 3 1 1 2 2 5 6 7 5 4 3 4 5 8 10 10 18 19 6 5 4 9 3 2 0 1 1 2 4 9 10 15 19 22 18 9 2 1 1 0])

-(defn average [lst] (float (/ (reduce + lst) (count lst))))

+; Useful general functions

-; De-seasonalize time-series
-;
-; mu = np.average(Y1)
-; fix = np.linalg.inv(Xdt * Xd) * Xdt * Y1                                #Regress original timeseries on 11 monthly dummies and ones-vector (for constant)
-; Y1 = ((Y1 - Xd[:,1:12] * fix[1:12]) - fix[0]) + mu                      #Adjust the NDVI values by monthly averages
-
+(defn average
+  "average of a list"
+  [lst]
+  (float (/ (reduce + lst) (count lst))))

 (defn variance-matrix
   "construct a variance-covariance matrix from a given matrix X"
   [X]
   (i/solve (i/mmult (i/trans X) X)))
+
+(defn ones-column
+  "create a column of ones with length [x]"
+  [x]
+  (i/matrix (repeat x 1)))

-(defn make-matrix
-  [width height]
-  "Create a matrix (list of lists)"
-  (repeat width (repeat height 0)))
+; De-seasonalize time-series

-(defn matrix-map
-  [m func]
-  "Apply a function to every element in a matrix"
-  (map (fn [x] (map func x)) m))
-
-(def seasonal-vector (vec (conj (repeat 11 0) 1)))
+(defn seasonal-rows [n]
+  "lazy sequence of monthly dummy vectors"
+  (vec
+    (take n (partition 11 1 (cycle (cons 1 (repeat 11 0)))))))

 (defn seasonal-matrix
   "create a matrix of [num-months]x11 of monthly dummies, where
   [num-months] indicates the number of months in the time-series"
   [num-months]
-  )
-
-(def monthly-dummies
-  (i/bind-rows (repeat 11 0) (i/identity-matrix 11)))
+  (i/bind-columns (ones-column num-months)
+                  (seasonal-rows num-months)))

 (defn deseasonalize
-  "deseasonalize a time-series [ts] using monthly dummies."
+  "deseasonalize a time-series [ts] using monthly dummies. returns
+  a vector the same length of the original time-series, with desea-
+  sonalized values."
   [ts]
-  (let [avg (average ts)]
-  avg))
+  (let [avg-seq (repeat (count ts) (average ts))
+        X    (seasonal-matrix (count ts))
+        fix  (i/mmult (variance-matrix X) (i/trans X) ts)
+        adj  (i/mmult (i/sel X :except-cols 0) (i/sel fix :except-rows 0))
+        ats  (i/plus avg-seq (i/minus ts adj))]
+  ats))
+
+;
+(def plot1 (c/line-chart (range (count test-ts)) (deseasonalize test-ts)))
+; (c/add-lines plot1 (range 50) (range 50))

 ; WHOOPBANG

@@ -83,4 +91,15 @@
        (reduce min)))

 ; (def whizbang (ols-coeff test-ts))
-; juxt function ((juxt a b) x) -> ((a x) (b x))+; juxt function ((juxt a b) x) -> ((a x) (b x))
+
+
+; (defn make-matrix
+;   [width height]
+;   "Create a matrix (list of lists)"
+;   (repeat width (repeat height 0)))
+;
+; (defn matrix-map
+;   [m func]
+;   "Apply a function to every element in a matrix"
+;   (map (fn [x] (map func x)) m))


prevent Snoop ability from working with 0 counters

--- src/clj/game/cards-ice.clj
+++ src/clj/game/cards-ice.clj
@@ -685,7 +685,8 @@
                  :msg (msg "reveal " (join ", " (map :title (:hand runner))))}
                 {:label "Trace 3 - Place 1 power counter on Snoop"
                  :trace {:base 3 :msg "place 1 power counter on Snoop" :effect (effect (add-prop card :counter 1))}}
-                {:counter-cost 1 :label "Hosted power counter: Reveal all cards in Grip and trash 1 card"
+                {:req (req (> (get card :counter 0) 0))
+                 :counter-cost 1 :label "Hosted power counter: Reveal all cards in Grip and trash 1 card"
                  :msg (msg "look at all cards in Grip and trash " (:title target))
                  :choices (req (:hand runner)) :prompt "Choose a card to trash"
                  :effect (effect (trash target))}]}


issue #5 austin only for dev build

issue #5 austin only for dev build

--- src/clj/hit_wl/handler.clj
+++ src/clj/hit_wl/handler.clj
@@ -16,7 +16,6 @@
             [hiccup.element :as e]
             [clojure.edn :as edn]
             [cemerick.friend :as friend]
-            [cemerick.austin]
             [clojure.java.io :as io]
             (cemerick.friend [workflows :as workflows]
                              [credentials :as creds])


Barcodes that are not numbers are saved as nil

--- src/clj/proto/db/goods.clj
+++ src/clj/proto/db/goods.clj
@@ -14,10 +14,16 @@
 ;;; Persistence layer for the goods.
 (def goods-coll "goods")

+(defn- persist-good
+  [good]
+  (if (not (number? (:barcode good)))
+    (coll/insert-and-return db goods-coll (assoc good {:barcode nil}))
+    (coll/insert-and-return db goods-coll good)))
+
 (defn create! [good]
   (let [errors (validate-item good)]
     (if (empty? errors)
-      (coll/insert-and-return db goods-coll good)
+      (persist-good good)
       errors)))

 (defn all


update for cake face branch

update for cake face branch

--- src/clj/protobuf/tasks.clj
+++ src/clj/protobuf/tasks.clj
@@ -1,7 +1,7 @@
 (ns protobuf.tasks
   (:use cake cake.core cake.ant
         [cake.file :only [file]]
-        [cake.project :only [log]]
+        [bake.core :only [log]]
         [cake.utils :only [os-name prompt-read]]
         [cake.tasks.compile :only [compile-java]]
         [clojure.java.shell :only [sh]]


as-bytes doesnt exist

as-bytes doesnt exist

--- src/clj_kafka/producer.clj
+++ src/clj_kafka/producer.clj
@@ -2,7 +2,7 @@
   (:import [kafka.javaapi.producer Producer ProducerData]
            [kafka.producer ProducerConfig]
            [kafka.message Message])
-  (:use [clj-kafka.core :only (as-properties as-bytes)]))
+  (:use [clj-kafka.core :only (as-properties)]))

 (defn producer
   "Creates a Producer. m is the configuration


Docstring format.

Docstring format.

--- src/clj_ravendb/client.clj
+++ src/clj_ravendb/client.clj
@@ -14,14 +14,21 @@

   Optionally takes a map of options.

-  *`:replicated?` is used to find replicated endpoints
-  *`:master-only-writes?` is used to indicate that write operations only go to the master
-  *`:caching?` is used to indicate if documents should be cached locally
-  *`:enable-oauth?` is used to enable oauth with RavenDB
-  *`:oauth-url` is the oauth url to use
-  *`:oauth-expiry-seconds` is the number of seconds to use an oauth token before requesting a new one
-  *`:api-key` the api key to use for oauth autentication
-  *`:ssl-insecure? use insecure underlying http requests"
+  `:replicated?` is used to find replicated endpoints
+
+  `:master-only-writes?` is used to indicate that write operations only go to the master
+
+  `:caching?` is used to indicate if documents should be cached locally
+
+  `:enable-oauth?` is used to enable oauth with RavenDB
+
+  `:oauth-url` is the oauth url to use
+
+  `:oauth-expiry-seconds` is the number of seconds to use an oauth token before requesting a new one
+
+  `:api-key` the api key to use for oauth autentication
+
+  `:ssl-insecure? use insecure underlying http requests"
   ([url database]
    (client url database {}))
   ([url database {:keys [caching] :as options
@@ -41,6 +48,7 @@
   Optionally takes a map of options.

   `:request-builder` is a custom request builder fn.
+
   `:response-parser` is a customer response parser fn."
   [{:keys [load-documents] :as client} & args]
   (apply load-documents client args))
@@ -56,6 +64,7 @@
   Optionally takes a map of options.

   `:request-builder` is a custom request builder fn.
+
   `:response-parser` is a customer response parser fn."
   [{:keys [put-document!] :as client} & args]
   (apply put-document! client args))
@@ -74,9 +83,12 @@

   `:max-attempts` is the maximum number of times to try
   and hit a non stale index.
+
   `:wait` is the time interval to wait before trying to
   hit a non stale index.
-  `:request-builder` is a custom request builder fn.
+
+  `:request-builder` is a custom request builder fn.
+
   `:response-parser` is a customer response parser fn."
   [{:keys [query-index] :as client} & args]
   (apply query-index client args))
@@ -96,6 +108,7 @@
   Optionally takes a map of options.

   `:request-builder` is a custom request builder fn.
+
   `:response-parser` is a customer response parser fn."
   [{:keys [put-index!] :as client} & args]
   (apply put-index! client args))
@@ -110,6 +123,7 @@
   Optionally takes a map of options.

   `:request-builder` is a custom request builder fn.
+
   `:response-parser` is a customer response parser fn."
   [{:keys [delete-index!] :as client} & args]
   (apply delete-index! client args))
@@ -125,6 +139,7 @@
   Optionally takes a map of options.

   `:request-builder` is a custom request builder fn.
+
   `:response-parser` is a customer response parser fn."
   [{:keys [bulk-operations!] :as client} & args]
   (apply bulk-operations! client args))
@@ -170,6 +185,7 @@
   Optionally takes a map of options.

   `:request-builder` is a custom request builder fn.
+
   `:response-parser` is a customer response parser fn."
   [{:keys [stats] :as client} & args]
   (apply stats client args))
@@ -182,6 +198,7 @@
   Optionally takes a map of options.

   `:request-builder` is a custom request builder fn.
+
   `:response-parser` is a customer response parser fn."
   [{:keys [user-info] :as client} & args]
   (apply user-info client args))


Cleaning up styling on manage

Cleaning up styling on manage

--- src/cljs/bmihw/manage.cljs
+++ src/cljs/bmihw/manage.cljs
@@ -41,52 +41,60 @@
 (defn delete-page
   []
   (if-let [drunk (:drunk @current-event)]
-    [:div
-     [:p "NOPE!!!"]
-     [:p "Always do sober what you said you'd do drunk. That will teach you to keep your mouth shut."]
-     [:i "- Ernest Hemmingway"]
-     [:br]
-     [:br]
-     [:div [:a {:href "#/manage"
-                :on-click (fn [e]
-                            (reset! current-event nil)
-                            (session/put! :current-page #'manage-page))} "Back To Manage Submissions"]]]
-    [:div
-     [:p "Are you sure you want to hide the evidence?"]
-     [:a {:href "#/manage"
-                :on-click (fn [e]
-                            (let [id (:id @current-event)
-                                  ref (.child fb id)
-                                  clean-events (filter (fn [e] (not (= id (:id e))))  @events)]
-                              (.remove ref)
-                              (reset! events clean-events)
-                              (reset! current-event nil)
-                              (session/put! :current-page #'manage-page)))} "Yes, I'm a pussy."]
-     [:a {:href "#/manage"
-                :on-click (fn [e]
-                            (reset! current-event nil)
-                            (session/put! :current-page #'manage-page))} "Hell No!."]]))
+    [:div.panel.panel-default
+     [:div.panel-heading
+      [:h3.panel-title "NOPE!!!!"]]
+     [:div.panel-body
+	     [:p "Always do sober what you said you'd do drunk. That will teach you to keep your mouth shut."]
+	     [:i "- Ernest Hemmingway"]
+	     [:br]
+	     [:br]
+	     [:div.btn-group.btn-group-justified
+	      [:a.btn.btn-default {:href "#/manage"
+	           :on-click (fn [e]
+	                       (reset! current-event nil)
+	                       (session/put! :current-page #'manage-page))} "Back To Manage Submissions"]]]]
+    [:div.panel.panel-default
+     [:div.panel-heading
+      [:h3.panel-title "Really???"]]
+     [:div.panel-body
+	     [:p "Are you sure you want to hide the evidence?"]
+	     [:div.btn-group.btn-group-justified
+		     [:a.btn.btn-default {:href "#/manage"
+	           :on-click (fn [e]
+		                      (let [id (:id @current-event)
+		                            ref (.child fb id)
+		                            clean-events (filter (fn [e] (not (= id (:id e))))  @events)]
+		                        (.remove ref)
+		                        (reset! events clean-events)
+		                        (reset! current-event nil)
+		                        (session/put! :current-page #'manage-page)))} "Yes, I'm a pussy."]
+		     [:a.btn.btn-default {:href "#/manage"
+	           :on-click (fn [e]
+	                       (reset! current-event nil)
+	                       (session/put! :current-page #'manage-page))} "Hell No!."]]]]))

 (defn manage-page
   []
   (let [who (get-in auth ["uid"])]
 	  [:div.panel.panel-default
-     [:div.panel-heading "Manage Your Insults To Those Deserving Bastards!"]
-	   [:table#manage {:style {:width "100%"}}
+     [:div.panel-heading
+      [:h3.panel-title "Manage Your Insults To Those Deserving Bastards!"]]
+     [:div.panel-body
+	   [:table#manage.table {:style {:width "100%"}}
 	    [:tr
 	     [:th "Drunk"][:th "Event"][:th "Insult"][:th "Keyword"] [:td who]]
      (for [event @events]
        [:tr {:key (:id event)}
-        [:td (or (and (:drunk event) "Hell Yeah!") "Nope")]
+        [:td (or (and (:drunk event) "Yep") "Nope")]
         [:td (:target event)]
         [:td (:content event)]
         [:td (:keyword event)]
-        [:td [:input {:type "button"
-                      :value "Delete"
-                      :on-click (fn [e]
-                                  (reset! current-event event)
-                                  (session/put! :current-page #'delete-page))}]]])]]))
+        [:td [:button.btn.btn-default {:type "button"
+                                       :on-click (fn [e]
+                                                   (reset! current-event event)
+                                                   (session/put! :current-page #'delete-page))} "Delete"]]])]]]))

 (.on fb "child_added" handle-childsnapshot)


Clicking on shape plays root note of chord

--- src/cljs/omnibar/core.cljs
+++ src/cljs/omnibar/core.cljs
@@ -15,6 +15,14 @@
 (def vcf (hum/create-biquad-filter ctx))
 (def output (hum/create-gain ctx))

+
+(defn midi-to-freq [note-num]
+  (let [expt-numerator (- note-num 49)
+        expt-denominator 12
+        expt (/ expt-numerator expt-denominator)
+        multiplier (.pow js/Math 2 expt)
+        a 440]
+    (* multiplier a)))
                                         ; connect the VCO to the VCF and on to the output gain node
 (hum/connect vco vcf output)

@@ -100,30 +108,37 @@
 ;; All the points to make up a polygon
 (def hexagon-points "20.000,0.000 10.000,17.321 -10.000,17.321 -20.000,0.000 -10.000,-17.321 10.000,-17.321")

-(def hexagon
-  [:polygon {:transform "rotate(-30),scale(1.6,1.6)"
+(defn hexagon [freq]
+  [:polygon {:on-mouse-down #(hum/note-on output vco freq)
+             :on-mouse-up #(hum/note-off output)
+             :transform "rotate(-30),scale(1.6,1.6)"
              :fill "hsl(20, 10%, 95%)"
              :stroke "hsl(0, 0%, 70%)"
              :stroke-width "0.5"
              :points hexagon-points}] )

-(def circle
-  [:circle {:r "27" :stroke "black" :stroke-width "1" :fill "red"}] )
+(defn circle [freq]
+  [:circle {
+            :on-mouse-down #(hum/note-on output vco freq)
+            :on-mouse-up #(hum/note-off output)
+            :r "27" :stroke "black" :stroke-width "1" :fill "red"}] )
+

 (defn accordion-keyboard [shape note]
   (let [[x y] (:position note)
         title (:text note)
+        freq (midi-to-freq (first (:midi note)))
         y-start-pos 33
         x-start-pos 33
         hx   (+ y-start-pos (* x 48))
         hy   (+ x-start-pos (* x 27) (* y 55))]

     [:g {:class "tile" :transform (str "translate(" hy "," hx ")")}
-     shape
+     (if (= shape "circle") (circle freq) (hexagon freq))
      [:text {:y "0.4em"
+             :on-mouse-down #(hum/note-on output vco freq)
+             :on-mouse-up #(hum/note-off output)
              :transform "scale(.95)"
-             :on-mouse-down #(hum/note-on output vco 440)
-             :on-mouse-up #(hum/note-off output)
              :text-anchor "middle"}
       title]]))

@@ -157,8 +172,8 @@
    [:div [:a {:href "/about"} "go to about page"]]
    [:div
     [svg-piano-keyboard 150 800]
-    [svg-accordion [320 1250] hexagon]
-    [svg-accordion [320 1250] circle]
+    [svg-accordion [320 1250] "hexagon"]
+    [svg-accordion [320 1250] "circle"]
     [svg-inkscape-hexagons 250 500]]    ])

 (defn about-page []


Another (hot) fix on last-form

Another (hot) fix on last-form

--- src/cljs/replumb/repl.cljs
+++ src/cljs/replumb/repl.cljs
@@ -723,8 +723,9 @@

 (defn last-form
   [source]
-  (let [eof (js-obj)
-        read #(read-string {:eof eof} source)]
+  (let [rdr (rt/string-push-back-reader source)
+        eof (js-obj)
+        read #(read {:eof eof} rdr)]
     (loop [first-form (read)
            second-form (read)]
       (if (identical? eof second-form)


Add a total points counter and the ability to specify point creation qty

--- src/cljs_leaflet/core.cljs
+++ src/cljs_leaflet/core.cljs
@@ -40,8 +40,9 @@

 ;; define your app data so that it doesn't get over-written on reload
 (defonce app-state
-  (atom {:latest-id 0
-         :map-layers {} }))
+  (r/atom {:latest-id 0
+           :create-points-qty 10
+           :map-layers {} }))

 (defonce main-map
   (.setView (.map js/L "map") (clj->js (:center map-info)) (:zoom map-info)))
@@ -125,27 +126,31 @@
   ;; your application
   (swap! app-state update-in [:__figwheel_counter] inc))

-;; Button to generate 10 random points on the map
-(defn add-points-btn [num-points]
+;; Button to generate random points on the map
+(defn add-points-btn []
   [:div
    [:br]
    [:input {:type "button"
             :value "Add points to Map"
-            :on-click #(time (add-points! (generate-random-points num-points)))
-            }]])
+            :on-click #(time (add-points! (generate-random-points (:create-points-qty @app-state)))) }]])

-;; TODO: Automatically increment
-;(defn total-points-count []
-  ;[:div
-   ;[:b "Total Points:"] (count (:map-layers @app-state)) ])
+(defn point-qty-input [ratom]
+  [:input {:type "number"
+           :value (:create-points-qty @ratom)
+           :on-change #(swap! ratom assoc :create-points-qty (-> % .-target .-value js/parseInt)) }])
+
+(defn total-points-count []
+  [:div
+   [:b "Add points: " (point-qty-input app-state)]
+   [:br]
+   [:b "Total Points: "] (count (:map-layers @app-state)) ])

 (defn render-page []
   (r/render-component
     [:div
-     [add-points-btn 50]
+     [add-points-btn]
      [:br]
-     ;[total-points-count]
-     ]
+     [total-points-count] ]
     (.getElementById js/document "app"))
   (setup-map! main-map))


implement cached fetch (synchronous)

implement cached fetch (synchronous)

--- src/appengine_magic/services/urlfetch.clj
+++ src/appengine_magic/services/urlfetch.clj
@@ -5,7 +5,8 @@
             FetchOptions$Builder
             HTTPRequest
             HTTPMethod])
-  (:require [clojure.contrib.string :as string]))
+  (:require [clojure.contrib.string :as string]
+            [appengine-magic.services.memcache :as memcache]))

 (defonce *urlfetch-service* (atom nil))

@@ -13,6 +14,8 @@
   (do (when (nil? @*urlfetch-service*)
 	(reset! *urlfetch-service* (URLFetchServiceFactory/getURLFetchService)))
       @*urlfetch-service*))
+
+(defn- urlify [url] (if (string? url) (java.net.URL. url) url))

 (defrecord HTTPResponse [content
 			 final-url
@@ -55,7 +58,7 @@
       (.followRedirects fetch-options)
       (.doNotFollowRedirects fetch-options))
     (.setDeadline fetch-options deadline)
-    (let [url-obj    (if (string? url) (java.net.URL. url) url)
+    (let [url-obj    (urlify url)
           method-obj (method {:delete HTTPMethod/DELETE
                               :get    HTTPMethod/GET
                               :head   HTTPMethod/HEAD
@@ -101,3 +104,36 @@
       (isCancelled [_] (.isCancelled f))
       (isDone [_] (.isDone f))
       (cancel [_ interrupt?] (.cancel f interrupt?)))))
+
+(def *memcache-namespace* "appengine-magic.services.urlfetch")
+(def *memory-cache* (atom {}))
+(defn cache-response [url response]
+  ;; save unnecessary memcache calls by checking for relevant headers
+  (if (or (:Last-Modified (:headers response))
+          (:ETag (:headers response)))
+    (do (swap! assoc url response)
+        (memcache/put! url response :namespace *memcache-namespace*)
+        response)))
+(defn uncache-response [url]
+  (if-let [response (@*memory-cache* url)]
+    response
+    (memcache/get url :namespace *memcache-namespace*)))
+
+(defn memcached-fetch
+  "Like fetch, but caches its results in memcache and uses ETag or
+   Last-Modified headers to avoid doing full-fetches when possible."
+  [url & opts]
+  (let [request (apply make-request url opts)
+        url     (.getURL request)]
+    (if-let [old-response (uncache-response url)]
+      (do
+        (if-let [etag (:ETag (:headers old-response))]
+          (.setHeader request "If-None-Match" etag)
+          (if-let [last-modified (:Last-Modified (:headers old-response))]
+            (.setHeader request "If-Modified-Since" last-modified)))
+        (let [response (parse-response (.fetch (get-urlfetch-service) request))]
+          (if (= 304 (:response-code response))
+            old-response
+            (cache-response url response))))
+      ;; if no cache, do a regular fetch
+      (cache-response (apply fetch url opts)))))


Re-added the body index so that we--er--search it.  Oops.

--- src/net/dishevelled/mailindex.clj
+++ src/net/dishevelled/mailindex.clj
@@ -62,6 +62,7 @@
       "subject" {:pattern "Subject: " :boost 5}
       "to"      {:pattern "To: "      :boost 2}
       "from"    {:pattern "From: "    :boost 3}
+      "body"    {:pattern nil}
       })


small-fix

small-fix

--- src/cljs/salava/badge/ui/endorsement.cljs
+++ src/cljs/salava/badge/ui/endorsement.cljs
@@ -21,7 +21,7 @@

     [:div {:style {:margin-bottom "20px"}}
      [:h5
-      (when (:image_file issuer) [:img {:src (str "/" (:image_file issuer)) :style {:width "65px" :height "auto" :padding "7px"}}])
+      (when (:image_file issuer) [:img {:src (str "/" (:image_file issuer)) :style {:width "55px" :height "auto" :padding "7px"}}])
       [:a {:href "#"
            :on-click #(do (.preventDefault %) (mo/set-new-view [:badge :issuer] (:id issuer)))
            } (:name issuer)]
@@ -166,7 +166,8 @@

 (defn init-editor [element-id value]
   (reset! editor (js/SimpleMDE. (clj->js {:element (.getElementById js/document element-id)
-                                          :toolbar simplemde-toolbar})))
+                                          :toolbar simplemde-toolbar
+                                          :spellChecker false})))
   (.value @editor @value)
   (js/setTimeout (fn [] (.value @editor @value)) 200)
   (.codemirror.on @editor "change" (fn [] (reset! value (.value @editor)))))


adding default configuration for log and tracking

--- core/src/samsara_core/main.clj
+++ core/src/samsara_core/main.clj
@@ -27,7 +27,15 @@
     ;; and date will appened eg: events-2015-05-27
     :strategy :single
     :base-index "events"
-    :event-type "events"}})
+    :event-type "events"}
+
+   ;; metrics trackings
+   :tracking
+   {:enabled false :type :console}
+
+   ;; logging
+   :log
+   {:timestamp-pattern "yyyy-MM-dd HH:mm:ss.SSS zzz"}})


Remove unnecessary try/catch

Remove unnecessary try/catch

This was required before the aleph upgrade, as close was not idempotent.

--- app/src/edge/httpd.clj
+++ app/src/edge/httpd.clj
@@ -37,10 +37,10 @@
                                                        :ctx ctx}))}}})]

     ["" (assoc (yada/redirect :edge.resources/index) :id :edge.resources/content)]
-    ["public/" (assoc (new-classpath-resource "public") :id :edge.resources/static)]
+    ["public/" (assoc (new-classpath-resource "public") :id :edge.resources/static)]]])

     ;; Add some pairs (as vectors) here. First item is the path, second is the handler.
-    ]])
+

 (defn routes
   "Create the URI route structure for our application."
@@ -124,7 +124,4 @@

 (defmethod ig/halt-key! :edge/httpd [_ {:keys [listener]}]
   (when-let [close (:close listener)]
-    (try
-      (close)
-      (catch Exception e
-        (log/error e "Failed to properly close http listener")))))
+    (close)))


Get rid of `:refer :all` in frontend-dev ns

--- dev-src/clj/comic_reader/frontend_dev.clj
+++ dev-src/clj/comic_reader/frontend_dev.clj
@@ -2,7 +2,7 @@
   (:require [clojure.java.browse :refer [browse-url]]
             [clojure.repl :refer :all]
             [clojure.tools.namespace.repl :refer [refresh]]
-            [comic-reader.system :refer [go start stop]]
+            [comic-reader.system :as system]
             [figwheel-sidecar.repl-api :refer :all]))

 (defn- cwd []
@@ -37,7 +37,7 @@
                   :asset-path "js/compiled/devcards_out"}}]})

 (defn start-dev! [& args]
-  (apply go args)
+  (apply system/go args)
   (start-figwheel! figwheel-config)
   (start-autobuild)
   (browse-url "http://localhost:10555/devcards"))
@@ -45,7 +45,7 @@
 (defn stop-dev! []
   (stop-autobuild)
   (stop-figwheel!)
-  (stop))
+  (system/stop))

 (defn reset []
   (stop-dev!)


CMR-2146: Reverted inadvertent changed to tag_save_test

--- metadata-db-app/int_test/cmr/metadata_db/int_test/concepts/tag_save_test.clj
+++ metadata-db-app/int_test/cmr/metadata_db/int_test/concepts/tag_save_test.clj
@@ -34,128 +34,52 @@
           422
           ["Tag could not be associated with provider [REG_PROV]. Tags are system level entities."])))

-(deftest save-group-with-concept-id
-  (doseq [provider-id ["REG_PROV" "SMAL_PROV1"]]
-    (let [serv-concept-id (str "S10-" provider-id)
-          group (util/group-concept provider-id 1 {:concept-id serv-concept-id})
-          {:keys [status revision-id concept-id]} (util/save-concept group)]
+(deftest save-tag-with-concept-id
+  (testing "with concept-id"
+    ;; valid save with concept-id
+    (let [tag (util/tag-concept 1 {:concept-id "T10-CMR"})
+          {:keys [status revision-id concept-id]} (util/save-concept tag)]
       (is (= 201 status))
       (is (= revision-id 1))
-      (util/verify-concept-was-saved (assoc group :revision-id revision-id :concept-id concept-id))
+      (util/verify-concept-was-saved
+        (assoc tag :revision-id revision-id :provider-id "CMR"))

-      (testing "with incorrect native id"
-        (let [response (util/save-concept (assoc group :native-id "foo"))]
-          (is (= {:status 409,
-                  :errors [(msg/concept-exists-with-different-id
-                             serv-concept-id (:native-id group)
-                             serv-concept-id "foo"
-                             :group provider-id) ]}
-                 (select-keys response [:status :errors])))))
+      (testing "Get Tag Concept Id"
+        (is (= {:status 200 :concept-id concept-id :errors nil}
+               (util/get-concept-id :tag "CMR" (:native-id tag)))))

-      (testing "with incorrect concept id"
-        (let [other-serv-concept-id (str "S11-" provider-id)
-              response (util/save-concept (assoc group :concept-id other-serv-concept-id))]
-          (is (= {:status 409,
-                  :errors [(msg/concept-exists-with-different-id
-                             serv-concept-id (:native-id group)
-                             other-serv-concept-id (:native-id group)
-                             :group provider-id) ]}
-                 (select-keys response [:status :errors])))))
+      (testing "new revision"
+        (let [{:keys [status revision-id]} (util/save-concept (assoc tag :revision-id 2))]
+          (is (= 201 status))
+          (is (= revision-id 2))
+          (util/verify-concept-was-saved
+            (assoc tag :revision-id revision-id :provider-id "CMR"))))

-      (testing "with incorrect concept id matching another concept"
-        (let [other-serv-concept-id (str "S11-" provider-id)
-              group2 (util/group-concept provider-id 2
-                                             {:concept-id other-serv-concept-id
-                                              :native-id "native2"})
-              _ (is (= 201 (:status (util/save-concept group2))))
-              response (util/save-concept (assoc group :concept-id other-serv-concept-id))]
-          (is (= {:status 409,
-                  :errors [(msg/concept-exists-with-different-id
-                             serv-concept-id (:native-id group)
-                             other-serv-concept-id (:native-id group)
-                             :group provider-id) ]}
-                 (select-keys response [:status :errors]))))))))
+      ;; error cases
+      (are2 [test-tag exp-status exp-errors]
+            (let [{:keys [status errors]} (util/save-concept test-tag)]
+              (is (= exp-status status))
+              (is (= (set exp-errors) (set errors))))

-(deftest save-group-with-revision-date-test
-  (doseq [provider-id ["REG_PROV" "SMAL_PROV1"]]
-    (let [concept (util/group-concept provider-id 1 {:revision-date (t/date-time 2001 1 1 12 12 14)})
-          {:keys [status revision-id concept-id]} (util/save-concept concept)]
-      (is (= 201 status))
-      (is (= revision-id 1))
-      (let [retrieved-concept (util/get-concept-by-id-and-revision concept-id revision-id)]
-        (is (= (:revision-date concept) (:revision-date (:concept retrieved-concept))))))))
+            "conflicting native-id"
+            (assoc tag :native-id "foo")
+            409
+            [(str "A concept with concept-id [T10-CMR] and native-id [namespace1" (char 29)
+                  "value1] already exists for concept-type [:tag] provider-id [CMR]. The given "
+                  "concept-id [T10-CMR] and native-id [foo] would conflict with that one.")]

-(deftest save-group-with-bad-revision-date-test
-  (doseq [provider-id ["REG_PROV" "SMAL_PROV1"]]
-    (let [concept (util/group-concept provider-id 1 {:revision-date "foo"})
-          {:keys [status errors]} (util/save-concept concept)]
-      (is (= 422 status))
-      (is (= ["[foo] is not a valid datetime"] errors)))))

-(deftest save-group-with-same-native-id-test
-  (testing "Save groups with the same native-id for two small providers is OK"
-    (let [serv1 (util/create-and-save-group "SMAL_PROV1" 1 1 {:native-id "foo"})
-          serv2 (util/create-and-save-group "SMAL_PROV2" 2 1 {:native-id "foo"})
-          [serv1-concept-id serv2-concept-id] (map :concept-id [serv1 serv2])]
-      (util/verify-concept-was-saved serv1)
-      (util/verify-concept-was-saved serv2)
-      (is (not= serv1-concept-id serv2-concept-id)))))
+            "conflicting concept-id"
+            (assoc tag :concept-id "T11-CMR")
+            409
+            [(str "A concept with concept-id [T10-CMR] and native-id [namespace1" (char 29)
+                  "value1] already exists for concept-type [:tag] provider-id [CMR]. The given "
+                  "concept-id [T11-CMR] and native-id [namespace1" (char 29) "value1] "
+                  "would conflict with that one.")]

-(deftest save-group-test-with-proper-revision-id-test
-  (doseq [provider-id ["REG_PROV" "SMAL_PROV1"]]
-    (let [concept (util/group-concept provider-id 1)]
-      ;; save the concept once
-      (let [{:keys [revision-id concept-id]} (util/save-concept concept)
-            new-revision-id (inc revision-id)
-            revision-date-0 (get-in (util/get-concept-by-id-and-revision concept-id revision-id)
-                                    [:concept :revision-date])]
-        ;; save it again with a valid revision-id
-        (let [updated-concept (assoc concept :revision-id new-revision-id :concept-id concept-id)
-              {:keys [status revision-id]} (util/save-concept updated-concept)
-              revision-date-1 (get-in (util/get-concept-by-id-and-revision concept-id revision-id)
-                                      [:concept :revision-date])]
-          (is (= 201 status))
-          (is (= revision-id new-revision-id))
-          (is (t/after? revision-date-1 revision-date-0))
-          (util/verify-concept-was-saved updated-concept))))))
+            "incorrect concept-id prefix"
+            (assoc (util/tag-concept 2) :concept-id "G10-CMR")
+            422
+            [(str "Concept-id [G10-CMR] for concept does not match provider-id [CMR] or "
+                  "concept-type [:tag].")]))))

-(deftest save-group-with-skipped-revisions-test
-  (doseq [provider-id ["REG_PROV" "SMAL_PROV1"]]
-    (let [concept (util/group-concept provider-id 1)
-          {:keys [concept-id]} (util/save-concept concept)
-          concept-with-skipped-revisions (assoc concept :concept-id concept-id :revision-id 100)
-          {:keys [status revision-id]} (util/save-concept concept-with-skipped-revisions)
-          {retrieved-concept :concept} (util/get-concept-by-id concept-id)]
-      (is (= 201 status))
-      (is (= 100 revision-id (:revision-id retrieved-concept))))))
-
-(deftest auto-increment-of-revision-id-works-with-skipped-revisions-test
-  (doseq [provider-id ["REG_PROV" "SMAL_PROV1"]]
-    (let [concept (util/group-concept provider-id 1)
-          {:keys [concept-id]} (util/save-concept concept)
-          concept-with-concept-id (assoc concept :concept-id concept-id)
-          _ (util/save-concept (assoc concept-with-concept-id :revision-id 100))
-          {:keys [status revision-id]} (util/save-concept concept-with-concept-id)
-          {retrieved-concept :concept} (util/get-concept-by-id concept-id)]
-      (is (= 201 status))
-      (is (= 101 revision-id (:revision-id retrieved-concept))))))
-
-(deftest save-group-with-low-revision-test
-  (doseq [provider-id ["REG_PROV" "SMAL_PROV1"]]
-    (let [concept (util/group-concept provider-id 1)
-          {:keys [concept-id]} (util/save-concept concept)
-          concept-with-bad-revision (assoc concept :concept-id concept-id :revision-id 0)
-          {:keys [status revision-id]} (util/save-concept concept-with-bad-revision)]
-      (is (= 409 status))
-      (is (nil? revision-id)))))
-
-(deftest save-group-with-missing-required-field
-  (doseq [provider-id ["REG_PROV" "SMAL_PROV1"]]
-    (let [concept (util/group-concept provider-id 1)]
-      (are [field] (let [{:keys [status errors]} (util/save-concept (dissoc concept field))]
-                     (and (= 422 status)
-                          (re-find (re-pattern (name field)) (first errors))))
-           :concept-type
-           :provider-id
-           :native-id
-           :extra-fields))))


[#429] Fixed string format call

[#429] Fixed string format call

--- backend/src/akvo/lumen/transformation/engine.clj
+++ backend/src/akvo/lumen/transformation/engine.clj
@@ -298,7 +298,7 @@
                                "columnName" column-name})})
     (catch Exception e
       {:success? false
-       :message ("Failed to transform: %s" (.getMessage e))})))
+       :message (format "Failed to transform: %s" (.getMessage e))})))

 (comment