buildcheck: vcproj -> vcxproj.

buildcheck: vcproj -> vcxproj.

Might still be broken where it attempts to read the contents of .vcxproj files.

git-svn-id: 03a8048b5ee8463be5048a3801110fb50f378627@11970 d0ab736e-dc22-4aeb-8dc9-08def0aa14fd

--- buildscripts/buildcheck/src/buildcheck/core.clj
+++ buildscripts/buildcheck/src/buildcheck/core.clj
@@ -60,23 +60,19 @@
     (filter #(.. % getName (endsWith ending))
             (mapcat file-seq parent-dirs))))

-(defn missing-vcproj []
+(defn missing-vcxproj []
   (let [device-adapter-dirs (device-adapter-dirs)
-        directories-without-vcproj
+        directories-without-vcxproj
         (filter identity
                 (for [device-adapter-dir device-adapter-dirs]
-                  (when (empty? (filter #(.. % getName (endsWith ".vcproj"))
+                  (when (empty? (filter #(.. % getName (endsWith ".vcxproj"))
                                         (file-seq device-adapter-dir)))
                     device-adapter-dir)))]
         (sort
           (clojure.set/difference
-            (set (map #(.getName %) directories-without-vcproj))
+            (set (map #(.getName %) directories-without-vcxproj))
             (do-not-build)
             non-windows-device-adapters))))
-
-(defn device-vcproj-files []
-    (filter #(.. % getName (endsWith ".vcproj"))
-            (mapcat file-seq device-adapter-parent-dirs)))

 (defn device-vcxproj-files []
     (filter #(.. % getName (endsWith ".vcxproj"))
@@ -85,10 +81,10 @@
 (defn dll-name [file]
   (second (re-find #"mmgr_dal_(.*?).dll" (.getName file))))

-(defn project-name [vcproj-file]
+(defn project-name [vcxproj-file]
   (try
-    (-> vcproj-file clojure.xml/parse :attrs :Name)
-    (catch Exception e (println vcproj-file))))
+    (-> vcxproj-file clojure.xml/parse :attrs :Name)
+    (catch Exception e (println vcxproj-file))))

 (defn dll-dir [bits]
   (File. micromanager
@@ -99,23 +95,23 @@
 (defn get-dll-names [bits]
   (map dll-name (device-adapter-dlls (dll-dir bits))))

-(def helper-vcprojs #{"DEClientLib" "DEMessaging"})
+(def helper-vcxprojs #{"DEClientLib" "DEMessaging"})

 (defn missing-device-adapters [bits]
   (let [dll-names (get-dll-names bits)
         project-names (map project-name (filter #(not (.. % getAbsolutePath (contains "_ATTIC")))
-                                          (device-vcproj-files)))]
+                                          (device-vcxproj-files)))]
     (sort (clojure.set/difference (set project-names)
                                   #{nil}
                                   (set dll-names)
                                   (do-not-build)
-                                  helper-vcprojs))))
+                                  helper-vcxprojs))))

 (defn all-devices []
   (let [dll-names (get-dll-names 32)]
         (clojure.set/difference
           (clojure.set/union (set non-windows-device-adapters)
-                             (missing-vcproj)
+                             (missing-vcxproj)
                              (set dll-names))
           (do-not-build))))

@@ -155,13 +151,13 @@
   (let [installer32-ok (exe-on-server? 32 today-token)
         installer64-ok (exe-on-server? 64 today-token)
         mac-ok (mac-build-on-server? today-token)
-        missing-vcproj-files (missing-vcproj)
+        missing-vcxproj-files (missing-vcxproj)
         missing-links (missing-device-links)]
     (when-not (and (not testmode)
                    installer32-ok
                    installer64-ok
                    mac-ok
-                   (empty? missing-vcproj-files)
+                   (empty? missing-vcxproj-files)
                    (empty? missing-links))
       (str
         "MICROMANAGER BUILD STATUS REPORT\n"
@@ -171,7 +167,7 @@
         (if installer64-ok "Yes." "No. (build missing)\n")
         "\n\nIs Mac installer download available on website?\n"
         (if mac-ok "Yes." "No. (build missing)\n")
-        (report-segment "Missing .vcproj files" missing-vcproj-files)
+        (report-segment "Missing .vcxproj files" missing-vcxproj-files)
         (report-segment "Uncompiled device adapters (Win32)" (missing-device-adapters 32))
         (report-segment "Uncompiled device adapters (x64)" (missing-device-adapters 64))
         (report-segment "Missing device links" missing-links)
@@ -217,29 +213,29 @@
   (dorun (map #(replace-in-file! % pat new-val) files)))

 (defn fix-output-file-tags!
-  "Fix the dll output path specified in all vcproj files."
+  "Fix the dll output path specified in all vcxproj files."
   []
-  (replace-in-files! (device-vcproj-files)
+  (replace-in-files! (device-vcxproj-files)
                     #"\$\(OutDir\)/.+?\.dll" "\\$(OutDir)/mmgr_dal_\\$(ProjectName).dll"))

-(defn find-copy-step [vcproj]
-  (re-find #"\"copy .+?\"" (slurp vcproj)))
-
-(defn bad-copy-step [vcproj]
-  (not (.contains (or (find-copy-step vcproj) "PlatformName") "PlatformName")))
+(defn find-copy-step [vcxproj]
+  (re-find #"\"copy .+?\"" (slurp vcxproj)))
+
+(defn bad-copy-step [vcxproj]
+  (not (.contains (or (find-copy-step vcxproj) "PlatformName") "PlatformName")))

 (defn all-bad-copy-steps
-  "Find all vcproj files with a bad post-build copy step"
+  "Find all vcxproj files with a bad post-build copy step"
   []
-  (filter bad-copy-step (device-vcproj-files)))
-
-(defn find-pdb [vcproj]
-  (re-find #"\".*?\.pdb\"" (slurp vcproj)))
+  (filter bad-copy-step (device-vcxproj-files)))
+
+(defn find-pdb [vcxproj]
+  (re-find #"\".*?\.pdb\"" (slurp vcxproj)))

 (defn fix-pdb-file-tags!
-  "Fix the pdb file path specified in all vcproj files."
+  "Fix the pdb file path specified in all vcxproj files."
   []
-  (replace-in-files! (device-vcproj-files)
+  (replace-in-files! (device-vcxproj-files)
                     #"\".*?\.pdb\"" "\"\\$(OutDir)/\\$(ProjectName).pdb\""))


Prevent message handling in Slack for yetibot's own messages

--- src/yetibot/core/adapters/slack.clj
+++ src/yetibot/core/adapters/slack.clj
@@ -20,6 +20,12 @@
 (defn config [] (get-config :yetibot :adapters :slack))

 (defonce conn (atom nil))
+
+(defn self
+  "Slack acount for yetibot from `rtm.start` (represented at (-> @conn :start)).
+   You must call `start` in order to define `conn`."
+  []
+  (-> @conn :start :self))

 (defn slack-config []
   (let [c (config)]
@@ -53,14 +59,16 @@
 ;; events

 (defn on-message [event]
-  (log/info "message" event)
-  (let [channel (:channel event)]
-    (binding [*target* channel
-              yetibot.core.chat/*messaging-fns* messaging-fns]
-      (handle-raw (chat-source channel)
-                  (:user event)
-                  :message
-                  (:text event)))))
+  ;; don't listen to yetibot's own messages
+  (when (not= (:id (self)) (:user event))
+    (log/info "message" event)
+    (let [channel (:channel event)]
+      (binding [*target* channel
+                yetibot.core.chat/*messaging-fns* messaging-fns]
+        (handle-raw (chat-source channel)
+                    (:user event)
+                    :message
+                    (:text event))))))

 (defn on-hello [event]
   (log/info "hello" event))


Fix read-related

Fix read-related

This patch corrects the behavior of read-related so that it will parse a
Grimoire 0.3.X file of fully qualified symbols correctly rather than
assuming related files are filled with Thing URIs

--- src/grimoire/api/fs.clj
+++ src/grimoire/api/fs.clj
@@ -172,14 +172,21 @@
           edn/read-string))))

 (defmethod api/read-related :filesystem [config thing]
+  ;; FIXME: This assumes the old Grimoire 0.3.X related file format,
+  ;; being a sequence of fully qualified symbols not Thing URIs. Will
+  ;; work, but not optimal in terms of utility going forwards.
+
   (let [thing  (ensure-thing thing)]
     (for [thing (api/thing->prior-versions config thing)
           :let  [v (:name (thing->version thing))
                  h (thing->related-handle config thing)]
           :when (.exists h)
           :when (.isFile h)
-          line  (line-seq (io/reader h))]
-      (path->thing line))))
+          line  (line-seq (io/reader h))
+          :let  [sym (read-string line)]]
+      (-> thing
+          (->Ns  (namespace sym))
+          (->Def (name sym))))))

 ;; Interacting with the datastore - writing
 ;;--------------------------------------------------------------------


Added optimization for literal tag with unknown body

--- src/hiccup/compiler.clj
+++ src/hiccup/compiler.clj
@@ -112,7 +112,7 @@

 (declare compile-html)

-(defn- compile-partial
+(defn- compile-lit-tag+attrs
   "Compile an element when only the tag and attributes are literal."
   [tag attrs content]
   (let [[tag attrs _] (parse-element [tag attrs])]
@@ -122,16 +122,38 @@
             ~(str "</" tag ">"))
        (str "<" tag (make-attrs attrs) " />"))))

+(defn compile-lit-tag
+  "Compile an element when only the tag is literal."
+  [tag [attrs & content :as element]]
+  (let [[tag tag-attrs _] (parse-element [tag])]
+    `(if (map? ~attrs)
+       ~(if (or content (container-tags tag))
+          `(str ~(str "<" tag) (make-attrs (merge ~tag-attrs ~attrs)) ">"
+                ~@(compile-html content)
+                ~(str "</" tag ">"))
+          `(str ~(str "<" tag) (make-attrs (merge ~tag-attrs ~attrs)) "/>"))
+       ~(if (or element (container-tags tag))
+          `(str ~(str "<" tag ">")
+                ~@(compile-html element)
+                ~(str "</" tag ">"))
+           (str "<" tag " />")))))
+
 (defn- compile-tag
   "Pre-compile a single tag vector where possible."
   [[tag attrs & content :as element]]
   (cond
+    ;; e.g. [:span "foo"]
     (every? literal? element)
       (render-tag (eval element))
+    ;; e.g. [:span {} x]
     (and (literal? tag) (map? attrs))
-      (compile-partial tag attrs content)
+      (compile-lit-tag+attrs tag attrs content)
+    ;; e.g. [:span #^String x]
     (and (literal? tag) (or (not (uneval? attrs)) (not-hint? attrs Map)))
-      (compile-partial tag {} (cons attrs content))
+      (compile-lit-tag+attrs tag {} (cons attrs content))
+    ;; e.g. [:span x]
+    (literal? tag)
+      (compile-lit-tag tag (cons attrs content))
     :else
       `(render-tag
          [~(first element)


Remove unused/weird stroll function

Remove unused/weird stroll function

--- src/hildebrand/util.clj
+++ src/hildebrand/util.clj
@@ -2,27 +2,6 @@
   (:require [clojure.set :as set]
             [plumbing.core :refer :all])
   (:import (clojure.lang BigInt)))
-
-;; Experiments, mostly
-
-(defn stroll [inner outer state form]
-  (if-not (coll? form)
-    (outer state form)
-    (let [[state form']
-          (reduce
-           (fn [[s f] x]
-             (let [[s f'] (inner s x)]
-               [s (conj f f')]))
-           [state []]
-           form)
-          form (cond
-                 (instance? clojure.lang.IMapEntry form) (vec form')
-                 (seq? form) (doall form')
-                 :else (into (empty form) form'))]
-      (outer state form))))
-
-(defn post-stroll [f state form]
-  (stroll (partial post-stroll f) f state form))

 (defn transform-map [spec m]
   (into {}


yet another change

yet another change

--- src/http_users/core.clj
+++ src/http_users/core.clj
@@ -8,7 +8,9 @@
          '[clojure.java.io :as io])

 ;(def user-data "/var/www/json/user-data.json")
-(def user-data (.getFile (clojure.java.io/resource "user-data.json")))
+;(def user-data (.getFile (clojure.java.io/resource "user-data.json")))
+
+(def user-data (io/file (io/resource "user-data.json")))
 (def port 8080)

 (defn user-to-html [user]


Updated repositories to use official path

--- kuona-core/project.clj
+++ kuona-core/project.clj
@@ -3,7 +3,7 @@
   :url "https://github.com/kuona/kuona-project"
   :license {:name "Apache License 2.0"
             :url  "http://www.apache.org/licenses/LICENSE-2.0"}
-  :repositories [["gradle" "https://repo.gradle.org"]]
+  :repositories [["gradle" "https://repo.gradle.org/gradle/libs-releases-local/"]]
   :dependencies [[org.clojure/clojure "1.9.0"]
                  [org.clojure/tools.logging "0.4.1"]
                  [log4j/log4j "1.2.17" :exclusions [javax.mail/mail


Fixed bug caused by trying to sort a map with keywords and string keys

--- lib/compojure/html/html.clj
+++ lib/compojure/html/html.clj
@@ -44,13 +44,13 @@
 (def h escape-html)    ; Shortcut for escaping HTML

 (defn- map-to-attrs
-  "Turn a map into a string of XML attributes."
+  "Turn a map into a string of XML attributes, sorted by attribute name."
   [attrs]
   (str-map
     (fn [[key val]]
-      (str* " " key "=\"" (h val) "\""))
+      (str " " key "=\"" (h val) "\""))
     (apply sorted-map
-      (mapcat identity attrs))))
+      (mapcat #(map str* %) attrs))))

 (def xml)


Add save feedback route.

Add save feedback route.

--- src/haystack/routes.clj
+++ src/haystack/routes.clj
@@ -27,6 +27,26 @@
 (def my-routes ["/" {"index.html" :index
                      "articles/" {"index.html" :article-index
                                   "article.html" :article}}])
+
+(defn save-feedback
+  [ctx]
+  (let [query-map (-> ctx :parameters :query walk/keywordize-keys)
+        query-map (merge
+                   query-map
+                   {:created-on (java.util.Date.)})]
+    (println "in save-feedback")
+    ;; (println (-> ctx :parameters :query walk/keywordize-keys))
+    (prn query-map)
+    (try
+      (esd/create repo "searchecommerce" "feedback" query-map)
+      (catch Throwable e
+        (println e)
+        (throw e)))
+    (json-response {:saved true})))
+
+(defn get-feedback
+  []
+  (esd/search repo "searchecommerce" "feedback" ""))

 (def scheme "http")
 (def host "locahost:8080")
@@ -182,7 +202,7 @@
                          {:response (fn [ctx]
                                       (println "in mappings")
                                       (esi/get-mapping repo "searchecommerce"))}}})
-         "my-mappings" (yada/resource
+        "my-mappings" (yada/resource
                  {:id :sql
                   :description "Explicitly defined mappings"
                   :produces    {:media-type "application/json"}
@@ -218,6 +238,18 @@
         {"dump"   (fn [req]
                     {:status 200
                      :body   "api/v2/"})
+         "feedback" (yada/resource
+                     {:id :feedback
+                      :description "Post feedback"
+                      :access-control {:allow-origin "*"
+                                       :allow-methods #{:get :post}
+                                       :allow-credentials false
+                                       :expose-headers #{"X-Custom"}}
+                      :consumes    {:media-type #{"application/json" "application/transit" "application/transmit+json"}}
+                      :produces    {:media-type "application/json"}
+                      :methods
+                      {:get
+                       {:response (fn [ctx] (save-feedback ctx))}}})
          "search" (yada/resource
                    {:id          :homepage
                     :description "Process search request"


Refactoring - .getMessage in the server module

--- src/hurvinek/server.clj
+++ src/hurvinek/server.clj
@@ -18,6 +18,7 @@
 (require '[hurvinek.html-renderer :as html-renderer])
 (require '[hurvinek.exporter      :as exporter])
 (require '[hurvinek.db-interface  :as db-interface])
+(require '[hurvinek.utils         :as utils])

 (defn println-and-flush
     "Original (println) has problem with syncing when it's called from more threads.
@@ -90,7 +91,7 @@
           (cond
               (empty? product-name) (finish-processing html-renderer/render-product-list request title product-list "danger" "Product name is not specified")
               (empty? description)  (finish-processing html-renderer/render-product-list request title product-list "danger" "Product description is not specified")
-              insert-result         (finish-processing html-renderer/render-product-list request title product-list "danger" (.getMessage insert-result))
+              insert-result         (finish-processing html-renderer/render-product-list request title product-list "danger" (utils/get-exception-message insert-result))
               :else                 (finish-processing html-renderer/render-product-list request title product-list "info"   (str "Product " product-name " has been added into the database"))
           )))

@@ -107,7 +108,7 @@
               (finish-processing html-renderer/render-chapter-list request title product-id product-name chapter-list groups-per-chapter)
               (cond
                   (empty? chapter-name) (finish-processing html-renderer/render-chapter-list request title product-id product-name chapter-list groups-per-chapter "danger" "Chapter name is not specified")
-                  insert-result         (finish-processing html-renderer/render-chapter-list request title product-id product-name chapter-list groups-per-chapter "danger" (.getMessage insert-result))
+                  insert-result         (finish-processing html-renderer/render-chapter-list request title product-id product-name chapter-list groups-per-chapter "danger" (utils/get-exception-message insert-result))
                   :else                 (finish-processing html-renderer/render-chapter-list request title product-id product-name chapter-list groups-per-chapter "info"   (str "Chapter " chapter-name " has been added into the database"))
               ))))

@@ -129,14 +130,14 @@
                        groups-per-chapter (db-interface/read-groups-per-chapter product-id chapter-list)]
                        (cond
                            (empty? group-name) (finish-processing html-renderer/render-chapter-list request title product-id product-name chapter-list groups-per-chapter "danger" "Group name is not specified")
-                           insert-result       (finish-processing html-renderer/render-chapter-list request title product-id product-name chapter-list groups-per-chapter "danger" (.getMessage insert-result))
+                           insert-result       (finish-processing html-renderer/render-chapter-list request title product-id product-name chapter-list groups-per-chapter "danger" (utils/get-exception-message insert-result))
                            :else               (finish-processing html-renderer/render-chapter-list request title product-id product-name chapter-list groups-per-chapter "info"   (str "Group " group-name " has been added into the database"))
                        ))
                   (let [chapter-name   (db-interface/read-chapter-name chapter-id)
                         group-list     (db-interface/read-groups chapter-id)]
                        (cond
                            (empty? group-name) (finish-processing html-renderer/render-group-list request title product-id chapter-id product-name chapter-name group-list "danger" "Group name is not specified")
-                           insert-result       (finish-processing html-renderer/render-group-list request title product-id chapter-id product-name chapter-name group-list "danger" (.getMessage insert-result))
+                           insert-result       (finish-processing html-renderer/render-group-list request title product-id chapter-id product-name chapter-name group-list "danger" (utils/get-exception-message insert-result))
                            :else               (finish-processing html-renderer/render-group-list request title product-id chapter-id product-name chapter-name group-list "info"   (str "Group " group-name " has been added into the database"))
                        ))))))

@@ -152,7 +153,7 @@
         (if entered-name
             (cond
                 (empty? entered-name) (finish-processing html-renderer/render-edit-chapter request title product-id product-name chapter-id chapter-name "danger" "Chapter name is not specified")
-                update-result         (finish-processing html-renderer/render-edit-chapter request title product-id product-name chapter-id chapter-name "danger" (.getMessage update-result))
+                update-result         (finish-processing html-renderer/render-edit-chapter request title product-id product-name chapter-id chapter-name "danger" (utils/get-exception-message update-result))
                 :else                 (finish-processing html-renderer/render-edit-chapter request title product-id product-name chapter-id chapter-name "info"   "Chapter has been renamed"))
             (finish-processing html-renderer/render-edit-chapter request title product-id product-name chapter-id chapter-name))))

@@ -169,7 +170,7 @@
               (cond
                   (empty? entered-name)         (finish-processing html-renderer/render-edit-product request title product-id product-name description "danger" "Product name is not specified")
                   (empty? entered-description)  (finish-processing html-renderer/render-edit-product request title product-id product-name description "danger" "Product description is not specified")
-                  update-result                 (finish-processing html-renderer/render-edit-product request title product-id product-name description "danger" (.getMessage update-result))
+                  update-result                 (finish-processing html-renderer/render-edit-product request title product-id product-name description "danger" (utils/get-exception-message update-result))
                   :else                         (finish-processing html-renderer/render-edit-product request title product-id product-name description "info"   (str "Product " product-name " has been updated")))
               (finish-processing html-renderer/render-edit-product request title product-id product-name description))))

@@ -244,7 +245,7 @@
           group-name     (db-interface/read-group-name group-id)
           component-list (db-interface/read-components group-id)]
           (if delete-result
-              (finish-processing html-renderer/render-component-list request title product-id chapter-id group-id product-name chapter-name group-name component-list "danger" (.getMessage delete-result))
+              (finish-processing html-renderer/render-component-list request title product-id chapter-id group-id product-name chapter-name group-name component-list "danger" (utils/get-exception-message delete-result))
               (finish-processing html-renderer/render-component-list request title product-id chapter-id group-id product-name chapter-name group-name component-list "info" (str "Component " component-name " has been deleted")))))

 (defn get-output-format


Clicking support button takes free user to Discuss

--- src-cljs/frontend/components/common.cljs
+++ src-cljs/frontend/components/common.cljs
@@ -5,6 +5,7 @@
             [frontend.config :as config]
             [frontend.datetime :as datetime]
             [frontend.models.feature :as feature]
+            [frontend.models.user :as user]
             [frontend.utils :as utils :include-macros true]
             [frontend.utils.github :as gh-utils]
             [frontend.utils.github :refer [auth-url]]
@@ -19,10 +20,11 @@

 (defn contact-support-a-info [owner & {:keys [tags]
                                        :or {tags [:support-dialog-raised]}}]
-  (if (config/intercom-enabled?)
-        {:on-click #(raise! owner tags)}
-        {:href (str "mailto:" (config/support-email))
-         :target "_blank"}))
+  (cond (not (config/elevio-enabled?)) {:href (str "mailto:" (config/support-email))
+                                        :target "_blank"}
+        user/free? {:href "https://discuss.circleci.com/t/community-support/1470"
+                    :target "_blank"}
+        :else {:on-click #(raise! owner tags)}))

 (defn contact-us-inner [owner]
   [:a (contact-support-a-info owner)


sort comments

sort comments

--- src-cljs/frontend/components/issues.cljs
+++ src-cljs/frontend/components/issues.cljs
@@ -310,7 +310,7 @@
           (when (and (not (contains? ancestors (:db/id comment))) ; don't render cycles
                      (pos? (count rendered-child-ids)))
             [:div.comments {:key "child-comments"}
-             (for [id rendered-child-ids]
+             (for [id (reverse (sort-by (fn [i] (:comment/created-at (d/entity @issue-db i))) rendered-child-ids))]
                (om/build single-comment {:issue-id issue-id
                                          :comment-id id}
                          {:key :comment-id
@@ -363,7 +363,7 @@
           (unrendered-comments-notice all-top-level-ids rendered-top-level-ids
                                       #(om/update-state! owner (fn [s]
                                                                  (assoc s :rendered-top-level-ids (:all-top-level-ids s)))))
-          (for [id rendered-top-level-ids]
+          (for [id (reverse (sort-by (fn [i] (:comment/created-at (d/entity @issue-db i))) rendered-top-level-ids))]
             (om/build single-comment {:comment-id id
                                       :issue-id issue-id}
                       {:key :comment-id}))])))))


CMR-1199: Fixed bug in default-error-format-fn

--- ingest-app/src/cmr/ingest/api/routes.clj
+++ ingest-app/src/cmr/ingest/api/routes.clj
@@ -305,7 +305,7 @@
   key set on the ExceptionInfo object passed in as parameter e. Defaults to json if
   the default format has not been set to :xml."
   [_request e]
-  (mt/format->mime-type (:default-format (ex-data e))))
+  (get mt/format->mime-type (:default-format (ex-data e)) "application/json"))

 (defn make-api [system]
   (-> (build-routes system)


Added assert on upserter to ensure it has the needed fields

--- src/kixi/hecuba/dev.clj
+++ src/kixi/hecuba/dev.clj
@@ -59,12 +59,14 @@

+
 (deftype RefCommander [r]
   Commander
   (upsert! [_ payload]
+    (assert (every? payload #{:name :type}))
     (infof "upserting... %s" payload)
     (let [id (sha1 (:name payload))]
-      (dosync (alter r assoc id (assoc payload :id id))))))
+      (dosync (alter r assoc-in [id] (assoc payload :id id))))))

 (defrecord RefQuerier [r]
   Querier


Rework handling of :user profile

Rework handling of :user profile

Some potentially incompatible options are now removed from :user profile.
Also system-wide :android-debug and :android-release profiles were introduced.

--- src/leiningen/droid.clj
+++ src/leiningen/droid.clj
@@ -40,12 +40,25 @@

 (declare execute-subtask)

+(defn apply-profiles
+  "Takes a project map, reconfigures some of the profiles to work with
+  Android and adds some extra ones."
+  [project]
+  (-> project
+      (unmerge-profiles [:base :user])
+      ;; Remove some possibly incompatible options from :user profile
+      ;; and merge it back.
+      (vary-meta update-in [:profiles :user]
+                 dissoc :dependencies :injections :repl-options)
+      (merge-profiles [:user :android-dev])
+      android-parameters))
+
 (defn transform-into-release
   "Takes a project map and replaces `:dev` profile with `:release` profile."
   [project]
   (-> project
-      (unmerge-profiles [:dev :base])
-      (merge-profiles [:release])
+      (unmerge-profiles [:dev :base :android-dev])
+      (merge-profiles [:release :android-release])
       android-parameters))

 (def ^{:doc "Default set of tasks to create an application release."}
@@ -87,8 +100,7 @@
   ([project & [cmd & args]]
      (init-hooks)
      (some-> project
-             (unmerge-profiles [:base])
-             android-parameters   ;; Poor man's middleware here
+             apply-profiles
              (execute-subtask cmd args))))

 (defn execute-subtask


Don't try to check if engine is valid before drivers are loaded

--- src/metabase/driver.clj
+++ src/metabase/driver.clj
@@ -306,7 +306,6 @@
      (can-connect-with-details? :postgres {:host \"localhost\", :port 5432, ...})"
   [engine details-map & [rethrow-exceptions]]
   {:pre [(keyword? engine)
-         (is-engine? engine)
          (map? details-map)]}
   (let [driver (engine->driver engine)]
     (try


fix shift to stop in chromium

fix shift to stop in chromium

--- src/metronome/core.cljs
+++ src/metronome/core.cljs
@@ -93,7 +93,7 @@
                      :adjusting false})
     om/IDidMount
     (did-mount [_]
-      (letfn [(key-handler [e] (when (= "Shift" (.-key e)) (om/set-state! owner :should-stop (= "keydown" (.-type e)))))]
+      (letfn [(key-handler [e] (when (or (= "Shift" (.-key e)) (= 16 (.-keyCode e))) (om/set-state! owner :should-stop (= "keydown" (.-type e)))))]
         (.addEventListener js/document "keydown" key-handler)
         (.addEventListener js/document "keyup" key-handler)))
     om/IRenderState


added Emily update to in-the-media

added Emily update to in-the-media


added docstrings for the generated functions

--- src/push/types/core.clj
+++ src/push/types/core.clj
@@ -132,6 +132,8 @@
     (eval (list
       'push.instructions.core/build-instruction
       instruction-name
+      (str "`:" instruction-name "` pushes an `:integer` which is the number of items in the "
+        pushtype " stack.")
       :tags #{:visible}
       `(push.instructions.dsl/count-of ~typename :as :depth)
       '(push.instructions.dsl/push-onto :integer :depth)))))
@@ -145,6 +147,8 @@
     (eval (list
       'push.instructions.core/build-instruction
       instruction-name
+      (str "`:" instruction-name "` pushes a `:boolean`, `true` if the "
+        pushtype " stack is empty, `false` otherwise.")
       :tags #{:visible}
       `(push.instructions.dsl/count-of ~typename :as :depth)
       '(push.instructions.dsl/calculate [:depth] #(zero? %1) :as :check)
@@ -173,6 +177,8 @@
     (eval (list
       'push.instructions.core/build-instruction
       instruction-name
+      (str "`:" instruction-name "` pops the top two `" pushtype
+        "` items and pushes `true` if they are equal, `false` otherwise.")
       :tags #{:equatable}
       `(push.instructions.dsl/consume-top-of ~typename :as :arg1)
       `(push.instructions.dsl/consume-top-of ~typename :as :arg2)
@@ -188,6 +194,8 @@
     (eval (list
       'push.instructions.core/build-instruction
       instruction-name
+      (str "`:" instruction-name "` pops the top two `" pushtype
+        "` items and pushes `false` if they are equal, `true` otherwise.")
       :tags #{:equatable}
       `(push.instructions.dsl/consume-top-of ~typename :as :arg1)
       `(push.instructions.dsl/consume-top-of ~typename :as :arg2)
@@ -217,6 +225,8 @@
     (eval (list
       'push.instructions.core/build-instruction
       instruction-name
+      (str "`:" instruction-name "` pops the top two `" pushtype
+        "` items and pushes `true` if the top item is less than the second, `false` otherwise.")
       :tags #{:comparison}
       `(push.instructions.dsl/consume-top-of ~typename :as :arg2)
       `(push.instructions.dsl/consume-top-of ~typename :as :arg1)
@@ -232,6 +242,8 @@
     (eval (list
       'push.instructions.core/build-instruction
       instruction-name
+      (str "`:" instruction-name "` pops the top two `" pushtype
+        "` items and pushes `true` if the top item is less than or equal to the second, `false` otherwise.")
       :tags #{:comparison}
       `(push.instructions.dsl/consume-top-of ~typename :as :arg2)
       `(push.instructions.dsl/consume-top-of ~typename :as :arg1)
@@ -247,6 +259,8 @@
     (eval (list
       'push.instructions.core/build-instruction
       instruction-name
+      (str "`:" instruction-name "` pops the top two `" pushtype
+        "` items and pushes `true` if the top item is greater than or equal to the second, `false` otherwise.")
       :tags #{:comparison}
       `(push.instructions.dsl/consume-top-of ~typename :as :arg2)
       `(push.instructions.dsl/consume-top-of ~typename :as :arg1)
@@ -262,6 +276,8 @@
     (eval (list
       'push.instructions.core/build-instruction
       instruction-name
+      (str "`:" instruction-name "` pops the top two `" pushtype
+        "` items and pushes `true` if the top item is greater than the second, `false` otherwise.")
       :tags #{:comparison}
       `(push.instructions.dsl/consume-top-of ~typename :as :arg2)
       `(push.instructions.dsl/consume-top-of ~typename :as :arg1)
@@ -277,6 +293,8 @@
     (eval (list
       'push.instructions.core/build-instruction
       instruction-name
+      (str "`:" instruction-name "` pops the top two `" pushtype
+        "` items and pushes the _smaller_ of the two.")
       :tags #{:comparison}
       `(push.instructions.dsl/consume-top-of ~typename :as :arg2)
       `(push.instructions.dsl/consume-top-of ~typename :as :arg1)
@@ -293,6 +311,8 @@
     (eval (list
       'push.instructions.core/build-instruction
       instruction-name
+      (str "`:" instruction-name "` pops the top two `" pushtype
+        "` items and pushes the _larger_ of the two.")
       :tags #{:comparison}
       `(push.instructions.dsl/consume-top-of ~typename :as :arg2)
       `(push.instructions.dsl/consume-top-of ~typename :as :arg1)
@@ -327,6 +347,8 @@
     (eval (list
       'push.instructions.core/build-instruction
       instruction-name
+      (str "`:" instruction-name "` examines the top `" pushtype
+        "` item and pushes a duplicate to the same stack.")
       :tags #{:combinator}
       `(push.instructions.dsl/save-top-of ~typename :as :arg1)
       `(push.instructions.dsl/push-onto ~typename :arg1)))))
@@ -340,6 +362,8 @@
     (eval (list
       'push.instructions.core/build-instruction
       instruction-name
+      (str "`:" instruction-name "` discards all items from the `" pushtype
+        "` stack.")
       :tags #{:combinator}
       `(push.instructions.dsl/delete-stack ~typename)))))

@@ -352,6 +376,8 @@
     (eval (list
       'push.instructions.core/build-instruction
       instruction-name
+      (str "`:" instruction-name "` discards the top item from the `" pushtype
+        "` stack.")
       :tags #{:combinator}
       `(push.instructions.dsl/delete-top-of ~typename)))))

@@ -364,6 +390,8 @@
     (eval (list
       'push.instructions.core/build-instruction
       instruction-name
+      (str "`:" instruction-name "` pops the top three items from the `" pushtype
+        "` stack; call them `A`, `B` and `C`, respectively. It pushes them back so that top-to-bottom order is now `'(C A B ...)`")
       :tags #{:combinator}
       `(push.instructions.dsl/consume-top-of ~typename :as :arg1)
       `(push.instructions.dsl/consume-top-of ~typename :as :arg2)
@@ -381,6 +409,8 @@
     (eval (list
       'push.instructions.core/build-instruction
       instruction-name
+      (str "`:" instruction-name "` pops the top item from the `" pushtype
+        "` stack and the top `:integer`. The `:integer` is brought into range as an index by applying `(mod integer (count stack))`, and then the top item is _moved_ so that it is in that position in the resulting stack.")
       :tags #{:combinator}
       '(push.instructions.dsl/consume-top-of :integer :as :index)
       `(push.instructions.dsl/consume-top-of ~typename :as :shoved-item)
@@ -396,6 +426,8 @@
     (eval (list
       'push.instructions.core/build-instruction
       instruction-name
+      (str "`:" instruction-name "` swaps the positions of the top two `" pushtype
+        "` items.")
       :tags #{:combinator}
       `(push.instructions.dsl/consume-top-of ~typename :as :arg1)
       `(push.instructions.dsl/consume-top-of ~typename :as :arg2)
@@ -411,6 +443,7 @@
     (eval (list
       'push.instructions.core/build-instruction
       instruction-name
+      (str "`:" instruction-name "` pops the top `:integer`. The `:integer` is brought into range as an index by applying `(mod integer (count stack))`, and then the item _currently_ found in the indexed position in the `" pushtype "` stack is _moved_ so that it is on top.")
       :tags #{:combinator}
       '(push.instructions.dsl/consume-top-of :integer :as :index)
       `(push.instructions.dsl/count-of ~typename :as :how-many)
@@ -426,6 +459,7 @@
     (eval (list
       'push.instructions.core/build-instruction
       instruction-name
+      (str "`:" instruction-name "` pops the top `:integer`. The `:integer` is brought into range as an index by applying `(mod integer (count stack))`, and then the item _currently_ found in the indexed position in the `" pushtype "` stack is _copied_ so that a duplicate of it is on top.")
       :tags #{:combinator}
       '(push.instructions.dsl/consume-top-of :integer :as :index)
       `(push.instructions.dsl/count-of ~typename :as :how-many)


Add cp as data-property

Add cp as data-property

--- frontend/src/cruncher/views.cljs
+++ frontend/src/cruncher/views.cljs
@@ -66,7 +66,8 @@
                    :className       "poketable-row"
                    :data-favorite   (:favorite pokemon)
                    :data-id         (:id pokemon)
-                   :data-iv-perfect (:individual_percentage pokemon)}
+                   :data-iv-perfect (:individual_percentage pokemon)
+                   :data-cp         (:cp pokemon)}
               (dom/td nil
                       (dom/div #js {:className "checkbox"})
                       (dom/label nil


Fix varying number of assertions

Fix varying number of assertions

--- test/com/climate/claypoole_test.clj
+++ test/com/climate/claypoole_test.clj
@@ -503,17 +503,18 @@
         inputs (range ni)
         ;; Keep track of what threads are active.
         n-active (atom 0)
+        n-seen-active (atom [])
         results (pmap-like pool
                            (fn [i]
                              (swap! n-active inc)
                              (Thread/sleep 1)
-                             ;; Make sure not too many threads are
-                             ;; going.
-                             (is (<= @n-active n))
+                             ;; Make sure not too many threads are going.
+                             (swap! n-seen-active conj @n-active)
                              (swap! n-active dec)
                              i)
                            inputs)]
-    (is (= (sort results) inputs))))
+    (is (= (sort results) inputs))
+    (is (every? #(<= % n) @n-seen-active))))

 (defn check-maximum-parallelism
   "Check that a pmap function doesn't exhibit excessive parallelism."


NPE check for obj.substring

NPE check for obj.substring

--- test/emender_jenkins/utils_test.clj
+++ test/emender_jenkins/utils_test.clj
@@ -139,6 +139,10 @@
     "Check the function emender-jenkins.utils/third."
     (testing "the function emender-jenkins.utils/third."
         (are [x y] (= x y)
+            nil (third [])
+            nil (third '())
+            nil (third [1])
+            nil (third '(1))
             nil (third [1 2])
             nil (third '(1 2)))))

@@ -185,6 +189,13 @@
             "" (substring "Hello world!" 2 2)
             "" (substring "Hello world!" 10 10))))

+(deftest test-substring-NPE
+    "Check the function emender-jenkins.utils/substring."
+    (testing "the function emender-jenkins.utils/substring."
+        (is (thrown? NullPointerException (substring nil 0 0)))
+        (is (thrown? NullPointerException (substring "" nil 0)))
+        (is (thrown? NullPointerException (substring "" 0 nil)))))
+
 (deftest test-contains-1
     "Check the function emender-jenkins.utils/contains."
     (testing "the function emender-jenkins.utils/contains."


fixed test

fixed test

--- test/forma/trends/analysis_test.clj
+++ test/forma/trends/analysis_test.clj
@@ -174,12 +174,16 @@
   (let [ndvi (vector (:ndvi m))
         reli (vector (:reli m))
         rain (vector (:rain m))])
-  (transpose (telescoping-long-trend 23 135 136 ndvi reli rain)))
+  (vec (transpose (telescoping-long-trend 23 135 136 ndvi reli rain))))
+
+(defn short-trend-results
+  [m]
+  )

 (def long-trend-query
   (<- [?han-stat ?long-drop ?long-tstat]
       (total-tap ?ts-map)
-      (tele-wrap ?ts-map :> ?han-stat ?long-drop ?long-tstat)
+      (long-trend-results ?ts-map :> ?han-stat ?long-drop ?long-tstat)
       (:distinct false)))

 (fact


Fix bug where focus was returned illegally to reabledit if data changed

--- src/reabledit/core.cljs
+++ src/reabledit/core.cljs
@@ -20,8 +20,22 @@
   [{:keys [columns data primary-key row-change-fn]}]
   (let [state (reagent/atom {})]
     (reagent/create-class
-     {:component-did-mount #(util/post-render (reagent/dom-node %))
-      :component-did-update #(util/post-render (reagent/dom-node %))
+     {:component-did-mount
+      (fn [this]
+        (util/post-render (reagent/dom-node this))
+        (util/add-blur-emulator! state
+                                 #(if-not (dom/getAncestorByClass (.-target %)
+                                                                  "reabledit")
+                                    (swap! state
+                                           dissoc
+                                           :selected-row-id
+                                           :selected-column-key))))
+      :component-did-update
+      (fn [this _]
+        (util/post-render (reagent/dom-node this)))
+      :component-will-unmount
+      (fn [_]
+        (util/remove-blur-emulator! state))
       :reagent-render
       (fn [{:keys [columns data primary-key row-change-fn]}]
         (let [column-keys (mapv :key columns)


Make control over worker integration test more granular.

--- test/clj/hatnik/worker/worker_integration_test.clj
+++ test/clj/hatnik/worker/worker_integration_test.clj
@@ -7,7 +7,8 @@
             [hatnik.versions :as ver]
             [com.stuartsierra.component :as component]
             [hatnik.test-utils :refer :all :exclude [config]]
-            [taoensso.timbre :as timbre]))
+            [taoensso.timbre :as timbre])
+  (:import [java.util.concurrent Semaphore TimeUnit]))

 ;;;
 ;;; Integration test that verifies that worker job is executed periodically.
@@ -38,32 +39,17 @@
 (defn mock-latest-release-fn
   "Create latest-release version which returns
   new version every time it called."
-  []
-  (let [versions (atom {"lib-1" 0
-                        "lib-2" 1
-                        "lib-3" 2
-                        "lib-4" 3})]
-    (fn [library]
-      (timbre/debug library)
-      (let [version (-> versions
-                        (swap! update-in [library] inc)
-                        (get library))]
-        (str version ".0")))))
+  [versions]
+  (fn [library]
+    (str (@versions library) ".0")))

 (defn create-function-mock
   "Creates mock funciton which saves all arguments it called with into
-  'arguments' atom vector. Also delivers 'true' to the 'finished' promise
-  once it called times-to-call times."
-  [arguments times-to-call finished]
-  (let [counter (atom times-to-call)]
-    (fn [& args]
-      (when (zero? @counter)
-        (throw (ex-info (str "Function expected to be called only "
-                             times-to-call " times.")
-                        {})))
-      (swap! arguments conj (vec args))
-      (when (zero? (swap! counter dec))
-        (deliver finished true)))))
+  'arguments' atom vector. Also releases a permit on provided semaphore."
+  [arguments semaphore]
+  (fn [& args]
+    (swap! arguments conj (vec args))
+    (.release semaphore)))

 (defn create-actions []
   (binding [clj-http.core/*cookie-store* (clj-http.cookies/cookie-store)]
@@ -150,20 +136,29 @@
         :body (str "Body lib-3 5.0 4.0 Default {{not-used}}"
                    "\n\nThis issue is created on behalf of @dummy-login")}))

+(defn acquire
+  "Acquires a permit from semaphore with 10s timeout."
+  [semaphore permits]
+  (.tryAcquire semaphore permits 10 TimeUnit/SECONDS))
+
 (defn run-worker
   "Run worker jobs. The job will be run 2 times."
-  [db]
+  [db versions]
+  (reset! versions {"lib-1" 2
+                    "lib-2" 3
+                    "lib-3" 4
+                    "lib-4" 5})
   (let [; send-email is called 4 times: 2 times for 2 actions.
         ; Both first and second users have email actions.
         email-args (atom [])
-        emails-done (promise)
-        send-email (create-function-mock email-args 4 emails-done)
+        email-semaphore (Semaphore. 0)
+        send-email (create-function-mock email-args email-semaphore)

         ; create-github-issue is run 2 times: first user has single
         ; github-issue action.
         gi-args (atom [])
-        gi-done (promise)
-        create-github-issue (create-function-mock gi-args 2 gi-done)
+        gi-semaphore (Semaphore. 0)
+        create-github-issue (create-function-mock gi-args gi-semaphore)

         utils {:send-email send-email
                :create-github-issue create-github-issue}
@@ -173,8 +168,18 @@
                                         :utils utils})
                    component/start)]
     (try
-      (assert (deref emails-done 5000 false) "send-email not done")
-      (assert (deref gi-done 5000 false) "create-github-issue not done")
+      ; Wait for the first update by worker and update libraries.
+      (acquire email-semaphore 2)
+      (acquire gi-semaphore 1)
+      (reset! versions {"lib-1" 3
+                        "lib-2" 4
+                        "lib-3" 5
+                        "lib-4" 6})
+
+      ; Wait for the second update by worker and verify send-email
+      ; and create-github-issue mocks.
+      (acquire email-semaphore 2)
+      (acquire gi-semaphore 1)
       (assert-emails-args @email-args)
       (assert-github-issue-args @gi-args)

@@ -204,18 +209,22 @@

       (assert (= (count bar-actions) 1))
       (assert (and (= (:library (first bar-actions)) "lib-4")
-               (= (:last-processed-version (first bar-actions))
-                  "6.0"))))))
+                   (= (:last-processed-version (first bar-actions))
+                      "6.0"))))))

 (deftest worker-integration-test
   (let [db (component/start (get-db))
         web-server (component/start (map->WebServer {:config config
-                                                     :db db}))]
+                                                     :db db}))
+        versions (atom {"lib-1" 1
+                        "lib-2" 2
+                        "lib-3" 3
+                        "lib-4" 4})]
     (timbre/set-level! :info)
     (try
-      (with-redefs [ver/latest-release (mock-latest-release-fn)]
+      (with-redefs [ver/latest-release (mock-latest-release-fn versions)]
         (create-actions)
-        (run-worker db)
+        (run-worker db versions)
         (assert-actions-updated))
       (finally
         (component/stop web-server)


Give more descriptive test names. Add test for empty root object

--- test/javascript_externs_generator/extern_test.cljs
+++ test/javascript_externs_generator/extern_test.cljs
@@ -4,21 +4,28 @@

 (enable-console-print!)

-(defn compare! [expected, js-string]
+(defn compare!
+  "eval and extract input, then compare it with the expected output"
+  [expected, js-string]
   (js/eval js-string)
   (is (= expected (extern/extract "TEST" js/TEST))))

-(deftest function
+(deftest top-level-function
   (let [js-string "function TEST() {}"
         expected "var TEST = {\"testFunction\": function () {}};"]
     (compare! expected js-string)))

-(deftest property
+(deftest object-with-property
   (let [js-string "var TEST = {testProperty: \"value\"}"
         expected "var TEST = {\"testProperty\": {}};"]
     (compare! expected js-string)))

-(deftest object
+(deftest empty-object
+  (let [js-string "var TEST = {}"
+        expected "var TEST = {};"]
+    (compare! expected js-string)))
+
+(deftest nested-object
   (let [js-string "var TEST = {testObject: {testProperty: \"value\"}}"
         expected "var TEST = {\"testObject\": {\"testProperty\": {}}};"]
     (compare! expected js-string)))


Send container stdout to websocket until it starts

--- src/replme/web/repl.clj
+++ src/replme/web/repl.clj
@@ -53,16 +53,19 @@
         port 8081]
     (go-loop [msg (<! stdout)]
       (if (re-find nrepl-sentinel msg)
+        (do
+          (log/info (str "Connecting to docker nrepl at" ip ":" port))
+          (>! out-chan "REPL OK")
           (go-loop [repl-conn (repl/connect :host ip :port port)
-                    command (<! in-chan)
-                    client (repl/client repl-conn 1000)]
-            (log/info (str "Connecting to docker nrepl at" ip ":" port))
+                    client (repl/client repl-conn 1000)
+                    command (<! in-chan)]
             (->> (repl/message client {:op :eval :code command})
                  repl/response-values
                  prn-str
-                 (>! out-chan))
-            (recur repl-conn (<! in-chan) client))
-        (recur (<! stdout))))
+                 (>! out-chan)))
+          (recur repl-conn (<! in-chan) client))
+        (do (>! out-chan msg)
+            (recur (<! stdout)))))
     [id http-client]))

 (defn- handle-input


Remove unnecessary requires

Remove unnecessary requires

--- src/io/perun/render.clj
+++ src/io/perun/render.clj
@@ -1,8 +1,6 @@
 (ns io.perun.render
   (:require [boot.pod :as pod]
             [boot.util :as util]
-            [clojure.string :as string]
-            [clojure.java.io :as io]
             [clojure.tools.namespace.dir :as dir]
             [clojure.tools.namespace.track :as track]
             [clojure.tools.namespace.reload :as reload]))


Adds 'runs' function to examine moving-event-windows

--- src/riemann/streams.clj
+++ src/riemann/streams.clj
@@ -1466,6 +1466,24 @@
          (condp ~pred (valuefn# ~event-sym)
            ~@condp-clauses)))))

+(defn runs
+  [len-run field & children]
+  "Usable to perform flap detection, runs examines a moving-event-window of
+  n events and determines if :field is the same across all them. If it is,
+  runs passes on the *first* event of the window. In practice, this can be
+  used nested within a (changed-state ...) to reduce 'flappiness' for
+  state changes.
+
+  (runs 3 :state prn) ; Print events where there are 3-in-a-row of a state."
+  (moving-event-window
+    len-run
+    (smap
+      (fn [events]
+        (if (apply = (map field events))
+          (first events)))
+      (apply sdo children))))
+
+
 (defn project*
   "Like project, but takes predicate *functions* instead of where expressions."
   [predicates & children]


[#672] WIP coerce row values to correct PSQL type when column type matches

--- backend/src/akvo/lumen/import/csv.clj
+++ backend/src/akvo/lumen/import/csv.clj
@@ -3,43 +3,53 @@
             [clojure.data.csv :as csv]
             [clojure.java.io :as io]
             [clojure.java.jdbc :as jdbc]
-            [cuerdas.core :as s])
+            [cuerdas.core :as string])
   (:import com.ibm.icu.text.CharsetDetector))

-(defn nilify
-  "Coerces blank string values to nil"
-  [value]
-  (if (s/blank? value) nil value))
+(defn transform-value
+  "Transforms the given value according to its associated type label.
+  Numeric strings are cast to numbers, only if the type label is 'number'"
+  [[value type-label]]
+  (cond
+    (string/blank? value) nil
+    (and (string/numeric? value) (= "number" type-label)) (Double/parseDouble value)
+    :else value))
+
+(defn transform-rows
+  "Transform values in the given rows based on the given column types"
+  [rows column-types]
+  (let [value-type-pairs (map #(map vector % column-types) rows)]
+    (map #(map transform-value %) value-type-pairs)))

 (defn get-column-names
   "Returns a seq of alphanumeric column names of the form
   c1, c2, c3, ... for the given number of columns"
   [num-cols]
-  (let [nums (range 1 (inc num-cols))]
-    (->> (map vector (repeat \c) nums)
-         (map s/join))))
+  (let [num-range (range 1 (inc num-cols))]
+    (->> (map vector (repeat \c) num-range)
+         (map string/join))))

 (defn get-column-titles
-  "Returns a seq of titles of the form
+  "Returns a seq of alphanumeric column titles of the form
   Column 1, Column 2, Column 3, ... for the given number of columns"
   [num-cols]
-  (let [nums (range 1 (inc num-cols))]
-    (->> (map vector (repeat "Column ") nums)
-         (map s/join))))
+  (let [num-range (range 1 (inc num-cols))]
+    (->> (map vector (repeat "Column ") num-range)
+         (map string/join))))

-(defn get-type-kw
-  "Returns a keyword representation of the type of the given value.
+(defn get-type-label
+  "Returns a keyword label representing the type of the given value.
   Defaults to `:text`."
   [value]
   (condp #(%1 %2) value
+    string/blank? :nil
     ;; TODO date-string? :date
-    nil? :nil
-    s/numeric? :number
+    string/numeric? :number
     :text))

 (defn all-of-type?
-  "Determines if all types in the given column are the same or `:nil`"
+  "Determines if all type labels for the given column are the same or `:nil`"
   [coll type-kw]
   {:pre [(contains? #{:date :number :text} type-kw)]}
   (every? true? (map #(contains? #{:nil type-kw} %) coll)))
@@ -55,10 +65,10 @@
     {:client "text" :psql "text"}))

 (defn get-column-types
-  "Returns a seq of types for each column in the given rows"
+  "Returns a seq of client & SQL types for each column in the given rows"
   [rows]
   (let [columns (apply map vector rows)]
-    (->> (map #(map get-type-kw %) columns)
+    (->> (map #(map get-type-label %) columns)
          (map get-common-type))))

 (defn get-column-tuples
@@ -68,9 +78,9 @@

   [{:column-name \"c1\" :title \"Column 1\" :type \"text\"} ...]
   "
-  [column-ids column-names column-types]
+  [column-names column-titles column-types]
   (map #(zipmap [:column-name :title :type] [%1 %2 %3])
-       column-ids column-names column-types))
+       column-names column-titles column-types))

 (defn- load-csv!
   "Imports the given CSV data into a PostgreSQL table"
@@ -86,7 +96,7 @@
             column-types (get-column-types rows)
             client-types (map :client column-types)
             psql-types (map :psql column-types)
-            transformed-rows (map #(transform-row % client-types) rows)]
+            transformed-rows (transform-rows rows client-types)]
         (jdbc/db-do-commands tenant-conn
           (jdbc/create-table-ddl table-name
                                  (apply vector [:rnum :serial :primary :key]
@@ -100,7 +110,7 @@

 (defn get-encoding
   "Returns the character encoding reading some bytes from the file
-  using ICU's CharsetDetector."
+  using ICU's CharsetDetector"
   [path]
   (let [detector (CharsetDetector.)
         ;; 100kb
@@ -130,7 +140,7 @@
         (if file-on-disk?
           (str file-upload-path
             "/resumed/"
-            (last (s/split url #"\/"))
+            (last (string/split url #"\/"))
             "/file")
           url))))


[#2127] Remove rqg flag

[#2127] Remove rqg flag

--- backend/src/akvo/lumen/lib/import.clj
+++ backend/src/akvo/lumen/lib/import.clj
@@ -22,8 +22,7 @@
 (def ^:dynamic *data-groups-future* true)

 (defn- successful-execution [conn job-execution-id data-source-id dataset-id table-name columns {:keys [spec-name spec-description]} claims]
-  (let [imported-table-name (util/gen-table-name "imported")
-        {:strs [rqg]} (env/all conn)]
+  (let [imported-table-name (util/gen-table-name "imported")]
     (db.dataset/insert-dataset conn {:id dataset-id
                           :title spec-name ;; TODO Consistent naming. Change on client side?
                           :description spec-description
@@ -40,20 +39,17 @@
                                :imported-table-name imported-table-name
                                :version 1
                                :columns (mapv (fn [{:keys [title id type key multipleType multipleId groupName groupId ns]}]
-                                                (let [column-def {:columnName id
-                                                                  :direction nil
-                                                                  :hidden false
-                                                                  :key (boolean key)
-                                                                  :multipleId multipleId
-                                                                  :multipleType multipleType
-                                                                  :groupName groupName
-                                                                  :groupId groupId
-                                                                  :sort nil
-                                                                  :title (string/trim title)
-                                                                  :type type}]
-                                                  (if rqg
-                                                    (assoc column-def :ns ns :repeatable (= groupId ns))
-                                                    column-def)))
+                                                {:columnName id
+                                                 :direction nil
+                                                 :hidden false
+                                                 :key (boolean key)
+                                                 :multipleId multipleId
+                                                 :multipleType multipleType
+                                                 :groupName groupName
+                                                 :groupId groupId
+                                                 :sort nil
+                                                 :title (string/trim title)
+                                                 :type type})
                                               columns)
                                :transformations []})))


Add label field to the inline doc for behaviors and objects.

--- src/lt/plugins/doc.cljs
+++ src/lt/plugins/doc.cljs
@@ -72,6 +72,9 @@
    (when (and (:args doc)
               (not= (:args doc) "nil"))
      [:h3 (:args doc)])
+   (when (and (:labels doc)
+              (not= (:labels doc) ""))
+     [:h3 (str "[" (:labels doc) "]")])
    (when (and (:doc doc)
               (not= (:doc doc) "nil"))
      [:pre (:doc doc)])])
@@ -92,19 +95,22 @@
   [ns name]
   (@object/object-defs (keyword (str ns "/" (subs name 2)))))

+(defn- retrieve
+  [ns name]
+  (or (retrieve-behavior ns name)
+      (retrieve-object-def ns name)))
+
 (defn- retrieve-docstring
   "Helper method for behavior `editor.doc.show!` that returns the docstring for a matching
   object or behavior. If `:doc` is not found, then `:desc` is used. Otherwise `nil`."
   [ns name]
-  (let [beh (retrieve-behavior ns name)
-        beh-doc (or (:doc beh) (:desc beh))
-        obj (retrieve-object-def ns name)
-        obj-doc (or (:doc obj) (:desc obj))]
-    (if (and (nil? beh-doc) (nil? obj-doc))
-      nil
-      (if (nil? beh-doc)
-        obj-doc
-        beh-doc))))
+  (let [o (retrieve ns name)]
+    (or (:doc o) (:desc o))))
+
+(defn- retrieve-labels
+  [ns name]
+  (let [o (retrieve ns name)]
+    (clojure.string/join ", " (map #(get %1 :label) (:params o [])))))

 (behavior ::editor.doc.show!
           :triggers #{:editor.doc.show!}
@@ -113,7 +119,8 @@
                         ;; If :file and :doc are nil then this is likely a behavior or object.
                         ;; Check if a match exists and splice the resulting :doc into the doc argument.
                         (let [doc (if (and (nil? (:file doc)) (nil? (:doc doc)))
-                                    (merge doc {:doc (retrieve-docstring (:ns doc) (:name doc))})
+                                    (merge doc {:doc (retrieve-docstring (:ns doc) (:name doc))
+                                                :labels (retrieve-labels (:ns doc) (:name doc))})
                                     doc)]
                           (inline-doc editor (doc-ui doc) {} (:loc doc))))))


Destructure options in `yaml-metadata`

Destructure options in `yaml-metadata`

--- src/io/perun.clj
+++ src/io/perun.clj
@@ -247,8 +247,7 @@
   '[[circleci/clj-yaml "0.5.5"]])

 (def ^:private +yaml-metadata-defaults+
-  {:filterer identity
-   :extensions []})
+  {:extensions []})

 (deftask yaml-metadata
   "Parse YAML metadata at the beginning of files
@@ -259,10 +258,10 @@
   with the parsed data added as perun metadata."
   [e extensions EXTENSIONS [str] "extensions of files to include (default: `[]`, aka, all extensions)"]
   (let [pod     (create-pod yaml-metadata-deps)
-        options (merge +yaml-metadata-defaults+ *opts*)]
+        {:keys [extensions] :as options} (merge +yaml-metadata-defaults+ *opts*)]
     (content-pre-wrap
      {:parse-form-fn (fn [metas] `(io.perun.yaml/parse-yaml ~metas))
-      :extensions (:extensions options)
+      :extensions extensions
       :output-extension nil ;; keeps the same extension as the input file
       :tracer :io.perun/yaml-metadata
       :options options


Fix format-data test

Fix format-data test

--- test/servisne_info/test/logging.clj
+++ test/servisne_info/test/logging.clj
@@ -4,8 +4,8 @@

 (deftest format-data-test
   (let [data (l/format-data {:username "john" :email "john@example.com"})]
-    (is (= data
-           " username='john' email='john@example.com'"))))
+    (is (.contains data "username='john'"))
+    (is (.contains data "email='john@example.com'"))))

 (deftest format-message-test
   (let [message (l/format-message "New user" {:email "john@example.com"})]


cleanup

cleanup

--- src/babel/francais/morphology/verbs.cljc
+++ src/babel/francais/morphology/verbs.cljc
@@ -1054,7 +1054,6 @@
     (fn [val]
       {:français {:infl :future
                   :val val
-                  :got-here true
                   :conjugated true
                   :français (str (get-in val [:français :future-stem]) "as")
                   :agr {:number :sing


Add support for moving empty tile with arrow keys

--- src/tile_game/grid.cljs
+++ src/tile_game/grid.cljs
@@ -52,4 +52,20 @@
              (str "Suggested Moves: " (b/solve-next board)))]
      (board-size-slider size)]))

-(r/render-component [tile-grid] (. js/document (getElementById "grid")))
+(def codename
+  {37 :left
+   39 :right
+   38 :up
+   40 :down})
+
+(defn handle-keydown [e]
+  (when-let [direction (codename (.-keyCode e))]
+    (.preventDefault e)
+    (swap! app-state update-in [:board] b/slide direction)))
+
+(defn init []
+  (.addEventListener js/document "keydown" handle-keydown)
+  (r/render-component [tile-grid] (. js/document (getElementById "grid"))))
+
+(defonce start
+  (init))


Rework Dadevtools to support being in an external (currently largely unstyled) window

--- src/cljs/dato/debug/components/core.cljs
+++ src/cljs/dato/debug/components/core.cljs
@@ -193,11 +193,11 @@
                   (pr-str))]
     (js/localStorage.setItem "dato-debugger-settings" state)))

-(defn history-com [data owner opts]
+(defn devtools* [data owner opts]
   (reify
     om/IDisplayName
     (display-name [_]
-      "DatoDebuggerContainer")
+      "DatoDevtools")
     om/IWillMount
     (will-mount [_]
       (let [local-storage-state (reader/read-string (or (js/localStorage.getItem "dato-debugger-settings") "{}"))]
@@ -281,8 +281,7 @@
         (dom/div
          (dom/div
           {:className "dato-debugger"}
-          (om/build keyboard/keyboard-handler {} {:opts {:keymap (atom {["ctrl+slash"]   #(om/update-state! owner [:open?] not)
-                                                                        ["ctrl+s"]       #(save-state! owner (om/get-state owner [:current-save-slot]))
+          (om/build keyboard/keyboard-handler {} {:opts {:keymap (atom {["ctrl+s"]       #(save-state! owner (om/get-state owner [:current-save-slot]))
                                                                         ["ctrl+r"]       #(restore-save-state! owner (om/get-state owner [:current-save-slot]))
                                                                         ["ctrl+0"]       #(om/set-state! owner [:current-save-slot] 0)
                                                                         ["ctrl+1"]       #(om/set-state! owner [:current-save-slot] 1)
@@ -442,7 +441,7 @@
                                (dom/input {:type      "range"
                                            :min       0
                                            :max       (max 0 (dec (count (:log data))))
-                                           :value     (get-in l-state [:states :selected])
+                                           :value     (or (get-in l-state [:states :selected]) 0)
                                            :on-change #(let [idx (reader/read-string (.. % -target -value))]
                                                          (om/set-state! owner [:states :selected] idx)
                                                          (set-app-state! idx))})
@@ -470,3 +469,88 @@
                                      {:className (when (:selected? tx) "selected-event")}
                                      (pr-str (:tx/intent tx))
                                      (when (pos? (dec (:count tx))) (str " x " (:count tx))))))))))))))))))))
+
+(defn devtools [data owner opts]
+  (reify
+    om/IDisplayName
+    (display-name [_]
+      "DatoDevtoolsContainer")
+    om/IWillMount
+    (will-mount [_]
+      (let [local-storage-state (reader/read-string (or (js/localStorage.getItem "dato-devtools") "{}"))
+            saved-keys          (set (keys local-storage-state))
+            watch-key           (gensym)]
+        (add-watch (get-in data [:dato :history]) watch-key (fn [_]
+                                                              (if (and owner (om/mounted? owner))
+                                                                (om/refresh! owner)
+                                                                (remove-watch (get-in data [:dato :history]) watch-key))))
+        (om/set-state! owner {:watch-key     watch-key
+                              :ext-devtools? (if (get saved-keys :ext-devtools?)
+                                               (:ext-devtools? local-storage-state)
+                                               (:ext-devtools? opts))
+                              :open?         (if (get saved-keys :open?)
+                                               (:open? local-storage-state)
+                                               (:open? opts))})))
+    om/IWillUnmount
+    (will-unmount [_]
+      (let [watch-key (om/get-state owner :watch-key)]
+        (remove-watch (get-in data [:dato :history]) watch-key)))
+    om/IDidUpdate
+    (did-update [_ _ prev]
+      (let [l-state      (om/get-state owner)
+            popping-out? (and (or (not (:ext-devtools? prev))
+                                  (not (:open? prev)))
+                              (and (:ext-devtools? l-state)
+                                   (:open? l-state)))
+            popping-in?  (and (:ext-devtools? prev)
+                              (or (not (:ext-devtools? l-state))
+                                  (not (:open? l-state))))
+            ext-win      (if popping-out?
+                           (do
+                             (let [win (.open js/window nil, "dato-devtools", "menubar=no,location=no,resizable=yes,scrollbars=no,status=no")]
+                               (set! (.-onclose win) (fn [] (om/set-state! owner [:ext-devtools?] false)))
+                               (.. win -location reload)
+                               ;; None of this seems to work to
+                               ;; prevent the devtools from stealing
+                               ;; focus.
+                               (js/setTimeout #(do (.focus js/window)
+                                                   (.blur win)) 2050)
+                               (om/set-state-nr! owner :ext-win win)
+                               win))
+                           (:ext-win l-state))
+            ext-child    (:ext-child l-state)
+            child        (:child l-state)
+            to-save-state {:ext-devtools? (:ext-devtools? l-state)
+                           :open?         (:open? l-state)}]
+        (js/localStorage.setItem "dato-devtools" (pr-str to-save-state))
+        (when (and popping-in? ext-win)
+          (om/set-state-nr! owner :ext-win nil)
+          (.close ext-win))
+        (cond
+          (and popping-out? ext-win) (js/setTimeout
+                                      #(om/set-state! owner :ext-child (om/root devtools* (get-in data [:dato :history])
+                                                                                {:target (.. ext-win -document -body)
+                                                                                :shared (om/get-shared owner)
+                                                                                :opts   opts}))
+                                      10)
+          (and ext-win ext-child) (om/refresh! ext-child))))
+    om/IRender
+    (render [_]
+      (let [l-state (om/get-state owner)
+            open?   (:open? l-state)]
+        (dom/div
+         {:style {:display (when-not open? "none")}}
+         (om/build keyboard/keyboard-handler {} {:opts {:keymap (atom {["ctrl+slash"] #(om/update-state! owner [:open?] not)})}})
+         (when open?
+           (dom/button
+            {:on-click #(om/update-state! owner [:ext-devtools?] not)}
+            (if (:ext-devtools? l-state)
+              (dom/div
+               {:style {:position "fixed"
+                        :bottom   0
+                        :left     0}}
+               "⤶")
+              "⤴")))
+         (when open?
+           (when-not (:ext-devtools? l-state)
+             (om/build devtools* @(get-in data [:dato :history]) {:opts opts}))))))))


Advanced compilation friendly version of make-get-gamepads.

--- src/cljs/infinitelives/utils/events.cljs
+++ src/cljs/infinitelives/utils/events.cljs
@@ -290,11 +290,11 @@
 ;; define game controller functions
 (defn make-get-gamepads []
   (cond
-   (.-getGamepads js/navigator)
-   #(.getGamepads js/navigator %)
-
-   (.-webkitGetGamepads js/navigator)
-   #(.webkitGetGamepads js/navigator %)
+   (aget js/navigator "getGamepads")
+   (fn [&args] (.apply (aget js/navigator "getGamepads") js/navigator []))
+
+   (aget js/navigator "wegkitGetGamepads")
+   (fn [&args] (.apply (aget js/navigator "webkitGetGamepads") js/navigator []))

    :default
    #()))


excel report precision -> configurable

excel report precision -> configurable

--- src/clojure/zensols/model/classifier.clj
+++ src/clojure/zensols/model/classifier.clj
@@ -93,6 +93,11 @@
   * **:train-classifier** called when the classifier is training a model
   * **:test-classifier** called when the classifier is testing a model"
   nil)
+
+(def ^:dynamic excel-results-precision
+  "An integer specifying the length of the mantissa when creating the results
+  spreadsheet in [[excel-results]]."
+  3)

 (defn initialize
   "Initialize model resource locations.
@@ -451,9 +456,11 @@
   (letfn [(create-sheet-data [results]
             (map (fn [result]
                    (letfn [(fp [key]
-                             (format "%.2f%%" (get result key)))
+                             (format (str "%." excel-results-precision "f%%")
+                                     (get result key)))
                            (f [key]
-                             (format "%.2f" (get result key)))]
+                             (format (str "%." excel-results-precision "f")
+                                     (get result key)))]
                      (vec (apply concat
                                  `(~(fp :accuracy)
                                    ~(f :wprecision)


Added minimum-genetic-difference diversification constraing (with hardcoded limit for now).

--- src/clojush/pushgp/genetic_operators.clj
+++ src/clojush/pushgp/genetic_operators.clj
@@ -834,6 +834,12 @@
   (and (not= g parent1-genome)
        (not= g parent2-genome)))

+(defn minimum-genetic-difference-diversifying?
+  "Returns true iff genome g passes the diversification test."
+  [g {:keys [parent1-genome parent2-genome]}]
+  (and (<= (sequence-similarity g parent1-genome) 0.9)
+       (<= (sequence-similarity g parent2-genome) 0.9)))
+
 (defn three-gens-diff-diffs-diversifying?
   "Returns true iff genome g passes the diversification test."
   [g argmap]
@@ -1025,6 +1031,7 @@
      :si-and-mate-use si-and-mate-use-diversifying?
      :no-clones no-clones-diversifying?
      :not-a-clone not-a-clone-diversifying?
+     :minimum-genetic-difference minimum-genetic-difference-diversifying?
      :none (fn [genome argmap] true))
     g
     argmap))
@@ -1156,3 +1163,4 @@
         :is-random-replacement
         (if use-child false true)))))

+


Readd allowed origins

Readd allowed origins

--- src/obb_api/service.clj
+++ src/obb_api/service.clj
@@ -53,8 +53,8 @@
               ;;
               ;; "http://localhost:8080"
               ;;
-              ::bootstrap/allowed-origins ["*.orionsbelt.eu"
-                                           "localhost"]
+              ::bootstrap/allowed-origins ["http://orionsbelt.eu"
+                                           "http://localhost"]

               ;; Root for resource interceptor that is available by default.
               ::bootstrap/resource-path "/public"


Allow github org as origin

Allow github org as origin

--- src/obb_api/service.clj
+++ src/obb_api/service.clj
@@ -54,6 +54,7 @@
               ;; "http://localhost:8080"
               ;;
               ::bootstrap/allowed-origins ["http://orionsbelt.eu"
+                                           "http://orionsbelt-battlegrounds.github.io/"
                                            "http://localhost"]

               ;; Root for resource interceptor that is available by default.


Fix filter bounced email function.

Fix filter bounced email function.

--- src/oc/email/mailer.clj
+++ src/oc/email/mailer.clj
@@ -33,9 +33,9 @@
 (defn- default-source []
   (str default-from " <" (default-reply-to) ">"))

-(defun- can-send-to?
+(defun- filter-bounced-recipients
   ([to-addresses :guard sequential?]
-   (filter can-send-to? to-addresses))
+   (filter filter-bounced-recipients to-addresses))
   ([to-address :guard string?]
    (-> c/dynamodb-opts
        (bounced-email/retrieve-email to-address)
@@ -51,8 +51,8 @@
         html-body (if html (assoc text-body :html html) text-body)
         fixed-reply-to (or reply-to (default-reply-to))
         fixed-to (if (sequential? to) to [to])
-        filtered-to (can-send-to? fixed-to)
-        skip-to (clj-set/difference fixed-to filtered-to)
+        filtered-to (filter-bounced-recipients fixed-to)
+        skip-to (clj-set/difference (set fixed-to) (set filtered-to))
         error-msg (when (seq skip-to)
                     (format "Skipping %d recipients because of hard bounce: %s" (count skip-to) (s/join ", " skip-to)))]
     (when (seq filtered-to)


Validation passing.

Validation passing.

--- src/onyx/validation.clj
+++ src/onyx/validation.clj
@@ -1,5 +1,8 @@
 (ns onyx.validation
-  (:require [schema.core :as schema]))
+  (:require [clojure.data.fressian :as fressian]
+            [com.stuartsierra.dependency :as dep]
+            [onyx.planning :as planning]
+            [schema.core :as schema]))

 (def base-catalog-entry-validator
   {:onyx/name schema/Keyword
@@ -8,11 +11,36 @@
    :onyx/batch-size (schema/pred pos? 'pos?)
    schema/Keyword schema/Any})

+(defn edge-two-nodes? [edge]
+  (= (count edge) 2))
+
+(def edge-validator
+  (schema/->Both [(schema/pred vector? 'vector?)
+                  (schema/pred edge-two-nodes? 'edge-two-nodes?)
+                  [schema/Keyword]]))
+
+(def workflow-validator
+  (schema/->Both [(schema/pred vector? 'vector?)
+                  [edge-validator]]))
+
 (def catalog-entry-validator
   (schema/conditional #(or (= (:onyx/type %) :input) (= (:onyx/type %) :output))
                       (merge base-catalog-entry-validator {:onyx/medium schema/Keyword})
                       :else
                       (merge base-catalog-entry-validator {:onyx/fn schema/Keyword})))
+
+(defn serializable? [x]
+  (try
+    (do (fressian/write x)
+        true)
+    (catch Exception e
+      false)))
+
+(defn task-dispatch-validator [task]
+  (when (= (:onyx/name task)
+           (:onyx/type task))
+    (throw (Exception. (str "Task " (:onyx/name task)
+                            " cannot use the same value for :onyx/name as :onyx/type.")))))

 (defn validate-catalog
   [catalog]
@@ -28,9 +56,63 @@
                             "for the following workflow keywords: "
                             (apply str (interpose ", " missing-names)))))))

+
+
+(defn validate-workflow-names [{:keys [workflow catalog]}]
+  (when-let [missing-names (->> workflow
+                                (mapcat identity)
+                                (remove (set (map :onyx/name catalog)))
+                                seq)]
+    (throw (Exception. (str "Catalog is missing :onyx/name values "
+                            "for the following workflow keywords: "
+                            (apply str (interpose ", " missing-names)))))))
+
+(defn catalog->type-task-names [catalog type-pred]
+  (set (map :onyx/name
+            (filter (fn [task]
+                      (type-pred (:onyx/type task)))
+                    catalog))))
+
+(defn validate-workflow-inputs [g input-tasks]
+  (when-let [invalid (ffirst (filter (comp seq second)
+                                     (map (juxt identity
+                                                (partial dep/immediate-dependencies g))
+                                          input-tasks)))]
+    (throw (Exception. (str "Input task " invalid " has incoming edge.")))))
+
+(defn validate-workflow-outputs [g output-tasks]
+  (when-let [invalid (ffirst (filter (comp seq second)
+                                     (map (juxt identity
+                                                (partial dep/immediate-dependents g))
+                                          output-tasks)))]
+    (throw (Exception. (str "Output task " invalid " has outgoing edge.")))))
+
+(defn validate-workflow-intermediates [g intermediate-tasks]
+  (let [invalid-intermediate? (fn [[_ dependencies dependents]]
+                                (let [dependencies? (empty? dependencies)
+                                      dependents? (empty? dependents)]
+                                  (or (and dependencies? (not dependents?))
+                                      (and (not dependencies?) dependents?))))]
+    (when-let [invalid (ffirst (filter invalid-intermediate?
+                                       (map (juxt identity
+                                                  (partial dep/immediate-dependencies g)
+                                                  (partial dep/immediate-dependents g))
+                                            intermediate-tasks)))]
+      (throw (Exception. (str "Intermediate task " invalid " requires both incoming and outgoing edges."))))))
+
+(defn validate-workflow-graph [{:keys [catalog workflow]}]
+  (let [g (planning/to-dependency-graph workflow)]
+    (validate-workflow-intermediates g (catalog->type-task-names catalog #{:function}))
+    (validate-workflow-inputs g (catalog->type-task-names catalog #{:input}))
+    (validate-workflow-outputs g (catalog->type-task-names catalog #{:output}))))
+
+(defn validate-workflow [job]
+  (validate-workflow-graph job)
+  (validate-workflow-names job))
+
 (def job-validator
   {:catalog [(schema/pred map? 'map?)]
-   :workflow (schema/pred vector? 'vector?)
+   :workflow workflow-validator
    :task-scheduler schema/Keyword
    (schema/optional-key :percentage) schema/Int})

@@ -38,5 +120,5 @@
   [job]
   (schema/validate job-validator job)
   (validate-catalog (:catalog job))
-  (validate-workflow-names job))
+  (validate-workflow job))


Improving control bus manipulation.

Improving control bus manipulation.

* now we can use either bus ids or bus objects in bus functions
* added get and set for bus ranges

--- src/overtone/sc/bus.clj
+++ src/overtone/sc/bus.clj
@@ -1,5 +1,8 @@
 (ns overtone.sc.bus
+  (:import [java.util.concurrent TimeoutException])
   (:use [overtone.sc.machinery defaults allocator]
+        [overtone.sc.machinery.server comms]
+        [overtone.util lib]
         [overtone.sc server]))

 ;; ## Busses
@@ -15,8 +18,15 @@

 (defn bus?
   [b]
-  (and (associative? b)
-       (or (isa? (type b) ::bus))))
+  (or (number? b)
+      (and (associative? b)
+       (or (isa? (type b) ::bus)))))
+
+(defn- bus-id
+  [b]
+  (if (number? b)
+    b
+    (:id b)))

 ; TODO: In order to allocate multi-channel busses we actually need to
 ; allocate multiple, adjacent busses, which the current bitset based
@@ -60,18 +70,38 @@
 ;(on-sync-event :reset reset-busses ::reset-busses)

 (defn bus-set!
-  "Takes a list of bus indices and values and sets the buses to those values.
+  "Takes a list of control bus indices and values and sets the buses to those values.
   Modifies bus(ses) in place on the server.

   (bus-set! my-bus 3) ;=> Sets my-bus to the value 3"
   [bus val]
   (assert (bus? bus))
+  (snd "/c_set" (bus-id bus) (double val)))

-  (snd "/c_set" (:id bus) (double val)))
+(defn bus-get
+  "Get the current value of a control bus."
+  [bus]
+  (assert (bus? bus))
+  (let [p (server-recv "/c_set")]
+    (snd "/c_get" (bus-id bus))
+    (try
+      (second (:args (deref! p)))
+      (catch TimeoutException t
+        :timeout))))

 (defn bus-set-range!
-  "Set a range of consecutive busses to the supplied vals"
-  [bus start len data]
+  "Set a range of consecutive control busses to the supplied values."
+  [bus start len vals]
   (assert (bus? bus))
+  (apply snd "/c_setn" (bus-id bus) start len (floatify vals)))

-  (apply snd "/c_setn" (:id bus) start len (map double data)))
+(defn bus-get-range
+  "Get a range of consecutive control bus values."
+  [bus len]
+  (assert (bus? bus))
+  (let [p (server-recv "/c_setn")]
+    (snd "/c_getn" (bus-id bus) len)
+    (try
+      (drop 2 (:args (deref! p)))
+      (catch TimeoutException t
+        :timeout))))


Improve arg name in copy-resource-file

Improve arg name in copy-resource-file

--- src/docker_clojure/dockerfile/shared.clj
+++ src/docker_clojure/dockerfile/shared.clj
@@ -49,12 +49,11 @@
         nil))))

 (defn copy-resource-file
-  "Copy a file named `filename` from resources to a dir in the image
-  `image-dir`. The file contents will be passed to the `processor`
-  fn and whatever that returns used in the image (default processor is
-  `identity`)."
-  ([image-dir filename] (copy-resource-file image-dir filename identity))
-  ([image-dir filename processor]
+  "Copy a file named `filename` from resources to a specified `build-dir`.
+  The file contents will be passed to the `processor` fn and whatever that
+  returns used in the image (default processor is `identity`)."
+  ([build-dir filename] (copy-resource-file build-dir filename identity))
+  ([build-dir filename processor]
    (let [src  (-> filename io/resource io/file)
-         dest (io/file image-dir filename)]
+         dest (io/file build-dir filename)]
      (->> src slurp processor (spit dest)))))


App makes xhr and renders results.

App makes xhr and renders results.

--- src/dummy_om_app/app/components/app.cljs
+++ src/dummy_om_app/app/components/app.cljs
@@ -11,6 +11,12 @@
    (xhr/xhr-req {:method      :get
                  :url         "users/accounts"
                  :on-complete (fn [resp]
-                                (om/update! data [:users :accounts] resp))}))
+                                (om/transact! data [:users :accounts] (fn [_]
+                                                                        resp)))}))
   (render
-   (dom/div nil "hello")))
+   (apply dom/div #js {:id "user-list"}
+          (mapv (fn [{:strs [username email]}]
+                  (dom/ul nil
+                          (dom/li nil (str "Username: " username))
+                          (dom/li nil (str "Email: " email))))
+                (get-in data [:users :accounts])))))


Uses go-loop over go loop

Uses go-loop over go loop

--- src/wordsmith/core.cljs
+++ src/wordsmith/core.cljs
@@ -1,5 +1,5 @@
 (ns wordsmith.core
-  (:require-macros [cljs.core.async.macros :refer [go]])
+  (:require-macros [cljs.core.async.macros :refer [go-loop]])
   (:require [om.core :as om :include-macros true]
             [om.dom :as dom :include-macros true]
             [wordsmith.persistence :as p]
@@ -83,10 +83,10 @@
     (will-mount [_]
       (om/update! app :titles (p/get-all-titles))
       (let [channel (:channel app)]
-        (go (loop []
+        (go-loop []
           (let [[action params] (<! channel)]
             (save-document app)
-            (recur))))))
+            (recur)))))
     om/IRender
     (render [_]
       (dom/div #js {:className "container"}


increase zombie speed

increase zombie speed

--- src/zombie_run/quil.clj
+++ src/zombie_run/quil.clj
@@ -54,7 +54,7 @@

 (defn tick-game-fn [game]
   (fn []
-    (Thread/sleep 500)
+    (Thread/sleep 100)
     (swap! game z/run-zombie-actions)
     (recur)))


Use DATABASE_URL env var

Use DATABASE_URL env var

--- src/zoo_live/system.clj
+++ src/zoo_live/system.clj
@@ -17,7 +17,7 @@
     {:redis-pub-sub {:pool {}
                      :listener nil
                      :spec {:uri redis-pub-sub}}
-     :postgres (get env "HEROKU_POSTGRESQL_PURPLE_URL")
+     :postgres (get env "DATABASE_URL")
      :redis {:pool {} :spec {:uri redis}}
      :handler (r/routes)
      :port 8080}))


Improve docs for :on-click

Improve docs for :on-click

--- src/re_com/buttons.cljs
+++ src/re_com/buttons.cljs
@@ -12,7 +12,7 @@

 (def button-args-desc
   [{:name :label            :required true                           :type "string | hiccup" :description "Label for the button."}
-   {:name :on-click         :required false                          :type "() -> nil"       :description "the function to callback when button is clicked."}
+   {:name :on-click         :required false                          :type "() -> nil"       :description "function to call when the button is clicked."}
    {:name :tooltip          :required false :default "no tooltop"    :type "string"          :description "show a popover-tooltip using this text."}
    {:name :tooltip-position :required false :default :below-center   :type "keyword"         :description "position of the popover-tooltip. e.g. :right-below."}
    {:name :disabled?        :required false :default false           :type "boolean | atom"  :description "Set to true to disable the button."}
@@ -67,7 +67,7 @@

 (def md-circle-icon-button-args-desc
   [{:name :md-icon-name     :required true   :default "md-add"       :type "string"     :description "the name of the icon. See http://zavoloklom.github.io/material-design-iconic-font/icons.html"}
-   {:name :on-click         :required false                          :type "() -> nil"  :description "a callback function to be invoked when button is clicked."}
+   {:name :on-click         :required false                          :type "() -> nil"  :description "function to call when the button is clicked"}
    {:name :size             :required false  :default "nil"          :type "keyword"    :description "set size of button (nil = regular, or :smaller or :larger."}
    {:name :tooltip          :required false                          :type "string"     :description "show a popover-tooltip using this text."}
    {:name :tooltip-position :required false :default ":below-center" :type "keyword"    :description "position of the popover-tooltip. e.g. :right-below."}
@@ -126,7 +126,7 @@

 (def md-icon-button-args-desc
   [{:name :md-icon-name     :required true   :default "md-add"       :type "string"     :description "the name of the icon. See http://zavoloklom.github.io/material-design-iconic-font/icons.html"}
-   {:name :on-click         :required false                          :type "() -> nil"  :description "a callback function to be invoked when button is clicked."}
+   {:name :on-click         :required false                          :type "() -> nil"  :description "function to call when the button is clicked"}
    {:name :size             :required false  :default "nil"          :type "keyword"    :description "set size of button (nil = regular, or :smaller or :larger."}
    {:name :tooltip          :required false                          :type "string"     :description "show a popover-tooltip using this text."}
    {:name :tooltip-position :required false :default ":below-center" :type "keyword"    :description "position of the popover-tooltip. e.g. :right-below."}
@@ -229,7 +229,7 @@

 (def row-button-args-desc
   [{:name :md-icon-name     :required true  :default "md-add"        :type "string"     :description "the name of the icon. See http://zavoloklom.github.io/material-design-iconic-font/icons.html"}
-   {:name :on-click         :required false                          :type "() -> nil"  :description "the fucntion to call when the button is clicked."}
+   {:name :on-click         :required false                          :type "() -> nil"  :description "function to call when the button is clicked."}
    {:name :mouse-over-row?  :required false :default false           :type "boolean"    :description "true if the mouse is hovering over the row this button is in."}
    {:name :tooltip          :required false                          :type "string"     :description "show a popover-tooltip using this text."}
    {:name :tooltip-position :required false :default ":below-center" :type "keyword"    :description "position of the popover-tooltip. e.g. :right-below."}
@@ -281,7 +281,7 @@

 (def hyperlink-args-desc
   [{:name :label            :required false                          :type "string"     :description "Label for the button (can be artitrary markup)."}
-   {:name :on-click         :required false                          :type "string"     :description "Callback when the hyperlink is clicked."}
+   {:name :on-click         :required false                          :type "() -> nil"  :description "function to call when the hyperlink is clicked."}
    {:name :tooltip          :required false                          :type "string"     :description "show a popover-tooltip using this text."}
    {:name :tooltip-position :required false :default ":below-center" :type "keyword"    :description "position of the popover-tooltip. e.g. :right-below."}
    {:name :disabled?        :required false :default false           :type "string"     :description "Set to true to disable the hyperlink."}


Add other round of console API methods.  Not very happy about this.  But will sort it out later.

--- src/re_frame/utils.cljs
+++ src/re_frame/utils.cljs
@@ -5,6 +5,21 @@
    [& args]
    (.warn js/console (apply str args)))

+ (defn dbg
+   [& args]
+   (.debug js/console (apply str args)))
+
+ (defn log
+   [& args]
+   (.log js/console (apply str args)))
+
+ (defn group
+   [& args]
+   (.group js/console (apply str args)))
+
+ (defn groupEnd
+   []
+   (.groupEnd js/console))

  (defn first-in-vector
   [v]


librato/safe-name: fix a bug which broke metric name escaping

Invalid characters which were replaced and changed the length of the
string caused safe-name to (sometimes) call subs with a length larger
than the string itself, throwing an exception.

--- src/riemann/librato.clj
+++ src/riemann/librato.clj
@@ -5,13 +5,14 @@
         clojure.math.numeric-tower))

 (defn safe-name
-  "Converts a string into a safe name for Librato's metrics and streams. Converts spaces to periods, preserves only A-Za-z0-9.:-_, and cuts to 255 characters."
+  "Converts a string into a safe name for Librato's metrics and streams.
+  Converts spaces to periods, preserves only A-Za-z0-9.:-_, and cuts to 255
+  characters."
   [s]
   (when s
-    (-> s
-      (string/replace " " ".")
-      (string/replace #"[^-.:_\w]" "")
-      (subs 0 (min 255 (count s))))))
+    (let [s (string/replace s " " ".")
+          s (string/replace s #"[^-.:_\w]" "")]
+      (subs s 0 (min 255 (count s))))))

 (defn event->gauge
   "Converts an event to a gauge."


Delete all save files on death

Delete all save files on death

--- src/robinson/update.clj
+++ src/robinson/update.clj
@@ -2480,7 +2480,10 @@
             (update-quests)
             (arg-when-> [state] (contains? (-> state :world :player :status) :dead)
               ((fn [state]
-                (.delete (io/file "save/world.edn"))
+                (->>
+                  (file-seq (io/file "save"))
+                  (filter (fn [file] (re-matches #".*edn" (.getName file))))
+                  (map (fn [file] (.delete file))))
                 state))
               (update-in [:world :player :status]
                (fn [status]


speed up admin sync rate

speed up admin sync rate

--- cljs-admin/tourneybot_admin/core.cljs
+++ cljs-admin/tourneybot_admin/core.cljs
@@ -106,7 +106,7 @@
 ;; Update games when the state changes
 ;;------------------------------------------------------------------------------

-(def upload-rate-ms 4000)
+(def upload-rate-ms 2500)

 (defn- upload-games!
   "Upload the games to tournament.json"


remove some noise

remove some noise

--- src/main/shadow/cljs/devtools/server.clj
+++ src/main/shadow/cljs/devtools/server.clj
@@ -100,7 +100,7 @@
        (discard-println ~(str "shutdown failed: " (pr-str body))))))

 (defn shutdown-system [{:keys [shutdown-hook http port-files-ref socket-repl cli-repl cli-checker nrepl] :as app}]
-  (discard-println "shutting down ...")
+  #_ (discard-println "shutting down ...")
   (try
     (. (Runtime/getRuntime) (removeShutdownHook shutdown-hook))
     (catch IllegalStateException e
@@ -313,7 +313,7 @@
         shutdown-hook
         (Thread.
           (fn []
-            (println "Running shutdown hook.")
+            #_ (println "Running shutdown hook.")
             (stop!)))

         app


Properly return 404s on unknown session ids.

--- src/shale/resources.clj
+++ src/shale/resources.clj
@@ -157,7 +157,7 @@
                            (contains? context ::session))
    :new? (fn [context]
            (and (not (false? (::new? context)))
-                (contains? context ::session)))
+                (::session context)))
    :exists? (fn [context]
               (let [session (shale.sessions/view-model
                               (or (::id context)


Log reading checkpoint coordinate when building resume point.

--- src/onyx/api.clj
+++ src/onyx/api.clj
@@ -250,6 +250,7 @@
   (s/validate os/JobId job-id)
   (let [{:keys [log] :as client} (component/start (system/onyx-client peer-client-config))]
     (try
+     (info "Reading checkpoint coordinate at:" tenancy-id job-id)
      (checkpoint/read-checkpoint-coordinate log tenancy-id job-id)
      (finally
       (component/stop client)))))


wip walking db

wip walking db

--- src/sql_walker/core.clj
+++ src/sql_walker/core.clj
@@ -105,9 +105,30 @@
   (not (is-entity? t)))

 (defn walk-database
-  [t]
-  (-> (query-get-columns t)
-      (case (is-entity?))))
+  [start-t]
+  (let [already-walked []
+        inserted-values {}]
+    (defn walk-table
+      [t]
+      (defn deal-with-pk
+        [t col]
+        nil)
+      (defn deal-with-fk
+        [t col]
+        (case
+            (is-entity? (query-get-parent-table t col))
+          (if (.contains already-walked t)
+            (get-inserted-value t)
+            (walk-table (query-get-parent-table t col)))
+          (is-lookup? t)
+          (get-lookup-value )))
+      (defn deal-with-col
+        [t col]
+        (case (is-pk? col) (deal-with-pk t col)
+              (is-fk? col) (deal-with-fk-col t col)
+              :else (deal-with-primitive-col t col)))
+      (let [cols  (query-get-columns start-t)]
+        ()))))

 ;; from https://stackoverflow.com/questions/925738/how-to-find-foreign-key-dependencies-in-sql-server
 ;;   SELECT


fix translations for locales with underscore (like es_419)

--- src/status_im/i18n.cljs
+++ src/status_im/i18n.cljs
@@ -14,7 +14,11 @@
 ;; translations
 (def translations-by-locale
   (->> (i18n/translations [:en :ko :ru :pl :es_419])
-       (map (fn [[k t]] [k (types/json->clj t)]))
+       (map (fn [[k t]]
+              (let [k' (-> (name k)
+                           (string/replace "_" "-")
+                           keyword)]
+                [k' (types/json->clj t)])))
        (into {})))

 ;; english as source of truth


Remove debug output

Remove debug output

--- src/puppeteer/infra/repository/build.clj
+++ src/puppeteer/infra/repository/build.clj
@@ -22,7 +22,6 @@
                       (.setName (-> % :name)))
                    (-> build :steps))
         images (-> build :images)]
-    (println steps)
     (doto (Build.)
       (.setSource source)
       (.setSteps steps)


Removing redundant :path key in tests

Removing redundant :path key in tests

--- test/aero/core_test.clj
+++ test/aero/core_test.clj
@@ -57,8 +57,7 @@
            (:flavor-string config)))))

 (deftest path-test
-  (let [config (read-config "test/aero/config.edn" {:path true
-                                                    :transforms [:path]
+  (let [config (read-config "test/aero/config.edn" {:transforms [:path]
                                                     :profile :test
                                                     :schema clojure.core/identity})]
     (is (= (get-in config [:greeting])
@@ -72,13 +71,11 @@
     (is config)))

 (deftest remote-file-test
-  (let [config (read-config "test/aero/config.edn" {:path true
-                                                    :transforms [:path]
+  (let [config (read-config "test/aero/config.edn" {:transforms [:path]
                                                     :profile :test})]
     (is (= (get-in config [:remote :greeting])
            "str"))))

 (deftest nested-path-test
-  (let [config (read-config "test/aero/config.edn" {:path true
-                                                    :transforms [:path]})]
+  (let [config (read-config "test/aero/config.edn" {:transforms [:path]})]
     (is (= "Hello World!" (get-in config [:test-nested])))))


Make bold work on desktop again

Make bold work on desktop again

Signed-off-by: yenda <96f164ad4d9b2b0dacf8ebee2bb1eeb3aa69adf1@status.im>

--- src/status_im/ui/screens/chat/utils.cljs
+++ src/status_im/ui/screens/chat/utils.cljs
@@ -16,12 +16,8 @@
       (format-author from username)))

 (def ^:private styling->prop
-  {:bold      (if platform/desktop?
-                {:font :medium}
-                {:style {:font-weight :bold}})
-   :italic    (if platform/desktop?
-                {:font :italic}
-                {:style {:font-style  :italic}})
+  {:bold      {:style {:font-weight :bold}}
+   :italic    {:style {:font-style  :italic}}
    :backquote {:style {:background-color colors/black
                        :color            colors/green}}})


whitespace

whitespace

--- src/strictly_specking/error_printing.clj
+++ src/strictly_specking/error_printing.clj
@@ -222,8 +222,6 @@
            (.getAbsolutePath (io/file file))
            f))
        (if line (str ":" line) "") (if (and line column) (str ":" column) "")))
-
-

 (defn pprint-in-file [file base-path key-message-map]
   (try