remove support for servlet apps

remove support for servlet apps

* new get-target-dir function
* switch from pre/post wrap style to explicit middleware and handler
* remove dead code
* add some new tasks: keep-config, build-sift, config-service
* renames: earxml -> config-app
* etc.

Signed-off-by: Gregg Reynolds <d0f77bc71a9867acdcb4f62f012b858edad79160@norc.org>

--- src/migae/boot_gae.clj
+++ src/migae/boot_gae.clj
@@ -24,10 +24,6 @@
 (def appengine-edn "appengine.edn")
 (def appstats-edn "appstats.edn")

-;; for microservices app:
-(def services-edn "services.edn")
-
-
 (def meta-inf-dir "META-INF")
 (def web-inf-dir "WEB-INF")
   ;; (let [mod (-> (boot/get-env) :gae :module :name)]
@@ -44,6 +40,37 @@
        .getMainAttributes
        (map (fn [[k v]] [(str k) v]))
        (into {})))
+
+(defn get-target-dir
+  [fileset servlet]
+  (if servlet
+    "target"
+    (let [boot-config-edn-files (->> (boot/input-files fileset)
+                                     (boot/by-name [boot-config-edn]))
+          boot-config-edn-f (condp = (count boot-config-edn-files)
+                              0 nil
+                              1 (first boot-config-edn-files)  ;; this is a boot.tmpdir.TmpFile
+                              (throw (Exception.
+                                      (str "only one _boot_config.edn file allowed, found "
+                                           (count boot-config-edn-files)))))
+          boot-config-edn-map (if boot-config-edn-f
+                                (-> (boot/tmp-file boot-config-edn-f) slurp read-string)
+                                nil)]
+      (if boot-config-edn-map
+        (str "target/" (-> boot-config-edn-map :module :name))
+        (let [appengine-edn-fs (->> fileset
+                                    boot/input-files
+                                    (boot/by-name [appengine-edn]))
+
+              appengine-edn-f (condp = (count appengine-edn-fs)
+                                0 (throw (Exception. appengine-edn " file not found"))
+                                1 (first appengine-edn-fs)
+                                (throw (Exception. (str "Only one " appengine-edn " file allowed"))))
+
+              appengine-config-map (-> (boot/tmp-file appengine-edn-f) slurp read-string)]
+          (if servlet "target" (if (-> appengine-config-map :services)
+                                 "target/default"
+                                 (str "target/" (-> appengine-config-map :module :name)))))))))

 (defn expand-home [s]
   (if (or (.startsWith s "~") (.startsWith s "$HOME"))
@@ -275,10 +302,11 @@
    d dir DIR str "output dir"
    k keep bool "keep intermediate .clj files"
    m module MODULE str "module dirpath"
-   s servlet-app SERVLET bool "generate config for servlet-app instead of service component"
+   s servlet bool "generate config for servlet app instead of service component DEPRECATED"
    v verbose bool "Print trace messages."]
   ;; boolean hasUppercase = !password.equals(password.toLowerCase());
-  (let [tmp-dir (boot/tmp-dir!)
+  (let [workspace (boot/tmp-dir!)
+        config-workspace (boot/tmp-dir!)
         prev-pre (atom nil)
         dir (if dir dir web-inf-dir)]
     (boot/with-pre-wrap fileset
@@ -307,47 +335,64 @@

              appengine-config-map (-> (boot/tmp-file appengine-edn-f) slurp read-string)

+             module (if servlet "default"
+                        (if (-> appengine-config-map :services)
+                          "default"
+                          (if (-> appengine-config-map :module)
+                            (if (-> appengine-config-map :module :default)
+                              "default"
+                              (if-let [m (-> appengine-config-map :module :name)]
+                                m
+                                (throw (Exception.
+                                        (str ":module :name required in "
+                                             appengine-edn)))))
+                            (throw (Exception.
+                                    (str ":module clause required in"
+                                         appengine-edn))))))
+
              appengine-config-map (assoc-in appengine-config-map
-                                            [:module :name]
-                                            (if servlet-app
-                                              "default"
-                                              (if (-> appengine-config-map :module)
-                                                (if (-> appengine-config-map :module :default)
-                                                  "default"
-                                                  (if-let [m (-> appengine-config-map :module :name)]
-                                                    m
-                                                    (throw (Exception.
-                                                            (str ":module :name required in " appengine-edn)))))
-                                                (throw (Exception. (str ":module clause required in" appengine-edn))))))
-
-             app-id (name (-> (boot/get-env) :gae :app :id))
-
-              version (-> appengine-config-map :module :version)
-              _ (if version
-                  (if (not= version  (.toLowerCase version))
-                    (throw (Exception. (str "Upper-case not allowed in GAE version string: " version))))
-                  (throw (Exception. ":module :version string required in " appengine-edn)))
-
-              appengine-config-map (assoc
-                                    (-> appengine-config-map
-                                        (assoc-in [:system-properties]
-                                                  (into
-                                                   (:system-properties appengine-config-map)
-                                                   {:props (:system-properties boot-config-edn-map)})))
-                                    :app-id app-id)
+                                            [:module :name] module)
+
+             app-id (:app-id appengine-config-map)
+
+             version (-> appengine-config-map :module :version)
+             _ (if version
+                 (if (not= version  (.toLowerCase version))
+                   (throw (Exception. (str "Upper-case not allowed in GAE version string: " version))))
+                 (throw (Exception. ":module :version string required in " appengine-edn)))
+
+             appengine-config-map (assoc
+                                   (-> appengine-config-map
+                                       (assoc-in [:system-properties]
+                                                 (into
+                                                  (:system-properties appengine-config-map)
+                                                  {:props (:system-properties boot-config-edn-map)})))
+                                   :app-id app-id)
+
+             ;; inject appengine map into master map
+             master-config (conj boot-config-edn-map appengine-config-map)
+             master-config (with-out-str (pp/pprint master-config))
+             boot-config-edn-out-file (io/file config-workspace
+                                               (if (instance? boot.tmpdir.TmpFile boot-config-edn-f)
+                                                 (boot/tmp-path boot-config-edn-f)
+                                                 boot-config-edn-f))
              ]
-
-         (println "appengine-config-map 2: " appengine-config-map)
+         ;;(println "master config: " master-config)
+         ;;(println "appengine-config-map 2: " appengine-config-map)
          (let [content (stencil/render-file
                         "migae/templates/xml.appengine-web.mustache"
                         appengine-config-map)]
            ;;(if verbose (println content))
            (if verbose (util/info "Configuring appengine-web.xml\n"))
            (let [xml-out-path (str dir "/appengine-web.xml")
-                 xml-out-file (doto (io/file tmp-dir xml-out-path) io/make-parents)
+                 xml-out-file (doto (io/file workspace xml-out-path) io/make-parents)
                  ]
+             (spit boot-config-edn-out-file master-config)
              (spit xml-out-file content))))
-    (-> fileset (boot/add-resource tmp-dir) boot/commit!))))
+    (-> fileset
+        (boot/add-source config-workspace)
+        (boot/add-resource workspace)
+        boot/commit!))))

 ;; (defn- add-appstats!
 ;;   [reloader-ns urls in-file out-file]
@@ -389,7 +434,7 @@
              boot-config-edn-map (if (instance? boot.tmpdir.TmpFile boot-config-edn-f)
                                    (-> (boot/tmp-file boot-config-edn-f) slurp read-string)
                                    {})]
-         (println "boot-config-edn-map: " boot-config-edn-map)
+         ;; (println "boot-config-edn-map: " boot-config-edn-map)

          (if (:appstats boot-config-edn-map)
            fileset
@@ -464,11 +509,17 @@
      (target)
      )))

+(boot/deftask build-sift
+  []
+  (comp
+   (builtin/sift :move {#"(.*clj$)" (str classes-dir "/$1")})
+   (builtin/sift :move {#"(.*\.class$)" (str classes-dir "/$1")})))
+
 (boot/deftask build
   "Configure and build servlet or service app"
   [k keep bool "keep intermediate .clj and .edn files"
    p prod bool "production build, without reloader"
-   s service bool "build a service"
+   s servlet bool "build a servlet-based app DEPRECATED"
    v verbose bool "verbose"]
   (let [keep (or keep false)
         verbose (or verbose false)]
@@ -478,7 +529,7 @@
           (libs :verbose verbose)
           (appstats :verbose verbose)
           ;; (builtin/javac :options ["-source" "1.7", "-target" "1.7"])
-          (if prod identity (reloader :keep keep :service service :verbose verbose))
+          (if prod identity (reloader :keep keep :servlet servlet :verbose verbose))
           (filters :keep keep :verbose verbose)
           (servlets :keep keep :verbose verbose)
           (logging :verbose verbose)
@@ -486,12 +537,12 @@
           (appengine :verbose verbose)
           (builtin/sift :move {#"(.*clj$)" (str classes-dir "/$1")})
           (builtin/sift :move {#"(.*\.class$)" (str classes-dir "/$1")})
-          (if service
+          (if servlet
+            identity
             (comp
              (builtin/pom)
-             (builtin/jar))
-            identity)
-          (target :service service :verbose verbose)
+             (builtin/jar)))
+          (target :servlet servlet :verbose verbose)
           #_(builtin/sift :include #{(re-pattern (str mod ".*jar"))})
           #_(builtin/install)
           #_(target :verbose verbose)
@@ -499,25 +550,6 @@
           ;; FIXME: use cache instead?
           ;; (builtin/target :dir #{(str "target/" mod)})
           )))
-
-(boot/deftask target
-  "target, using module name"
-  [C no-clean bool "Don't clean target before writing project files"
-   m monitor bool "monitoring - target service assembly"
-   s service bool "building as service"
-   v verbose bool "verbose"]
-  (let [mod      (-> (boot/get-env) :gae :module :name)
-        app-dir  (-> (boot/get-env) :gae :app :dir)
-        dir      (if monitor
-                   (str app-dir "/target/" mod)
-                   (if service (str "target/" mod)
-                       "target"))]
-    (if service
-      (if (not (and mod app-dir))
-        (throw (Exception. "For service targets, both :name and :app :dir must be specified in :gae map of build.boot"))))
-    (println "TARGET DIR: " dir)
-    (builtin/target :dir #{dir}
-                    :no-clean (or no-clean false))))

 (boot/deftask cache
   "control cache: retrieve, save, clean"
@@ -553,58 +585,72 @@
                 fileset)
               fileset)))))))

-(boot/deftask earxml
+(boot/deftask config-service
+  "generate xml config files for service war"
+  [d dir DIR str "output dir"
+   c config-syms SYMS #{sym} "namespaced symbols bound to meta-config data"
+   k keep bool "keep intermediate .clj files"
+   v verbose bool "Print trace messages."]
+  (comp
+   (webxml :verbose verbose)
+   (appengine :verbose verbose)))
+
+(boot/deftask service-app
   "generate xml config files for microservices app"
   [d dir DIR str "output dir"
    c config-syms SYMS #{sym} "namespaced symbols bound to meta-config data"
    k keep bool "keep intermediate .clj files"
    v verbose bool "Print trace messages."]
-  (let [edn-tmp (boot/tmp-dir!)
+  (let [workspace (boot/tmp-dir!)
         prev-pre (atom nil)
         odir (if dir dir meta-inf-dir)]
-    ;; FIXME create services.edn map from :checkouts
-    (boot/with-pre-wrap fileset
-      (let [services-fs (->> (boot/fileset-diff @prev-pre fileset)
-                                boot/input-files
-                                (boot/by-re [(re-pattern (str services-edn "$"))]))]
-            ;; (boot/by-name [services]))]
-        (if (> (count services-fs) 1) (throw (Exception. "only one services.edn file allowed")))
-        (if (= (count services-fs) 0) (throw (Exception. "services.edn file not found")))
-
-        (let [services-f (first services-fs)
-              services-cfg (-> (boot/tmp-file services-f) slurp read-string)
-              path     (boot/tmp-path services-f)
-              in-file  (boot/tmp-file services-f)
-              out-file (io/file edn-tmp path)]
-          (let [appengine-application-cfg (stencil/render-file
-                                           "migae/templates/xml.appengine-application.mustache"
-                                           services-cfg)
-                application-cfg (stencil/render-file
-                                 "migae/templates/xml.application.mustache"
-                                 services-cfg)
-                manifest-cfg (stencil/render-file
-                              "migae/templates/MANIFEST.MF.mustache"
-                              services-cfg)]
-            (if verbose
-              (do (println appengine-application-cfg)
-                  (println application-cfg)
-                  (println manifest-cfg)))
-            (let [appengine-application-out-path (str odir "/appengine-application.xml")
-                  appengine-application-out-file (doto
-                                                     (io/file edn-tmp appengine-application-out-path)
-                                                   io/make-parents)
-                  application-out-path (str odir "/application.xml")
-                  application-out-file (doto (io/file edn-tmp application-out-path)
-                                         io/make-parents)
-                  manifest-out-path (str odir "/MANIFEST.MF")
-                  manifest-out-file (doto (io/file edn-tmp manifest-out-path)
-                                      io/make-parents)
-                  ]
-              (util/info "Configuring microservices app\n")
-              (spit appengine-application-out-file appengine-application-cfg)
-              (spit application-out-file application-cfg)
-              (spit manifest-out-file manifest-cfg)))))
-      (-> fileset (boot/add-resource edn-tmp) boot/commit!))))
+    (boot/with-pre-wrap [fileset]
+      (let [appengine-config-edn-files (->> (boot/fileset-diff @prev-pre fileset)
+                                            boot/input-files
+                                            (boot/by-re [(re-pattern (str appengine-edn "$"))]))
+            ;; (if (> (count services-fs) 1) (throw (Exception. "Only one " appengine-edn " file allowed")))
+            ;; (if (= (count services-fs) 0)
+            appengine-config-edn-f (condp = (count appengine-config-edn-files)
+                                     0 (throw (Exception. appengine-edn " file not found"))
+                                     1 (first appengine-config-edn-files)
+                                     (throw (Exception.
+                                             (str "Only one " appengine-edn " file allowed; found "
+                                                  (count appengine-config-edn-files)))))
+
+            appengine-cfg (-> (boot/tmp-file appengine-config-edn-f) slurp read-string)
+            ;; path     (boot/tmp-path appengine-config-edn-f)
+            ;; in-file  (boot/tmp-file appengine-config-edn-f)
+            ;; out-file (io/file workspace path)
+            appengine-application-cfg (stencil/render-file
+                                       "migae/templates/appengine-application.mustache"
+                                       appengine-cfg)
+            services-app-cfg (stencil/render-file
+                             "migae/templates/services-app.mustache"
+                             (-> appengine-cfg
+                                 (assoc-in [:services]
+                                           (conj (seq (:services appengine-cfg))
+                                                 {:name "default"}))))
+
+            manifest-cfg (stencil/render-file
+                          "migae/templates/MANIFEST.MF.mustache"
+                          appengine-cfg)]
+        (if verbose
+          (do (println appengine-application-cfg)
+              (println services-app-cfg)
+              (println manifest-cfg)))
+        (let [appengine-application-out-path (str odir "/appengine-application.xml")
+              appengine-application-out-file (doto (io/file workspace appengine-application-out-path)
+                                               io/make-parents)
+              services-app-out-path (str odir "/application.xml")
+              services-app-out-file (doto (io/file workspace services-app-out-path) io/make-parents)
+              manifest-out-path (str odir "/MANIFEST.MF")
+              manifest-out-file (doto (io/file workspace manifest-out-path) io/make-parents)
+              ]
+          (if verbose (util/info "Configuring services application\n"))
+          (spit appengine-application-out-file appengine-application-cfg)
+          (spit services-app-out-file services-app-cfg)
+          (spit manifest-out-file manifest-cfg)))
+      (-> fileset (boot/add-resource workspace) boot/commit!))))

 (boot/deftask deploy
   "Installs a new version of the application onto the server, as the default version for end users."
@@ -644,37 +690,44 @@
   (if verbose (println "TASK: boot-gae/deploy"))
   (validate-tools-api-jar)
   ;; (println "PARAMS: " *opts*)
-  (let [mod      (-> (boot/get-env) :gae :module :name)
-        app-dir  (-> (boot/get-env) :gae :app :dir)
-        ;; dir      (if service (str "target/" mod) "target")
-        opts (merge {:sdk-root (:sdk-root config-map)
-                     ;; :use-java7 true
-                     :build-dir (str "target/" (if service mod))}
-                                  ;; build-dir build-dir (gae-app-dir))} ;; (:build-dir config-map)}
-                    *opts*)
-        _ (println "OPTS: " opts)
-        params (into [] (for [[k v] (remove (comp nil? second)
-                                            (dissoc opts :build-dir :verbose :sdk-help))]
-                          (str "--" (str/replace (name k) #"-" "_")
-                               (if (not (instance? Boolean v)) (str "=" v)))))
-        params (if (:sdk-help *opts*)
-                 ["help" "update"]
-                 (conj params "update" (:build-dir opts)))
-        params (into-array String params)
-        ;; ClassLoader classLoader = Thread.currentThread().contextClassLoader
-        class-loader (-> (Thread/currentThread) (.getContextClassLoader))
-        cl (.getParent class-loader)
-        app-cfg (Class/forName appcfg-class true class-loader)]
-
-  ;; def appCfg = classLoader.loadClass(APPENGINE_TOOLS_MAIN)
-  ;; appCfg.main(params as String[])
-    (def method (first (filter #(= (. % getName) "main") (. app-cfg getMethods))))
-    (def invoke-args (into-array Object [params]))
-    (if verbose ;; (or (:verbose *opts*) (:verbose config-map))
-      (do (println "CMD: AppCfg")
-          (doseq [arg params]
-            (println "\t" arg))))
-    (. method invoke nil invoke-args)))
+
+  (fn middleware [next-handler]
+    (fn handler [fileset]
+      (let [target-dir (get-target-dir fileset false)
+            mod      (-> (boot/get-env) :gae :module :name)
+            app-dir  (-> (boot/get-env) :gae :app :dir)
+
+            opts (merge {:sdk-root (:sdk-root config-map)
+                         :build-dir (get-target-dir fileset false)}
+                        ;;(str "target/" (if service mod))}
+                        ;; build-dir build-dir (gae-app-dir))} ;; (:build-dir config-map)}
+                        *opts*)
+            _ (println "OPTS: " opts)
+            params (into [] (for [[k v] (remove (comp nil? second)
+                                                (dissoc opts :build-dir :verbose :sdk-help))]
+                              (str "--" (str/replace (name k) #"-" "_")
+                                   (if (not (instance? Boolean v)) (str "=" v)))))
+            params (if (:sdk-help *opts*)
+                     ["help" "update"]
+                     (conj params "update" (:build-dir opts)))
+            params (into-array String params)
+            ;; ClassLoader classLoader = Thread.currentThread().contextClassLoader
+            class-loader (-> (Thread/currentThread) (.getContextClassLoader))
+            cl (.getParent class-loader)
+            app-cfg (Class/forName appcfg-class true class-loader)
+            target-middleware identity
+            target-handler (target-middleware next-handler)]
+        ;; def appCfg = classLoader.loadClass(APPENGINE_TOOLS_MAIN)
+        ;; appCfg.main(params as String[])
+        (def method (first (filter #(= (. % getName) "main") (. app-cfg getMethods))))
+        (def invoke-args (into-array Object [params]))
+        (if verbose ;; (or (:verbose *opts*) (:verbose config-map))
+          (do (println "CMD: AppCfg")
+              (doseq [arg params]
+                (println "\t" arg))))
+        (. method invoke nil invoke-args)
+        (target-handler fileset)))))
+

 (boot/deftask filters
   "generate filters class files"
@@ -754,6 +807,40 @@
         (builtin/sift :to-asset #{(re-pattern gen-filters-path)}))
        identity)
      )))
+
+(defn- install-jarfile-internal
+  [jarname]
+  "Install jarfile from fileset"
+  (fn middleware [next-handler]
+    (fn handler [fileset]
+      (let [jar-tmpfile (first (->> (boot/output-files fileset)
+                                    (boot/by-re [(re-pattern (str ".*" jarname))])))
+            jar-jfile (boot/tmp-file jar-tmpfile)
+            jar-path (.getCanonicalPath jar-jfile)
+            jar-name (.getName jar-jfile)
+            target-middleware (comp
+                               (builtin/install :file jar-path)
+                               (builtin/sift :to-source #{(re-pattern (str ".*" jar-name))}))
+            target-handler (target-middleware next-handler)]
+        (target-handler fileset)))))
+
+(boot/deftask install-service
+  "Install service component"
+  [p project PROJECT sym "project name"
+   r version VERSION str "project version string"
+   v verbose bool "Print trace messages"]
+  (fn middleware [next-handler]
+    (fn handler [fileset]
+      (let [e (boot/get-env)
+            target-dir (get-target-dir fileset false)
+            jarname (util/jarname project version)
+            jarpath (str target-dir "/" jarname)
+            target-middleware (comp
+                               (builtin/pom)
+                               (builtin/jar)
+                               (install-jarfile-internal jarname))
+            target-handler (target-middleware next-handler)]
+        (target-handler fileset)))))

 (boot/deftask install-sdk
   "Unpack and install the SDK zipfile"
@@ -787,57 +874,10 @@
           (pod/unpack-jar jar-path (.getParent sdk-dir))))
       fileset)))

-;;(core/deftask buber
-;; FIXME: what was this for???
-#_(defn buber
-  [tgt]
-  (println "BUBER ")
-  (let [;; tgt        (boot/tmp-dir!)
-        cache      (boot/cache-dir! ::uber :global true)
-        dfl-scopes #{"compile" "runtime"}
-        scopes     dfl-scopes
-        ;; scopes     (-> dfl-scopes
-        ;;                (set/union include-scope)
-        ;;                (set/difference exclude-scope))
-        _ (println "SCOPES: " dfl-scopes)
-        scope?     #(contains? scopes (:scope (util/dep-as-map %)))
-        jars       (-> pod/env ;; (boot/get-env)
-                       (update-in [:dependencies] (partial filter scope?))
-                       pod/resolve-dependency-jars)
-        _ (println "JARS: " jars)
-        jars       (remove #(.endsWith (.getName %) ".pom") jars)
-        checkouts  (->> (boot/get-checkouts)
-                        (filter (comp scope? :dep val))
-                        (into {}))
-        co-jars    (->> checkouts (map (comp :jar val)))
-        ;; co-dirs    (->> checkouts (map (comp :dir val)))
-        ;; exclude    (or exclude pod/standard-jar-exclusions)
-        ;; merge      (or merge pod/standard-jar-mergers)
-        ;; reducer    (fn [xs jar]
-        ;;              (boot/add-cached-resource
-        ;;                xs (digest/md5 jar) (partial pod/unpack-jar jar)
-        ;;                :include include :exclude exclude :mergers merge))
-        ;; co-reducer #(boot/add-resource
-        ;;               %1 %2 :include include :exclude exclude :mergers merge)
-        ]
-    ;; (boot/with-pre-wrap [fs]
-    ;; (println "co jars: " co-jars)
-      (when (seq jars)
-        (doseq [jar jars] ;; (reduce into [] [jars co-jars])]
-          (let [dest (doto (io/file tgt (.getName jar)) io/make-parents)]
-            (println "dest: " dest)
-            (file/copy-atomically jar dest))))))
-
-      ;;       (when-not (.exists src)
-      ;;         (println "CACHING " name)
-      ;;         (util/dbug* "Caching jar %s...\n" name)
-      ;;         (file/copy-atomically jar src))
-      ;;       (util/dbug* "Adding cached jar %s...\n" name)
-      ;;       (println (format "Adding cached jar %s...\n" name))
-      ;;       (file/hard-link src (io/file tgt name)))))
-      ;; #_(boot/commit! (if as-jars
-      ;;                 (boot/add-resource fs tgt)
-      ;;                 (reduce co-reducer (reduce reducer fs jars) co-dirs)))))
+(boot/deftask keep-config
+  "Retain master config file"
+  []
+  (builtin/sift :to-resource #{(re-pattern (str ".*" boot-config-edn))}))

 ;; FIXME:  for dev phase, we want to include deps in test scope
 (boot/deftask libs
@@ -964,51 +1004,21 @@

 (boot/deftask monitor
   "watch etc. for gae project"
-  [s service bool "service"
+  [d dir DIR str "target dir"
+   s servlet bool "servlet"
    v verbose bool "verbose"]
-  ;;(let [mod (str (-> (boot/get-env) :gae :module :name))]
-  (comp (builtin/watch)
-        (builtin/notify :audible true)
-        (builtin/sift :move {#"(.*\.clj$)" (str classes-dir "/$1")})
-        (if service
-          (target :no-clean true :service service :monitor true)
-          (target :no-clean true :service service :monitor false))))
-
-;; FIXME: not sure what this was for.  Just moving clj sources to the right output dir?
-;; replaced by sifting?
-#_(boot/deftask make
-  "dev build, source only"
-  [v verbose bool "verbose"]
-  (let [mod (str (-> (boot/get-env) :gae :module))
-        prev (atom nil)
-        cache-dir (boot/cache-dir! :boot-gae/build)
-        tmpdir (boot/tmp-dir!)]
-    ;; (println "MODULE: " mod)
-    (boot/empty-dir! tmpdir)
-    (comp
-     (boot/with-pre-wrap [fileset]
-       (let [changes (->> (boot/fileset-diff @prev fileset)
-                          boot/output-files
-                          (map :path))]
-             ;; fs (boot/new-fileset)]
-         (doseq [path changes]
-           (if verbose (util/info (str "changed: " path "\n")))
-           (let [in-file (boot/tmp-file (boot/tmp-get fileset path))
-                 out-file (if (str/ends-with? path "clj")
-                            (doto (io/file cache-dir classes-dir path) io/make-parents)
-                            (doto (io/file cache-dir path) io/make-parents))
-                 tmp-file (if (str/ends-with? path "clj")
-                            (doto (io/file tmpdir classes-dir path) io/make-parents)
-                            (doto (io/file tmpdir path) io/make-parents))]
-             (io/copy in-file out-file)
-             (io/copy in-file tmp-file)))
-         (reset! prev fileset)))
-     (builtin/sift :include #{#"^.*$"} :invert true)
-     (boot/with-pre-wrap [fileset]
-       (-> fileset
-           (boot/add-asset tmpdir)
-           boot/commit!))
-     )))
+  (fn middleware [next-handler]
+    (fn handler [fileset]
+      (let [dir (or dir (get-target-dir fileset servlet))
+            _ (println "TARGET DIR: " dir)
+            target-middleware (comp (builtin/watch)
+                                    (builtin/notify :audible true)
+                                    (builtin/sift :move {#"(.*\.clj$)" (str classes-dir "/$1")})
+                                    (if servlet
+                                      (target :no-clean true :servlet servlet)
+                                      (target :no-clean true :servlet servlet :dir dir)))
+            target-handler (target-middleware next-handler)]
+        (target-handler fileset)))))

 (boot/deftask rollback
   "appcfg rollback"
@@ -1021,50 +1031,54 @@
    m module MODULE str "module pfx"
    n gen-reloader-ns NS sym "ns for gen-reloader"
    r reloader-impl-ns NS sym "ns for reloader"
-   s service bool "build as service"
+   s servlet bool "build as servlet"
    w web-inf WEB-INF str "WEB-INF dir, default: WEB-INF"
    v verbose bool "Print trace messages."]
   (let [workspace (boot/tmp-dir!)
         prev-pre (atom nil)
         web-inf (if web-inf web-inf web-inf-dir)

-        module (if service
-                 (or module (-> (boot/get-env) :gae :module :name))
-                 nil)
-
         gen-reloader-ns (if gen-reloader-ns (symbol gen-reloader-ns) (gensym "reloadergen"))
         gen-reloader-path (str gen-reloader-ns ".clj")
         reloader-impl-ns (if reloader-impl-ns (symbol reloader-impl-ns) "reloader")
-        reloader-impl-path (str reloader-impl-ns ".clj")
-        ]
+        reloader-impl-path (str reloader-impl-ns ".clj")]
     (comp
      (boot/with-pre-wrap [fileset]
-       (let [
-             ;; webapp-edn-files (->> (boot/fileset-diff @prev-pre fileset)
-             ;;                       boot/input-files
-             ;;                       (boot/by-name [webapp-edn]))
-             ;; webapp-edn-f (condp = (count webapp-edn-files)
-             ;;                0 nil
-             ;;                1 (first webapp-edn-files)
-             ;;                (throw (Exception. "only one webapp.edn file allowed")))
-             ;; webapp-edn-map (if webapp-edn-f (-> (boot/tmp-file webapp-edn-f) slurp read-string) {})
-             boot-config-edn-files (->> (boot/fileset-diff @prev-pre fileset)
-                                    boot/input-files
-                                    (boot/by-re [(re-pattern (str boot-config-edn "$"))]))
-                                    ;; (boot/by-name [boot-config-edn]))
+       (let [boot-config-edn-files (->> (boot/fileset-diff @prev-pre fileset)
+                                        boot/input-files
+                                        (boot/by-re [(re-pattern (str boot-config-edn "$"))]))
+             ;; (boot/by-name [boot-config-edn]))
              boot-config-edn-f (condp = (count boot-config-edn-files)
-                             0 (do (util/info (str "Creating " boot-config-edn "\n"))
-                                   (io/file boot-config-edn)) ;; this creates a java.io.File
-                             1 (first boot-config-edn-files)  ;; this is a boot.tmpdir.TmpFile
-                             (throw (Exception.
-                                     (str "only one _boot_config.edn file allowed, found "
-                                          (count boot-config-edn-files)))))
+                                 0 (do (util/info (str "Creating " boot-config-edn "\n"))
+                                       (io/file boot-config-edn)) ;; this creates a java.io.File
+                                 1 (first boot-config-edn-files)  ;; this is a boot.tmpdir.TmpFile
+                                 (throw (Exception.
+                                         (str "only one _boot_config.edn file allowed, found "
+                                              (count boot-config-edn-files)))))
              boot-config-edn-map (if (instance? boot.tmpdir.TmpFile boot-config-edn-f)
                                    (-> (boot/tmp-file boot-config-edn-f) slurp read-string)
                                    {})
-             ;; boot-config-edn-map (merge boot-config-edn-map webapp-edn-map)
+
+             module (if-let [module (-> boot-config-edn-map :module :name)]
+                      module
+                      (let [appengine-config-edn-files
+                            (->> (boot/fileset-diff @prev-pre fileset)
+                                 boot/input-files
+                                 (boot/by-re [(re-pattern (str appengine-edn "$"))]))
+
+                            appengine-config-edn-f
+                            (condp = (count appengine-config-edn-files)
+                              0 (throw (Exception. appengine-edn " file not found"))
+                              1 (first appengine-config-edn-files)
+                              (throw (Exception.
+                                      (str "Only one " appengine-edn " file allowed, found "
+                                           (count appengine-config-edn-files)))))
+
+                            appengine-config-edn-map
+                            (-> (boot/tmp-file boot-config-edn-f) slurp read-string)]
+                        (-> appengine-config-edn-map :module :name)))
              ]
-         ;; (println "boot-config-edn-map: " boot-config-edn-map)
+         (println "MODULE: " module)

          (if (:reloader boot-config-edn-map)
            fileset
@@ -1073,12 +1087,12 @@
              ;; step 1: create config map for reloader, inject into master config file
              (let [urls (flatten (concat (map #(% :urls) (:servlets boot-config-edn-map))))
                    m (-> boot-config-edn-map (assoc-in [:reloader]
-                                                 {:ns reloader-impl-ns
-                                                  :name "reloader"
-                                                  :display {:name "Clojure reload filter"}
-                                                  :urls (if (empty? urls) [{:url "/*"}]
-                                                            (vec urls))
-                                                  :desc {:text "Clojure reload filter"}}))
+                                                       {:ns reloader-impl-ns
+                                                        :name "reloader"
+                                                        :display {:name "Clojure reload filter"}
+                                                        :urls (if (empty? urls) [{:url "/*"}]
+                                                                  (vec urls))
+                                                        :desc {:text "Clojure reload filter"}}))
                    boot-config-edn-s (with-out-str (pp/pprint m))
                    boot-config-edn-out-file (io/file workspace
                                                      (if (instance? boot.tmpdir.TmpFile boot-config-edn-f)
@@ -1156,27 +1170,31 @@

    _ modules MODULES edn "modules map"

-   s service bool "service"
+   s servlet bool "servlet app DEPRECATED"
    v verbose bool "verbose"]

   (boot/with-pre-wrap [fileset]
-    (let [webapp-edn-files (->> fileset
+    (let [appengine-edn-fs (->> fileset
                                 boot/input-files
-                                (boot/by-name [webapp-edn]))
-          webapp-edn-f (condp = (count webapp-edn-files)
-                         0 nil
-                         1 (first webapp-edn-files)
-                         (throw (Exception. "only one webapp.edn file allowed")))
-          webapp-edn-map (if webapp-edn-f (-> (boot/tmp-file webapp-edn-f) slurp read-string) {})
+                                (boot/by-name [appengine-edn]))
+
+          appengine-edn-f (condp = (count appengine-edn-fs)
+                            0 (throw (Exception. appengine-edn " file not found"))
+                            1 (first appengine-edn-fs)
+                            (throw (Exception. (str "Only one " appengine-edn " file allowed"))))
+
+          appengine-config-map (-> (boot/tmp-file appengine-edn-f) slurp read-string)
+
+
           ;; (println "*OPTS*: " *opts*)
           args (->args *opts*)
           ;; _ (println "ARGS: " args)
           ;; jargs (into-array String (conj jargs "build/exploded-app"))

-          target-dir (if service (str (-> (boot/get-env) :gae :app :dir)
-                                      "/target/"
-                                      (-> (boot/get-env) :gae :module :name))
-                         "target")
+          target-dir (if servlet "target"
+                         (if (-> appengine-config-map :services)
+                           "target/default"
+                           (str "target/" (-> appengine-config-map :module :name))))

           checkout-vec (-> (boot/get-env) :checkouts)
           cos (map #(assoc (apply hash-map %) :coords [(first %) (second %)]) checkout-vec)
@@ -1336,6 +1354,19 @@
         (builtin/sift :to-asset #{(re-pattern gen-servlets-path)}))
        identity)
      )))
+
+(boot/deftask target
+  "target, using module name"
+  [C no-clean bool "Don't clean target before writing project files"
+   d dir DIR str "target dir"
+   s servlet bool "building as servlet"
+   v verbose bool "verbose"]
+  (fn middleware [next-handler]
+    (fn handler [fileset]
+      (let [target-dir (or dir (get-target-dir fileset servlet))
+            target-middleware (builtin/target :dir #{target-dir} :no-clean no-clean)
+            target-handler (target-middleware next-handler)]
+        (target-handler fileset)))))

 (boot/deftask webxml
   "generate gae web.xml"


Add menu entry for line tool

Add menu entry for line tool

--- src/cljs/goya/components/toolsmenu.cljs
+++ src/cljs/goya/components/toolsmenu.cljs
@@ -40,6 +40,17 @@
         (omdom/div #js {:className class-name
                         :onClick (fn [e] (put! toolchan :brush))}
           (omdom/i #js {:className "icon-brush"}))))))
+
+
+(defn line-tool-component [app owner]
+  (reify
+    om/IRenderState
+      (render-state [this {:keys [toolchan]}]
+        (let [current-paint-tool (:paint-tool app)
+              class-name (class-name-for-tool current-paint-tool :line)]
+        (omdom/div #js {:className class-name
+                        :onClick (fn [e] (put! toolchan :line))}
+          (omdom/i #js {:className "icon-pencil"}))))))

 (defn fill-tool-component [app owner]
@@ -95,6 +106,7 @@
     (render-state [this {:keys [toolchan]}]
       (omdom/div #js {:className "tools-menu"}
         (om/build brush-tool-component app {:init-state {:toolchan toolchan}})
+        (om/build line-tool-component app {:init-state {:toolchan toolchan}})
         (om/build box-tool-component app {:init-state {:toolchan toolchan}})
         (om/build fill-tool-component app {:init-state {:toolchan toolchan}})
         (om/build picker-tool-component app {:init-state {:toolchan toolchan}})


login button as anchor

login button as anchor

--- src/cljs/movement/components/login.cljs
+++ src/cljs/movement/components/login.cljs
@@ -9,30 +9,27 @@
             [reagent.session :as session]))

 (defn header []
-  [:div
-   [:div.pure-g
-    [:div.pure-u-1
-     [:div.home-menu.pure-menu-horizontal
-      [:a.pure-menu-heading {:title  "Home"
-                             :href   "/"
-                             :target ""} "Movement Session"]
-      [:ul.pure-menu-list
-       [:li.pure-menu-item
-        [:a.pure-menu-link {:title  "Home"
-                            :href   "/"
-                            :target ""} "Home"]]
-       [:li.pure-menu-item
-        [:a.pure-menu-link {:title  "Tour"
-                            :href   "/tour"
-                            :target ""} "Tour"]]
-       [:li.pure-menu-item
-        [:a.pure-menu-link {:title  "Pricing"
-                            :href   "/pricing"
-                            :target ""} "Pricing"]]
-       [:li.pure-menu-item
-        [:a.pure-menu-link {:title  "Sign in"
-                            :href   "/app"
-                            :target ""} "Sign in"]]]]]]])
+  [:div.home-menu.pure-menu-horizontal
+   [:a.pure-menu-heading {:title  "Home"
+                          :href   "/"
+                          :target ""} "Movement Session"]
+   [:ul.pure-menu-list
+    [:li.pure-menu-item
+     [:a.pure-menu-link {:title  "Home"
+                         :href   "/"
+                         :target ""} "Home"]]
+    [:li.pure-menu-item
+     [:a.pure-menu-link {:title  "Tour"
+                         :href   "/tour"
+                         :target ""} "Tour"]]
+    [:li.pure-menu-item
+     [:a.pure-menu-link {:title  "Pricing"
+                         :href   "/pricing"
+                         :target ""} "Pricing"]]
+    [:li.pure-menu-item
+     [:a.pure-menu-link {:title  "Sign in"
+                         :href   "/app"
+                         :target ""} "Sign in"]]]])

 (defn footer []
   [:div#footer.l-box.is-center
@@ -97,7 +94,7 @@
          [:div.notice e])
        [:div.pure-g
         [:div.pure-u.pure-u-md-1-5]
-        [:button.pure-u.pure-u-md-3-5.button.button-primary
+        [:a.pure-u.pure-u-md-3-5.button.button-primary
          {:class    (when @loading? " disabled")
           :on-click #(if-not (and (seq @user) (seq @password))
                       (reset! error "Both fields are required.")


ui changes

ui changes

--- src/cljs/salava/metabadge/ui/modal.cljs
+++ src/cljs/salava/metabadge/ui/modal.cljs
@@ -139,7 +139,7 @@
        [:img {:src (:image badge) :class (if-not is-complete? " opaque")}]]
       [:div.progress
        [:div.progress-bar.progress-bar-success
-        {;:class (if  is-complete? "" " progress-bar-striped")
+        {
           :role "progressbar"
           :aria-valuenow (str completed)
           :style {:width (str completed "%")}
@@ -147,11 +147,16 @@
           :aria-valuemax "100"}
         (str completed "%")]]]
      [:div.col-md-9 {:id "badge-stats"}
-      (t :metabadge/Requiredbadgeinfo)
+      [:div.col-md-12
+              [:h1.uppercase-header (:name metabadge)]
+       [:div.description (if-not is-complete? (t :metabadge/Milestoneinfo) (t :metabadge/Completedmilestoneinfo))]
+       #_[:div {:style {:margin-top "10px"}}[:label (str (t :metabadge/Minimumrequired) ": ")] min_required]
+       #_[:div [:label (str (t :metabadge/Amountearned)": ")] amount_received]
+      [:hr]
       [:div.panel
        [:div.panel-body
-        [:div.row.header {:style {:margin-bottom "10px"}}
-         [:div.flip-table
+        [:div.row.header {:style {:margin-bottom "10px" :margin-top "10px"}}
+         [:div.row.flip-table
           [:div.col-md-6]
           [:div.col-md-2 (t :metabadge/Earnedon)]
           [:div.col-md-4]]]
@@ -160,8 +165,8 @@
                         {:keys [name image criteria]} badge-info
                         {:keys [id issued_on status]} user_badge
                         image-class (if-not received " opaque")]
-                    (conj r [:div.col-md-12
-                             [:div.flip-table
+                    (conj r [:div
+                             [:div.row.flip-table {:style {:margin-bottom "10px"}}
                               [:div.col-md-1 [:img.badge-icon {:src image :class image-class}]]
                               [:div.col-md-5 (if received
                                                (if (= status "declined")
@@ -172,7 +177,7 @@
                               [:div.col-md-2 [:label (t :metabadge/Dateissued)] (if issued_on (date-from-unix-time (* 1000 issued_on)) "-")]
                               [:div.col-md-4 ]]]))) [:div.row.body] (->> required_badges
                                                                          (sort-by #(-> % :user_badge :issued_on) >)
-                                                                         (sort-by :received >)))]]]]))
+                                                                         (sort-by :received >)))]]]]]))

 (defn modal-navi [metabadge state]
   [:div.row.flip-table
@@ -184,7 +189,7 @@
        [:div  [:i.nav-icon {:class "fa fa-puzzle-piece fa-lg"}] (t :metabadge/Requiredbadges)  ]]]
      [:li.nav-item {:class  (if (or (nil? (:tab-no @state))(= 2 (:tab-no @state))) "active")}
       [:a.nav-link {:href "#" :on-click #(swap! state assoc :tab [view-content metabadge] :tab-no 2 )}
-       [:div  [:i.nav-icon {:class "fa fa-info-circle fa-lg"}] (t :metabadge/info)]]]]]])
+       [:div  [:i.nav-icon {:class "fa fa-info-circle fa-lg"}] (t :metabadge/Info)]]]]]])

 (defn metabadge-content [metabadge state]
   (let [{:keys [badge required_badges milestone? min_required]} metabadge


Use ratpack promises instead of streams for async values that represents one value.

(The futura promises and completable future instances as response return value
are now handler in more efficient way)

--- src/clojure/catacumba/impl/handlers.clj
+++ src/clojure/catacumba/impl/handlers.clj
@@ -101,7 +101,8 @@

   CompletableFuture
   (handle-response [data ^DefaultContext context]
-    (handle-response (p/promise data) context)))
+    (set-status* context 200)
+    (send data (:catacumba/context context))))

 (extend-protocol ISend
   String
@@ -119,20 +120,22 @@
     (-> (stream/publisher data)
         (send ctx)))

-  futura.promise.Promise
+  manifold.deferred.IDeferred
   (send [data ^Context ctx]
     (-> (stream/publisher data)
         (send ctx)))

-  manifold.deferred.IDeferred
-  (send [data ^Context ctx]
-    (-> (stream/publisher data)
-        (send ctx)))
-
   CompletableFuture
   (send [data ^Context ctx]
-    (-> (stream/publisher data)
-        (send ctx)))
+    (let [prom (helpers/promise ctx (fn [^Fulfiller ff]
+                                      (.accept ff data)))]
+      (.then ^Promise prom (helpers/action
+                            (fn [response]
+                              (send response ctx))))))
+
+  futura.promise.Promise
+  (send [data ^Context ctx]
+    (send (p/future data) ctx))

   Publisher
   (send [data ^Context ctx]


Add testing-context-str to test output. Fixes #15.

--- src/jx/reporter/karma.cljs
+++ src/jx/reporter/karma.cljs
@@ -1,7 +1,8 @@
 (ns jx.reporter.karma
   (:require [cljs.test]
             [clojure.data]
-            [fipp.clojure])
+            [fipp.clojure]
+            [clojure.string :as str])
   (:require-macros [jx.reporter.karma :as karma]))

 (def karma (volatile! nil))
@@ -55,10 +56,12 @@
       (str (format "-" removed)
            (format (str "\n" (apply str (repeat indentation " ")) "+") added)))))

-(defn- format-log [{:keys [expected actual message] :as result}]
+(defn- format-log [{:keys [expected actual message testing-contexts-str] :as result}]
   (let [indentation (count "expected: ")]
     (str
       "FAIL in   " (cljs.test/testing-vars-str result) "\n"
+      (when-not (str/blank? testing-contexts-str)
+        (str "\"" testing-contexts-str "\"\n"))
       (if (and (seq? expected)
                (seq? actual))
         (str
@@ -102,11 +105,11 @@

 (defmethod cljs.test/report [::karma :fail] [m]
   (cljs.test/inc-report-counter! :fail)
-  (vswap! test-var-result conj m))
+  (vswap! test-var-result conj (assoc m :testing-contexts-str (cljs.test/testing-contexts-str))))

 (defmethod cljs.test/report [::karma :error] [m]
   (cljs.test/inc-report-counter! :error)
-  (vswap! test-var-result conj m))
+  (vswap! test-var-result conj (assoc m :testing-contexts-str (cljs.test/testing-contexts-str))))

 (defmethod cljs.test/report [::karma :end-run-tests] [_]
   (karma-complete!))


Add state and values to inputs.

Add state and values to inputs.

--- src/lab_notebook/core.cljs
+++ src/lab_notebook/core.cljs
@@ -15,8 +15,13 @@

 (defn item-table [cursor component]
   (reify
-    om/IRender
-    (render [this]
+    om/IInitState
+    (init-state [this]
+      {:summary ""
+       :date-time ""
+       :notes ""})
+    om/IRenderState
+    (render-state [this state]
       (dom/div nil
         (apply dom/div nil
           (for [entry (:entries cursor)]
@@ -26,11 +31,14 @@
           (dom/form #js {:className "form-horizontal"}
             (dom/input #js {:type "text"
                             :className "form-control"
+                            :value (:summary state)
                             :placeholder "Summary"})
             (dom/input #js {:type "text"
                             :className "form-control"
+                            :value (:date-time state)
                             :placeholder "Time"})
             (dom/textarea #js {:className "form-control":placeholder "Notes"
+                               :value (:notes state)
                                :rows "5"})
             (dom/button #js {:className "btn btn-primary"
                              :onClick (fn [e]


ex24 out

ex24 out

--- examples/ex24-sdf.clj
+++ examples/ex24-sdf.clj
@@ -1,151 +0,0 @@
-(ns examples.ex24-sdf
-  (:require [clojure2d.core :refer :all]
-            [clojure2d.math :as m]
-            [clojure2d.math.vector :as v]
-            [clojure2d.color :as c]
-            [clojure2d.extra.raymarching :as r])
-  (:import [clojure2d.math.vector Vec2 Vec3]
-           [java.awt Color]))
-
-(set! *warn-on-reflection* true)
-
-(def ^:const w 600)
-(def ^:const h 600)
-
-(def canvas (create-canvas w h))
-
-(def window (show-window canvas "sdf" w h 15))
-
-(defmethod key-pressed ["sdf" \space] [_]
-  (save-canvas canvas "results/ex24/scene.jpg"))
-
-(do
-  (def max-depth 20.0)
-
-  ;; ray origin
-  (def ro (Vec3. 0.0 5.0 3.0))
-
-  ;; camera
-  (def camera (r/make-camera ro (Vec3. 0.0 4.0 1.0) 0.0))
-
-  ;; object
-  (def sphere (r/make-primitive :sphere 1 {:r 3.0}))
-  (def box    (r/make-primitive :box 2 {:box (Vec3. 3.0 3.0 3.0)}))
-  (def torus  (r/make-primitive :torus 3 {:small-radius 0.3
-                                          :large-radius 3.0}))
-
-  (def box-sphere (r/op-subtract box (r/make-primitive :sphere 1 {:r 3.5})))
-
-  (def lrp    (r/op-transform (r/op-rotate box-sphere (Vec3. 0.3 1.1 0.3) -0.4) (Vec3. 0.0 1.0 -3.0)))
-
-  (def plane (r/make-primitive :plane 0 {:normal (Vec3. 0.0 1.0 0.0)
-                                         :dist-from-origin 1.0}))
-
-  ;; normal calculator
-  (def norm (r/make-normal 0.01))
-
-  ;; ray marching fn
-  (def ray-marching (r/make-ray-marching 0.01 max-depth 100))
-
-  ;; ambient occlusion
-  (def ao (r/make-ao 0.5 0.65 5))
-
-  (def shadow-f (r/make-soft-shadow 8 20 max-depth))
-
-  (def light1 (v/normalize (Vec3. -2.0 2.0 1.0)))
-  (def light2 (v/normalize (Vec3. 0.0 1.0 1.0)))
-
-  (let [^Vec3 a1 (Vec3. 1.0 1.0 1.0)
-        ^Vec3 a2 (Vec3. -1.0 -1.0 1.0)
-        ^Vec3 a3 (Vec3. 1.0 -1.0 -1.0)
-        ^Vec3 a4 (Vec3. -1.0 1.0 -1.0)
-        scale 3.0
-        iters 5
-        dscale (dec scale)
-        fact (m/pow scale (- iters))]
-   (defn sierp [p]
-     (loop [n (int 0)
-            z p]
-       (if (< n iters)
-           (let [d1 (v/mag (v/sub z a1))
-                 d2 (v/mag (v/sub z a2))
-                 d3 (v/mag (v/sub z a3))
-                 d4 (v/mag (v/sub z a4))
-                 c [a1 d1]
-                 c (if (< d2 (c 1)) [a2 d2] c)
-                 c (if (< d3 (c 1)) [a3 d3] c)
-                 c (if (< d4 (c 1)) [a4 d4] c)]
-             (recur (unchecked-inc n)
-                    (v/sub (v/mult z scale)
-                           (v/mult (c 0) dscale))))
-           (Vec2. (* fact (v/mag z)) 2)
-           ))))
-
-  (let [bailout 2.0
-        iters 5
-        power 8
-        dpower (dec power)]
-      (defn mandelbulb
-        ""
-        [p]
-        (loop [^Vec3 z p
-               dr 1.0
-               r (v/mag z)
-               i (int 0)]
-          (if (and
-               (< i iters)
-               (< r bailout))
-            (let [theta (* power (m/acos (/ (.z z) r)))
-                  phi (* power (m/atan (/ (.y z) (.x z))))
-                  zr (m/pow r power)
-                  ^Vec3 nz (v/from-polar (Vec3. zr theta phi))
-                  newz (v/add p nz)]
-              (recur newz
-                     (inc (* (m/pow r dpower) power dr))
-                     (v/mag newz)
-                     (unchecked-inc i)))
-            (Vec2. (/ (* (m/log r) r)
-                      (* 2.0 dr))
-                   1)))
-        ))
-
-
-  ;; scene
-  (def scene (r/op-transform (r/op-scale (r/op-rotate lrp (Vec3. 0.0 1.0 0.0) m/HALF_PI) 3.0) (Vec3. 0.0 5.0 -1.0 )))
-
-(comment conj (map #(r/op-rotate % (Vec3. 0.0 1.0 0.0) 0.0)
-                          [sphere box lrp]) plane)
-
-  (def scene-colors [(v/div (Vec3. 222 223 225) 255.0)
-                     (v/div (Vec3. 223 223 252) 255.0)
-                     (v/div (Vec3. 113 223 52) 255.0)
-                     (Vec3. 1.0 0.0 0.0)])
-  (def background-color (v/div (Vec3. 232 221 203) 255.0))
-
-    ;; fog
-  (def fog (r/make-distance-fog background-color -0.001)))
-
-(dotimes [x w]
-  (let [xx (m/norm x 0.0 w -3.0 3.0)]
-    (dotimes [y h]
-      (let [yy (m/norm y 0.0 h 3.0 -3.0)
-            ^Vec3 rd (camera (v/normalize (Vec3. xx yy 1.0)))
-            ^Vec3 t (ray-marching scene ro rd)
-            col (if (> (.x t) max-depth)
-                  background-color
-                  (let [^Vec3 pos (r/ray ro rd (.x t))
-                        ^Vec3 n (norm scene pos)
-                        obj (int (.y t))
-                        occ (ao scene pos n)
-                        sha1 (shadow-f scene pos light1)
-                        dif1 (* (m/constrain (v/dot n light1) 0.0 1.0) sha1)
-                        sha2 (shadow-f scene pos light2)
-                        dif2 (* (m/constrain (v/dot n light2) 0.0 1.0) sha2)
-                        col (scene-colors obj)
-                        col (v/mult col (* 0.6 dif1 dif2))
-                        col (v/add col (Vec3. occ occ occ))
-                        ]
-                    (fog (.x t) col)))]
-        (with-canvas canvas
-          (set-color (c/to-color3 (v/mult col 255)))
-          (rect x y 1 1))))))


remove ghost margin

remove ghost margin

--- frontend/components/app.cljs
+++ frontend/components/app.cljs
@@ -98,7 +98,8 @@
            (let [inner? (get-in app state/inner?-path)]

              [:div#app {:class (concat [(if inner? "inner" "outer")]
-                                       (when slim-aside? ["aside-slim"]))}
+                                       (when slim-aside? ["aside-slim"])
+                                       (when-not logged-in? ["aside-nil"]))}
               (om/build keyq/KeyboardHandler app-without-container-data
                         {:opts {:keymap keymap
                                 :error-ch (get-in app [:comms :errors])}})


improved comments

improved comments

--- src/ontrail/search.clj
+++ src/ontrail/search.clj
@@ -20,7 +20,7 @@
 ;; are not updated to the index.
 ;;
 ;; Results set are paginated, and the result set is sorted by :lastModifiedDate
-;; -field of the exercise.
+;; -field of the exercise, so that the latest is first search result.
 ;;

 ;; Ref to associative map from a search term to set of document id:s where


Add def->var to pattern

Add def->var to pattern

--- src/oxcart/pattern.clj
+++ src/oxcart/pattern.clj
@@ -40,6 +40,16 @@
     (:name ast)))

+(defn def->var
+  "λ AST → (Option Var)
+
+  If the argument form was a def returns the defined var. Otherwise
+  the return value is garbage."
+  [ast]
+  (when (def? ast)
+    (:var ast)))
+
+
 (defn top-level?
   "λ AST → Boolean


Fix problem with ConsString in Rhino

Fix problem with ConsString in Rhino

--- src/photon/streams.clj
+++ src/photon/streams.clj
@@ -71,8 +71,23 @@
   (fn [& args]
     (let [res (apply js/call-timeout scope fun 9999999 args)]
       (try
-        (json/read-str res :key-fn keyword)
-        (catch Exception e res)))))
+        (let [converted (clojure.walk/walk
+                         (fn [elem]
+                           (if (instance?
+                                org.mozilla.javascript.ConsString
+                                elem)
+                             (.toString elem)))
+                         identity
+                         (js/from-js res)
+                         #_(json/read-str res :key-fn keyword))]
+          (println "!!!!!!!!!!!!!!!!!! CONVERTED")
+          (clojure.pprint/pprint converted)
+          (println "!!!!!!!!!!!!!!!!!! CONVERTED")
+          converted)
+        (catch Exception e
+          (println (.getMessage e))
+          (.printStackTrace e)
+          res)))))

 (defmethod generate-function "javascript" [lang f]
   (let [sc (js/new-safe-scope)


Favor builtin.

Favor builtin.

--- src/postal/message.clj
+++ src/postal/message.clj
@@ -1,5 +1,6 @@
 (ns postal.message
   (:use [clojure.set :only [difference]]
+        [clojure.java.io :only [file]]
         [postal.date :only [make-date]]
         [postal.support :only [do-when make-props]])
   (:import [java.util UUID]
@@ -50,9 +51,6 @@
         (add-recipient! jmsg rtype addr))))
   jmsg)

-(defn- fileize [x]
-  (if (instance? java.io.File x) x (java.io.File. x)))
-
 (declare eval-bodypart eval-multipart)

 (defprotocol PartEval (eval-part [part]))
@@ -69,7 +67,7 @@
   (condp (fn [test type] (some #(= % type) test)) (:type part)
     [:inline :attachment]
     (let [attachment-part (doto (javax.mail.internet.MimeBodyPart.)
-                            (.attachFile (fileize (:content part)))
+                            (.attachFile (file (:content part)))
                             (.setDisposition (name (:type part))))]

       (when (:content-type part)


Fix move handler for back in time case

Fix move handler for back in time case

--- src/pot/core/hand.cljs
+++ src/pot/core/hand.cljs
@@ -34,9 +34,8 @@
         cursor (:cursor history-value)
         next-snapshot (get-in history-value [:snapshots (inc cursor)])]
     (when (not (:game-over state-value))
-      (if next-snapshot
-        (when (= direction (:direction next-snapshot))
-          (reset! state next-snapshot))
+      (if (and next-snapshot (= direction (:direction next-snapshot)))
+        (reset! state next-snapshot)
         (let [take-up-to-cursor (comp vec (partial take (inc cursor)))
               new-board (-> state-value :board handler add-random-cell)]
           (swap! history update-in [:snapshots] take-up-to-cursor)


Implementing call a system process

Implementing call a system process

--- src/power/relay_py.clj
+++ src/power/relay_py.clj
@@ -1,5 +1,5 @@
 (ns power.relay-py
-  (:require [clojure.java.shell :only [sh]]
+  (:require [clojure.java.shell :refer [sh]]
             [clojure.java.io :as io]))

 (def python-path "/usr/bin/python")


cleanup

cleanup

--- src/frontend/cljs/alibi/entry_page.cljs
+++ src/frontend/cljs/alibi/entry_page.cljs
@@ -137,12 +137,10 @@
   {:dispatch! (partial dispatch! state)}
   {:target (js/document.getElementById "activity-graphic-tooltip-container")})

-
 (defn render-day-entry-table!
   [for-state]
   (let [new-date (get for-state :selected-date)]
     (day-entry-table/render "day-entry-table" new-date)))
-

 (add-watch
   state :renderer


config: use load-file instead of load-string (slurp file))

Not sure why I made this choice in the first place, but I'm pretty sure
I was crazy to do it. Removes the need for config file validation,
simplifies error handling. Closes #114.

--- src/riemann/config.clj
+++ src/riemann/config.clj
@@ -174,14 +174,6 @@
                 (.getParent))]
       (str (file dir path)))))

-(defn validate-config
-  "Check that a config file has valid syntax."
-  [file]
-  (try
-    (read-strings (slurp file))
-    (catch clojure.lang.LispReader$ReaderException e
-      (throw (logging/nice-syntax-error e file)))))
-
 (defn include
   "Include another config file.

@@ -194,5 +186,4 @@
   (let [path (config-file-path path)]
     (binding [*config-file* path
               *ns* (find-ns 'riemann.config)]
-      (validate-config path)
-      (load-string (slurp path)))))
+      (load-file path))))


SPEAr6xx: Add compilation support for dtbs using 'make dtbs'

'make dtbs' compiles all dtbs for a family. For this we need to add entries for
all board dtb's in Makefile.boot file. This patch does it.

Signed-off-by: Viresh Kumar <5ff32272b3d9f86512eddc8e0af523fc6f7924e5@st.com>

--- arch/arm/mach-spear6xx/Makefile.boot
+++ arch/arm/mach-spear6xx/Makefile.boot
@@ -1,3 +1,5 @@
 zreladdr-y	+= 0x00008000
 params_phys-y	:= 0x00000100
 initrd_phys-y	:= 0x00800000
+
+dtb-$(CONFIG_BOARD_SPEAR600_DT)	+= spear600-evb.dtb


Cosmetic.

Cosmetic.

--- src/onyx/queue/hornetq.clj
+++ src/onyx/queue/hornetq.clj
@@ -47,6 +47,17 @@
   (let [k (first (filter #(= (keyword (name %)) :cluster-name) (keys opts)))]
     (get opts k)))

+(defn split-host-str [s]
+  (let [[h p] (split s #":")]
+    [(second (split h #"/")) p]))
+
+(defn initial-connectors [locator]
+  (map
+   (fn [config]
+     (let [params (.getParams config)]
+       [(get params "host") (get params "port")]))
+   (into [] (.getStaticTransportConfigurations locator))))
+
 (defrecord HornetQConnection [opts]
   component/Lifecycle

@@ -121,17 +132,6 @@
   [queue session queue-name]
   (let [query (.queueQuery session (SimpleString. queue-name))]
     (.getMessageCount query)))
-
-(defn split-host-str [s]
-  (let [[h p] (split s #":")]
-    [(second (split h #"/")) p]))
-
-(defn initial-connectors [locator]
-  (map
-   (fn [config]
-     (let [params (.getParams config)]
-       [(get params "host") (get params "port")]))
-   (into [] (.getStaticTransportConfigurations locator))))

 (defmethod extensions/n-consumers HornetQConnection
   [queue queue-name]


Fixed potential session/user clobbering/masquerade bug in email validation

--- src/sdos_site/user.clj
+++ src/sdos_site/user.clj
@@ -170,11 +170,13 @@
   (let [submitted-key (-> req :request-params :validation-key)
         db (:db req)]
     (if (users/validate-key db submitted-key)
-      (let [user (-> req :session :user)
+      (let [username (-> req :session :user :username)
             body (view/success-page (str "Email validated."))]
-        (if user
-          {:session {:user (assoc-in user :validated true)}
-           :body body}
+        (if username
+          (let [session (:session req)
+                updated-user (users/get-by-username db username)]
+            {:session (assoc-in [:session :user] updated-user)
+             :body body})
           body))
       (layout/error-template (get-settings req)
                              "Sorry, email validation key not found."))))


Use resolve to fetch project workflow runs

--- src-cljs/frontend/send.cljs
+++ src-cljs/frontend/send.cljs
@@ -1,13 +1,17 @@
 (ns frontend.send
-  (:require [cljs-time.coerce :as time-coerce]
+  (:require [bodhi.aliasing :as aliasing]
+            [bodhi.core :as bodhi]
+            [cljs-time.coerce :as time-coerce]
             [cljs-time.core :as time]
-            [cljs.core.async :refer [chan <!]]
+            [cljs.core.async :refer [<! chan]]
             [clojure.set :refer [rename-keys]]
             [frontend.api :as api]
             [frontend.send.resolve :refer [resolve]]
             [frontend.utils.expr-ast :as expr-ast]
             [frontend.utils.vcs-url :as vcs-url]
-            [om.next.impl.parser :as om-parser])
+            [om.next :as om-next]
+            [om.next.impl.parser :as om-parser]
+            [promesa.core :as p :include-macros true])
   (:require-macros [cljs.core.async.macros :as am :refer [go-loop]]))

 (def ^:private ms-until-retried-run-retrieved 3000)
@@ -26,6 +30,24 @@
         (when-not (= state :finished)
           (recur))))
     ch))
+
+(defn- api-promise
+  "Takes an API function which expects a channel as its first arg, followed by
+  the API functions other args. Returns a promise of the response the API
+  function puts on the channel.
+
+  This is a temporary shim to reuse the old API functions in the Om Next send."
+  [api-f & args]
+  (p/promise
+   (fn [resolve reject]
+     (let [ch (chan)]
+       (go-loop []
+         (let [[_ state data] (<! ch)]
+           (when (= state :success)
+             (resolve (:resp data)))
+           (when-not (= state :finished)
+             (recur))))
+       (apply api-f ch args)))))

 (defn- job-run-status [job-status-str]
   (case job-status-str
@@ -189,17 +211,6 @@
         (-> expr-ast
             (expr-ast/get-in [:organization/project :project/branch])
             (expr-ast/has-children? #{:branch/name})))))
-
-(defn- get-branch-name [cb expr-ast query]
-  (let [branch-name (-> expr-ast
-                        (expr-ast/get-in [:organization/project :project/branch])
-                        :params
-                        :branch/name)
-        novelty {:circleci/organization
-                 {:organization/project
-                  {:project/branch
-                   {:branch/name branch-name}}}}]
-    (cb novelty query)))

 (defn- branch-runs-ast?
   "returns true if the ast is for an expression rendering the branch
@@ -319,6 +330,12 @@
           (cb novelty query))))
      id)))

+;; The parser used by the resolvers when they return deeply nested data.
+(def parser
+  (om-next/parser {:read (bodhi/read-fn
+                          (-> bodhi/basic-read
+                              aliasing/read))}))
+
 (def resolvers
   {:circleci/organization
    (fn [env ast]
@@ -342,7 +359,56 @@

    :branch/name
    (fn [env ast]
-     (:branch/name env))})
+     (:branch/name env))
+
+   :branch/project
+   (fn [env ast]
+     (resolve (dissoc env :branch/name)
+              ast
+              (chan)))
+
+   :project/name
+   (fn [env ast]
+     (:project/name env))
+
+   :project/organization
+   (fn [env ast]
+     (resolve (dissoc env :project/name)
+              ast
+              (chan)))
+
+   :organization/name
+   (fn [env ast]
+     (:organization/name env))
+
+   :branch/workflow-runs
+   (fn [env ast]
+     (-> (api-promise
+          api/get-branch-workflows
+          (:organization/vcs-type env)
+          (:organization/name env)
+          (:project/name env)
+          (:branch/name env)
+          {:offset (:connection/offset (:params ast))
+           :limit (:connection/limit (:params ast))})
+
+         (p/then
+          (fn [response]
+            (let [adapted {:connection/total-count (:total-count response)
+                           :connection/edges (->> (:results response)
+                                                  (map adapt-to-run)
+                                                  (mapv #(hash-map :edge/node %)))}]
+              ;; Run the adapted structure through a parser to match it to the
+              ;; rest of the query.
+              (parser {:state (atom adapted)} (mapv om-next/ast->query (:children ast))))))))})
+
+(defn- resolvers-can-handle?
+  "Tool for migrating to resolvers. True if the expression can be handled by the
+  resolvers above."
+  [expr]
+  (let [de-aliased-ast (om-parser/expr->ast (first (de-alias-expression expr #())))]
+    (or (branch-crumb-ast? de-aliased-ast)
+        (branch-runs-ast? de-aliased-ast))))

 (defmulti send* key)

@@ -361,7 +427,7 @@
       (js/setTimeout #(send* [:remote (rest query)] cb)
                      ms-until-retried-run-retrieved))
     (doseq [expr query]
-      (if (branch-crumb-ast? (om-parser/expr->ast (first (de-alias-expression expr cb))))
+      (if (resolvers-can-handle? expr)
         (let [ch (resolve {:resolvers resolvers} [expr] (chan))]
           (go-loop []
             (when-let [novelty (<! ch)]
@@ -371,8 +437,6 @@
         (let [[expr cb] (de-alias-expression expr cb)
               ast (om-parser/expr->ast expr)]
           (cond
-            ;; (branch-crumb-ast? ast) (get-branch-name cb ast query)
-            (branch-runs-ast? ast) (get-branch-runs cb ast query)
             (= {:app/current-user [{:user/organizations [:organization/name :organization/vcs-type :organization/avatar-url]}]}
                expr)
             (let [ch (callback-api-chan


Explicitly build local images for linux/amd64 for now

Tried building images on an M1 Mac for the first time and ran into the fact that not every upstream image exists for linux/arm64 (which is handled by the clojure manifest for the official images). So for now I'm just explicitly building on linux/amd64 locally (which is supported via qemu on M1 Macs w/ buildx). Should make it smarter at some point.

--- src/docker_clojure/core.clj
+++ src/docker_clojure/core.clj
@@ -120,7 +120,10 @@

 (defn build-image [{:keys [docker-tag dockerfile build-dir base-image] :as variant}]
   (let [image-tag (str "clojure:" docker-tag)
-        build-cmd ["docker" "build" "--no-cache" "-t" image-tag "-f" dockerfile "."]]
+        ;; TODO: Build for all appropriate platforms instead of just linux/amd64.
+        ;;       alpine & JDK 8 won't build for arm64.
+        build-cmd ["docker" "build" "--no-cache" "--platform" "linux/amd64"
+                   "-t" image-tag "-f" dockerfile "."]]
     (println "Pulling base image" base-image)
     (pull-image base-image)
     (df/write-file build-dir dockerfile variant)


jail type and making machine common

jail type and making machine common

--- src/freenas/validations.clj
+++ src/freenas/validations.clj
@@ -21,11 +21,15 @@
   (when-not-nil (partial re-find #"\d+\.\d+\.\d+\.\d+\/\d\d") "must be a legal netmask"))

-(def machine-entity
+(def machine-common
   {:hostname #{:required :String} :ip #{:required :String :ip}
-   :netmask #{:required :String :netmask} :mac #{:required :mac}
+   :netmask #{:required :String} :mac #{:required :mac}
   })

+(def jail-type #{:standard :pluginjail :portjail})
+
+(validation :jail-type
+  (when-not-nil jail-type (<< "Jail type must be either ~{jail-type}")))

 (def freenas
   {:freenas {
@@ -35,13 +39,13 @@

 (defn validate-entity
   "freenas based system entity validation for persistence layer"
-  [{:keys [machine freenas] :as spec}]
-  (validate! spec (combine machine-entity freenas) :error ::invalid-system))
+  [spec]
+  (validate! spec (combine {:machine machine-common} freenas) :error ::invalid-system))

 (def jail-mappings {
   :ip :jail_ipv4 :hostname :jail_host :netmask :jail_ipv4_netmask
    :mac :jail_mac :type :jail_type :flags :jail_flags })

 (defn validate-provider [spec]
-  (validate! spec (combine (mappings machine-entity jail-mappings))  :error ::invalid-jail))
+  (validate! spec (combine (mappings machine-common jail-mappings))  :error ::invalid-jail))


[#21] Removed config from component

[#21] Removed config from component

--- backend/src/org/akvo/dash/config.clj
+++ backend/src/org/akvo/dash/config.clj
@@ -5,5 +5,6 @@
   ^:displace {:http {:port 3000}})

 (def environ
-  {:http {:port (some-> env :port Integer.)}
+  {:http {:port (some-> env :port Integer.)
+          :path "api"}
    :db   {:uri  (env :database-url)}})


add obj-map benchmarks, add -lookup benchmark for array-map

--- benchmark/cljs/benchmark_runner.cljs
+++ benchmark/cljs/benchmark_runner.cljs
@@ -78,8 +78,15 @@
 (simple-benchmark [coll (into [] (range 1000000))] (apply + coll) 1)
 (println)

+(println ";;; obj-map")
+(simple-benchmark [coll (obj-map)] (assoc coll :foo 'bar) 1000000)
+(simple-benchmark [coll (obj-map :foo :bar)] (-lookup coll :foo) 1000000)
+(println)
+
 (println ";;; array-map")
 (simple-benchmark [coll (array-map)] (assoc coll :foo 'bar) 1000000)
+(simple-benchmark [coll (array-map :foo :bar)] (-lookup coll :foo) 1000000)
+(println)

 (println ";;; map / record ops")
 (simple-benchmark [coll {:foo 1 :bar 2}] (get coll :foo) 1000000)


Updating fx definitions now that synths are automatically loaded when connected to scsynth.

--- src/overtone/studio/fx.clj
+++ src/overtone/studio/fx.clj
@@ -4,51 +4,49 @@
   overtone.studio.fx
   (:use (overtone.core synth ugen event)))

-(on :connected (fn []
-                 (defsynth fx-noise-gate [in-bus 10 out-bus 0 threshold 0.4
-                                       slope-below 1 slope-above 0.1
-                                       clamp-time 0.01 relax-time 0.1]
-                   (let [source (in in-bus)]
-                     (out out-bus
-                          (compander source source threshold
-                                     slope-below slope-above
-                                     clamp-time relax-time))))
+(defsynth fx-noise-gate [in-bus 10 out-bus 0 threshold 0.4
+                         slope-below 1 slope-above 0.1
+                         clamp-time 0.01 relax-time 0.1]
+  (let [source (in in-bus)]
+    (out out-bus
+         (compander source source threshold
+                    slope-below slope-above
+                    clamp-time relax-time))))

-                 (defsynth fx-compressor [in-bus 10 out-bus 0 threshold 0.2
-                                       slope-below 1 slope-above 0.5
-                                       clamp-time 0.01 relax-time 0.01]
-                   (let [source (in in-bus)]
-                     (out out-bus
-                          (compander source source threshold
-                                     slope-below slope-above
-                                     clamp-time relax-time))))
+(defsynth fx-compressor [in-bus 10 out-bus 0 threshold 0.2
+                         slope-below 1 slope-above 0.5
+                         clamp-time 0.01 relax-time 0.01]
+  (let [source (in in-bus)]
+    (out out-bus
+         (compander source source threshold
+                    slope-below slope-above
+                    clamp-time relax-time))))

-                 (defsynth fx-limiter [in-bus 10 out-bus 0 threshold 0.2
-                                    slope-below 1 slope-above 0.1
-                                    clamp-time 0.01 relax-time 0.01]
-                   (let [source (in in-bus)]
-                     (out out-bus
-                          (compander source source threshold
-                                     slope-below slope-above
-                                     clamp-time relax-time))))
+(defsynth fx-limiter [in-bus 10 out-bus 0 threshold 0.2
+                      slope-below 1 slope-above 0.1
+                      clamp-time 0.01 relax-time 0.01]
+  (let [source (in in-bus)]
+    (out out-bus
+         (compander source source threshold
+                    slope-below slope-above
+                    clamp-time relax-time))))

-                 (defsynth fx-sustainer [in-bus 10 out-bus 0 threshold 0.2
-                                      slope-below 1 slope-above 0.5
-                                      clamp-time 0.01 relax-time 0.01]
-                   (let [source (in in-bus)]
-                     (out out-bus
-                          (compander source source threshold
-                                     slope-below slope-above
-                                     clamp-time relax-time))))
+(defsynth fx-sustainer [in-bus 10 out-bus 0 threshold 0.2
+                        slope-below 1 slope-above 0.5
+                        clamp-time 0.01 relax-time 0.01]
+  (let [source (in in-bus)]
+    (out out-bus
+         (compander source source threshold
+                    slope-below slope-above
+                    clamp-time relax-time))))

-                 (defsynth fx-reverb [in-bus 10 out-bus 0
-                                   wet-dry 0.5 room-size 0.5 dampening 0.5]
-                   (out out-bus
-                        (free-verb (in in-bus) wet-dry room-size dampening)))
+(defsynth fx-reverb [in-bus 10 out-bus 0
+                     wet-dry 0.5 room-size 0.5 dampening 0.5]
+  (out out-bus
+       (free-verb (in in-bus) wet-dry room-size dampening)))

-                 (defsynth fx-echo [in-bus 10 out-bus 0
-                                 max-delay 0.5 delay-time 0.2 decay-time 2.0]
-                   (let [source (in in-bus)
-                         echo (comb-n source max-delay delay-time decay-time)]
-                     (out out-bus (pan2 (+ echo source) 0))))
-))
+(defsynth fx-echo [in-bus 10 out-bus 0
+                   max-delay 0.5 delay-time 0.2 decay-time 2.0]
+  (let [source (in in-bus)
+        echo (comb-n source max-delay delay-time decay-time)]
+    (out out-bus (pan2 (+ echo source) 0))))


fix om-app cursor reset

fix om-app cursor reset

--- src-cljs/frontend/components/app.cljs
+++ src-cljs/frontend/components/app.cljs
@@ -38,7 +38,7 @@
             right-click-learned? (get-in app state/right-click-learned-path)]
         (html [:div.inner {:on-click (when (overlay-visible? app)
                                           #(cast! :overlay-closed))}
-               [:style "#om-app:active {cursor: default;}"]
+               [:style "#om-app:active{cursor:auto}"]
                [:div.canvas-background]
                [:div.canvas {:onContextMenu (fn [e]
                                                  (.preventDefault e)


NM|ME: download link to redirect to s3

NM|ME: download link to redirect to s3

--- src/hatti/views/photos.cljs
+++ src/hatti/views/photos.cljs
@@ -81,8 +81,6 @@
                             (js-obj "x" (.-left rect)
                                     "y" (+ (.-top rect) page-y-scroll)
                                     "w" (.-width rect))))
-                        "getImageURLForShare"
-                        (fn [share-button-data] (full-url-from-active-image))
                         "addCaptionHTMLFn"
                         (fn [item caption-el is-fake]
                           (set! (-> caption-el .-children first .-innerHTML)
@@ -91,6 +89,11 @@
                                 js/PhotoSwipeUI_Default
                                 (clj->js photos)
                                 options)]
+    (set! (.. gallery
+              -options
+              -getImageURLForShare)
+          (fn [share-button-data]
+            (or (aget gallery "currItem" "original-src") "")))
     (.init gallery)))

 (defn- on-thumbnail-click


Version 0.9.1-SNAPSHOT

Version 0.9.1-SNAPSHOT

--- project.clj
+++ project.clj
@@ -1,4 +1,4 @@
-(defproject re-frame "0.9.0"
+(defproject re-frame "0.9.1-SNAPSHOT"
   :description  "A Clojurescript MVC-like Framework For Writing SPAs Using Reagent."
   :url          "https://github.com/Day8/re-frame.git"
   :license      {:name "MIT"}


Version 2.15.3-1-SNAPSHOT [ci skip]

Version 2.15.3-1-SNAPSHOT [ci skip]

--- project.clj
+++ project.clj
@@ -1,5 +1,5 @@

-(defproject clojush "2.15.3"
+(defproject clojush "2.15.3-1-SNAPSHOT"
   :description "The Push programming language and the PushGP genetic programming
                 system implemented in Clojure.
                 See http://pushlanguage.com"


Release v0.2.0.

Release v0.2.0.

--- project.clj
+++ project.clj
@@ -1,4 +1,4 @@
-(defproject com.keminglabs/c2 "0.2.0-SNAPSHOT"
+(defproject com.keminglabs/c2 "0.2.0"
   :description "Declarative data visualization in Clojure(Script)."
   :url "http://keminglabs.com/c2/"
   :license {:name "BSD" :url "http://www.opensource.org/licenses/BSD-3-Clause"}


Bump to 0.2.2-S

Bump to 0.2.2-S

--- project.clj
+++ project.clj
@@ -1,4 +1,4 @@
-(defproject yetibot.core "0.2.1"
+(defproject yetibot.core "0.2.2-SNAPSHOT"
   :description "Core yetibot utilities, extracted for shared use among yetibot
                 and its various plugins"
   :url "https://github.com/devth/yetibot.core"


Update buddy-sign to 0.8.1.

Update buddy-sign to 0.8.1.

--- project.clj
+++ project.clj
@@ -4,7 +4,7 @@
   :license {:name "Apache 2.0"
             :url "http://www.apache.org/licenses/LICENSE-2.0"}
   :dependencies [[org.clojure/clojure "1.7.0" :scope "provided"]
-                 [buddy/buddy-sign "0.8.0"]
+                 [buddy/buddy-sign "0.8.1"]
                  [funcool/cuerdas "0.6.0"]
                  [clout "2.1.2"]]
   :source-paths ["src"]


Update project.clj.

Update project.clj.

--- project.clj
+++ project.clj
@@ -1,6 +1,6 @@
 (defproject lein-xjc "0.1.0-SNAPSHOT"
-  :description "FIXME: write description"
-  :url "http://example.com/FIXME"
+  :description "Call xjc from leiningen."
+  :url "http://lein-xjc.ferdinandhofherr.de"
   :license {:name "Eclipse Public License"
             :url "http://www.eclipse.org/legal/epl-v10.html"}
   :eval-in-leiningen true)


Back to dev version

Back to dev version

--- project.clj
+++ project.clj
@@ -1,4 +1,4 @@
-(defproject clojurewerkz/cassaforte "1.3.0-beta2"
+(defproject clojurewerkz/cassaforte "1.3.0-beta3-SNAPSHOT"
   :min-lein-version "2.0.0"
   :description "A Clojure client for Apache Cassandra"
   :url "http://clojurecassandra.info"


Revert "Update jetty test dependencies"

Revert "Update jetty test dependencies"

This reverts commit 3436f25988e78ec6b402e3a59f1d9f619282c1d9 due
to exceptions when testing under Java 7

--- project.clj
+++ project.clj
@@ -12,9 +12,9 @@
              :1.4.0 {:dependencies [[org.clojure/clojure "1.4.0"]]}
              :1.5.1 {:dependencies [[org.clojure/clojure "1.5.1"]]}
              :dev {:resource-paths ["test-resources"],
-                   :dependencies [[org.eclipse.jetty/jetty-server "9.3.0.RC1"]
-                                  [org.eclipse.jetty/jetty-security "9.3.0.RC1"]
-                                  [org.eclipse.jetty/jetty-continuation "9.3.0.RC1"]
+                   :dependencies [[org.eclipse.jetty/jetty-server "9.3.0.RC0"]
+                                  [org.eclipse.jetty/jetty-security "9.3.0.RC0"]
+                                  [org.eclipse.jetty/jetty-continuation "9.3.0.RC0"]
                                   [log4j "1.2.17"]
                                   [org.slf4j/slf4j-log4j12 "1.7.12"]]}}
   ;; :repositories {"snapshots" "http://oss.sonatype.org/content/repositories/snapshots/"}


Enable the previous month arrow so that you can get to the current month after moving forward

Conflicts:
	src/re_com/datepicker.cljs

--- src/re_com/datepicker.cljs
+++ src/re_com/datepicker.cljs
@@ -93,7 +93,7 @@
   ;;TODO: We might choose later to style by removing arrows altogether instead of greying when disabled navigation
   (let [style         (fn [week-day] {:class (if (enabled-days week-day) "day-enabled" "day-disabled")})
         prev-date     (dec-month @current)
-        prev-enabled? (if minimum (after? prev-date minimum) true)
+        prev-enabled? (if minimum (after? prev-date (dec-month minimum)) true)
         next-date     (inc-month @current)
         next-enabled? (if maximum (before? next-date maximum) true)
         template-row  (if show-weeks? [:tr [:th]] [:tr])]


Apply no-select style on welcome page

Apply no-select style on welcome page

--- frontend/src/faceboard/views/welcome.cljs
+++ frontend/src/faceboard/views/welcome.cljs
@@ -12,9 +12,9 @@
     (let [ui (:ui data)]
       (page/page-skeleton
         (dom/div {:class "standard-page welcome"}
-          (dom/div {:class "big-logo"}
+          (dom/div {:class "big-logo no-select"}
             (dom/span {} "FACEBOARD"))
-          (dom/div {:class "teaser"}
+          (dom/div {:class "teaser no-select"}
             (dom/img {:src "images/faceboard-teaser.jpg"}))
           (dom/div {:class "buttons"}
             (dom/span {:class "button"


Enable a workaround to make fineuploader with with alternative storage providers

--- web-app/src/cljs/potato/fineuploader.cljs
+++ web-app/src/cljs/potato/fineuploader.cljs
@@ -37,7 +37,7 @@
 (defn create-fine-uploader-s3 [instance-callback current-user-id current-channel-id]
   ;; Workaround for a bug in fineuploader that prevents it from using
   ;; the "bucket" key in the "request" struct.
-  ;;(set! js/qq.s3.util.getBucket (fn [_] (:bucket potato.state/init-s3-credentials)))
+  (set! js/qq.s3.util.getBucket (fn [_] (:bucket potato.state/init-s3-credentials)))
   ;;
   (new js/qq.s3.FineUploaderBasic
        (clj->js {"request"          {"endpoint"  (:endpoint potato.state/init-s3-credentials)


Add support for multi ref-loci Tn-Seq; fix offset capital letter bug

--- src/aerobio/htseq/tnseq.clj
+++ src/aerobio/htseq/tnseq.clj
@@ -191,15 +191,46 @@
      otmap otbam otbai]))

+
+
 (def offsets
   (let [llets "abcdefghijklmnopqrstuvwxyz"
-        offset (-> "a" str/codepoints first dec)
-        chints (mapv #(- % offset) (str/codepoints llets))
+        ulets (cljstr/upper-case llets)
+        loffset (-> "a" str/codepoints first dec)
+        lchints (mapv #(- % loffset) (str/codepoints llets))
+        uoffset (-> "A" str/codepoints first dec)
+        uchints (mapv #(- % uoffset) (str/codepoints ulets))
         offmap (into {} (map
                          (fn[[k v]] [(str k) v])
-                         (partition 2 (interleave (seq llets) chints))))
+                         (partition 2 (interleave (seq llets) lchints))))
+        offmap (into offmap (map
+                             (fn[[k v]] [(str k) v])
+                             (partition 2 (interleave (seq ulets) uchints))))
         offmap (into offmap (map #(vector (str %) %) (range 1 27)))]
     offmap))
+
+(defn expand-by-refs [grp refnms]
+  (mapv (fn[refnm]
+          (let [[_ tcsv] (last grp)
+                tdir (fs/dirname tcsv)
+                tfname (str refnm "-" (fs/basename tcsv))
+                pairs (butlast grp)]
+            (conj
+             (mapv (fn [[ag ft]]
+                     (let [agdir (fs/dirname ag)
+                           ftdir (fs/dirname ft)
+                           fname (str refnm "-" (fs/basename ft))]
+                       [(fs/join agdir fname)
+                        (fs/join ftdir fname)]))
+                   pairs)
+             [refnm (fs/join tdir tfname)])))
+        refnms))
+
+(defn refloci [refnm refdir]
+  (->> (str refnm ".gtf") (fs/join refdir)
+       slurp (#(csv/read-csv % :separator \tab))
+       (reduce (fn [S [nm & tail]] (conj S nm)) #{})
+       sort))

 (defn get-comparison-files-
   "Compute the set of comparison pairs for tnseq fitness
@@ -212,7 +243,8 @@
   ([eid aggr?]
    (get-comparison-files- eid "ComparisonSheet.csv" aggr?))
   ([eid comp-filename aggr?]
-   (let [maps (cmn/get-exp-info eid :rep :maps)
+   (let [refs (cmn/get-exp-info eid :refs)
+         maps (cmn/get-exp-info eid :rep :maps)
          fit  (cmn/get-exp-info eid :rep :fit)
          aggr (cmn/get-exp-info eid :rep :aggrs)
          compvec (->> comp-filename
@@ -241,29 +273,57 @@
                                     (conj v csv ef (offsets k))))
                                 %1))
                        mapsvec
-                       compvec)]
+                       compvec)
+         refinfo (volatile! {})]
      (if aggr?
-       (mapv (fn[grp]
-               (when (seq grp)
-                 (let [grp (sort-by last grp)
-                       l (->> grp last first fs/basename (str/split #"-")
-                              last (str/split #"\.") first)
-                       g (mapv (fn[[_ _ csv _]]
-                                 [(fs/join aggr csv) (fs/join fit csv)])
-                               grp)
-                       allcsv (->> g first first
-                                   (#(fs/replace-type % (str "-" l ".csv"))))]
-                   (conj g allcsv))))
-             cmpgrps)
+       (->>
+        cmpgrps
+        (mapcat (fn[grp]
+                  (when (seq grp)
+                    (let [grp (sort-by last grp)
+                          l (->> grp last first fs/basename (str/split #"-")
+                                 last (str/split #"\.") first)
+                          g (mapv (fn[[_ _ csv _]]
+                                    [(fs/join aggr csv) (fs/join fit csv)])
+                                  grp)
+                          strain-map (cmn/get-exp-info eid :ncbi-sample-xref)
+                          refnm (-> g ffirst fs/basename
+                                    (cljstr/split #"-") first
+                                    strain-map)
+                          allcsv (-> g first first
+                                     (fs/replace-type (str "-" l ".csv")))
+                          newgrp (conj g [refnm allcsv])]
+                      (when (not (@refinfo refnm))
+                        (vswap! refinfo
+                                (fn[refm]
+                                  (assoc refm refnm (refloci refnm refs)))))
+                      (if (> (count (@refinfo refnm)) 1)
+                        (expand-by-refs newgrp (@refinfo refnm))
+                        [newgrp])))))
+        vec)
        ;; else fitness groups
        (mapcat (fn[grp]
                  (mapv (fn[[t1 t2 csv ef]] [t1 t2 (fs/join fit csv) ef]) grp))
                cmpgrps)
        ))))

+#_(let [eid "JSA-TEST-MULTI-TNSEQ"
+      compfile "ComparisonSheet.csv"
+      refdir (cmn/get-exp-info eid :refs)
+      grps (cmn/get-comparison-files :tnseq eid compfile true)
+      grp (first grps)
+      pairs (butlast grp)
+      allins (mapv second pairs)
+      [refnm allcsv] (last grp)
+      gtf (fs/join refdir (str refnm ".gbk"))
+      norm   (fs/join refdir "NormGenes" (str refnm ".txt"))]
+  [gtf norm])
+
 (defmethod cmn/get-comparison-files :tnseq
   [_ & args]
   (apply get-comparison-files- args))
+
+

 (defn get-phase-2-dirs [eid]


Add TODO for future work.

Add TODO for future work.

--- src/afterglow/transform.clj
+++ src/afterglow/transform.clj
@@ -78,6 +78,10 @@
   [deg]
   (* (/ deg 180) Math/PI))

+;; TODO: Today we are considering the heads to be in a fixed location relative to
+;;       the fixture. Someday this needs to be generalized to cope with fixtures
+;;       with multiple heads where the base fixture can pan and tilt, moving the
+;;       heads themselves, which can then individually pan and tilt.
 (defn- transform-head
   "Determine the position and orientation of a fixture's head."
   [fixture head]


migrate measurements to new partitioned_measurements CF

--- dev/migrate.clj
+++ dev/migrate.clj
@@ -12,7 +12,7 @@
   [f & lists]
   (apply mapv f lists) nil)

-(defn convert-metadata
+(defn convert-metadata
   "Reads stringified metadata into a clojure map."
   [m]
   (let [metadata (:metadata m)]
@@ -20,7 +20,7 @@
       (clojure.walk/stringify-keys (read-string metadata))
       nil)))

-(defn migrate-reading-metadata
+(defn migrate-reading-metadata
   "Works on a lazy sequence of all measurements for all sensors in the database and
   populates (new) reading_metadata with data coming from (old) metadata."
   [{:keys [store]}]
@@ -30,14 +30,14 @@
       (doseq [s sensors]
         (let [measurements (measurements/all-measurements store s)]
           (when measurements
-            (doseq [m measurements]
+            (doseq [m measurements]
                (db/execute session
-                           (hayt/update :measurements
-                                        (hayt/set-columns :reading_metadata (convert-metadata m))
-                                        (hayt/where [[= :device_id (:device_id m)]
-                                                     [= :type (:type m)]
-                                                     [= :month (:month m)]
-                                                     [= :timestamp (:timestamp m)]])))))))))
+                           (hayt/update :partitioned_measurements
+                                        (hayt/values {:device_id (:device_id m)
+                                                      :type (:type m)
+                                                      :month (:month m)
+                                                      :timestamp (:timestamp m)
+                                                      :reading_metadata (convert-metadata m)})))))))))
   (log/info "Finished migrating reading metadata."))

 (defn fill-sensor-bounds


refactor(core): make code more readable

refactor(core): make code more readable

--- src/asset_minifier/core.clj
+++ src/asset_minifier/core.clj
@@ -1,5 +1,6 @@
 (ns asset-minifier.core
   (:require [clojure.java.io :refer [file reader writer make-parents]]
+            [clojure.string :as string]
             [clj-html-compressor.core :as html-comressor])
   (:import com.yahoo.platform.yui.compressor.CssCompressor
            java.util.zip.GZIPOutputStream
@@ -16,33 +17,38 @@
             SourceFile
             CompilerOptions$LanguageMode]))

+(def js ".js")
+(def css ".css")
+(def html ".html")
+(def gz ".gz")
+
 (defn- delete-target [target]
   (let [f (file target)]
     (when (.exists f)
       (.delete f))
     (make-parents f)))

-(defn- find-assets [f ext]
-  (if (.isDirectory f)
-    (->> f
-         file-seq
-         (filter (fn [file] (-> file .getName (.endsWith ext)))))
-    [f]))
+(defn- find-assets [folder ext]
+  (if (not (.isDirectory folder))
+    [folder]
+    (->> folder
+         (file-seq)
+         (filter #(string/ends-with? (.getName %) ext)))))

-(defn- aggregate [path ext]
-  (if (coll? path)
-    (flatten
-     (for [item path]
-       (let [f (file item)]
-         (find-assets f ext))))
-    (let [f (file path)]
-      (find-assets f ext))))
+(defn- aggregate [paths ext]
+  (if (not (coll? paths))
+    (aggregate [paths] ext)
+    (->> paths
+         (map #(find-assets (file %) ext))
+         (flatten))))

 (defn total-size [files]
-  (->> files (map #(.length %)) (apply +)))
+  (->> files
+       (map #(.length %))
+       (apply +)))

 (defn- create-temp-file [source]
-  (File/createTempFile (.getName source) ".gz"))
+  (File/createTempFile (.getName source) gz))

 (defn- create-temp-files [sources]
   (map create-temp-file sources))
@@ -81,12 +87,14 @@
 (defn minify-css-input [source target {:keys [linebreak] :or {linebreak -1}}]
   (with-open [rdr (reader source)
               wrt (writer target)]
-    (-> rdr (CssCompressor.) (.compress wrt linebreak))))
+    (-> rdr
+        (CssCompressor.)
+        (.compress wrt linebreak))))

 (defn minify-css [path target & [opts]]
   (delete-target target)
-  (let [assets (aggregate path ".css")
-        tmp    (File/createTempFile "temp-sources" ".css")
+  (let [assets (aggregate path css)
+        tmp    (File/createTempFile "temp-sources" css)
         target (file target)]
     (with-open [wrt (writer tmp :append true)]
       (doseq [file assets]
@@ -139,12 +147,12 @@
                                       optimization :simple}}]]
   (delete-target target)
   (if (= :none optimization)
-    (merge-files (aggregate path ".js") target)
+    (merge-files (aggregate path js) target)
     (do
       (if quiet?
         (com.google.javascript.jscomp.Compiler/setLoggingLevel Level/OFF)
         (com.google.javascript.jscomp.Compiler/setLoggingLevel Level/SEVERE))
-      (let [assets   (aggregate path ".js")
+      (let [assets   (aggregate path js)
             compiler (com.google.javascript.jscomp.Compiler.)
             result   (compile-js compiler assets externs optimization language)]
         (spit target (.toSource compiler))
@@ -158,10 +166,10 @@

 (defn minify-html [path target opts]
   (delete-target target)
-  (let [assets (aggregate path ".html")]
+  (let [assets (aggregate path html)]
     (doseq [asset assets]
       (minify-html-asset asset target opts))
-    (compression-details assets (aggregate target ".html"))))
+    (compression-details assets (aggregate target html))))

 (defn minify
   "assets are specified using a map where the key is the output file and the value is the asset paths, eg:
@@ -174,6 +182,6 @@
         (for [[target path] assets]
           [[path target]
            (cond
-             (.endsWith target ".js")  (minify-js path target opts)
-             (.endsWith target ".css") (minify-css path target opts)
+             (.endsWith target js)  (minify-js path target opts)
+             (.endsWith target css) (minify-css path target opts)
              :else (throw (ex-info "unrecognized target" target)))])))


adding types

adding types

--- src/celestial/hosts_api.clj
+++ src/celestial/hosts_api.clj
@@ -132,6 +132,9 @@

 (defroutes- type {:path "/type" :description "Operations on types"}

+  (GET- "/types" [] {:nickname "getTypes" :summary "Get all types"}
+        (success {:types (map p/get-type (p/all-types))}))
+
   (GET- "/types/:type" [^:string type] {:nickname "getType" :summary "Get type"}
         (success (p/get-type type)))

@@ -148,7 +151,7 @@
                 (success {:msg "type updated"})))))

   (DELETE- "/types/:type" [^:string type] {:nickname "deleteType" :summary "Delete type"
-                                          :errorResponses (errors {:bad-req "Type does not exist"})}
+                                           :errorResponses (errors {:bad-req "Type does not exist"})}
            (if (p/type-exists? type)
              (do (p/delete-type type)
                  (success {:msg "Type deleted"}))