:tada: Initial work on copy & paste functionality.

--- frontend/src/uxbox/main/data/workspace.cljs
+++ frontend/src/uxbox/main/data/workspace.cljs
@@ -1986,6 +1986,95 @@

 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Clipboard
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(def copy-selected
+  (letfn [(prepare-selected [state selected]
+            (let [data (reduce #(prepare %1 state %2) {} selected)]
+              {:type :copied-shapes
+               :data (assoc data :selected selected)}))
+
+          (prepare [result state id]
+            (let [page-id (::page-id state)
+                  objects (get-in state [:workspace-data page-id :objects])
+                  object  (get objects id)]
+              (cond-> (assoc-in result [:objects id] object)
+                (= :frame (:type object))
+                (as-> $ (reduce #(prepare %1 state %2) $ (:shapes object))))))
+
+          (on-copy-error [error]
+            (js/console.error "Clipboard blocked:" error)
+            (rx/empty))]
+
+    (ptk/reify ::copy-selected
+      ptk/WatchEvent
+      (watch [_ state stream]
+        (let [selected (get-in state [:workspace-local :selected])
+              cdata    (prepare-selected state selected)]
+          (->> (rx/from (wapi/write-to-clipboard cdata))
+               (rx/catch on-copy-error)
+               (rx/ignore)))))))
+
+
+(defn- paste-impl
+  [{:keys [selected objects] :as data}]
+  (letfn [(prepare-change [id]
+            (let [obj (get objects id)]
+              ;; (prn "prepare-change" id obj)
+              (if (= :frame (:type obj))
+                (prepare-frame-change obj)
+                (prepare-shape-change obj uuid/zero))))
+
+          (prepare-shape-change [obj frame-id]
+            (let [id (uuid/next)]
+              {:type :add-obj
+               :id id
+               :frame-id frame-id
+               :obj (assoc obj :id id :frame-id frame-id)}))
+
+          (prepare-frame-change [obj]
+            (let [frame-id (uuid/next)
+                  sch (->> (map #(get objects %) (:shapes obj))
+                           (map #(prepare-shape-change % frame-id)))
+                  fch {:type :add-obj
+                       :id frame-id
+                       :frame-id uuid/zero
+                       :obj (-> obj
+                                (assoc :id frame-id)
+                                (assoc :frame-id uuid/zero)
+                                (assoc :shapes (mapv :id sch)))}]
+              (d/concat [fch] sch)))]
+
+  (ptk/reify ::paste-impl
+    ptk/WatchEvent
+    (watch [_ state stream]
+      (let [rchanges (->> (map prepare-change selected)
+                          (flatten))
+            uchanges (map (fn [ch]
+                            {:type :del-obj
+                             :id (:id ch)})
+                          rchanges)]
+        (cljs.pprint/pprint rchanges)
+        (rx/of (commit-changes (vec rchanges)
+                               (vec (reverse uchanges))
+                               {:commit-local? true})))))))
+
+(def paste
+  (ptk/reify ::paste
+    ptk/WatchEvent
+    (watch [_ state stream]
+      (->> (rx/from (wapi/read-from-clipboard))
+           (rx/filter #(= :copied-shapes (:type %)))
+           (rx/pr-log "pasting:")
+           (rx/map :data)
+           (rx/map paste-impl)
+           (rx/catch (fn [err]
+                       (js/console.error "Clipboard blocked:" err)
+                       (rx/empty)))))))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; Page Changes Reactions
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


Improve FMI Testbed image fetching error detection

--- src/env_logger/handler.clj
+++ src/env_logger/handler.clj
@@ -168,9 +168,17 @@
                                                                       9)))
                                                  (t/now)))
                               (let [image (get-testbed-image)]
-                                (when (nil? image)
-                                  (log/error "Testbed image is empty"))
-                                image))
+                                (if (or (nil? image)
+                                        (zero? (count image)))
+                                  (do
+                                    (log/error (format (str "Testbed image at"
+                                                            " %s is empty")
+                                                       (f/unparse
+                                                        (f/formatters
+                                                         :date-time-no-ms)
+                                                        (t/now))))
+                                    nil)
+                                  image)))
               insert-status (db/insert-observation
                              db/postgres
                              (assoc (assoc (parse-string obs-string true)


Add delete button.

Add delete button.

--- src/lab_notebook/core.cljs
+++ src/lab_notebook/core.cljs
@@ -41,7 +41,7 @@
                                       (on-save (:summary state) (:date-time state) (:notes state))))}
           "Save")))))

-(defn item-view [cursor component]
+(defn item-view [cursor component options]
   (reify
     om/IInitState
     (init-state [this]
@@ -63,9 +63,18 @@
                            :onClick (fn [e]
                                       (om/set-state! component :editing? true))}
             "Edit")
+          (dom/button #js {:className "btn btn-primary"
+                           :onClick (fn [e]
+                                      (.preventDefault e)
+                                      (when-let [on-delete (:on-delete options)]
+                                        (on-delete)))}
+            "Delete")
           (dom/div nil (:summary cursor))
           (dom/div nil (:date-time cursor))
           (dom/div nil (:notes cursor)))))))
+
+(defn delete [v i]
+  (into (subvec v 0 i) (subvec v (inc i))))

 (defn item-table [cursor component]
   (reify
@@ -80,8 +89,10 @@
                                     (om/set-state! component :editing? true))}
           "New entry")
         (apply dom/div nil
-          (for [entry (:entries cursor)]
-            (om/build item-view entry)))
+          (for [[i entry] (map vector (range) (:entries cursor))]
+            (om/build item-view entry
+              {:opts {:on-delete (fn []
+                                   (om/transact! cursor :entries #(delete % i)))}})))
         (when (or (:editing? state)
                 (empty? (:entries cursor)))
           (dom/div nil


CMR-3773: Cleaning up Ruby spec code.

CMR-3773: Cleaning up Ruby spec code.

--- orbits-lib/test/cmr/orbits/ruby_specs.clj
+++ orbits-lib/test/cmr/orbits/ruby_specs.clj
@@ -6,11 +6,8 @@
    [clojure.test :refer :all])
   (:import
    (javax.script
-    Invocable
-    ScriptEngine
-    ScriptEngineManager)
-   (java.io
-    ByteArrayInputStream)))
+    ScriptEngineManager)))
+

 (defn- create-jruby-runtime
   "Creates and initializes a JRuby runtime."
@@ -21,17 +18,22 @@
   [jruby s]
   (.eval jruby (java.io.StringReader. s)))

-
 (deftest test-ruby-specs
+  ;; Find all the spec files in the test_resources/spec folder
   (let [specs (->> (io/file (io/resource "spec"))
                    (.list)
                    (filter #(str/ends-with? %"_spec.rb")))]
     (doseq [spec-name specs
+            ;; Create a new instance of the JRuby runtime for each spec so that we can show separate
+            ;; results for each spec.
             :let [jruby (create-jruby-runtime)]]
-      (eval-jruby
-       jruby
-       (format "load 'spec/%s'" spec-name))
-      (is (= 0 (eval-jruby jruby "require 'rspec/core'; RSpec::Core::Runner.run([])"))))))
+      (testing spec-name
+       (eval-jruby
+        jruby
+        (format "load 'spec/%s'" spec-name))
+       ;; RSPec returns 0 when tests pass and 1 when they fail.
+       (is (= 0 (eval-jruby jruby "require 'rspec/core'; RSpec::Core::Runner.run([])"))
+           (str "RSPec returned failure status for " spec-name))))))


Rules for computing the actions' enabled states.

--- src/fm/simrunner/model.clj
+++ src/fm/simrunner/model.clj
@@ -29,14 +29,31 @@
           (assoc-in [:model :changed?] true)
           (assoc-in [:model :valid?] (cfg/complete? config))))))

+(defn- rule [& preds]
+  (partial map (fn [pred flag] (pred flag)) preds))
+
+(def ^{:private true} action-rules {:open-config    (rule (constantly true)
+                                                          (constantly true)
+                                                          (constantly true))
+                                    :save-config    (rule true?
+                                                          true?
+                                                          (constantly true))
+                                    :save-config-as (rule true?
+                                                          (constantly true)
+                                                          (constantly true))
+                                    :run-simulation (rule true?
+                                                          false?
+                                                          boolean)})
+
 (defn- update-actions [{:keys [ui model]:as app-state}]
-  (let [valid?   (:valid? model)
-        changed? (:changed? model)
-        actions  (case [valid? changed?]
-                   [false false] #{:open-config}
-                   [false  true] #{:open-config}
-                   [true  false] #{:open-config :save-config-as :run-simulation}
-                   #{:open-config :save-config :save-config-as})]
+  (let [rule-args [(:valid? model)
+                   (:changed? model)
+                   (-> ui :model :values :output-file)]
+        actions   (->> action-rules
+                       (filter (fn [[action rule]]
+                                 (every? true? (rule rule-args))))
+                       (map first)
+                       (into #{}))]
     (-> app-state
         (assoc-in [:ui :model :actions] actions)
         (assoc-in [:ui :dirty?] true))))


Fix test

Fix test

--- storm-core/test/clj/org/apache/storm/security/auth/nimbus_auth_test.clj
+++ storm-core/test/clj/org/apache/storm/security/auth/nimbus_auth_test.clj
@@ -125,7 +125,6 @@

         (is (thrown-cause? AuthorizationException (.uploadChunk nimbus_client nil nil)))
         (is (thrown-cause? AuthorizationException (.finishFileUpload nimbus_client nil)))
-        (is (thrown-cause? AuthorizationException (.beginFileDownload nimbus_client nil)))
         (is (thrown-cause? AuthorizationException (.downloadChunk nimbus_client nil)))
         (is (thrown-cause? AuthorizationException (.getNimbusConf nimbus_client)))
         (is (thrown-cause? AuthorizationException (.getClusterInfo nimbus_client)))
@@ -192,7 +191,6 @@

         (is (thrown-cause? AuthorizationException (.uploadChunk nimbus_client nil nil)))
         (is (thrown-cause? AuthorizationException (.finishFileUpload nimbus_client nil)))
-        (is (thrown-cause? AuthorizationException (.beginFileDownload nimbus_client nil)))
         (is (thrown-cause? AuthorizationException (.downloadChunk nimbus_client nil)))
         (is (thrown-cause? AuthorizationException (.getNimbusConf nimbus_client)))
         (is (thrown-cause? AuthorizationException (.getClusterInfo nimbus_client)))


resolve root query

resolve root query

--- src/graphql_clj/parser.clj
+++ src/graphql_clj/parser.clj
@@ -137,31 +137,43 @@
   :NOT_NULL)

 (def type-map
-  {:UserType {:name "User"
+  {:GraphQLString {:name "String"
+                   :kind :SCALAR}
+   :UserType {:name "User"
               :kind :OBJECT
               :fields {:id {:type :GraphQLString}
                        :name {:type :GraphQLString}}
               :args {}
-              :resolve-fn (fn [object] {:id "test"})}})
+              :resolve-fn (fn [object]
+                            (println "user resolve-fn: ")
+                            {:id "test"})}})

 (def schema
   {:query {:name "Query"
            :kind :OBJECT
            :fields {:user {:type :UserType}}
-           :args {:id :GraphQLString}}})
+           :resolve-fn (fn [obj]
+                         (println "query resolve-fn:" obj)
+                         (identity obj))}})
+
+(defn get-type-meta
+  [type-key]
+  (or (get schema type-key)
+      (get type-map type-key)
+      (throw (ex-info (format "Unknown object type: %s." type-key)
+                      {:type-key type-key}))))

 (defn type-system-lookup
-  [object-type object-name]
-  (case object-type
-    :root (case object-name
-            "user" {:name "User"
-                    :kind :OBJECT
-                    :fields {:id {:type :GraphQLString}
-                             :name {:type :GraphQLString}}
-                    :args {}
-                    :resolve-fn (fn [object] {:id "test"})}
-            (throw (ex-info (format "Unknown object name: %s." object-name) {})))
-    (throw (ex-info (format "Unknown object type: %s." object-type) {}))))
+  [parent-object-type-key object-name]
+  (let [parent-object-type (get-type-meta parent-object-type-key)
+        type (or (get-in parent-object-type [:fields (keyword object-name) :type])
+                 (throw (ex-info (format "Unknown object name: %s." parent-object-type-key)
+                                 {:parent-object-type-key parent-object-type-key
+                                  :object-name object-name})))]
+    (println "type: " type)
+    (if (map? type)
+      type
+      (get type-map type))))

 (defn get-field-type-from-object-type
   "FIXME"
@@ -169,15 +181,18 @@
   (println (format "get-field-type-from-object-type: object-type: %s, field-selection: %s." object-type field-selection))
   (let [object-name (get-selection-object-name field-selection)
         _ (println "object-name: " object-name)
-        type-meta (type-system-lookup object-type object-name)]
-    type-meta))
+        type (get-in object-type [:fields (keyword object-name) :type])]
+    (if (map? type)
+      type
+      (get-type-meta type))))

 (defn resolve-field-on-object
   "FIXME"
   [object-type object field-entry]
   (let [object-name (get-selection-object-name field-entry)
-        type-info (type-system-lookup object-type object-name)
-        resolve-fn (:resolve-fn type-info)]
+        resolve-fn (:resolve-fn object-type)]
+    (println "resolve-filed-on-object: object-type: " object-type)
+    (println "resolve-field-on-object: resolve-fn: " resolve-fn)
     (resolve-fn object)))

 (defn merge-selection-sets
@@ -228,7 +243,8 @@
     (cond
       (is-scalar-field-type? field-type) result
       (is-enum-field-type? field-type) result
-      (is-object-field-type? field-type) (evaluate-selection-set field-type result sub-selection-set nil))))
+      (is-object-field-type? field-type) (evaluate-selection-set field-type result sub-selection-set nil)
+      :else (throw (ex-info (format "Not a valid field type %s." field-type) {:field-type field-type})))))

 (defn get-field-entry [object-type object fields]
   (println "get-field-entry: " fields)
@@ -258,8 +274,9 @@

 (defn execute-query [query]
   (let [selection-set (:selection-set query)
-        visitied-fragments nil]
-    (evaluate-selection-set :root nil selection-set visitied-fragments)))
+        visitied-fragments nil
+        object-type (get-type-meta :query)]
+    (evaluate-selection-set object-type :root selection-set visitied-fragments)))

 (defn execute-definition
   [definition]


WM: Set resize column sync to false

WM: Set resize column sync to false

--- src/hatti/views/table.cljs
+++ src/hatti/views/table.cljs
@@ -113,7 +113,7 @@
        :enableColumnReorder false
        :enableTextSelectionOnCells true
        :rowHeight 40
-       :syncColumnCellResize true})
+       :syncColumnCellResize false})

 (defn bind-external-sg-grid-event-handlers
   [grid event-handlers]


Moved utility functions to chimera

Moved utility functions to chimera

--- src/hatti/views/table.cljs
+++ src/hatti/views/table.cljs
@@ -2,7 +2,7 @@
   (:require-macros [cljs.core.async.macros :refer [go go-loop]])
   (:require [chimera.js-interop :refer [safe-regex]]
             [chimera.urls :refer [last-url-param url]]
-            [chimera.seq :refer [in?]]
+            [chimera.seq :refer [in? add-element remove-element]]
             [chimera.om.state :refer [transact!]]
             [chimera.string :refer [escape-for-type]]
             [clojure.string :refer [escape]]
@@ -198,18 +198,6 @@
          :let [handler-name (hyphen->camel-case (name handler-key))
                event (aget dataview handler-name)]]
      (.subscribe event handler-function))))
-
-(defn add-element
-  [vector value]
-  (-> vector
-      (conj (int value))
-      set
-      vec))
-
-(defn remove-element
-  [vector value]
-  (vec (remove (fn [id] (= id value))
-               vector)))

 (defn update-data-to-be-deleted-vector
   [checked? data-id]


OO: Undo changes to table page component

--- src/hatti/views/table.cljs
+++ src/hatti/views/table.cljs
@@ -303,45 +303,6 @@
       (om/set-state! owner :dataview dataview)
       [grid dataview])))

-(defn get-table-view-height
-  []
-  (let [body (js/document.querySelector "body")
-        body-height (.-clientHeight body)
-        body-width (.-clientWidth body)
-        main-navigation-height (-> "#dataview-menu"
-                                   js/document.querySelector
-                                   .-clientHeight)
-        tab-navigation-height (-> ".tab-bar a.clicked"
-                                  js/document.querySelector
-                                  .-clientHeight)
-        record-summary-container-height
-        (-> ".tab-bar .rec-summary"
-            js/document.querySelector
-            .-clientHeight)
-        tablet-width 1024
-        phablet-width 704
-        submission-view-y-top-offset 2]
-    (- body-height
-       (+ main-navigation-height
-          tab-navigation-height
-          (if (> body-width phablet-width)
-            0
-            tab-navigation-height)
-          (if (> body-width tablet-width)
-            0
-            submission-view-y-top-offset)))))
-
-(defn set-window-resize-handler
-  [owner]
-  (let [resize-handler (fn [event]
-                         (om/set-state! owner
-                                        :table-view-height
-                                        (get-table-view-height)))]
-    (.addEventListener js/window
-                       "resize"
-                       resize-handler)
-    (om/set-state! owner :resize-handler resize-handler)))
-
 (defmethod table-page :default
   [app-state owner {:keys [slick-grid-event-handlers] :as opts}]
   "Om component for the table grid.
@@ -370,20 +331,31 @@
    in the SlickGrid documentation for event handlers.
    https://github.com/mleibman/SlickGrid/wiki/Getting-Started"
   (reify
+    om/IRenderState
+    (render-state [_ _]
+      (let [no-data? (empty? (get-in app-state [:data]))
+            {:keys [num_of_submissions] :as dataset-info}
+            (:dataset-info app-state)
+            with-info #(merge % {:dataset-info dataset-info})]
+        (html
+         [:div.table-view
+          (om/build submission-view
+                    (with-info (get-in app-state
+                                       [:table-page :submission-clicked]))
+                    {:opts (merge (select-keys opts #{:delete-record! :role})
+                                  {:view :table})})
+          (om/build table-header app-state)
+          [:div {:id table-id :class "slickgrid"}
+           (if (and no-data? (zero? num_of_submissions))
+             [:span {:class "empty-state"} "No data"]
+             [:span
+              [:i.fa.fa-spinner.fa-pulse] "Loading..."])]])))
     om/IDidMount
     (did-mount [_]
-      (set-window-resize-handler owner)
       (let [data (get-in app-state [:data])]
         (when-let [[grid dataview]
                    (init-grid! data owner slick-grid-event-handlers)]
           (handle-table-events app-state grid dataview))))
-
-    om/IWillUnmount
-    (will-unmount [_]
-      (.removeEventListener js/window
-                            "resize"
-                            (om/get-state owner :resize-handler)))
-
     om/IWillReceiveProps
     (will-receive-props [_ next-props]
       "will-recieve-props resets slickgrid data if the table data has changed."
@@ -398,31 +370,4 @@
             (do ; data has changed
               (.invalidateAllRows grid)
               (.setItems dataview (clj->js new-data) _id)
-              (.render grid))))))
-
-    om/IRenderState
-    (render-state [_ {:keys [table-view-height]}]
-      (let [{:keys [data dataset-info]
-             {:keys [prevent-scrolling-in-table-view? submission-clicked]}
-             :table-page}
-            app-state
-            {:keys [num_of_submissions]} dataset-info
-            no-data? (empty? data)
-            with-info #(merge % {:dataset-info dataset-info})]
-        (html
-         [:div {:class "table-view"
-                :style (when prevent-scrolling-in-table-view?
-                         {:height (or table-view-height
-                                      (get-table-view-height))
-                          :overflow "hidden"})}
-          (when (:data submission-clicked)
-            (om/build submission-view
-                      (with-info submission-clicked)
-                      {:opts (merge (select-keys opts #{:delete-record! :role})
-                                    {:view :table})}))
-          (om/build table-header app-state)
-          [:div {:id table-id :class "slickgrid"}
-           (if (and no-data? (zero? num_of_submissions))
-             [:span {:class "empty-state"} "No data"]
-             [:span
-              [:i.fa.fa-spinner.fa-pulse] "Loading..."])]])))))
+              (.render grid))))))))


Target Java 6 in template

Target Java 6 in template

--- res/templates/project.clj
+++ res/templates/project.clj
@@ -9,6 +9,7 @@

   :source-paths ["src/clojure" "src"]
   :java-source-paths ["src/java" "gen"]
+  :javac-options ["-target" "1.6" "-source" "1.6" "-Xlint:-options"]

   :dependencies [[org.clojure-android/clojure "1.5.1-jb" :use-resources true]
                  [neko/neko "3.0.0-preview1"]]


fix indentation

fix indentation

--- src/metabase/db/internal.clj
+++ src/metabase/db/internal.clj
@@ -35,7 +35,7 @@

     *  If entity is a vector like `[User :name]`, only keeps the first arg (`User`)
     *  Converts fully-qualified entity name strings like `\"metabase.models.user/User\"` to the corresponding entity
-  and requires their namespace if needed."
+       and requires their namespace if needed."
   (memoize
    (fn -entity->korma [entity]
      {:post [(= (type %) :korma.core/Entity)]}


Fixed redirect bug.

Fixed redirect bug.

--- src/kixi/hecuba/routes.clj
+++ src/kixi/hecuba/routes.clj
@@ -49,8 +49,8 @@
       ;; index redirect
       (ANY (amon-resource-route route)
            []
-           (let [redirect-route (amon-index-route route)]
-             (log/infof "Received: %s Redirecting to: %s" route redirect-route)
+           (let [redirect-route (str (:uri params) "/")]
+             (log/infof "Redirecting to: %s" redirect-route)
              (redirect redirect-route)))))
   ([route keys handler]
      (let [params (mapv #(symbol (name %)) keys)]
@@ -61,8 +61,8 @@
         ;; index redirect
         (ANY (amon-resource-route route keys)
              params
-             (let [redirect-route (amon-index-route route params)]
-               (log/infof "Received: %s Redirecting to: %s" route redirect-route)
+             (let [redirect-route (str (:uri params) "/")]
+               (log/infof "Redirecting to: %s" redirect-route)
                (redirect redirect-route)))))))

 (defn resource-route [route keys handler]


Updated the development dependency versions

--- src/leiningen/new/repl.clj
+++ src/leiningen/new/repl.clj
@@ -5,9 +5,9 @@
   [options]
   (if (some #{"+figwheel"} (:features options))
     (-> options
-        (append-options :dev-dependencies [['figwheel "0.1.7-SNAPSHOT"]])
-        (append-options :dev-plugins [['lein-figwheel "0.1.7-SNAPSHOT"]])
-        (append-options :core-dependencies [['figwheel.client :as 'fw]])
+        (append-options :dev-dependencies [['figwheel "0.2.2-SNAPSHOT"]])
+        (append-options :dev-plugins [['lein-figwheel "0.2.2-SNAPSHOT"]])
+        (append-options :dev-requires [['figwheel.client :as 'fw]])
         (assoc :figwheel? true))
     options))

@@ -15,9 +15,9 @@
   [options]
   (if (some #{"+weasel"} (:features options))
     (-> options
-        (append-options :dev-dependencies [['com.cemerick/piggieback "0.1.3"]
-                                           ['weasel "0.4.2"]])
-        (append-options :core-dependencies [['weasel.repl :as 'ws-repl]])
+        (append-options :dev-dependencies [['com.cemerick/piggieback "0.1.5"]
+                                           ['weasel "0.5.0"]])
+        (append-options :dev-requires [['weasel.repl :as 'ws-repl]])
         (update-in [:repl-options]
                    assoc :nrepl-middleware ['cemerick.piggieback/wrap-cljs-repl])
         (assoc :weasel? true))


Checkpoint

Checkpoint

Signed-off-by: Gregory Haskins <640d9fe47775e6723f0355b7315e38f7d98d3539@gmail.com>

--- src/obcc/build/interface.clj
+++ src/obcc/build/interface.clj
@@ -10,7 +10,7 @@
 ;;

 ;;(deftype Field    [^String modifier ^String type ^String name ^Int index])
-;;(deftype Message  [^String name ^ArrayList fields])
+(deftype Message  [^String name ^ArrayList fields])

 (def grammar (insta/parser (io/resource "parsers/interface/grammar.bnf")
                            :auto-whitespace (insta/parser (io/resource "parsers/interface/skip.bnf"))))
@@ -45,7 +45,10 @@
   (let [interfaces (getinterfaces config)]
     (into {} (map #(vector % (compileintf path %)) interfaces))))

-(defn fieldattrs [ast]
+;;-----------------------------------------------------------------
+;; getX - extracts fields from an AST message
+;;-----------------------------------------------------------------
+(defn getfieldattrs [ast]
   (loop [loc ast attrs {}]
     (if (nil? loc)
       attrs
@@ -53,7 +56,7 @@
       (let [[k v] (zip/node loc)]
         (recur (zip/right loc) (assoc attrs k v))))))

-(defn buildfields [ast]
+(defn getfields [ast]
   (loop [loc ast fields {}]
     (cond

@@ -61,14 +64,21 @@
       fields

       :else
-      (let [attrs (->> loc zip/down zip/right fieldattrs)]
-        ;; do something with each node here
+      ;; do something with each node here
+      (let [attrs (->> loc zip/down zip/right getfieldattrs)]
         (recur (zip/right loc) (assoc fields (:index attrs) attrs))))))
+
+;;-----------------------------------------------------------------
+;; buildX - build our ST friendly objects from the AST
+;;-----------------------------------------------------------------
+(defn buildfields [ast]
+  (let [rawfields (getfields ast)]
+      rawfields))

 (defn buildmessage [ast]
   (let [name (->> ast zip/right zip/node)
         fields (buildfields (->> ast zip/right zip/right))]
-      [name fields]))
+      (->Message name fields)))

 ;;(defn generateproto [intf ast template]
 ;;  (loop [loc ast]


Fix query filter and sort condition to make it faster in case there are pins.

--- src/oc/storage/db/common.clj
+++ src/oc/storage/db/common.clj
@@ -78,36 +78,37 @@
                                          (r/get-field :created-at)
                                          (r/default (r/get-field post-row :published-at))
                                          (r/default (r/get-field post-row :created-at)))
-                    container-pin (r/default (r/get-field post-row [:pins fixed-container-id]) nil)
-                    can-pin-to-container? (r/and container-pin
+                    can-pin-to-container? (r/and (r/default (r/get-field post-row [:pins fixed-container-id]) nil)
                                                  (r/or (r/ne container-id config/seen-home-container-id)
                                                        (r/not (r/contains (r/coerce-to private-board-uuids :array) (r/get-field post-row [:board-uuid])))))
-                    sort-field (r/branch (r/eq sort-type :recent-activity)
-                                         last-activity-at
-                                         (r/branch (r/eq sort-type :digest)
-                                                   (r/default
-                                                     (r/get-field post-row :published-at)
-                                                     (r/get-field post-row :created-at))
-                                                   (r/branch (r/eq sort-type :bookmarked-at)
-                                                             (-> (r/get-field post-row [:bookmarks])
-                                                                 (r/filter {:user-id user-id})
-                                                                 (r/nth 0)
-                                                                 (r/get-field :bookmarked-at)
-                                                                 (r/default (r/get-field post-row :published-at))
-                                                                 (r/default (r/get-field post-row :created-at)))
-                                                             (r/branch can-pin-to-container?
-                                                                       (-> (r/get-field post-row [:pins fixed-container-id :pinned-at])
-                                                                           (r/default (r/get-field post-row :published-at))
-                                                                           (r/default (r/get-field post-row :created-at)))
-                                                                       ;:else
-                                                                       (r/default
-                                                                        (r/get-field post-row :published-at)
-                                                                        (r/get-field post-row :created-at))))))
+                    sort-field (cond ;; Recent activity sort
+                                     (= sort-type :recent-activity)
+                                     last-activity-at
+                                     ;; Digest sort (recently published without pins at the top)
+                                     (= sort-type :digest)
+                                     (r/default (r/get-field post-row :published-at)
+                                                (r/get-field post-row :created-at))
+                                     (= sort-type :bookmarked-at)
+                                     (-> (r/get-field post-row [:bookmarks])
+                                         (r/filter {:user-id user-id})
+                                         (r/nth 0)
+                                         (r/get-field :bookmarked-at)
+                                         (r/default (r/get-field post-row :published-at))
+                                         (r/default (r/get-field post-row :created-at)))
+                                     ;; In all other cases, check if container can contain pins
+                                     :else
+                                     (r/branch can-pin-to-container?
+                                               (-> (r/get-field post-row [:pins fixed-container-id :pinned-at])
+                                                   (r/default (r/get-field post-row :published-at))
+                                                   (r/default (r/get-field post-row :created-at)))
+                                               ;:else
+                                               (r/default (r/get-field post-row :published-at)
+                                                          (r/get-field post-row :created-at))))
                     sort-value-base (-> sort-field
-                                     (r/iso8601)
-                                     (r/to-epoch-time)
-                                     (r/mul 1000)
-                                     (r/round))
+                                        (r/iso8601)
+                                        (r/to-epoch-time)
+                                        (r/mul 1000)
+                                        (r/round))
                     unseen-entry? (r/and (seq container-last-seen-at)
                                          (r/gt (r/get-field post-row :published-at) container-last-seen-at))
                     unseen-with-cap? (r/and unseen-entry?
@@ -129,8 +130,11 @@
                                                              sort-value-base)))]
                 {;; Date of the last added comment on this entry
                  :last-activity-at last-activity-at
+                 ;; Sorting base value: the timestamp of the event without pins or unseen changes
                  :sort-base sort-value-base
+                 ;; The real value used for the sort
                  :sort-value sort-value
+                 ;; If the entry is unseen
                  :unseen unseen-with-cap?})))
             ;; Filter out:
             (r/filter query (r/fn [row]
@@ -343,17 +347,21 @@
        ;; Merge in last-activity-at and entry
        (r/merge query (r/fn [row]
         (let [interactions-base (-> (r/table "interactions")
-                                 (r/get-all [[(r/get-field row :uuid) true]] {:index :resource-uuid-comment}))
+                                    (r/get-all [[(r/get-field row :uuid) true]] {:index :resource-uuid-comment}))
               last-activity-at (-> interactions-base
-                                 (r/max :created-at)
-                                 (r/get-field :created-at)
-                                 (r/default (r/get-field row [:published-at])))
+                                   (r/max :created-at)
+                                   (r/get-field :created-at)
+                                   (r/default (r/get-field row [:published-at])))
               sort-value-base (-> last-activity-at
+                                  (r/iso8601)
+                                  (r/to-epoch-time)
+                                  (r/mul 1000)
+                                  (r/round))
+              published-ms (-> (r/get-field row [:published-at])
                                (r/iso8601)
                                (r/to-epoch-time)
                                (r/mul 1000)
                                (r/round))
-              published-ms (-> (r/get-field row [:published-at]) (r/iso8601) (r/to-epoch-time) (r/mul 1000) (r/round))
               has-seen-at? (seq container-last-seen-at)
               container-seen-ms (when has-seen-at?
                                   (-> container-last-seen-at


replace the old /api/table/:id/fks implementation with one that works simply using Field and :fk_target_field_id instead.

--- src/metabase/api/table.clj
+++ src/metabase/api/table.clj
@@ -6,7 +6,6 @@
             [metabase.db :refer :all]
             (metabase.models [hydrate :refer :all]
                              [field :refer [Field]]
-                             [foreign-key :refer [ForeignKey]]
                              [table :refer [Table] :as table])
             [metabase.driver :as driver]))

@@ -80,11 +79,16 @@
 (defendpoint GET "/:id/fks"
   "Get all `ForeignKeys` whose destination is a `Field` that belongs to this `Table`."
   [id]
-  (read-check Table id)
-  (let-404 [field-ids (sel :many :id Field :table_id id :visibility_type [not= "retired"])]
-    (-> (sel :many ForeignKey :destination_id [in field-ids])
-        ;; TODO - it's a little silly to hydrate both of these table objects
-        (hydrate [:origin [:table :db]] [:destination :table]))))
+  (let-404 [table (Table id)]
+    (read-check table)
+    (let [field-ids (sel :many :id Field :table_id id :visibility_type [not= "retired"])]
+      (for [origin-field (sel :many Field :fk_target_field_id [in field-ids])]
+        ;; it's silly to be hydrating some of these tables/dbs
+        {:relationship   :Mt1
+         :origin_id      (:id origin-field)
+         :origin         (hydrate origin-field [:table :db])
+         :destination_id (:fk_target_field_id origin-field)
+         :destination    (hydrate (Field (:fk_target_field_id origin-field)) :table)}))))

 (defendpoint POST "/:id/sync"
   "Re-sync the metadata for this `Table`."


Use if-not instead of (if (not))

Use if-not instead of (if (not))

--- src/re_frame/middleware.cljs
+++ src/re_frame/middleware.cljs
@@ -22,7 +22,7 @@
   [handler]
   (fn pure-handler
     [app-db event-vec]
-    (if (not (satisfies? IReactiveAtom app-db))
+    (if-not (satisfies? IReactiveAtom app-db)
       (do
         (if (map? app-db)
           (warn "re-frame: Looks like \"pure\" is in the middleware pipeline twice. Ignoring.")


Use Records for performance

Use Records for performance

--- src/montebot/connect4.cljc
+++ src/montebot/connect4.cljc
@@ -7,13 +7,12 @@
 #?(:clj (set! *warn-on-reflection* true))
 #?(:cljs (enable-console-print!))

+(def cols (vec (range 7)))
+
+(defrecord State [active occupied p1 p2])
+
 (defn initial-state []
-  {:active   :p1
-   :occupied []
-   :p1       []
-   :p2       []})
-
-(def cols (vec (range 7)))
+  (State. :p1 [] [] []))

 (def MAX_VALUE #?(:clj Long/MAX_VALUE :cljs js/Number.MAX_VALUE))

@@ -119,11 +118,22 @@
         (check-win (:p2 state)) :p2
         (empty? (valid-moves state)) :draw))

+(defn perform-move-old [state move]
+  (-> state
+      (update (:active state) #(conj % move))
+      (update :occupied #(conj % move))
+      (assoc :active (if (= :p1 (:active state)) :p2 :p1))))
+
 (defn perform-move [state move]
-  (-> state
-      (update-in [(:active state)] #(conj % move))
-      (update-in [:occupied] #(conj % move))
-      (assoc :active (if (= :p1 (:active state)) :p2 :p1))))
+  (let [p1-active? (= :p1 (:active state))]
+    (State. (if p1-active? :p2 :p1)
+            (conj (:occupied state) move)
+            (if p1-active?
+              (conj (:p1 state) move)
+              (:p1 state))
+            (if (not p1-active?)
+              (conj (:p2 state) move)
+              (:p2 state)))))

 (defn uct [node parent-visits]
   (if (zero? (:visited node))


Added buffer-update-lines! to nvim api.

Added buffer-update-lines! to nvim api.

--- src/neovim_client/nvim.clj
+++ src/neovim_client/nvim.clj
@@ -47,7 +47,14 @@

 ;; ***** Experimental *****

+(defn buffer-update-lines!
+  "Alter each line of the buffer using the function."
+  [buffer update-fn]
+  (doseq [n (range (get-buffer-line-count buffer))]
+    (buffer-set-line! buffer n (update-fn (buffer-get-line buffer n)))))
+
 (defn buffer-get-text
+  "Get the buffer's text as a single string."
   [buffer]
   (let [buf-size (get-buffer-line-count buffer)
         lines (map (partial buffer-get-line buffer) (range buf-size))]


matcher-combinators: Some tweaks

matcher-combinators: Some tweaks

--- test/com/nomistech/clojure_the_language/c_800_libraries/s_106_matcher_combinators/matcher_generators_test.clj
+++ test/com/nomistech/clojure_the_language/c_800_libraries/s_106_matcher_combinators/matcher_generators_test.clj
@@ -74,12 +74,12 @@
 ;;;; ---- Predicates ----

 (deftest predicate-test
-  ;; Functions are used as predicates.
+  ;; A function is interpreted as a predicate.
   (is (match? even?
               1234))
   (is (match? not
               (= 1 2)))
-  (is (match? inc ; not normally considered a predicate, but used as one here
+  (is (match? inc ; not normally considered a predicate, but treated as one here
               1)))

 ;;;; ___________________________________________________________________________
@@ -87,19 +87,18 @@

 (deftest maps-test

-  ;; A map is interpreted as an `embeds` matcher, which ignores
-  ;; un-specified keys.
-  ;; - TODO: When you understand properly, maybe fix that comma.
-
-  (testing "Bare map -- expected equal to actual"
+  ;; A map is interpreted as an `embeds` matcher, so it's OK for actual to
+  ;; have keys that are not present in expected.
+
+  (testing "Expected equal to actual"
     (is (match? {:a 1}
                 {:a 1})))

-  (testing "Bare map -- ignores unspecified keys"
+  (testing "Ignores unspecified keys"
     (is (match? {:a 1}
                 {:a 1 :b 2})))

-  (testing "Use m/absent to check for absence of a key"
+  (testing "Use `m/absent` to check for absence of a key"
     (is (match? {:a 1 :b m/absent}
                 {:a 1}))
     (is (match? (m/mismatch ; see ++use-of-mismatch++ at top of file


added #'buffer-cue-pos for changing the start frame of a ::buffer-cue.

--- src/overtone/sc/buffer.clj
+++ src/overtone/sc/buffer.clj
@@ -235,7 +235,7 @@
 (defn buffer-cue
   "Returns a buffer-cue which is similar to a regular buffer but may be used
   with the disk-in ugen to stream from a specific file on disk.
-  Use #'buffer-cue-close to close the stream to finish reading from disk.
+  Use #'buffer-cue-close to close the stream when finished.

   Options:

@@ -266,6 +266,20 @@
 (defn buffer-cue?
   [bc]
   (isa? (type bc) ::buffer-cue))
+
+(defn buffer-cue-pos
+  "Moves the start position of a buffer cue to the frame indicated by
+  'pos'. Defaults to 0. Returns the buffer when done."
+  ([buf-cue]
+     (buffer-cue-pos buf-cue 0))
+  ([buf-cue pos]
+     (assert (buffer-cue? buf-cue))
+     (when-not @(:open? buf-cue)
+       (throw (Exception. "buffer-cue is closed.")))
+     (let [{:keys [id path]} buf-cue]
+       (snd "/b_close" id)
+       (snd "/b_read" id path pos -1 0 1))
+     buf-cue))

 (defn buffer-cue-close
   "Close a buffer stream created with #'buffer-cue. Also frees the internal


add alternative pack implementation

add alternative pack implementation

--- clojure/ninety-nine-lisp-problems/src/ninety_nine_lisp_problems/core.clj
+++ clojure/ninety-nine-lisp-problems/src/ninety_nine_lisp_problems/core.clj
@@ -88,17 +88,22 @@
         (= (first coll) current) (recur (rest coll) current acc)
         :else (recur (rest coll) (first coll) (conj acc (first coll)))))))

+;; (defn pack
+;;   "Pack consecutive duplicates of list elements into sublists."
+;;   [coll]
+;;   (loop [coll coll
+;;          sublist '()
+;;          acc []]
+;;     (cond
+;;       (empty? coll) (conj acc sublist)
+;;       (empty? sublist) (recur (rest coll) (conj sublist (first coll)) acc)
+;;       (= (first sublist) (first coll)) (recur (rest coll) (conj sublist (first coll)) acc)
+;;       :else (recur (rest coll) (list (first coll)) (conj acc sublist)))))
+
 (defn pack
   "Pack consecutive duplicates of list elements into sublists."
   [coll]
-  (loop [coll coll
-         sublist '()
-         acc []]
-    (cond
-      (empty? coll) (conj acc sublist)
-      (empty? sublist) (recur (rest coll) (conj sublist (first coll)) acc)
-      (= (first sublist) (first coll)) (recur (rest coll) (conj sublist (first coll)) acc)
-      :else (recur (rest coll) (list (first coll)) (conj acc sublist)))))
+  (partition-by identity coll))

 (defn encode
   "Run-length encoding of a list"


Fix the wrapping adding function

Fix the wrapping adding function

--- src/petulant_life/life.clj
+++ src/petulant_life/life.clj
@@ -37,7 +37,7 @@
 (defn mk-wrapping-add [wrap-at]
   (fn [a b]
     (let [sum (+ a b)]
-      (cond (> sum wrap-at) (- sum wrap-at)
+      (cond (>= sum wrap-at) (- sum wrap-at)
             (< sum 0)       (+ wrap-at sum)
             :else           sum))))


Remake the run function in life ns

Remake the run function in life ns

Now actually prints out different iterations of the board

--- src/petulant_life/life.clj
+++ src/petulant_life/life.clj
@@ -68,9 +68,14 @@

 (def torus-step (stepper (mk-torus-neighbours [6 6]) #{3} #{2 3}))

-(defn run [step-n]
-  (->> (iterate rect-step #{[2 0] [2 1] [2 2] [1 2] [0 1]})
-       (drop (dec step-n))
-       first
-       (populate (empty-board 6 6))
-       pprint))
+(defn run [steps]
+  (loop [steps steps
+         board #{[2 0] [2 1] [2 2] [1 2] [0 1]}]
+    (when (> steps 0)
+      (->> board
+           (populate (empty-board 6 6))
+           pprint)
+      (println)
+      (Thread/sleep 1000)
+      (recur (dec steps)
+             (rect-step board)))))


thru rm_lm_study_cohorts (has column name="primary"

--- src/pg_demo/table_defs.clj
+++ src/pg_demo/table_defs.clj
@@ -5175,6 +5175,66 @@
               PRIMARY KEY (ENTERPRISE_ID,SITE_ID)
           ); " }

+    { "rm_lm_studies"
+          "CREATE TABLE rm_lm_studies (
+              ENTERPRISE_ID numeric NOT NULL,
+              STUDY_KEY numeric NOT NULL,
+              ALERT_AC_ID numeric,
+              STUDY_NUM varchar(35),
+              PROTOCOL_NUM varchar(40),
+              OTHER_NUM varchar(20),
+              STUDY_TYPE numeric,
+              UNBLIND_OK numeric(1),
+              ENCODING numeric(4),
+              DRUG_AUTO numeric(4),
+              DRUG_DICT varchar(20),
+              EVENT_AUTO numeric(4),
+              EVENT_DICT varchar(20),
+              EVENT_NO_MANUAL numeric(4),
+              EVENT_CLOSURE numeric(4),
+              CLASSIFICATION_ID numeric,
+              TEMPLATE numeric(1),
+              RULES_TEMPLATE_ID numeric,
+              ID_PROTOCOL numeric,
+              STUDY_ABBREV varchar(5),
+              DELETED timestamp,
+              COMMENTS varchar(1000),
+              DEV_PHASE_ID numeric,
+              CASE_UNDER_ADMIN_J numeric,
+              STUDY_NUM_J varchar(35),
+              TARGET_DISEASE_J varchar(500),
+              CLIN_COMP_NUM_J varchar(70),
+              STUDY_DESC text,
+              STUDY_DESC_J text,
+              CENTRAL_EVENT numeric,
+              COMMENTS_J varchar(1000),
+              PRIMARY KEY (ENTERPRISE_ID,STUDY_KEY)
+          ); " }
+
+    { "rm_lm_study_centers"
+          "CREATE TABLE rm_lm_study_centers (
+              ENTERPRISE_ID numeric NOT NULL,
+              CENTER_ID numeric NOT NULL,
+              STUDY_KEY numeric NOT NULL,
+              SEQ_NUM numeric NOT NULL,
+              DELETED timestamp,
+              PRIMARY KEY (ENTERPRISE_ID,CENTER_ID,STUDY_KEY,SEQ_NUM)
+          ); " }
+
+    { "rm_lm_study_cohorts"
+          "CREATE TABLE rm_lm_study_cohorts (
+              ENTERPRISE_ID numeric NOT NULL,
+              COHORT_ID numeric NOT NULL,
+              STUDY_KEY numeric NOT NULL,
+              BLIND_NAME varchar(70),
+              BLIND_NAME_J varchar(70),
+              STUDY_TYPE_ID numeric NOT NULL,
+              SORT_ID numeric NOT NULL,
+              \"primary\" numeric NOT NULL,
+              DELETED timestamp,
+              PRIMARY KEY (ENTERPRISE_ID,COHORT_ID)
+          ); " }
+
   ] ))

 (def dummy


Added delay optional slots.

Added delay optional slots.

--- src/plan_schema/coerce.clj
+++ src/plan_schema/coerce.clj
@@ -148,7 +148,8 @@
 (defmethod convert-property :plant-part [key value]
   (to-keyword key value))

-(def delay-activity-slots #{:uid :tpn-type :name :htn-node :constraints :label :display-name :controllable :end-node})
+(def delay-activity-slots #{:uid :tpn-type :name :htn-node :constraints :controllable :end-node})
+(def delay-activity-slots-optional #{:label :display-name})
 (def activity-slots #{:uid :tpn-type :name :htn-node :constraints :controllable :end-node :args :argsmap :command}) ;FIXME :args-mapping
 (def activity-slots-optional #{:interface :plantid :plant-part :label :display-name}) ;FIXME :args-mapping
 (def null-activity-slots #{:constraints :uid :tpn-type :end-node})
@@ -235,7 +236,8 @@
   (log-debug (with-out-str (pprint m))))

 (defmethod check-object :delay-activity [m]
-  (check-and-print-object-issues m delay-activity-slots))
+  (check-and-print-object-issues m delay-activity-slots
+    delay-activity-slots-optional))

 (defmethod check-object :null-activity [m]
   (check-and-print-object-issues m null-activity-slots))


limit 36345

limit 36345

--- src/pg_demo/core.clj
+++ src/pg_demo/core.clj
@@ -112,7 +112,7 @@
 (def enable-testing true)   ; #todo  FOR TESTING ONLY *******************************************
 (def test-rs-limit-fn       ; #todo  FOR TESTING ONLY *******************************************
   (if enable-testing
-    #(take 12345 %)
+    #(take 36345 %)
     identity ))

 ;; A threadpool with 2 threads.


adding used ip marking

adding used ip marking

--- src/proxmox/generators.clj
+++ src/proxmox/generators.clj
@@ -92,17 +92,24 @@
 (def range-keys [])

 (defn ip-range
-  ""
+  "Configured ip range"
   []
   (try+
     (let [[s e] (map ip-to-long (get* :hypervisor :proxmox :generators :ip-range))]
       [s e])
     (catch [:type :celestial.common/missing-conf] e nil)))

+(defn mark-used
+  "marks existing ips as used"
+  []
+  (doseq [ip (map ip-to-long (get* :hypervisor :proxmox :generators :used-ips))]
+    (wcar (car/zadd "ips" 1 ip))))
+
 (defn initialize-range
   "Initializes ip range zset 0 marks unused 1 marks used (only if missing)."
   []
-  (if-let [[s e] (ip-range)]
+  (when-let [[s e] (ip-range)]
+    (mark-used)
     (wcar
       (when-not (= 1 (car/exists "ips"))
         (doseq [ip (range s (+ 1 e))]
@@ -139,6 +146,8 @@
        return nil "
       {:ips "ips"} {:rel-ip (ip-to-long ip)}))))

+
+
 (comment
   (release-ip "192.168.5.130")
   (gen-ip {})


Fix for suggestions bar (#370)

Fix for suggestions bar (#370)

Former-commit-id: 697ba310d057a3504d3440b397475f7e8c40e146

--- src/status_im/chat/subs.cljs
+++ src/status_im/chat/subs.cljs
@@ -219,8 +219,10 @@
     (let [chat-id (subscribe [:get-current-chat-id])]
       (reaction
         (min (get-in @db [:animations :to-response-height @chat-id])
-             (- (:layout-height @db)
-                (get-in platform-specific [:component-styles :status-bar status-bar :height])))))))
+             (if (> (:layout-height @db) 0)
+               (- (:layout-height @db)
+                  (get-in platform-specific [:component-styles :status-bar status-bar :height]))
+               0))))))

 (register-sub :web-view-url
   (fn [db]


Replacing deleted ?

Replacing deleted ?

amann [9:43 AM]
@drazisil found the bug: https://github.com/circleci/frontend-private/pull/1489/files#diff-a0bede874dba456e74d1f8a863e2f9e5R502

[9:43]
no question mark

[9:43]
god damnit

[9:44]
@drazisil I have to run, can you get a pr together for that?


Change the height for web-view in entry-scene


defui-devtools: refactored selecting a file to be a callback to install-listeners

--- src/untangled/client/ui.cljs
+++ src/untangled/client/ui.cljs
@@ -4,8 +4,7 @@
     [om.dom :as dom]
     [goog.object :as gobj]
     [goog.dom :as gdom]
-    [goog.events :as gevt]
-    [figwheel.client.heads-up :refer [heads-up-event-dispatch]])
+    [goog.events :as gevt])
   (:import
     goog.events.EventType))

@@ -27,19 +26,15 @@
         (.. current-node -classList (add "highlight-element"))
         (reset! last-node current-node)))))

-(defn inspect-element [{:keys [node-clone]}]
+(defn inspect-element [{:keys [node-clone select-file]}]
   (fn [evt]
+    ;TODO: ?? disable all other clicks?
     ;(let [e (.getBrowserEvent evt)]
     ;  (.preventDefault e)
     ;  (.stopPropagation e)
     ;  (.stopImmediatePropagation e))
     (js/console.log @node-clone)
-    (let [{:keys [file line column]} (cljs.reader/read-string (.getAttribute @node-clone "data-untangled-ui"))]
-      (heads-up-event-dispatch
-        #js {:figwheelEvent "file-selected"
-             :fileName file
-             :fileLine (str line)
-             :fileColumn (str column)}))))
+    (select-file (cljs.reader/read-string (.getAttribute @node-clone "data-untangled-ui")))))

 (defn toggle-devtools [{:keys [last-node node-clone prev-on-click remove-all-listeners install-listeners]}]
   (fn [e]
@@ -62,9 +57,9 @@
           (gobj/set js/window "attached-listeners" (atom #{})))
     (gobj/get js/window "attached-listeners")))

-(defn install-listeners []
+(defn install-listeners [& {:keys [select-file]}]
   (let [add-listener (fn [et f] (swap! attached-listeners conj (gevt/listen js/document et f)))
-        add-and-remove-listener
+        remove-and-add-listener
         (fn [et f]
           (gevt/unlistenByKey (gobj/get js/window "keypress-listener"))
           (gobj/set js/window "keypress-listener"
@@ -76,12 +71,18 @@
              :node-clone (atom #js {})
              :prev-on-click (atom #js {})
              :remove-all-listeners remove-all-listeners
-             :install-listeners install-listeners}]
+             :install-listeners install-listeners
+             :select-file (or select-file
+                              (fn [{:keys [file line column]}]
+                                (figwheel.client.heads-up/heads-up-event-dispatch
+                                  #js {:figwheelEvent "file-selected"
+                                       :fileName file
+                                       :fileLine (str line)
+                                       :fileColumn (str column)})))}]
     (remove-all-listeners)
     (add-listener EventType.MOUSEMOVE (highlight-element ctx))
     (add-listener EventType.CLICK (inspect-element ctx))
-    (add-and-remove-listener EventType.KEYPRESS (toggle-devtools ctx))))
+    (remove-and-add-listener EventType.KEYPRESS (toggle-devtools ctx))))

 (defn wrap-render [meta-info {:keys [this class]} body]
-  (dom/div #js {:data-untangled-ui meta-info}
-    body))
+  (dom/div #js {:data-untangled-ui meta-info} body))