 public extension EUtils {
     static func FASTA(accession: String, f: (String) -> Bool) throws
     {
-        let gilist = search(accession, database: "nuccore")
+        let gilist = IDList("nuccore", term: accession)
         guard gilist.count > 0 else { return }
-        let url = fetchURL(gilist[0], database: "nuccore").url
+        let url = fetchURL(gilist[0], database: "nuccore")
         try String(contentsOfURL: url, encoding: NSUTF8StringEncoding).enumerateLines { (line, inout stop: Bool) in
             stop = f(line)
         }
     }
 }
+
+func extractRunAttributes(escapedXML: String) -> [EUtils.Run]
+{
+    let xml = escapedXML.stringByReplacingOccurrencesOfString("&lt;", withString: "<")
+                        .stringByReplacingOccurrencesOfString("&gt;", withString: ">")
+                        .stringByReplacingOccurrencesOfString("&amp;", withString: "&")
+
+    class parserDelegate: NSObject, NSXMLParserDelegate {
+        var runs : [EUtils.Run] = []
+        
+        @objc func parser(_: NSXMLParser, didStartElement element: String, namespaceURI: String?, qualifiedName: String?, attributes: [String : String]) {
+            if element == "Run" && attributes["acc"] != nil {
+                runs.append(EUtils.Run(attr: attributes))
+            }
+        }
+    }
+    let d = parserDelegate()
+    let p = NSXMLParser(data: xml.dataUsingEncoding(NSUTF8StringEncoding)!)
+    
+    p.delegate = d
+    if p.parse() {
+        return d.runs
+    }
+    return []
+}
+
+public extension EUtils {
+    public struct Run : CustomStringConvertible {
+        private let attr: [String : String]
+        
+        public var accession: String {
+            get {
+                return attr["acc"]!
+            }
+        }
+        public var baseCount: UInt {
+            get {
+                if let x = attr["total_bases"], y = UInt(x) { return y }
+                return 0
+            }
+        }
+        public var spotCount: UInt {
+            get {
+                if let x = attr["total_spots"], y = UInt(x) { return y }
+                return 0
+            }
+        }
+        public var isLoaded: Bool {
+            get {
+                if let x = attr["load_done"] where x == "true" { return true }
+                return false
+            }
+        }
+        public var isPublic: Bool {
+            get {
+                if let x = attr["is_public"] where x == "true" { return true }
+                return false
+            }
+        }
+        public var description: String { get { return attr.description } }
+    }
+    static func SRARunList(term: String) -> [Run]
+    {
+        var rslt = [Run]()
+        for id in IDList("sra", term: term) {
+            let s = summary("sra", accession: id)
+            if let runs = s["runs"] as? String {
+                rslt.appendContentsOf(extractRunAttributes(runs))
+            }
+        }
+        return rslt
+    }
+}

}

public extension EUtils {
    static func summary(accession: String) throws -> [String:AnyObject]
    {
        let gilist = search(accession, database: "nuccore")
        guard gilist.count > 0 else { return [:] }
        let url = summaryURL(gilist[0], database: "nuccore").url
        guard
            let data = try? NSData(contentsOfURL: url, options: []),
            let json = try? NSJSONSerialization.JSONObjectWithData(data, options: []),

    }
}

extension EUtils {
    static func IDList(database: String, term: String) -> [String]
    {
        let url = searchURL(term, database: database)
        guard
            let data = try? NSData(contentsOfURL: url, options: []),
            let json = try? NSJSONSerialization.JSONObjectWithData(data, options: []),
