     (if (= c cc) v
       (do (debug "cmd" args "timed out after" sec) nil))))
 
+(defn sqs-listen
+  "Listen on an SQS queue, sending messages to a channel, which is returned."
+ [& [url]]
+  (let [url (or url my-sqs-url)
+        c   (chan)]
+    (async/go-loop []
+      (if (pimpl/closed? c)
+        (debug "Shutting down sqs-listen" url)
+        (let [_ (trace "sqs-listen polling" url)
+              messages  (:messages (receive-message :queue-url url :wait-time-seconds 20))]
+          (trace "sq-listen" url "received" messages)
+          (doseq [{r :receipt-handle b :body} messages]
+            (debug "sqs-listen received" b)
+            (try (>! c (get (json/read-str b) "Message"))
+                 (catch Exception e (info "sqs-listen" (stack-trace e))))
+            (try (delete-message :queue-url url :receipt-handle r)
+                 (catch Exception e (info "sqs-listen" (stack-trace e)))))
+          (recur))))
+    c))
+
+(defmacro go-try [& forms]
+  `(go (try (do ~@forms)
+            (catch Exception e#
+              (do (debug "Caught exception" e#) nil)))))
+
 (defn request-status [rs]
   (let [d    (cmd-timeout 5 describe-spot-instance-requests :spot-instance-request-ids rs)
         sirs (:spot-instance-requests d)
         _    (debug "Request statuses" rs d sirs)]
     (map :state sirs)))
 
+(defn instance-info-map
+  "Returns map of instance-id to map of information about instance."
+  [is]
+  (let [res   (:reservations (describe-instances :instance-ids is))
+        ims   (map #(get-in % [:instances 0]) res)
+        xms   (map (fn [im] (m-section im
+                      [:instance-id
+                       [:state [:state :name]]
+                       [:ip :private-ip-address]
+                       [:host [:public-dns-name #(when (seq %) %)]]])) ims)]
+    (mseq->m xms :instance-id)))
+
+(defn request-info-map [ids]
+  (let [descs  (describe-spot-instance-requests :spot-instance-request-ids ids)
+        sirs   (:spot-instance-requests descs)
+        sirs   (map (fn [rm] (m-section rm [[:request-id :spot-instance-request-id] :state :instance-id])) sirs)
+        is     (filter string? (map :instance-id sirs))
+        ims    (instance-info-map is)
+        sirs   (map #(merge % (ims (:instance-id %))) sirs)]
+    (mseq->m sirs :request-id)))
+
+
+
 
 (defn good-strings [vs]
   (and (sequential?  vs)

  (let [d (describe-spot-instance-requests :spot-instance-request-ids rs)]
    (map :instance-id (:spot-instance-requests d))))

(defn cancel [rs]
  (let [c (:cancelled-spot-instance-requests
        (cancel-spot-instance-requests :spot-instance-request-ids rs))]
    (debug c)
    c))

(defn terminate [is]
  (let [t (terminate-instances :instance-ids is)]
    (debug t)
    t))

(defn- give-up-and-cancel [req & [msg]]
  (when msg (debug msg))
  (concat  (some-> req :is terminate)
           (some-> req :rs cancel)))

(defn request-spots [req]
  (let [args    (apply concat (seq req))
        rs     (apply request-spot-instances args)]
    (debug "Spot request" args "->" rs)
    (map :spot-instance-request-id  (:spot-instance-requests rs))))

(defn- add-requests [req]
  (let [req (assoc req :rs (request-spots (:req req)))]
    (patience
     #(assoc req :req-status (cmd-timeout 5 request-status (:rs req)))
     (fn [req] (let [rss (:req-status req)]
                 (and (seq rss) (every? #(= "active" %) rss))))
   #(give-up-and-cancel req "Failed to fulfill spot requests")
   600 60)))

(defn- add-instances [req]
  (patience 
   #(assoc req :is (request-instances (:rs req)))
   #(good-strings (:is %))
   #(give-up-and-cancel req "Failed to get instance ids")
   10 1))


(defn- add-hosts [req]
  (patience
   (fn [] (assoc req :hosts (->> (:is req)
                                 (describe-instances :instance-ids)
                                 :reservations
                                 (map #(get-in % [:instances 0 :public-dns-name])))))
   #(good-strings (:hosts %))
   #(give-up-and-cancel req "Failed to get hosts.")
   10 1))


(defn- add-ips [req]
  (patience
   (fn [] (assoc req :ips (->> (:is req)
                                 (describe-instances :instance-ids)
                                 :reservations
                                 (map #(get-in % [:instances 0 :private-ip-address])))))
   #(good-strings (:ips %))
   #(give-up-and-cancel req "Failed to get IPs")
   10 1))

(def ag (ssh/ssh-agent {}))





(defn EDNify
"EDN-ify an arbitrary object, leaving it alone if it's an innocuous string."
  [x] 
