Index: /trunk/Cocoa/Pester/Source/English.lproj/Alarms.nib/classes.nib
===================================================================
--- /trunk/Cocoa/Pester/Source/English.lproj/Alarms.nib/classes.nib	(revision 50)
+++ /trunk/Cocoa/Pester/Source/English.lproj/Alarms.nib/classes.nib	(revision 51)
@@ -3,4 +3,17 @@
         {CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, 
         {CLASS = NJRScrollView; LANGUAGE = ObjC; SUPERCLASS = NSScrollView; }, 
+        {
+            CLASS = NJRTableDelegate; 
+            LANGUAGE = ObjC; 
+            OUTLETS = {tableView = NSTableView; }; 
+            SUPERCLASS = NSObject; 
+        }, 
+        {
+            CLASS = NJRTableView; 
+            LANGUAGE = ObjC; 
+            OUTLETS = {typeSelectDisplay = id; }; 
+            SUPERCLASS = NSTableView; 
+        }, 
+        {CLASS = NSObject; LANGUAGE = ObjC; }, 
         {
             ACTIONS = {remove = id; }; 
Index: /trunk/Cocoa/Pester/Source/English.lproj/Alarms.nib/info.nib
===================================================================
--- /trunk/Cocoa/Pester/Source/English.lproj/Alarms.nib/info.nib	(revision 50)
+++ /trunk/Cocoa/Pester/Source/English.lproj/Alarms.nib/info.nib	(revision 51)
@@ -1,10 +1,10 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
+<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">
+<plist version="0.9">
 <dict>
 	<key>IBDocumentLocation</key>
-	<string>579 27 356 240 0 0 1600 1178 </string>
+	<string>322 50 356 240 0 0 1280 832 </string>
 	<key>IBFramework Version</key>
-	<string>286.0</string>
+	<string>263.2</string>
 	<key>IBOpenObjects</key>
 	<array>
@@ -12,5 +12,5 @@
 	</array>
 	<key>IBSystem Version</key>
-	<string>6D52</string>
+	<string>5S66</string>
 </dict>
 </plist>
Index: /trunk/Cocoa/Pester/Source/NJRTableDelegate.h
===================================================================
--- /trunk/Cocoa/Pester/Source/NJRTableDelegate.h	(revision 50)
+++ /trunk/Cocoa/Pester/Source/NJRTableDelegate.h	(revision 51)
@@ -4,18 +4,24 @@
 //
 //  Created by Nicholas Riley on Sun Oct 27 2002.
-//  Copyright (c) 2002 __MyCompanyName__. All rights reserved.
+//  Copyright (c) 2002 Nicholas Riley. All rights reserved.
 //
 
 #import <AppKit/AppKit.h>
+#import "NJRTableView.h"
 
 
 @interface NJRTableDelegate : NSObject {
-    IBOutlet NSTableView *tableView;
+    IBOutlet NJRTableView *tableView;
     NSTableColumn *sortingColumn;
     NSString *sortingKey;
     BOOL sortDescending;
 
-    id oData; // XXX ???
+    NSMutableArray *reorderedData;
 }
 
+- (NSMutableArray *)reorderedDataForData:(NSArray *)data;
+
+- (NSSet *)selectedItems;
+- (void)selectItems:(NSSet *)inSelectedItems;
+
 @end
Index: /trunk/Cocoa/Pester/Source/NJRTableDelegate.m
===================================================================
--- /trunk/Cocoa/Pester/Source/NJRTableDelegate.m	(revision 50)
+++ /trunk/Cocoa/Pester/Source/NJRTableDelegate.m	(revision 51)
@@ -4,5 +4,5 @@
 //
 //  Created by Nicholas Riley on Sun Oct 27 2002.
-//  Copyright (c) 2002 __MyCompanyName__. All rights reserved.
+//  Copyright (c) 2002 Nicholas Riley. All rights reserved.
 //
 
@@ -14,5 +14,5 @@
 typedef struct { NSString *key; BOOL descending; } SortContext;
 
-// Sort array of itemNums, by looking up the itemNum in the dictionary of dictionaries.
+// Sort array of itemNums, by looking up the itemNum in the dictionary of objects.
 // based on code of Ondra Cada <ocs@ocs.cz> on cocoa-dev list
 
@@ -25,9 +25,9 @@
 
         if (context->descending) {
-            first  = [right objectForKey: key];
-            second = [left  objectForKey: key];
+            first  = [right valueForKey: key];
+            second = [left  valueForKey: key];
         } else {
-            first  = [left  objectForKey: key];
-            second = [right objectForKey: key];
+            first  = [left  valueForKey: key];
+            second = [right valueForKey: key];
         }
 
@@ -41,12 +41,26 @@
 }
 
+@interface NJRTableDelegate (Private)
+
+- (void)_positionTypeSelectDisplay;
+- (void)_sortByColumn:(NSTableColumn *)inTableColumn;
+
+@end
+
 @implementation NJRTableDelegate
 
 #pragma mark initialize-release
 
+- (void)awakeFromNib;
+{
+    [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(_positionTypeSelectDisplay) name: NSViewFrameDidChangeNotification object: tableView];
+}
+
 - (void)dealloc
 {
+    [[NSNotificationCenter defaultCenter] removeObserver: self];
     [sortingColumn release];
     [sortingKey release];
+    [reorderedData release];
     [super dealloc];
 }
@@ -68,4 +82,112 @@
 }
 
+#pragma mark sorting
+
+- (NSString *)_sortContextDefaultKey;
+{
+    NSString *autosaveName = [tableView autosaveName];
+    if (autosaveName != nil)
+        return [NSString stringWithFormat: @"NJRTableDelegate SortContext %@", autosaveName];
+    else
+        return nil;
+}
+
+- (void)_sortData;
+{
+    SortContext ctxt = { sortingKey, sortDescending };
+    NSString *sortContextKey = [self _sortContextDefaultKey];
+
+    if (sortContextKey != nil) {
+        [[NSUserDefaults standardUserDefaults] setObject:
+            [NSDictionary dictionaryWithObjectsAndKeys: sortingKey, @"sortingKey", [NSNumber numberWithBool: sortDescending], @"sortDescending", nil]
+                                                    forKey: [self _sortContextDefaultKey]];
+    }
+    
+    // sort the NSMutableArray
+    [reorderedData sortUsingFunction: ORDER_BY_CONTEXT context: &ctxt];
+    [tableView reloadData];
+}
+
+- (void)_sortByColumn:(NSTableColumn *)inTableColumn;
+{
+    NSSet *oldSelection = [self selectedItems];
+    if (sortingColumn == inTableColumn) {
+        // User clicked same column, change sort order
+        sortDescending = !sortDescending;
+        // Possible optimization: Don't actually re-sort if you just change the sorting direction; instead, just display either the nth item or the (count-1-n)th item depending on ascending/descending.)
+    } else {
+        // User clicked new column, change old/new column headers, save new sorting column, and re-sort the array.
+        if (sortingColumn != nil) {
+            [tableView setIndicatorImage: nil inTableColumn: sortingColumn];
+            sortDescending = NO; // on initial sort, preserve previous sort order
+        }
+        [self setSortingKey: [inTableColumn identifier]];
+        [self setSortingColumn: inTableColumn];
+        [tableView setHighlightedTableColumn: inTableColumn];
+    }
+    [tableView setIndicatorImage: (sortDescending ? [NSTableView descendingSortIndicator] : [NSTableView ascendingSortIndicator]) inTableColumn: inTableColumn];
+    [self _positionTypeSelectDisplay];
+    // Actually sort the data
+    [self _sortData];
+    [self selectItems: oldSelection];
+}
+
+- (void)_initialSortData;
+{
+    NSString *sortContextKey = [self _sortContextDefaultKey];
+    NSDictionary *sortContext;
+    NSString *key;
+    NSTableColumn *column;
+
+    if (sortContextKey == nil) goto noContext;
+    if ( (sortContext = [[NSUserDefaults standardUserDefaults] dictionaryForKey: sortContextKey]) == nil) goto noContext;
+    if ( (key = [sortContext objectForKey: @"sortingKey"]) == nil) goto noContext;
+    if ( (column = [tableView tableColumnWithIdentifier: key]) == nil) goto noContext;
+    sortDescending = [[sortContext objectForKey: @"sortDescending"] boolValue];
+    [self _sortByColumn: column];
+    return;
+    
+noContext:
+    sortDescending = NO;
+    [self _sortByColumn: [[tableView tableColumns] objectAtIndex: 0]];
+}
+
+- (NSMutableArray *)reorderedDataForData:(NSArray *)data;
+{
+    if (reorderedData == nil) {
+        reorderedData = [data mutableCopy];
+        [self _initialSortData];
+    } else {
+        NSSet *oldSelection = [self selectedItems];
+        [reorderedData release]; reorderedData = nil;
+        reorderedData = [data mutableCopy];
+        [self _sortData];
+        [self selectItems: oldSelection];
+    }
+    return reorderedData;
+}
+
+#pragma mark type selection
+
+- (void)_positionTypeSelectDisplay;
+{
+    [tableView resetTypeSelect]; // avoid extraneous matching
+    if ([tableView typeSelectDisplay] != nil && sortingColumn != nil) {
+        NSControl *typeSelectControl = [tableView typeSelectDisplay];
+        if ([typeSelectControl isKindOfClass: [NSControl class]]) {
+            NSView *superview = [typeSelectControl superview];
+            NSRect columnRect = [superview convertRect: [tableView rectOfColumn: [tableView columnWithIdentifier: sortingKey]] fromView: tableView];
+            // XXX support horizontal scroll bar/clipping (not for Pester, but eventually)
+            NSRect tableScrollFrame = [[tableView enclosingScrollView] frame];
+            NSRect selectFrame = [typeSelectControl frame];
+            [superview setNeedsDisplayInRect: selectFrame]; // fix artifacts caused by moving view
+            selectFrame.origin.x = columnRect.origin.x;
+            selectFrame.size.width = columnRect.size.width;
+            [typeSelectControl setAlignment: [[sortingColumn dataCell] alignment]];
+            [typeSelectControl setFrame: selectFrame];
+        }
+    }
+}
+
 #pragma mark saving/restoring selection
 
@@ -77,5 +199,5 @@
 
     while ( (rowNum = [e nextObject]) != nil) {
-        id item = [oData objectAtIndex: [rowNum intValue]];
+        id item = [reorderedData objectAtIndex: [rowNum intValue]];
         [result addObject: item];
     }
@@ -92,5 +214,5 @@
 
     while ( (item = [e nextObject]) != nil ) {
-        int row = [oData indexOfObjectIdenticalTo: item];
+        int row = [reorderedData indexOfObjectIdenticalTo: item];
         if (row != NSNotFound) {
             [tableView selectRow: row byExtendingSelection: YES];
@@ -101,75 +223,49 @@
 }
 
-// ----------------------------------------------------------------------------------------
-// Sorting
-// ----------------------------------------------------------------------------------------
-
-- (void)sortData
-{
-    SortContext ctxt = { sortingKey, sortDescending };
-    NSSet *oldSelection = [self selectedItems];
-
-    // sort the NSMutableArray
-    [oData sortUsingFunction: ORDER_BY_CONTEXT context: &ctxt];
-
-    [tableView reloadData];
-    [self selectItems: oldSelection];
-}
-
-- (void)sortByColumn:(NSTableColumn *)inTableColumn;
-{
-    if (sortingColumn == inTableColumn) {
-        // User clicked same column, change sort order
-        sortDescending = !sortDescending;
-        // Possible optimization: Don't actually re-sort if you just change the sorting direction;
-        // instead, just display either the nth item or the (count-1-n)th item depending on ascending/descending.)
+@end
+
+@implementation NJRTableDelegate (NJRTableViewDelegate)
+
+- (void)tableView:(NSTableView *)aTableView didClickTableColumn:(NSTableColumn *)inTableColumn
+{
+    [[tableView window] makeFirstResponder: aTableView];
+    [self _sortByColumn: inTableColumn];
+}
+
+- (void)tableViewColumnDidResize:(NSNotification *)notification;
+{
+    [self _positionTypeSelectDisplay];
+}
+
+- (void)tableViewColumnDidMove:(NSNotification *)notification;
+{
+    [self _positionTypeSelectDisplay];
+}
+
+- (void)tableView:(NSTableView *)aTableView selectRowMatchingString:(NSString *)matchString;
+{
+    // Look for a highlighted column, presuming we are sorted by that column, and search its values.
+    NSTableColumn *col = [aTableView highlightedTableColumn];
+    id dataSource = [aTableView dataSource];
+    int i, rowCount = [reorderedData count];
+    if (nil == col) return;
+    if (sortDescending) {
+        for ( i = rowCount - 1 ; i >= 0 ; i-- ) {
+            NSComparisonResult order = [matchString caseInsensitiveCompare:
+                [dataSource tableView: aTableView objectValueForTableColumn: col row: i]];
+            if (order != NSOrderedDescending) break;
+        }
+        if (i < 0) i = 0;
     } else {
-        // User clicked new column, change old/new column headers,
-        // save new sorting column, and re-sort the array.
-        sortDescending = NO;
-        if (nil != sortingColumn) {
-            [tableView setIndicatorImage: nil inTableColumn: sortingColumn];
-        }
-        [self setSortingKey: [inTableColumn identifier]];
-        [self setSortingColumn: inTableColumn];
-        [tableView setHighlightedTableColumn: inTableColumn];
-    }
-    [tableView setIndicatorImage: (sortDescending ? [NSTableView descendingSortIndicator] : [NSTableView ascendingSortIndicator]) inTableColumn: inTableColumn];
-    // Actually sort the data
-    [self sortData];
-}
-
-//	Sort by whatever column was clicked upon
-- (void)tableView:(NSTableView*)aTableView didClickTableColumn:(NSTableColumn *)inTableColumn
-{
-    [[tableView window] makeFirstResponder: aTableView]; // help make this tableView be first responder
-    [self sortByColumn:inTableColumn];
-}
-
-// ----------------------------------------------------------------------------------------
-// Alphabetic Type Ahead
-// ----------------------------------------------------------------------------------------
-
-- (void) typeAheadString:(NSString *)inString;
-{
-    // This general sample looks for a highlighted column, presuming that is that column we are sorted by, and uses that as the lookup key.
-    NSTableColumn *col = [tableView highlightedTableColumn];
-    if (nil != col) {
-        NSString *key = [col identifier];
-        int i;
-        for ( i = 0 ; i < [oData count] ; i++ ) {
-            NSDictionary *rowDict = [oData objectAtIndex:i];
-            NSString *compareTo = [rowDict objectForKey:key];
-            NSComparisonResult order = [inString caseInsensitiveCompare:compareTo];
+        for ( i = 0 ; i < rowCount ; i++ ) {
+            NSComparisonResult order = [matchString caseInsensitiveCompare:
+                [dataSource tableView: aTableView objectValueForTableColumn: col row: i]];
             if (order != NSOrderedDescending) break;
         }
-        // Make sure we're not overflowing the row count.
-        if (i >= [oData count]) {
-            i = [oData count] - 1;
-        }
-        // Now select row i -- either the one we found, or the last row if not found.
-        [tableView selectRow:i byExtendingSelection:NO];
-        [tableView scrollRowToVisible:i];
-    }
+        if (i >= rowCount) i = rowCount - 1;
+    }
+    // Now select row i -- either the one we found, or the first/last row if not found.
+    [aTableView selectRow: i byExtendingSelection: NO];
+    [aTableView scrollRowToVisible: i];
 }
 
Index: /trunk/Cocoa/Pester/Source/NJRTableView.h
===================================================================
--- /trunk/Cocoa/Pester/Source/NJRTableView.h	(revision 51)
+++ /trunk/Cocoa/Pester/Source/NJRTableView.h	(revision 51)
@@ -0,0 +1,32 @@
+//
+//  NJRTableView.h
+//  Pester
+//
+//  Created by Nicholas Riley on Sun Nov 17 2002.
+//  Copyright (c) 2002 Nicholas Riley. All rights reserved.
+//
+
+#import <AppKit/AppKit.h>
+
+
+@interface NJRTableView : NSTableView {
+    NSMutableString *typed;
+    IBOutlet id typeSelectDisplay;
+}
+
+- (id)typeSelectDisplay;
+- (void)resetTypeSelect;
+
+@end
+
+@interface NSObject (NJRTableViewDelegate)
+
+- (void)tableView:(NSTableView *)aTableView selectRowMatchingString:(NSString *)matchString;
+
+@end
+
+@interface NSObject (NJRTableViewDataSource)
+
+- (void)removeSelectedRowsFromTableView:(NSTableView *)tableView;
+
+@end
Index: /trunk/Cocoa/Pester/Source/NJRTableView.m
===================================================================
--- /trunk/Cocoa/Pester/Source/NJRTableView.m	(revision 51)
+++ /trunk/Cocoa/Pester/Source/NJRTableView.m	(revision 51)
@@ -0,0 +1,146 @@
+//
+//  NJRTableView.m
+//  Pester
+//
+//  Created by Nicholas Riley on Sun Nov 17 2002.
+//  Copyright (c) 2002 Nicholas Riley. All rights reserved.
+//
+
+#import "NJRTableView.h"
+#import "NSTableView-NJRExtensions.h"
+#import "NSCharacterSet-NJRExtensions.h"
+
+/* only defined in 10.2, but we want to be able to compile without warnings on 10.1.x */
+@interface NSColor (JaguarExtras)
++ (NSColor *)alternateSelectedControlColor;
+@end
+
+@implementation NJRTableView
+
+- (id)typeSelectDisplay;
+{
+    return typeSelectDisplay;
+}
+
+- (void)moveToEndOfDocument:(id)sender {
+    [self scrollRowToVisible: [self numberOfRows] - 1];
+}
+
+- (void)moveToBeginningOfDocument:(id)sender {
+    [self scrollRowToVisible: 0];
+}
+
+- (void)keyDown:(NSEvent *)theEvent;
+{
+    NSString *characters;
+    unichar firstCharacter;
+    characters = [theEvent characters];
+    firstCharacter = [characters characterAtIndex: 0];
+    switch (firstCharacter) {
+        case 0177: // delete key
+        case NSDeleteFunctionKey:
+        case NSDeleteCharFunctionKey:
+            if ([self selectedRow] >= 0 && [[self dataSource] respondsToSelector: @selector(removeSelectedRowsFromTableView:)]) {
+                [[self dataSource] removeSelectedRowsFromTableView: self];
+            }
+            return;
+        case NSHomeFunctionKey:
+            [self moveToBeginningOfDocument: nil];
+            return;
+        case NSEndFunctionKey:
+            [self moveToEndOfDocument: nil];
+            return;
+    }
+    if ([[NSCharacterSet typeSelectSet] characterIsMember: firstCharacter]) {
+        // invoking -[NSResponder interpretKeyEvents:] will cause insertText: to be invoked, and allows function keys to still work.
+        [self interpretKeyEvents: [NSArray arrayWithObject: theEvent]];
+    } else {
+        [super keyDown: theEvent];
+    }
+}
+
+- (void)insertText:(id)inString;
+{
+    if (![[self delegate] respondsToSelector:@selector(selectString:inTableView:)]) {
+        // For consistency with List Manager as documented, reset the typeahead buffer after twice the delay until key repeat (in ticks).
+        NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
+        int keyRepeatTicks = [defaults integerForKey: @"InitialKeyRepeat"];
+        NSTimeInterval resetDelay;
+
+        if (keyRepeatTicks == 0) keyRepeatTicks = 35; // default may be missing; if so, set default
+
+        resetDelay = MIN(2.0 / 60.0 * keyRepeatTicks, 2.0);
+
+        if (typed == nil) typed = [[NSMutableString alloc] init];
+        [typed appendString: inString];
+
+        // Cancel any previously queued future invocations of _resetTypeSelect
+        [NSObject cancelPreviousPerformRequestsWithTarget: self selector: @selector(_resetTypeSelect) object: nil];
+
+        // queue an invocation of clearAccumulatingTypeahead for the near future.
+        [self performSelector: @selector(_resetTypeSelect) withObject: nil afterDelay: resetDelay];
+
+        // Use stringWithString to make an autoreleased copy, since we may clear out the original string below before it can be used.
+        [[self delegate] tableView: self selectRowMatchingString: [NSString stringWithString: typed]];
+
+        // Show the current typeahead string in the optional display field, like CodeWarrior does (well, not really, CW is much more elegant because it doesn't select anything until you stop typing)
+        [typeSelectDisplay setObjectValue: typed];
+    }
+}
+
+- (void)_resetTypeSelect;
+{
+    [typed setString: @""];
+    [typeSelectDisplay setObjectValue: nil];
+}
+
+- (void)resetTypeSelect;
+{
+    [NSObject cancelPreviousPerformRequestsWithTarget: self selector: @selector(_resetTypeSelect) object: nil];
+    [self _resetTypeSelect];
+}
+
+#pragma mark row coloring
+
+- (void)drawGridInClipRect:(NSRect)rect;
+{
+    NSRange columnRange = [self columnsInRect: rect];
+    int i;
+    // match iTunesÕ grid color
+    [[[NSColor gridColor] blendedColorWithFraction: 0.70 ofColor: [NSColor whiteColor]] set];
+    for (i = columnRange.location ; i < NSMaxRange(columnRange) ; i++) {
+        NSRect colRect = [self rectOfColumn:i];
+        int rightEdge = (int) 0.5 + colRect.origin.x + colRect.size.width;
+        [NSBezierPath strokeLineFromPoint: NSMakePoint(-0.5 + rightEdge, -0.5 + rect.origin.y)
+                                  toPoint: NSMakePoint(-0.5 + rightEdge, -0.5 + rect.origin.y + rect.size.height)];
+    }
+}
+
+- (void)highlightSelectionInClipRect:(NSRect)clipRect;
+{
+    NSColor *evenColor, *oddColor = [self backgroundColor];
+    float cellHeight = [self cellHeight];
+    NSRect visibleRect = [self visibleRect];
+    NSRect highlightRect;
+    
+    if ([NSColor respondsToSelector: @selector(alternateSelectedControlColor)])
+        evenColor = [[NSColor alternateSelectedControlColor] highlightWithLevel:0.90];
+    else // match iTunesÕ row background color
+        evenColor = [NSColor colorWithCalibratedRed: 0.929 green: 0.953 blue: 0.996 alpha:1.0];
+
+    highlightRect.origin = NSMakePoint(NSMinX(visibleRect), (int)(NSMinY(clipRect) / cellHeight) * cellHeight);
+    highlightRect.size = NSMakeSize(NSWidth(visibleRect), cellHeight);
+
+    while (NSMinY(highlightRect) < NSMaxY(clipRect)) {
+        NSRect clippedHighlightRect = NSIntersectionRect(highlightRect, clipRect);
+        int row = (int)((NSMinY(highlightRect) + cellHeight / 2.0) / cellHeight);
+        NSColor *rowColor = (row % 2 == 0) ? evenColor : oddColor;
+        [rowColor set];
+        NSRectFill(clippedHighlightRect);
+        highlightRect.origin.y += cellHeight;
+    }
+
+    [super highlightSelectionInClipRect: clipRect];
+}
+
+@end
Index: /trunk/Cocoa/Pester/Source/NSCharacterSet-NJRExtensions.h
===================================================================
--- /trunk/Cocoa/Pester/Source/NSCharacterSet-NJRExtensions.h	(revision 51)
+++ /trunk/Cocoa/Pester/Source/NSCharacterSet-NJRExtensions.h	(revision 51)
@@ -0,0 +1,16 @@
+//
+//  NSCharacterSet-NJRExtensions.h
+//  Pester
+//
+//  Created by Nicholas Riley on Sun Nov 17 2002.
+//  Copyright (c) 2002 __MyCompanyName__. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+
+@interface NSCharacterSet (NJRExtensions)
+
++ (NSCharacterSet *)typeSelectSet;
+
+@end
Index: /trunk/Cocoa/Pester/Source/NSCharacterSet-NJRExtensions.m
===================================================================
--- /trunk/Cocoa/Pester/Source/NSCharacterSet-NJRExtensions.m	(revision 51)
+++ /trunk/Cocoa/Pester/Source/NSCharacterSet-NJRExtensions.m	(revision 51)
@@ -0,0 +1,28 @@
+//
+//  NSCharacterSet-NJRExtensions.m
+//  Pester
+//
+//  Created by Nicholas Riley on Sun Nov 17 2002.
+//  Copyright (c) 2002 __MyCompanyName__. All rights reserved.
+//
+
+#import "NSCharacterSet-NJRExtensions.h"
+
+
+@implementation NSCharacterSet (NJRExtensions)
+
+static NSCharacterSet *_typeSelectSet = nil;
+
++ (NSCharacterSet *)typeSelectSet {
+    if (_typeSelectSet == nil) {
+        NSMutableCharacterSet *set;
+        set = [[NSCharacterSet alphanumericCharacterSet] mutableCopy];
+        [set formUnionWithCharacterSet: [NSCharacterSet punctuationCharacterSet]];
+        [set formUnionWithCharacterSet: [NSCharacterSet whitespaceCharacterSet]];
+        _typeSelectSet = [set copy]; // make immutable again - for efficiency
+        [set release];
+    }
+    return _typeSelectSet;
+}
+
+@end
Index: /trunk/Cocoa/Pester/Source/NSTableView-NJRExtensions.h
===================================================================
--- /trunk/Cocoa/Pester/Source/NSTableView-NJRExtensions.h	(revision 50)
+++ /trunk/Cocoa/Pester/Source/NSTableView-NJRExtensions.h	(revision 51)
@@ -17,5 +17,3 @@
 - (float)cellHeight;
 
-- (NSArray *)selectedRowIndices;
-
 @end
Index: /trunk/Cocoa/Pester/Source/NSTableView-NJRExtensions.m
===================================================================
--- /trunk/Cocoa/Pester/Source/NSTableView-NJRExtensions.m	(revision 50)
+++ /trunk/Cocoa/Pester/Source/NSTableView-NJRExtensions.m	(revision 51)
@@ -28,20 +28,8 @@
 + (NSImage *)descendingSortIndicator;
 {
-    NSImage *result = [NSImage imageNamed:@"NSDescendingSortIndicator"];
-    if (result == nil && [[NSTableView class] respondsToSelector:@selector(_defaultTableHeaderReverseSortImage)])
+    NSImage *result = [NSImage imageNamed: @"NSDescendingSortIndicator"];
+    if (result == nil && [[NSTableView class] respondsToSelector: @selector(_defaultTableHeaderReverseSortImage)])
         result = [NSTableView _defaultTableHeaderReverseSortImage];
     return result;
-}
-
-- (NSArray *)selectedRowIndices;
-{
-    NSEnumerator *theEnum = [self selectedRowEnumerator];
-    NSNumber *rowNumber;
-    NSMutableArray *rowNumberArray = [NSMutableArray arrayWithCapacity: [self numberOfSelectedRows]];
-
-    while (nil != (rowNumber = [theEnum nextObject]) )
-        [rowNumberArray addObject: rowNumber];
-
-    return rowNumberArray;
 }
 
Index: /trunk/Cocoa/Pester/Source/PSAlarm.h
===================================================================
--- /trunk/Cocoa/Pester/Source/PSAlarm.h	(revision 50)
+++ /trunk/Cocoa/Pester/Source/PSAlarm.h	(revision 51)
@@ -38,4 +38,5 @@
 
 - (NSCalendarDate *)date;
+- (NSCalendarDate *)time;
 - (NSTimeInterval)interval;
 - (NSString *)message;
@@ -50,8 +51,9 @@
 - (NSString *)invalidMessage;
 
-- (NSComparisonResult)compare:(PSAlarm *)otherAlarm;
+- (NSComparisonResult)compareDate:(PSAlarm *)otherAlarm;
+- (NSComparisonResult)compareMessage:(PSAlarm *)otherAlarm;
 
 - (BOOL)setTimer;
-- (void)cancel;
+- (void)cancelTimer;
 
 @end
Index: /trunk/Cocoa/Pester/Source/PSAlarm.m
===================================================================
--- /trunk/Cocoa/Pester/Source/PSAlarm.m	(revision 50)
+++ /trunk/Cocoa/Pester/Source/PSAlarm.m	(revision 51)
@@ -20,4 +20,6 @@
 
 @implementation PSAlarm
+
+#pragma mark initialize-release
 
 + (void)initialize; // XXX change on locale modification, subscribe to NSNotifications
@@ -41,4 +43,6 @@
 }
 
+#pragma mark private
+
 - (void)_setAlarmDate:(NSCalendarDate *)aDate;
 {
@@ -50,5 +54,5 @@
 }
 
-- (void)_invalidate:(NSString *)aMessage;
+- (void)_beInvalid:(NSString *)aMessage;
 {
     alarmType = PSAlarmInvalid;
@@ -62,5 +66,5 @@
 }
 
-- (void)_validateForType:(PSAlarmType)type;
+- (void)_beValidWithType:(PSAlarmType)type;
 {
     if (alarmType == PSAlarmSet) return; // already valid
@@ -75,6 +79,35 @@
     alarmDate = [NSCalendarDate dateWithTimeIntervalSinceNow: alarmInterval];
     [alarmDate retain];
-    [self _validateForType: PSAlarmInterval];
-}
+    [self _beValidWithType: PSAlarmInterval];
+}
+
+- (void)_setIntervalFromDate;
+{
+    alarmInterval = [alarmDate timeIntervalSinceNow] + 1;
+    if (alarmInterval <= 0) {
+        [self _beInvalid: @"Please specify an alarm time in the future."];
+        return;
+    }
+    [self _beValidWithType: PSAlarmDate];
+}
+
+- (NSString *)_alarmTypeString;
+{
+    switch (alarmType) {
+        case PSAlarmDate: return @"PSAlarmDate";
+        case PSAlarmInterval: return @"PSAlarmInterval";
+        case PSAlarmSet: return @"PSAlarmSet";
+        case PSAlarmInvalid: return @"PSAlarmInvalid";
+        default: return [NSString stringWithFormat: @"<unknown: %u>", alarmType];
+    }
+}
+
+- (void)_timerExpired:(NSTimer *)aTimer;
+{
+    [[NSNotificationCenter defaultCenter] postNotificationName: PSAlarmTimerExpiredNotification object: self];
+    [timer release]; timer = nil;
+}
+
+#pragma mark alarm setting
 
 - (void)setInterval:(NSTimeInterval)anInterval;
@@ -82,17 +115,7 @@
     alarmInterval = anInterval;
     if (alarmInterval <= 0) {
-        [self _invalidate: @"Please specify an alarm interval."]; return;
+        [self _beInvalid: @"Please specify an alarm interval."]; return;
     }
     [self _setDateFromInterval];
-}
-
-- (void)_setIntervalFromDate;
-{
-    alarmInterval = [alarmDate timeIntervalSinceNow] + 1;
-    if (alarmInterval <= 0) {
-        [self _invalidate: @"Please specify an alarm time in the future."];
-        return;
-    }
-    [self _validateForType: PSAlarmDate];
 }
 
@@ -107,11 +130,11 @@
     NSCalendarDate *calTime, *calDate;
     if (time == nil && date == nil) {
-        [self _invalidate: @"Please specify an alarm date and time."]; return;
+        [self _beInvalid: @"Please specify an alarm date and time."]; return;
     }
     if (time == nil) {
-        [self _invalidate: @"Please specify an alarm time."]; return;
+        [self _beInvalid: @"Please specify an alarm time."]; return;
     }
     if (date == nil) {
-        [self _invalidate: @"Please specify an alarm date."]; return;
+        [self _beInvalid: @"Please specify an alarm date."]; return;
     }
     // XXX if calTime's date is different from the default date, complain
@@ -119,5 +142,5 @@
     calDate = [NSCalendarDate dateWithTimeIntervalSinceReferenceDate: [date timeIntervalSinceReferenceDate]];
     if (calTime == nil || calDate == nil) {
-        [self _invalidate: @"Please specify a reasonable date and time."];
+        [self _beInvalid: @"Please specify a reasonable date and time."];
     }
     [self setForDateAtTime:
@@ -131,8 +154,11 @@
 }
 
-- (BOOL)isValid;
-{
-    if (alarmType == PSAlarmDate) [self _setIntervalFromDate];
-    return (alarmType != PSAlarmInvalid);
+#pragma mark accessing
+
+- (NSString *)message;
+{
+    if (alarmMessage == nil || [alarmMessage isEqualToString: @""])
+        return @"Alarm!";
+    return alarmMessage;
 }
 
@@ -146,9 +172,8 @@
 }
 
-- (NSString *)message;
-{
-    if (alarmMessage == nil || [alarmMessage isEqualToString: @""])
-        return @"Alarm!";
-    return alarmMessage;    
+- (BOOL)isValid;
+{
+    if (alarmType == PSAlarmDate) [self _setIntervalFromDate];
+    return (alarmType != PSAlarmInvalid);
 }
 
@@ -163,4 +188,38 @@
     if (alarmType == PSAlarmInterval) [self _setDateFromInterval];
     return alarmDate;
+}
+
+- (NSCalendarDate *)time;
+{
+    if (alarmType == PSAlarmInterval) [self _setDateFromInterval];
+    return [[NSCalendarDate alloc] initWithYear: 0
+                                          month: 1
+                                            day: 1
+                                           hour: [alarmDate hourOfDay]
+                                         minute: [alarmDate minuteOfHour]
+                                         second: [alarmDate secondOfMinute]
+                                       timeZone: nil];
+}
+
+- (NSTimeInterval)interval;
+{
+    if (alarmType == PSAlarmSet || alarmType == PSAlarmDate) [self _setIntervalFromDate];
+    return alarmInterval;
+}
+
+- (void)addAlert:(PSAlert *)alert;
+{
+    if (alerts == nil) alerts = [[NSMutableArray alloc] initWithCapacity: 4];
+    [alerts addObject: alert];
+}
+
+- (void)removeAlerts;
+{
+    [alerts removeAllObjects];
+}
+
+- (NSArray *)alerts;
+{
+    return [[alerts copy] autorelease];
 }
 
@@ -193,9 +252,5 @@
 }
 
-- (NSTimeInterval)interval;
-{
-    if (alarmType == PSAlarmSet || alarmType == PSAlarmDate) [self _setIntervalFromDate];
-    return alarmInterval;
-}
+#pragma mark actions
 
 - (BOOL)setTimer;
@@ -204,9 +259,5 @@
         case PSAlarmDate: if (![self isValid]) return NO;
         case PSAlarmInterval:
-            timer = [NSTimer scheduledTimerWithTimeInterval: alarmInterval
-                                                     target: self
-                                                   selector: @selector(_timerExpired:)
-                                                   userInfo: nil
-                                                    repeats: NO];
+            timer = [NSTimer scheduledTimerWithTimeInterval: alarmInterval target: self selector: @selector(_timerExpired:) userInfo: nil repeats: NO];
             if (timer != nil) {
                 [timer retain];
@@ -220,46 +271,22 @@
 }
 
-- (void)cancel;
+- (void)cancelTimer;
 {
     [timer invalidate]; [timer release]; timer = nil;
 }
 
-- (void)_timerExpired:(NSTimer *)aTimer;
-{
-    [[NSNotificationCenter defaultCenter] postNotificationName: PSAlarmTimerExpiredNotification object: self];
-    [timer release]; timer = nil;
-}
-
-- (NSString *)_alarmTypeString;
-{
-    switch (alarmType) {
-        case PSAlarmDate: return @"PSAlarmDate";
-        case PSAlarmInterval: return @"PSAlarmInterval";
-        case PSAlarmSet: return @"PSAlarmSet";
-        case PSAlarmInvalid: return @"PSAlarmInvalid";
-        default: return [NSString stringWithFormat: @"<unknown: %u>", alarmType];
-    }
-}
-
-- (NSComparisonResult)compare:(PSAlarm *)otherAlarm;
+#pragma mark comparing
+
+- (NSComparisonResult)compareDate:(PSAlarm *)otherAlarm;
 {
     return [[self date] compare: [otherAlarm date]];
 }
 
-- (void)addAlert:(PSAlert *)alert;
-{
-    if (alerts == nil) alerts = [[NSMutableArray alloc] initWithCapacity: 4];
-    [alerts addObject: alert];
-}
-
-- (void)removeAlerts;
-{
-    [alerts removeAllObjects];
-}
-
-- (NSArray *)alerts;
-{
-    return [[alerts copy] autorelease];
-}
+- (NSComparisonResult)compareMessage:(PSAlarm *)otherAlarm;
+{
+    return [[self message] caseInsensitiveCompare: [otherAlarm message]];
+}
+
+#pragma mark printing
 
 - (NSString *)description;
@@ -272,4 +299,6 @@
            [NSString stringWithFormat: @"\ntimer: %@", timer] : @""))];
 }
+
+#pragma mark archiving
 
 - (void)encodeWithCoder:(NSCoder *)coder;
Index: /trunk/Cocoa/Pester/Source/PSAlarmSetController.m
===================================================================
--- /trunk/Cocoa/Pester/Source/PSAlarmSetController.m	(revision 50)
+++ /trunk/Cocoa/Pester/Source/PSAlarmSetController.m	(revision 51)
@@ -92,8 +92,9 @@
     [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(playSoundChanged:) name: NJRQTMediaPopUpButtonMovieChangedNotification object: sound];
     [voice setDelegate: self];
-    if (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_1) {
+    // XXX still broken under 10.2, check 10.1 behavior and see if subclassing NSComboBox will help
+    // if (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_1) {
         // XXX workaround for 10.1.x bug which sets the first responder to the wrong field, but it works if I set the initial first responder to nil... go figure.
         [[self window] setInitialFirstResponder: nil];
-    }
+    // }
     [[self window] makeKeyAndOrderFront: nil];
 }
Index: /trunk/Cocoa/Pester/Source/PSAlarms.h
===================================================================
--- /trunk/Cocoa/Pester/Source/PSAlarms.h	(revision 50)
+++ /trunk/Cocoa/Pester/Source/PSAlarms.h	(revision 51)
@@ -22,4 +22,5 @@
 + (PSAlarms *)allAlarms;
 
+- (NSArray *)alarms;
 - (PSAlarm *)nextAlarm;
 - (int)alarmCount;
@@ -27,4 +28,5 @@
 - (void)removeAlarmAtIndex:(int)index;
 - (void)removeAlarmsAtIndices:(NSArray *)indices;
+- (void)removeAlarms:(NSSet *)alarmsToRemove;
 
 @end
Index: /trunk/Cocoa/Pester/Source/PSAlarms.m
===================================================================
--- /trunk/Cocoa/Pester/Source/PSAlarms.m	(revision 50)
+++ /trunk/Cocoa/Pester/Source/PSAlarms.m	(revision 51)
@@ -46,5 +46,5 @@
     nextAlarm = nil;
     // sort alarms so earliest is first
-    [alarms sortUsingSelector: @selector(compare:)];
+    [alarms sortUsingSelector: @selector(compareDate:)];
     // find first un-expired alarm
     e = [alarms objectEnumerator];
@@ -126,4 +126,9 @@
 }
 
+- (NSArray *)alarms;
+{
+    return alarms;
+}
+
 - (int)alarmCount;
 {
@@ -138,5 +143,5 @@
 - (void)removeAlarmAtIndex:(int)index;
 {
-    [(PSAlarm *)[alarms objectAtIndex: index] cancel];
+    [(PSAlarm *)[alarms objectAtIndex: index] cancelTimer];
     [alarms removeObjectAtIndex: index];
 }
@@ -151,9 +156,10 @@
         while ( (n = [e nextObject]) != nil) {
             alarmIndex = [n intValue];
-            [(PSAlarm *)[alarms objectAtIndex: alarmIndex] cancel];
+            [(PSAlarm *)[alarms objectAtIndex: alarmIndex] cancelTimer];
             indexArray[i] = alarmIndex;
             i++;
         }
         [alarms removeObjectsFromIndices: indexArray numIndices: indexCount];
+        free(indexArray); indexArray = NULL;
         [self _changed];
     NS_HANDLER
@@ -164,3 +170,18 @@
 }
 
+- (void)removeAlarms:(NSSet *)alarmsToRemove;
+{
+    NSEnumerator *e = [alarms objectEnumerator];
+    PSAlarm *alarm;
+    NSMutableArray *indices = [NSMutableArray arrayWithCapacity: [alarmsToRemove count]];
+    int alarmIndex = 0;
+
+    while ( (alarm = [e nextObject]) != nil) {
+        if ([alarmsToRemove containsObject: alarm])
+            [indices addObject: [NSNumber numberWithInt: alarmIndex]];
+        alarmIndex++;
+    }
+    [self removeAlarmsAtIndices: indices];
+}
+
 @end
Index: /trunk/Cocoa/Pester/Source/PSAlarmsController.h
===================================================================
--- /trunk/Cocoa/Pester/Source/PSAlarmsController.h	(revision 50)
+++ /trunk/Cocoa/Pester/Source/PSAlarmsController.h	(revision 51)
@@ -14,4 +14,5 @@
     IBOutlet NSButton *removeButton;
     PSAlarms *alarms;
+    NSArray *reorderedAlarms;
 }
 
Index: /trunk/Cocoa/Pester/Source/PSAlarmsController.m
===================================================================
--- /trunk/Cocoa/Pester/Source/PSAlarmsController.m	(revision 50)
+++ /trunk/Cocoa/Pester/Source/PSAlarmsController.m	(revision 51)
@@ -10,7 +10,13 @@
 #import "PSAlarm.h"
 #import "NSTableView-NJRExtensions.h"
-
+#import "NJRTableView.h"
+#import "NJRTableDelegate.h"
 
 @implementation PSAlarmsController
+
+- (void)alarmsChanged;
+{
+    reorderedAlarms = [[tableView delegate] reorderedDataForData: [alarms alarms]];
+}
 
 - (id)init;
@@ -23,25 +29,22 @@
         if (nil == [[NSUserDefaults standardUserDefaults] objectForKey:
             [@"NSWindow Frame " stringByAppendingString: [[self window] frameAutosaveName]]])
-        {
+           {
             [[self window] center];
-        }
+           }
         [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(alarmsChanged) name: PSAlarmsDidChangeNotification object: alarms];
+        [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(tableViewSelectionDidChange:) name: NSTableViewSelectionDidChangeNotification object: tableView];
         [tableView setAutosaveName: @"Alarm list"];
         [tableView setAutosaveTableColumns: YES];
-        [tableView noteNumberOfRowsChanged];
+        [self alarmsChanged];
         [[self window] makeFirstResponder: tableView];
+        [[self window] setResizeIncrements: NSMakeSize(1, [tableView cellHeight])];
     }
     return self;
 }
 
-- (void)alarmsChanged; // XXX fix autoselection to be more reasonable, see whatever I did in that _Learning Cocoa_ project I think
-{
-    [tableView reloadData];
-    [tableView deselectAll: self];
-}
 
 - (IBAction)remove:(id)sender;
 {
-    [alarms removeAlarmsAtIndices: [[tableView selectedRowEnumerator] allObjects]];
+    [alarms removeAlarms: [[tableView delegate] selectedItems]];
 }
 
@@ -57,5 +60,5 @@
 - (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(int)row;
 {
-    PSAlarm *alarm = [alarms alarmAtIndex: row];
+    PSAlarm *alarm = [reorderedAlarms objectAtIndex: row];
 
     if ([[tableColumn identifier] isEqualToString: @"message"]) return [alarm message];
@@ -70,4 +73,13 @@
     return nil;
 }
+@end
+
+@implementation PSAlarmsController (NJRTableViewDataSource)
+
+- (void)removeSelectedRowsFromTableView:(NSTableView *)aTableView;
+{
+    [self remove: aTableView];
+}
+
 @end
 
Index: /trunk/Cocoa/Pester/Source/Pester.pbproj/nicholas.pbxuser
===================================================================
--- /trunk/Cocoa/Pester/Source/Pester.pbproj/nicholas.pbxuser	(revision 50)
+++ /trunk/Cocoa/Pester/Source/Pester.pbproj/nicholas.pbxuser	(revision 51)
@@ -12,5 +12,4 @@
 			F500E5370359719B01AEEDB1,
 			F5B15F74037E42EB01AEEDB1,
-			F562F810037E79EE01AEEDB1,
 		);
 		executables = (
@@ -18,15 +17,303 @@
 		);
 		perUserDictionary = {
-			PBXPerProjectTemplateStateSaveDate = 58758807;
-			"PBXTemplateGeometry-F5CA7EC8015C06940DCA290F" = {
-				ContentSize = "{705, 569}";
+			PBXPerProjectTemplateStateSaveDate = 59271904;
+			"PBXTemplateGeometry-F5314676015831810DCA290F" = {
+				ContentSize = "{618, 257}";
 				LeftSlideOut = {
 					Collapsed = NO;
-					Frame = "{{0, 0}, {705, 569}}";
+					Frame = "{{0, 23}, {618, 234}}";
+					Split0 = {
+						ActiveTab = 2;
+						Collapsed = YES;
+						Frame = "{{0, 0}, {618, 234}}";
+						Split0 = {
+							Frame = "{{1e+06, 1e+06}, {618, 0}}";
+						};
+						SplitCount = 1;
+						Tab0 = {
+							Debugger = {
+								Collapsed = NO;
+								Frame = "{{0, 0}, {952, 321}}";
+								Split0 = {
+									Frame = "{{0, 24}, {952, 297}}";
+									Split0 = {
+										Frame = "{{0, 0}, {468, 297}}";
+									};
+									Split1 = {
+										DebugVariablesTableConfiguration = (
+											Name,
+											126.803,
+											Value,
+											150.074,
+											Summary,
+											172.123,
+										);
+										Frame = "{{477, 0}, {475, 297}}";
+									};
+									SplitCount = 2;
+								};
+								SplitCount = 1;
+								Tab0 = {
+									Frame = "{{0, 0}, {100, 50}}";
+								};
+								Tab1 = {
+									Frame = "{{0, 0}, {100, 50}}";
+								};
+								TabCount = 2;
+								TabsVisible = YES;
+							};
+							Frame = "{{0, 0}, {952, 321}}";
+							LauncherConfigVersion = 7;
+						};
+						Tab1 = {
+							Frame = "{{0, 0}, {781, 452}}";
+							LauncherConfigVersion = 3;
+							Runner = {
+								Frame = "{{0, 0}, {781, 452}}";
+							};
+						};
+						Tab2 = {
+							BuildMessageFrame = "{{0, 0}, {620, 123}}";
+							BuildTranscriptFrame = "{{0, 132}, {620, 98}}";
+							Frame = "{{0, 0}, {618, 228}}";
+						};
+						Tab3 = {
+							Frame = "{{0, 0}, {612, 295}}";
+						};
+						TabCount = 4;
+						TabsVisible = NO;
+					};
+					SplitCount = 1;
+					Tab0 = {
+						Frame = "{{0, 0}, {300, 533}}";
+						GroupTreeTableConfiguration = (
+							TargetStatusColumn,
+							18,
+							MainColumn,
+							267,
+						);
+					};
+					Tab1 = {
+						ClassesFrame = "{{0, 0}, {280, 398}}";
+						ClassesTreeTableConfiguration = (
+							PBXBookColumnIdentifier,
+							20,
+							PBXClassColumnIdentifier,
+							237,
+						);
+						Frame = "{{0, 0}, {278, 659}}";
+						MembersFrame = "{{0, 407}, {280, 252}}";
+						MembersTreeTableConfiguration = (
+							PBXBookColumnIdentifier,
+							20,
+							PBXMethodColumnIdentifier,
+							236,
+						);
+					};
+					Tab2 = {
+						Frame = "{{0, 0}, {200, 100}}";
+					};
+					Tab3 = {
+						Frame = "{{0, 0}, {200, 100}}";
+						Split0 = {
+							Frame = "{{0, 0}, {200, 45}}";
+							TargetTreeTableConfiguration = (
+								ActiveTarget,
+								16,
+								TargetName,
+								168,
+							);
+						};
+						Split1 = {
+							BuildStyleTreeTableConfiguration = (
+								IsActive,
+								16,
+								Name,
+								169,
+							);
+							Frame = "{{0, 54}, {200, 46}}";
+						};
+						SplitCount = 2;
+					};
+					Tab4 = {
+						ExecutableTreeTableConfiguration = (
+							ActiveExecutable,
+							16,
+							ExecutableName,
+							217,
+						);
+						Frame = "{{0, 0}, {250, 100}}";
+					};
+					Tab5 = {
+						BreakpointsTreeTableConfiguration = (
+							breakpointColumn,
+							197,
+							enabledColumn,
+							31,
+						);
+						Frame = "{{0, 0}, {250, 100}}";
+					};
+					TabCount = 6;
+					TabsVisible = NO;
+				};
+				StatusViewVisible = YES;
+				Template = F5314676015831810DCA290F;
+				ToolbarVisible = YES;
+				WindowLocation = "{460, 270}";
+			};
+			"PBXTemplateGeometry-F5CA7EC9015C08ED0DCA290F" = {
+				ContentSize = "{665, 594}";
+				LeftSlideOut = {
+					Collapsed = NO;
+					Frame = "{{0, 0}, {665, 594}}";
+					Split0 = {
+						ActiveTab = 3;
+						Collapsed = NO;
+						Frame = "{{0, 0}, {665, 594}}";
+						Split0 = {
+							Frame = "{{0, 304}, {665, 290}}";
+						};
+						SplitCount = 1;
+						Tab0 = {
+							Debugger = {
+								Collapsed = NO;
+								Frame = "{{0, 0}, {484, 208}}";
+								Split0 = {
+									Frame = "{{0, 24}, {484, 184}}";
+									Split0 = {
+										Frame = "{{0, 0}, {236, 184}}";
+									};
+									Split1 = {
+										DebugVariablesTableConfiguration = (
+											Name,
+											48.80299,
+											Value,
+											71.07401,
+											Summary,
+											93.123,
+										);
+										Frame = "{{245, 0}, {239, 184}}";
+									};
+									SplitCount = 2;
+								};
+								SplitCount = 1;
+								Tab0 = {
+									Frame = "{{0, 0}, {100, 50}}";
+								};
+								Tab1 = {
+									Frame = "{{0, 0}, {100, 50}}";
+								};
+								TabCount = 2;
+								TabsVisible = YES;
+							};
+							Frame = "{{0, 0}, {484, 208}}";
+							LauncherConfigVersion = 7;
+						};
+						Tab1 = {
+							Frame = "{{0, 0}, {664, 208}}";
+							LauncherConfigVersion = 3;
+							Runner = {
+								Frame = "{{0, 0}, {664, 208}}";
+							};
+						};
+						Tab2 = {
+							BuildMessageFrame = "{{0, 0}, {666, 43}}";
+							BuildTranscriptFrame = "{{0, 52}, {666, 0}}";
+							Frame = "{{0, 0}, {664, 50}}";
+						};
+						Tab3 = {
+							Frame = "{{0, 0}, {665, 298}}";
+						};
+						TabCount = 4;
+						TabsVisible = NO;
+					};
+					SplitCount = 1;
+					Tab0 = {
+						Frame = "{{0, 0}, {313, 531}}";
+						GroupTreeTableConfiguration = (
+							TargetStatusColumn,
+							18,
+							MainColumn,
+							280,
+						);
+					};
+					Tab1 = {
+						ClassesFrame = "{{0, 0}, {280, 398}}";
+						ClassesTreeTableConfiguration = (
+							PBXBookColumnIdentifier,
+							20,
+							PBXClassColumnIdentifier,
+							237,
+						);
+						Frame = "{{0, 0}, {278, 659}}";
+						MembersFrame = "{{0, 407}, {280, 252}}";
+						MembersTreeTableConfiguration = (
+							PBXBookColumnIdentifier,
+							20,
+							PBXMethodColumnIdentifier,
+							236,
+						);
+					};
+					Tab2 = {
+						Frame = "{{0, 0}, {200, 100}}";
+					};
+					Tab3 = {
+						Frame = "{{0, 0}, {200, 557}}";
+						Split0 = {
+							Frame = "{{0, 0}, {200, 270}}";
+							TargetTreeTableConfiguration = (
+								ActiveTarget,
+								16,
+								TargetName,
+								168,
+							);
+						};
+						Split1 = {
+							BuildStyleTreeTableConfiguration = (
+								IsActive,
+								16,
+								Name,
+								169,
+							);
+							Frame = "{{0, 279}, {200, 278}}";
+						};
+						SplitCount = 2;
+					};
+					Tab4 = {
+						ExecutableTreeTableConfiguration = (
+							ActiveExecutable,
+							16,
+							ExecutableName,
+							217,
+						);
+						Frame = "{{0, 0}, {250, 100}}";
+					};
+					Tab5 = {
+						BreakpointsTreeTableConfiguration = (
+							breakpointColumn,
+							197,
+							enabledColumn,
+							31,
+						);
+						Frame = "{{0, 0}, {250, 100}}";
+					};
+					TabCount = 6;
+					TabsVisible = NO;
+				};
+				StatusViewVisible = NO;
+				Template = F5CA7EC9015C08ED0DCA290F;
+				ToolbarVisible = NO;
+				WindowLocation = "{69, 216}";
+			};
+			"PBXTemplateGeometry-F5CA7ECB015C094F0DCA290F" = {
+				ContentSize = "{668, 621}";
+				LeftSlideOut = {
+					Collapsed = NO;
+					Frame = "{{0, 0}, {668, 621}}";
 					Split0 = {
 						Collapsed = NO;
-						Frame = "{{0, 0}, {705, 569}}";
-						Split0 = {
-							Frame = "{{0, 0}, {705, 569}}";
+						Frame = "{{0, 0}, {668, 621}}";
+						Split0 = {
+							Frame = "{{0, 0}, {668, 621}}";
 						};
 						SplitCount = 1;
@@ -67,14 +354,14 @@
 						};
 						Tab1 = {
-							Frame = "{{0, 0}, {522, 208}}";
+							Frame = "{{0, 0}, {664, 208}}";
 							LauncherConfigVersion = 3;
 							Runner = {
-								Frame = "{{0, 0}, {522, 208}}";
+								Frame = "{{0, 0}, {664, 208}}";
 							};
 						};
 						Tab2 = {
-							BuildMessageFrame = "{{0, 0}, {809, 410}}";
-							BuildTranscriptFrame = "{{0, 419}, {809, 119}}";
-							Frame = "{{0, 0}, {807, 536}}";
+							BuildMessageFrame = "{{0, 0}, {666, 43}}";
+							BuildTranscriptFrame = "{{0, 52}, {666, 0}}";
+							Frame = "{{0, 0}, {664, 50}}";
 						};
 						Tab3 = {
@@ -86,10 +373,10 @@
 					SplitCount = 1;
 					Tab0 = {
-						Frame = "{{0, 0}, {300, 533}}";
+						Frame = "{{0, 0}, {313, 531}}";
 						GroupTreeTableConfiguration = (
 							TargetStatusColumn,
 							18,
 							MainColumn,
-							267,
+							280,
 						);
 					};
@@ -115,13 +402,35 @@
 					};
 					Tab3 = {
-						Frame = "{{0, 0}, {222, 536}}";
-						TargetTableConfiguration = (
-							ActiveObject,
+						Frame = "{{0, 0}, {200, 557}}";
+						Split0 = {
+							Frame = "{{0, 0}, {200, 270}}";
+							TargetTreeTableConfiguration = (
+								ActiveTarget,
+								16,
+								TargetName,
+								168,
+							);
+						};
+						Split1 = {
+							BuildStyleTreeTableConfiguration = (
+								IsActive,
+								16,
+								Name,
+								169,
+							);
+							Frame = "{{0, 279}, {200, 278}}";
+						};
+						SplitCount = 2;
+					};
+					Tab4 = {
+						ExecutableTreeTableConfiguration = (
+							ActiveExecutable,
 							16,
-							ObjectNames,
-							202.296,
-						);
-					};
-					Tab4 = {
+							ExecutableName,
+							217,
+						);
+						Frame = "{{0, 0}, {250, 100}}";
+					};
+					Tab5 = {
 						BreakpointsTreeTableConfiguration = (
 							breakpointColumn,
@@ -130,24 +439,170 @@
 							31,
 						);
-						Frame = "{{0, 0}, {250, 528}}";
-					};
-					TabCount = 5;
+						Frame = "{{0, 0}, {250, 100}}";
+					};
+					TabCount = 6;
 					TabsVisible = NO;
 				};
 				StatusViewVisible = NO;
-				Template = F5CA7EC8015C06940DCA290F;
-				ToolbarVisible = YES;
-				WindowLocation = "{11, 351}";
+				Template = F5CA7ECB015C094F0DCA290F;
+				ToolbarVisible = NO;
+				WindowLocation = "{361, 189}";
 			};
-			"PBXTemplateGeometry-F5CA7ECB015C094F0DCA290F" = {
-				ContentSize = "{668, 621}";
+			"PBXTemplateGeometry-F5CA7ECC015C09990DCA290F" = {
+				ContentSize = "{773, 558}";
 				LeftSlideOut = {
 					Collapsed = NO;
-					Frame = "{{0, 0}, {668, 621}}";
+					Frame = "{{0, 23}, {773, 535}}";
+					Split0 = {
+						ActiveTab = 0;
+						Collapsed = NO;
+						Frame = "{{24, 0}, {749, 535}}";
+						Split0 = {
+							Frame = "{{0, 337}, {749, 198}}";
+						};
+						SplitCount = 1;
+						Tab0 = {
+							Debugger = {
+								ActiveTab = 1;
+								Collapsed = NO;
+								Frame = "{{0, 0}, {749, 331}}";
+								Split0 = {
+									Frame = "{{0, 127}, {749, 204}}";
+									Split0 = {
+										Frame = "{{0, 0}, {366, 204}}";
+									};
+									Split1 = {
+										DebugVariablesTableConfiguration = (
+											Name,
+											120.803,
+											Value,
+											116.074,
+											Summary,
+											111.123,
+										);
+										Frame = "{{375, 0}, {374, 204}}";
+									};
+									SplitCount = 2;
+								};
+								SplitCount = 1;
+								Tab0 = {
+									Frame = "{{0, 0}, {100, 50}}";
+								};
+								Tab1 = {
+									Frame = "{{0, 0}, {749, 103}}";
+								};
+								TabCount = 2;
+								TabsVisible = YES;
+							};
+							Frame = "{{0, 0}, {749, 331}}";
+							LauncherConfigVersion = 7;
+						};
+						Tab1 = {
+							Frame = "{{0, 0}, {664, 208}}";
+							LauncherConfigVersion = 3;
+							Runner = {
+								Frame = "{{0, 0}, {664, 208}}";
+							};
+						};
+						Tab2 = {
+							BuildMessageFrame = "{{0, 0}, {666, 43}}";
+							BuildTranscriptFrame = "{{0, 52}, {666, 0}}";
+							Frame = "{{0, 0}, {664, 50}}";
+						};
+						Tab3 = {
+							Frame = "{{0, 0}, {612, 295}}";
+						};
+						TabCount = 4;
+						TabsVisible = NO;
+					};
+					SplitCount = 1;
+					Tab0 = {
+						Frame = "{{0, 0}, {313, 531}}";
+						GroupTreeTableConfiguration = (
+							TargetStatusColumn,
+							18,
+							MainColumn,
+							280,
+						);
+					};
+					Tab1 = {
+						ClassesFrame = "{{0, 0}, {280, 398}}";
+						ClassesTreeTableConfiguration = (
+							PBXBookColumnIdentifier,
+							20,
+							PBXClassColumnIdentifier,
+							237,
+						);
+						Frame = "{{0, 0}, {278, 659}}";
+						MembersFrame = "{{0, 407}, {280, 252}}";
+						MembersTreeTableConfiguration = (
+							PBXBookColumnIdentifier,
+							20,
+							PBXMethodColumnIdentifier,
+							236,
+						);
+					};
+					Tab2 = {
+						Frame = "{{0, 0}, {200, 100}}";
+					};
+					Tab3 = {
+						Frame = "{{0, 0}, {200, 557}}";
+						Split0 = {
+							Frame = "{{0, 0}, {200, 270}}";
+							TargetTreeTableConfiguration = (
+								ActiveTarget,
+								16,
+								TargetName,
+								168,
+							);
+						};
+						Split1 = {
+							BuildStyleTreeTableConfiguration = (
+								IsActive,
+								16,
+								Name,
+								169,
+							);
+							Frame = "{{0, 279}, {200, 278}}";
+						};
+						SplitCount = 2;
+					};
+					Tab4 = {
+						ExecutableTreeTableConfiguration = (
+							ActiveExecutable,
+							16,
+							ExecutableName,
+							217,
+						);
+						Frame = "{{0, 0}, {250, 100}}";
+					};
+					Tab5 = {
+						BreakpointsTreeTableConfiguration = (
+							breakpointColumn,
+							197,
+							enabledColumn,
+							31,
+						);
+						Frame = "{{0, 0}, {250, 100}}";
+					};
+					TabCount = 6;
+					TabsVisible = YES;
+				};
+				StatusViewVisible = YES;
+				Template = F5CA7ECC015C09990DCA290F;
+				ToolbarVisible = YES;
+				WindowLocation = "{13, 212}";
+			};
+			"PBXTemplateGeometry-F5E465990156DFB90DCA290F" = {
+				ContentSize = "{352, 553}";
+				LeftSlideOut = {
+					ActiveTab = 0;
+					Collapsed = YES;
+					Frame = "{{0, 23}, {352, 530}}";
 					Split0 = {
 						Collapsed = NO;
-						Frame = "{{0, 0}, {668, 621}}";
-						Split0 = {
-							Frame = "{{0, 0}, {668, 621}}";
+						Frame = "{{1e+06, 1e+06}, {0, 530}}";
+						Split0 = {
+							Frame = "{{0, 0}, {0, 530}}";
 						};
 						SplitCount = 1;
@@ -207,42 +662,64 @@
 					SplitCount = 1;
 					Tab0 = {
-						Frame = "{{0, 0}, {313, 531}}";
+						Frame = "{{0, 0}, {328, 530}}";
 						GroupTreeTableConfiguration = (
 							TargetStatusColumn,
 							18,
 							MainColumn,
-							280,
+							295,
 						);
 					};
 					Tab1 = {
-						ClassesFrame = "{{0, 0}, {280, 398}}";
+						ClassesFrame = "{{0, 0}, {343, 348}}";
 						ClassesTreeTableConfiguration = (
 							PBXBookColumnIdentifier,
 							20,
 							PBXClassColumnIdentifier,
-							237,
-						);
-						Frame = "{{0, 0}, {278, 659}}";
-						MembersFrame = "{{0, 407}, {280, 252}}";
+							300,
+						);
+						Frame = "{{0, 0}, {341, 578}}";
+						MembersFrame = "{{0, 357}, {343, 221}}";
 						MembersTreeTableConfiguration = (
 							PBXBookColumnIdentifier,
 							20,
 							PBXMethodColumnIdentifier,
-							236,
+							299,
 						);
 					};
 					Tab2 = {
-						Frame = "{{0, 0}, {200, 100}}";
+						Frame = "{{0, 0}, {319, 576}}";
 					};
 					Tab3 = {
-						Frame = "{{0, 0}, {200, 557}}";
-						TargetTableConfiguration = (
-							ActiveObject,
+						Frame = "{{0, 0}, {341, 578}}";
+						Split0 = {
+							Frame = "{{0, 0}, {341, 281}}";
+							TargetTreeTableConfiguration = (
+								ActiveTarget,
+								16,
+								TargetName,
+								309,
+							);
+						};
+						Split1 = {
+							BuildStyleTreeTableConfiguration = (
+								IsActive,
+								16,
+								Name,
+								310,
+							);
+							Frame = "{{0, 290}, {341, 288}}";
+						};
+						SplitCount = 2;
+					};
+					Tab4 = {
+						ExecutableTreeTableConfiguration = (
+							ActiveExecutable,
 							16,
-							ObjectNames,
-							202.296,
-						);
-					};
-					Tab4 = {
+							ExecutableName,
+							286,
+						);
+						Frame = "{{0, 0}, {319, 576}}";
+					};
+					Tab5 = {
 						BreakpointsTreeTableConfiguration = (
 							breakpointColumn,
@@ -253,134 +730,11 @@
 						Frame = "{{0, 0}, {250, 100}}";
 					};
-					TabCount = 5;
-					TabsVisible = NO;
-				};
-				StatusViewVisible = NO;
-				Template = F5CA7ECB015C094F0DCA290F;
-				ToolbarVisible = NO;
-				WindowLocation = "{48, 349}";
-			};
-			"PBXTemplateGeometry-F5CA7ECC015C09990DCA290F" = {
-				ContentSize = "{956, 601}";
-				LeftSlideOut = {
-					ActiveTab = 4;
-					Collapsed = NO;
-					Frame = "{{0, 23}, {956, 578}}";
-					Split0 = {
-						ActiveTab = 0;
-						Collapsed = NO;
-						Frame = "{{274, 0}, {682, 578}}";
-						Split0 = {
-							Frame = "{{0, 273}, {682, 305}}";
-						};
-						SplitCount = 1;
-						Tab0 = {
-							Debugger = {
-								Collapsed = NO;
-								Frame = "{{0, 0}, {682, 267}}";
-								Split0 = {
-									Frame = "{{0, 24}, {682, 243}}";
-									Split0 = {
-										Frame = "{{0, 0}, {328, 243}}";
-									};
-									Split1 = {
-										DebugVariablesTableConfiguration = (
-											Name,
-											93.80298,
-											Value,
-											116.074,
-											Summary,
-											109.123,
-										);
-										Frame = "{{337, 0}, {345, 243}}";
-									};
-									SplitCount = 2;
-								};
-								SplitCount = 1;
-								Tab0 = {
-									Frame = "{{0, 0}, {100, 50}}";
-								};
-								Tab1 = {
-									Frame = "{{0, 0}, {100, 50}}";
-								};
-								TabCount = 2;
-								TabsVisible = YES;
-							};
-							Frame = "{{0, 0}, {682, 267}}";
-							LauncherConfigVersion = 7;
-						};
-						Tab1 = {
-							Frame = "{{0, 0}, {664, 208}}";
-							LauncherConfigVersion = 3;
-							Runner = {
-								Frame = "{{0, 0}, {664, 208}}";
-							};
-						};
-						Tab2 = {
-							BuildMessageFrame = "{{0, 0}, {666, 43}}";
-							BuildTranscriptFrame = "{{0, 52}, {666, 0}}";
-							Frame = "{{0, 0}, {664, 50}}";
-						};
-						Tab3 = {
-							Frame = "{{0, 0}, {612, 295}}";
-						};
-						TabCount = 4;
-						TabsVisible = NO;
-					};
-					SplitCount = 1;
-					Tab0 = {
-						Frame = "{{0, 0}, {313, 531}}";
-						GroupTreeTableConfiguration = (
-							TargetStatusColumn,
-							18,
-							MainColumn,
-							280,
-						);
-					};
-					Tab1 = {
-						ClassesFrame = "{{0, 0}, {280, 398}}";
-						ClassesTreeTableConfiguration = (
-							PBXBookColumnIdentifier,
-							20,
-							PBXClassColumnIdentifier,
-							237,
-						);
-						Frame = "{{0, 0}, {278, 659}}";
-						MembersFrame = "{{0, 407}, {280, 252}}";
-						MembersTreeTableConfiguration = (
-							PBXBookColumnIdentifier,
-							20,
-							PBXMethodColumnIdentifier,
-							236,
-						);
-					};
-					Tab2 = {
-						Frame = "{{0, 0}, {200, 100}}";
-					};
-					Tab3 = {
-						Frame = "{{0, 0}, {200, 557}}";
-						TargetTableConfiguration = (
-							ActiveObject,
-							16,
-							ObjectNames,
-							202.296,
-						);
-					};
-					Tab4 = {
-						BreakpointsTreeTableConfiguration = (
-							breakpointColumn,
-							197,
-							enabledColumn,
-							31,
-						);
-						Frame = "{{0, 0}, {250, 578}}";
-					};
-					TabCount = 5;
+					TabCount = 6;
 					TabsVisible = YES;
 				};
 				StatusViewVisible = YES;
-				Template = F5CA7ECC015C09990DCA290F;
+				Template = F5E465990156DFB90DCA290F;
 				ToolbarVisible = YES;
-				WindowLocation = "{79, 361}";
+				WindowLocation = "{2, 217}";
 			};
 			PBXWorkspaceContents = (
@@ -459,7 +813,13 @@
 						Split0 = {
 							Split0 = {
+								NavContent0 = {
+									bookmark = F562F80B037E5D2101AEEDB1;
+									history = (
+										F5B163A5037E543A01AEEDB1,
+									);
+								};
 								NavCount = 1;
 								NavGeometry0 = {
-									Frame = "{{0, 0}, {618, 150}}";
+									Frame = "{{0, 0}, {668, 621}}";
 									NavBarVisible = YES;
 								};
@@ -494,58 +854,7 @@
 						Split0 = {
 							Split0 = {
-								NavContent0 = {
-									bookmark = F562F814037E7F6101AEEDB1;
-									history = (
-										F562F813037E7F6101AEEDB1,
-									);
-								};
 								NavCount = 1;
 								NavGeometry0 = {
-									Frame = "{{0, 0}, {668, 621}}";
-									NavBarVisible = YES;
-								};
-							};
-							SplitCount = 1;
-							Tab0 = {
-								Debugger = {
-									Split0 = {
-										SplitCount = 2;
-									};
-									SplitCount = 1;
-									TabCount = 2;
-								};
-								LauncherConfigVersion = 7;
-							};
-							Tab1 = {
-								LauncherConfigVersion = 3;
-								Runner = {
-								};
-							};
-							TabCount = 4;
-						};
-						SplitCount = 1;
-						Tab1 = {
-							OptionsSetName = "Hierarchy, all classes";
-						};
-						TabCount = 5;
-					};
-				},
-				{
-					LeftSlideOut = {
-						Split0 = {
-							Split0 = {
-								NavContent0 = {
-									bookmark = F562F818037E7F6101AEEDB1;
-									history = (
-										F562F815037E7F6101AEEDB1,
-										F562F816037E7F6101AEEDB1,
-									);
-									prevStack = (
-										F562F817037E7F6101AEEDB1,
-									);
-								};
-								NavCount = 1;
-								NavGeometry0 = {
-									Frame = "{{0, 0}, {682, 305}}";
+									Frame = "{{0, 0}, {618, 150}}";
 									NavBarVisible = YES;
 								};
@@ -823,4 +1132,125 @@
 				},
 				{
+					ContentSize = "{668, 621}";
+					LeftSlideOut = {
+						Collapsed = NO;
+						Frame = "{{0, 0}, {668, 621}}";
+						Split0 = {
+							Collapsed = NO;
+							Frame = "{{0, 0}, {668, 621}}";
+							Split0 = {
+								Frame = "{{0, 0}, {668, 621}}";
+							};
+							SplitCount = 1;
+							Tab0 = {
+								Debugger = {
+									Collapsed = NO;
+									Frame = "{{0, 0}, {484, 208}}";
+									Split0 = {
+										Frame = "{{0, 24}, {484, 184}}";
+										Split0 = {
+											Frame = "{{0, 0}, {236, 184}}";
+										};
+										Split1 = {
+											DebugVariablesTableConfiguration = (
+												Name,
+												123,
+												Value,
+												85,
+												Summary,
+												62.123,
+											);
+											Frame = "{{245, 0}, {239, 184}}";
+										};
+										SplitCount = 2;
+									};
+									SplitCount = 1;
+									Tab0 = {
+										Frame = "{{0, 0}, {100, 50}}";
+									};
+									Tab1 = {
+										Frame = "{{0, 0}, {100, 50}}";
+									};
+									TabCount = 2;
+									TabsVisible = YES;
+								};
+								Frame = "{{0, 0}, {484, 208}}";
+								LauncherConfigVersion = 7;
+							};
+							Tab1 = {
+								Frame = "{{0, 0}, {664, 208}}";
+								LauncherConfigVersion = 3;
+								Runner = {
+									Frame = "{{0, 0}, {664, 208}}";
+								};
+							};
+							Tab2 = {
+								BuildMessageFrame = "{{0, 0}, {666, 43}}";
+								BuildTranscriptFrame = "{{0, 52}, {666, 0}}";
+								Frame = "{{0, 0}, {664, 50}}";
+							};
+							Tab3 = {
+								Frame = "{{0, 0}, {612, 295}}";
+							};
+							TabCount = 4;
+							TabsVisible = NO;
+						};
+						SplitCount = 1;
+						Tab0 = {
+							Frame = "{{0, 0}, {313, 531}}";
+							GroupTreeTableConfiguration = (
+								TargetStatusColumn,
+								18,
+								MainColumn,
+								280,
+							);
+						};
+						Tab1 = {
+							ClassesFrame = "{{0, 0}, {280, 398}}";
+							ClassesTreeTableConfiguration = (
+								PBXBookColumnIdentifier,
+								20,
+								PBXClassColumnIdentifier,
+								237,
+							);
+							Frame = "{{0, 0}, {278, 659}}";
+							MembersFrame = "{{0, 407}, {280, 252}}";
+							MembersTreeTableConfiguration = (
+								PBXBookColumnIdentifier,
+								20,
+								PBXMethodColumnIdentifier,
+								236,
+							);
+						};
+						Tab2 = {
+							Frame = "{{0, 0}, {200, 100}}";
+						};
+						Tab3 = {
+							Frame = "{{0, 0}, {200, 557}}";
+							TargetTableConfiguration = (
+								ActiveObject,
+								16,
+								ObjectNames,
+								202.296,
+							);
+						};
+						Tab4 = {
+							BreakpointsTreeTableConfiguration = (
+								breakpointColumn,
+								197,
+								enabledColumn,
+								31,
+							);
+							Frame = "{{0, 0}, {250, 100}}";
+						};
+						TabCount = 5;
+						TabsVisible = NO;
+					};
+					StatusViewVisible = NO;
+					Template = F5CA7ECB015C094F0DCA290F;
+					ToolbarVisible = NO;
+					WindowLocation = "{392, 503}";
+				},
+				{
 					ContentSize = "{618, 257}";
 					LeftSlideOut = {
@@ -878,6 +1308,6 @@
 							};
 							Tab2 = {
-								BuildMessageFrame = "{{0, 0}, {620, 122}}";
-								BuildTranscriptFrame = "{{0, 131}, {620, 99}}";
+								BuildMessageFrame = "{{0, 0}, {620, 123}}";
+								BuildTranscriptFrame = "{{0, 132}, {620, 98}}";
 								Frame = "{{0, 0}, {618, 228}}";
 							};
@@ -944,258 +1374,10 @@
 					WindowLocation = "{427, 271}";
 				},
-				{
-					ContentSize = "{668, 621}";
-					LeftSlideOut = {
-						Collapsed = NO;
-						Frame = "{{0, 0}, {668, 621}}";
-						Split0 = {
-							Collapsed = NO;
-							Frame = "{{0, 0}, {668, 621}}";
-							Split0 = {
-								Frame = "{{0, 0}, {668, 621}}";
-							};
-							SplitCount = 1;
-							Tab0 = {
-								Debugger = {
-									Collapsed = NO;
-									Frame = "{{0, 0}, {484, 208}}";
-									Split0 = {
-										Frame = "{{0, 24}, {484, 184}}";
-										Split0 = {
-											Frame = "{{0, 0}, {236, 184}}";
-										};
-										Split1 = {
-											DebugVariablesTableConfiguration = (
-												Name,
-												123,
-												Value,
-												85,
-												Summary,
-												62.123,
-											);
-											Frame = "{{245, 0}, {239, 184}}";
-										};
-										SplitCount = 2;
-									};
-									SplitCount = 1;
-									Tab0 = {
-										Frame = "{{0, 0}, {100, 50}}";
-									};
-									Tab1 = {
-										Frame = "{{0, 0}, {100, 50}}";
-									};
-									TabCount = 2;
-									TabsVisible = YES;
-								};
-								Frame = "{{0, 0}, {484, 208}}";
-								LauncherConfigVersion = 7;
-							};
-							Tab1 = {
-								Frame = "{{0, 0}, {664, 208}}";
-								LauncherConfigVersion = 3;
-								Runner = {
-									Frame = "{{0, 0}, {664, 208}}";
-								};
-							};
-							Tab2 = {
-								BuildMessageFrame = "{{0, 0}, {666, 43}}";
-								BuildTranscriptFrame = "{{0, 52}, {666, 0}}";
-								Frame = "{{0, 0}, {664, 50}}";
-							};
-							Tab3 = {
-								Frame = "{{0, 0}, {612, 295}}";
-							};
-							TabCount = 4;
-							TabsVisible = NO;
-						};
-						SplitCount = 1;
-						Tab0 = {
-							Frame = "{{0, 0}, {313, 531}}";
-							GroupTreeTableConfiguration = (
-								TargetStatusColumn,
-								18,
-								MainColumn,
-								280,
-							);
-						};
-						Tab1 = {
-							ClassesFrame = "{{0, 0}, {280, 398}}";
-							ClassesTreeTableConfiguration = (
-								PBXBookColumnIdentifier,
-								20,
-								PBXClassColumnIdentifier,
-								237,
-							);
-							Frame = "{{0, 0}, {278, 659}}";
-							MembersFrame = "{{0, 407}, {280, 252}}";
-							MembersTreeTableConfiguration = (
-								PBXBookColumnIdentifier,
-								20,
-								PBXMethodColumnIdentifier,
-								236,
-							);
-						};
-						Tab2 = {
-							Frame = "{{0, 0}, {200, 100}}";
-						};
-						Tab3 = {
-							Frame = "{{0, 0}, {200, 557}}";
-							TargetTableConfiguration = (
-								ActiveObject,
-								16,
-								ObjectNames,
-								202.296,
-							);
-						};
-						Tab4 = {
-							BreakpointsTreeTableConfiguration = (
-								breakpointColumn,
-								197,
-								enabledColumn,
-								31,
-							);
-							Frame = "{{0, 0}, {250, 100}}";
-						};
-						TabCount = 5;
-						TabsVisible = NO;
-					};
-					StatusViewVisible = NO;
-					Template = F5CA7ECB015C094F0DCA290F;
-					ToolbarVisible = NO;
-					WindowLocation = "{392, 503}";
-				},
-				{
-					ContentSize = "{956, 601}";
-					LeftSlideOut = {
-						ActiveTab = 4;
-						Collapsed = NO;
-						Frame = "{{0, 23}, {956, 578}}";
-						Split0 = {
-							ActiveTab = 0;
-							Collapsed = NO;
-							Frame = "{{274, 0}, {682, 578}}";
-							Split0 = {
-								Frame = "{{0, 273}, {682, 305}}";
-							};
-							SplitCount = 1;
-							Tab0 = {
-								Debugger = {
-									Collapsed = NO;
-									Frame = "{{0, 0}, {682, 267}}";
-									Split0 = {
-										Frame = "{{0, 24}, {682, 243}}";
-										Split0 = {
-											Frame = "{{0, 0}, {329, 243}}";
-										};
-										Split1 = {
-											DebugVariablesTableConfiguration = (
-												Name,
-												93.80298,
-												Value,
-												116.074,
-												Summary,
-												108.123,
-											);
-											Frame = "{{338, 0}, {344, 243}}";
-										};
-										SplitCount = 2;
-									};
-									SplitCount = 1;
-									Tab0 = {
-										Frame = "{{0, 0}, {100, 50}}";
-									};
-									Tab1 = {
-										Frame = "{{0, 0}, {100, 50}}";
-									};
-									TabCount = 2;
-									TabsVisible = YES;
-								};
-								Frame = "{{0, 0}, {682, 267}}";
-								LauncherConfigVersion = 7;
-							};
-							Tab1 = {
-								Frame = "{{0, 0}, {664, 208}}";
-								LauncherConfigVersion = 3;
-								Runner = {
-									Frame = "{{0, 0}, {664, 208}}";
-								};
-							};
-							Tab2 = {
-								BuildMessageFrame = "{{0, 0}, {666, 43}}";
-								BuildTranscriptFrame = "{{0, 52}, {666, 0}}";
-								Frame = "{{0, 0}, {664, 50}}";
-							};
-							Tab3 = {
-								Frame = "{{0, 0}, {612, 295}}";
-							};
-							TabCount = 4;
-							TabsVisible = NO;
-						};
-						SplitCount = 1;
-						Tab0 = {
-							Frame = "{{0, 0}, {313, 531}}";
-							GroupTreeTableConfiguration = (
-								TargetStatusColumn,
-								18,
-								MainColumn,
-								280,
-							);
-						};
-						Tab1 = {
-							ClassesFrame = "{{0, 0}, {280, 398}}";
-							ClassesTreeTableConfiguration = (
-								PBXBookColumnIdentifier,
-								20,
-								PBXClassColumnIdentifier,
-								237,
-							);
-							Frame = "{{0, 0}, {278, 659}}";
-							MembersFrame = "{{0, 407}, {280, 252}}";
-							MembersTreeTableConfiguration = (
-								PBXBookColumnIdentifier,
-								20,
-								PBXMethodColumnIdentifier,
-								236,
-							);
-						};
-						Tab2 = {
-							Frame = "{{0, 0}, {200, 100}}";
-						};
-						Tab3 = {
-							Frame = "{{0, 0}, {200, 557}}";
-							TargetTableConfiguration = (
-								ActiveObject,
-								16,
-								ObjectNames,
-								202.296,
-							);
-						};
-						Tab4 = {
-							BreakpointsTreeTableConfiguration = (
-								breakpointColumn,
-								197,
-								enabledColumn,
-								31,
-							);
-							Frame = "{{0, 0}, {250, 578}}";
-						};
-						TabCount = 5;
-						TabsVisible = YES;
-					};
-					StatusViewVisible = YES;
-					Template = F5CA7ECC015C09990DCA290F;
-					ToolbarVisible = YES;
-					WindowLocation = "{79, 361}";
-				},
 			);
-			PBXWorkspaceStateSaveDate = 58758807;
+			PBXWorkspaceStateSaveDate = 59271904;
 		};
 		perUserProjectItems = {
-			F562F813037E7F6101AEEDB1 = F562F813037E7F6101AEEDB1;
-			F562F814037E7F6101AEEDB1 = F562F814037E7F6101AEEDB1;
-			F562F815037E7F6101AEEDB1 = F562F815037E7F6101AEEDB1;
-			F562F816037E7F6101AEEDB1 = F562F816037E7F6101AEEDB1;
-			F562F817037E7F6101AEEDB1 = F562F817037E7F6101AEEDB1;
-			F562F818037E7F6101AEEDB1 = F562F818037E7F6101AEEDB1;
+			F562F80B037E5D2101AEEDB1 = F562F80B037E5D2101AEEDB1;
+			F5B163A5037E543A01AEEDB1 = F5B163A5037E543A01AEEDB1;
 		};
 		projectwideBuildSettings = {
@@ -1231,5 +1413,5 @@
 		name = "PSAlarmSetController.m: inAtChanged:";
 		rLen = 0;
-		rLoc = 8580;
+		rLoc = 8686;
 		rType = 0;
 		vrLen = 1674;
@@ -1241,5 +1423,5 @@
 		name = "PSAlarm.m: scheduledTimerWithTarget:selector:";
 		rLen = 0;
-		rLoc = 7029;
+		rLoc = 8289;
 		rType = 0;
 		vrLen = 822;
@@ -1271,64 +1453,18 @@
 		name = "PSAlarmsController.m: numberOfRowsInTableView:";
 		rLen = 0;
-		rLoc = 1720;
+		rLoc = 1925;
 		rType = 0;
 		vrLen = 1085;
 		vrLoc = 0;
 	};
-	F562F810037E79EE01AEEDB1 = {
-		isa = PBXSymbolicBreakpoint;
-		state = 1;
-		symbolName = "-[PSAlarmSetController awakeFromNib]";
-	};
-	F562F813037E7F6101AEEDB1 = {
-		fRef = F59DC6D40353C9E601AEEDB1;
-		isa = PBXBookmark;
-	};
-	F562F814037E7F6101AEEDB1 = {
-		fRef = F59DC6D40353C9E601AEEDB1;
+	F562F80B037E5D2101AEEDB1 = {
+		fRef = F59DC6FD0354188F01AEEDB1;
 		isa = PBXTextBookmark;
-		name = "PSAlarmSetController.m: awakeFromNib";
+		name = "NJRDateFormatter.m: initWithDateFormat:allowNaturalLanguage:";
 		rLen = 0;
-		rLoc = 2784;
+		rLoc = 6368;
 		rType = 0;
-		vrLen = 1841;
-		vrLoc = 0;
-	};
-	F562F815037E7F6101AEEDB1 = {
-		fRef = F59DC6D40353C9E601AEEDB1;
-		isa = PBXTextBookmark;
-		name = "PSAlarmSetController.m: awakeFromNib";
-		rLen = 51;
-		rLoc = 3497;
-		rType = 0;
-		vrLen = 1188;
-		vrLoc = 3010;
-	};
-	F562F816037E7F6101AEEDB1 = {
-		fRef = F5F240CC036A877301FE7503;
-		isa = PBXTextBookmark;
-		rLen = 0;
-		rLoc = 71;
-		rType = 1;
-	};
-	F562F817037E7F6101AEEDB1 = {
-		fRef = F59DC6D40353C9E601AEEDB1;
-		isa = PBXTextBookmark;
-		name = "PSAlarmSetController.m: awakeFromNib";
-		rLen = 51;
-		rLoc = 3497;
-		rType = 0;
-		vrLen = 1188;
-		vrLoc = 3010;
-	};
-	F562F818037E7F6101AEEDB1 = {
-		fRef = F5F240CC036A877301FE7503;
-		isa = PBXTextBookmark;
-		name = "NJRQTMediaPopUpButton.m: _addRecentMediaFromAliasesData:";
-		rLen = 0;
-		rLoc = 2850;
-		rType = 0;
-		vrLen = 580;
-		vrLoc = 2437;
+		vrLen = 2132;
+		vrLoc = 5663;
 	};
 	F596730D0355CFA301407038 = {
@@ -1372,4 +1508,6 @@
 			F515C769037DFB63018DB5B3,
 			F515C76A037E01E1018DB5B3,
+			F5B79835035F3A180136A8DD,
+			F5B7983A035F65070136A8DD,
 		);
 		isa = PBXBookmarkGroup;
@@ -1391,5 +1529,5 @@
 		name = "PSAlarmSetController.m: inAtChanged:";
 		rLen = 36;
-		rLoc = 8485;
+		rLoc = 8591;
 		rType = 0;
 		vrLen = 478;
@@ -1421,4 +1559,34 @@
 		symbolName = "-[NSException raise]";
 	};
+	F5B163A5037E543A01AEEDB1 = {
+		fRef = F59DC6FD0354188F01AEEDB1;
+		isa = PBXTextBookmark;
+		name = "NJRDateFormatter.m: format:withoutComponent:";
+		rLen = 0;
+		rLoc = 829;
+		rType = 0;
+		vrLen = 2132;
+		vrLoc = 5663;
+	};
+	F5B79835035F3A180136A8DD = {
+		fRef = F517D63E0356B80C016D68B9;
+		isa = PBXTextBookmark;
+		name = "PSAlarmsController.m: alarmsChanged";
+		rLen = 0;
+		rLoc = 384;
+		rType = 0;
+		vrLen = 989;
+		vrLoc = 1167;
+	};
+	F5B7983A035F65070136A8DD = {
+		fRef = F5B79836035F64F80136A8DD;
+		isa = PBXTextBookmark;
+		name = "NJRTableView.m: 1";
+		rLen = 0;
+		rLoc = 0;
+		rType = 0;
+		vrLen = 215;
+		vrLoc = 0;
+	};
 	F5F19881036B90CD01EB0372 = {
 		fRef = F59DC6D40353C9E601AEEDB1;
@@ -1426,5 +1594,5 @@
 		name = "PSAlarmSetController.m: setAlarm:";
 		rLen = 0;
-		rLoc = 12078;
+		rLoc = 12184;
 		rType = 0;
 		vrLen = 1431;
Index: /trunk/Cocoa/Pester/Source/Pester.pbproj/project.pbxproj
===================================================================
--- /trunk/Cocoa/Pester/Source/Pester.pbproj/project.pbxproj	(revision 50)
+++ /trunk/Cocoa/Pester/Source/Pester.pbproj/project.pbxproj	(revision 51)
@@ -241,6 +241,6 @@
 			productReference = 17587328FF379C6511CA2CBB;
 			productSettingsXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
-<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
-<plist version=\"1.0\">
+<!DOCTYPE plist SYSTEM \"file://localhost/System/Library/DTDs/PropertyList.dtd\">
+<plist version=\"0.9\">
 <dict>
 	<key>CFBundleDevelopmentRegion</key>
@@ -312,7 +312,8 @@
 				F5F19910036D3B3101EB0372,
 				F515C768037DFB56018DB5B3,
+				F5B79839035F64F80136A8DD,
+				F5B79868038865B30136A8DD,
 			);
 			isa = PBXHeadersBuildPhase;
-			runOnlyForDeploymentPostprocessing = 0;
 		};
 		29B97328FDCFA39411CA2CEA = {
@@ -330,5 +331,4 @@
 			);
 			isa = PBXResourcesBuildPhase;
-			runOnlyForDeploymentPostprocessing = 0;
 		};
 		29B9732BFDCFA39411CA2CEA = {
@@ -369,7 +369,8 @@
 				F5F198DB036BE75E01EB0372,
 				F5F1990F036D3B3101EB0372,
+				F5B79838035F64F80136A8DD,
+				F5B79867038865B30136A8DD,
 			);
 			isa = PBXSourcesBuildPhase;
-			runOnlyForDeploymentPostprocessing = 0;
 		};
 		29B9732CFDCFA39411CA2CEA = {
@@ -390,5 +391,4 @@
 			);
 			isa = PBXFrameworksBuildPhase;
-			runOnlyForDeploymentPostprocessing = 0;
 		};
 //290
@@ -631,8 +631,12 @@
 				F59DC6FD0354188F01AEEDB1,
 				F5F2418A036A910B01FE7503,
+				F5B79866038865B30136A8DD,
+				F5B79865038865B30136A8DD,
 				F5F1990E036D3B3101EB0372,
 				F5F1990D036D3B3101EB0372,
 				F59E4C0E036B43D2016B311C,
 				F59E4C0D036B43D2016B311C,
+				F560E30E035787BC01A4E466,
+				F560E30D035787BB01A4E466,
 				F5F198DA036BE75E01EB0372,
 				F5F198D9036BE75E01EB0372,
@@ -644,6 +648,6 @@
 		F560E314035787F901A4E466 = {
 			children = (
-				F560E30E035787BC01A4E466,
-				F560E30D035787BB01A4E466,
+				F5B79837035F64F80136A8DD,
+				F5B79836035F64F80136A8DD,
 				F552A8AB0358E8B201AEEDB1,
 				F552A8AC0358E8B201AEEDB1,
@@ -1241,4 +1245,48 @@
 			};
 		};
+		F5B79836035F64F80136A8DD = {
+			isa = PBXFileReference;
+			path = NJRTableView.m;
+			refType = 4;
+		};
+		F5B79837035F64F80136A8DD = {
+			isa = PBXFileReference;
+			path = NJRTableView.h;
+			refType = 4;
+		};
+		F5B79838035F64F80136A8DD = {
+			fileRef = F5B79836035F64F80136A8DD;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		F5B79839035F64F80136A8DD = {
+			fileRef = F5B79837035F64F80136A8DD;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		F5B79865038865B30136A8DD = {
+			isa = PBXFileReference;
+			path = "NSCharacterSet-NJRExtensions.m";
+			refType = 4;
+		};
+		F5B79866038865B30136A8DD = {
+			isa = PBXFileReference;
+			path = "NSCharacterSet-NJRExtensions.h";
+			refType = 4;
+		};
+		F5B79867038865B30136A8DD = {
+			fileRef = F5B79865038865B30136A8DD;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		F5B79868038865B30136A8DD = {
+			fileRef = F5B79866038865B30136A8DD;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
 		F5F19865036B806201EB0372 = {
 			children = (
