flesh out, add basic Instapaper support

This commit is contained in:
Sami Samhuri 2011-12-19 17:12:08 -05:00
parent 15c1744e66
commit ab538612df
22 changed files with 967 additions and 31 deletions

View file

@ -27,6 +27,11 @@
7B1A6EF1149D140600FC5105 /* SSDetailViewController_iPad.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7B1A6EEF149D140600FC5105 /* SSDetailViewController_iPad.xib */; };
7B1A6EF9149D148800FC5105 /* FiveByFive.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B1A6EF8149D148800FC5105 /* FiveByFive.m */; };
7B1A6EFC149D14C500FC5105 /* Show.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B1A6EFB149D14C500FC5105 /* Show.m */; };
7B4CADE9149FE797007E7941 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7B4CADE8149FE797007E7941 /* Security.framework */; };
7B4CADF0149FE944007E7941 /* UIAlertView+marshmallows.h in Headers */ = {isa = PBXBuildFile; fileRef = 7B4CADEE149FE944007E7941 /* UIAlertView+marshmallows.h */; };
7B4CADF1149FE944007E7941 /* UIAlertView+marshmallows.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B4CADEF149FE944007E7941 /* UIAlertView+marshmallows.m */; };
7B4CADF5149FEAE5007E7941 /* UIAlertViewDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 7B4CADF3149FEAE5007E7941 /* UIAlertViewDelegate.h */; };
7B4CADF6149FEAE5007E7941 /* UIAlertViewDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B4CADF4149FEAE5007E7941 /* UIAlertViewDelegate.m */; };
7B7302F2149D670A003547E5 /* GTMNSString+HTML.h in Headers */ = {isa = PBXBuildFile; fileRef = 7B7302EA149D670A003547E5 /* GTMNSString+HTML.h */; };
7B7302F3149D670A003547E5 /* GTMNSString+HTML.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B7302EB149D670A003547E5 /* GTMNSString+HTML.m */; };
7B7302F4149D670A003547E5 /* NSDate+InternetDateTime.h in Headers */ = {isa = PBXBuildFile; fileRef = 7B7302EC149D670A003547E5 /* NSDate+InternetDateTime.h */; };
@ -46,6 +51,12 @@
7B86894B149D5C1000F3A2C6 /* ShowViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B868949149D5C0F00F3A2C6 /* ShowViewController.m */; };
7B868951149D5C6F00F3A2C6 /* ShowViewController_iPad.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7B86894D149D5C6F00F3A2C6 /* ShowViewController_iPad.xib */; };
7B868952149D5C6F00F3A2C6 /* ShowViewController_iPhone.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7B86894F149D5C6F00F3A2C6 /* ShowViewController_iPhone.xib */; };
7BDCFA03149E695E00DDF1B3 /* MMHTTPRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 7BDCFA01149E695E00DDF1B3 /* MMHTTPRequest.h */; };
7BDCFA04149E695E00DDF1B3 /* MMHTTPRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 7BDCFA02149E695E00DDF1B3 /* MMHTTPRequest.m */; };
7BDCFA07149E69E700DDF1B3 /* MMHTTPClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 7BDCFA05149E69E700DDF1B3 /* MMHTTPClient.h */; };
7BDCFA08149E69E700DDF1B3 /* MMHTTPClient.m in Sources */ = {isa = PBXBuildFile; fileRef = 7BDCFA06149E69E700DDF1B3 /* MMHTTPClient.m */; };
7BDCFA0B149E6A2B00DDF1B3 /* NSString+marshmallows.h in Headers */ = {isa = PBXBuildFile; fileRef = 7BDCFA09149E6A2A00DDF1B3 /* NSString+marshmallows.h */; };
7BDCFA0C149E6A2B00DDF1B3 /* NSString+marshmallows.m in Sources */ = {isa = PBXBuildFile; fileRef = 7BDCFA0A149E6A2B00DDF1B3 /* NSString+marshmallows.m */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
@ -77,6 +88,11 @@
7B1A6EF8149D148800FC5105 /* FiveByFive.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FiveByFive.m; sourceTree = "<group>"; };
7B1A6EFA149D14C500FC5105 /* Show.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Show.h; sourceTree = "<group>"; };
7B1A6EFB149D14C500FC5105 /* Show.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Show.m; sourceTree = "<group>"; };
7B4CADE8149FE797007E7941 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; };
7B4CADEE149FE944007E7941 /* UIAlertView+marshmallows.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIAlertView+marshmallows.h"; sourceTree = "<group>"; };
7B4CADEF149FE944007E7941 /* UIAlertView+marshmallows.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIAlertView+marshmallows.m"; sourceTree = "<group>"; };
7B4CADF3149FEAE5007E7941 /* UIAlertViewDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UIAlertViewDelegate.h; sourceTree = "<group>"; };
7B4CADF4149FEAE5007E7941 /* UIAlertViewDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UIAlertViewDelegate.m; sourceTree = "<group>"; };
7B7302EA149D670A003547E5 /* GTMNSString+HTML.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "GTMNSString+HTML.h"; sourceTree = "<group>"; };
7B7302EB149D670A003547E5 /* GTMNSString+HTML.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "GTMNSString+HTML.m"; sourceTree = "<group>"; };
7B7302EC149D670A003547E5 /* NSDate+InternetDateTime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDate+InternetDateTime.h"; sourceTree = "<group>"; };
@ -98,6 +114,13 @@
7B868949149D5C0F00F3A2C6 /* ShowViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ShowViewController.m; sourceTree = "<group>"; };
7B86894E149D5C6F00F3A2C6 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/ShowViewController_iPad.xib; sourceTree = "<group>"; };
7B868950149D5C6F00F3A2C6 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/ShowViewController_iPhone.xib; sourceTree = "<group>"; };
7BDCFA00149E688600DDF1B3 /* InstapaperCredentials.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = InstapaperCredentials.h; sourceTree = "<group>"; };
7BDCFA01149E695E00DDF1B3 /* MMHTTPRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MMHTTPRequest.h; sourceTree = "<group>"; };
7BDCFA02149E695E00DDF1B3 /* MMHTTPRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MMHTTPRequest.m; sourceTree = "<group>"; };
7BDCFA05149E69E700DDF1B3 /* MMHTTPClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MMHTTPClient.h; sourceTree = "<group>"; };
7BDCFA06149E69E700DDF1B3 /* MMHTTPClient.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MMHTTPClient.m; sourceTree = "<group>"; };
7BDCFA09149E6A2A00DDF1B3 /* NSString+marshmallows.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+marshmallows.h"; sourceTree = "<group>"; };
7BDCFA0A149E6A2B00DDF1B3 /* NSString+marshmallows.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+marshmallows.m"; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -105,6 +128,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
7B4CADE9149FE797007E7941 /* Security.framework in Frameworks */,
7B1A6ECF149D140600FC5105 /* UIKit.framework in Frameworks */,
7B1A6ED1149D140600FC5105 /* Foundation.framework in Frameworks */,
7B1A6ED3149D140600FC5105 /* CoreGraphics.framework in Frameworks */,
@ -118,6 +142,7 @@
isa = PBXGroup;
children = (
7B7302E9149D66ED003547E5 /* MWFeedParser */,
7B4CADF2149FE954007E7941 /* Marshmallows */,
7B1A6ED4149D140600FC5105 /* 5by5Browser */,
7B1A6ECD149D140600FC5105 /* Frameworks */,
7B1A6ECB149D140600FC5105 /* Products */,
@ -135,6 +160,7 @@
7B1A6ECD149D140600FC5105 /* Frameworks */ = {
isa = PBXGroup;
children = (
7B4CADE8149FE797007E7941 /* Security.framework */,
7B1A6ECE149D140600FC5105 /* UIKit.framework */,
7B1A6ED0149D140600FC5105 /* Foundation.framework */,
7B1A6ED2149D140600FC5105 /* CoreGraphics.framework */,
@ -145,6 +171,7 @@
7B1A6ED4149D140600FC5105 /* 5by5Browser */ = {
isa = PBXGroup;
children = (
7BDCFA00149E688600DDF1B3 /* InstapaperCredentials.h */,
7B1A6EDD149D140600FC5105 /* SSAppDelegate.h */,
7B1A6EDE149D140600FC5105 /* SSAppDelegate.m */,
7B868948149D5C0F00F3A2C6 /* ShowViewController.h */,
@ -187,6 +214,24 @@
name = "Supporting Files";
sourceTree = "<group>";
};
7B4CADF2149FE954007E7941 /* Marshmallows */ = {
isa = PBXGroup;
children = (
7BDCFA05149E69E700DDF1B3 /* MMHTTPClient.h */,
7BDCFA06149E69E700DDF1B3 /* MMHTTPClient.m */,
7BDCFA01149E695E00DDF1B3 /* MMHTTPRequest.h */,
7BDCFA02149E695E00DDF1B3 /* MMHTTPRequest.m */,
7BDCFA09149E6A2A00DDF1B3 /* NSString+marshmallows.h */,
7BDCFA0A149E6A2B00DDF1B3 /* NSString+marshmallows.m */,
7B4CADF3149FEAE5007E7941 /* UIAlertViewDelegate.h */,
7B4CADF4149FEAE5007E7941 /* UIAlertViewDelegate.m */,
7B4CADEE149FE944007E7941 /* UIAlertView+marshmallows.h */,
7B4CADEF149FE944007E7941 /* UIAlertView+marshmallows.m */,
);
name = Marshmallows;
path = 5by5Browser;
sourceTree = "<group>";
};
7B7302E7149D66EA003547E5 /* Categories */ = {
isa = PBXGroup;
children = (
@ -232,6 +277,11 @@
7B730303149D6714003547E5 /* MWFeedItem.h in Headers */,
7B730305149D6714003547E5 /* MWFeedParser_Private.h in Headers */,
7B730306149D6714003547E5 /* MWFeedParser.h in Headers */,
7BDCFA03149E695E00DDF1B3 /* MMHTTPRequest.h in Headers */,
7BDCFA07149E69E700DDF1B3 /* MMHTTPClient.h in Headers */,
7BDCFA0B149E6A2B00DDF1B3 /* NSString+marshmallows.h in Headers */,
7B4CADF0149FE944007E7941 /* UIAlertView+marshmallows.h in Headers */,
7B4CADF5149FEAE5007E7941 /* UIAlertViewDelegate.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -326,6 +376,11 @@
7B730302149D6714003547E5 /* MWFeedInfo.m in Sources */,
7B730304149D6714003547E5 /* MWFeedItem.m in Sources */,
7B730307149D6714003547E5 /* MWFeedParser.m in Sources */,
7BDCFA04149E695E00DDF1B3 /* MMHTTPRequest.m in Sources */,
7BDCFA08149E69E700DDF1B3 /* MMHTTPClient.m in Sources */,
7BDCFA0C149E6A2B00DDF1B3 /* NSString+marshmallows.m in Sources */,
7B4CADF1149FE944007E7941 /* UIAlertView+marshmallows.m in Sources */,
7B4CADF6149FEAE5007E7941 /* UIAlertViewDelegate.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

View file

@ -5,7 +5,7 @@
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleDisplayName</key>
<string>${PRODUCT_NAME}</string>
<string>5by5 Browser</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIdentifier</key>
@ -24,6 +24,8 @@
<string>1.0</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UIStatusBarStyle</key>
<string>UIStatusBarStyleBlackTranslucent</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>

View file

@ -7,14 +7,18 @@
//
#import <Foundation/Foundation.h>
#import "Show.h"
@class Show;
@interface Episode : NSObject
@property (nonatomic, retain) NSString *name;
@property (nonatomic, retain) NSString *number;
@property (nonatomic, retain) Show *show;
@property (nonatomic, retain) NSURL *url;
+ (id) episodeWithName: (NSString *)name number: (NSString *)number url: (NSURL *)url;
- (id) initWithName: (NSString *)name number: (NSString *)number url: (NSURL *)url;
+ (id) episodeWithShow: (Show *)show name: (NSString *)name number: (NSString *)number url: (NSURL *)url;
- (id) initWithShow: (Show *)show name: (NSString *)name number: (NSString *)number url: (NSURL *)url;
@end

View file

@ -12,17 +12,19 @@
@synthesize name = _name;
@synthesize number = _number;
@synthesize show = _show;
@synthesize url = _url;
+ (id) episodeWithName: (NSString *)name number: (NSString *)number url: (NSURL *)url
+ (id) episodeWithShow: (Show *)show name: (NSString *)name number: (NSString *)number url: (NSURL *)url
{
return [[self alloc] initWithName: name number: number url: url];
return [[self alloc] initWithShow: show name: name number: number url: url];
}
- (id) initWithName: (NSString *)name number: (NSString *)number url: (NSURL *)url
- (id) initWithShow: (Show *)show name: (NSString *)name number: (NSString *)number url: (NSURL *)url
{
self = [super init];
if (self) {
self.show = show;
self.name = name;
self.number = number;
self.url = url;
@ -30,4 +32,13 @@
return self;
}
- (void) setName: (NSString *)name
{
if (self.show && [name hasPrefix: self.show.name]) {
NSString *showName = [self.show.name stringByAppendingString: @" "];
name = [name stringByReplacingOccurrencesOfString: showName withString: @""];
}
_name = name;
}
@end

View file

@ -0,0 +1,54 @@
//
// MMHTTPClient.h
// Marshmallows
//
// Created by Sami Samhuri on 11-09-03.
// Copyright 2011 Guru Logic. All rights reserved.
//
#import <UIKit/UIImage.h>
#import "MMHTTPRequest.h"
@interface MMHTTPClient : NSObject
{
NSString *_baseURL;
NSUInteger _timeout;
}
+ (MMHTTPClient *) sharedClient;
+ (id) client;
+ (id) clientWithBaseURL: (NSString *)baseURL;
+ (id) clientWithBaseURL: (NSString *)baseURL timeout: (NSUInteger)timeout;
+ (NSString *) pathFor: (NSString *)first, ... NS_REQUIRES_NIL_TERMINATION;
+ (NSString *) urlFor: (NSString *)first, ... NS_REQUIRES_NIL_TERMINATION;
+ (NSString *) urlWithPath: (NSString *)path;
+ (MMHTTPRequest *) request: (NSDictionary *)options then: (MMHTTPCallback)callback;
+ (MMHTTPRequest *) get: (NSString *)url then: (MMHTTPCallback)callback;
+ (MMHTTPRequest *) getImage: (NSString *)url then: (MMHTTPImageCallback)callback;
+ (MMHTTPRequest *) getText: (NSString *)url then: (MMHTTPTextCallback)callback;
+ (MMHTTPRequest *) post: (NSString *)url then: (MMHTTPCallback)callback;
+ (MMHTTPRequest *) post: (NSString *)url fields: (NSDictionary *)fields then: (MMHTTPCallback)callback;
+ (MMHTTPRequest *) post: (NSString *)url data: (NSData *)data then: (MMHTTPCallback)callback;
+ (MMHTTPRequest *) put: (NSString *)url data: (NSData *)data then: (MMHTTPCallback)callback;
+ (MMHTTPRequest *) delete: (NSString *)url then: (MMHTTPCallback)callback;
@property (nonatomic, retain) NSString *baseURL;
@property NSUInteger timeout;
- (id) initWithBaseURL: (NSString *)baseURl;
- (id) initWithBaseURL: (NSString *)baseURl timeout: (NSUInteger)timeout;
- (NSString *) pathFor: (NSString *)first, ... NS_REQUIRES_NIL_TERMINATION;
- (NSString *) urlFor: (NSString *)first, ... NS_REQUIRES_NIL_TERMINATION;
- (NSString *) urlWithPath: (NSString *)path;
- (MMHTTPRequest *) request: (NSDictionary *)options then: (MMHTTPCallback)callback;
- (MMHTTPRequest *) get: (NSString *)url then: (MMHTTPCallback)callback;
- (MMHTTPRequest *) getImage: (NSString *)url then: (MMHTTPImageCallback)callback;
- (MMHTTPRequest *) getText: (NSString *)url then: (MMHTTPTextCallback)callback;
- (MMHTTPRequest *) post: (NSString *)url then: (MMHTTPCallback)callback;
- (MMHTTPRequest *) post: (NSString *)url fields: (NSDictionary *)fields then: (MMHTTPCallback)callback;
- (MMHTTPRequest *) post: (NSString *)url data: (NSData *)data then: (MMHTTPCallback)callback;
- (MMHTTPRequest *) put: (NSString *)url data: (NSData *)data then: (MMHTTPCallback)callback;
- (MMHTTPRequest *) delete: (NSString *)url then: (MMHTTPCallback)callback;
@end

252
5by5Browser/MMHTTPClient.m Normal file
View file

@ -0,0 +1,252 @@
//
// MMHTTPClient.m
// Marshmallows
//
// Created by Sami Samhuri on 11-09-03.
// Copyright 2011 Guru Logic. All rights reserved.
//
#import "MMHTTPClient.h"
#import "NSString+marshmallows.h"
MMHTTPClient *_client;
NSString *JoinURLComponents(NSString *first, va_list args)
{
NSMutableString *url = [NSMutableString string];
NSString *slash = @"";
for (NSString *arg = first; arg != nil; arg = va_arg(args, NSString *)) {
[url appendFormat: @"%@%@", slash, [arg stringByURLEncoding]];
slash = @"/";
}
return [NSString stringWithString: url];
}
@implementation MMHTTPClient
@synthesize baseURL = _baseURL;
@synthesize timeout = _timeout;
+ (MMHTTPClient *) sharedClient
{
if (!_client) {
_client = [[self alloc] init];
}
return _client;
}
+ (id) client
{
return [[self alloc] init];
}
+ (id) clientWithBaseURL: (NSString *)baseURL
{
return [[self alloc] initWithBaseURL: baseURL];
}
+ (id) clientWithBaseURL: (NSString *)baseURL timeout: (NSUInteger)timeout
{
return [[self alloc] initWithBaseURL: baseURL timeout: timeout];
}
+ (NSString *) pathFor: (NSString *)first, ...
{
va_list args;
va_start(args, first);
NSString *url = JoinURLComponents(first, args);
va_end(args);
return url;
}
+ (NSString *) urlFor: (NSString *)first, ...
{
va_list args;
va_start(args, first);
NSString *url = [[[self sharedClient] baseURL] stringByAppendingString: JoinURLComponents(first, args)];
va_end(args);
return url;
}
+ (NSString *) urlWithPath: (NSString *)path
{
return [[[self sharedClient] baseURL] stringByAppendingPathComponent: path];
}
+ (MMHTTPRequest *) request: (NSDictionary *)options then: (MMHTTPCallback)callback
{
return [[self sharedClient] request: options then: callback];
}
+ (MMHTTPRequest *) get: (NSString *)url then: (MMHTTPCallback)callback
{
return [[self sharedClient] get: url then: callback];
}
+ (MMHTTPRequest *) getImage: (NSString *)url then: (MMHTTPImageCallback)callback
{
return [[self sharedClient] getImage: url then: callback];
}
+ (MMHTTPRequest *) getText: (NSString *)url then: (MMHTTPTextCallback)callback
{
return [[self sharedClient] getText: url then: callback];
}
+ (MMHTTPRequest *) post: (NSString *)url then: (MMHTTPCallback)callback
{
return [[self sharedClient] post: url then: callback];
}
+ (MMHTTPRequest *) post: (NSString *)url fields: (NSDictionary *)fields then: (MMHTTPCallback)callback
{
return [[self sharedClient] post: url fields: fields then: callback];
}
+ (MMHTTPRequest *) post: (NSString *)url data: (NSData *)data then: (MMHTTPCallback)callback
{
return [[self sharedClient] post: url data: data then: callback];
}
+ (MMHTTPRequest *) put: (NSString *)url data: (NSData *)data then: (MMHTTPCallback)callback
{
return [[self sharedClient] put: url data: data then: callback];
}
+ (MMHTTPRequest *) delete: (NSString *)url then: (MMHTTPCallback)callback
{
return [[self sharedClient] delete: url then: callback];
}
- (id) init
{
return [self initWithBaseURL: nil timeout: MMHTTPRequestDefaultTimeout];
}
- (id) initWithBaseURL: (NSString *)baseURL
{
return [self initWithBaseURL: baseURL timeout: MMHTTPRequestDefaultTimeout];
}
- (id) initWithBaseURL: (NSString *)baseURL timeout: (NSUInteger)timeout
{
self = [super init];
if (self) {
_baseURL = [baseURL copy];
_timeout = timeout;
}
return self;
}
- (NSString *) pathFor: (NSString *)first, ...
{
va_list args;
va_start(args, first);
NSString *url = JoinURLComponents(first, args);
va_end(args);
return url;
}
- (NSString *) urlFor: (NSString *)first, ...
{
va_list args;
va_start(args, first);
NSString *url = [_baseURL stringByAppendingString: JoinURLComponents(first, args)];
va_end(args);
return url;
}
- (NSString *) urlWithPath: (NSString *)path
{
return [_baseURL stringByAppendingPathComponent: path];
}
- (MMHTTPRequest *) getImage: (NSString *)url then: (MMHTTPImageCallback)callback
{
return [self request: [NSDictionary dictionary] then: (MMHTTPCallback)callback];
}
- (MMHTTPRequest *) getText: (NSString *)url then: (MMHTTPTextCallback)callback
{
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
url, @"url",
@"text", @"type",
nil];
return [self request: options then: (MMHTTPCallback)callback];
}
- (MMHTTPRequest *) get: (NSString *)url then: (MMHTTPCallback)callback
{
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
url, @"url",
@"image", @"type",
nil];
return [self request: options then: (MMHTTPCallback)callback];
}
- (MMHTTPRequest *) post: (NSString *)url then: (MMHTTPCallback)callback
{
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
@"POST", @"method",
url, @"url",
nil];
return [self request: options then: callback];
}
- (MMHTTPRequest *) post: (NSString *)url fields: (NSDictionary *)fields then: (MMHTTPCallback)callback
{
NSMutableArray *parts = [NSMutableArray array];
NSString *value;
for (NSString *key in [fields keyEnumerator]) {
value = [fields objectForKey: key];
[parts addObject: [NSString stringWithFormat: @"%@=%@", [key stringByURLEncoding], [value stringByURLEncoding]]];
}
NSString *body = [parts componentsJoinedByString: @"&"];
return [self post: url data: [body dataUsingEncoding: NSUTF8StringEncoding] then: callback];
}
- (MMHTTPRequest *) post: (NSString *)url data: (NSData *)data then: (MMHTTPCallback)callback
{
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
@"POST", @"method",
url, @"url",
data, @"data",
nil];
return [self request: options then: callback];
}
- (MMHTTPRequest *) put: (NSString *)url data: (NSData *)data then: (MMHTTPCallback)callback
{
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
@"PUT", @"method",
url, @"url",
data, @"data",
nil];
return [self request: options then: callback];
}
- (MMHTTPRequest *) delete: (NSString *)url then: (MMHTTPCallback)callback
{
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
@"DELETE", @"method",
url, @"url",
nil];
return [self request: options then: callback];
}
- (MMHTTPRequest *) request: (NSDictionary *)options then: (MMHTTPCallback)callback
{
NSString *url = [options objectForKey: @"url"];
NSMutableDictionary *mutableOptions = [options mutableCopy];
if (_baseURL && !([url hasPrefix: @"http:"] || [url hasPrefix: @"https:"])) {
[mutableOptions setObject: [self urlWithPath: url] forKey: @"url"];
}
NSUInteger timeout = [[options objectForKey: @"timeout"] unsignedIntValue];
if (timeout == 0) {
[mutableOptions setValue: [NSNumber numberWithUnsignedInt: self.timeout] forKey: @"timeout"];
}
options = [NSDictionary dictionaryWithDictionary: mutableOptions];
return [MMHTTPRequest requestWithOptions: options callback: callback];
}
@end

View file

@ -0,0 +1,43 @@
//
// MMHTTPRequest.h
// Marshmallows
//
// Created by Sami Samhuri on 11-09-03.
// Copyright 2011 Guru Logic. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <UIKit/UIImage.h>
#define MMHTTPRequestStatusError -1
#define MMHTTPRequestDefaultTimeout 120
typedef void (^MMHTTPCallback)(NSInteger status, id data);
typedef void (^MMHTTPTextCallback)(NSInteger status, NSString *text);
typedef void (^MMHTTPImageCallback)(NSInteger status, UIImage *image);
@interface MMHTTPRequest : NSObject
{
NSMutableData *_responseData;
}
@property (nonatomic, retain) NSURLConnection *connection;
@property (nonatomic, retain) NSMutableURLRequest *request;
@property (nonatomic, retain) NSString *method;
@property (nonatomic, retain) NSString *url;
@property (nonatomic, retain) NSMutableDictionary *headers;
@property (nonatomic, retain) NSData *data;
@property (nonatomic, retain) NSString *type;
@property (nonatomic, copy) MMHTTPCallback callback;
@property NSUInteger timeout;
@property (readonly) NSInteger statusCode;
@property (readonly) NSDictionary *responseHeaders;
@property (readonly) NSData *responseData;
@property (readonly) NSString *responseText;
@property (readonly) UIImage *responseImage;
+ (id) requestWithOptions: (NSDictionary *)options callback: (MMHTTPCallback)callback;
- (id) initWithOptions: (NSDictionary *)options callback: (MMHTTPCallback)callback;
- (void) cancel;
@end

147
5by5Browser/MMHTTPRequest.m Normal file
View file

@ -0,0 +1,147 @@
//
// MMHTTPRequest.m
// Marshmallows
//
// Created by Sami Samhuri on 11-09-03.
// Copyright 2011 Guru Logic. All rights reserved.
//
#import "MMHTTPRequest.h"
@interface MMHTTPRequest ()
- (void) _start;
@end
@implementation MMHTTPRequest
@synthesize connection = _connection;
@synthesize request = _request;
@synthesize method = _method;
@synthesize url = _url;
@synthesize headers = _headers;
@synthesize data = _data;
@synthesize type = _type;
@synthesize callback = _callback;
@synthesize timeout = _timeout;
@synthesize statusCode = _statusCode;
@synthesize responseHeaders = _responseHeaders;
+ (id) requestWithOptions: (NSDictionary *)options callback: (MMHTTPCallback)callback
{
return [[self alloc] initWithOptions: options callback: callback];
}
- (id) initWithOptions: (NSDictionary *)options callback: (MMHTTPCallback)callback
{
self = [super init];
if (self) {
self.callback = [callback copy];
self.timeout = MMHTTPRequestDefaultTimeout;
self.method = [options objectForKey: @"method"];
self.url = [options objectForKey: @"url"];
self.headers = [options objectForKey: @"headers"];
self.data = [options objectForKey: @"data"];
self.type = [options objectForKey: @"type"];
if (!self.method) self.method = @"GET";
[self _start];
}
return self;
}
- (void) cancel
{
[_connection cancel];
}
- (NSData *) responseData
{
return [NSData dataWithData: _responseData];
}
- (NSString *) responseText
{
return [[NSString alloc] initWithBytes: _responseData.bytes
length: _responseData.length
encoding: NSUTF8StringEncoding];
}
- (UIImage *) responseImage
{
return [UIImage imageWithData: _responseData];
}
- (void) _start
{
self.request = [NSMutableURLRequest requestWithURL: [NSURL URLWithString: self.url]
cachePolicy: NSURLRequestUseProtocolCachePolicy
timeoutInterval: self.timeout];
[self.request setHTTPMethod: self.method];
if (self.data && ([self.method isEqualToString: @"POST"] || [self.method isEqualToString: @"PUT"])) {
[self.request setHTTPBody: self.data];
}
if (self.headers) {
for (NSString *key in self.headers) {
[self.request setValue: [self.headers objectForKey: key] forHTTPHeaderField: key];
}
}
self.connection = [NSURLConnection connectionWithRequest: self.request delegate: self];
[self.connection start];
}
#pragma mark - NSURLConnection delegate methods
- (void) connection: (NSURLConnection *)connection didReceiveResponse: (NSURLResponse *)response
{
// NSLog(@"didReceiveResponse: %@",response);
if ([response respondsToSelector: @selector(statusCode)])
{
_statusCode = [(NSHTTPURLResponse *)response statusCode];
_responseHeaders = [(NSHTTPURLResponse *)response allHeaderFields];
}
else {
NSLog(@"Not an HTTP response? connection: %@ response: %@", connection, response);
_statusCode = 500;
_responseHeaders = [[NSDictionary alloc] init];
}
_responseData = [[NSMutableData alloc] init];
}
- (void) connection: (NSURLConnection *)connection didReceiveData: (NSData *)data
{
// NSLog(@"didReceiveData: %@", data);
[_responseData appendData: data];
}
- (void) connection: (NSURLConnection *)connection didFailWithError: (NSError *)error
{
NSLog(@"didFailWithError: %@", error);
_responseData = nil;
_statusCode = MMHTTPRequestStatusError;
self.callback(self.statusCode, error);
}
- (void) connectionDidFinishLoading: (NSURLConnection *)connection
{
// NSLog(@"didFinishLoading: %d", self.statusCode);
id data = nil;
if (self.statusCode == 200) {
if ([self.type isEqualToString: @"text"]) {
data = self.responseText;
}
else if ([self.type isEqualToString: @"image"]) {
data = self.responseImage;
}
else {
data = self.responseData;
}
}
self.callback(self.statusCode, data);
}
@end

View file

@ -0,0 +1,19 @@
//
// NSString+marshmallows.h
// Marshmallows
//
// Created by Sami Samhuri on 11-09-03.
// Copyright 2011 Guru Logic. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface NSString (NSString_marshmallows)
- (NSString *) firstMatch: (NSString *)pattern;
- (NSString *) stringByReplacing: (NSString *)pattern with: (NSString *)replacement;
- (NSString *) stringByReplacingFirst: (NSString *)pattern with: (NSString *)replacement;
- (NSString *) stringByTrimmingWhitespace;
- (NSString *) stringByURLEncoding;
@end

View file

@ -0,0 +1,76 @@
//
// NSString+marshmallows.m
// Marshmallows
//
// Created by Sami Samhuri on 11-09-03.
// Copyright 2011 Guru Logic. All rights reserved.
//
#import "NSString+marshmallows.h"
// Encode a string to embed in an URL.
NSString* URLEncode(NSString *string) {
return (__bridge NSString *)
CFURLCreateStringByAddingPercentEscapes(NULL,
(__bridge CFStringRef) string,
NULL,
(CFStringRef) @"!*'();:@&=+$,/?%#[]",
kCFStringEncodingUTF8);
}
@implementation NSString (NSString_marshmallows)
- (NSString *) stringByTrimmingWhitespace
{
return [self stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceAndNewlineCharacterSet]];
}
- (NSString *) firstMatch: (NSString *)pattern
{
NSRegularExpression *regex = [NSRegularExpression
regularExpressionWithPattern: pattern
options: 0
error: NULL];
NSRange match = [regex rangeOfFirstMatchInString: self
options: NSMatchingCompleted
range: NSMakeRange(0, self.length)];
return match.location == NSNotFound ? nil : [self substringWithRange: match];
}
- (NSString *) stringByReplacing: (NSString *)pattern with: (NSString *)replacement
{
NSRegularExpression *regex = [NSRegularExpression
regularExpressionWithPattern: pattern
options: NSRegularExpressionCaseInsensitive
error: NULL];
return [regex stringByReplacingMatchesInString: self
options: NSMatchingCompleted
range: NSMakeRange(0, [self length])
withTemplate: @""];
}
- (NSString *) stringByReplacingFirst: (NSString *)pattern with: (NSString *)replacement
{
NSRegularExpression *regex = [NSRegularExpression
regularExpressionWithPattern: pattern
options: 0
error: NULL];
NSRange match = [regex rangeOfFirstMatchInString: self
options: NSMatchingCompleted
range: NSMakeRange(0, self.length)];
if (match.location != NSNotFound) {
NSString *rest = [self substringFromIndex: match.location + match.length];
return [[[self substringToIndex: match.location]
stringByAppendingString: replacement]
stringByAppendingString: rest];
}
return [self copy];
}
- (NSString *) stringByURLEncoding
{
return URLEncode(self);
}
@end

View file

@ -25,7 +25,7 @@
FiveByFive *fiveByFive = [[FiveByFive alloc] initWithBaseURL: @"http:/feeds.feedburner.com/"];
[fiveByFive addShow: [Show showWithName: @"Back to Work" path: @"back2work"]];
[fiveByFive addShow: [Show showWithName: @"Build and Analyze" path: @"buildanalyze"]];
[fiveByFive addShow: [Show showWithName: @"Critical Path" path: @"criticalpath"]];
[fiveByFive addShow: [Show showWithName: @"The Critical Path" path: @"criticalpath"]];
[fiveByFive addShow: [Show showWithName: @"Geek Friday" path: @"GeekFriday"]];
[fiveByFive addShow: [Show showWithName: @"Hypercritical" path: @"hypercritical"]];
[fiveByFive addShow: [Show showWithName: @"The Talk Show" path: @"thetalkshow"]];
@ -35,13 +35,16 @@
SSMasterViewController *masterViewController = [[SSMasterViewController alloc] initWithNibName:@"SSMasterViewController_iPhone" bundle:nil];
masterViewController.fiveByFive = fiveByFive;
self.navigationController = [[UINavigationController alloc] initWithRootViewController:masterViewController];
[self.navigationController.navigationBar setTintColor: [UIColor colorWithWhite: 0.3 alpha: 1.0]];
self.window.rootViewController = self.navigationController;
} else {
SSMasterViewController *masterViewController = [[SSMasterViewController alloc] initWithNibName:@"SSMasterViewController_iPad" bundle:nil];
UINavigationController *masterNavigationController = [[UINavigationController alloc] initWithRootViewController:masterViewController];
[masterNavigationController.navigationBar setTintColor: [UIColor colorWithWhite: 0.3 alpha: 1.0]];
SSDetailViewController *detailViewController = [[SSDetailViewController alloc] initWithNibName:@"SSDetailViewController_iPad" bundle:nil];
UINavigationController *detailNavigationController = [[UINavigationController alloc] initWithRootViewController:detailViewController];
[detailNavigationController.navigationBar setTintColor: [UIColor colorWithWhite: 0.3 alpha: 1.0]];
masterViewController.fiveByFive = fiveByFive;

View file

@ -14,9 +14,13 @@
@property (strong, nonatomic) Episode *episode;
@property (strong, nonatomic) IBOutlet UILabel *detailDescriptionLabel;
@property (strong, nonatomic) IBOutlet UIWebView *webView;
@property (strong, nonatomic) IBOutlet UIToolbar *toolbar;
@property (strong, nonatomic) IBOutlet UIBarButtonItem *backButton;
@property (strong, nonatomic) IBOutlet UIBarButtonItem *forwardButton;
@property (strong, nonatomic) IBOutlet UIBarButtonItem *instapaperButton;
@property (strong, nonatomic) IBOutlet UIView *loadingView;
- (IBAction) goHome;
- (IBAction) goHome: (id)sender;
- (IBAction)sendToInstapaper: (id)sender;
@end

View file

@ -7,6 +7,9 @@
//
#import "SSDetailViewController.h"
#import "MMHTTPClient.h"
#import "InstapaperCredentials.h"
#import "UIAlertView+marshmallows.h"
@interface SSDetailViewController ()
@property (strong, nonatomic) UIPopoverController *masterPopoverController;
@ -18,8 +21,11 @@
@synthesize episode = _episode;
@synthesize detailDescriptionLabel = _detailDescriptionLabel;
@synthesize webView = _webView;
@synthesize toolbar = _toolbar;
@synthesize backButton = _backButton;
@synthesize forwardButton = _forwardButton;
@synthesize instapaperButton = _instapaperButton;
@synthesize loadingView = _loadingView;
@synthesize masterPopoverController = _masterPopoverController;
#pragma mark - Managing the detail item
@ -40,19 +46,16 @@
- (void)configureView
{
// Update the user interface for the detail item.
if (self.episode) {
self.title = self.episode.name;
self.detailDescriptionLabel.text = self.episode.name;
[self.webView loadRequest: [NSURLRequest requestWithURL: self.episode.url]];
[self goHome: nil];
}
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self configureView];
}
@ -61,6 +64,9 @@
[self setWebView:nil];
[self setBackButton:nil];
[self setForwardButton:nil];
[self setInstapaperButton:nil];
[self setToolbar:nil];
[self setLoadingView:nil];
[super viewDidUnload];
// Release any retained subviews of the main view.
self.detailDescriptionLabel = nil;
@ -75,17 +81,50 @@
}
}
- (void) webViewDidStartLoad: (UIWebView *)webView
{
[UIView animateWithDuration: 1.0 animations: ^{
self.loadingView.alpha = 1.0;
}];
}
- (void) webViewDidFinishLoad: (UIWebView *)webView
{
[UIView animateWithDuration: 0.3 animations: ^{
self.loadingView.alpha = 0.0;
}];
[self.backButton setEnabled: webView.canGoBack];
[self.forwardButton setEnabled: webView.canGoForward];
}
- (IBAction) goHome
- (IBAction) goHome: (id)sender
{
while (self.webView.canGoBack) {
[self.webView goBack];
}
[self.webView loadRequest: [NSURLRequest requestWithURL: self.episode.url]];
}
- (IBAction) sendToInstapaper: (id)sender
{
NSString *url = self.webView.request.URL.absoluteString;
NSDictionary *fields = [NSDictionary dictionaryWithObjectsAndKeys:
kInstapaperUser, @"username",
kInstapaperPassword, @"password",
url, @"url",
nil];
UIActivityIndicatorView *indicatorView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle: UIActivityIndicatorViewStyleWhite];
[indicatorView startAnimating];
UIBarButtonItem *indicatorItem = [[UIBarButtonItem alloc] initWithCustomView: indicatorView];
NSMutableArray *items = [[self.toolbar items] mutableCopy];
NSInteger i = [items indexOfObject: self.instapaperButton];
[items replaceObjectAtIndex: i withObject: indicatorItem];
[self.toolbar setItems: items];
[MMHTTPClient post: @"https://www.instapaper.com/api/add" fields: fields then: ^(NSInteger status, id data) {
[items replaceObjectAtIndex: i withObject: self.instapaperButton];
[self.toolbar setItems: items];
if (status != 201) {
[UIAlertView showAlertWithTitle: @"Error" message: @"Failed to send to Instapaper. Try again later."];
}
}];
}
#pragma mark - Split view

View file

@ -107,7 +107,7 @@
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[[self.fiveByFive.shows objectAtIndex: indexPath.row] getEpisodes];
UIActivityIndicatorView *indicatorView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle: UIActivityIndicatorViewStyleGray];
UIActivityIndicatorView *indicatorView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle: UIActivityIndicatorViewStyleWhite];
[indicatorView startAnimating];
[tableView cellForRowAtIndexPath: indexPath].accessoryView = indicatorView;
}

View file

@ -11,6 +11,8 @@
#import "Episode.h"
#import "FiveByFive.h"
@class Episode;
@protocol ShowDelegate <NSObject>
- (void) gotEpisodesForShow: (Show *)show;
@end

View file

@ -79,7 +79,8 @@
- (void) feedParser: (MWFeedParser *)parser didParseFeedItem: (MWFeedItem *)item
{
NSLog(@"feed item: %@", item);
[self addEpisode: [Episode episodeWithName: item.title number: @"<n>" url: [NSURL URLWithString: item.link]]];
NSLog(@"show name: %@", self.name);
[self addEpisode: [Episode episodeWithShow: self name: item.title number: @"<n>" url: [NSURL URLWithString: item.link]]];
}
- (void) feedParserDidFinish: (MWFeedParser *)parser

View file

@ -0,0 +1,17 @@
//
// UIAlertView+marshmallows.h
// DatingX
//
// Created by Sami Samhuri on 11-08-24.
// Copyright 2011 __MyCompanyName__. All rights reserved.
//
#import <UIKit/UIKit.h>
typedef void (^UIAlertViewCallback)(BOOL ok);
@interface UIAlertView (UIAlertView_marshmallows)
+ (void) showAlertWithTitle: (NSString *)title message: (NSString *)message;
@end

View file

@ -0,0 +1,32 @@
//
// UIAlertView+marshmallows.m
// DatingX
//
// Created by Sami Samhuri on 11-08-24.
// Copyright 2011 __MyCompanyName__. All rights reserved.
//
#import "UIAlertView+marshmallows.h"
#import "UIAlertViewDelegate.h"
@implementation UIAlertView (UIAlertView_marshmallows)
+ (void) showAlertWithTitle: (NSString *)title message: (NSString *)message
{
[[[self alloc] initWithTitle: title
message: message
delegate: nil
cancelButtonTitle: @"OK"
otherButtonTitles: nil] show];
}
+ (void) confirmWithTitle: (NSString *)title message: (NSString *)message then: (UIAlertViewCallback)callback
{
[[[self alloc] initWithTitle: title
message: message
delegate: [UIAlertViewDelegate alertViewDelegateWithCallback: callback]
cancelButtonTitle: @"Cancel"
otherButtonTitles: @"OK", nil] show];
}
@end

View file

@ -0,0 +1,20 @@
//
// UIAlertViewDelegate.h
// Marshmallows
//
// Created by Sami Samhuri on 11-09-05.
// Copyright 2011 Guru Logic. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "UIAlertView+marshmallows.h"
@interface UIAlertViewDelegate : NSObject <UIAlertViewDelegate>
{
UIAlertViewCallback _callback;
}
+ (id) alertViewDelegateWithCallback: (UIAlertViewCallback)callback;
- (id) initWithCallback: (UIAlertViewCallback)callback;
@end

View file

@ -0,0 +1,33 @@
//
// UIAlertViewDelegate.m
// Marshmallows
//
// Created by Sami Samhuri on 11-09-05.
// Copyright 2011 Guru Logic. All rights reserved.
//
#import "UIAlertViewDelegate.h"
@implementation UIAlertViewDelegate
+ (id) alertViewDelegateWithCallback: (UIAlertViewCallback)callback
{
return [[self alloc] initWithCallback: callback];
}
- (id) initWithCallback: (UIAlertViewCallback)callback
{
self = [super init];
if (self) {
_callback = callback;
}
return self;
}
- (void) alertView: (UIAlertView *)alertView clickedButtonAtIndex: (NSInteger)buttonIndex
{
BOOL ok = (buttonIndex == 1);
_callback(ok);
}
@end

View file

@ -14,6 +14,7 @@
<string>IBUIWebView</string>
<string>IBUIBarButtonItem</string>
<string>IBUIToolbar</string>
<string>IBUIActivityIndicatorView</string>
<string>IBUIView</string>
<string>IBProxyObject</string>
</array>
@ -43,7 +44,7 @@
<string key="NSFrameSize">{320, 416}</string>
<reference key="NSSuperview" ref="191373211"/>
<reference key="NSWindow"/>
<reference key="NSNextKeyView" ref="592752272"/>
<reference key="NSNextKeyView" ref="230351054"/>
<string key="NSReuseIdentifierKey">_NS:693</string>
<object class="NSColor" key="IBUIBackgroundColor">
<int key="NSColorSpace">1</int>
@ -85,6 +86,20 @@
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
<int key="IBUIStyle">1</int>
<reference key="IBUIToolbar" ref="592752272"/>
<object class="NSColor" key="IBUITintColor">
<int key="NSColorSpace">1</int>
<bytes key="NSRGB">MC4zMjE1Njg2Mjc1IDAgMAA</bytes>
</object>
</object>
<object class="IBUIBarButtonItem" id="279018819">
<string key="IBUITitle">Instapaper</string>
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
<int key="IBUIStyle">1</int>
<reference key="IBUIToolbar" ref="592752272"/>
<object class="NSColor" key="IBUITintColor">
<int key="NSColorSpace">1</int>
<bytes key="NSRGB">MC4zMjE1Njg2Mjc1IDAgMAA</bytes>
</object>
</object>
<object class="IBUIBarButtonItem" id="8781673">
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
@ -101,6 +116,40 @@
<reference key="IBUIToolbar" ref="592752272"/>
</object>
</array>
<object class="NSColor" key="IBUITintColor">
<int key="NSColorSpace">3</int>
<bytes key="NSWhite">MC4zMzMzMzMzMzMzAA</bytes>
</object>
</object>
<object class="IBUIView" id="230351054">
<reference key="NSNextResponder" ref="191373211"/>
<int key="NSvFlags">274</int>
<array class="NSMutableArray" key="NSSubviews">
<object class="IBUIActivityIndicatorView" id="269906149">
<reference key="NSNextResponder" ref="230351054"/>
<int key="NSvFlags">301</int>
<string key="NSFrame">{{142, 189}, {37, 37}}</string>
<reference key="NSSuperview" ref="230351054"/>
<reference key="NSWindow"/>
<reference key="NSNextKeyView" ref="592752272"/>
<string key="NSReuseIdentifierKey">_NS:1030</string>
<bool key="IBUIOpaque">NO</bool>
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
<bool key="IBUIHidesWhenStopped">NO</bool>
<bool key="IBUIAnimating">YES</bool>
<int key="IBUIStyle">0</int>
</object>
</array>
<string key="NSFrameSize">{320, 416}</string>
<reference key="NSSuperview" ref="191373211"/>
<reference key="NSWindow"/>
<reference key="NSNextKeyView" ref="269906149"/>
<string key="NSReuseIdentifierKey">_NS:196</string>
<object class="NSColor" key="IBUIBackgroundColor">
<int key="NSColorSpace">1</int>
<bytes key="NSRGB">MCAwIDAgMC42AA</bytes>
</object>
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
</object>
</array>
<string key="NSFrame">{{0, 20}, {320, 460}}</string>
@ -152,6 +201,30 @@
</object>
<int key="connectionID">19</int>
</object>
<object class="IBConnectionRecord">
<object class="IBCocoaTouchOutletConnection" key="connection">
<string key="label">instapaperButton</string>
<reference key="source" ref="372490531"/>
<reference key="destination" ref="279018819"/>
</object>
<int key="connectionID">23</int>
</object>
<object class="IBConnectionRecord">
<object class="IBCocoaTouchOutletConnection" key="connection">
<string key="label">toolbar</string>
<reference key="source" ref="372490531"/>
<reference key="destination" ref="592752272"/>
</object>
<int key="connectionID">24</int>
</object>
<object class="IBConnectionRecord">
<object class="IBCocoaTouchOutletConnection" key="connection">
<string key="label">loadingView</string>
<reference key="source" ref="372490531"/>
<reference key="destination" ref="230351054"/>
</object>
<int key="connectionID">28</int>
</object>
<object class="IBConnectionRecord">
<object class="IBCocoaTouchOutletConnection" key="connection">
<string key="label">delegate</string>
@ -178,11 +251,19 @@
</object>
<object class="IBConnectionRecord">
<object class="IBCocoaTouchEventConnection" key="connection">
<string key="label">goHome</string>
<string key="label">goHome:</string>
<reference key="source" ref="362932883"/>
<reference key="destination" ref="372490531"/>
</object>
<int key="connectionID">20</int>
<int key="connectionID">25</int>
</object>
<object class="IBConnectionRecord">
<object class="IBCocoaTouchEventConnection" key="connection">
<string key="label">sendToInstapaper:</string>
<reference key="source" ref="279018819"/>
<reference key="destination" ref="372490531"/>
</object>
<int key="connectionID">22</int>
</object>
</array>
<object class="IBMutableOrderedSet" key="objectRecords">
@ -198,6 +279,7 @@
<reference key="object" ref="191373211"/>
<array class="NSMutableArray" key="children">
<reference ref="517643825"/>
<reference ref="230351054"/>
<reference ref="592752272"/>
</array>
<reference key="parent" ref="0"/>
@ -227,6 +309,7 @@
<reference ref="703595657"/>
<reference ref="8781673"/>
<reference ref="362932883"/>
<reference ref="279018819"/>
</array>
<reference key="parent" ref="191373211"/>
</object>
@ -257,6 +340,24 @@
<reference key="object" ref="362932883"/>
<reference key="parent" ref="592752272"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">21</int>
<reference key="object" ref="279018819"/>
<reference key="parent" ref="592752272"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">26</int>
<reference key="object" ref="230351054"/>
<array class="NSMutableArray" key="children">
<reference ref="269906149"/>
</array>
<reference key="parent" ref="191373211"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">27</int>
<reference key="object" ref="269906149"/>
<reference key="parent" ref="230351054"/>
</object>
</array>
</object>
<dictionary class="NSMutableDictionary" key="flattenedProperties">
@ -271,34 +372,43 @@
<string key="13.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
<string key="14.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
<string key="15.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
<string key="21.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
<string key="26.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
<string key="27.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
<string key="7.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
</dictionary>
<dictionary class="NSMutableDictionary" key="unlocalizedProperties"/>
<nil key="activeLocalization"/>
<dictionary class="NSMutableDictionary" key="localizations"/>
<nil key="sourceID"/>
<int key="maxID">20</int>
<int key="maxID">28</int>
</object>
<object class="IBClassDescriber" key="IBDocument.Classes">
<array class="NSMutableArray" key="referencedPartialClassDescriptions">
<object class="IBPartialClassDescription">
<string key="className">SSDetailViewController</string>
<string key="superclassName">UIViewController</string>
<object class="NSMutableDictionary" key="actions">
<string key="NS.key.0">goHome</string>
<string key="NS.object.0">id</string>
</object>
<object class="NSMutableDictionary" key="actionInfosByName">
<string key="NS.key.0">goHome</string>
<object class="IBActionInfo" key="NS.object.0">
<string key="name">goHome</string>
<dictionary class="NSMutableDictionary" key="actions">
<string key="goHome:">id</string>
<string key="sendToInstapaper:">id</string>
</dictionary>
<dictionary class="NSMutableDictionary" key="actionInfosByName">
<object class="IBActionInfo" key="goHome:">
<string key="name">goHome:</string>
<string key="candidateClassName">id</string>
</object>
</object>
<object class="IBActionInfo" key="sendToInstapaper:">
<string key="name">sendToInstapaper:</string>
<string key="candidateClassName">id</string>
</object>
</dictionary>
<dictionary class="NSMutableDictionary" key="outlets">
<string key="backButton">UIBarButtonItem</string>
<string key="detailDescriptionLabel">UILabel</string>
<string key="forwardButton">UIBarButtonItem</string>
<string key="instapaperButton">UIBarButtonItem</string>
<string key="loadingView">UIView</string>
<string key="toolbar">UIToolbar</string>
<string key="webView">UIWebView</string>
</dictionary>
<dictionary class="NSMutableDictionary" key="toOneOutletInfosByName">
@ -314,6 +424,18 @@
<string key="name">forwardButton</string>
<string key="candidateClassName">UIBarButtonItem</string>
</object>
<object class="IBToOneOutletInfo" key="instapaperButton">
<string key="name">instapaperButton</string>
<string key="candidateClassName">UIBarButtonItem</string>
</object>
<object class="IBToOneOutletInfo" key="loadingView">
<string key="name">loadingView</string>
<string key="candidateClassName">UIView</string>
</object>
<object class="IBToOneOutletInfo" key="toolbar">
<string key="name">toolbar</string>
<string key="candidateClassName">UIToolbar</string>
</object>
<object class="IBToOneOutletInfo" key="webView">
<string key="name">webView</string>
<string key="candidateClassName">UIWebView</string>