Ben Copsey

Added basic unit tests

Added responseStatusCode property
Various cleanups
@@ -26,9 +26,12 @@ @@ -26,9 +26,12 @@
26 //Files that will be POSTed to the url 26 //Files that will be POSTed to the url
27 NSMutableDictionary *fileData; 27 NSMutableDictionary *fileData;
28 28
29 - //Dictionary for custom request headers 29 + //Dictionary for custom HTTP request headers
30 NSMutableDictionary *requestHeaders; 30 NSMutableDictionary *requestHeaders;
31 31
  32 + //Will be populate with HTTP response headers from the server
  33 + NSDictionary *responseHeaders;
  34 +
32 //If useKeychainPersistance is true, network requests will attempt to read credentials from the keychain, and will save them in the keychain when they are successfully presented 35 //If useKeychainPersistance is true, network requests will attempt to read credentials from the keychain, and will save them in the keychain when they are successfully presented
33 BOOL useKeychainPersistance; 36 BOOL useKeychainPersistance;
34 37
@@ -72,11 +75,15 @@ @@ -72,11 +75,15 @@
72 CFReadStreamRef readStream; 75 CFReadStreamRef readStream;
73 76
74 // Authentication currently being used for prompting and resuming 77 // Authentication currently being used for prompting and resuming
75 - CFHTTPAuthenticationRef authentication; 78 + CFHTTPAuthenticationRef requestAuthentication;
  79 + NSMutableDictionary *requestCredentials;
76 80
77 // Credentials associated with the authentication (reused until server says no) 81 // Credentials associated with the authentication (reused until server says no)
78 //CFMutableDictionaryRef credentials; 82 //CFMutableDictionaryRef credentials;
79 83
  84 + // HTTP status code, eg: 200 = OK, 404 = Not found etc
  85 + int responseStatusCode;
  86 +
80 //Size of the response 87 //Size of the response
81 double contentLength; 88 double contentLength;
82 89
@@ -103,8 +110,6 @@ @@ -103,8 +110,6 @@
103 //Called on the delegate when the request fails 110 //Called on the delegate when the request fails
104 SEL didFailSelector; 111 SEL didFailSelector;
105 112
106 - NSDictionary *responseHeaders;  
107 - NSMutableDictionary *requestCredentials;  
108 113
109 } 114 }
110 115
@@ -113,9 +118,6 @@ @@ -113,9 +118,6 @@
113 // Should be an HTTP or HTTPS url, may include username and password if appropriate 118 // Should be an HTTP or HTTPS url, may include username and password if appropriate
114 - (id)initWithURL:(NSURL *)newURL; 119 - (id)initWithURL:(NSURL *)newURL;
115 120
116 -#pragma mark delegate configuration  
117 -  
118 -  
119 #pragma mark setup request 121 #pragma mark setup request
120 122
121 //Add a custom header to the request 123 //Add a custom header to the request
@@ -159,10 +161,10 @@ @@ -159,10 +161,10 @@
159 161
160 #pragma mark handling request complete / failure 162 #pragma mark handling request complete / failure
161 163
162 -//Called when a request completes successfully - defaults to: @selector(requestFinished:) 164 +// Called when a request completes successfully - defaults to: @selector(requestFinished:)
163 - (void)requestFinished; 165 - (void)requestFinished;
164 166
165 -//Called when a request fails - defaults to: @selector(requestFailed:) 167 +// Called when a request fails - defaults to: @selector(requestFailed:)
166 - (void)failWithProblem:(NSString *)problem; 168 - (void)failWithProblem:(NSString *)problem;
167 169
168 #pragma mark http authentication stuff 170 #pragma mark http authentication stuff
@@ -170,6 +172,12 @@ @@ -170,6 +172,12 @@
170 // Reads the response headers to find the content length, and returns true if the request needs a username and password (or if those supplied were incorrect) 172 // Reads the response headers to find the content length, and returns true if the request needs a username and password (or if those supplied were incorrect)
171 - (BOOL)readResponseHeadersReturningAuthenticationFailure; 173 - (BOOL)readResponseHeadersReturningAuthenticationFailure;
172 174
  175 +// Apply credentials to this request
  176 +- (BOOL)applyCredentials:(NSMutableDictionary *)newCredentials;
  177 +
  178 +// Attempt to obtain credentials for this request from the URL, username and password or keychain
  179 +- (NSMutableDictionary *)findCredentials;
  180 +
173 // Unlock (unpause) the request thread so it can resume the request 181 // Unlock (unpause) the request thread so it can resume the request
174 // Should be called by delegates when they have populated the authentication information after an authentication challenge 182 // Should be called by delegates when they have populated the authentication information after an authentication challenge
175 - (void)retryWithAuthentication; 183 - (void)retryWithAuthentication;
@@ -188,16 +196,23 @@ @@ -188,16 +196,23 @@
188 - (void)handleStreamComplete; 196 - (void)handleStreamComplete;
189 - (void)handleStreamError; 197 - (void)handleStreamError;
190 198
  199 +#pragma mark managing the session
  200 +
  201 ++ (void)setSessionCredentials:(NSMutableDictionary *)newCredentials;
  202 ++ (void)setSessionAuthentication:(CFHTTPAuthenticationRef)newAuthentication;
191 203
192 #pragma mark keychain storage 204 #pragma mark keychain storage
193 205
194 -//Save credentials to the keychain 206 +// Save credentials for this request to the keychain
  207 +- (void)saveCredentialsToKeychain:(NSMutableDictionary *)newCredentials;
  208 +
  209 +// Save creddentials to the keychain
195 + (void)saveCredentials:(NSURLCredential *)credentials forHost:(NSString *)host port:(int)port protocol:(NSString *)protocol realm:(NSString *)realm; 210 + (void)saveCredentials:(NSURLCredential *)credentials forHost:(NSString *)host port:(int)port protocol:(NSString *)protocol realm:(NSString *)realm;
196 211
197 -//Return credentials from the keychain 212 +// Return credentials from the keychain
198 + (NSURLCredential *)savedCredentialsForHost:(NSString *)host port:(int)port protocol:(NSString *)protocol realm:(NSString *)realm; 213 + (NSURLCredential *)savedCredentialsForHost:(NSString *)host port:(int)port protocol:(NSString *)protocol realm:(NSString *)realm;
199 214
200 -//Remove credentials from the keychain 215 +// Remove credentials from the keychain
201 + (void)removeCredentialsForHost:(NSString *)host port:(int)port protocol:(NSString *)protocol realm:(NSString *)realm; 216 + (void)removeCredentialsForHost:(NSString *)host port:(int)port protocol:(NSString *)protocol realm:(NSString *)realm;
202 217
203 218
@@ -215,9 +230,7 @@ @@ -215,9 +230,7 @@
215 @property (assign,readonly) BOOL complete; 230 @property (assign,readonly) BOOL complete;
216 @property (retain) NSDictionary *responseHeaders; 231 @property (retain) NSDictionary *responseHeaders;
217 @property (retain) NSDictionary *requestCredentials; 232 @property (retain) NSDictionary *requestCredentials;
218 - 233 +@property (assign) int responseStatusCode;
219 -- (void)saveCredentialsToKeychain:(NSMutableDictionary *)newCredentials;  
220 -- (BOOL)applyCredentials:(NSMutableDictionary *)newCredentials;  
221 234
222 235
223 @end 236 @end
@@ -33,12 +33,6 @@ static void ReadStreamClientCallBack(CFReadStreamRef readStream, CFStreamEventTy @@ -33,12 +33,6 @@ static void ReadStreamClientCallBack(CFReadStreamRef readStream, CFStreamEventTy
33 33
34 - (id)initWithURL:(NSURL *)newURL 34 - (id)initWithURL:(NSURL *)newURL
35 { 35 {
36 - [self init];  
37 - url = [newURL retain];  
38 - return self;  
39 -}  
40 -  
41 -- (id)init {  
42 [super init]; 36 [super init];
43 lastBytesSent = 0; 37 lastBytesSent = 0;
44 postData = nil; 38 postData = nil;
@@ -48,7 +42,7 @@ static void ReadStreamClientCallBack(CFReadStreamRef readStream, CFStreamEventTy @@ -48,7 +42,7 @@ static void ReadStreamClientCallBack(CFReadStreamRef readStream, CFStreamEventTy
48 requestHeaders = nil; 42 requestHeaders = nil;
49 authenticationRealm = nil; 43 authenticationRealm = nil;
50 outputStream = nil; 44 outputStream = nil;
51 - authentication = NULL; 45 + requestAuthentication = NULL;
52 //credentials = NULL; 46 //credentials = NULL;
53 request = NULL; 47 request = NULL;
54 responseHeaders = nil; 48 responseHeaders = nil;
@@ -57,13 +51,14 @@ static void ReadStreamClientCallBack(CFReadStreamRef readStream, CFStreamEventTy @@ -57,13 +51,14 @@ static void ReadStreamClientCallBack(CFReadStreamRef readStream, CFStreamEventTy
57 didFinishSelector = @selector(requestFinished:); 51 didFinishSelector = @selector(requestFinished:);
58 didFailSelector = @selector(requestFailed:); 52 didFailSelector = @selector(requestFailed:);
59 delegate = nil; 53 delegate = nil;
  54 + url = [newURL retain];
60 return self; 55 return self;
61 } 56 }
62 57
63 - (void)dealloc 58 - (void)dealloc
64 { 59 {
65 - if (authentication) { 60 + if (requestAuthentication) {
66 - CFRelease(authentication); 61 + CFRelease(requestAuthentication);
67 } 62 }
68 if (request) { 63 if (request) {
69 CFRelease(request); 64 CFRelease(request);
@@ -146,12 +141,6 @@ static void ReadStreamClientCallBack(CFReadStreamRef readStream, CFStreamEventTy @@ -146,12 +141,6 @@ static void ReadStreamClientCallBack(CFReadStreamRef readStream, CFStreamEventTy
146 141
147 #pragma mark request logic 142 #pragma mark request logic
148 143
149 -+ (void)setSessionCredentials:(NSMutableDictionary *)newCredentials  
150 -{  
151 - [sessionCredentials release];  
152 - sessionCredentials = [newCredentials retain];  
153 -}  
154 -  
155 // Create the request 144 // Create the request
156 - (void)main 145 - (void)main
157 { 146 {
@@ -173,8 +162,7 @@ static void ReadStreamClientCallBack(CFReadStreamRef readStream, CFStreamEventTy @@ -173,8 +162,7 @@ static void ReadStreamClientCallBack(CFReadStreamRef readStream, CFStreamEventTy
173 //If we've already talked to this server and have valid credentials, let's apply them to the request 162 //If we've already talked to this server and have valid credentials, let's apply them to the request
174 if (useSessionPersistance && sessionCredentials && sessionAuthentication) { 163 if (useSessionPersistance && sessionCredentials && sessionAuthentication) {
175 if (!CFHTTPMessageApplyCredentialDictionary(request, sessionAuthentication, (CFMutableDictionaryRef)sessionCredentials, NULL)) { 164 if (!CFHTTPMessageApplyCredentialDictionary(request, sessionAuthentication, (CFMutableDictionaryRef)sessionCredentials, NULL)) {
176 - CFRelease(sessionAuthentication); 165 + [ASIHTTPRequest setSessionAuthentication:NULL];
177 - sessionAuthentication = NULL;  
178 [ASIHTTPRequest setSessionCredentials:nil]; 166 [ASIHTTPRequest setSessionCredentials:nil];
179 } 167 }
180 } 168 }
@@ -415,9 +403,10 @@ static void ReadStreamClientCallBack(CFReadStreamRef readStream, CFStreamEventTy @@ -415,9 +403,10 @@ static void ReadStreamClientCallBack(CFReadStreamRef readStream, CFStreamEventTy
415 CFHTTPMessageRef headers = (CFHTTPMessageRef)CFReadStreamCopyProperty(readStream, kCFStreamPropertyHTTPResponseHeader); 403 CFHTTPMessageRef headers = (CFHTTPMessageRef)CFReadStreamCopyProperty(readStream, kCFStreamPropertyHTTPResponseHeader);
416 if (CFHTTPMessageIsHeaderComplete(headers)) { 404 if (CFHTTPMessageIsHeaderComplete(headers)) {
417 responseHeaders = (NSDictionary *)CFHTTPMessageCopyAllHeaderFields(headers); 405 responseHeaders = (NSDictionary *)CFHTTPMessageCopyAllHeaderFields(headers);
  406 + responseStatusCode = CFHTTPMessageGetResponseStatusCode(headers);
418 407
419 // Is the server response a challenge for credentials? 408 // Is the server response a challenge for credentials?
420 - isAuthenticationChallenge = (CFHTTPMessageGetResponseStatusCode(headers) == 401); 409 + isAuthenticationChallenge = (responseStatusCode == 401);
421 410
422 //We won't reset the download progress delegate if we got an authentication challenge 411 //We won't reset the download progress delegate if we got an authentication challenge
423 if (!isAuthenticationChallenge) { 412 if (!isAuthenticationChallenge) {
@@ -438,13 +427,6 @@ static void ReadStreamClientCallBack(CFReadStreamRef readStream, CFStreamEventTy @@ -438,13 +427,6 @@ static void ReadStreamClientCallBack(CFReadStreamRef readStream, CFStreamEventTy
438 } 427 }
439 428
440 429
441 -// Called by delegate to resume loading once authentication info has been populated  
442 -- (void)retryWithAuthentication  
443 -{  
444 - [authenticationLock lockWhenCondition:1];  
445 - [authenticationLock unlockWithCondition:2];  
446 -}  
447 -  
448 - (void)saveCredentialsToKeychain:(NSMutableDictionary *)newCredentials 430 - (void)saveCredentialsToKeychain:(NSMutableDictionary *)newCredentials
449 { 431 {
450 NSURLCredential *authenticationCredentials = [NSURLCredential credentialWithUser:[newCredentials objectForKey:(NSString *)kCFHTTPAuthenticationUsername] 432 NSURLCredential *authenticationCredentials = [NSURLCredential credentialWithUser:[newCredentials objectForKey:(NSString *)kCFHTTPAuthenticationUsername]
@@ -458,20 +440,16 @@ static void ReadStreamClientCallBack(CFReadStreamRef readStream, CFStreamEventTy @@ -458,20 +440,16 @@ static void ReadStreamClientCallBack(CFReadStreamRef readStream, CFStreamEventTy
458 - (BOOL)applyCredentials:(NSMutableDictionary *)newCredentials 440 - (BOOL)applyCredentials:(NSMutableDictionary *)newCredentials
459 { 441 {
460 442
461 - if (newCredentials && authentication && request) { 443 + if (newCredentials && requestAuthentication && request) {
462 // Apply whatever credentials we've built up to the old request 444 // Apply whatever credentials we've built up to the old request
463 - if (CFHTTPMessageApplyCredentialDictionary(request, authentication, (CFMutableDictionaryRef)newCredentials, NULL)) { 445 + if (CFHTTPMessageApplyCredentialDictionary(request, requestAuthentication, (CFMutableDictionaryRef)newCredentials, NULL)) {
464 //If we have credentials and they're ok, let's save them to the keychain 446 //If we have credentials and they're ok, let's save them to the keychain
465 if (useKeychainPersistance) { 447 if (useKeychainPersistance) {
466 [self saveCredentialsToKeychain:newCredentials]; 448 [self saveCredentialsToKeychain:newCredentials];
467 } 449 }
468 if (useSessionPersistance) { 450 if (useSessionPersistance) {
469 - if (sessionAuthentication) {  
470 - CFRelease(sessionAuthentication);  
471 - }  
472 - sessionAuthentication = authentication;  
473 - CFRetain(sessionAuthentication);  
474 451
  452 + [ASIHTTPRequest setSessionAuthentication:requestAuthentication];
475 [ASIHTTPRequest setSessionCredentials:newCredentials]; 453 [ASIHTTPRequest setSessionCredentials:newCredentials];
476 } 454 }
477 [self setRequestCredentials:newCredentials]; 455 [self setRequestCredentials:newCredentials];
@@ -481,15 +459,15 @@ static void ReadStreamClientCallBack(CFReadStreamRef readStream, CFStreamEventTy @@ -481,15 +459,15 @@ static void ReadStreamClientCallBack(CFReadStreamRef readStream, CFStreamEventTy
481 return FALSE; 459 return FALSE;
482 } 460 }
483 461
484 -- (NSMutableDictionary *)getCredentials 462 +- (NSMutableDictionary *)findCredentials
485 { 463 {
486 NSMutableDictionary *newCredentials = [[[NSMutableDictionary alloc] init] autorelease]; 464 NSMutableDictionary *newCredentials = [[[NSMutableDictionary alloc] init] autorelease];
487 465
488 // Get the authentication realm 466 // Get the authentication realm
489 [authenticationRealm release]; 467 [authenticationRealm release];
490 authenticationRealm = nil; 468 authenticationRealm = nil;
491 - if (!CFHTTPAuthenticationRequiresAccountDomain(authentication)) { 469 + if (!CFHTTPAuthenticationRequiresAccountDomain(requestAuthentication)) {
492 - authenticationRealm = (NSString *)CFHTTPAuthenticationCopyRealm(authentication); 470 + authenticationRealm = (NSString *)CFHTTPAuthenticationCopyRealm(requestAuthentication);
493 } 471 }
494 472
495 //First, let's look at the url to see if the username and password were included 473 //First, let's look at the url to see if the username and password were included
@@ -519,30 +497,37 @@ static void ReadStreamClientCallBack(CFReadStreamRef readStream, CFStreamEventTy @@ -519,30 +497,37 @@ static void ReadStreamClientCallBack(CFReadStreamRef readStream, CFStreamEventTy
519 [newCredentials setObject:pass forKey:(NSString *)kCFHTTPAuthenticationPassword]; 497 [newCredentials setObject:pass forKey:(NSString *)kCFHTTPAuthenticationPassword];
520 return newCredentials; 498 return newCredentials;
521 } 499 }
522 - return NULL; 500 + return nil;
  501 +}
  502 +
  503 +// Called by delegate to resume loading once authentication info has been populated
  504 +- (void)retryWithAuthentication
  505 +{
  506 + [authenticationLock lockWhenCondition:1];
  507 + [authenticationLock unlockWithCondition:2];
523 } 508 }
524 509
525 - (void)attemptToApplyCredentialsAndResume 510 - (void)attemptToApplyCredentialsAndResume
526 { 511 {
527 512
528 //Read authentication data 513 //Read authentication data
529 - if (!authentication) { 514 + if (!requestAuthentication) {
530 CFHTTPMessageRef responseHeader = (CFHTTPMessageRef) CFReadStreamCopyProperty(readStream,kCFStreamPropertyHTTPResponseHeader); 515 CFHTTPMessageRef responseHeader = (CFHTTPMessageRef) CFReadStreamCopyProperty(readStream,kCFStreamPropertyHTTPResponseHeader);
531 - authentication = CFHTTPAuthenticationCreateFromResponse(NULL, responseHeader); 516 + requestAuthentication = CFHTTPAuthenticationCreateFromResponse(NULL, responseHeader);
532 CFRelease(responseHeader); 517 CFRelease(responseHeader);
533 } 518 }
534 519
535 - if (!authentication) { 520 + if (!requestAuthentication) {
536 [self failWithProblem:@"Failed to get authentication object from response headers"]; 521 [self failWithProblem:@"Failed to get authentication object from response headers"];
537 return; 522 return;
538 } 523 }
539 524
540 //See if authentication is valid 525 //See if authentication is valid
541 CFStreamError err; 526 CFStreamError err;
542 - if (!CFHTTPAuthenticationIsValid(authentication, &err)) { 527 + if (!CFHTTPAuthenticationIsValid(requestAuthentication, &err)) {
543 528
544 - CFRelease(authentication); 529 + CFRelease(requestAuthentication);
545 - authentication = NULL; 530 + requestAuthentication = NULL;
546 531
547 // check for bad credentials, so we can give the delegate a chance to replace them 532 // check for bad credentials, so we can give the delegate a chance to replace them
548 if (err.domain == kCFStreamErrorDomainHTTP && (err.error == kCFStreamErrorHTTPAuthenticationBadUserName || err.error == kCFStreamErrorHTTPAuthenticationBadPassword)) { 533 if (err.domain == kCFStreamErrorDomainHTTP && (err.error == kCFStreamErrorHTTPAuthenticationBadUserName || err.error == kCFStreamErrorHTTPAuthenticationBadPassword)) {
@@ -572,9 +557,9 @@ static void ReadStreamClientCallBack(CFReadStreamRef readStream, CFStreamEventTy @@ -572,9 +557,9 @@ static void ReadStreamClientCallBack(CFReadStreamRef readStream, CFStreamEventTy
572 } 557 }
573 558
574 // are a user name & password needed? 559 // are a user name & password needed?
575 - } else if (CFHTTPAuthenticationRequiresUserNameAndPassword(authentication)) { 560 + } else if (CFHTTPAuthenticationRequiresUserNameAndPassword(requestAuthentication)) {
576 561
577 - NSMutableDictionary *newCredentials = [self getCredentials]; 562 + NSMutableDictionary *newCredentials = [self findCredentials];
578 563
579 //If we have some credentials to use let's apply them to the request and continue 564 //If we have some credentials to use let's apply them to the request and continue
580 if (newCredentials) { 565 if (newCredentials) {
@@ -714,6 +699,24 @@ static void ReadStreamClientCallBack(CFReadStreamRef readStream, CFStreamEventTy @@ -714,6 +699,24 @@ static void ReadStreamClientCallBack(CFReadStreamRef readStream, CFStreamEventTy
714 } 699 }
715 } 700 }
716 701
  702 +#pragma mark managing the session
  703 +
  704 ++ (void)setSessionCredentials:(NSMutableDictionary *)newCredentials
  705 +{
  706 + [sessionCredentials release];
  707 + sessionCredentials = [newCredentials retain];
  708 +}
  709 +
  710 ++ (void)setSessionAuthentication:(CFHTTPAuthenticationRef)newAuthentication
  711 +{
  712 + if (sessionAuthentication) {
  713 + CFRelease(sessionAuthentication);
  714 + }
  715 + sessionAuthentication = newAuthentication;
  716 + if (newAuthentication) {
  717 + CFRetain(sessionAuthentication);
  718 + }
  719 +}
717 720
718 #pragma mark keychain storage 721 #pragma mark keychain storage
719 722
@@ -774,4 +777,5 @@ static void ReadStreamClientCallBack(CFReadStreamRef readStream, CFStreamEventTy @@ -774,4 +777,5 @@ static void ReadStreamClientCallBack(CFReadStreamRef readStream, CFStreamEventTy
774 @synthesize complete; 777 @synthesize complete;
775 @synthesize responseHeaders; 778 @synthesize responseHeaders;
776 @synthesize requestCredentials; 779 @synthesize requestCredentials;
  780 +@synthesize responseStatusCode;
777 @end 781 @end
  1 +//
  2 +// ASIHTTPRequestTests.h
  3 +// asi-http-request
  4 +//
  5 +// Created by Ben Copsey on 01/08/2008.
  6 +// Copyright 2008 All-Seeing Interactive. All rights reserved.
  7 +//
  8 +
  9 +#import <SenTestingKit/SenTestingKit.h>
  10 +
  11 +
  12 +@interface ASIHTTPRequestTests : SenTestCase {
  13 +}
  14 +
  15 +- (void)testBasicDownload;
  16 +
  17 +@end
  1 +//
  2 +// ASIHTTPRequestTests.m
  3 +// asi-http-request
  4 +//
  5 +// Created by Ben Copsey on 01/08/2008.
  6 +// Copyright 2008 All-Seeing Interactive. All rights reserved.
  7 +//
  8 +
  9 +#import "ASIHTTPRequestTests.h"
  10 +#import "ASIHTTPRequest.h"
  11 +
  12 +@implementation ASIHTTPRequestTests
  13 +
  14 +- (void)testBasicDownload
  15 +{
  16 + //Grab data
  17 + NSURL *url = [[[NSURL alloc] initWithString:@"http://allseeing-i.com"] autorelease];
  18 + ASIHTTPRequest *request = [[[ASIHTTPRequest alloc] initWithURL:url] autorelease];
  19 + [request start];
  20 + NSString *html = [request dataString];
  21 + STAssertNotNil(html,@"Basic synchronous request failed");
  22 +
  23 + //Check we're getting the correct response headers
  24 + NSString *pingBackHeader = [[request responseHeaders] objectForKey:@"X-Pingback"];
  25 + BOOL success = [pingBackHeader isEqualToString:@"http://allseeing-i.com/Ping-Back"];
  26 + STAssertTrue(success,@"Failed to populate response headers");
  27 +
  28 + //Check we're getting back the correct status code
  29 + url = [[[NSURL alloc] initWithString:@"http://allseeing-i.com/a-page-that-does-not-exist"] autorelease];
  30 + request = [[[ASIHTTPRequest alloc] initWithURL:url] autorelease];
  31 + [request start];
  32 + success = ([request responseStatusCode] == 404);
  33 + STAssertTrue(success,@"Didn't get correct status code");
  34 +
  35 + //Check data
  36 + NSRange notFound = NSMakeRange(NSNotFound, 0);
  37 + success = !NSEqualRanges([html rangeOfString:@"All-Seeing Interactive"],notFound);
  38 + STAssertTrue(success,@"Failed to download the correct data");
  39 +
  40 + //Attempt to grab from bad url (astonishingly, there is a website at http://aaaaaaaaaaaaaaaaaaaaaaaaaaaaa.com !)
  41 + url = [[[NSURL alloc] initWithString:@"http://aaaaaaaaaaaaaaaaaaaaaaaaaaaaab.com"] autorelease];
  42 + request = [[[ASIHTTPRequest alloc] initWithURL:url] autorelease];
  43 + [request start];
  44 + NSError *error = [request error];
  45 + STAssertNotNil(error,@"Failed to generate an error for a bad host");
  46 +}
  47 +
  48 +@end
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
  3 +<plist version="1.0">
  4 +<dict>
  5 + <key>CFBundleDevelopmentRegion</key>
  6 + <string>English</string>
  7 + <key>CFBundleExecutable</key>
  8 + <string>${EXECUTABLE_NAME}</string>
  9 + <key>CFBundleIdentifier</key>
  10 + <string>com.yourcompany.${PRODUCT_NAME:identifier}</string>
  11 + <key>CFBundleInfoDictionaryVersion</key>
  12 + <string>6.0</string>
  13 + <key>CFBundlePackageType</key>
  14 + <string>BNDL</string>
  15 + <key>CFBundleSignature</key>
  16 + <string>????</string>
  17 + <key>CFBundleVersion</key>
  18 + <string>1.0</string>
  19 +</dict>
  20 +</plist>
@@ -255,7 +255,7 @@ @@ -255,7 +255,7 @@
255 <dict> 255 <dict>
256 <key>PBXSmartGroupTreeModuleColumnWidthsKey</key> 256 <key>PBXSmartGroupTreeModuleColumnWidthsKey</key>
257 <array> 257 <array>
258 - <real>186</real> 258 + <real>312</real>
259 </array> 259 </array>
260 <key>PBXSmartGroupTreeModuleColumnsKey_v4</key> 260 <key>PBXSmartGroupTreeModuleColumnsKey_v4</key>
261 <array> 261 <array>
@@ -267,20 +267,28 @@ @@ -267,20 +267,28 @@
267 <key>PBXSmartGroupTreeModuleOutlineStateExpansionKey</key> 267 <key>PBXSmartGroupTreeModuleOutlineStateExpansionKey</key>
268 <array> 268 <array>
269 <string>29B97314FDCFA39411CA2CEA</string> 269 <string>29B97314FDCFA39411CA2CEA</string>
  270 + <string>B5731AF70E430B020008024F</string>
270 <string>080E96DDFE201D6D7F000001</string> 271 <string>080E96DDFE201D6D7F000001</string>
  272 + <string>29B97315FDCFA39411CA2CEA</string>
271 <string>29B97317FDCFA39411CA2CEA</string> 273 <string>29B97317FDCFA39411CA2CEA</string>
  274 + <string>29B97323FDCFA39411CA2CEA</string>
  275 + <string>1058C7A0FEA54F0111CA2CBB</string>
  276 + <string>1C37FBAC04509CD000000102</string>
  277 + <string>B5731BB50E4318C20008024F</string>
  278 + <string>B5731C080E431A3C0008024F</string>
  279 + <string>B5731BBD0E4319180008024F</string>
  280 + <string>B5731C320E431B3F0008024F</string>
272 <string>1C37FABC05509CD000000102</string> 281 <string>1C37FABC05509CD000000102</string>
273 </array> 282 </array>
274 <key>PBXSmartGroupTreeModuleOutlineStateSelectionKey</key> 283 <key>PBXSmartGroupTreeModuleOutlineStateSelectionKey</key>
275 <array> 284 <array>
276 <array> 285 <array>
277 - <integer>4</integer> 286 + <integer>2</integer>
278 - <integer>1</integer>  
279 <integer>0</integer> 287 <integer>0</integer>
280 </array> 288 </array>
281 </array> 289 </array>
282 <key>PBXSmartGroupTreeModuleOutlineStateVisibleRectKey</key> 290 <key>PBXSmartGroupTreeModuleOutlineStateVisibleRectKey</key>
283 - <string>{{0, 0}, {186, 760}}</string> 291 + <string>{{0, 0}, {312, 760}}</string>
284 </dict> 292 </dict>
285 <key>PBXTopSmartGroupGIDs</key> 293 <key>PBXTopSmartGroupGIDs</key>
286 <array/> 294 <array/>
@@ -292,19 +300,19 @@ @@ -292,19 +300,19 @@
292 <key>GeometryConfiguration</key> 300 <key>GeometryConfiguration</key>
293 <dict> 301 <dict>
294 <key>Frame</key> 302 <key>Frame</key>
295 - <string>{{0, 0}, {203, 778}}</string> 303 + <string>{{0, 0}, {329, 778}}</string>
296 <key>GroupTreeTableConfiguration</key> 304 <key>GroupTreeTableConfiguration</key>
297 <array> 305 <array>
298 <string>MainColumn</string> 306 <string>MainColumn</string>
299 - <real>186</real> 307 + <real>312</real>
300 </array> 308 </array>
301 <key>RubberWindowFrame</key> 309 <key>RubberWindowFrame</key>
302 - <string>353 264 1342 819 0 0 1920 1178 </string> 310 + <string>483 359 1342 819 0 0 1920 1178 </string>
303 </dict> 311 </dict>
304 <key>Module</key> 312 <key>Module</key>
305 <string>PBXSmartGroupTreeModule</string> 313 <string>PBXSmartGroupTreeModule</string>
306 <key>Proportion</key> 314 <key>Proportion</key>
307 - <string>203pt</string> 315 + <string>329pt</string>
308 </dict> 316 </dict>
309 <dict> 317 <dict>
310 <key>Dock</key> 318 <key>Dock</key>
@@ -317,7 +325,7 @@ @@ -317,7 +325,7 @@
317 <key>PBXProjectModuleGUID</key> 325 <key>PBXProjectModuleGUID</key>
318 <string>1CE0B20306471E060097A5F4</string> 326 <string>1CE0B20306471E060097A5F4</string>
319 <key>PBXProjectModuleLabel</key> 327 <key>PBXProjectModuleLabel</key>
320 - <string>ASIHTTPRequest.h</string> 328 + <string>ASIHTTPRequestTests.m</string>
321 <key>PBXSplitModuleInNavigatorKey</key> 329 <key>PBXSplitModuleInNavigatorKey</key>
322 <dict> 330 <dict>
323 <key>Split0</key> 331 <key>Split0</key>
@@ -325,20 +333,26 @@ @@ -325,20 +333,26 @@
325 <key>PBXProjectModuleGUID</key> 333 <key>PBXProjectModuleGUID</key>
326 <string>1CE0B20406471E060097A5F4</string> 334 <string>1CE0B20406471E060097A5F4</string>
327 <key>PBXProjectModuleLabel</key> 335 <key>PBXProjectModuleLabel</key>
328 - <string>ASIHTTPRequest.h</string> 336 + <string>ASIHTTPRequestTests.m</string>
329 <key>_historyCapacity</key> 337 <key>_historyCapacity</key>
330 <integer>0</integer> 338 <integer>0</integer>
331 <key>bookmark</key> 339 <key>bookmark</key>
332 - <string>B569CF4A0E41D94E00B57986</string> 340 + <string>B5731DB10E433BDB0008024F</string>
333 <key>history</key> 341 <key>history</key>
334 <array> 342 <array>
335 - <string>B513D3E90E2BD48A000A50C6</string>  
336 - <string>B513D3EA0E2BD48A000A50C6</string>  
337 - <string>B5AACA810E3F3D3400064080</string>  
338 <string>B5127C400E41C09D00D266C2</string> 343 <string>B5127C400E41C09D00D266C2</string>
339 - <string>B5127C540E41C0F300D266C2</string> 344 + <string>B5731B350E430D310008024F</string>
340 - <string>B569CED90E41D71C00B57986</string> 345 + <string>B5731B8B0E4310180008024F</string>
341 - <string>B569CEDA0E41D71C00B57986</string> 346 + <string>B5731BBE0E4319180008024F</string>
  347 + <string>B5731BEE0E431A050008024F</string>
  348 + <string>B5731BEF0E431A050008024F</string>
  349 + <string>B5731BF00E431A050008024F</string>
  350 + <string>B5731C780E4333810008024F</string>
  351 + <string>B5731C790E4333810008024F</string>
  352 + <string>B5731D960E433A750008024F</string>
  353 + <string>B5731D970E433A750008024F</string>
  354 + <string>B5731DA30E433B550008024F</string>
  355 + <string>B5731DB00E433BDB0008024F</string>
342 </array> 356 </array>
343 <key>prevStack</key> 357 <key>prevStack</key>
344 <array> 358 <array>
@@ -349,41 +363,52 @@ @@ -349,41 +363,52 @@
349 <string>B5ABC8300E24CDE70072F422</string> 363 <string>B5ABC8300E24CDE70072F422</string>
350 <string>B513D4020E2BD48A000A50C6</string> 364 <string>B513D4020E2BD48A000A50C6</string>
351 <string>B513D4030E2BD48A000A50C6</string> 365 <string>B513D4030E2BD48A000A50C6</string>
352 - <string>B569CDCF0E41C1DC00B57986</string> 366 + <string>B5731B390E430D310008024F</string>
353 - <string>B569CDD50E41C1EE00B57986</string> 367 + <string>B5731B3A0E430D310008024F</string>
354 - <string>B569CE040E41C8E100B57986</string> 368 + <string>B5731B8F0E4310180008024F</string>
355 - <string>B569CE050E41C8E100B57986</string> 369 + <string>B5731BC00E4319180008024F</string>
356 - <string>B569CE060E41C8E100B57986</string> 370 + <string>B5731BF30E431A050008024F</string>
357 - <string>B569CE070E41C8E100B57986</string> 371 + <string>B5731BF40E431A050008024F</string>
358 - <string>B569CE130E41CB6200B57986</string> 372 + <string>B5731BF50E431A050008024F</string>
359 - <string>B569CE140E41CB6200B57986</string> 373 + <string>B5731BF60E431A050008024F</string>
360 - <string>B569CE1C0E41CCC500B57986</string> 374 + <string>B5731BF70E431A050008024F</string>
361 - <string>B569CE1D0E41CCC500B57986</string> 375 + <string>B5731BF80E431A050008024F</string>
362 - <string>B569CE1E0E41CCC500B57986</string> 376 + <string>B5731BF90E431A050008024F</string>
363 - <string>B569CE1F0E41CCC500B57986</string> 377 + <string>B5731BFA0E431A050008024F</string>
364 - <string>B569CE3A0E41D24C00B57986</string> 378 + <string>B5731BFB0E431A050008024F</string>
365 - <string>B569CE3B0E41D24C00B57986</string> 379 + <string>B5731BFC0E431A050008024F</string>
366 - <string>B569CE3C0E41D24C00B57986</string> 380 + <string>B5731C0B0E431A3C0008024F</string>
367 - <string>B569CE3D0E41D24C00B57986</string> 381 + <string>B5731C350E431B3F0008024F</string>
368 - <string>B569CE3E0E41D24C00B57986</string> 382 + <string>B5731C360E431B3F0008024F</string>
369 - <string>B569CE3F0E41D24C00B57986</string> 383 + <string>B5731C370E431B3F0008024F</string>
370 - <string>B569CE490E41D2D200B57986</string> 384 + <string>B5731C380E431B3F0008024F</string>
371 - <string>B569CE4A0E41D2D200B57986</string> 385 + <string>B5731C4D0E431B890008024F</string>
372 - <string>B569CE4B0E41D2D200B57986</string> 386 + <string>B5731C4E0E431B890008024F</string>
373 - <string>B569CE510E41D30800B57986</string> 387 + <string>B5731C4F0E431B890008024F</string>
374 - <string>B569CE5A0E41D3A800B57986</string> 388 + <string>B5731C500E431B890008024F</string>
375 - <string>B569CE610E41D3E300B57986</string> 389 + <string>B5731C620E431CD80008024F</string>
376 - <string>B569CE6A0E41D41200B57986</string> 390 + <string>B5731C630E431CD80008024F</string>
377 - <string>B569CE730E41D5EB00B57986</string> 391 + <string>B5731C7C0E4333810008024F</string>
378 - <string>B569CE740E41D5EB00B57986</string> 392 + <string>B5731C7D0E4333810008024F</string>
379 - <string>B569CE750E41D5EB00B57986</string> 393 + <string>B5731C7E0E4333810008024F</string>
380 - <string>B569CE760E41D5EB00B57986</string> 394 + <string>B5731C7F0E4333810008024F</string>
381 - <string>B569CE770E41D5EB00B57986</string> 395 + <string>B5731C800E4333810008024F</string>
382 - <string>B569CE780E41D5EB00B57986</string> 396 + <string>B5731C810E4333810008024F</string>
383 - <string>B569CE790E41D5EB00B57986</string> 397 + <string>B5731C820E4333810008024F</string>
384 - <string>B569CE7A0E41D5EB00B57986</string> 398 + <string>B5731C830E4333810008024F</string>
385 - <string>B569CE800E41D63F00B57986</string> 399 + <string>B5731C840E4333810008024F</string>
386 - <string>B569CEDB0E41D71C00B57986</string> 400 + <string>B5731C9A0E4334260008024F</string>
  401 + <string>B5731C9B0E4334260008024F</string>
  402 + <string>B5731C9C0E4334260008024F</string>
  403 + <string>B5731C9D0E4334260008024F</string>
  404 + <string>B5731D840E4339F30008024F</string>
  405 + <string>B5731D8C0E433A1F0008024F</string>
  406 + <string>B5731D990E433A750008024F</string>
  407 + <string>B5731D9A0E433A750008024F</string>
  408 + <string>B5731D9B0E433A750008024F</string>
  409 + <string>B5731D9C0E433A750008024F</string>
  410 + <string>B5731DA50E433B550008024F</string>
  411 + <string>B5731DA60E433B550008024F</string>
387 </array> 412 </array>
388 </dict> 413 </dict>
389 <key>SplitCount</key> 414 <key>SplitCount</key>
@@ -395,9 +420,9 @@ @@ -395,9 +420,9 @@
395 <key>GeometryConfiguration</key> 420 <key>GeometryConfiguration</key>
396 <dict> 421 <dict>
397 <key>Frame</key> 422 <key>Frame</key>
398 - <string>{{0, 0}, {1134, 679}}</string> 423 + <string>{{0, 0}, {1008, 679}}</string>
399 <key>RubberWindowFrame</key> 424 <key>RubberWindowFrame</key>
400 - <string>353 264 1342 819 0 0 1920 1178 </string> 425 + <string>483 359 1342 819 0 0 1920 1178 </string>
401 </dict> 426 </dict>
402 <key>Module</key> 427 <key>Module</key>
403 <string>PBXNavigatorGroup</string> 428 <string>PBXNavigatorGroup</string>
@@ -415,9 +440,9 @@ @@ -415,9 +440,9 @@
415 <key>GeometryConfiguration</key> 440 <key>GeometryConfiguration</key>
416 <dict> 441 <dict>
417 <key>Frame</key> 442 <key>Frame</key>
418 - <string>{{0, 684}, {1134, 94}}</string> 443 + <string>{{0, 684}, {1008, 94}}</string>
419 <key>RubberWindowFrame</key> 444 <key>RubberWindowFrame</key>
420 - <string>353 264 1342 819 0 0 1920 1178 </string> 445 + <string>483 359 1342 819 0 0 1920 1178 </string>
421 </dict> 446 </dict>
422 <key>Module</key> 447 <key>Module</key>
423 <string>XCDetailModule</string> 448 <string>XCDetailModule</string>
@@ -426,7 +451,7 @@ @@ -426,7 +451,7 @@
426 </dict> 451 </dict>
427 </array> 452 </array>
428 <key>Proportion</key> 453 <key>Proportion</key>
429 - <string>1134pt</string> 454 + <string>1008pt</string>
430 </dict> 455 </dict>
431 </array> 456 </array>
432 <key>Name</key> 457 <key>Name</key>
@@ -441,9 +466,9 @@ @@ -441,9 +466,9 @@
441 </array> 466 </array>
442 <key>TableOfContents</key> 467 <key>TableOfContents</key>
443 <array> 468 <array>
444 - <string>B569CDBD0E41C18F00B57986</string> 469 + <string>B5731BC20E4319180008024F</string>
445 <string>1CE0B1FE06471DED0097A5F4</string> 470 <string>1CE0B1FE06471DED0097A5F4</string>
446 - <string>B569CDBE0E41C18F00B57986</string> 471 + <string>B5731BC30E4319180008024F</string>
447 <string>1CE0B20306471E060097A5F4</string> 472 <string>1CE0B20306471E060097A5F4</string>
448 <string>1CE0B20506471E060097A5F4</string> 473 <string>1CE0B20506471E060097A5F4</string>
449 </array> 474 </array>
@@ -577,15 +602,15 @@ @@ -577,15 +602,15 @@
577 <integer>5</integer> 602 <integer>5</integer>
578 <key>WindowOrderList</key> 603 <key>WindowOrderList</key>
579 <array> 604 <array>
580 - <string>B569CDC80E41C18F00B57986</string> 605 + <string>B5731C3B0E431B3F0008024F</string>
581 - <string>B569CDC90E41C18F00B57986</string> 606 + <string>B5731C3C0E431B3F0008024F</string>
582 - <string>1CD10A99069EF8BA00B06720</string>  
583 <string>B5ABC8410E24CDE70072F422</string> 607 <string>B5ABC8410E24CDE70072F422</string>
  608 + <string>1CD10A99069EF8BA00B06720</string>
584 <string>1C78EAAD065D492600B07095</string> 609 <string>1C78EAAD065D492600B07095</string>
585 <string>/Users/ben/asi-http-request/asi-http-request.xcodeproj</string> 610 <string>/Users/ben/asi-http-request/asi-http-request.xcodeproj</string>
586 </array> 611 </array>
587 <key>WindowString</key> 612 <key>WindowString</key>
588 - <string>353 264 1342 819 0 0 1920 1178 </string> 613 + <string>483 359 1342 819 0 0 1920 1178 </string>
589 <key>WindowToolsV3</key> 614 <key>WindowToolsV3</key>
590 <array> 615 <array>
591 <dict> 616 <dict>
@@ -608,7 +633,7 @@ @@ -608,7 +633,7 @@
608 <key>PBXProjectModuleGUID</key> 633 <key>PBXProjectModuleGUID</key>
609 <string>1CD0528F0623707200166675</string> 634 <string>1CD0528F0623707200166675</string>
610 <key>PBXProjectModuleLabel</key> 635 <key>PBXProjectModuleLabel</key>
611 - <string>ASIHTTPRequest.m</string> 636 + <string>RunPlatformUnitTests.include</string>
612 <key>StatusBarVisibility</key> 637 <key>StatusBarVisibility</key>
613 <true/> 638 <true/>
614 </dict> 639 </dict>
@@ -617,7 +642,7 @@ @@ -617,7 +642,7 @@
617 <key>Frame</key> 642 <key>Frame</key>
618 <string>{{0, 0}, {1440, 536}}</string> 643 <string>{{0, 0}, {1440, 536}}</string>
619 <key>RubberWindowFrame</key> 644 <key>RubberWindowFrame</key>
620 - <string>396 341 1440 818 0 0 1920 1178 </string> 645 + <string>257 107 1440 818 0 0 1920 1178 </string>
621 </dict> 646 </dict>
622 <key>Module</key> 647 <key>Module</key>
623 <string>PBXNavigatorGroup</string> 648 <string>PBXNavigatorGroup</string>
@@ -641,7 +666,7 @@ @@ -641,7 +666,7 @@
641 <key>Frame</key> 666 <key>Frame</key>
642 <string>{{0, 541}, {1440, 236}}</string> 667 <string>{{0, 541}, {1440, 236}}</string>
643 <key>RubberWindowFrame</key> 668 <key>RubberWindowFrame</key>
644 - <string>396 341 1440 818 0 0 1920 1178 </string> 669 + <string>257 107 1440 818 0 0 1920 1178 </string>
645 </dict> 670 </dict>
646 <key>Module</key> 671 <key>Module</key>
647 <string>PBXBuildResultsModule</string> 672 <string>PBXBuildResultsModule</string>
@@ -664,14 +689,14 @@ @@ -664,14 +689,14 @@
664 <key>TableOfContents</key> 689 <key>TableOfContents</key>
665 <array> 690 <array>
666 <string>B5ABC8410E24CDE70072F422</string> 691 <string>B5ABC8410E24CDE70072F422</string>
667 - <string>B569CDBF0E41C18F00B57986</string> 692 + <string>B5731BC40E4319180008024F</string>
668 <string>1CD0528F0623707200166675</string> 693 <string>1CD0528F0623707200166675</string>
669 <string>XCMainBuildResultsModuleGUID</string> 694 <string>XCMainBuildResultsModuleGUID</string>
670 </array> 695 </array>
671 <key>ToolbarConfiguration</key> 696 <key>ToolbarConfiguration</key>
672 <string>xcode.toolbar.config.buildV3</string> 697 <string>xcode.toolbar.config.buildV3</string>
673 <key>WindowString</key> 698 <key>WindowString</key>
674 - <string>396 341 1440 818 0 0 1920 1178 </string> 699 + <string>257 107 1440 818 0 0 1920 1178 </string>
675 <key>WindowToolGUID</key> 700 <key>WindowToolGUID</key>
676 <string>B5ABC8410E24CDE70072F422</string> 701 <string>B5ABC8410E24CDE70072F422</string>
677 <key>WindowToolIsVisible</key> 702 <key>WindowToolIsVisible</key>
@@ -784,13 +809,13 @@ @@ -784,13 +809,13 @@
784 <key>TableOfContents</key> 809 <key>TableOfContents</key>
785 <array> 810 <array>
786 <string>1CD10A99069EF8BA00B06720</string> 811 <string>1CD10A99069EF8BA00B06720</string>
787 - <string>B569CDC00E41C18F00B57986</string> 812 + <string>B5731BE60E4319EE0008024F</string>
788 <string>1C162984064C10D400B95A72</string> 813 <string>1C162984064C10D400B95A72</string>
789 - <string>B569CDC10E41C18F00B57986</string> 814 + <string>B5731BE70E4319EE0008024F</string>
790 - <string>B569CDC20E41C18F00B57986</string> 815 + <string>B5731BE80E4319EE0008024F</string>
791 - <string>B569CDC30E41C18F00B57986</string> 816 + <string>B5731BE90E4319EE0008024F</string>
792 - <string>B569CDC40E41C18F00B57986</string> 817 + <string>B5731BEA0E4319EE0008024F</string>
793 - <string>B569CDC50E41C18F00B57986</string> 818 + <string>B5731BEB0E4319EE0008024F</string>
794 </array> 819 </array>
795 <key>ToolbarConfiguration</key> 820 <key>ToolbarConfiguration</key>
796 <string>xcode.toolbar.config.debugV3</string> 821 <string>xcode.toolbar.config.debugV3</string>
@@ -799,7 +824,7 @@ @@ -799,7 +824,7 @@
799 <key>WindowToolGUID</key> 824 <key>WindowToolGUID</key>
800 <string>1CD10A99069EF8BA00B06720</string> 825 <string>1CD10A99069EF8BA00B06720</string>
801 <key>WindowToolIsVisible</key> 826 <key>WindowToolIsVisible</key>
802 - <false/> 827 + <true/>
803 </dict> 828 </dict>
804 <dict> 829 <dict>
805 <key>FirstTimeWindowDisplayed</key> 830 <key>FirstTimeWindowDisplayed</key>
@@ -923,7 +948,7 @@ @@ -923,7 +948,7 @@
923 <key>Frame</key> 948 <key>Frame</key>
924 <string>{{0, 0}, {629, 511}}</string> 949 <string>{{0, 0}, {629, 511}}</string>
925 <key>RubberWindowFrame</key> 950 <key>RubberWindowFrame</key>
926 - <string>385 95 629 552 0 0 1920 1178 </string> 951 + <string>67 588 629 552 0 0 1920 1178 </string>
927 </dict> 952 </dict>
928 <key>Module</key> 953 <key>Module</key>
929 <string>PBXDebugCLIModule</string> 954 <string>PBXDebugCLIModule</string>
@@ -946,13 +971,13 @@ @@ -946,13 +971,13 @@
946 <key>TableOfContents</key> 971 <key>TableOfContents</key>
947 <array> 972 <array>
948 <string>1C78EAAD065D492600B07095</string> 973 <string>1C78EAAD065D492600B07095</string>
949 - <string>B569CDC60E41C18F00B57986</string> 974 + <string>B5731C0D0E431A3C0008024F</string>
950 <string>1C78EAAC065D492600B07095</string> 975 <string>1C78EAAC065D492600B07095</string>
951 </array> 976 </array>
952 <key>ToolbarConfiguration</key> 977 <key>ToolbarConfiguration</key>
953 <string>xcode.toolbar.config.consoleV3</string> 978 <string>xcode.toolbar.config.consoleV3</string>
954 <key>WindowString</key> 979 <key>WindowString</key>
955 - <string>385 95 629 552 0 0 1920 1178 </string> 980 + <string>67 588 629 552 0 0 1920 1178 </string>
956 <key>WindowToolGUID</key> 981 <key>WindowToolGUID</key>
957 <string>1C78EAAD065D492600B07095</string> 982 <string>1C78EAAD065D492600B07095</string>
958 <key>WindowToolIsVisible</key> 983 <key>WindowToolIsVisible</key>
This diff could not be displayed because it is too large.
This diff was suppressed by a .gitattributes entry.