<commit_before>import Foundation
import UIKit.UIImage


private func fetch<T>(var request: NSURLRequest, body: ((T) -> Void, (NSError) -> Void, NSData) -> Void) -> Promise<T> {
    if request.valueForHTTPHeaderField("User-Agent") == nil {
        let rq = request.mutableCopy() as NSMutableURLRequest
        rq.setValue(OMGUserAgent(), forHTTPHeaderField:"User-Agent")
        request = rq
    }

    return Promise<T> { (fulfiller, rejunker) in
        NSURLConnection.sendAsynchronousRequest(request, queue:Q) { (rsp, data, err) in

            assert(!NSThread.isMainThread())

            //TODO handle non 2xx responses
            //TODO in the event of a non 2xx rsp, try to parse JSON out of the response anyway

            func rejecter(error: NSError) {
                let info = NSMutableDictionary(dictionary: error.userInfo ?? [:])
                info[NSURLErrorFailingURLErrorKey] = request.URL
                info[NSURLErrorFailingURLStringErrorKey] = request.URL.absoluteString
                if data != nil { info[PMKURLErrorFailingDataKey] = data! }
                if rsp != nil { info[PMKURLErrorFailingURLResponseKey] = rsp! }
                rejunker(NSError(domain:error.domain, code:error.code, userInfo:info))
            }

            if err != nil {
                rejecter(err)
            } else {
                body(fulfiller, rejecter, data!)
            }
        }
    }
}

func NSJSONFromData<T>(data: NSData) -> Promise<T> {
    var error:NSError?
    let json:AnyObject? = NSJSONSerialization.JSONObjectWithData(data, options:nil, error:&error)

    if error != nil {
        return Promise(error: error!)
    } else if let cast = json as? T {
        return Promise(value: cast)
    } else {
        var info:Dictionary = [:]
        info[NSLocalizedDescriptionKey] = "The server returned JSON in an unexpected arrangement"
        if let jo:AnyObject = json { info[PMKJSONErrorJSONObjectKey] = jo }
        let error = NSError(domain:PMKErrorDomain, code:PMKJSONError, userInfo:info)
        return Promise(error: error)
    }
}

private func fetchJSON<T>(request: NSURLRequest) -> Promise<T> {
    return fetch(request) { (fulfill, reject, data) in
        let result: Promise<T> = NSJSONFromData(data)
        if result.fulfilled {
            fulfill(result.value!)
        } else {
            reject(result.error!)
        }
    }
}


extension NSURLConnection {

    // I couldn’t persuade Swift to process these generically hence the lack of DRY

    public class func GET(url:String) -> Promise<NSData> {
        return promise(NSURLRequest(URL:NSURL(string:url)))
    }
    public class func GET(url:String) -> Promise<String> {
        return promise(NSURLRequest(URL:NSURL(string:url)))
    }
    public class func GET(url:String) -> Promise<UIImage> {
        return promise(NSURLRequest(URL:NSURL(string:url)))
    }
    public class func GET(url:String) -> Promise<NSArray> {
        return promise(NSURLRequest(URL:NSURL(string:url)))
    }
    public class func GET(url:String) -> Promise<NSDictionary> {<commit_msg>Add Ruby JSON bug check from objc version<commit_after>import Foundation
import UIKit.UIImage


private func fetch<T>(var request: NSURLRequest, body: ((T) -> Void, (NSError) -> Void, NSData) -> Void) -> Promise<T> {
    if request.valueForHTTPHeaderField("User-Agent") == nil {
        let rq = request.mutableCopy() as NSMutableURLRequest
        rq.setValue(OMGUserAgent(), forHTTPHeaderField:"User-Agent")
        request = rq
    }

    return Promise<T> { (fulfiller, rejunker) in
        NSURLConnection.sendAsynchronousRequest(request, queue:Q) { (rsp, data, err) in

            assert(!NSThread.isMainThread())

            //TODO handle non 2xx responses
            //TODO in the event of a non 2xx rsp, try to parse JSON out of the response anyway

            func rejecter(error: NSError) {
                let info = NSMutableDictionary(dictionary: error.userInfo ?? [:])
                info[NSURLErrorFailingURLErrorKey] = request.URL
                info[NSURLErrorFailingURLStringErrorKey] = request.URL.absoluteString
                if data != nil { info[PMKURLErrorFailingDataKey] = data! }
                if rsp != nil { info[PMKURLErrorFailingURLResponseKey] = rsp! }
                rejunker(NSError(domain:error.domain, code:error.code, userInfo:info))
            }

            if err != nil {
                rejecter(err)
            } else {
                body(fulfiller, rejecter, data!)
            }
        }
    }
}

func NSJSONFromData(data: NSData) -> Promise<NSArray> {
    // work around ever-so-common Rails issue: https://github.com/rails/rails/issues/1742
    if data.isEqualToData(NSData(bytes: " ", length: 1)) {
        return Promise(value: NSArray())  // couldn’t do T() in generic function
    }
    return NSJSONFromDataT(data)
}

func NSJSONFromData(data: NSData) -> Promise<NSDictionary> {
    if data.isEqualToData(NSData(bytes: " ", length: 1)) {
        return Promise(value: NSDictionary())
    }
    return NSJSONFromDataT(data)
}

private func NSJSONFromDataT<T>(data: NSData) -> Promise<T> {
    var error:NSError?
    let json:AnyObject? = NSJSONSerialization.JSONObjectWithData(data, options:nil, error:&error)

    if error != nil {
        return Promise(error: error!)
    } else if let cast = json as? T {
        return Promise(value: cast)
    } else {
        var info:Dictionary = [:]
        info[NSLocalizedDescriptionKey] = "The server returned JSON in an unexpected arrangement"
        if let jo:AnyObject = json { info[PMKJSONErrorJSONObjectKey] = jo }
        let error = NSError(domain:PMKErrorDomain, code:PMKJSONError, userInfo:info)
        return Promise(error: error)
    }
}

private func fetchJSON<T>(request: NSURLRequest) -> Promise<T> {
    return fetch(request) { (fulfill, reject, data) in
        let result: Promise<T> = NSJSONFromDataT(data)
        if result.fulfilled {
            fulfill(result.value!)
        } else {
            reject(result.error!)
        }
    }
}


extension NSURLConnection {

    // I couldn’t persuade Swift to process these generically hence the lack of DRY

    public class func GET(url:String) -> Promise<NSData> {
        return promise(NSURLRequest(URL:NSURL(string:url)))
    }
    public class func GET(url:String) -> Promise<String> {
        return promise(NSURLRequest(URL:NSURL(string:url)))
    }
    public class func GET(url:String) -> Promise<UIImage> {
        return promise(NSURLRequest(URL:NSURL(string:url)))
    }
    public class func GET(url:String) -> Promise<NSArray> {
        return promise(NSURLRequest(URL:NSURL(string:url)))
    }
    public class func GET(url:String) -> Promise<NSDictionary> {
{'fraction_non_alphanumeric': 0.11078111078111078, 'fraction_numerical': 0.001485001485001485, 'mean_word_length': 2.7189398122584207, 'pattern_counts': {'":': 0, '<': 31, '<?xml version=': 0, '>': 55, 'https://': 1, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6976650', 'n_tokens_mistral': 2085, 'n_tokens_neox': 1999, 'n_words': 480}