Index: trunk/Cocoa/Pester/Source/NJRCenteringMovieView.h
===================================================================
--- trunk/Cocoa/Pester/Source/NJRCenteringMovieView.h	(revision 60)
+++ trunk/Cocoa/Pester/Source/NJRCenteringMovieView.h	(revision 60)
@@ -0,0 +1,16 @@
+//
+//  NJRCenteringMovieView.h
+//  Pester
+//
+//  Created by Nicholas Riley on Fri Jan 03 2003.
+//  Copyright (c) 2003 Nicholas Riley. All rights reserved.
+//
+
+#import <AppKit/AppKit.h>
+
+
+@interface NJRCenteringMovieView : NSMovieView {
+
+}
+
+@end
Index: trunk/Cocoa/Pester/Source/NJRCenteringMovieView.m
===================================================================
--- trunk/Cocoa/Pester/Source/NJRCenteringMovieView.m	(revision 60)
+++ trunk/Cocoa/Pester/Source/NJRCenteringMovieView.m	(revision 60)
@@ -0,0 +1,57 @@
+//
+//  NJRCenteringMovieView.m
+//  Pester
+//
+//  Created by Nicholas Riley on Fri Jan 03 2003.
+//  Copyright (c) 2003 Nicholas Riley. All rights reserved.
+//
+
+#import "NJRCenteringMovieView.h"
+#import <QuickTime/Movies.h>
+
+@implementation NJRCenteringMovieView
+
+// from _MacTech_ December 2002, p. 76
+
+- (NSRect)movieRect;
+{
+    NSRect viewRect = [super movieRect];
+    Movie qtMovie = [[self movie] QTMovie];
+    Rect movieRect = {0, 0, 0, 0};
+
+    GetMovieNaturalBoundsRect(qtMovie, &movieRect);
+
+    float movieWidth = movieRect.right - movieRect.left;
+    float movieHeight = movieRect.bottom - movieRect.top;
+
+    if ( (movieWidth <= viewRect.size.width) &&
+         (movieHeight <= viewRect.size.height) ) {
+        // Movie is smaller than or equal to the view size; just center the movie
+        viewRect.origin.y += (int)((viewRect.size.height - movieHeight) / 2.);
+        viewRect.size.height = movieHeight;
+
+        viewRect.origin.x += (int)((viewRect.size.width - movieWidth) / 2.);
+        viewRect.size.width = movieWidth;
+    } else {
+        // We need to scale down movie, centering horizontally and vertically
+        float movieRatio = movieWidth / (float)movieHeight;
+        float viewRatio = viewRect.size.width / viewRect.size.height;
+
+        if (movieRatio > viewRatio) {
+            // Movie is wider than will fit; rescale.
+            float newHeight = viewRect.size.width / movieRatio;
+
+            viewRect.origin.y += (int)((viewRect.size.height - newHeight) / 2.);
+            viewRect.size.height = newHeight;
+        } else {
+            // Movie is taller than will fit (or has the ideal aspect ratio); rescale.
+            float newWidth = viewRect.size.height * movieRatio;
+
+            viewRect.origin.x += (int) ((viewRect.size.width - newWidth) / 2.);
+            viewRect.size.width = newWidth;
+        }
+    }
+    return viewRect;
+}
+
+@end
Index: trunk/Cocoa/Pester/Source/NJRQTMediaPopUpButton.m
===================================================================
--- trunk/Cocoa/Pester/Source/NJRQTMediaPopUpButton.m	(revision 59)
+++ trunk/Cocoa/Pester/Source/NJRQTMediaPopUpButton.m	(revision 60)
@@ -11,4 +11,5 @@
 #import "NSMovie-NJRExtensions.h"
 #import "NSImage-NJRExtensions.h"
+#import <QuickTime/Movies.h>
 
 // XXX workaround for SoundFileManager log message in 10.2.3 and earlier
@@ -275,4 +276,13 @@
 }
 
+void
+MovieStoppedCB(QTCallBack cb, long refCon)
+{
+    NSMovieView *preview = (NSMovieView *)refCon;
+    // if we donÕt do this after the runloop has finished, then we crash in MCIdle because itÕs expecting a movie and doesnÕt have one any more
+    [preview performSelector: @selector(setMovie:) withObject: nil afterDelay: 0]; // otherwise we get an extra runloop timer which uses a lot of CPU from +[NSMovieView _idleMovies]
+    DisposeCallBack(cb);
+}
+
 - (BOOL)_validateWithPreview:(BOOL)doPreview;
 {
@@ -285,7 +295,7 @@
         NSMovie *movie = [[NSMovie alloc] initWithURL: [NSURL fileURLWithPath: [selectedAlias fullPath]] byReference: YES];
         movieCanRepeat = ![movie isStatic];
-        if ([movie hasAudio])
-            [preview setMovie: movie];
-        else {
+        if ([movie hasAudio]) {
+            [preview setMovie: doPreview ? movie : nil];
+        } else {
             [preview setMovie: nil];
             if (movie == nil) {
@@ -301,6 +311,16 @@
             }
         }
+        if (doPreview) {
+            Movie qtMovie = [movie QTMovie];
+            QTCallBack cbStop = NewCallBack(GetMovieTimeBase(qtMovie), callBackAtExtremes);
+            QTCallBackUPP cbStopUPP = NewQTCallBackUPP(MovieStoppedCB);
+            OSErr err = CallMeWhen(cbStop, cbStopUPP, (long)preview, triggerAtStop, 0, 0);
+            if (err != noErr) {
+                NSLog(@"CanÕt register QuickTime stop timebase callback for preview: %ld", err);
+                DisposeCallBack(cbStop);
+            }
+            [preview start: self];
+        }
         [movie release];
-        if (doPreview) [preview start: self];
     }
     [[NSNotificationCenter defaultCenter] postNotificationName: NJRQTMediaPopUpButtonMovieChangedNotification object: self];
@@ -313,4 +333,5 @@
 {
     [preview stop: self];
+    [preview setMovie: nil]; // otherwise we get an extra runloop timer which uses a lot of CPU from +[NSMovieView _idleMovies]
 }
 
Index: trunk/Cocoa/Pester/Source/NJRVoicePopUpButton.m
===================================================================
--- trunk/Cocoa/Pester/Source/NJRVoicePopUpButton.m	(revision 59)
+++ trunk/Cocoa/Pester/Source/NJRVoicePopUpButton.m	(revision 60)
@@ -8,6 +8,4 @@
 
 #import "NJRVoicePopUpButton.h"
-
-// XXX says nothing instead of "Alarm!" any more if there's no alarm message specified
 
 @implementation NJRVoicePopUpButton
Index: trunk/Cocoa/Pester/Source/NSImage-NJRExtensions.h
===================================================================
--- trunk/Cocoa/Pester/Source/NSImage-NJRExtensions.h	(revision 59)
+++ trunk/Cocoa/Pester/Source/NSImage-NJRExtensions.h	(revision 60)
@@ -4,5 +4,5 @@
 //
 //  Created by Nicholas Riley on Mon Oct 28 2002.
-//  Copyright (c) 2002 __MyCompanyName__. All rights reserved.
+//  Copyright (c) 2002 Nicholas Riley. All rights reserved.
 //
 
Index: trunk/Cocoa/Pester/Source/NSImage-NJRExtensions.m
===================================================================
--- trunk/Cocoa/Pester/Source/NSImage-NJRExtensions.m	(revision 59)
+++ trunk/Cocoa/Pester/Source/NSImage-NJRExtensions.m	(revision 60)
@@ -4,5 +4,5 @@
 //
 //  Created by Nicholas Riley on Mon Oct 28 2002.
-//  Copyright (c) 2002 __MyCompanyName__. All rights reserved.
+//  Copyright (c) 2002 Nicholas Riley. All rights reserved.
 //
 
Index: trunk/Cocoa/Pester/Source/PSAlarmSetController.m
===================================================================
--- trunk/Cocoa/Pester/Source/PSAlarmSetController.m	(revision 59)
+++ trunk/Cocoa/Pester/Source/PSAlarmSetController.m	(revision 60)
@@ -67,4 +67,5 @@
 {
     NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
+    NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
     alarm = [[PSAlarm alloc] init];
     [[self window] center];
@@ -119,6 +120,8 @@
     [self editAlertChanged: nil];
     [script setFileTypes: [NSArray arrayWithObjects: @"applescript", @"script", NSFileTypeForHFSTypeCode(kOSAFileType), NSFileTypeForHFSTypeCode('TEXT'), nil]];
-    [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(silence:) name: PSAlarmAlertStopNotification object: nil];
-    [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(playSoundChanged:) name: NJRQTMediaPopUpButtonMovieChangedNotification object: sound];
+    [notificationCenter addObserver: self selector: @selector(silence:) name: PSAlarmAlertStopNotification object: nil];
+    [notificationCenter addObserver: self selector: @selector(playSoundChanged:) name: NJRQTMediaPopUpButtonMovieChangedNotification object: sound];
+    [notificationCenter addObserver: self selector: @selector(applicationWillHide:) name: NSApplicationWillHideNotification object: NSApp];
+    [notificationCenter addObserver: self selector: @selector(applicationDidUnhide:) name: NSApplicationDidUnhideNotification object: NSApp];
     [voice setDelegate: self]; // XXX why don't we do this in IB?  It should use the accessor...
     [wakeUp setEnabled: [PSPowerManager autoWakeSupported]];
@@ -519,2 +522,23 @@
 
 @end
+
+@implementation PSAlarmSetController (NSApplicationNotifications)
+
+- (void)applicationWillHide:(NSNotification *)notification;
+{
+    if ([[self window] isVisible]) {
+        NSLog(@"hide");
+        [self silence: nil];
+        [self _stopUpdateTimer];
+    }
+}
+
+- (void)applicationDidUnhide:(NSNotification *)notification;
+{
+    if ([[self window] isVisible]) {
+        NSLog(@"unhide");
+        [self update: self];
+    }
+}
+
+@end
Index: trunk/Cocoa/Pester/Source/PSAlarms.h
===================================================================
--- trunk/Cocoa/Pester/Source/PSAlarms.h	(revision 59)
+++ trunk/Cocoa/Pester/Source/PSAlarms.h	(revision 60)
@@ -37,3 +37,5 @@
 - (void)removeAlarms:(NSSet *)alarmsToRemove;
 
+- (BOOL)alarmsExpiring;
+
 @end
Index: trunk/Cocoa/Pester/Source/PSAlarms.m
===================================================================
--- trunk/Cocoa/Pester/Source/PSAlarms.m	(revision 59)
+++ trunk/Cocoa/Pester/Source/PSAlarms.m	(revision 60)
@@ -206,4 +206,9 @@
     }
     [self removeAlarmsAtIndices: indices];
+}
+
+- (BOOL)alarmsExpiring;
+{
+    return [expiredAlarms count] != 0;
 }
 
Index: trunk/Cocoa/Pester/Source/PSApplication.m
===================================================================
--- trunk/Cocoa/Pester/Source/PSApplication.m	(revision 59)
+++ trunk/Cocoa/Pester/Source/PSApplication.m	(revision 60)
@@ -153,5 +153,5 @@
 - (BOOL)applicationShouldHandleReopen:(NSApplication *)sender hasVisibleWindows:(BOOL)flag;
 {
-    if (!flag) [alarmSetController showWindow: self];
+    if (!flag && ![[PSAlarms allAlarms] alarmsExpiring]) [alarmSetController showWindow: self];
     return YES;
 }
Index: trunk/Cocoa/Pester/Source/PSMovieAlert.m
===================================================================
--- trunk/Cocoa/Pester/Source/PSMovieAlert.m	(revision 59)
+++ trunk/Cocoa/Pester/Source/PSMovieAlert.m	(revision 60)
@@ -35,4 +35,5 @@
         alias = [anAlias retain];
         repetitions = numReps;
+        // XXX if we support remote movie URLs, need to call EnterMovies() ourselves at least in Jaguar (_MacTech_ December 2002, p. 64); also should do async movie loading (p. 73Ð74).
         movie = [[NSMovie alloc] initWithURL: [NSURL fileURLWithPath: path] byReference: YES];
         if (movie == nil) {
Index: trunk/Cocoa/Pester/Source/PSMovieAlertController.m
===================================================================
--- trunk/Cocoa/Pester/Source/PSMovieAlertController.m	(revision 59)
+++ trunk/Cocoa/Pester/Source/PSMovieAlertController.m	(revision 60)
@@ -12,6 +12,4 @@
 #import "NSMovie-NJRExtensions.h"
 #import <QuickTime/Movies.h>
-
-// XXX if you specify a truly tiny movie, obey the minimum window size to compensate
 
 @implementation PSMovieAlertController
@@ -36,4 +34,5 @@
     }
     delay = (GetMovieDuration((Movie)theMovie) - GetMovieTime((Movie)theMovie, NULL)) / (double)GetMovieTimeScale((Movie)theMovie);
+    // XXX should use a timebase callback for this instead (see NJRQTMediaPopUpButton); also, use QuickTimeÕs built-in loop functionality instead of rolling our own?
     [self performSelector: @selector(play) withObject: nil afterDelay: delay inModes: [NSArray arrayWithObject: NSDefaultRunLoopMode]];
 }
@@ -52,6 +51,9 @@
             float magnification = 1.0;
             NSSize movieSize;
+            NSSize minSize = [window minSize];
+            float windowFrameHeight = [window frame].size.height - [[window contentView] frame].size.height;
             NSRect frame;
-            screenRect.size.height -= [window frame].size.height - [[window contentView] frame].size.height; // account for height of window frame
+            screenRect.size.height -= windowFrameHeight;
+            minSize.height -= windowFrameHeight;
             while (1) {
                 movieSize = [movieView sizeForMagnification: magnification];
@@ -62,4 +64,6 @@
                     break;
             }
+            if (movieSize.width < minSize.width) movieSize.width = minSize.width;
+            if (movieSize.height < minSize.height) movieSize.width = minSize.height;
             [window setContentSize: movieSize];
             [window center];
Index: trunk/Cocoa/Pester/Source/PSScriptAlert.m
===================================================================
--- trunk/Cocoa/Pester/Source/PSScriptAlert.m	(revision 59)
+++ trunk/Cocoa/Pester/Source/PSScriptAlert.m	(revision 60)
@@ -9,5 +9,4 @@
 #import "PSScriptAlert.h"
 #import "BDAlias.h"
-// XXX remove #import "NDAppleScriptObject.h"
 #import "NSDictionary-NJRExtensions.h"
 
Index: trunk/Cocoa/Pester/Source/Pester.pbproj/nicholas.pbxuser
===================================================================
--- trunk/Cocoa/Pester/Source/Pester.pbproj/nicholas.pbxuser	(revision 59)
+++ trunk/Cocoa/Pester/Source/Pester.pbproj/nicholas.pbxuser	(revision 60)
@@ -22,5 +22,5 @@
 		);
 		perUserDictionary = {
-			PBXPerProjectTemplateStateSaveDate = 63172038;
+			PBXPerProjectTemplateStateSaveDate = 63490351;
 			"PBXTemplateGeometry-F5CA7ECB015C094F0DCA290F" = {
 				ContentSize = "{668, 621}";
@@ -147,5 +147,135 @@
 				Template = F5CA7ECB015C094F0DCA290F;
 				ToolbarVisible = NO;
-				WindowLocation = "{420, 75}";
+				WindowLocation = "{48, 189}";
+			};
+			"PBXTemplateGeometry-F5CA7ECC015C09990DCA290F" = {
+				ContentSize = "{773, 558}";
+				LeftSlideOut = {
+					Collapsed = NO;
+					Frame = "{{0, 23}, {773, 535}}";
+					Split0 = {
+						ActiveTab = 0;
+						ActiveTabName = PBXDebugSessionModule;
+						Collapsed = NO;
+						Frame = "{{24, 0}, {749, 535}}";
+						Split0 = {
+							Frame = "{{0, 334}, {749, 201}}";
+						};
+						SplitCount = 1;
+						Tab0 = {
+							Frame = "{{0, 0}, {749, 267}}";
+						};
+						Tab1 = {
+							Debugger = {
+								ActiveTab = 0;
+								ActiveTabName = PBXDebugCLIModule;
+								Collapsed = NO;
+								Frame = "{{0, 0}, {749, 328}}";
+								Split0 = {
+									Frame = "{{0, 73}, {749, 255}}";
+									Split0 = {
+										Frame = "{{0, 0}, {367, 255}}";
+									};
+									Split1 = {
+										DebugVariablesTableConfiguration = (
+											Name,
+											123,
+											Value,
+											85,
+											Summary,
+											139.123,
+										);
+										Frame = "{{376, 0}, {373, 255}}";
+									};
+									SplitCount = 2;
+								};
+								SplitCount = 1;
+								Tab0 = {
+									Frame = "{{0, 0}, {749, 50}}";
+								};
+								Tab1 = {
+									Frame = "{{0, 0}, {749, 49}}";
+								};
+								TabCount = 2;
+								TabsVisible = YES;
+							};
+							Frame = "{{0, 0}, {749, 328}}";
+							LauncherConfigVersion = 7;
+						};
+						Tab2 = {
+							Frame = "{{0, 0}, {664, 50}}";
+							LauncherConfigVersion = 3;
+							Runner = {
+								Frame = "{{0, 0}, {664, 50}}";
+							};
+						};
+						Tab3 = {
+							BuildMessageFrame = "{{0, 0}, {614, 262}}";
+							BuildTranscriptFrame = "{{0, 271}, {614, 2}}";
+							BuildTranscriptFrameExpanded = YES;
+							Frame = "{{0, 0}, {612, 295}}";
+						};
+						Tab4 = {
+							Frame = "{{0, 0}, {612, 295}}";
+						};
+						TabCount = 5;
+						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 = YES;
+				};
+				NavBarShownByDefault = YES;
+				StatusViewVisible = YES;
+				Template = F5CA7ECC015C09990DCA290F;
+				ToolbarVisible = YES;
+				WindowLocation = "{436, 82}";
 			};
 			PBXWorkspaceContents = (
@@ -1703,5 +1833,5 @@
 				},
 			);
-			PBXWorkspaceStateSaveDate = 63172038;
+			PBXWorkspaceStateSaveDate = 63490351;
 		};
 		perUserProjectItems = {
@@ -2296,5 +2426,5 @@
 		name = "PSAlarmSetController.m: 505";
 		rLen = 0;
-		rLoc = 22304;
+		rLoc = 22635;
 		rType = 0;
 		vrLen = 301;
@@ -2316,5 +2446,5 @@
 		name = "PSAlarmSetController.m: 489";
 		rLen = 0;
-		rLoc = 21925;
+		rLoc = 22256;
 		rType = 0;
 		vrLen = 1118;
@@ -2324,18 +2454,4 @@
 		isa = PBXTargetBookmark;
 		trg = 29B97326FDCFA39411CA2CEA;
-		uiCtxt = {
-			TOCViewDetailVisibleRect = "{{0, 0}, {467, 233}}";
-			TOCViewExpandedItems = (
-				"com.apple.target-editor-pane.settings",
-				"com.apple.target-editor-pane.settings.simple",
-				"com.apple.target-editor-pane.info-plist",
-				"com.apple.target-editor-pane.info-plist.simple",
-				"com.apple.target-editor-pane.buildphases",
-			);
-			TOCViewMasterVisibleRect = "{{0, 0}, {183, 581}}";
-			TOCViewSelectedItems = (
-				PBXTargetSummarySettingsModule,
-			);
-		};
 	};
 	E1096EC303C3F504009B92C1 = {
@@ -2344,5 +2460,5 @@
 		name = "PSAlarmSetController.m: 505";
 		rLen = 0;
-		rLoc = 22304;
+		rLoc = 22635;
 		rType = 0;
 		vrLen = 301;
@@ -2364,5 +2480,5 @@
 		name = "PSAlarmSetController.m: 489";
 		rLen = 0;
-		rLoc = 21925;
+		rLoc = 22256;
 		rType = 0;
 		vrLen = 1144;
@@ -2378,5 +2494,5 @@
 		fileReference = F59DC6D40353C9E601AEEDB1;
 		isa = PBXFileBreakpoint;
-		lineNumber = 477;
+		lineNumber = 480;
 		state = 1;
 	};
@@ -2394,5 +2510,5 @@
 		fileReference = F59DC6D40353C9E601AEEDB1;
 		isa = PBXFileBreakpoint;
-		lineNumber = 502;
+		lineNumber = 505;
 		state = 1;
 	};
@@ -2714,5 +2830,5 @@
 		name = "PSAlarms.m: 244";
 		rLen = 0;
-		rLoc = 7594;
+		rLoc = 7662;
 		rType = 0;
 		vrLen = 1412;
@@ -2914,5 +3030,5 @@
 		name = "PSMovieAlert.m: 61";
 		rLen = 0;
-		rLoc = 1644;
+		rLoc = 1829;
 		rType = 0;
 		vrLen = 1158;
@@ -2924,5 +3040,5 @@
 		name = "PSMovieAlertController.m: delay";
 		rLen = 0;
-		rLoc = 664;
+		rLoc = 578;
 		rType = 0;
 		vrLen = 1660;
@@ -3004,5 +3120,5 @@
 		name = "PSAlarmSetController.m: 513";
 		rLen = 0;
-		rLoc = 22685;
+		rLoc = 23016;
 		rType = 0;
 		vrLen = 1154;
@@ -3084,5 +3200,5 @@
 		name = "PSAlarmSetController.m: 510";
 		rLen = 0;
-		rLoc = 22661;
+		rLoc = 22992;
 		rType = 0;
 		vrLen = 1204;
@@ -3104,5 +3220,5 @@
 		name = "PSAlarmSetController.m: 513";
 		rLen = 0;
-		rLoc = 22685;
+		rLoc = 23016;
 		rType = 0;
 		vrLen = 1154;
@@ -3236,5 +3352,5 @@
 		rLoc = 532;
 		rType = 0;
-		vrLen = 697;
+		vrLen = 695;
 		vrLoc = 0;
 	};
@@ -3304,5 +3420,5 @@
 		name = "PSMovieAlert.m: 61";
 		rLen = 0;
-		rLoc = 1644;
+		rLoc = 1829;
 		rType = 0;
 		vrLen = 1158;
@@ -3394,5 +3510,5 @@
 		name = "PSMovieAlertController.m: delay";
 		rLen = 0;
-		rLoc = 664;
+		rLoc = 578;
 		rType = 0;
 		vrLen = 1660;
@@ -3524,5 +3640,5 @@
 		name = "PSAlarmSetController.m: 513";
 		rLen = 0;
-		rLoc = 22685;
+		rLoc = 23016;
 		rType = 0;
 		vrLen = 1154;
@@ -3664,5 +3780,5 @@
 		name = "PSAlarmSetController.m: 513";
 		rLen = 0;
-		rLoc = 22685;
+		rLoc = 23016;
 		rType = 0;
 		vrLen = 1154;
@@ -5041,5 +5157,5 @@
 		name = "PSMovieAlertController.m: windowWillClose:";
 		rLen = 0;
-		rLoc = 4368;
+		rLoc = 4730;
 		rType = 0;
 		vrLen = 1986;
@@ -5061,5 +5177,5 @@
 		name = "PSMovieAlertController.m: windowWillClose:";
 		rLen = 0;
-		rLoc = 4181;
+		rLoc = 4543;
 		rType = 0;
 		vrLen = 1994;
@@ -5081,5 +5197,5 @@
 		name = "PSMovieAlertController.m: dealloc";
 		rLen = 0;
-		rLoc = 3878;
+		rLoc = 4240;
 		rType = 0;
 		vrLen = 2014;
@@ -5592,5 +5708,5 @@
 		name = "PSMovieAlertController.m: controllerWithAlarm:movieAlert:";
 		rLen = 0;
-		rLoc = 621;
+		rLoc = 535;
 		rType = 0;
 		vrLen = 1544;
@@ -6020,5 +6136,5 @@
 		name = "NJRQTMediaPopUpButton.m: 181";
 		rLen = 0;
-		rLoc = 6701;
+		rLoc = 6730;
 		rType = 0;
 		vrLen = 952;
@@ -6060,5 +6176,5 @@
 		name = "PSMovieAlertController.m: 92";
 		rLen = 0;
-		rLoc = 3878;
+		rLoc = 4240;
 		rType = 0;
 		vrLen = 1703;
@@ -6080,5 +6196,5 @@
 		name = "PSMovieAlertController.m: 105";
 		rLen = 0;
-		rLoc = 4196;
+		rLoc = 4558;
 		rType = 0;
 		vrLen = 1707;
@@ -6090,5 +6206,5 @@
 		name = "NJRQTMediaPopUpButton.m: ";
 		rLen = 0;
-		rLoc = 4123;
+		rLoc = 4152;
 		rType = 0;
 		vrLen = 1323;
@@ -6179,5 +6295,5 @@
 		name = "NJRQTMediaPopUpButton.m: ";
 		rLen = 0;
-		rLoc = 6837;
+		rLoc = 6866;
 		rType = 0;
 		vrLen = 1590;
@@ -6229,5 +6345,5 @@
 		name = "NJRQTMediaPopUpButton.m: 259";
 		rLen = 0;
-		rLoc = 9493;
+		rLoc = 9522;
 		rType = 0;
 		vrLen = 1353;
@@ -6249,5 +6365,5 @@
 		name = "NJRQTMediaPopUpButton.m: ";
 		rLen = 0;
-		rLoc = 6312;
+		rLoc = 6341;
 		rType = 0;
 		vrLen = 960;
@@ -6279,5 +6395,5 @@
 		name = "NJRQTMediaPopUpButton.m: ";
 		rLen = 0;
-		rLoc = 6837;
+		rLoc = 6866;
 		rType = 0;
 		vrLen = 1590;
@@ -8189,3 +8305,17 @@
 		symbolName = "-[NSException raise]";
 	};
+	F5F19866036B80AF01EB0372 = {
+		fileEncoding = 30;
+		isa = PBXFileReference;
+		name = SUSpeaker.h;
+		path = /Users/nicholas/Documents/Development/Cocoa/Pester/Source/SUSpeaker.h;
+		refType = 0;
+	};
+	F5F19867036B80AF01EB0372 = {
+		fileEncoding = 30;
+		isa = PBXFileReference;
+		name = SUSpeaker.m;
+		path = /Users/nicholas/Documents/Development/Cocoa/Pester/Source/SUSpeaker.m;
+		refType = 0;
+	};
 }
Index: trunk/Cocoa/Pester/Source/Pester.pbproj/project.pbxproj
===================================================================
--- trunk/Cocoa/Pester/Source/Pester.pbproj/project.pbxproj	(revision 59)
+++ trunk/Cocoa/Pester/Source/Pester.pbproj/project.pbxproj	(revision 60)
@@ -328,9 +328,10 @@
 				F59E4BE9036B2E5E016B311C,
 				F5F1986F036B813101EB0372,
-				F5F19868036B80AF01EB0372,
 				F5F2418B036A910B01FE7503,
 				E130B9AE03B7C59700000028,
 				E13919E403B9E4E100000028,
 				E1ECA00803C002B300F54C66,
+				E1D358BB03C60CE900C8A18E,
+				E1E9A33C03C8EF6700050002,
 			);
 			isa = PBXHeadersBuildPhase;
@@ -392,8 +393,9 @@
 				F59E4BE8036B2E5E016B311C,
 				E1A18CB103B439AD00000028,
-				F5F19869036B80AF01EB0372,
 				29B9732CFDCFA39411CA2CEA,
 				E13919E503B9E4E100000028,
 				E1ECA00903C002B300F54C66,
+				E1D358BC03C60CE900C8A18E,
+				E1E9A33B03C8EF6700050002,
 			);
 			isa = PBXSourcesBuildPhase;
@@ -689,4 +691,61 @@
 			};
 		};
+		E1D358B903C60CE900C8A18E = {
+			fileEncoding = 4;
+			isa = PBXFileReference;
+			path = NJRCenteringMovieView.h;
+			refType = 4;
+		};
+		E1D358BA03C60CE900C8A18E = {
+			fileEncoding = 4;
+			isa = PBXFileReference;
+			path = NJRCenteringMovieView.m;
+			refType = 4;
+		};
+		E1D358BB03C60CE900C8A18E = {
+			fileRef = E1D358B903C60CE900C8A18E;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		E1D358BC03C60CE900C8A18E = {
+			fileRef = E1D358BA03C60CE900C8A18E;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		E1E9A33903C8EF6700050002 = {
+			fileEncoding = 30;
+			isa = PBXFileReference;
+			path = SUSpeaker.m;
+			refType = 4;
+		};
+		E1E9A33A03C8EF6700050002 = {
+			fileEncoding = 30;
+			isa = PBXFileReference;
+			path = SUSpeaker.h;
+			refType = 4;
+		};
+		E1E9A33B03C8EF6700050002 = {
+			fileRef = E1E9A33903C8EF6700050002;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		E1E9A33C03C8EF6700050002 = {
+			fileRef = E1E9A33A03C8EF6700050002;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		E1E9A33D03C8EF6800050002 = {
+			children = (
+				E1E9A33903C8EF6700050002,
+				E1E9A33A03C8EF6700050002,
+			);
+			isa = PBXGroup;
+			name = SpeechUtilities;
+			refType = 4;
+		};
 		E1ECA00603C002B300F54C66 = {
 			fileEncoding = 4;
@@ -973,5 +1032,5 @@
 		F560E313035787ED01A4E466 = {
 			children = (
-				F5F19865036B806201EB0372,
+				E1E9A33D03C8EF6800050002,
 				F59E47A6036AA5FC016B311C,
 				E1ECA00603C002B300F54C66,
@@ -991,4 +1050,6 @@
 		F560E314035787F901A4E466 = {
 			children = (
+				E1D358B903C60CE900C8A18E,
+				E1D358BA03C60CE900C8A18E,
 				E1F0B14A03AD8CEF00AEFBE0,
 				E1F0B14B03AD8CEF00AEFBE0,
@@ -1583,38 +1644,4 @@
 			};
 		};
-		F5F19865036B806201EB0372 = {
-			children = (
-				F5F19866036B80AF01EB0372,
-				F5F19867036B80AF01EB0372,
-			);
-			isa = PBXGroup;
-			name = SpeechUtilities;
-			path = NDAppleScript;
-			refType = 4;
-		};
-		F5F19866036B80AF01EB0372 = {
-			fileEncoding = 30;
-			isa = PBXFileReference;
-			path = SUSpeaker.h;
-			refType = 2;
-		};
-		F5F19867036B80AF01EB0372 = {
-			fileEncoding = 30;
-			isa = PBXFileReference;
-			path = SUSpeaker.m;
-			refType = 2;
-		};
-		F5F19868036B80AF01EB0372 = {
-			fileRef = F5F19866036B80AF01EB0372;
-			isa = PBXBuildFile;
-			settings = {
-			};
-		};
-		F5F19869036B80AF01EB0372 = {
-			fileRef = F5F19867036B80AF01EB0372;
-			isa = PBXBuildFile;
-			settings = {
-			};
-		};
 		F5F1986C036B813101EB0372 = {
 			fileEncoding = 30;
