     (.setReadTimeout con timeout)
     (with-open [in (.getInputStream con)
                 out (io/output-stream target-path)]
-      (io/copy in out))))
+      (io/copy in out))
+    target-path))
+
+(defn get-file-with-timeout
+  "Returns a stringified version of the file pointed to by url. If download
+  stalls for more than timeout ms an exception is thrown."
+  [url timeout]
+  (let [url (URL. url)
+        con  (.openConnection url)]
+    (.setReadTimeout con timeout)
+    (with-open [in (.getInputStream con)
+                out (StringWriter.)]
+      (io/copy in out)
+      (.toString out))))
 
 (defn download-file
   "Downloads the file pointed to by URI to local path target-path. If no timeout

(declare mk-path)

(defn resolve-tilde-path
  [path]
  (cond
   (= "~" path)
   (home-dir)

   (.startsWith path (str "~" (file-separator)))
   (mk-path [(home-dir) (chop-first-n 2 path)])

   :default
   path))

(defn mk-path
  "Takes a seq of strings and returns a string which is a concatanation of all
  the input strings separated by the system's default file separator."
  [parts]
  (let [path (apply str (interpose (file-separator) parts))]
    (resolve-tilde-path path)))


    ^{:doc "Useful file manipulation fns"
      :author "Sam Aaron"}
  overtone.helpers.file
  (:import [java.net URL]
           [java.io StringWriter File])
  (:use [clojure.java.io]
        [overtone.helpers.string])
  (:require [org.satta.glob :as satta-glob]
            [clojure.java.io :as io]))

(defn file?
  "Returns true if f is of type java.io.File"
  [f]
  (= java.io.File (type f)))

(defn- files->abs-paths
  "Given a seq of java.io.File objects, returns a seq of absolute paths for each
