Project import
diff --git a/OCCukes/OCCucumber.h b/OCCukes/OCCucumber.h
new file mode 100755
index 0000000..929bb0f
--- /dev/null
+++ b/OCCukes/OCCucumber.h
@@ -0,0 +1,80 @@
+// OCCukes OCCucumber.h
+//
+// Copyright © 2012, 2013, The OCCukes Organisation. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the “Software”), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+//	The above copyright notice and this permission notice shall be included in
+//	all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED “AS IS,” WITHOUT WARRANTY OF ANY KIND, EITHER
+// EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO
+// EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
+// OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+//------------------------------------------------------------------------------
+
+#import <Foundation/Foundation.h>
+
+@class OCCucumberWorld;
+
+/**
+ * Offers a set of class-scoped convenience methods for interacting with
+ * Cucumber language and runtime.
+ *
+ * Typically, your unit tests will interact via this interface, rather
+ * than via the Cucumber shared language, or some other instance of the language
+ * class.
+ *
+ * All the class-scoped methods access the shared runtime's language, rather
+ * than the shared language. Typically this amounts to exactly the same
+ * thing. The answer differs only in one case: when the runtime overrides the
+ * language. In that case, the runtime takes precedence.
+ */
+@interface OCCucumber : NSObject
+
+//----------------------------------------------------------- Language Shortcuts
+
++ (void)given:(NSString *)pattern step:(void (^)(NSArray *arguments))block;
++ (void)when:(NSString *)pattern step:(void (^)(NSArray *arguments))block;
++ (void)then:(NSString *)pattern step:(void (^)(NSArray *arguments))block;
+
++ (void)given:(NSString *)pattern
+		 step:(void (^)(NSArray *arguments))block
+		 file:(const char *)file
+		 line:(unsigned int)line;
++ (void)when:(NSString *)pattern
+		step:(void (^)(NSArray *arguments))block
+		file:(const char *)file
+		line:(unsigned int)line;
++ (void)then:(NSString *)pattern
+		step:(void (^)(NSArray *arguments))block
+		file:(const char *)file
+		line:(unsigned int)line;
+
+/**
+ * Answers the shared language's current world, a shortcut.
+ *
+ * World's appear and disappear as scenarios begin and end. Step
+ * definitions use them as scratchpads for persisting arguments and other pieces
+ * of information in-between steps. Use key-value coding to access world values.
+ */
++ (OCCucumberWorld *)currentWorld;
+
++ (void)step:(NSString *)name arguments:(NSArray *)arguments;
++ (void)step:(NSString *)name;
+
+//------------------------------------------------------------ Runtime Shortcuts
+
++ (void)pending;
++ (void)pending:(NSString *)message;
+
+@end
diff --git a/OCCukes/OCCucumber.m b/OCCukes/OCCucumber.m
new file mode 100755
index 0000000..c8c8ccb
--- /dev/null
+++ b/OCCukes/OCCucumber.m
@@ -0,0 +1,106 @@
+// OCCukes OCCucumber.m
+//
+// Copyright © 2012, 2013, The OCCukes Organisation. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the “Software”), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+//	The above copyright notice and this permission notice shall be included in
+//	all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED “AS IS,” WITHOUT WARRANTY OF ANY KIND, EITHER
+// EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO
+// EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
+// OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+//------------------------------------------------------------------------------
+
+#import "OCCucumber.h"
+#import "OCCucumberRuntime.h"
+#import "OCCucumberLanguage.h"
+#import "OCCucumberWorld.h"
+#import "OCCucumberStepDefinition.h"
+
+@implementation OCCucumber
+
++ (void)given:(NSString *)pattern step:(void (^)(NSArray *arguments))block
+{
+	[[[OCCucumberRuntime sharedRuntime] language] registerStepPattern:pattern block:block];
+}
+
++ (void)when:(NSString *)pattern step:(void (^)(NSArray *arguments))block
+{
+	[[[OCCucumberRuntime sharedRuntime] language] registerStepPattern:pattern block:block];
+}
+
++ (void)then:(NSString *)pattern step:(void (^)(NSArray *arguments))block
+{
+	[[[OCCucumberRuntime sharedRuntime] language] registerStepPattern:pattern block:block];
+}
+
++ (void)given:(NSString *)pattern
+		 step:(void (^)(NSArray *arguments))block
+		 file:(const char *)file
+		 line:(unsigned int)line
+{
+	OCCucumberLanguage *language = [[OCCucumberRuntime sharedRuntime] language];
+	OCCucumberStepDefinition *stepDefinition = [language registerStepPattern:pattern block:block];
+	[stepDefinition setFile:file];
+	[stepDefinition setLine:line];
+}
+
++ (void)when:(NSString *)pattern
+		step:(void (^)(NSArray *arguments))block
+		file:(const char *)file
+		line:(unsigned int)line
+{
+	OCCucumberLanguage *language = [[OCCucumberRuntime sharedRuntime] language];
+	OCCucumberStepDefinition *stepDefinition = [language registerStepPattern:pattern block:block];
+	[stepDefinition setFile:file];
+	[stepDefinition setLine:line];
+}
+
++ (void)then:(NSString *)pattern
+		step:(void (^)(NSArray *arguments))block
+		file:(const char *)file
+		line:(unsigned int)line
+{
+	OCCucumberLanguage *language = [[OCCucumberRuntime sharedRuntime] language];
+	OCCucumberStepDefinition *stepDefinition = [language registerStepPattern:pattern block:block];
+	[stepDefinition setFile:file];
+	[stepDefinition setLine:line];
+}
+
++ (OCCucumberWorld *)currentWorld
+{
+	return [[[OCCucumberRuntime sharedRuntime] language] currentWorld];
+}
+
++ (void)step:(NSString *)name arguments:(NSArray *)arguments
+{
+	[[[OCCucumberRuntime sharedRuntime] language] step:name arguments:arguments];
+}
+
++ (void)step:(NSString *)name
+{
+	[self step:name arguments:nil];
+}
+
++ (void)pending
+{
+	@throw [NSArray arrayWithObject:@"pending"];
+}
+
++ (void)pending:(NSString *)message
+{
+	@throw [NSArray arrayWithObjects:@"pending", message, nil];
+}
+
+@end
diff --git a/OCCukes/OCCucumberException.h b/OCCukes/OCCucumberException.h
new file mode 100644
index 0000000..7d9af5a
--- /dev/null
+++ b/OCCukes/OCCucumberException.h
@@ -0,0 +1,5 @@
+#import <Foundation/Foundation.h>
+
+@interface OCCucumberException : NSException
+
+@end
diff --git a/OCCukes/OCCucumberException.m b/OCCukes/OCCucumberException.m
new file mode 100644
index 0000000..1ba7318
--- /dev/null
+++ b/OCCukes/OCCucumberException.m
@@ -0,0 +1,5 @@
+#import "OCCucumberException.h"
+
+@implementation OCCucumberException
+
+@end
diff --git a/OCCukes/OCCucumberExceptions.h b/OCCukes/OCCucumberExceptions.h
new file mode 100755
index 0000000..3e7ec0a
--- /dev/null
+++ b/OCCukes/OCCucumberExceptions.h
@@ -0,0 +1,29 @@
+/* OCCukes OCCucumberExceptions.h
+ *
+ * Copyright © 2012, 2013, The OCCukes Organisation. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the “Software”), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ *	The above copyright notice and this permission notice shall be included in
+ *	all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED “AS IS,” WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO
+ * EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
+ * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ ******************************************************************************/
+
+#import <Foundation/Foundation.h>
+
+extern NSString *const OCCucumberUndefinedException;
+extern NSString *const OCCucumberPendingException;
+extern NSString *const OCCucumberAmbiguousException;
diff --git a/OCCukes/OCCucumberExceptions.m b/OCCukes/OCCucumberExceptions.m
new file mode 100755
index 0000000..c99bc86
--- /dev/null
+++ b/OCCukes/OCCucumberExceptions.m
@@ -0,0 +1,29 @@
+/* OCCukes OCCucumberExceptions.m
+ *
+ * Copyright © 2012, 2013, The OCCukes Organisation. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the “Software”), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ *	The above copyright notice and this permission notice shall be included in
+ *	all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED “AS IS,” WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO
+ * EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
+ * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ ******************************************************************************/
+
+#import "OCCucumberExceptions.h"
+
+NSString *const OCCucumberUndefinedException = @"OCCucumberUndefinedException";
+NSString *const OCCucumberPendingException = @"OCCucumberPendingException";
+NSString *const OCCucumberAmbiguousException = @"OCCucumberAmbiguousException";
diff --git a/OCCukes/OCCucumberLanguage.h b/OCCukes/OCCucumberLanguage.h
new file mode 100755
index 0000000..4e3b94d
--- /dev/null
+++ b/OCCukes/OCCucumberLanguage.h
@@ -0,0 +1,65 @@
+// OCCukes OCCucumberLanguage.h
+//
+// Copyright © 2012, 2013, The OCCukes Organisation. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the “Software”), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+//	The above copyright notice and this permission notice shall be included in
+//	all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED “AS IS,” WITHOUT WARRANTY OF ANY KIND, EITHER
+// EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO
+// EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
+// OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+//------------------------------------------------------------------------------
+
+#import <Foundation/Foundation.h>
+
+@class OCCucumberWorld;
+@class OCCucumberStepDefinition;
+
+@interface OCCucumberLanguage : NSObject
+
+@property(strong, NS_NONATOMIC_IOSONLY) OCCucumberWorld *currentWorld;
+@property(strong, NS_NONATOMIC_IOSONLY) NSMutableSet *stepDefinitions;
+
+- (void)registerStepDefinition:(OCCucumberStepDefinition *)stepDefinition;
+- (OCCucumberStepDefinition *)registerStep:(NSRegularExpression *)regularExpression block:(void (^)(NSArray *arguments))block;
+- (OCCucumberStepDefinition *)registerStepPattern:(NSString *)pattern block:(void (^)(NSArray *arguments))block;
+
+/**
+ * Answers the steps matching a given step name.
+ *
+ * There could be more than one. The resulting array contains Step
+ * Match objects. Each Step Match retains its step definition for later
+ * invocation and the argument values derived from the match.
+ */
+- (NSArray *)stepMatches:(NSString *)nameToMatch;
+
+- (void)beginScenario;
+- (void)endScenario;
+
+/**
+ * Invokes a single step.
+ *
+ * Be careful when invoking steps. Make sure you do not invoke yourself
+ * and recurse infinitely.
+ *
+ * @exception Raises an ambiguity exception if more than one match. Raises an
+ * undefined exception if no match.
+ */
+- (void)step:(NSString *)name arguments:(NSArray *)arguments;
+- (void)step:(NSString *)name;
+
++ (OCCucumberLanguage *)sharedLanguage;
+
+@end
diff --git a/OCCukes/OCCucumberLanguage.m b/OCCukes/OCCucumberLanguage.m
new file mode 100755
index 0000000..1993453
--- /dev/null
+++ b/OCCukes/OCCucumberLanguage.m
@@ -0,0 +1,129 @@
+// OCCukes OCCucumberLanguage.m
+//
+// Copyright © 2012, 2013, The OCCukes Organisation. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the “Software”), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+//	The above copyright notice and this permission notice shall be included in
+//	all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED “AS IS,” WITHOUT WARRANTY OF ANY KIND, EITHER
+// EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO
+// EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
+// OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+//------------------------------------------------------------------------------
+
+#import "OCCucumberLanguage.h"
+#import "OCCucumberWorld.h"
+#import "OCCucumberStepDefinition.h"
+#import "OCCucumberStepMatch.h"
+#import "OCCucumberStepArgument.h"
+#import "OCCucumberExceptions.h"
+
+@implementation OCCucumberLanguage
+
+@synthesize currentWorld = _currentWorld;
+@synthesize stepDefinitions = _stepDefinitions;
+
+// designated initialiser
+- (id)init
+{
+	if ((self = [super init]))
+	{
+		[self setStepDefinitions:[NSMutableSet set]];
+	}
+	return self;
+}
+
+- (void)registerStepDefinition:(OCCucumberStepDefinition *)stepDefinition
+{
+	[[self stepDefinitions] addObject:stepDefinition];
+}
+
+- (OCCucumberStepDefinition *)registerStep:(NSRegularExpression *)regularExpression block:(void (^)(NSArray *arguments))block
+{
+	OCCucumberStepDefinition *stepDefinition = [[OCCucumberStepDefinition alloc] initWithRegularExpression:regularExpression block:block];
+	[self registerStepDefinition:stepDefinition];
+	return stepDefinition;
+}
+
+- (OCCucumberStepDefinition *)registerStepPattern:(NSString *)pattern block:(void (^)(NSArray *arguments))block
+{
+	OCCucumberStepDefinition *stepDefinition = [[OCCucumberStepDefinition alloc] initWithPattern:pattern block:block];
+	[self registerStepDefinition:stepDefinition];
+	return stepDefinition;
+}
+
+- (NSArray *)stepMatches:(NSString *)nameToMatch
+{
+	NSMutableArray *matches = [NSMutableArray array];
+	for (OCCucumberStepDefinition *stepDefinition in [self stepDefinitions])
+	{
+		NSArray *arguments = [stepDefinition argumentsFromStepName:nameToMatch];
+		if (arguments)
+		{
+			[matches addObject:[[OCCucumberStepMatch alloc] initWithDefinition:stepDefinition arguments:arguments]];
+		}
+	}
+	return [matches copy];
+}
+
+- (void)beginScenario
+{
+	[self setCurrentWorld:[[OCCucumberWorld alloc] init]];
+}
+
+- (void)endScenario
+{
+	[self setCurrentWorld:nil];
+}
+
+- (void)step:(NSString *)name arguments:(NSArray *)arguments
+{
+	NSArray *stepMatches = [self stepMatches:name];
+	if ([stepMatches count] == 0)
+	{
+		[NSException raise:OCCucumberUndefinedException format:@"Undefined step \"%@\"", name];
+	}
+	if ([stepMatches count] > 1)
+	{
+		[NSException raise:OCCucumberAmbiguousException format:@"Ambiguous match of \"%@\"", name];
+	}
+	OCCucumberStepMatch *stepMatch = [stepMatches objectAtIndex:0];
+	NSMutableArray *values = [NSMutableArray array];
+	for (OCCucumberStepArgument *stepArgument in [stepMatch stepArguments])
+	{
+		[values addObject:[stepArgument value]];
+	}
+	if (arguments)
+	{
+		[values addObjectsFromArray:arguments];
+	}
+	[[stepMatch stepDefinition] invokeWithArguments:[values copy]];
+}
+
+- (void)step:(NSString *)name
+{
+	[self step:name arguments:nil];
+}
+
++ (OCCucumberLanguage *)sharedLanguage
+{
+	static OCCucumberLanguage *__strong sharedLanguage;
+	if (sharedLanguage == nil)
+	{
+		sharedLanguage = [[OCCucumberLanguage alloc] init];
+	}
+	return sharedLanguage;
+}
+
+@end
diff --git a/OCCukes/OCCucumberRuntime+WireProtocol.h b/OCCukes/OCCucumberRuntime+WireProtocol.h
new file mode 100755
index 0000000..33ec074
--- /dev/null
+++ b/OCCukes/OCCucumberRuntime+WireProtocol.h
@@ -0,0 +1,72 @@
+// OCCukes OCCucumberRuntime+WireProtocol.h
+//
+// Copyright © 2012, 2013, The OCCukes Organisation. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the “Software”), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+//	The above copyright notice and this permission notice shall be included in
+//	all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED “AS IS,” WITHOUT WARRANTY OF ANY KIND, EITHER
+// EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO
+// EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
+// OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+//------------------------------------------------------------------------------
+
+#import "OCCucumberRuntime.h"
+
+extern NSString *const OCCucumberRuntimeUnhandledStepNotification;

+
extern NSString *const OCCucumberRuntimeUnhandledStepNameKey;

+
+@interface OCCucumberRuntime(WireProtocol)
+
+- (id)handleWirePacketWithObject:(id)object;
+- (id)handleWirePacketWithArray:(NSArray *)array;
+
+/**
+ * Finds out whether the wire server has a definition for a given step.
+ *
+ * When features have been parsed, Cucumber will send a "step_matches"
+ * message to ask the wire server if it can match a step name. This happens for
+ * each of the steps in each of the features.
+ *
+ * @result The wire server replies with an array of Step Match objects.
+ * Each Step Match hash element comprises the following key-value pairs.
+ * - An "id" string identifier for the step definition to be referenced later
+ *   when it needs to be invoked. The identifier can be any string value and is
+ *   simply used for wire server's own reference.
+ * - An "args" array for any argument values captured by the wire end's own
+ *   regular expression (or other argument matching) process.
+ */
+- (id)handleStepMatchesWithHash:(NSDictionary *)hash;
+
+/**
+ * Requests a snippet for an undefined step.
+ */
+- (id)handleSnippetTextWithHash:(NSDictionary *)hash;
+
+/**
+ * Signals that Cucumber is about to execute a scenario.
+ */
+- (id)handleBeginScenario;
+
+/**
+ * Signals that Cucumber has finished executing a scenario.
+ */
+- (id)handleEndScenario;
+
+/**
+ * Asks for a step definition to be invoked.
+ */
+- (id)handleInvokeWithHash:(NSDictionary *)hash;
+
+@end
diff --git a/OCCukes/OCCucumberRuntime+WireProtocol.m b/OCCukes/OCCucumberRuntime+WireProtocol.m
new file mode 100755
index 0000000..1c78625
--- /dev/null
+++ b/OCCukes/OCCucumberRuntime+WireProtocol.m
@@ -0,0 +1,226 @@
+// OCCukes OCCucumberRuntime+WireProtocol.m
+//
+// Copyright © 2012, 2013, The OCCukes Organisation. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the “Software”), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+//	The above copyright notice and this permission notice shall be included in
+//	all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED “AS IS,” WITHOUT WARRANTY OF ANY KIND, EITHER
+// EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO
+// EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
+// OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+//------------------------------------------------------------------------------
+
+#import "OCCucumberRuntime+WireProtocol.h"
+#import "OCCucumberLanguage.h"
+#import "OCCucumberStepDefinition.h"
+#import "OCCucumberStepMatch.h"
+#import "OCCucumberStepArgument.h"
+#import "OCCucumberException.h"
+
+// Semantic issue: performSelector may cause a leak because its selector is
+// unknown! Ignore this "ARC performSelector leaks" warning.
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
+
+NSString *const OCCucumberRuntimeUnhandledStepNotification = @"OCCucumberRuntimeUnhandledStep";

+
NSString *const OCCucumberRuntimeUnhandledStepNameKey = @"OCCucumberRuntimeUnhandledStepName";

+
+NSString *__OCCucumberRuntimeCamelize(NSString *string);
+
+@implementation OCCucumberRuntime(WireProtocol)
+
+- (id)handleWirePacketWithObject:(id)object
+{
+	// By default, all paths through the demultiplexer answer nil. All the
+	// handler methods follow this same outline: set up a default nil result
+	// then attempt to handle the wire packet.
+	id result = nil;
+	if ([object isKindOfClass:[NSArray class]])
+	{
+		result = [self handleWirePacketWithArray:(NSArray *)object];
+	}
+	return result;
+}
+
+- (id)handleWirePacketWithArray:(NSArray *)array
+{
+	id result = nil;
+	switch ([array count])
+	{
+		case 1:
+		{
+			SEL selector = NSSelectorFromString([NSString stringWithFormat:@"handle%@", __OCCucumberRuntimeCamelize([array objectAtIndex:0])]);
+			if ([self respondsToSelector:selector])
+			{
+				result = [self performSelector:selector];
+			}
+			break;
+		}
+		case 2:
+		{
+			// Handle wire packets consisting of two array elements. The first
+			// element describes the message. The second element, either an
+			// array or a hash, describes the message parameter. Invoke the
+			// runtime with a selector of the form -handle<Message>WithArray: or
+			// -handle<Message>WithHash: passing an array or a dictionary,
+			// respectively. Ignore messages where there is no corresponding
+			// selector.
+			NSString *with;
+			id object = [array objectAtIndex:1];
+			if ([object isKindOfClass:[NSArray class]])
+			{
+				with = @"Array";
+			}
+			else if ([object isKindOfClass:[NSDictionary class]])
+			{
+				with = @"Hash";
+			}
+			else
+			{
+				with = nil;
+			}
+			if (with)
+			{
+				SEL selector = NSSelectorFromString([NSString stringWithFormat:@"handle%@With%@:", __OCCucumberRuntimeCamelize([array objectAtIndex:0]), with]);
+				if ([self respondsToSelector:selector])
+				{
+					result = [self performSelector:selector withObject:object];
+				}
+			}
+		}
+	}
+	return result;
+}
+
+- (id)handleStepMatchesWithHash:(NSDictionary *)hash
+{
+	NSMutableArray *stepMatches = [NSMutableArray array];
+	NSString *nameToMatch = [hash objectForKey:@"name_to_match"];
+	for (OCCucumberStepMatch *match in [[self language] stepMatches:nameToMatch])
+	{
+		OCCucumberStepDefinition *stepDefinition = [match stepDefinition];
+
+		// The "args" response is an array of hashes. Each hash has a "val" and
+		// "pos" key specifying the argument's value and position.
+		NSMutableArray *args = [NSMutableArray array];
+		for (OCCucumberStepArgument *argument in [match stepArguments])
+		{
+			[args addObject:[NSDictionary dictionaryWithObjectsAndKeys:[argument value], @"val", [NSNumber numberWithUnsignedInteger:[argument offset]], @"pos", nil]];
+		}
+
+		const char *file = [stepDefinition file];
+		NSString *source = file ? [NSString stringWithFormat:@"%s:%u", file, [stepDefinition line]] : nil;
+		[stepMatches addObject:[NSDictionary dictionaryWithObjectsAndKeys:[stepDefinition identifierString], @"id", args, @"args", source, @"source", nil]];
+	}
+
+    if (stepMatches.count == 0) {
+        [self notifyAboutUnhandledStepWithName:nameToMatch];
+    }
+
+    return [NSArray arrayWithObjects:@"success", [stepMatches copy], nil];
+}
+
+- (id)handleSnippetTextWithHash:(NSDictionary *)hash
+{
+	NSString *stepKeyword = [hash objectForKey:@"step_keyword"];
+	NSString *stepName = [hash objectForKey:@"step_name"];
+
+	// Handle argument patterns: double-quoted strings and digit
+	// sequences. Note, the question mark in *? means match zero
+	// or more times and match as few times as possible.
+	NSMutableString *snippetPattern = [NSMutableString stringWithString:[NSRegularExpression escapedPatternForString:stepName]];
+	for (NSString *pattern in [NSArray arrayWithObjects:@"\"(.*?)\"", @"(\\d+)", nil])
+	{
+		NSError *__autoreleasing error = nil;
+		NSRegularExpression *regularExpression = [NSRegularExpression regularExpressionWithPattern:pattern options:0 error:&error];
+		[regularExpression replaceMatchesInString:snippetPattern options:0 range:NSMakeRange(0, [snippetPattern length]) withTemplate:[NSRegularExpression escapedPatternForString:pattern]];
+	}
+	[snippetPattern replaceOccurrencesOfString:@"\\" withString:@"\\\\" options:0 range:NSMakeRange(0, [snippetPattern length])];
+	[snippetPattern replaceOccurrencesOfString:@"\"" withString:@"\\\"" options:0 range:NSMakeRange(0, [snippetPattern length])];
+
+	return [NSArray arrayWithObjects:@"success", [NSString stringWithFormat:@"\t[OCCucumber %@:@\"^%@$\" step:^(NSArray *arguments) {\n\t\t// express the regular expression above with the code you wish you had\n\t\t[OCCucumber pending:@\"TODO\"];\n\t} file:__FILE__ line:__LINE__];", [stepKeyword lowercaseString], [snippetPattern copy]], nil];
+}
+
+- (id)handleBeginScenario
+{
+	[[self language] beginScenario];
+	return [NSArray arrayWithObject:@"success"];
+}
+
+- (id)handleEndScenario
+{
+	[[self language] endScenario];
+	return [NSArray arrayWithObject:@"success"];
+}
+
+- (id)handleInvokeWithHash:(NSDictionary *)hash
+{
+	id result = nil;
+	NSString *identifierString = [hash objectForKey:@"id"];
+	for (OCCucumberStepDefinition *stepDefinition in [[self language] stepDefinitions])
+	{
+		if ([[stepDefinition identifierString] isEqualToString:identifierString])
+		{
+			// The step block throws any object in order to respond. If the wire
+			// server can successfully convert the thrown object to JSON, it
+			// becomes the reply. If the step does not raise an exception,
+			// answer with success.
+			//
+			// Catch NextStep exceptions. Such an exception gives a Cucumber
+			// failure result, where the exception reason becomes the failure
+			// message.
+			@try
+			{
+				[stepDefinition invokeWithArguments:[hash objectForKey:@"args"]];
+				result = [NSArray arrayWithObject:@"success"];
+			}
+			@catch (OCCucumberException *exception)
+			{
+				result = [NSArray arrayWithObjects:@"fail", [NSDictionary dictionaryWithObjectsAndKeys:[exception reason], @"message", [exception name], @"exception", nil], nil];
+			}
+			break;
+		}
+	}
+	return result;
+}
+
+- (void)notifyAboutUnhandledStepWithName:(NSString *)unhadledStepName {

+    NSDictionary *userInfo = @{OCCucumberRuntimeUnhandledStepNameKey: unhadledStepName};

+    NSNotification *notification = [NSNotification notificationWithName:OCCucumberRuntimeUnhandledStepNotification
+                                                                 object:self
+                                                               userInfo:userInfo];


+
+    [[NSNotificationQueue defaultQueue] enqueueNotification:notification postingStyle:NSPostASAP];

+}

+
+@end
+
+/*
+ * Converts a string with underscore delimiters to camel-case with leading
+ * capital letter. Useful for deriving selectors from wire protocol messages,
+ * e.g. for converting begin_scenario to BeginScenario.
+ */
+NSString *__OCCucumberRuntimeCamelize(NSString *string)
+{
+	NSMutableArray *components = [NSMutableArray array];
+	for (NSString *component in [string componentsSeparatedByString:@"_"])
+	{
+		[components addObject:[component capitalizedString]];
+	}
+	return [components componentsJoinedByString:@""];
+}
+
+// arc-performSelector-leaks ignored
+#pragma clang diagnostic pop
diff --git a/OCCukes/OCCucumberRuntime.h b/OCCukes/OCCucumberRuntime.h
new file mode 100644
index 0000000..182c824
--- /dev/null
+++ b/OCCukes/OCCucumberRuntime.h
@@ -0,0 +1,110 @@
+// OCCukes OCCucumberRuntime.h
+//
+// Copyright © 2012, 2013, The OCCukes Organisation. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the “Software”), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+//	The above copyright notice and this permission notice shall be included in
+//	all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED “AS IS,” WITHOUT WARRANTY OF ANY KIND, EITHER
+// EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO
+// EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
+// OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+//------------------------------------------------------------------------------
+
+#import <Foundation/Foundation.h>
+
+#import <CFSockets/CFSockets.h>
+
+@class OCCucumberLanguage;
+
+/**
+ * Ties everything together, the meaty part.
+ *
+ * You set up and tear down the run-time at run time. The runtime
+ * accepts socket connections from Cucumber.
+ */
+@interface OCCucumberRuntime : NSObject <CFSocketDelegate, CFStreamPairDelegate>
+
+@property(strong, NS_NONATOMIC_IOSONLY) OCCucumberLanguage *language;
+
+@property(assign, NS_NONATOMIC_IOSONLY) NSTimeInterval connectTimeout;
+@property(assign, NS_NONATOMIC_IOSONLY) NSTimeInterval disconnectTimeout;
+
+/**
+ * Runtime address and port. Default ones are 0.0.0.0:31337
+ */
+@property(strong, NS_NONATOMIC_IOSONLY) NSString *address;
+@property(assign, NS_NONATOMIC_IOSONLY) NSUInteger port;
+
+/**
+ * Date when the runtime expires.
+ *
+ * Expiring date describes when the runtime should stop running. While
+ * connections exist, the runtime never expires, or expires in the distant
+ * future to be more precise. The runtime expires after the disconnect timeout
+ * after all connections disconnect. It also expires after the connect timeout
+ * after setting up the runtime.
+ */
+@property(strong, NS_NONATOMIC_IOSONLY) NSDate *expiresDate;
+
+/**
+ * Answers all the current connections as a set.
+ *
+ * Connections change dynamically as remote Cucumber clients connect to
+ * and disconnect from the wire server.
+ */
+- (NSSet *)allConnections;
+
+- (void)setUp;
+
+- (void)setUpWithPort:(int)port serviceType:(NSString *)serviceType;
+
+- (void)tearDown;
+
+/**
+ * Cucumber runtime runs, naturally.
+ *
+ * When running the wire server, there are two timing
+ * requirements. First, wait at least for a nominal 10 seconds before giving up
+ * on taking a connection. Call this the "connect timeout" period; it defines
+ * the maximum delay in-between setting up the server and making the first
+ * wire-client connection. There must be at least one incoming Cucumber
+ * connection to disable this timeout. When a connection activates, the timeout
+ * becomes infinite. Provided at least one connection remains, the server
+ * continues running indefinitely. When the last connection closes, the wire
+ * server sustains the server socket for one more second before exiting. This
+ * allows for execution of Cucumber commands over multiple socket connections in
+ * rapid sequence. Call this the disconnect timeout. You can adjust the connect
+ * and disconnect timeouts accordingly.
+ */
+- (void)run;
+
+/**
+ * Answers YES if the runtime wants to continue running.
+ *
+ * The runtime continues running while connections exist, or the
+ * current time lies within connection and disconnection timeout
+ * periods. Outside these conditions, the runtime will continue to accept new
+ * connections if you ignore the running status. In such event, the is-running
+ * status will revert to YES when incoming new connections establish.
+ */
+- (BOOL)isRunning;
+
++ (OCCucumberRuntime *)sharedRuntime;
+
+@end
+
+extern NSString *const OCCucumberRuntimeConnectNotification;
+extern NSString *const OCCucumberRuntimeDisconnectNotification;
+extern NSString *const OCCucumberRuntimeWirePairKey;
\ No newline at end of file
diff --git a/OCCukes/OCCucumberRuntime.m b/OCCukes/OCCucumberRuntime.m
new file mode 100644
index 0000000..9d556ce
--- /dev/null
+++ b/OCCukes/OCCucumberRuntime.m
@@ -0,0 +1,255 @@
+// OCCukes OCCucumberRuntime.m
+//
+// Copyright © 2012, 2013, The OCCukes Organisation. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the “Software”), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+//	The above copyright notice and this permission notice shall be included in
+//	all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED “AS IS,” WITHOUT WARRANTY OF ANY KIND, EITHER
+// EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO
+// EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
+// OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+//------------------------------------------------------------------------------
+
+#import <arpa/inet.h>
+#import <ifaddrs.h>
+#import "OCCucumberRuntime.h"
+#import "OCCucumberRuntime+WireProtocol.h"
+#import "OCCucumberLanguage.h"
+
+static const int DefaultPort = 31337;
+
+@interface OCCucumberRuntime ()
+
+// The wire socket accepts connections on a prescribed host and port, typically
+// local host, port 54321. Wire pairs represent a set of Core Foundation stream
+// pairs for individual connections to remote wire clients, typically Ruby
+// interpreters running Cucumber. Wire pairs appear when the wire socket accepts
+// a new connection and disappear when the remote Cucumber client closes the
+// connection.
+@property(strong, NS_NONATOMIC_IOSONLY) CFSocket *wireSocket;
+@property(strong, NS_NONATOMIC_IOSONLY) NSMutableSet *wirePairs;
+@property(strong, NS_NONATOMIC_IOSONLY) NSNetService *netService;
+
+@end
+
+@implementation OCCucumberRuntime
+
+@synthesize language = _language;
+@synthesize connectTimeout = _connectTimeout;
+@synthesize disconnectTimeout = _disconnectTimeout;
+
+@synthesize expiresDate = _expiresDate;
+
+@synthesize wireSocket = _wireSocket;
+@synthesize wirePairs = _wirePairs;
+@synthesize netService = _netService;
+
+- (void)setLanguage:(OCCucumberLanguage *)language {
+    _language = language;
+}
+
+- (OCCucumberLanguage *)language {
+    // You can override the runtime instance's language. By default, if language
+    // equals nil, the runtime picks up the shared language.
+    return _language ? _language : [OCCucumberLanguage sharedLanguage];
+}
+
+- (NSSet *)allConnections {
+    return [[self wirePairs] copy];
+}
+
+- (id)init {
+    if ((self = [super init])) {
+        [self setConnectTimeout:10.0];
+        [self setDisconnectTimeout:1.0];
+
+        self.port = DefaultPort;
+        self.address = nil;
+    }
+    return self;
+}
+
+- (void)setUp {
+    if (self.address.length > 0) {
+        NSLog(@"Starting OCCucumber runtime [%@ :%zd]", self.address, self.port);
+
+        [self setUpWithAddress:self.address port:self.port];
+    } else {
+        NSLog(@"Starting OCCucumber runtime [0.0.0.0:%zd]", self.port);
+
+        [self setUpWithPort:(int)self.port];
+    }
+}
+
+- (void)setUpWithAddress:(NSString *)address port:(NSUInteger)port {
+    in_addr_t addr;
+    inet_pton(AF_INET, [address cStringUsingEncoding:NSUTF8StringEncoding], &addr);
+
+    [self setUpWithSocketAddressData:CFSocketAddressDataFromIPv4AddressWithPort(addr, (in_port_t) port)];
+}
+
+- (void)setUpWithPort:(int)port {
+    [self setUpWithSocketAddressData:CFSocketAddressDataFromIPv4AddressWithPort(INADDR_ANY, (in_port_t) port)];
+}
+
+- (void)setUpWithSocketAddressData:(NSData *)socketAddress {
+    CFSocket *socket = [[CFSocket alloc] initForTCPv4];
+    [socket setDelegate:self];
+    [socket setReuseAddressOption:YES];
+    [socket setAddress:socketAddress error:NULL];
+    [socket addToCurrentRunLoopForCommonModes];
+
+    [self setWireSocket:socket];
+    [self setWirePairs:[NSMutableSet set]];
+    [self setExpiresDate:[NSDate dateWithTimeIntervalSinceNow:[self connectTimeout]]];
+}
+
+- (void)setUpWithPort:(int)port serviceType:(NSString *)serviceType {
+    CFSocket *socket = [[CFSocket alloc] initForTCPv6];
+    [socket setDelegate:self];
+    [socket setReuseAddressOption:YES];
+    [socket setAddress:CFSocketAddressDataFromAnyIPv6WithPort(port) error:NULL];
+    [socket addToCurrentRunLoopForCommonModes];
+
+    [self setWireSocket:socket];
+    [self setWirePairs:[NSMutableSet set]];
+    [self setExpiresDate:[NSDate dateWithTimeIntervalSinceNow:[self connectTimeout]]];
+
+    // Publish the Cucumber runtime as a "_occukes-runtime._tcp."  network
+    // service type. Application protocol name must be an underscore plus 1-15
+    // characters. See http://www.dns-sd.org/ServiceTypes.html for examples.
+    [self setNetService:[[NSNetService alloc] initWithDomain:@"" type:[NSString stringWithFormat:@"_%@._tcp.", serviceType] name:@"" port:[socket port]]];
+    if ([self netService]) {
+        [[self netService] publish];
+    }
+}
+
+- (void)tearDown {
+    // Removing all connections automatically closes the connections because the
+    // request-response stream pair closes on deallocation. Therefore, no need
+    // to explicitly close every pair, as follows. Releasing the socket shuts
+    // down the socket. Releasing the pair set releases and shuts down all the
+    // wire connections.
+    //
+    //	for (CFStreamPair *wirePair in [self wirePairs])
+    //	{
+    //		[wirePair close];
+    //	}
+    //
+    [self setWireSocket:nil];
+    [self setWirePairs:nil];
+    [self setExpiresDate:nil];
+
+    // Stop publishing the network service.
+    if ([self netService]) {
+        [[self netService] stop];
+        [self setNetService:nil];
+    }
+}
+
+- (void)run {
+    do {
+        [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
+    }
+    while ([self isRunning]);
+}
+
+- (BOOL)isRunning {
+    NSDate *expiresDate = [self expiresDate];
+    return expiresDate && [expiresDate compare:[NSDate date]] == NSOrderedDescending;
+}
+
+- (void)socket:(CFSocket *)socket acceptStreamPair:(CFStreamPair *)streamPair {
+    // Accepts new connections. Attaches a stream-pair to each incoming
+    // connection. Retains, delegates and opens the new wire pair.
+    // The wire server opens one "wire" for each connection, each Cucumber
+    // client. The wire connection's stream-pair encapsulates client-server
+    // interactions. It decodes wire packets from the request stream and encodes
+    // wire packets to the response stream.
+    if ([[self wirePairs] count] == 0) {
+        [self setExpiresDate:[NSDate distantFuture]];
+    }
+    [[self wirePairs] addObject:streamPair];
+    [streamPair setDelegate:self];
+    [streamPair open];
+    NSDictionary *userInfo = [NSDictionary dictionaryWithObject:streamPair forKey:OCCucumberRuntimeWirePairKey];
+    NSNotification *notification = [NSNotification notificationWithName:OCCucumberRuntimeConnectNotification object:self userInfo:userInfo];
+    [[NSNotificationQueue defaultQueue] enqueueNotification:notification postingStyle:NSPostASAP];
+}
+
+- (void)streamPair:(CFStreamPair *)streamPair hasBytesAvailable:(NSUInteger)bytesAvailable {
+    // The wire protocol begins by quantising the request messages by line
+    // terminator. One line equates to one message, or wire packet. The request
+    // is a JSON array. The first element specifies the message, one of:
+    // step_matches, invoke, begin_scenario, end_scenario, or snippet_text. The
+    // second array element specifies the parameters, a hash or array depending
+    // on the message. Demultiplex the JSON request and invoke the corresponding
+    // handler.
+    NSString *line;
+    while ((line = [streamPair receiveLineUsingEncoding:NSUTF8StringEncoding])) {
+        NSError *__autoreleasing error = nil;
+        id object = [NSJSONSerialization JSONObjectWithData:[line dataUsingEncoding:NSUTF8StringEncoding] options:0 error:&error];
+        if (object) {
+            id result = [self handleWirePacketWithObject:object];
+            // Always answer with something whenever the request decodes valid
+            // JSON. Send valid JSON back because at the other end of the
+            // connection likely sits a Cucumber instance. Send a Cucumber
+            // wire-protocol failure packet.
+            if (result == nil) {
+                result = [NSArray arrayWithObject:@"fail"];
+            }
+            NSData *data = [NSJSONSerialization dataWithJSONObject:result options:0 error:&error];
+            if (data) {
+                [streamPair sendBytes:data];
+                [streamPair sendBytes:[@"\n" dataUsingEncoding:NSUTF8StringEncoding]];
+            }
+        }
+    }
+}
+
+- (void)streamPair:(CFStreamPair *)streamPair handleRequestEvent:(NSStreamEvent)eventCode {
+    switch (eventCode) {
+        case NSStreamEventEndEncountered: {
+            // Enqueue the disconnect notification. It does not post
+            // immediately. By the time the notification arrives at its
+            // destination, or destinations, the stream pair no longer appears
+            // as a wire pair; and if it was the very last wire pair, the
+            // expires date reflects the disconnect timeout since now.
+            NSDictionary *userInfo = [NSDictionary dictionaryWithObject:streamPair forKey:OCCucumberRuntimeWirePairKey];
+            NSNotification *notification = [NSNotification notificationWithName:OCCucumberRuntimeDisconnectNotification object:self userInfo:userInfo];
+            [[NSNotificationQueue defaultQueue] enqueueNotification:notification postingStyle:NSPostASAP];
+            [[self wirePairs] removeObject:streamPair];
+            if ([[self wirePairs] count] == 0) {
+                [self setExpiresDate:[NSDate dateWithTimeIntervalSinceNow:[self disconnectTimeout]]];
+            }
+            break;
+        }
+        default:;
+    }
+}
+
++ (OCCucumberRuntime *)sharedRuntime {
+    static OCCucumberRuntime *__strong sharedRuntime;
+    if (sharedRuntime == nil) {
+        sharedRuntime = [[OCCucumberRuntime alloc] init];
+    }
+    return sharedRuntime;
+}
+
+@end
+
+NSString *const OCCucumberRuntimeConnectNotification = @"OCCucumberRuntimeConnect";
+NSString *const OCCucumberRuntimeDisconnectNotification = @"OCCucumberRuntimeDisconnect";
+NSString *const OCCucumberRuntimeWirePairKey = @"OCCucumberRuntimeWirePair";
diff --git a/OCCukes/OCCucumberStepArgument.h b/OCCukes/OCCucumberStepArgument.h
new file mode 100755
index 0000000..28e2c27
--- /dev/null
+++ b/OCCukes/OCCucumberStepArgument.h
@@ -0,0 +1,32 @@
+// OCCukes OCCucumberStepArgument.h
+//
+// Copyright © 2012, 2013, The OCCukes Organisation. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the “Software”), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+//	The above copyright notice and this permission notice shall be included in
+//	all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED “AS IS,” WITHOUT WARRANTY OF ANY KIND, EITHER
+// EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO
+// EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
+// OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+//------------------------------------------------------------------------------
+
+#import <Foundation/Foundation.h>
+
+@interface OCCucumberStepArgument : NSObject
+
+@property(assign, NS_NONATOMIC_IOSONLY) NSUInteger offset;
+@property(strong, NS_NONATOMIC_IOSONLY) NSString *value;
+
+@end
diff --git a/OCCukes/OCCucumberStepArgument.m b/OCCukes/OCCucumberStepArgument.m
new file mode 100755
index 0000000..59cf3de
--- /dev/null
+++ b/OCCukes/OCCucumberStepArgument.m
@@ -0,0 +1,29 @@
+// OCCukes OCCucumberStepArgument.m
+//
+// Copyright © 2012, 2013, The OCCukes Organisation. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the “Software”), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+//	The above copyright notice and this permission notice shall be included in
+//	all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED “AS IS,” WITHOUT WARRANTY OF ANY KIND, EITHER
+// EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO
+// EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
+// OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+//------------------------------------------------------------------------------
+
+#import "OCCucumberStepArgument.h"
+
+@implementation OCCucumberStepArgument
+
+@end
diff --git a/OCCukes/OCCucumberStepDefinition.h b/OCCukes/OCCucumberStepDefinition.h
new file mode 100755
index 0000000..738974a
--- /dev/null
+++ b/OCCukes/OCCucumberStepDefinition.h
@@ -0,0 +1,94 @@
+// OCCukes OCCucumberStepDefinition.h
+//
+// Copyright © 2012, 2013, The OCCukes Organisation. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the “Software”), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+//	The above copyright notice and this permission notice shall be included in
+//	all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED “AS IS,” WITHOUT WARRANTY OF ANY KIND, EITHER
+// EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO
+// EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
+// OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+//------------------------------------------------------------------------------
+
+#import <Foundation/Foundation.h>
+
+/**
+ * Step definitions hold a regular expression and a C block.
+ *
+ * You create a step definition by registering a Give, When or Then
+ * step. You can invoke a step definition.
+ *
+ * Step definitions carry a file and line property. Assign these to `__FILE__`
+ * and `__LINE__` respectively. Cucumber reports source file-colon-line
+ * references for step definitions. These become clickable in editors such as
+ * TextMate and RubyMine. Very useful when developing. Note that `__FILE__` is a
+ * pointer to a static string of characters. No need to copy the static
+ * null-terminated C string. As a static, the string will remain in place and
+ * unchanged. Line numbers are ordinal, rather than cardinal. Line 1 is the
+ * first line, not the second line. Hence line 0 means line number unspecified.
+ */
+@interface OCCucumberStepDefinition : NSObject
+
+@property(strong, NS_NONATOMIC_IOSONLY) NSRegularExpression *regularExpression;
+@property(copy, NS_NONATOMIC_IOSONLY) void (^block)(NSArray *arguments);
+@property(assign, NS_NONATOMIC_IOSONLY) const char *file;
+@property(assign, NS_NONATOMIC_IOSONLY) unsigned int line;
+
+// convenience initialisers
+- (id)initWithRegularExpression:(NSRegularExpression *)regularExpression block:(void (^)(NSArray *arguments))block;
+
+/**
+ * Constructs a new step definition from a given pattern string.
+ *
+ * Compiles a new regular expression for the step based on the given
+ * pattern string. Answers a new step definition if the expression successfully
+ * compiles. Otherwise answers @c nil.
+ */
+- (id)initWithPattern:(NSString *)pattern block:(void (^)(NSArray *arguments))block;
+
+/**
+ * Answers a unique string identifier for the step definition.
+ *
+ * All step definitions need a unique string identifier. The Cucumber
+ * client utilises these identifiers in order to reference remote step
+ * definitions across the wire. Identifiers are string values. So long as they
+ * are one-to-one with the identity of the step definition, and not the state of
+ * the step definition, their exact contents are arbitrary. The implementation
+ * uses a string value based on the "self" pointer.
+ */
+- (NSString *)identifierString;
+
+/**
+ * @result Answers an array of regular-expression match capture values, one for
+ * each matching capture group. Answers @c nil if the step definition's regular
+ * expression pattern does not match the given step name. Answers an array of
+ * zero length if the pattern matches but no capture groups exist in the step
+ * expression.
+ */
+- (NSArray *)argumentsFromStepName:(NSString *)stepName;
+
+/**
+ * Invokes a step given its name, using the given arguments.
+ *
+ * First derives the step matches. If it finds just one, invokes the
+ * step using the supplied arguments.
+ * Step definitions can invoke other step definitions as necessary. This method
+ * gives access to the steps @em by @em name. There could be more than one
+ * matching definition. There may even be no match. In such cases, the step
+ * invocation throws an exception.
+ */
+- (void)invokeWithArguments:(NSArray *)arguments;
+
+@end
diff --git a/OCCukes/OCCucumberStepDefinition.m b/OCCukes/OCCucumberStepDefinition.m
new file mode 100755
index 0000000..a1f74b8
--- /dev/null
+++ b/OCCukes/OCCucumberStepDefinition.m
@@ -0,0 +1,99 @@
+// OCCukes OCCucumberStepDefinition.m
+//
+// Copyright © 2012, 2013, The OCCukes Organisation. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the “Software”), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+//	The above copyright notice and this permission notice shall be included in
+//	all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED “AS IS,” WITHOUT WARRANTY OF ANY KIND, EITHER
+// EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO
+// EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
+// OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+//------------------------------------------------------------------------------
+
+#import "OCCucumberStepDefinition.h"
+#import "OCCucumberStepArgument.h"
+
+@implementation OCCucumberStepDefinition
+
+@synthesize regularExpression = _regularExpression;
+@synthesize block = _block;
+@synthesize file = _file;
+@synthesize line = _line;
+
+- (id)initWithRegularExpression:(NSRegularExpression *)regularExpression block:(void (^)(NSArray *arguments))block
+{
+	if ((self = [self init]))
+	{
+		[self setRegularExpression:regularExpression];
+		[self setBlock:block];
+	}
+	return self;
+}
+
+- (id)initWithPattern:(NSString *)pattern block:(void (^)(NSArray *arguments))block
+{
+	NSError *__autoreleasing error = nil;
+	NSRegularExpression *regularExpression = [NSRegularExpression regularExpressionWithPattern:pattern options:0 error:&error];
+	// What to do with the error if the expression compiler raises one?
+	if (error)
+	{
+		[NSException raise:[error domain] format:@"%@", [error localizedDescription]];
+	}
+	return regularExpression ? [self initWithRegularExpression:regularExpression block:block] : nil;
+}
+
+- (NSString *)identifierString
+{
+	return [NSString stringWithFormat:@"%p", self];
+}
+
+- (NSArray *)argumentsFromStepName:(NSString *)stepName
+{
+	NSMutableArray *arguments;
+	NSTextCheckingResult *match = [[self regularExpression] firstMatchInString:stepName options:0 range:NSMakeRange(0, [stepName length])];
+	if (match)
+	{
+		arguments = [NSMutableArray array];
+		// The first range always captures the entire match; subsequent ranges
+		// match regular expression capture groups.
+		for (NSUInteger i = 1; i < [match numberOfRanges]; i++)
+		{
+			OCCucumberStepArgument *argument = [[OCCucumberStepArgument alloc] init];
+			NSRange range = [match rangeAtIndex:i];
+			// Only set up an argument's offset and value if the range is found.
+			// Optional captures may find nothing.
+			if (range.location != NSNotFound)
+			{
+				[argument setOffset:range.location];
+				[argument setValue:[stepName substringWithRange:range]];
+			}
+			[arguments addObject:argument];
+		}
+	}
+	else
+	{
+		// Yes, you can send -copy to nil; [(NSObject *)nil copy] answers
+		// nil. In Objective-C, nil is a valid message receiver.
+		arguments = nil;
+	}
+	return [arguments copy];
+}
+
+- (void)invokeWithArguments:(NSArray *)arguments
+{
+	[self block](arguments);
+}
+
+@end
diff --git a/OCCukes/OCCucumberStepMatch.h b/OCCukes/OCCucumberStepMatch.h
new file mode 100755
index 0000000..cc71383
--- /dev/null
+++ b/OCCukes/OCCucumberStepMatch.h
@@ -0,0 +1,36 @@
+// OCCukes OCCucumberStepMatch.h
+//
+// Copyright © 2012, 2013, The OCCukes Organisation. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the “Software”), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+//	The above copyright notice and this permission notice shall be included in
+//	all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED “AS IS,” WITHOUT WARRANTY OF ANY KIND, EITHER
+// EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO
+// EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
+// OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+//------------------------------------------------------------------------------
+
+#import <Foundation/Foundation.h>
+
+@class OCCucumberStepDefinition;
+
+@interface OCCucumberStepMatch : NSObject
+
+@property(strong, NS_NONATOMIC_IOSONLY) OCCucumberStepDefinition *stepDefinition;
+@property(strong, NS_NONATOMIC_IOSONLY) NSArray *stepArguments;
+
+- (id)initWithDefinition:(OCCucumberStepDefinition *)definition arguments:(NSArray *)arguments;
+
+@end
diff --git a/OCCukes/OCCucumberStepMatch.m b/OCCukes/OCCucumberStepMatch.m
new file mode 100755
index 0000000..9af8d13
--- /dev/null
+++ b/OCCukes/OCCucumberStepMatch.m
@@ -0,0 +1,42 @@
+// OCCukes OCCucumberStepMatch.m
+//
+// Copyright © 2012, 2013, The OCCukes Organisation. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the “Software”), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+//	The above copyright notice and this permission notice shall be included in
+//	all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED “AS IS,” WITHOUT WARRANTY OF ANY KIND, EITHER
+// EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO
+// EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
+// OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+//------------------------------------------------------------------------------
+
+#import "OCCucumberStepMatch.h"
+
+@implementation OCCucumberStepMatch
+
+@synthesize stepDefinition = _stepDefinition;
+@synthesize stepArguments = _stepArguments;
+
+- (id)initWithDefinition:(OCCucumberStepDefinition *)definition arguments:(NSArray *)arguments
+{
+	if ((self = [self init]))
+	{
+		[self setStepDefinition:definition];
+		[self setStepArguments:arguments];
+	}
+	return self;
+}
+
+@end
diff --git a/OCCukes/OCCucumberWorld.h b/OCCukes/OCCucumberWorld.h
new file mode 100755
index 0000000..a28995e
--- /dev/null
+++ b/OCCukes/OCCucumberWorld.h
@@ -0,0 +1,40 @@
+// OCCukes OCCucumberWorld.h
+//
+// Copyright © 2012, 2013, The OCCukes Organisation. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the “Software”), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+//	The above copyright notice and this permission notice shall be included in
+//	all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED “AS IS,” WITHOUT WARRANTY OF ANY KIND, EITHER
+// EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO
+// EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
+// OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+//------------------------------------------------------------------------------
+
+#import <Foundation/Foundation.h>
+
+/**
+ * Scenarios create worlds. Worlds carry state for steps. When a scenario
+ * begins, Cucumber creates and sets up the current world.
+ *
+ * In Objective-C, worlds instantiate when scenarios begin. The OCCucumber
+ * language creates and connects it. In order to facilitate a similar paradigm
+ * within Objective-C, steps can also access the current world via the shared
+ * language. Each scenario's world acts as a vehicle for carrying values
+ * in-between steps. Use the key-value coding interface to set up and access
+ * your custom values.
+ */
+@interface OCCucumberWorld : NSObject
+
+@end
diff --git a/OCCukes/OCCucumberWorld.m b/OCCukes/OCCucumberWorld.m
new file mode 100755
index 0000000..b5bc4bf
--- /dev/null
+++ b/OCCukes/OCCucumberWorld.m
@@ -0,0 +1,55 @@
+// OCCukes OCCucumberWorld.m
+//
+// Copyright © 2012, 2013, The OCCukes Organisation. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the “Software”), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+//	The above copyright notice and this permission notice shall be included in
+//	all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED “AS IS,” WITHOUT WARRANTY OF ANY KIND, EITHER
+// EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO
+// EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
+// OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+//------------------------------------------------------------------------------
+
+#import "OCCucumberWorld.h"
+
+@interface OCCucumberWorld()
+
+@property(strong, NS_NONATOMIC_IOSONLY) NSMutableDictionary *values;
+
+@end
+
+@implementation OCCucumberWorld
+
+// designated initialiser
+- (id)init
+{
+	if ((self = [super init]))
+	{
+		[self setValues:[NSMutableDictionary dictionary]];
+	}
+	return self;
+}
+
+- (void)setValue:(id)value forUndefinedKey:(NSString *)key
+{
+	[[self values] setObject:value forKey:key];
+}
+
+- (id)valueForUndefinedKey:(NSString *)key
+{
+	return [[self values] objectForKey:key];
+}
+
+@end
diff --git a/OCCukes/OCCukes.h b/OCCukes/OCCukes.h
new file mode 100755
index 0000000..60a2a6e
--- /dev/null
+++ b/OCCukes/OCCukes.h
@@ -0,0 +1,31 @@
+// OCCukes OCCukes.h
+//
+// Copyright © 2012, 2013, The OCCukes Organisation. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the “Software”), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+//	The above copyright notice and this permission notice shall be included in
+//	all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED “AS IS,” WITHOUT WARRANTY OF ANY KIND, EITHER
+// EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO
+// EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
+// OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+//------------------------------------------------------------------------------
+
+#import <OCCukes/OCCucumber.h>
+#import <OCCukes/OCCucumberRuntime.h>
+#import <OCCukes/OCCucumberLanguage.h>
+#import <OCCukes/OCCucumberWorld.h>
+#import <OCCukes/OCCucumberStepDefinition.h>
+#import <OCCukes/OCCucumberExceptions.h>
+#import <OCCukes/Versioning.h>
diff --git a/OCCukes/Versioning.h b/OCCukes/Versioning.h
new file mode 100755
index 0000000..246b13e
--- /dev/null
+++ b/OCCukes/Versioning.h
@@ -0,0 +1,36 @@
+/* OCCukes Versioning.h
+ *
+ * Copyright © 2012, 2013, The OCCukes Organisation. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the “Software”), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ *	The above copyright notice and this permission notice shall be included in
+ *	all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED “AS IS,” WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO
+ * EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
+ * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ ******************************************************************************/
+
+#import <Foundation/Foundation.h>
+
+extern const unsigned char kOCCukesVersionString[];
+extern const double kOCCukesVersionNumber;
+
+/**
+ * Answers the current Apple-generic versioning-formatted version string. The
+ * version string has been trimmed. It has no leading or trailing whitespace or
+ * newlines. Note that the raw C-based version string contrastingly has a single
+ * terminating newline character.
+ */
+NSString *OCCukesVersionString(void);
diff --git a/OCCukes/Versioning.m b/OCCukes/Versioning.m
new file mode 100755
index 0000000..fb8e334
--- /dev/null
+++ b/OCCukes/Versioning.m
@@ -0,0 +1,38 @@
+/* OCCukes Versioning.m
+ *
+ * Copyright © 2012, 2013, The OCCukes Organisation. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the “Software”), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ *	The above copyright notice and this permission notice shall be included in
+ *	all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED “AS IS,” WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO
+ * EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
+ * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ ******************************************************************************/
+
+#import "Versioning.h"
+
+NSString *OCCukesVersionString()
+{
+	// The implementation assumes that the raw C-language version string
+	// terminates with null. It also trims assuming that the very last character
+	// is a terminating line feed. Also assumes UTF-8 encoding.
+	static NSString *__strong versionString;
+	if (versionString == nil)
+	{
+		versionString = [[NSString stringWithCString:(const char *)kOCCukesVersionString encoding:NSUTF8StringEncoding] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
+	}
+	return versionString;
+}
diff --git a/README.md b/README.md
new file mode 100755
index 0000000..3c9fe83
--- /dev/null
+++ b/README.md
@@ -0,0 +1,286 @@
+# [![Cucumber Roll](http://files.softicons.com/download/object-icons/richs-misc-icons-by-rich-d/png/24/Cucumber%20Roll.png)](https://github.com/OCCukes/OCCukes) Objective-C Cucumber Wire Protocol
+
+[![Build Status](https://travis-ci.org/royratcliffe/OCCukes.png?branch=master)](https://travis-ci.org/royratcliffe/OCCukes)
+
+It allows Cucumber to touch your application in _intimate places_ (to quote
+Cucumber's [wire protocol feature description][wire-protocol]). Goals include
+and exclude:
+
+[wire-protocol]:https://github.com/cucumber/cucumber/blob/master/legacy_features/wire_protocol_erb.feature
+
+* Implement the Cucumber wire protocol.
+
+  This is the most direct way to connect Cucumber to non-Ruby environments.
+
+* Not to link against the C++ standard library.
+
+  Just pure Automatic Reference Counting (ARC) Objective-C based on Apple's
+  Foundation framework.
+
+Why the OC name-space prefix? OC stands for Objective-C. It emphasises the
+underlying dependency as well as the multiplatform capability. OCCukes supports
+Objective-C on all Apple platforms: iOS and OS X.
+
+The project does _not_ include an expectation framework. It only runs
+Objective-C coded step definitions. Your step definitions must assert
+appropriate expectations, possibly by running _other_ step definitions. Since
+you write your Cucumber step definitions in Objective-C, you can use any kind
+of assertion framework, or even write your own. Exceptions thrown by the step
+become Cucumber step failures. See
+[OCExpectations](https://github.com/OCCukes/OCExpectations) for an expectations
+library.
+
+OCCukes and its companion OCExpectations sails as close to Cucumber and RSpec
+shores as is possible. If you are familiar with Cucumber and RSpec, you should
+find these projects refreshingly familiar; despite the differing implementation
+languages. Interfaces and implementations mirror their Ruby counterparts.
+
+To use OCCukes, you need Xcode 4.4 or above, Ruby as well as Apple's Command
+Line Tools package. Install them on your Mac first. See
+[Prerequisites](https://github.com/OCCukes/OCCukes/wiki/Prerequisites) for
+details.
+
+## Usage
+
+OCCukes integrates with Xcode. You launch a Cucumber-based test suite along
+with any other Xcode project test suite: just press Command+U. Cucumber
+piggy-backs on the standard SenTestKit (OCUnit) tests.
+
+To make this work, you need to launch Cucumber in the background while your
+test suite runs. Xcode's pre-actions let you do this. To set up the pre- and
+post-actions for your test target, just install Cucumber using RVM.
+
+### Test scheme pre-action
+
+Make this your pre-action for the Test scheme:
+
+	PATH=$PATH:$HOME/.rvm/bin
+	rvm 1.9.3 do cucumber "$SRCROOT/features" --format html --out "$OBJROOT/features.html"
+
+It sets up the PATH variable so that the shell can find RVM; Xcode resets the
+PATH when shelling out. It then launches Cucumber using RVM with Ruby 1.9.3;
+this looks for the latest 1.9.3-version of Ruby installed, but quietly fails if
+the latest version is __not__ installed. Success assumes you have already
+installed Cucumber in the Ruby 1.9.3 RVM; adjust according to your local
+environment and personal preferences. Use `gem install cucumber dnssd` within
+the selected Ruby version to install Cucumber and its dependencies.
+
+### Test scheme post-action
+
+Then make this your post-action:
+
+	open "$OBJROOT/features.html"
+
+### Wire protocol configuration
+
+Add a wire configuration to your `features/step_definitions` folder, a YAML
+file with a `.wire` extension. Contents as follows.
+
+	host: _occukes-runtime._tcp.
+
+	# The default three-second time-out might not help a debugging
+	# effort. Instead, lengthen the timeouts for specific wire protocol
+	# messages.
+	timeout:
+	  step_matches: 120
+
+Host and port describe where to find the wire socket service. If you want to
+use Bonjour (DNS Service Discovery, DNSSD) to resolve the host address and the
+port number, specify a DNS service name as the host. This triggers Bonjour
+discovery. The Cucumber wire service accepts connections at port 54321 on _any_
+interface. So you can connect to non-local hosts as well.
+
+You can override the Cucumber runtime connect and disconnect timeouts
+at the command line. For example, use
+
+	defaults write org.OCCukes OCCucumberRuntimeDisconnectTimeout -float 120.0
+
+to reconfigure the disconnect timeout to two minutes. Express
+timeouts in units of seconds. Display the current configuration using
+
+	defaults read org.OCCukes
+
+### Environment Support
+
+[env-rb]:https://github.com/OCCukes/OCCukes/blob/master/features/support/env.rb
+
+Set up your `features/support/env.rb`. You can copy this code from
+[`features/support/env.rb`][env-rb]. The Ruby code defines a Cucumber
+`AfterConfiguration` block for daemonising the Cucumber process and waiting for
+the wire server to begin accepting socket connections. This block runs after
+Cucumber configuration.
+
+### Add test case
+
+Finally, integrate Cucumber tests with your standard unit test cases by adding
+steps.
+
+Basic template for some step definitions, `MySteps.m`:
+
+	#import <OCCukes/OCCukes.h>
+
+	__attribute__((constructor))
+	static void StepDefinitions()
+	{
+
+	}
+
+Make as many such step definition modules as required. Organise the steps
+around related features.
+
+Register your step definitions before executing the Objective-C Cucumber
+runtime by sending `-run`. As you see above, definitions manifest themselves in
+Objective-C as C blocks. These blocks assert the step's expectations, throwing
+an exception if any expectations fail. Steps therefore succeed when they
+encounter no exceptions.
+
+The runtime accepts connections until all connections disappear. By default, it
+offers an initial 10-second connection window; giving up if Cucumber fails to
+connect for 10 seconds. The runtime also offers a 1-second disconnection window
+before shutting down the socket. This allows all connections to disappear
+temporarily. You can adjust these connect and disconnect timeouts if necessary.
+
+Link your test target against the `OCCukes.framework` for OS X platforms; or
+against the `libOCCukes.a` static library for iOS test targets. For iOS
+targets, you also need `OTHER_LDFLAGS` equal to `-all_load`; the linker does
+not automatically load Objective-C categories when they appear in a static
+library but this flag forces it to.
+
+## Advantages
+
+Why use OCCukes?
+
+### Test bundle injection
+
+Takes advantage of Apple's test bundle injection mechanism. In other words, you
+do not need to link your target against some other library. Your target needs
+nothing extra. This obviates any need for maintaining multiple targets, one for
+the application proper, then another one for Cucumber testing. Xcode takes care
+of the injection of the wire protocol server along with all other tests and
+dependencies at testing time.
+
+This prevents a proliferation of targets, making project maintenance easier.
+You do not need to have a Cucumber'ified target which duplicates your target
+proper but adds additional dependencies. Bundle injection handles all that for
+you. One application, one target.
+
+### No additional Ruby
+
+The OCCukes approach obviates any additional Ruby-side client gem needed for
+bridging work between Cucumber and iOS or OS X. Cucumber is the direct client
+end-point. It already contains the necessary equipment for talking to OCCukes.
+No need for another adapter. OCCukes talks _native_ Cucumber.
+
+This also means that you do not need to build and maintain a skeletal structure
+within your features just for adapting and connecting to a remote test system.
+Cuts out the [cruft](http://foldoc.org/cruft).
+
+### No private dependencies
+
+The software only makes use of public APIs. This makes it far less brittle.
+Private frameworks can and do change without notice. Projects relying on them
+can easily become redundant especially as Apple's operating systems advance
+rapidly.
+
+### Multiple subprojects
+
+The OCCukes organisation publishes [various Cucumber-related subprojects](https://github.com/OCCukes/OCCukes/wiki/Repos).
+Although the OCCukes project lies at the core, complementary projects
+OCExpectations and a slew of iOS-specific spinoffs exist: UICukes,
+UIExpectations and UIAutomation. The structure helps to avoid an all-or-nothing
+mindset. Take whatever best suits your needs. The projects aim at various kinds
+of development projects: iOS application, Mac application, iOS library, or Mac
+framework.
+
+OCCukes sub-projects prefixed by `OC` have Objective-C and Foundation framework
+dependencies. That means they work on iOS _and_ OS X platforms. They are
+cross-platform projects and incorporate iOS library targets as well as OS X
+framework targets.
+
+Projects prefixed by `UI` have iOS UIKit dependencies. They aim at iOS projects
+only. Their Xcode projects contain a single iOS static library target.
+[UICukes](https://github.com/OCCukes/UICukes) acts as an umbrella project for
+iOS dependencies. It pulls in all other sub-projects needed for Cucumber on
+iOS. iOS developers will therefore normally clone out the UICukes submodule by
+itself. Doing so pulls in all other dependencies as sub-submodules.
+
+## Troubleshooting
+
+### Cucumber launches but invokes no steps
+
+You press Cmd+U in Xcode to run your tests. There is a brief pause then you see
+the Cucumber output. Cucumber has executed and parsed the features and
+scenarios. Trouble is, Cucumber stops at the first scenario's first step. No
+steps execute. When you set a breakpoint within your step definitions, sure
+enough, they never run.
+
+#### Solution
+
+Make sure that you are not running a Cucumber instance in some other process.
+For example, you might be running it as part of an IDE for some other project,
+or some other components of the same project. Terminate the other Cucumbers and
+re-test.
+
+## When and how to launch Cucumber?
+
+Running Cucumber with Mac or iOS software requires two synchronised processes:
+a Cucumber client in Ruby, and an Objective-C wire server running within an
+application test bundle. The server needs to run first in order to open a wire
+server socket. The socket may be local or on another device. Actual iOS devices
+do not share the same local host. Hence the Cucumber client cannot assume
+`localhost`.
+
+Wire server and client need to synchronise their execution. When Cucumber runs,
+it expects to connect to the wire server when it finds a wire configuration.
+Hence the Test scheme needs to launch the server beforehand. Best way to launch
+Cucumber from Xcode: use a pre-action within the Test scheme. Cucumber
+therefore needs to do three things at launch time:
+
+1. fork itself into the background so that Xcode testing can proceed, that is, daemonise;
+2. wait for the wire server to set itself up;
+3. close down the wire server when Cucumber finishes running its features and
+	invoking the remote-wire step definitions. This can happen automatically when
+	it server sees no wire connection after a given period of time, say a second.
+
+Step 2 raises issues when Cucumber tests actual iOS devices where the server
+does not open a port on `localhost`. Waiting for the wire server to initialise
+(step 2) requires that the Cucumber run-time environment establishes the wire
+server's address and port information. Without it, the Cucumber run will fail.
+The environment needs to wait an acceptable time for the server to appear on
+the prescribed port. Moreover, the client-side environment needs to attempt and
+reattempt to connect. The initial attempts will likely fail with a "refuse to
+connect" exception, simply because the server has not yet opened the socket.
+Steps 2 and 3 together imply a setting up and tearing down at the Cucumber
+client side.
+
+## MIT Licensing
+
+Copyright © 2012, 2013 The OCCukes Organisation. All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the “Software”), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+	The above copyright notice and this permission notice shall be included in
+	all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED “AS IS,” WITHOUT WARRANTY OF ANY KIND, EITHER
+EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO
+EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
+OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+## Sponsors
+
+- Levide Capital Limited, Blenheim, New Zealand
+
+## Contributors
+
+- Roy Ratcliffe, Pioneering Software, United Kingdom
+- Bennett Smith, Focal Shift LLC, United States
+- Terry Tucker, Focal Shift LLC, United States