<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -38,10 +38,33 @@ typedef struct	JSValueRefAndContextRef JSValueRefAndContextRef;
 
 	JSGlobalContextRef	ctx;
     id					_delegate;
+
+	//
+	// Safe dealloc
+	//	- (void)dealloc cannot be overloaded as it is called during JS GC, which forbids new JS code execution.
+	//	As the js dealloc method cannot be called, safe dealloc allows it to be executed during the next run loop cycle
+	//	NOTE : upon destroying a JSCocoaController, safe dealloc is disabled
+	//
 	BOOL				useSafeDealloc;
+
+	//
+	// Split call
+	//	Allows calling multi param ObjC messages with a jQuery-like syntax.
+	//
+	//	obj.do({ this : 'hello', andThat : 'world' })
+	//		instead of
+	//		obj.dothis_andThat_('hello', 'world')
+	//
+	BOOL				useSplitCall;
+
+	// JSLint : used for ObjJ syntax, class syntax, return if
+	BOOL				useJSLint;
 }
 
 @property (assign) id delegate;
+@property BOOL useSafeDealloc;
+@property BOOL useSplitCall;
+@property BOOL useJSLint;
 
 - (id)init;
 - (id)initWithGlobalContext:(JSGlobalContextRef)ctx;
@@ -102,6 +125,17 @@ typedef struct	JSValueRefAndContextRef JSValueRefAndContextRef;
 + (void)logBoxedObjects;
 
 //
+// Class inspection (shortcuts to JSCocoaLib)
+//
++ (id)rootclasses;
++ (id)classes;
++ (id)protocols;
++ (id)imageNames;
++ (id)methods;
++ (id)runtimeReport;
++ (id)explainMethodEncoding:(id)encoding;
+
+//
 // Class handling
 //
 + (BOOL)overloadInstanceMethod:(NSString*)methodName class:(Class)class jsFunction:(JSValueRefAndContextRef)valueAndContext;
@@ -140,8 +174,6 @@ typedef struct	JSValueRefAndContextRef JSValueRefAndContextRef;
 
 - (BOOL)useAutoCall;
 - (void)setUseAutoCall:(BOOL)b;
-- (BOOL)useSafeDealloc;
-- (void)setUseSafeDealloc:(BOOL)b;
 
 - (const char*)typeEncodingOfMethod:(NSString*)methodName class:(NSString*)className;
 + (const char*)typeEncodingOfMethod:(NSString*)methodName class:(NSString*)className;
@@ -193,7 +225,7 @@ typedef struct	JSValueRefAndContextRef JSValueRefAndContextRef;
 // Custom handler for calling
 //	Return YES to indicate you handled calling
 //	Return NO to let JSCocoa handle calling
-- (JSValueRef) JSCocoa:(JSCocoaController*)controller callMethod:(NSString*)methodName ofObject:(id)object argumentCount:(int)argumentCount arguments:(JSValueRef*)arguments inContext:(JSContextRef)ctx exception:(JSValueRef*)exception;
+- (JSValueRef) JSCocoa:(JSCocoaController*)controller callMethod:(NSString*)methodName ofObject:(id)callee privateObject:(JSCocoaPrivateObject*)thisPrivateObject argumentCount:(int)argumentCount arguments:(JSValueRef*)arguments inContext:(JSContextRef)localCtx exception:(JSValueRef*)exception;
 
 //
 // Getting global properties (classes, structures, C function names, enums via OSXObject_getProperty)</diff>
      <filename>jscocoa/JSCocoa/JSCocoaController.h</filename>
    </modified>
    <modified>
      <diff>@@ -73,7 +73,7 @@ const JSClassDefinition kJSClassDefinitionEmpty = { 0, 0,
 
 
 
-@synthesize delegate=_delegate;
+@synthesize delegate=_delegate, useSafeDealloc, useSplitCall, useJSLint;
 
 	// Given a jsFunction, retrieve its closure (jsFunction's pointer address is used as key)
 	static	id	closureHash;
@@ -204,6 +204,8 @@ const JSClassDefinition kJSClassDefinitionEmpty = { 0, 0,
 #endif
 
 	// Load class kit
+	id lintPath = [[NSBundle bundleForClass:[self class]] pathForResource:@&quot;jslint-jscocoa&quot; ofType:@&quot;js&quot;];
+	if ([[NSFileManager defaultManager] fileExistsAtPath:lintPath])	[self evalJSFile:lintPath];
 	id classKitPath = [[NSBundle bundleForClass:[self class]] pathForResource:@&quot;class&quot; ofType:@&quot;js&quot;];
 	if ([[NSFileManager defaultManager] fileExistsAtPath:classKitPath])	[self evalJSFile:classKitPath];
 
@@ -233,8 +235,12 @@ const JSClassDefinition kJSClassDefinitionEmpty = { 0, 0,
 	// JSCocoa registers 'safeDealloc' in place of 'dealloc' and calls it in the next run loop cycle. 
 	// (If called during dealloc, this would mean executing JS code during JS GC, which is not possible)
 	// useSafeDealloc will be turned to NO upon JSCocoaController dealloc
-	useSafeDealloc = YES;
-	
+	useSafeDealloc	= YES;
+	// Yep !
+	useJSLint		= YES;
+	// ObjJ syntax renders split call moot
+	useSplitCall	= NO;
+
 	return	self;
 }
 
@@ -384,8 +390,9 @@ static id JSCocoaSingleton = NULL;
 {
 #if defined(__ppc__)
 	return @&quot;PPC&quot;;
-#elif defined(__ppc64__)
-	return @&quot;PPC64&quot;;
+// Unsupported
+//#elif defined(__ppc64__)
+//	return @&quot;PPC64&quot;;
 #elif defined(__i386__) 
 	return @&quot;i386&quot;;
 #elif defined(__x86_64__) 
@@ -405,7 +412,7 @@ static id JSCocoaSingleton = NULL;
 //
 // Evaluate a file
 // 
-- (BOOL)evalJSFile:(NSString*)path toJSValueRef:(JSValueRef*)returnValue withLintex:(BOOL)withLintex
+- (BOOL)evalJSFile:(NSString*)path toJSValueRef:(JSValueRef*)returnValue
 {
 	NSError*	error;
 	id script = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:&amp;error];
@@ -420,12 +427,11 @@ static id JSCocoaSingleton = NULL;
 	// Normal path, with macro expansion for class definitions
 	// OR
 	// Lintex path
-	id functionName = withLintex ? @&quot;lintex&quot; : @&quot;expandJSMacros&quot;;
+	id functionName = @&quot;expandJSMacros&quot;;
 
-	// Expand macros or lintex
+	// Expand macros
 	BOOL hasFunction = [self hasJSFunctionNamed:functionName];
-	if (!hasFunction &amp;&amp; [functionName isEqualToString:@&quot;lintex&quot;])	NSLog(@&quot;lintex function not found to process %@&quot;, path);
-	if (hasFunction)
+	if (hasFunction &amp;&amp; useJSLint)
 	{
 		id expandedScript = [self unboxJSValueRef:[self callJSFunctionNamed:functionName withArguments:script, nil]];
 		// Bail if expansion failed
@@ -433,6 +439,8 @@ static id JSCocoaSingleton = NULL;
 			return NSLog(@&quot;%@ expansion failed on %@ (%@)&quot;, functionName, path, expandedScript), NO;
 
 		script = expandedScript;
+//		NSLog(@&quot;===================================================================================&quot;);
+//		NSLog(@&quot;%@&quot;, expandedScript);
 	}
 
 	//
@@ -465,11 +473,6 @@ static id JSCocoaSingleton = NULL;
 	return	YES;
 }
 
-- (BOOL)evalJSFile:(NSString*)path toJSValueRef:(JSValueRef*)returnValue
-{
-	return	[self evalJSFile:path toJSValueRef:returnValue withLintex:NO];
-}
-
 
 //
 // Evaluate a file, without caring about return result
@@ -479,11 +482,6 @@ static id JSCocoaSingleton = NULL;
 	return	[self evalJSFile:path toJSValueRef:nil];
 }
 
-- (BOOL)evalJSFileWithLintex:(NSString*)path
-{
-	return	[self evalJSFile:path toJSValueRef:nil withLintex:YES];
-}
-
 //
 // Evaluate a string
 // 
@@ -808,6 +806,14 @@ static id JSCocoaSingleton = NULL;
 	return	o;
 }
 
+//
+// Autocall
+//	Allow calling zero arg methods without parens
+//
+//	NSWorkspace.sharedWorkspace
+//		instead of
+//		NSWorkspace.sharedWorkspace()
+//
 - (BOOL)useAutoCall
 {
 	return	useAutoCall;
@@ -817,16 +823,6 @@ static id JSCocoaSingleton = NULL;
 	useAutoCall = b;
 }
 
-- (BOOL)useSafeDealloc
-{
-	return	useSafeDealloc;
-}
-- (void)setUseSafeDealloc:(BOOL)b
-{
-	useSafeDealloc = b;
-}
-
-
 - (JSGlobalContextRef)ctx
 {
 	return	ctx;
@@ -848,36 +844,6 @@ static id JSCocoaSingleton = NULL;
 + (void)ensureJSValueIsObjectAfterInstanceAutocall:(JSValueRef)jsValue inContext:(JSContextRef)ctx;
 {
 	NSLog(@&quot;***For zero arg instance, use obj.instance() instead of obj.instance***&quot;);
-/*	
-	// It's an instance if it has a property 'thisObject', holding the class name
-	// value is an object holding the method name, 'instance' - its only use is storing 'thisObject'
-	JSObjectRef jsObject = JSValueToObject(ctx, jsValue, NULL);
-
-	JSStringRef name = JSStringCreateWithUTF8CString(&quot;thisObject&quot;);
-	BOOL hasProperty =  JSObjectHasProperty(ctx, jsObject, name);
-	JSValueRef thisObjectValue = JSObjectGetProperty(ctx, jsObject, name, NULL);
-	if (hasProperty)	JSObjectDeleteProperty(ctx, jsObject, name, NULL);
-	JSStringRelease(name);
-	
-	if (!hasProperty)	return;
-
-	// Returning NULL will crash
-	if (!thisObjectValue)	return;
-	JSObjectRef thisObject = JSValueToObject(ctx, thisObjectValue, NULL);
-	if (!thisObject)		return;
-	JSCocoaPrivateObject* privateObject = JSObjectGetPrivate(thisObject);
-	if (!thisObject)		return;
-
-	NSLog(@&quot;Instance autocall on class %@&quot;, [privateObject object]);
-
-	// Create new instance and patch it into object
-	id newInstance = [[[privateObject object] alloc] init];
-	JSCocoaPrivateObject* instanceObject = JSObjectGetPrivate(jsObject);
-	instanceObject.type = @&quot;@&quot;;
-	[instanceObject setObject:newInstance];
-	// Make JS object sole owner
-	[newInstance release];
-*/	
 }
 
 //
@@ -1295,15 +1261,21 @@ static id JSCocoaSingleton = NULL;
 {
 	// Always add method to existing class to make sure we're swizzling this class' method and not the parent's.
 	// Courtesy of Jonathan 'Wolf' Rentzsch's JRSwizzle http://github.com/rentzsch/jrswizzle/tree/master
-	SEL origSel_			= NSSelectorFromString(methodName);
-	Method origMethod		= class_getInstanceMethod(class, origSel_);
-	if (!origMethod)		return	NSLog(@&quot;Method does not exist in instance swizzle %@.%@&quot;, class, methodName), NO;
+	SEL origSel_				= NSSelectorFromString(methodName);
+	Method origMethod			= class_getInstanceMethod(class, origSel_);
+	if (!origMethod)			return	NSLog(@&quot;Method does not exist in instance swizzle %@.%@&quot;, class, methodName), NO;
 
 	// Prefix method name with &quot;original&quot;
-	id originalMethodName	= [NSString stringWithFormat:@&quot;%@%@&quot;, OriginalMethodPrefix, methodName];
-	SEL altSel_				= NSSelectorFromString(originalMethodName);
+	id originalMethodName		= [NSString stringWithFormat:@&quot;%@%@&quot;, OriginalMethodPrefix, methodName];
+	SEL altSel_					= NSSelectorFromString(originalMethodName);
+
+	// If method is already swizzled, reswizzle it to reset the class. 
+	// addMethod: will overwrite our first swizzled method, which is what we want.
+	if ([class instancesRespondToSelector:altSel_])	
+		method_exchangeImplementations(class_getInstanceMethod(class, origSel_), class_getInstanceMethod(class, altSel_));
+
 	BOOL b = [self addMethod:originalMethodName class:class jsFunction:valueAndContext encoding:(char*)method_getTypeEncoding(origMethod)];
-	if (!b)					return NO;
+	if (!b)						return NO;
 
 	class_addMethod(class, origSel_, class_getMethodImplementation(class, origSel_), method_getTypeEncoding(origMethod));
 	
@@ -1317,15 +1289,21 @@ static id JSCocoaSingleton = NULL;
 
 	// Always add method to existing class to make sure we're swizzling this class' method and not the parent's.
 	// Courtesy of Jonathan 'Wolf' Rentzsch's JRSwizzle http://github.com/rentzsch/jrswizzle/tree/master
-	SEL origSel_			= NSSelectorFromString(methodName);
-	Method origMethod		= class_getClassMethod(class, origSel_);
-	if (!origMethod)		return	NSLog(@&quot;Method does not exist in class swizzle %@.%@&quot;, class, methodName), NO;
+	SEL origSel_				= NSSelectorFromString(methodName);
+	Method origMethod			= class_getClassMethod(class, origSel_);
+	if (!origMethod)			return	NSLog(@&quot;Method does not exist in class swizzle %@.%@&quot;, class, methodName), NO;
 
 	// Prefix method name with &quot;original&quot;
-	id originalMethodName	= [NSString stringWithFormat:@&quot;%@%@&quot;, OriginalMethodPrefix, methodName];
-	SEL altSel_				= NSSelectorFromString(originalMethodName);
+	id originalMethodName		= [NSString stringWithFormat:@&quot;%@%@&quot;, OriginalMethodPrefix, methodName];
+	SEL altSel_					= NSSelectorFromString(originalMethodName);
+
+	// If method is already swizzled, reswizzle it to reset the class. 
+	// addMethod: will overwrite our first swizzled method, which is what we want.
+	if ([class respondsToSelector:altSel_])	
+		method_exchangeImplementations(class_getInstanceMethod(class, origSel_), class_getInstanceMethod(class, altSel_));
+
 	BOOL b = [self addMethod:originalMethodName class:class jsFunction:valueAndContext encoding:(char*)method_getTypeEncoding(origMethod)];
-	if (!b)					return NO;
+	if (!b)						return NO;
 
 	class_addMethod(class, origSel_, class_getMethodImplementation(class, origSel_), method_getTypeEncoding(origMethod));
 	
@@ -1497,25 +1475,37 @@ static id JSCocoaSingleton = NULL;
 #pragma mark Variadic call
 - (BOOL)isMethodVariadic:(id)methodName class:(id)class
 {
-	id className = [class description];
-	id xml = [[BridgeSupportController sharedController] queryName:className];
-	if (!xml)	return NSLog(@&quot;isMethodVariadic for %@ called on unknown BridgeSupport class %@&quot;, methodName, class), NO;
-
-	// Get XML definition
-	id error;
-	// Clang will report a leak here, but NSXMLDocument auto releases itself if it fails loading
-	id xmlDocument = [[NSXMLDocument alloc] initWithXMLString:xml options:0 error:&amp;error];
-	if (error)	return	NSLog(@&quot;(isMethodVariadic:class:) malformed xml while getting method %@ of class %@ : %@&quot;, methodName, class, error), NO;
+	// Go up the class tree until we find a variadic method or exhaust superclasses
+	while (class)
+	{
+		id className = [class description];
+		id xml = [[BridgeSupportController sharedController] queryName:className];
+		// Go up if this class has no description
+		if (!xml)	
+		{
+			class = [class superclass];
+			continue;
+		}
+//NSLog(@&quot;variadic %@ xml=%@&quot;, methodName, xml);
+		// Get XML definition
+		id error;
+		// Clang will report a leak here, but NSXMLDocument auto releases itself if it fails loading
+		id xmlDocument = [[NSXMLDocument alloc] initWithXMLString:xml options:0 error:&amp;error];
+		if (error)	return	NSLog(@&quot;(isMethodVariadic:class:) malformed xml while getting method %@ of class %@ : %@&quot;, methodName, class, error), NO;
+			
+		// Query method
+		id xpath = [NSString stringWithFormat:@&quot;*[@selector=\&quot;%@\&quot; and @variadic=\&quot;true\&quot;]&quot;, methodName];
+		id nodes = [[xmlDocument rootElement] nodesForXPath:xpath error:&amp;error];
+		if (error)	NSLog(@&quot;isMethodVariadic:error: %@&quot;, error);
+
+		// It's a variadic method if XPath returned one result
+		BOOL	isVariadic = [nodes count] == 1;
+		[xmlDocument release];
+		if (isVariadic)	return YES;
 		
-	// Query method
-	id xpath = [NSString stringWithFormat:@&quot;*[@selector=\&quot;%@\&quot; and @variadic=\&quot;true\&quot;]&quot;, methodName];
-	id nodes = [[xmlDocument rootElement] nodesForXPath:xpath error:&amp;error];
-	if (error)	NSLog(@&quot;isMethodVariadic:error: %@&quot;, error);
-
-	// It's a variadic method if XPath returned one result
-	BOOL	isVariadic = [nodes count] == 1;
-	[xmlDocument release];
-	return	isVariadic;
+		class = [class superclass];
+	}
+	return	NO;
 }
 
 - (BOOL)isFunctionVariadic:(id)functionName
@@ -1729,6 +1719,9 @@ static id JSCocoaSingleton = NULL;
 	id files = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:path error:nil];
 	id predicate = [NSPredicate predicateWithFormat:@&quot;SELF ENDSWITH[c] '.js'&quot;];
 	files = [files filteredArrayUsingPredicate:predicate]; 
+	
+	// Execute in test order, not finder order
+	files = [files sortedArrayUsingSelector:@selector(localizedStandardCompare:)];
 //	NSLog(@&quot;files=%@&quot;, files);
 
 	if ([files count] == 0)	return	[JSCocoaController logAndSay:@&quot;no test files found&quot;], 0;
@@ -1887,11 +1880,45 @@ int	liveInstanceCount	= 0;
 	NSLog(@&quot;%@&quot;, boxedObjects);
 }
 
-#pragma mark Distant Object Handling (DO)
-//
-// Distant object handling, courtesy of Gus Mueller
-//
-//
+#pragma mark Class inspection
++ (id)rootclasses
+{
+	return [JSCocoaLib rootclasses];
+}
++ (id)classes
+{
+	return [JSCocoaLib classes];
+}
++ (id)protocols
+{
+	return [JSCocoaLib protocols];
+}
++ (id)imageNames
+{
+	return [JSCocoaLib imageNames];
+}
++ (id)methods
+{
+	return [JSCocoaLib methods];
+}
++ (id)runtimeReport
+{
+	return [JSCocoaLib runtimeReport];
+}
++ (id)explainMethodEncoding:(id)encoding
+{
+	id argumentEncodings	= [JSCocoaController parseObjCMethodEncoding:[encoding UTF8String]];
+	id explication			= [NSMutableArray array];
+	for (id arg in argumentEncodings)
+		[explication addObject:[arg typeDescription]
+		];
+	
+	return	explication;
+}
+
+
+
+
 // JSCocoa : handle setting with callMethod
 //	object.width = 100
 //	-&gt; 
@@ -1906,17 +1933,17 @@ int	liveInstanceCount	= 0;
 										[[propertyName substringWithRange:NSMakeRange(0,1)] capitalizedString], 
 										[propertyName substringWithRange:NSMakeRange(1, [propertyName length]-1)]];
 	
-    if ([self JSCocoa:controller callMethod:setterName ofObject:object argumentCount:1 arguments:&amp;value inContext:localCtx exception:exception]) {
+    if ([self JSCocoa:controller callMethod:setterName ofObject:object privateObject:nil argumentCount:1 arguments:&amp;value inContext:localCtx exception:exception]) {
         return YES;
     }
 	
     return	NO;
 }
-
+#pragma mark Distant Object Handling (DO)
 //
 // NSDistantObject call using NSInvocation
 //
-- (JSValueRef) JSCocoa:(JSCocoaController*)controller callMethod:(NSString*)methodName ofObject:(id)callee argumentCount:(int)argumentCount arguments:(JSValueRef*)arguments inContext:(JSContextRef)localCtx exception:(JSValueRef*)exception
+- (JSValueRef) JSCocoa:(JSCocoaController*)controller callMethod:(NSString*)methodName ofObject:(id)callee privateObject:(JSCocoaPrivateObject*)thisPrivateObject argumentCount:(int)argumentCount arguments:(JSValueRef*)arguments inContext:(JSContextRef)localCtx exception:(JSValueRef*)exception
 {
     SEL selector = NSSelectorFromString(methodName);
 	if (class_getInstanceMethod([callee class], selector) || class_getClassMethod([callee class], selector)) {
@@ -2010,8 +2037,19 @@ int	liveInstanceCount	= 0;
         [invocation invokeWithTarget:callee];
     }
     @catch (NSException * e) {
-        NSLog(@&quot;Exception calling %@: %@&quot;, callee, [e reason]);
-        return JSValueMakeNull(localCtx);
+        NSLog(@&quot;Exception while calling %@. %@&quot;, methodName, [e reason]);
+        
+        if ([[e reason] isEqualToString:@&quot;connection went invalid while waiting for a reply&quot;]) {
+            // whoops?
+            // also, how do we not look for some funky localized string here?
+            // also also, can we now make whatever is pointing to this value, nil?
+            
+            if (thisPrivateObject) {
+                NSLog(@&quot;Connection terminated, removing reference to object&quot;);
+                thisPrivateObject.object = [NSNull null];
+                [thisPrivateObject setJSValueRef:JSValueMakeNull(localCtx) ctx:localCtx];
+            }
+        }
     }
 
 /*    
@@ -2322,6 +2360,7 @@ int	liveInstanceCount	= 0;
 }
 
 // Finalize - same as dealloc
+static BOOL __warningSuppressorAsFinalizeIsCalledBy_objc_msgSendSuper = NO;
 - (void)finalize
 {
 	JSObjectRef hash = NULL;
@@ -2341,6 +2380,7 @@ int	liveInstanceCount	= 0;
 	objc_msgSendSuper(&amp;superData, @selector(finalize));
 	
 	// Ignore warning about missing [super finalize] as the call IS made via objc_msgSendSuper
+	if (__warningSuppressorAsFinalizeIsCalledBy_objc_msgSendSuper)	[super finalize];
 }
 
 
@@ -2570,6 +2610,16 @@ JSValueRef OSXObject_getProperty(JSContextRef ctx, JSObjectRef object, JSStringR
 			return	JSValueMakeNumber(ctx, doubleValue);
 		}
 	}
+
+	// Describe ourselves
+	if ([propertyName isEqualToString:@&quot;toString&quot;])
+	{
+		JSStringRef scriptJS = JSStringCreateWithUTF8CString(&quot;return '(JSCocoa global object)'&quot;);
+		JSObjectRef fn = JSObjectMakeFunction(ctx, NULL, 0, NULL, scriptJS, NULL, 1, NULL);
+		JSStringRelease(scriptJS);
+		return	fn;
+	}
+
 	return	NULL;
 }
 
@@ -2875,7 +2925,7 @@ static void jsCocoaObject_finalize(JSObjectRef object)
 						if ([jsc useSafeDealloc])
 							[jsc performSelector:@selector(safeDeallocInstance:) withObject:boxedObject afterDelay:0];
 					}
-					else	NSLog(@&quot;safeDealloc could not find the context attached to %@.%x - allocate this object with instance(), or add a Javascript variable to it (obj.hello = 'world')&quot;, [boxedObject class], boxedObject);
+					else	NSLog(@&quot;safeDealloc could not find the context attached to %@.%x - allocate this object with instance, or add a Javascript variable to it (obj.hello = 'world')&quot;, [boxedObject class], boxedObject);
 				}
 				
 			}
@@ -2914,9 +2964,6 @@ static JSValueRef jsCocoaObject_getProperty(JSContextRef ctx, JSObjectRef object
 	NSString*	propertyName = (NSString*)JSStringCopyCFString(kCFAllocatorDefault, propertyNameJS);
 	[NSMakeCollectable(propertyName) autorelease];
 	
-	// Autocall instance
-	if ([propertyName isEqualToString:@&quot;thisObject&quot;])	return	NULL;
-	
 	JSCocoaPrivateObject* privateObject = JSObjectGetPrivate(object);
 //	NSLog(@&quot;Asking for property %@ %@(%@)&quot;, propertyName, privateObject, privateObject.type);
 
@@ -2949,7 +2996,7 @@ static JSValueRef jsCocoaObject_getProperty(JSContextRef ctx, JSObjectRef object
 			}
 		}
 
-		// Special case for NSMutableArray get
+		// Special case for NSMutableArray get and Javascript array methods
 		if ([privateObject.object isKindOfClass:[NSArray class]])
 		{
 			id array	= privateObject.object;
@@ -2969,6 +3016,33 @@ static JSValueRef jsCocoaObject_getProperty(JSContextRef ctx, JSObjectRef object
 			
 			// If we have 'length', switch it to 'count'
 			if ([propertyName isEqualToString:@&quot;length&quot;])	propertyName = @&quot;count&quot;;
+		
+			// NSArray bridge
+			id callee	= [privateObject object];
+			SEL sel		= NSSelectorFromString(propertyName);
+			if ([propertyName rangeOfString:@&quot;:&quot;].location == NSNotFound &amp;&amp; ![callee respondsToSelector:sel]
+				&amp;&amp; ![propertyName isEqualToString:@&quot;valueOf&quot;] 
+				&amp;&amp; ![propertyName isEqualToString:@&quot;toString&quot;] 
+			)
+			{
+				id script				= [NSString stringWithFormat:@&quot;return Array.prototype.%@&quot;, propertyName];
+				JSStringRef scriptJS	= JSStringCreateWithUTF8CString([script UTF8String]);
+				JSObjectRef fn			= JSObjectMakeFunction(ctx, NULL, 0, NULL, scriptJS, NULL, 1, NULL);
+				JSValueRef result		= JSObjectCallAsFunction(ctx, fn, NULL, 0, NULL, NULL);
+				JSStringRelease(scriptJS);
+				BOOL isJavascriptArrayMethod =  result ? !JSValueIsUndefined(ctx, result) : NO;
+
+				// Return the packaged Javascript function
+				if (isJavascriptArrayMethod)
+				{
+//					NSLog(@&quot;*** array method : %@&quot;, propertyName);
+					JSObjectRef o = [JSCocoaController jsCocoaPrivateObjectInContext:ctx];
+					JSCocoaPrivateObject* private = JSObjectGetPrivate(o);
+					private.type = @&quot;jsFunction&quot;;
+					[private setJSValueRef:result ctx:ctx];
+					return	o;
+				}
+			}
 		}
 		
 		
@@ -3035,8 +3109,11 @@ static JSValueRef jsCocoaObject_getProperty(JSContextRef ctx, JSObjectRef object
 		{
 			id callee	= [privateObject object];
 			SEL sel		= NSSelectorFromString(propertyName);
+			
+			BOOL isInstanceCall = [propertyName isEqualToString:@&quot;instance&quot;];
+			
 			// Go for zero arg call
-			if ([propertyName rangeOfString:@&quot;:&quot;].location == NSNotFound &amp;&amp; [callee respondsToSelector:sel])
+			if ([propertyName rangeOfString:@&quot;:&quot;].location == NSNotFound &amp;&amp; ([callee respondsToSelector:sel] || isInstanceCall))
 			{
 				//
 				// Delegate canCallMethod, callMethod
@@ -3054,14 +3131,30 @@ static JSValueRef jsCocoaObject_getProperty(JSContextRef ctx, JSObjectRef object
 						}
 					}
 					// Check if delegate handles calling
-					if ([delegate respondsToSelector:@selector(JSCocoa:callMethod:ofObject:argumentCount:arguments:inContext:exception:)])
+					if ([delegate respondsToSelector:@selector(JSCocoa:callMethod:ofObject:privateObject:argumentCount:arguments:inContext:exception:)])
 					{
-						JSValueRef delegateCall = [delegate JSCocoa:jsc callMethod:propertyName ofObject:callee argumentCount:0 arguments:NULL inContext:ctx exception:exception];
+						JSValueRef delegateCall = [delegate JSCocoa:jsc callMethod:propertyName ofObject:callee privateObject:privateObject argumentCount:0 arguments:NULL inContext:ctx exception:exception];
 						if (delegateCall)	
 							return	delegateCall;
 					}
 				}
 
+				// instance
+				if (isInstanceCall)
+				{
+					// Manually call and box our object
+					id class	= [callee class];
+					id instance	= [[class alloc] init];
+					JSValueRef	returnValue;
+					[JSCocoaFFIArgument boxObject:instance toJSValueRef:&amp;returnValue inContext:ctx];
+					// Release it, making the javascript box the sole retainer
+					// Nulling all references to this object will release the instance during Javascript GC					
+					JSCocoaPrivateObject* private = JSObjectGetPrivate(JSValueToObject(ctx, returnValue, NULL));
+					[private.object release];
+					
+					return	returnValue;
+				}
+
 				// Special case for alloc : objects 
 				if ([propertyName isEqualToString:@&quot;alloc&quot;])
 				{
@@ -3080,7 +3173,7 @@ static JSValueRef jsCocoaObject_getProperty(JSContextRef ctx, JSObjectRef object
 				// If we didn't find a method, try Distant Object
 				if (!method)
 				{
-					JSValueRef res = [jsc JSCocoa:jsc callMethod:propertyName ofObject:callee argumentCount:0 arguments:NULL inContext:ctx exception:exception];
+					JSValueRef res = [jsc JSCocoa:jsc callMethod:propertyName ofObject:callee privateObject:privateObject argumentCount:0 arguments:NULL inContext:ctx exception:exception];
 					if (res)	return	res;
 								
 					throwException(ctx, exception, [NSString stringWithFormat:@&quot;Could not get property[%@ %@]&quot;, callee, propertyName]);
@@ -3170,7 +3263,7 @@ static JSValueRef jsCocoaObject_getProperty(JSContextRef ctx, JSObjectRef object
 			&amp;&amp; ![methodName isEqualToString:@&quot;valueOf&quot;] 
 			&amp;&amp; ![methodName isEqualToString:@&quot;Super&quot;]
 			&amp;&amp; ![methodName isEqualToString:@&quot;Original&quot;]
-			&amp;&amp; ![methodName isEqualToString:@&quot;instance&quot;])
+/*			&amp;&amp; ![methodName isEqualToString:@&quot;instance&quot;]*/)
 		{
 			if ([methodName rangeOfString:@&quot;_&quot;].location != NSNotFound)
 				[methodName replaceOccurrencesOfString:@&quot;_&quot; withString:@&quot;:&quot; options:0 range:NSMakeRange(0, [methodName length])];
@@ -3179,6 +3272,20 @@ static JSValueRef jsCocoaObject_getProperty(JSContextRef ctx, JSObjectRef object
 
 			if (![callee respondsToSelector:NSSelectorFromString(methodName)])
 			{
+				// Instance check
+				if ([methodName hasPrefix:@&quot;instance&quot;])
+				{
+					id initMethodName = [NSString stringWithFormat:@&quot;init%@&quot;, [methodName substringFromIndex:8]];
+					if ([callee instancesRespondToSelector:NSSelectorFromString(initMethodName)])
+					{
+						JSObjectRef o = [JSCocoaController jsCocoaPrivateObjectInContext:ctx];
+						JSCocoaPrivateObject* private = JSObjectGetPrivate(o);
+						private.type = @&quot;method&quot;;
+						private.methodName = methodName;
+						return o;
+					}
+				}
+			
 				//
 				// This may be a JS function
 				//
@@ -3228,13 +3335,6 @@ static JSValueRef jsCocoaObject_getProperty(JSContextRef ctx, JSObjectRef object
 		private.type = @&quot;method&quot;;
 		private.methodName = methodName;
 
-		// Special case for instance : setup a valueOf callback calling instance
-		if ([callee class] == callee &amp;&amp; [propertyName isEqualToString:@&quot;instance&quot;])
-		{
-			JSStringRef jsName = JSStringCreateWithUTF8CString(&quot;thisObject&quot;);
-			JSObjectSetProperty(ctx, o, jsName, object, JSCocoaInternalAttribute, NULL);
-			JSStringRelease(jsName);
-		}
 		return	o;
 	}
 	
@@ -3408,7 +3508,7 @@ static bool jsCocoaObject_setProperty(JSContextRef ctx, JSObjectRef object, JSSt
 		
 		// Can't use capitalizedString on the whole string as it will transform 
 		//			myValue 
-		// to		Myvalue (therby destroying camel letters)
+		// to		Myvalue (thereby destroying camel letters)
 		// we want	MyValue
 //		NSString*	setterName = [NSString stringWithFormat:@&quot;set%@:&quot;, [propertyName capitalizedString]];
 		// Capitalize only first letter
@@ -3443,7 +3543,7 @@ static bool jsCocoaObject_setProperty(JSContextRef ctx, JSObjectRef object, JSSt
 				// Check if delegate handles calling
 				if ([delegate respondsToSelector:@selector(JSCocoa:callMethod:ofObject:argumentCount:arguments:inContext:exception:)])
 				{
-					JSValueRef delegateCall = [delegate JSCocoa:jsc callMethod:setterName ofObject:callee argumentCount:0 arguments:NULL inContext:ctx exception:exception];
+					JSValueRef delegateCall = [delegate JSCocoa:jsc callMethod:setterName ofObject:callee privateObject:privateObject argumentCount:0 arguments:NULL inContext:ctx exception:exception];
 					if (delegateCall)	return	!!delegateCall;
 				}
 			}
@@ -3546,7 +3646,6 @@ static bool jsCocoaObject_setProperty(JSContextRef ctx, JSObjectRef object, JSSt
 	// Special case for autocall : allow current js object to receive a custom valueOf method that will handle autocall
 	// And a thisObject property holding class for instance autocall
 	if ([propertyName isEqualToString:@&quot;valueOf&quot;])		return	false;
-	if ([propertyName isEqualToString:@&quot;thisObject&quot;])	return	false;
 	// Allow general setting on structs
 	if ([privateObject.type isEqualToString:@&quot;struct&quot;])	return	false;
 
@@ -3642,6 +3741,8 @@ static JSValueRef jsCocoaObject_callAsFunction_ffi(JSContextRef ctx, JSObjectRef
 	BOOL	callingObjC = NO;
 	// Structure return (objc_msgSend_stret)
 	BOOL	usingStret	= NO;
+	// Calling instance... , replaced with init... and released, making the js object sole owner
+	BOOL	callingInstance	= NO;
 
 
 	// Get delegate
@@ -3677,20 +3778,21 @@ static JSValueRef jsCocoaObject_callAsFunction_ffi(JSContextRef ctx, JSObjectRef
 				}
 			}
 			// Check if delegate handles calling
-			if ([delegate respondsToSelector:@selector(JSCocoa:callMethod:ofObject:argumentCount:arguments:inContext:exception:)])
+			if ([delegate respondsToSelector:@selector(JSCocoa:callMethod:ofObject:privateObject:argumentCount:arguments:inContext:exception:)])
 			{
-				JSValueRef delegateCall = [delegate JSCocoa:jsc callMethod:methodName ofObject:callee argumentCount:argumentCount arguments:arguments inContext:ctx exception:exception];
+				JSValueRef delegateCall = [delegate JSCocoa:jsc callMethod:methodName ofObject:callee privateObject:thisPrivateObject argumentCount:argumentCount arguments:arguments inContext:ctx exception:exception];
 				if (delegateCall)	return	delegateCall;
 			}
 		}
 
 		// Instance call
+/*
 		if ([callee class] == callee &amp;&amp; [methodName isEqualToString:@&quot;instance&quot;])
 		{
 			if (argumentCount &gt; 1)	return	throwException(ctx, exception, @&quot;Invalid argument count in instance call : must be 0 or 1&quot;), NULL;
 			return	[callee instanceWithContext:ctx argumentCount:argumentCount arguments:arguments exception:exception];
 		}
-
+*/
 		// Check selector
 		if (![callee respondsToSelector:NSSelectorFromString(methodName)])
 		{
@@ -3699,7 +3801,7 @@ static JSValueRef jsCocoaObject_callAsFunction_ffi(JSContextRef ctx, JSObjectRef
 			//	set( { value : '5', forKey : 'hello' } )
 			//	-&gt; setValue:forKey:
 			//
-			if (![callee respondsToSelector:NSSelectorFromString(methodName)])
+			if ([jsc useSplitCall])
 			{
 				id			splitMethodName		= privateObject.methodName;
 				id class = [callee class];
@@ -3719,34 +3821,48 @@ static JSValueRef jsCocoaObject_callAsFunction_ffi(JSContextRef ctx, JSObjectRef
 		Method method = class_getInstanceMethod([callee class], NSSelectorFromString(methodName));
 		if (!method)	method = class_getClassMethod([callee class], NSSelectorFromString(methodName));
 
-		// If we didn't find a method, try treating object as Javascript string, then try Distant Object
-		if (!method)	
+		// If we didn't find a method, try an instance call, then try treating object as Javascript string, then try Distant Object
+		if (!method)
 		{
-			// (First) Last chance before exception : try treating callee a Javascript string
-			if ([callee isKindOfClass:[NSString class]])
+			// Instance Check
+			if ([methodName hasPrefix:@&quot;instance&quot;])
 			{
-				id script = [NSString stringWithFormat:@&quot;String.prototype.%@&quot;, methodName];
-				JSStringRef	jsScript = JSStringCreateWithUTF8CString([script UTF8String]);
-				JSValueRef result = JSEvaluateScript(ctx, jsScript, NULL, NULL, 1, NULL);
-				JSStringRelease(jsScript);
-				if (result &amp;&amp; JSValueGetType(ctx, result) == kJSTypeObject)
+				id initMethodName = [NSString stringWithFormat:@&quot;init%@&quot;, [methodName substringFromIndex:8]];
+				id class		= [callee class];
+				method			= class_getInstanceMethod(class, NSSelectorFromString(initMethodName));
+				methodName		= initMethodName;
+				callee			= [class alloc];
+				callingInstance	= YES;
+			}
+			
+			if (!method)
+			{
+				// (First) Last chance before exception : try treating callee as a Javascript string
+				if ([callee isKindOfClass:[NSString class]])
 				{
-					JSStringRef string = JSStringCreateWithCFString((CFStringRef)callee);
-					JSValueRef stringValue = JSValueMakeString(ctx, string);
-					JSStringRelease(string);
-
-					JSObjectRef functionObject = JSValueToObject(ctx, result, NULL);
-					JSObjectRef jsThisObject = JSValueToObject(ctx, stringValue, NULL);
-					JSValueRef r =	JSObjectCallAsFunction(ctx, functionObject, jsThisObject, argumentCount, arguments, NULL);
-					return	r;
+					id script = [NSString stringWithFormat:@&quot;String.prototype.%@&quot;, methodName];
+					JSStringRef	jsScript = JSStringCreateWithUTF8CString([script UTF8String]);
+					JSValueRef result = JSEvaluateScript(ctx, jsScript, NULL, NULL, 1, NULL);
+					JSStringRelease(jsScript);
+					if (result &amp;&amp; JSValueGetType(ctx, result) == kJSTypeObject)
+					{
+						JSStringRef string = JSStringCreateWithCFString((CFStringRef)callee);
+						JSValueRef stringValue = JSValueMakeString(ctx, string);
+						JSStringRelease(string);
+
+						JSObjectRef functionObject = JSValueToObject(ctx, result, NULL);
+						JSObjectRef jsThisObject = JSValueToObject(ctx, stringValue, NULL);
+						JSValueRef r =	JSObjectCallAsFunction(ctx, functionObject, jsThisObject, argumentCount, arguments, NULL);
+						return	r;
+					}
 				}
+				
+				// Last chance before exception : try calling DO
+				JSValueRef res = [jsc JSCocoa:jsc callMethod:methodName ofObject:callee privateObject:thisPrivateObject argumentCount:argumentCount arguments:arguments inContext:ctx exception:exception];
+				if (res)	return	res;
+				
+				return	throwException(ctx, exception, [NSString stringWithFormat:@&quot;jsCocoaObject_callAsFunction : method %@ not found&quot;, methodName]), NULL;
 			}
-			
-			// Last chance before exception : try calling DO
-			JSValueRef res = [jsc JSCocoa:jsc callMethod:methodName ofObject:callee argumentCount:argumentCount arguments:arguments inContext:ctx exception:exception];
-			if (res)	return	res;
-			
-			return	throwException(ctx, exception, [NSString stringWithFormat:@&quot;jsCocoaObject_callAsFunction : method %@ not found&quot;, methodName]), NULL;
 		}
 		
 		// Extract arguments
@@ -3798,6 +3914,8 @@ static JSValueRef jsCocoaObject_callAsFunction_ffi(JSContextRef ctx, JSObjectRef
 	//	we may have a variadic call
 	//
 	BOOL isVariadic = NO;
+	// Possibly account for a missing terminating NULL in ObjC variadic method
+	BOOL sugarCheckVariadic = NO;
 	if (callAddressArgumentCount != argumentCount)	
 	{
 		if (methodName)		isVariadic = [[JSCocoaController controllerFromContext:ctx] isMethodVariadic:methodName class:[callee class]];
@@ -3808,6 +3926,14 @@ static JSValueRef jsCocoaObject_callAsFunction_ffi(JSContextRef ctx, JSObjectRef
 		{
 			return	throwException(ctx, exception, [NSString stringWithFormat:@&quot;Bad argument count in %@ : expected %d, got %d&quot;, functionName ? functionName : methodName,	callAddressArgumentCount, argumentCount]), NULL;
 		}
+		
+		// Sugar check : if last object is not NULL, account for it
+		if (isVariadic &amp;&amp; callingObjC &amp;&amp; argumentCount &amp;&amp; !JSValueIsNull(ctx, arguments[argumentCount-1]))
+		{
+			// Will be tested during argument conversion
+			sugarCheckVariadic = YES;
+			argumentCount++;
+		}
 	}
 
 	//
@@ -3858,7 +3984,7 @@ static JSValueRef jsCocoaObject_callAsFunction_ffi(JSContextRef ctx, JSObjectRef
 //				NSLog(@&quot;superClass=%@ (old=%@) (%@) function=%x&quot;, superSelectorClass, [callee superclass], [callee class], function);
 			}
 		}
-	
+
 		// Setup arguments, unboxing or converting data
 		for (i=0; i&lt;argumentCount; i++, idx++)
 		{
@@ -3874,7 +4000,7 @@ static JSValueRef jsCocoaObject_callAsFunction_ffi(JSContextRef ctx, JSObjectRef
 				arg		= [argumentEncodings objectAtIndex:idx+1];
 
 			// Convert argument
-			JSValueRef			jsValue	= arguments[i];
+			JSValueRef			jsValue	= sugarCheckVariadic &amp;&amp; i == argumentCount-1 ? JSValueMakeNull(ctx) : arguments[i];
 			BOOL	shouldConvert = YES;
 			// Check type o modifiers
 			if ([arg typeEncoding] == '^')
@@ -3921,7 +4047,6 @@ static JSValueRef jsCocoaObject_callAsFunction_ffi(JSContextRef ctx, JSObjectRef
 	// Get return value holder
 	id returnValue = [argumentEncodings objectAtIndex:0];
 	
-	
 	// Allocate return value storage if it's a pointer
 	if ([returnValue typeEncoding] == '^')
 		[returnValue allocateStorage];
@@ -3956,6 +4081,14 @@ static JSValueRef jsCocoaObject_callAsFunction_ffi(JSContextRef ctx, JSObjectRef
 	BOOL converted = [returnValue toJSValueRef:&amp;jsReturnValue inContext:ctx];
 	if (!converted)	return	throwException(ctx, exception, [NSString stringWithFormat:@&quot;Return value not converted in %@&quot;, methodName?methodName:functionName]), NULL;
 	
+	// Instance call : release object to make js object sole owner
+	if (callingInstance)
+	{
+		JSCocoaPrivateObject* private = JSObjectGetPrivate(JSValueToObject(ctx, jsReturnValue, NULL));
+		[private.object release];
+	}
+
+	
 	return	jsReturnValue;
 }
 
@@ -4031,85 +4164,91 @@ static JSValueRef jsCocoaObject_callAsFunction(JSContextRef ctx, JSObjectRef fun
 			return	o;
 		}
 	}
+
 	// Javascript custom methods
-	if ([privateObject.methodName isEqualToString:@&quot;toString&quot;] || [privateObject.methodName isEqualToString:@&quot;valueOf&quot;])
+	id methodName = privateObject.methodName;
+	// Possible optimization if more custom methods are handled
+//	if ([customCallPaths valueForKey:methodName])
 	{
-		JSValueRef jsValue = valueOfCallback(ctx, function, thisObject, 0, NULL, NULL);
-		if ([privateObject.methodName isEqualToString:@&quot;toString&quot;])	
+		if ([methodName isEqualToString:@&quot;toString&quot;] || [methodName isEqualToString:@&quot;valueOf&quot;])
 		{
-			JSStringRef str = JSValueToStringCopy(ctx, jsValue, NULL);
-			JSValueRef ret = JSValueMakeString(ctx, str);
-			JSStringRelease(str);
-			return ret;
+			JSValueRef jsValue = valueOfCallback(ctx, function, thisObject, 0, NULL, NULL);
+			if ([privateObject.methodName isEqualToString:@&quot;toString&quot;])	
+			{
+				JSStringRef str = JSValueToStringCopy(ctx, jsValue, NULL);
+				JSValueRef ret = JSValueMakeString(ctx, str);
+				JSStringRelease(str);
+				return ret;
+			}
+			return	jsValue;
 		}
-		return	jsValue;
-	}
-	
-	//
-	// Super/Swizzled handling : get method name and move js arguments to C array
-	//
-	//	call this.Super(arguments) to call parent method
-	//	call this.Original(arguments) to call swizzled method
-	//
-	if ([privateObject.methodName isEqualToString:@&quot;Super&quot;] || [privateObject.methodName isEqualToString:@&quot;Original&quot;])
-	{
-		id methodName = privateObject.methodName;
-		BOOL callingSwizzled = [methodName isEqualToString:@&quot;Original&quot;];
-		if (argumentCount != 1)	return	throwException(ctx, exception, [NSString stringWithFormat:@&quot;%@ wants one argument array&quot;, methodName]), NULL;
-
-		// Get argument object
-		JSObjectRef argumentObject = JSValueToObject(ctx, arguments[0], NULL);
-		
-		// Get argument count
-		JSStringRef	jsLengthName = JSStringCreateWithUTF8CString(&quot;length&quot;);
-		JSValueRef	jsLength = JSObjectGetProperty(ctx, argumentObject, jsLengthName, NULL);
-		JSStringRelease(jsLengthName);
-		if (JSValueGetType(ctx, jsLength) != kJSTypeNumber)	return	throwException(ctx, exception, [NSString stringWithFormat:@&quot;%@ has no arguments&quot;, methodName]), NULL;
 		
-		int i, superArgumentCount = (int)JSValueToNumber(ctx, jsLength, NULL);
-		if (superArgumentCount)
+		//
+		// Super/Swizzled handling : get method name and move js arguments to C array
+		//
+		//	call this.Super(arguments) to call parent method
+		//	call this.Original(arguments) to call swizzled method
+		//
+		if ([methodName isEqualToString:@&quot;Super&quot;] || [methodName isEqualToString:@&quot;Original&quot;])
 		{
-			superArguments = malloc(sizeof(JSValueRef)*superArgumentCount);
-			for (i=0; i&lt;superArgumentCount; i++)
-				superArguments[i] = JSObjectGetPropertyAtIndex(ctx, argumentObject, i, NULL);
-		}
+			id methodName = privateObject.methodName;
+			BOOL callingSwizzled = [methodName isEqualToString:@&quot;Original&quot;];
+			if (argumentCount != 1)	return	throwException(ctx, exception, [NSString stringWithFormat:@&quot;%@ wants one argument array&quot;, methodName]), NULL;
 
-		argumentCount = superArgumentCount;
-		
-		// Get method name and associated class (need class for obj_msgSendSuper)
-		JSStringRef	jsCalleeName = JSStringCreateWithUTF8CString(&quot;callee&quot;);
-		JSValueRef	jsCalleeValue = JSObjectGetProperty(ctx, argumentObject, jsCalleeName, NULL);
-		JSStringRelease(jsCalleeName);
-		JSObjectRef jsCallee = JSValueToObject(ctx, jsCalleeValue, NULL);
-		superSelector = [[JSCocoaController controllerFromContext:ctx] selectorForJSFunction:jsCallee];
-		if (!superSelector)	
-		{
-			if (superArguments)		free(superArguments);
-			if (callingSwizzled)	return	throwException(ctx, exception, @&quot;Original couldn't find swizzled method&quot;), NULL;
-			return	throwException(ctx, exception, @&quot;Super couldn't find parent method&quot;), NULL;
-		}
-		superSelectorClass = [[[JSCocoaController controllerFromContext:ctx] classForJSFunction:jsCallee] superclass];
-		
-		// Swizzled handling : we're just changing the selector
-		if (callingSwizzled)
-		{
-			if (![superSelector hasPrefix:OriginalMethodPrefix])
+			// Get argument object
+			JSObjectRef argumentObject = JSValueToObject(ctx, arguments[0], NULL);
+			
+			// Get argument count
+			JSStringRef	jsLengthName = JSStringCreateWithUTF8CString(&quot;length&quot;);
+			JSValueRef	jsLength = JSObjectGetProperty(ctx, argumentObject, jsLengthName, NULL);
+			JSStringRelease(jsLengthName);
+			if (JSValueGetType(ctx, jsLength) != kJSTypeNumber)	return	throwException(ctx, exception, [NSString stringWithFormat:@&quot;%@ has no arguments&quot;, methodName]), NULL;
+			
+			int i, superArgumentCount = (int)JSValueToNumber(ctx, jsLength, NULL);
+			if (superArgumentCount)
+			{
+				superArguments = malloc(sizeof(JSValueRef)*superArgumentCount);
+				for (i=0; i&lt;superArgumentCount; i++)
+					superArguments[i] = JSObjectGetPropertyAtIndex(ctx, argumentObject, i, NULL);
+			}
+
+			argumentCount = superArgumentCount;
+			
+			// Get method name and associated class (need class for obj_msgSendSuper)
+			JSStringRef	jsCalleeName = JSStringCreateWithUTF8CString(&quot;callee&quot;);
+			JSValueRef	jsCalleeValue = JSObjectGetProperty(ctx, argumentObject, jsCalleeName, NULL);
+			JSStringRelease(jsCalleeName);
+			JSObjectRef jsCallee = JSValueToObject(ctx, jsCalleeValue, NULL);
+			superSelector = [[JSCocoaController controllerFromContext:ctx] selectorForJSFunction:jsCallee];
+			if (!superSelector)	
 			{
 				if (superArguments)		free(superArguments);
-				return	throwException(ctx, exception, [NSString stringWithFormat:@&quot;Original called on a non swizzled method (%@)&quot;, superSelector]), NULL;
+				if (callingSwizzled)	return	throwException(ctx, exception, @&quot;Original couldn't find swizzled method&quot;), NULL;
+				return	throwException(ctx, exception, @&quot;Super couldn't find parent method&quot;), NULL;
 			}
-			function = [JSCocoaController jsCocoaPrivateObjectInContext:ctx];
-			JSCocoaPrivateObject* private = JSObjectGetPrivate(function);
-			private.type		= @&quot;method&quot;;
-			private.methodName	= superSelector;
+			superSelectorClass = [[[JSCocoaController controllerFromContext:ctx] classForJSFunction:jsCallee] superclass];
 			
-			superSelector		= NULL;
-			superSelectorClass	= NULL;
+			// Swizzled handling : we're just changing the selector
+			if (callingSwizzled)
+			{
+				if (![superSelector hasPrefix:OriginalMethodPrefix])
+				{
+					if (superArguments)		free(superArguments);
+					return	throwException(ctx, exception, [NSString stringWithFormat:@&quot;Original called on a non swizzled method (%@)&quot;, superSelector]), NULL;
+				}
+				function = [JSCocoaController jsCocoaPrivateObjectInContext:ctx];
+				JSCocoaPrivateObject* private = JSObjectGetPrivate(function);
+				private.type		= @&quot;method&quot;;
+				private.methodName	= superSelector;
+				
+				superSelector		= NULL;
+				superSelectorClass	= NULL;
+			}
+			
+			// Don't call NSObject's safeDealloc as it doesn't exist
+			if ([superSelector isEqualToString:@&quot;safeDealloc&quot;] &amp;&amp; superSelectorClass == [NSObject class])
+				return	JSValueMakeUndefined(ctx);
 		}
-		
-		// Don't call NSObject's safeDealloc as it doesn't exist
-		if ([superSelector isEqualToString:@&quot;safeDealloc&quot;] &amp;&amp; superSelectorClass == [NSObject class])
-			return	JSValueMakeUndefined(ctx);
 	}
 
 	JSValueRef* functionArguments	= superArguments ? superArguments : (JSValueRef*)arguments;
@@ -4212,12 +4351,6 @@ static void throwException(JSContextRef ctx, JSValueRef* exception, NSString* re
 		if (isSpeaking)	system([[NSString stringWithFormat:@&quot;say \&quot;%@\&quot; &amp;&quot;, reason] UTF8String]);
 	}
 
-	// Convert exception to string
-	JSStringRef jsName = JSStringCreateWithUTF8CString([reason UTF8String]);
-	JSValueRef jsString = JSValueMakeString(ctx, jsName);
-	JSStringRelease(jsName);
-
-
 	// Gather call stack
 	JSValueRef	callStackException = NULL;
 	JSStringRef scriptJS = JSStringCreateWithUTF8CString(&quot;return dumpCallStack()&quot;);
@@ -4237,6 +4370,11 @@ static void throwException(JSContextRef ctx, JSValueRef* exception, NSString* re
 			reason = [NSString stringWithFormat:@&quot;%@\n%@&quot;, reason, callStack];
 	}
 
+	// Convert exception to string
+	JSStringRef jsName = JSStringCreateWithUTF8CString([reason UTF8String]);
+	JSValueRef jsString = JSValueMakeString(ctx, jsName);
+	JSStringRelease(jsName);
+
 	// Convert to object to allow JavascriptCore to add line and sourceURL
 	*exception	= JSValueToObject(ctx, jsString, NULL);
 }</diff>
      <filename>jscocoa/JSCocoa/JSCocoaController.m</filename>
    </modified>
    <modified>
      <diff>@@ -31,6 +31,8 @@
 	BOOL		isOutArgument;
 }
 
+- (NSString*)typeDescription;
+
 - (BOOL)setTypeEncoding:(char)encoding;
 - (BOOL)setTypeEncoding:(char)encoding withCustomStorage:(void*)storagePtr;
 - (void)setStructureTypeEncoding:(NSString*)encoding;
@@ -52,6 +54,7 @@
 + (NSString*)structureNameFromStructureTypeEncoding:(NSString*)structureTypeEncoding;
 + (NSString*)structureFullTypeEncodingFromStructureTypeEncoding:(NSString*)structureTypeEncoding;
 + (NSString*)structureFullTypeEncodingFromStructureName:(NSString*)structureName;
++ (NSString*)structureTypeEncodingDescription:(NSString*)structureTypeEncoding;
 
 + (BOOL)fromJSValueRef:(JSValueRef)value inContext:(JSContextRef)ctx typeEncoding:(char)typeEncoding fullTypeEncoding:(NSString*)fullTypeEncoding fromStorage:(void*)ptr;
 </diff>
      <filename>jscocoa/JSCocoa/JSCocoaFFIArgument.h</filename>
    </modified>
    <modified>
      <diff>@@ -70,6 +70,55 @@
 			isReturnValue, ptr];
 }
 
++ (NSString*)typeDescriptionForTypeEncoding:(char)typeEncoding fullTypeEncoding:(NSString*)fullTypeEncoding 
+{
+	switch (typeEncoding)
+	{
+		case	_C_VOID:	return	@&quot;void&quot;;
+		case	_C_ID:		return	@&quot;ObjC object&quot;;
+		case	_C_CLASS:	return	@&quot;ObjC class&quot;;
+		case	_C_CHR:		return	@&quot;char&quot;;
+		case	_C_UCHR:	return	@&quot;unsigned char&quot;;
+		case	_C_SHT:		return	@&quot;short&quot;;
+		case	_C_USHT:	return	@&quot;unsigned short&quot;;
+		case	_C_INT:		return	@&quot;int&quot;;
+		case	_C_UINT:	return	@&quot;unsigned int&quot;;
+		case	_C_LNG:		return	@&quot;long&quot;;
+		case	_C_ULNG:	return	@&quot;unsigned long&quot;;
+		case	_C_LNG_LNG:	return	@&quot;long long&quot;;
+		case	_C_ULNG_LNG:return	@&quot;unsigned long long&quot;;
+		case	_C_FLT:		return	@&quot;float&quot;;
+		case	_C_DBL:		return	@&quot;double&quot;;
+		case	'{':
+		{
+			// Special case for getting raw JSValues to ObjC
+			BOOL isJSStruct = [fullTypeEncoding hasPrefix:@&quot;{JSValueRefAndContextRef&quot;];
+			if (isJSStruct)
+			{
+				return	@&quot;(JSCocoa structure used to pass JSValueRef without conversion)&quot;;
+			}
+
+//			if (!JSValueIsObject(ctx, value))	return	NO;
+//			JSObjectRef object = JSValueToObject(ctx, value, NULL);
+//			void* p = ptr;
+//			id r = [JSCocoaFFIArgument structureFullTypeEncodingFromStructureTypeEncoding:fullTypeEncoding];
+//			if (!r)	return [NSString stringWithFormat:@&quot;(unknown structure %@)&quot;, fullTypeEncoding];
+			return	[JSCocoaFFIArgument structureTypeEncodingDescription:fullTypeEncoding];
+		}
+		case	_C_SEL:		return	@&quot;selector&quot;;
+		case	_C_CHARPTR:	return	@&quot;char*&quot;;
+		case	_C_BOOL:	return	@&quot;BOOL&quot;;
+		case	_C_PTR:		return	@&quot;pointer&quot;;
+		case	_C_UNDEF:	return	@&quot;(function pointer or block?)&quot;;
+	}
+	return	@&quot;(unknown)&quot;;
+}
+
+- (NSString*)typeDescription
+{
+	return [[self class] typeDescriptionForTypeEncoding:typeEncoding fullTypeEncoding:structureTypeEncoding];
+}
+
 #pragma mark Getters / Setters
 
 //
@@ -369,7 +418,9 @@
 		case	'{':
 		{
 			// Special case for getting raw JSValues to ObjC
-			BOOL isJSStruct = NSOrderedSame == [fullTypeEncoding compare:@&quot;{JSValueRefAndContextRef&quot; options:0 range:NSMakeRange(0, sizeof(&quot;{JSValueRefAndContextRef&quot;)-1)];
+//			BOOL isJSStruct = NSOrderedSame == [fullTypeEncoding compare:@&quot;{JSValueRefAndContextRef&quot; options:0 range:NSMakeRange(0, sizeof(&quot;{JSValueRefAndContextRef&quot;)-1)];
+			BOOL isJSStruct = [fullTypeEncoding hasPrefix:@&quot;{JSValueRefAndContextRef&quot;];
+
 			if (isJSStruct)
 			{
 				// Beware ! This context is not the global context and will be valid only for that call.
@@ -501,7 +552,7 @@
 		case	'{':
 		{
 			// Special case for getting raw JSValues from ObjC to JS
-			BOOL isJSStruct = NSOrderedSame == [fullTypeEncoding compare:@&quot;{JSValueRefAndContextRef&quot; options:0 range:NSMakeRange(0, sizeof(&quot;{JSValueRefAndContextRef&quot;)-1)];
+			BOOL isJSStruct = [fullTypeEncoding hasPrefix:@&quot;{JSValueRefAndContextRef&quot;];
 			if (isJSStruct)
 			{
 				JSValueRefAndContextRef*	jsStruct = (JSValueRefAndContextRef*)ptr;
@@ -903,7 +954,7 @@ typedef	struct { char a; BOOL b;		} struct_C_BOOL;
 			continue;
 		}
 		if (*c == '=')	continue;
-	
+		
 		[types addObject:[NSString stringWithFormat:@&quot;%c&quot;, *c]];
 
 		// Special case for pointers
@@ -933,6 +984,116 @@ typedef	struct { char a; BOOL b;		} struct_C_BOOL;
 	return	types;
 }
 
+//
+// Given a structure encoding string, produce a human readable format
+//
++ (int)structureTypeEncodingDescription:(NSString*)structureTypeEncoding inString:(NSMutableString**)str
+{
+//	id types = [[[NSMutableArray alloc] init] autorelease];
+//	id str = [NSMutableString stringWithFormat:@&quot;%@&quot;, [self structureNameFromStructureTypeEncoding:structureTypeEncoding]];
+	
+//	NSLog(@&quot;describe2 %@&quot;, structureTypeEncoding);
+//	NSLog(@&quot;describe2 %@&quot;, structureTypeEncoding);
+	
+	
+	
+	char* c = (char*)[structureTypeEncoding UTF8String];
+	char* c0 = c;
+	// Skip '{'
+	c += 1;
+	// Skip '_' if it's there
+	if (*c == '_') c++;
+	// Skip structureName, '='
+//	c += [private.structureName length]+1;
+	id structureName = [self structureNameFromStructureTypeEncoding:structureTypeEncoding];
+	c += [structureName length]+1;
+
+	int	openedBracesCount = 1;
+	int closedBracesCount = 0;
+	int propertyCount = 0;
+	for (; *c &amp;&amp; closedBracesCount != openedBracesCount; c++)
+	{
+		if (*c == '{')	
+		{
+			[*str appendString:@&quot;{&quot;];
+			openedBracesCount++;
+		}
+		if (*c == '}')	
+		{
+			[*str appendString:@&quot;}&quot;];
+			closedBracesCount++;
+		}
+		// Parse name then type
+		if (*c == '&quot;')
+		{
+			propertyCount++;
+			if (propertyCount &gt; 1)	[*str appendString:@&quot;, &quot;];
+			char* c2 = c+1;
+			while (c2 &amp;&amp; *c2 != '&quot;') c2++;
+			id propertyName = [[[NSString alloc] initWithBytes:c+1 length:(c2-c-1) encoding:NSUTF8StringEncoding] autorelease];
+			c = c2;
+			// Skip '&quot;'
+			c++;
+			char encoding = *c;
+			[*str appendString:propertyName];
+			[*str appendString:@&quot;: &quot;];
+			
+//			JSValueRef	valueJS = NULL;
+			if (encoding == '{')
+			{
+				[*str appendString:@&quot;{&quot;];
+				int parsed = [self structureTypeEncodingDescription:[NSString stringWithUTF8String:c] inString:str];
+				c += parsed;
+//				NSLog(@&quot;parsed %@ (%d)&quot;, substr, [substr length]);
+			}
+			else
+			{
+				[*str appendString:@&quot;(&quot;];
+				[*str appendString:[self typeDescriptionForTypeEncoding:encoding fullTypeEncoding:nil]];
+				[*str appendString:@&quot;)&quot;];
+			}
+
+/*			
+			else
+			{
+				// Given a pointer to raw C structure data, convert its members to JS values
+				if (ptr)
+				{
+					// Align 
+					[JSCocoaFFIArgument alignPtr:ptr accordingToEncoding:encoding];
+					// Get value
+					[JSCocoaFFIArgument toJSValueRef:&amp;valueJS inContext:ctx typeEncoding:encoding fullTypeEncoding:nil fromStorage:*ptr];
+					// Advance ptr
+					[JSCocoaFFIArgument advancePtr:ptr accordingToEncoding:encoding];
+				}
+				else
+				// Given no pointer, get values from initialValues array. If not present, create undefined values
+				{
+					if (!convertedValueCount)	return 0;
+					if (initialValues &amp;&amp; initialValueCount &amp;&amp; *convertedValueCount &lt; initialValueCount)	valueJS = initialValues[*convertedValueCount];
+					else																				valueJS = JSValueMakeUndefined(ctx);									
+				}
+				if (convertedValueCount)	*convertedValueCount = *convertedValueCount+1;
+			}
+*/
+//			JSStringRef	propertyNameJS = JSStringCreateWithCFString((CFStringRef)propertyName);
+//			JSObjectSetProperty(ctx, jsObject, propertyNameJS, valueJS, 0, NULL);
+//			JSStringRelease(propertyNameJS);
+		}
+	}
+	return	c-c0-1;
+}
++ (NSString*)structureTypeEncodingDescription:(NSString*)structureTypeEncoding
+{
+	id fullStructureTypeEncoding = [self structureFullTypeEncodingFromStructureTypeEncoding:structureTypeEncoding];
+	if (!fullStructureTypeEncoding)	return	[NSString stringWithFormat:@&quot;(Could not describe struct %@)&quot;, structureTypeEncoding];
+
+	id str = [NSMutableString stringWithFormat:@&quot;%@{&quot;, [self structureNameFromStructureTypeEncoding:fullStructureTypeEncoding]];
+	[self structureTypeEncodingDescription:fullStructureTypeEncoding inString:&amp;str];
+	[str appendString:@&quot;}&quot;];
+	return	str;
+}
+
 
 + (int)sizeOfStructure:(NSString*)encoding
 {</diff>
      <filename>jscocoa/JSCocoa/JSCocoaFFIArgument.m</filename>
    </modified>
    <modified>
      <diff>@@ -52,3 +52,47 @@
 - (int)typeCount;
 
 @end
+
+
+@interface JSCocoaLib : NSObject
+
++ (id)rootclasses;
++ (id)classes;
++ (id)protocols;
++ (id)imageNames;
++ (id)methods;
++ (id)runtimeReport;
+
+@end
+
+
+
+@interface NSObject(ClassWalker)
++ (id)__classImage;
+- (id)__classImage;
++ (id)__derivationPath;
+- (id)__derivationPath;
++ (int)__derivationLevel;
+- (int)__derivationLevel;
++ (id)__ownMethods;
+- (id)__ownMethods;
++ (id)__methods;
+- (id)__methods;
++ (id)__subclasses;
+- (id)__subclasses;
++ (id)__subclassTree;
+- (id)__subclassTree;
++ (id)__ownIvars;
+- (id)__ownIvars;
++ (id)__ivars;
+- (id)__ivars;
++ (id)__ownProperties;
+- (id)__ownProperties;
++ (id)__properties;
+- (id)__properties;
++ (id)__ownProtocols;
+- (id)__ownProtocols;
++ (id)__protocols;
+- (id)__protocols;
+
+@end</diff>
      <filename>jscocoa/JSCocoa/JSCocoaLib.h</filename>
    </modified>
    <modified>
      <diff>@@ -201,3 +201,575 @@
 
 @end
 
+
+
+@implementation JSCocoaLib
+
+//
+// Class list 
+//	Some classes are skipped as adding them to an array crashes (Zombie, classes derived from Object or NSProxy)
+//
++ (NSArray*)classes
+{
+	int classCount		= objc_getClassList(nil, 0);
+	Class* classList	= malloc(sizeof(Class)*classCount);
+	objc_getClassList(classList, classCount);
+	
+	
+	NSMutableArray* classArray	= [NSMutableArray array];
+	for (int i=0; i&lt;classCount; i++)
+	{
+		id class		= classList[i];
+		const char* name= class_getName(class);
+		if (!name)		continue;
+		id className	= [NSString stringWithUTF8String:name];
+		
+		id superclass	= class_getSuperclass(class);
+		id superclassName = superclass ? [NSString stringWithUTF8String:class_getName(superclass)] : @&quot;&quot;;
+		
+		// Check if this class inherits from NSProxy. isKindOfClass crashes, so use raw ObjC api.
+		BOOL	isKindOfNSProxy = NO;
+		id c = class;
+		while (c)
+		{
+			if ([[NSString stringWithUTF8String:class_getName(c)] isEqualToString:@&quot;NSProxy&quot;])	isKindOfNSProxy = YES;
+			c = class_getSuperclass(c);
+		}
+
+		// Skip classes crashing when added to an NSArray
+		if ([className hasPrefix:@&quot;_NSZombie_&quot;] 
+		||	[className isEqualToString:@&quot;Object&quot;]
+		||	[superclassName isEqualToString:@&quot;Object&quot;]
+		||	[className isEqualToString:@&quot;NSMessageBuilder&quot;]
+		||	[className isEqualToString:@&quot;NSLeafProxy&quot;]
+		||	[className isEqualToString:@&quot;__NSGenericDeallocHandler&quot;]
+		||	isKindOfNSProxy
+		)
+		{
+			continue;
+		}
+		
+		[classArray addObject:class];
+	}
+
+	free(classList);
+	return	classArray;
+}
+
++ (NSArray*)rootclasses
+{
+	id classes = [self classes];
+	NSMutableArray* classArray	= [NSMutableArray array];
+	for (id class in classes)
+	{
+		id superclass = class_getSuperclass(class);
+		if (superclass)	continue;
+
+		[classArray addObject:class];
+	}
+	return	classArray;
+}
+
+//
+// Return an array of { name : imageName, classNames : [className, className, ...] }
+//
++ (id)imageNames
+{
+	id array = [NSMutableArray array];
+
+	unsigned int imageCount;
+	const char** imageNames = objc_copyImageNames(&amp;imageCount);
+
+	for (int i=0; i&lt;imageCount; i++)
+	{
+		const char* cname	= imageNames[i];
+
+		// Gather image class names
+		id array2 = [NSMutableArray array];
+		unsigned int classCount;
+		const char** classNames = objc_copyClassNamesForImage(cname, &amp;classCount);
+		for (int j=0; j&lt;classCount; j++)
+			[array2 addObject:[NSString stringWithUTF8String:classNames[j]]];
+
+		free(classNames);
+
+		// Hash of name and classNames
+		id name	= [NSString stringWithUTF8String:cname];
+		id hash = [NSDictionary dictionaryWithObjectsAndKeys:
+			name,		@&quot;name&quot;,
+			array2,		@&quot;classNames&quot;,
+			nil];
+			
+		[array addObject:hash];
+	}
+	free(imageNames);
+	return	array;
+}
+
+//
+// Return protocols and their associated methods
+//
++ (id)protocols
+{
+#if NS_BLOCKS_AVAILABLE
+	id array = [NSMutableArray array];
+	unsigned int protocolCount;
+	Protocol** protocols = objc_copyProtocolList(&amp;protocolCount);
+
+	for (int i=0; i&lt;protocolCount; i++)
+	{
+		// array2 is modified by the following block
+		__block id array2	= [NSMutableArray array];
+		Protocol* p	= protocols[i];
+
+		// Common block for copying protocol method descriptions
+		void (^b)(BOOL, BOOL) = ^(BOOL isRequiredMethod, BOOL isInstanceMethod) {
+			unsigned int descriptionCount;
+			struct objc_method_description* methodDescriptions = protocol_copyMethodDescriptionList(p, isRequiredMethod, isInstanceMethod, &amp;descriptionCount);
+			for (int j=0; j&lt;descriptionCount; j++)
+			{
+				struct objc_method_description d = methodDescriptions[j];
+
+				id name			= NSStringFromSelector(d.name);
+				id encoding		= [NSString stringWithUTF8String:d.types];
+				id isRequired	= [NSNumber numberWithBool:isRequiredMethod];
+				id type			= isInstanceMethod ? @&quot;instance&quot; : @&quot;class&quot;;
+
+				id hash = [NSDictionary dictionaryWithObjectsAndKeys:
+					name,		@&quot;name&quot;,
+					encoding,	@&quot;encoding&quot;,
+					isRequired,	@&quot;isRequired&quot;,
+					type,		@&quot;type&quot;,
+					nil];
+					
+				[array2 addObject:hash];
+			}
+			if (methodDescriptions)	free(methodDescriptions);
+		};
+		
+		// Copy all methods, going through required, non-required, class, instance methods
+		b(YES, YES);
+		b(YES, NO);
+		b(NO, YES);
+		b(NO, NO);
+		
+		// Main object : { name : protocolName, methods : [{ name, encoding, isRequired, type }, ...]
+		id name	= [NSString stringWithUTF8String:protocol_getName(p)];
+		
+		id hash = [NSDictionary dictionaryWithObjectsAndKeys:
+			name,		@&quot;name&quot;,
+			array2,		@&quot;methods&quot;,
+			nil];
+			
+		[array addObject:hash];
+	}
+	free(protocols);
+	return	array;
+#else
+	return	nil;
+#endif
+}
+
++ (id)methods
+{
+	id classes = [self classes];
+	id methods = [NSMutableArray array];
+	for (id class in classes)
+		[methods addObjectsFromArray:[class __ownMethods]];
+	return methods;
+}
+
+//
+// Runtime report
+//	Report EVERYTHING
+//	classes
+//		{ className : { name
+//						superclassName
+//						derivationPath
+//						subclasses
+//						methods
+//						protocols
+//						ivars
+//						properties
+//					  }
+//	protocols
+//		{ protocolName : { name
+//						   methods
+//						 }
+//	imageNames
+//		{ imageName : { name
+//						classNames : [className1, className2, ...]
+//					  }
+//
++ (id)runtimeReport
+{
+/*
+	id classList	= [self classes];
+	id protocols	= [self protocols];
+	id imageNames	= [self imageNames];
+	
+	id classes		= [NSMutableDictionary dictionary];
+	int classCount	= [classList count];
+//	for (id class in classList)
+	for (int i=0; i&lt;classCount; i++)
+	{
+		id class = [classList objectAtIndex:i];
+		id className = [class description];
+
+		id superclass		= [class superclass];
+		id superclassName	= superclass ? [NSString stringWithUTF8String:class_getName(superclass)] : nil;
+//NSLog(@&quot;%@ (%d/%d)&quot;, className, i, classCount-1);
+		id hash = [NSDictionary dictionaryWithObjectsAndKeys:
+			className,					@&quot;name&quot;,
+			superclassName,				@&quot;superclassName&quot;,
+			[class __derivationPath],	@&quot;derivationPath&quot;,
+			[class __methods],			@&quot;methods&quot;,
+			[class __protocols],		@&quot;protocols&quot;,
+			[class __ivars],			@&quot;ivars&quot;,
+			[class __properties],		@&quot;properties&quot;,
+			nil];
+		[classes setObject:hash forKey:className];
+	}
+	
+	id dict = [NSDictionary dictionaryWithObjectsAndKeys:
+				classes,	@&quot;classes&quot;,
+				protocols,	@&quot;protocols&quot;,
+				imageNames,	@&quot;imageNames&quot;,
+				nil];
+	
+	return dict;
+*/
+	return	@&quot;Disabled for now, as the resulting hash hangs the app while goring memory&quot;;
+}
+
+@end
+
+
+//
+// Runtime information
+//
+@implementation NSObject(ClassWalker)
+
+//
+// Returns which framework containing the class
+//
++ (id)__classImage
+{
+	const char* name = class_getImageName(self);
+	if (!name)	return	nil;
+	return	[NSString stringWithUTF8String:name];
+}
+- (id)__classImage
+{	
+	return [[self class] __classImage];
+}
+
+
+//
+// Derivation path
+//	derivationPath(NSButton) = NSObject, NSResponder, NSView, NSControl, NSButton
+//
++ (id)__derivationPath
+{
+	int level = -1;
+	id class = self;
+	id classes = [NSMutableArray array];
+	while (class)
+	{
+		[classes insertObject:class atIndex:0];
+		level++;
+		class = [class superclass];
+	}
+	return	classes;
+}
+- (id)__derivationPath
+{
+	return [[self class] __derivationPath];
+}
+
+//
+// Derivation level
+//
++ (int)__derivationLevel
+{
+	return [[self __derivationPath] count]-1;
+}
+- (int)__derivationLevel
+{
+	return [[self class] __derivationLevel];
+}
+
+//
+// Methods
+//
+
+// Copy all class or instance (type) methods of a class in an array
+static id copyMethods(Class class, NSMutableArray* array, NSString* type)
+{
+	if ([type isEqualToString:@&quot;class&quot;])	class = objc_getMetaClass(class_getName(class));
+
+	unsigned int methodCount;
+	Method* methods = class_copyMethodList(class, &amp;methodCount);
+
+	for (int i=0; i&lt;methodCount; i++)
+	{
+		Method m	= methods[i];
+		Dl_info info;
+		dladdr(method_getImplementation(m), &amp;info);
+
+		id name		= NSStringFromSelector(method_getName(m));
+		id encoding	= [NSString stringWithUTF8String:method_getTypeEncoding(m)];
+		id framework= [NSString stringWithUTF8String:info.dli_fname];
+		
+		id hash = [NSDictionary dictionaryWithObjectsAndKeys:
+			name,		@&quot;name&quot;,
+			encoding,	@&quot;encoding&quot;,
+			type,		@&quot;type&quot;,
+			class,		@&quot;class&quot;,
+			framework, @&quot;framework&quot;,
+			nil];
+			
+		[array addObject:hash];
+	}
+	free(methods);
+	return	array;
+}
++ (id)__ownMethods
+{
+	id methods = [NSMutableArray array];
+	copyMethods([self class], methods, @&quot;class&quot;);
+	copyMethods([self class], methods, @&quot;instance&quot;);
+	return methods;
+}
+- (id)__ownMethods
+{
+	return [[self class] __ownMethods];
+}
++ (id)__methods
+{
+	id classes	= [self __derivationPath];
+	id methods	= [NSMutableArray array];
+	for (id class in classes)
+		[methods addObjectsFromArray:[class __ownMethods]];
+	return	methods;
+}
+- (id)__methods
+{
+	return [[self class] __methods];
+}
+
+
+//
+// Subclasses
+//
+
+// Recursively go breadth first all a class' subclasses
+static void populateSubclasses(Class class, NSMutableArray* array, NSMutableDictionary* subclassesHash)
+{
+	// Add ourselves
+	[array addObject:class];
+	
+	id className	= [NSString stringWithUTF8String:class_getName(class)];
+	id subclasses = [subclassesHash objectForKey:className];
+	for (id subclass in subclasses)
+	{
+		populateSubclasses(subclass, array, subclassesHash);
+	}
+}
+// Build a hash of className : [direct subclasses] then walk it down recursively.
++ (id)__subclasses
+{
+#if NS_BLOCKS_AVAILABLE
+	id classes		= [JSCocoaLib classes];
+	id subclasses	= [NSMutableArray array];
+	id subclassesHash	= [NSMutableDictionary dictionary];
+	
+	for (id class in classes)
+	{
+		id superclass		= [class superclass];
+		if (!superclass)	continue;
+		id superclassName	= [NSString stringWithUTF8String:class_getName(superclass)];
+		
+		id subclassesArray	= [subclassesHash objectForKey:superclassName];
+		if (!subclassesArray)
+		{
+			subclassesArray	= [NSMutableArray array];
+			[subclassesHash setObject:subclassesArray forKey:superclassName];
+		}
+		[subclassesArray addObject:class];
+	}
+	
+	// (Optional) sort by class name
+	for (id className in subclassesHash)
+	{
+		id subclassesArray = [subclassesHash objectForKey:className];
+		[subclassesArray sortUsingComparator:
+			^(id a, id b)	
+			{
+				// Case insensitive compare + remove underscores for sorting (yields [..., NSStatusBarButton, _NSThemeWidget, NSToolbarButton] )
+				return [[[a description] stringByReplacingOccurrencesOfString:@&quot;_&quot; withString:@&quot;&quot;] 
+						compare:[[b description] stringByReplacingOccurrencesOfString:@&quot;_&quot; withString:@&quot;&quot;] options:NSCaseInsensitiveSearch];
+			}];
+	}
+	
+	populateSubclasses(self, subclasses, subclassesHash);
+	return	subclasses;
+#else
+	return	nil;
+#endif
+}
+- (id)__subclasses
+{
+	return [[self class] __subclasses];
+}
+
+// Returns a string showing subclasses, prefixed with as many spaces as their derivation level
++ (id)__subclassTree
+{
+	id subclasses = [self __subclasses];
+	id str = [NSMutableString string];
+	for (id subclass in subclasses)
+	{
+		int level = [subclass __derivationLevel];
+		for (int i=0; i&lt;level; i++)
+			[str appendString:@&quot; &quot;];
+		[str appendString:[NSString stringWithUTF8String:class_getName(subclass)]];
+		[str appendString:@&quot;\n&quot;];
+	}
+	return	str;
+}
+- (id)__subclassTree
+{
+	return [[self class] __subclassTree];
+}
+
+//
+// ivars
+//
++ (id)__ownIvars
+{
+	unsigned int ivarCount;
+	Ivar* ivars = class_copyIvarList(self, &amp;ivarCount);
+	
+	id array = [NSMutableArray array];
+	for (int i=0; i&lt;ivarCount; i++)
+	{
+		Ivar ivar	= ivars[i];
+		
+		id name		= [NSString stringWithUTF8String:ivar_getName(ivar)];
+		id encoding	= [NSString stringWithUTF8String:ivar_getTypeEncoding(ivar)]; 
+		id offset	= [NSNumber numberWithLong:ivar_getOffset(ivar)]; 
+		id hash = [NSDictionary dictionaryWithObjectsAndKeys:
+			name,		@&quot;name&quot;,
+			encoding,	@&quot;encoding&quot;,
+			offset,		@&quot;offset&quot;,
+			self,		@&quot;class&quot;,
+			nil];
+			
+		[array addObject:hash];
+	}
+	
+	free(ivars);
+	return	array;
+}
+- (id)__ownIvars
+{
+	return [[self class] __ownIvars];
+}
++ (id)__ivars
+{
+	id classes	= [self __derivationPath];
+	id ivars	= [NSMutableArray array];
+	for (id class in classes)
+		[ivars addObjectsFromArray:[class __ownIvars]];
+	return	ivars;
+}
+- (id)__ivars
+{
+	return [[self class] __ivars];
+}
+
+//
+// Properties
+//
++ (id)__ownProperties
+{
+	unsigned int propertyCount;
+	objc_property_t* properties = class_copyPropertyList(self, &amp;propertyCount);
+	
+	id array = [NSMutableArray array];
+	for (int i=0; i&lt;propertyCount; i++)
+	{
+		objc_property_t property	= properties[i];
+		
+		id name			= [NSString stringWithUTF8String:property_getName(property)];
+		id attributes	= [NSString stringWithUTF8String:property_getAttributes(property)]; 
+		id hash = [NSDictionary dictionaryWithObjectsAndKeys:
+			name,		@&quot;name&quot;,
+			attributes,	@&quot;attributes&quot;,
+			self,		@&quot;class&quot;,
+			nil];
+		[array addObject:hash];
+	}
+	
+	free(properties);
+	return	array;
+}
+- (id)__ownProperties
+{
+	return [[self class] __ownProperties];
+}
++ (id)__properties
+{
+	id classes		= [self __derivationPath];
+	id properties	= [NSMutableArray array];
+	for (id class in classes)
+		[properties addObjectsFromArray:[class __ownProperties]];
+	return	properties;
+}
+- (id)__properties
+{
+	return [[self class] __properties];
+}
+
+//
+// Protocols
+//
++ (id)__ownProtocols
+{
+	unsigned int protocolCount;
+	Protocol** protocols = class_copyProtocolList(self, &amp;protocolCount);
+	
+	id array = [NSMutableArray array];
+	for (int i=0; i&lt;protocolCount; i++)
+	{
+		id name = [NSString stringWithUTF8String:protocol_getName(protocols[i])];
+		id hash = [NSDictionary dictionaryWithObjectsAndKeys:
+			name,		@&quot;name&quot;,
+			self,		@&quot;class&quot;,
+			nil];
+		[array addObject:hash];
+	}
+	
+	free(protocols);
+	return	array;
+}
+- (id)__ownProtocols
+{
+	return [[self class] __ownProtocols];
+}
+
++ (id)__protocols
+{
+	id classes		= [self __derivationPath];
+	id protocols	= [NSMutableArray array];
+	for (id class in classes)
+		[protocols addObjectsFromArray:[class __ownProtocols]];
+	return	protocols;
+}
+- (id)__protocols
+{
+	return [[self class] __protocols];
+}
+
+@end</diff>
      <filename>jscocoa/JSCocoa/JSCocoaLib.m</filename>
    </modified>
    <modified>
      <diff>@@ -8,9 +8,7 @@
 
 
 #import &lt;Cocoa/Cocoa.h&gt;
-#import &quot;MarkerLineNumberView.h&quot;
 #import &quot;JSTTextView.h&quot;
-#import &quot;TDParseKit.h&quot;
 #import &quot;JSTFileWatcher.h&quot;
 
 @interface JSTDocument : NSDocument {
@@ -19,10 +17,9 @@
     IBOutlet NSSplitView *splitView;
     IBOutlet NSTextField *errorLabel;
     
-	NoodleLineNumberView	*lineNumberView;
-    TDTokenizer *_tokenizer;
-    
-    NSDictionary *_keywords;
+	//NoodleLineNumberView	*lineNumberView;
+    //TDTokenizer *_tokenizer;
+    //NSDictionary *_keywords;
     
     NSMutableDictionary *_toolbarItems;
     
@@ -31,14 +28,12 @@
     NSDictionary *_previousOutputTypingAttributes;
 }
 
-@property (retain) TDTokenizer *tokenizer;
 @property (retain) NSDictionary *keywords;
 @property (retain) JSTFileWatcher *externalEditorFileWatcher;
 @property (retain) NSDictionary *previousOutputTypingAttributes;
 
 
 - (void) executeScript:(id)sender;
-- (void) parseCode:(id)sender;
 - (void) clearConsole:(id)sender;
 
 @end</diff>
      <filename>src/JSTDocument.h</filename>
    </modified>
    <modified>
      <diff>@@ -19,55 +19,23 @@
 
 
 @implementation JSTDocument
-@synthesize tokenizer=_tokenizer;
 @synthesize keywords=_keywords;
 @synthesize externalEditorFileWatcher=_externalEditorFileWatcher;
 @synthesize previousOutputTypingAttributes=_previousOutputTypingAttributes;
 
 - (id)init {
     self = [super init];
+    
     if (self) {
-        self.tokenizer = [[[TDTokenizer alloc] init] autorelease];
-        /*
-var s = &quot;break case catch continue default delete do else finally for function if in instanceof new return switch this throw try typeof var void while with abstract boolean byte char class const debugger double enum export extends final float goto implements import int interface long native package private protected public short static super synchronized throws transient volatile null true false nil&quot;
-
-words = s.split(&quot; &quot;)
-var i = 0;
-list = &quot;&quot;
-while (i &lt; words.length) {
-    list = list + '@&quot;' + words[i] + '&quot;, ';
-    i++
-}
-
-print(&quot;NSArray *blueWords = [NSArray arrayWithObjects:&quot; + list + &quot; nil];&quot;)
-        */
-        
-        NSArray *blueWords = [NSArray arrayWithObjects:@&quot;break&quot;, @&quot;case&quot;, @&quot;catch&quot;, @&quot;continue&quot;, @&quot;default&quot;, @&quot;delete&quot;, @&quot;do&quot;, @&quot;else&quot;, @&quot;finally&quot;, @&quot;for&quot;, @&quot;function&quot;, @&quot;if&quot;, @&quot;in&quot;, @&quot;instanceof&quot;, @&quot;new&quot;, @&quot;return&quot;, @&quot;switch&quot;, @&quot;this&quot;, @&quot;throw&quot;, @&quot;try&quot;, @&quot;typeof&quot;, @&quot;var&quot;, @&quot;void&quot;, @&quot;while&quot;, @&quot;with&quot;, @&quot;abstract&quot;, @&quot;boolean&quot;, @&quot;byte&quot;, @&quot;char&quot;, @&quot;class&quot;, @&quot;const&quot;, @&quot;debugger&quot;, @&quot;double&quot;, @&quot;enum&quot;, @&quot;export&quot;, @&quot;extends&quot;, @&quot;final&quot;, @&quot;float&quot;, @&quot;goto&quot;, @&quot;implements&quot;, @&quot;import&quot;, @&quot;int&quot;, @&quot;interface&quot;, @&quot;long&quot;, @&quot;native&quot;, @&quot;package&quot;, @&quot;private&quot;, @&quot;protected&quot;, @&quot;public&quot;, @&quot;short&quot;, @&quot;static&quot;, @&quot;super&quot;, @&quot;synchronized&quot;, @&quot;throws&quot;, @&quot;transient&quot;, @&quot;volatile&quot;, @&quot;null&quot;, @&quot;true&quot;, @&quot;false&quot;, @&quot;nil&quot;,  nil];
-        
-        NSMutableDictionary *keywords = [NSMutableDictionary dictionary];
-        
-        for (NSString *word in blueWords) {
-            [keywords setObject:[NSColor blueColor] forKey:word];
-        }
-        
-        self.keywords = keywords;
-        
+        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updateFont:) name:@&quot;JSTFontChangeNotification&quot; object:nil];
     }
     
-    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updateFont:) name:@&quot;JSTFontChangeNotification&quot; object:nil];
-    
     return self;
 }
 
 - (void)dealloc {
     [[NSNotificationCenter defaultCenter] removeObserver:self];
     
-    [_tokenizer release];
-    _tokenizer = 0x00;
-    
-    [_keywords release];
-    _keywords = 0x00;
-    
     [_externalEditorFileWatcher release];
     _externalEditorFileWatcher = 0x00;
     
@@ -107,18 +75,6 @@ print(&quot;NSArray *blueWords = [NSArray arrayWithObjects:&quot; + list + &quot; nil];&quot;)
         [self readFromFile:[self fileURL]];
     }
     
-    // FIXME: make this a pref
-    [[jsTextView textStorage] setAttributes:[NSDictionary dictionaryWithObject:[NSFont fontWithName:@&quot;Monaco&quot; size:10] forKey:NSFontAttributeName] range:NSMakeRange(0, [[jsTextView textStorage] length]) ];
-    
-    lineNumberView = [[MarkerLineNumberView alloc] initWithScrollView:[jsTextView enclosingScrollView]];
-    [[jsTextView enclosingScrollView] setVerticalRulerView:lineNumberView];
-    [[jsTextView enclosingScrollView] setHasHorizontalRuler:NO];
-    [[jsTextView enclosingScrollView] setHasVerticalRuler:YES];
-    [[jsTextView enclosingScrollView] setRulersVisible:YES];
-    
-    [[jsTextView textStorage] setDelegate:self];
-    [self parseCode:nil];
-    
     NSToolbar *toolbar  = [[[NSToolbar alloc] initWithIdentifier:@&quot;JSTalkDocument&quot;] autorelease];
     _toolbarItems       = [[NSMutableDictionary dictionary] retain];
     
@@ -280,10 +236,6 @@ print(&quot;NSArray *blueWords = [NSArray arrayWithObjects:&quot; + list + &quot; nil];&quot;)
     
 }
 
-- (void) textStorageDidProcessEditing:(NSNotification *)note {
-    [self parseCode:nil];
-}
-
 - (void) preprocessCodeAction:(id)sender {
     
     NSString *code = [JSTPreprocessor preprocessCode:[[jsTextView textStorage] string]];
@@ -296,55 +248,6 @@ print(&quot;NSArray *blueWords = [NSArray arrayWithObjects:&quot; + list + &quot; nil];&quot;)
 }
 
 
-- (void) parseCode:(id)sender {
-    
-    // we should really do substrings...
-    
-    NSString *sourceString = [[jsTextView textStorage] string];
-    TDTokenizer *tokenizer = [TDTokenizer tokenizerWithString:sourceString];
-    
-    tokenizer.commentState.reportsCommentTokens = YES;
-    tokenizer.whitespaceState.reportsWhitespaceTokens = YES;
-    
-    TDToken *eof = [TDToken EOFToken];
-    TDToken *tok = nil;
-    
-    [[jsTextView textStorage] beginEditing];
-    
-    NSUInteger sourceLoc = 0;
-    
-    while ((tok = [tokenizer nextToken]) != eof) {
-        
-        NSColor *fontColor = [NSColor blackColor];
-    
-        if (tok.quotedString) {
-            fontColor = [NSColor darkGrayColor];
-        }
-        else if (tok.isNumber) {
-            fontColor = [NSColor blueColor];
-        }
-        else if (tok.isComment) {
-            fontColor = [NSColor redColor];
-        }
-        else if (tok.isWord) {
-            NSColor *c = [_keywords objectForKey:[tok stringValue]];
-            fontColor = c ? c : fontColor;
-        }
-            
-        NSUInteger strLen = [[tok stringValue] length];
-        
-        if (fontColor) {
-            [[jsTextView textStorage] addAttribute:NSForegroundColorAttributeName value:fontColor range:NSMakeRange(sourceLoc, strLen)];
-        }
-        
-        sourceLoc += strLen;
-    }
-    
-    
-    [[jsTextView textStorage] endEditing];
-    
-}
-
 - (void)savePanelDidEndForApplicationSave:(NSSavePanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo {
     
     NSString *fileName = [sheet filename];
@@ -445,7 +348,7 @@ print(&quot;NSArray *blueWords = [NSArray arrayWithObjects:&quot; + list + &quot; nil];&quot;)
         return;
     }
     
-    // setup our watcher.
+    // setup our watcher.0
     self.externalEditorFileWatcher = [JSTFileWatcher fileWatcherWithPath:[self fileName] delegate:self];
     
     // and away we go.</diff>
      <filename>src/JSTDocument.m</filename>
    </modified>
    <modified>
      <diff>@@ -7,10 +7,18 @@
 //
 
 #import &lt;Cocoa/Cocoa.h&gt;
+#import &quot;NoodleLineNumberView.h&quot;
 
+@class NoodleLineNumberView;
 
 @interface JSTTextView : NSTextView {
-
+    NoodleLineNumberView	*_lineNumberView;
+    NSDictionary *_keywords;
 }
 
+
+@property (retain) NSDictionary *keywords;
+
+- (void) parseCode:(id)sender;
+
 @end</diff>
      <filename>src/JSTTextView.h</filename>
    </modified>
    <modified>
      <diff>@@ -7,12 +7,161 @@
 //
 
 #import &quot;JSTTextView.h&quot;
+#import &quot;MarkerLineNumberView.h&quot;
+#import &quot;TDParseKit.h&quot;
+
+@interface JSTTextView (Private)
+- (void) setupLineView;
+@end
 
 
 @implementation JSTTextView
 
-- (void)awakeFromNib {
-	[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textViewDidChangeSelection:) name:NSTextViewDidChangeSelectionNotification object:self];
+@synthesize keywords=_keywords;
+
+
+- (id)initWithFrame:(NSRect)frameRect textContainer:(NSTextContainer *)container {
+    
+	self = [super initWithFrame:frameRect textContainer:container];
+    
+	if (self != nil) {
+        [self performSelector:@selector(setupLineViewAndStuff) withObject:nil afterDelay:0];
+    }
+    
+    return self;
+}
+
+- (id) initWithCoder:(NSCoder *)aDecoder {
+    
+    self = [super initWithCoder:aDecoder];
+	if (self != nil) {
+        // what's the right way to do this?
+        [self performSelector:@selector(setupLineViewAndStuff) withObject:nil afterDelay:0];
+    }
+    
+    return self;
+}
+
+- (void)dealloc {
+    [[NSNotificationCenter defaultCenter] removeObserver:self];
+    
+    [_lineNumberView release];
+    
+    [super dealloc];
+}
+
+
+- (void) setupLineViewAndStuff {
+    
+    _lineNumberView = [[MarkerLineNumberView alloc] initWithScrollView:[self enclosingScrollView]];
+    [[self enclosingScrollView] setVerticalRulerView:_lineNumberView];
+    [[self enclosingScrollView] setHasHorizontalRuler:NO];
+    [[self enclosingScrollView] setHasVerticalRuler:YES];
+    [[self enclosingScrollView] setRulersVisible:YES];
+    
+    [[self textStorage] setDelegate:self];
+    
+    /*
+     var s = &quot;break case catch continue default delete do else finally for function if in instanceof new return switch this throw try typeof var void while with abstract boolean byte char class const debugger double enum export extends final float goto implements import int interface long native package private protected public short static super synchronized throws transient volatile null true false nil&quot;
+     
+     words = s.split(&quot; &quot;)
+     var i = 0;
+     list = &quot;&quot;
+     while (i &lt; words.length) {
+     list = list + '@&quot;' + words[i] + '&quot;, ';
+     i++
+     }
+     
+     print(&quot;NSArray *blueWords = [NSArray arrayWithObjects:&quot; + list + &quot; nil];&quot;)
+     */
+    
+    NSArray *blueWords = [NSArray arrayWithObjects:@&quot;break&quot;, @&quot;case&quot;, @&quot;catch&quot;, @&quot;continue&quot;, @&quot;default&quot;, @&quot;delete&quot;, @&quot;do&quot;, @&quot;else&quot;, @&quot;finally&quot;, @&quot;for&quot;, @&quot;function&quot;, @&quot;if&quot;, @&quot;in&quot;, @&quot;instanceof&quot;, @&quot;new&quot;, @&quot;return&quot;, @&quot;switch&quot;, @&quot;this&quot;, @&quot;throw&quot;, @&quot;try&quot;, @&quot;typeof&quot;, @&quot;var&quot;, @&quot;void&quot;, @&quot;while&quot;, @&quot;with&quot;, @&quot;abstract&quot;, @&quot;boolean&quot;, @&quot;byte&quot;, @&quot;char&quot;, @&quot;class&quot;, @&quot;const&quot;, @&quot;debugger&quot;, @&quot;double&quot;, @&quot;enum&quot;, @&quot;export&quot;, @&quot;extends&quot;, @&quot;final&quot;, @&quot;float&quot;, @&quot;goto&quot;, @&quot;implements&quot;, @&quot;import&quot;, @&quot;int&quot;, @&quot;interface&quot;, @&quot;long&quot;, @&quot;native&quot;, @&quot;package&quot;, @&quot;private&quot;, @&quot;protected&quot;, @&quot;public&quot;, @&quot;short&quot;, @&quot;static&quot;, @&quot;super&quot;, @&quot;synchronized&quot;, @&quot;throws&quot;, @&quot;transient&quot;, @&quot;volatile&quot;, @&quot;null&quot;, @&quot;true&quot;, @&quot;false&quot;, @&quot;nil&quot;,  nil];
+    
+    NSMutableDictionary *keywords = [NSMutableDictionary dictionary];
+    
+    for (NSString *word in blueWords) {
+        [keywords setObject:[NSColor blueColor] forKey:word];
+    }
+    
+    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textViewDidChangeSelection:) name:NSTextViewDidChangeSelectionNotification object:self];
+
+    
+    self.keywords = keywords;
+    
+    
+    [self parseCode:nil];
+    
+}
+
+
+
+
+
+
+- (void) parseCode:(id)sender {
+    
+    // we should really do substrings...
+    
+    NSString *sourceString = [[self textStorage] string];
+    TDTokenizer *tokenizer = [TDTokenizer tokenizerWithString:sourceString];
+    
+    tokenizer.commentState.reportsCommentTokens = YES;
+    tokenizer.whitespaceState.reportsWhitespaceTokens = YES;
+    
+    TDToken *eof = [TDToken EOFToken];
+    TDToken *tok = nil;
+    
+    [[self textStorage] beginEditing];
+    
+    NSUInteger sourceLoc = 0;
+    
+    while ((tok = [tokenizer nextToken]) != eof) {
+        
+        NSColor *fontColor = [NSColor blackColor];
+        
+        if (tok.quotedString) {
+            fontColor = [NSColor darkGrayColor];
+        }
+        else if (tok.isNumber) {
+            fontColor = [NSColor blueColor];
+        }
+        else if (tok.isComment) {
+            fontColor = [NSColor redColor];
+        }
+        else if (tok.isWord) {
+            NSColor *c = [_keywords objectForKey:[tok stringValue]];
+            fontColor = c ? c : fontColor;
+        }
+        
+        NSUInteger strLen = [[tok stringValue] length];
+        
+        if (fontColor) {
+            [[self textStorage] addAttribute:NSForegroundColorAttributeName value:fontColor range:NSMakeRange(sourceLoc, strLen)];
+        }
+        
+        sourceLoc += strLen;
+    }
+    
+    
+    [[self textStorage] endEditing];
+    
+}
+
+
+
+- (void) textStorageDidProcessEditing:(NSNotification *)note {
+    [self parseCode:nil];
+}
+
+
+
+
+
+
+
+
+- (NSArray *) writablePasteboardTypes {
+    return [[super writablePasteboardTypes] arrayByAddingObject:NSRTFPboardType];
 }
 
 - (void) insertTab:(id)sender {</diff>
      <filename>src/JSTTextView.m</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>c62d72f8147f27fbe523a4328d722344c8b67d3f</id>
    </parent>
  </parents>
  <author>
    <name>August Mueller</name>
    <email>gus@fmnorth.local</email>
  </author>
  <url>http://github.com/ccgus/jstalk/commit/b65e79367257dcac4d904984aac2785db8386a56</url>
  <id>b65e79367257dcac4d904984aac2785db8386a56</id>
  <committed-date>2009-10-14T14:02:41-07:00</committed-date>
  <authored-date>2009-10-14T14:02:41-07:00</authored-date>
  <message>moven' and grooven!</message>
  <tree>acc988b161e448afede8ac99443ba8204df2df20</tree>
  <committer>
    <name>August Mueller</name>
    <email>gus@fmnorth.local</email>
  </committer>
</commit>
