Commits

Jens Alfke committed 23caa06

* Use MYUtilities, including its build settings and improved logging / exception / error support.
* Use MYUtilities versions of HgTask and DirectoryWatcher.
* Added Credits.rtf, with contributor names, for display in About box.
* HgRepository uses full mode when getting log of a smallish number of revisions; this speeds it back up with non-huge repos.

Comments (0)

Files changed (31)

English.lproj/Credits.rtf

Binary file added.
+{\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf430
+{\fonttbl\f0\fnil\fcharset0 LucidaGrande;}
+{\colortbl;\red255\green255\blue255;\red102\green102\blue102;}
+{\info
+{\author Jens Alfke}}\margl1440\margr1440\vieww9600\viewh12000\viewkind0
+\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\qc\pardirnatural
+
+\f0\fs22 \cf0 by 
+\b Jens Alfke
+\b0 \
+\cf2 with contributions from:\cf0 \
+
+\b Benjamin\'a0Bock \'97 Peter\'a0Hosey \'97 Ryan\'a0Wilcox
+\b0  \'97 
+\b aias2
+\b0 \
+\
+This application is open source; get involved!\
+{\field{\*\fldinst{HYPERLINK "http://bitbucket.org/snej/murky/wiki/Home"}}{\fldrslt Source code}}\
+{\field{\*\fldinst{HYPERLINK "http://bitbucket.org/snej/murky/issues/?status=new&status=open"}}{\fldrslt Issue tracker}}\
+}

Murky.xcodeproj/project.pbxproj

 		277C51C20C56709800E60690 /* ImageAndTextCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 277C51C10C56709800E60690 /* ImageAndTextCell.m */; };
 		277C52120C56761000E60690 /* HgOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 277C52110C56761000E60690 /* HgOperation.m */; };
 		277C52D80C56871C00E60690 /* Repo.nib in Resources */ = {isa = PBXBuildFile; fileRef = 277C52D60C56871C00E60690 /* Repo.nib */; };
-		277D16A50C989182001D8600 /* RegEx.m in Sources */ = {isa = PBXBuildFile; fileRef = 277D16A40C989182001D8600 /* RegEx.m */; };
 		277D16B90C989715001D8600 /* libicucore.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 277D16B80C989715001D8600 /* libicucore.dylib */; };
-		277D19260C9B2E63001D8600 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; };
-		278CA6150C9B399500BD5484 /* DirectoryWatcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 278CA6140C9B399500BD5484 /* DirectoryWatcher.m */; };
 		27A6B63F0CAC254500482D5D /* RepoController_Actions.m in Sources */ = {isa = PBXBuildFile; fileRef = 27A6B63E0CAC254500482D5D /* RepoController_Actions.m */; };
+		27AA81BC0FADF65500D4FCBB /* CollectionUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 27AA81B50FADF65500D4FCBB /* CollectionUtils.m */; };
+		27AA81BD0FADF65500D4FCBB /* ExceptionUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 27AA81B70FADF65500D4FCBB /* ExceptionUtils.m */; };
+		27AA81BE0FADF65500D4FCBB /* Logging.m in Sources */ = {isa = PBXBuildFile; fileRef = 27AA81B90FADF65500D4FCBB /* Logging.m */; };
+		27AA81BF0FADF65500D4FCBB /* Test.m in Sources */ = {isa = PBXBuildFile; fileRef = 27AA81BB0FADF65500D4FCBB /* Test.m */; };
+		27AA81C70FADF83000D4FCBB /* MYUtilities_Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 27AA81C50FADF83000D4FCBB /* MYUtilities_Debug.xcconfig */; };
+		27AA81C80FADF83000D4FCBB /* MYUtilities_Release.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 27AA81C60FADF83000D4FCBB /* MYUtilities_Release.xcconfig */; };
 		27B042D40CA9A1390090DC04 /* RevisionGraphColumn.m in Sources */ = {isa = PBXBuildFile; fileRef = 27B042D30CA9A1390090DC04 /* RevisionGraphColumn.m */; };
+		27C656880FAE01A200CFB909 /* MYErrorUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 27C656850FAE01A200CFB909 /* MYErrorUtils.m */; };
+		27C656890FAE01A200CFB909 /* MYTask.m in Sources */ = {isa = PBXBuildFile; fileRef = 27C656870FAE01A200CFB909 /* MYTask.m */; };
+		27C656B90FAE046B00CFB909 /* MYDirectoryWatcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 27C656B70FAE046B00CFB909 /* MYDirectoryWatcher.m */; };
+		27C656FD0FAE0DC100CFB909 /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 27C656FB0FAE0DC100CFB909 /* Credits.rtf */; };
 		27D124F60C8F501B0075446A /* URLFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = 27D124F50C8F501B0075446A /* URLFormatter.m */; };
 		27D918810C890F5500D53A8D /* xmlminimal.style in Resources */ = {isa = PBXBuildFile; fileRef = 27D918800C890F5500D53A8D /* xmlminimal.style */; };
-		27DEDBA30C85DE8A00A713A9 /* HgTask.m in Sources */ = {isa = PBXBuildFile; fileRef = 27DEDBA20C85DE8A00A713A9 /* HgTask.m */; };
 		8D11072A0486CEB800E47090 /* MainMenu.nib in Resources */ = {isa = PBXBuildFile; fileRef = 29B97318FDCFA39411CA2CEA /* MainMenu.nib */; };
 		8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */; };
 		8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; };
 		277C52100C56761000E60690 /* HgOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HgOperation.h; sourceTree = "<group>"; };
 		277C52110C56761000E60690 /* HgOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HgOperation.m; sourceTree = "<group>"; };
 		277C52D70C56871C00E60690 /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = English.lproj/Repo.nib; sourceTree = SOURCE_ROOT; };
-		277D16A30C989182001D8600 /* RegEx.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RegEx.h; sourceTree = "<group>"; };
-		277D16A40C989182001D8600 /* RegEx.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RegEx.m; sourceTree = "<group>"; };
 		277D16B80C989715001D8600 /* libicucore.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libicucore.dylib; path = /usr/lib/libicucore.dylib; sourceTree = "<absolute>"; };
-		277D18720C9B1AD9001D8600 /* RegExTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RegExTest.h; sourceTree = "<group>"; };
-		277D18730C9B1AD9001D8600 /* RegExTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RegExTest.m; sourceTree = "<group>"; };
-		278CA6130C9B399500BD5484 /* DirectoryWatcher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DirectoryWatcher.h; sourceTree = "<group>"; };
-		278CA6140C9B399500BD5484 /* DirectoryWatcher.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DirectoryWatcher.m; sourceTree = "<group>"; };
 		27A6B63E0CAC254500482D5D /* RepoController_Actions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RepoController_Actions.m; sourceTree = "<group>"; };
+		27AA81A50FADF53100D4FCBB /* README.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README.txt; sourceTree = "<group>"; };
+		27AA81B40FADF65500D4FCBB /* CollectionUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CollectionUtils.h; sourceTree = "<group>"; };
+		27AA81B50FADF65500D4FCBB /* CollectionUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CollectionUtils.m; sourceTree = "<group>"; };
+		27AA81B60FADF65500D4FCBB /* ExceptionUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ExceptionUtils.h; sourceTree = "<group>"; };
+		27AA81B70FADF65500D4FCBB /* ExceptionUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ExceptionUtils.m; sourceTree = "<group>"; };
+		27AA81B80FADF65500D4FCBB /* Logging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Logging.h; sourceTree = "<group>"; };
+		27AA81B90FADF65500D4FCBB /* Logging.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Logging.m; sourceTree = "<group>"; };
+		27AA81BA0FADF65500D4FCBB /* Test.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Test.h; sourceTree = "<group>"; };
+		27AA81BB0FADF65500D4FCBB /* Test.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Test.m; sourceTree = "<group>"; };
+		27AA81C50FADF83000D4FCBB /* MYUtilities_Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = MYUtilities_Debug.xcconfig; sourceTree = "<group>"; };
+		27AA81C60FADF83000D4FCBB /* MYUtilities_Release.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = MYUtilities_Release.xcconfig; sourceTree = "<group>"; };
 		27B042D20CA9A1390090DC04 /* RevisionGraphColumn.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RevisionGraphColumn.h; sourceTree = "<group>"; };
 		27B042D30CA9A1390090DC04 /* RevisionGraphColumn.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RevisionGraphColumn.m; sourceTree = "<group>"; };
+		27C656840FAE01A200CFB909 /* MYErrorUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYErrorUtils.h; sourceTree = "<group>"; };
+		27C656850FAE01A200CFB909 /* MYErrorUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYErrorUtils.m; sourceTree = "<group>"; };
+		27C656860FAE01A200CFB909 /* MYTask.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYTask.h; sourceTree = "<group>"; };
+		27C656870FAE01A200CFB909 /* MYTask.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYTask.m; sourceTree = "<group>"; };
+		27C656B70FAE046B00CFB909 /* MYDirectoryWatcher.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYDirectoryWatcher.m; sourceTree = "<group>"; };
+		27C656B80FAE046B00CFB909 /* MYDirectoryWatcher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYDirectoryWatcher.h; sourceTree = "<group>"; };
+		27C656FC0FAE0DC100CFB909 /* English */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; name = English; path = English.lproj/Credits.rtf; sourceTree = "<group>"; };
 		27D124F40C8F501B0075446A /* URLFormatter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = URLFormatter.h; sourceTree = "<group>"; };
 		27D124F50C8F501B0075446A /* URLFormatter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = URLFormatter.m; sourceTree = "<group>"; };
 		27D918800C890F5500D53A8D /* xmlminimal.style */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = xmlminimal.style; sourceTree = "<group>"; };
-		27DEDBA10C85DE8A00A713A9 /* HgTask.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HgTask.h; sourceTree = "<group>"; };
-		27DEDBA20C85DE8A00A713A9 /* HgTask.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HgTask.m; sourceTree = "<group>"; };
-		29B97316FDCFA39411CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
 		29B97319FDCFA39411CA2CEA /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = English.lproj/MainMenu.nib; sourceTree = "<group>"; };
 		29B97324FDCFA39411CA2CEA /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = "<absolute>"; };
 		29B97325FDCFA39411CA2CEA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; };
 				277C50910C55BCB800E60690 /* MercurialApp.h */,
 				277C50920C55BCB800E60690 /* MercurialApp.m */,
 				32CA4F630368D1EE00C91783 /* Murky_Prefix.pch */,
-				29B97316FDCFA39411CA2CEA /* main.m */,
 				29B97318FDCFA39411CA2CEA /* MainMenu.nib */,
 			);
 			name = "User Interface";
 		2712F05C0C5823BF00E36E41 /* Support */ = {
 			isa = PBXGroup;
 			children = (
-				27DEDBA10C85DE8A00A713A9 /* HgTask.h */,
-				27DEDBA20C85DE8A00A713A9 /* HgTask.m */,
+				27AA81B30FADF60100D4FCBB /* MYUtilities */,
 				277C52100C56761000E60690 /* HgOperation.h */,
 				277C52110C56761000E60690 /* HgOperation.m */,
 				270E51270C56AD520069C9C6 /* HgLogOperation.h */,
 				27D124F50C8F501B0075446A /* URLFormatter.m */,
 				277C51C00C56709800E60690 /* ImageAndTextCell.h */,
 				277C51C10C56709800E60690 /* ImageAndTextCell.m */,
-				277D16A30C989182001D8600 /* RegEx.h */,
-				277D16A40C989182001D8600 /* RegEx.m */,
-				277D18720C9B1AD9001D8600 /* RegExTest.h */,
-				277D18730C9B1AD9001D8600 /* RegExTest.m */,
-				278CA6130C9B399500BD5484 /* DirectoryWatcher.h */,
-				278CA6140C9B399500BD5484 /* DirectoryWatcher.m */,
 			);
 			name = Support;
 			path = Source;
 			path = Source;
 			sourceTree = "<group>";
 		};
+		27AA81B30FADF60100D4FCBB /* MYUtilities */ = {
+			isa = PBXGroup;
+			children = (
+				27AA81B40FADF65500D4FCBB /* CollectionUtils.h */,
+				27AA81B50FADF65500D4FCBB /* CollectionUtils.m */,
+				27AA81B60FADF65500D4FCBB /* ExceptionUtils.h */,
+				27AA81B70FADF65500D4FCBB /* ExceptionUtils.m */,
+				27AA81B80FADF65500D4FCBB /* Logging.h */,
+				27AA81B90FADF65500D4FCBB /* Logging.m */,
+				27C656B70FAE046B00CFB909 /* MYDirectoryWatcher.m */,
+				27C656B80FAE046B00CFB909 /* MYDirectoryWatcher.h */,
+				27C656840FAE01A200CFB909 /* MYErrorUtils.h */,
+				27C656850FAE01A200CFB909 /* MYErrorUtils.m */,
+				27C656860FAE01A200CFB909 /* MYTask.h */,
+				27C656870FAE01A200CFB909 /* MYTask.m */,
+				27AA81BA0FADF65500D4FCBB /* Test.h */,
+				27AA81BB0FADF65500D4FCBB /* Test.m */,
+				27AA81C50FADF83000D4FCBB /* MYUtilities_Debug.xcconfig */,
+				27AA81C60FADF83000D4FCBB /* MYUtilities_Release.xcconfig */,
+			);
+			name = MYUtilities;
+			sourceTree = MYUtilities;
+		};
 		29B97314FDCFA39411CA2CEA /* MercurialViewer */ = {
 			isa = PBXGroup;
 			children = (
 				277C520A0C5674CC00E60690 /* Model */,
 				2712F05C0C5823BF00E36E41 /* Support */,
 				29B97317FDCFA39411CA2CEA /* Resources */,
+				27AA81A50FADF53100D4FCBB /* README.txt */,
 				29B97323FDCFA39411CA2CEA /* Frameworks */,
 				19C28FACFE9D520D11CA2CBB /* Products */,
 			);
 				270E512A0C56AED10069C9C6 /* xmlstyle */,
 				8D1107310486CEB800E47090 /* Info.plist */,
 				089C165CFE840E0CC02AAC07 /* InfoPlist.strings */,
+				27C656FB0FAE0DC100CFB909 /* Credits.rtf */,
 			);
 			name = Resources;
 			sourceTree = "<group>";
 				27D918810C890F5500D53A8D /* xmlminimal.style in Resources */,
 				275938630C931FED0088FFF4 /* Projects.nib in Resources */,
 				27075E6A0D66B9A900A8F759 /* mercurial-logo-official.icns in Resources */,
+				27AA81C70FADF83000D4FCBB /* MYUtilities_Debug.xcconfig in Resources */,
+				27AA81C80FADF83000D4FCBB /* MYUtilities_Release.xcconfig in Resources */,
+				27C656FD0FAE0DC100CFB909 /* Credits.rtf in Resources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
 				270E51290C56AD520069C9C6 /* HgLogOperation.m in Sources */,
 				270E52660C56BA310069C9C6 /* HgRevision.m in Sources */,
 				2712F0540C581F5300E36E41 /* HgTempDir.m in Sources */,
-				27DEDBA30C85DE8A00A713A9 /* HgTask.m in Sources */,
 				27107D1E0C887D3700ED7715 /* Predicate.m in Sources */,
 				272AB4CA0C8DD2600068C695 /* HgConfigFile.m in Sources */,
 				27D124F60C8F501B0075446A /* URLFormatter.m in Sources */,
 				275938660C93200B0088FFF4 /* ProjectsController.m in Sources */,
 				275938730C9321CF0088FFF4 /* HgProject.m in Sources */,
-				277D16A50C989182001D8600 /* RegEx.m in Sources */,
-				277D19260C9B2E63001D8600 /* main.m in Sources */,
-				278CA6150C9B399500BD5484 /* DirectoryWatcher.m in Sources */,
 				27B042D40CA9A1390090DC04 /* RevisionGraphColumn.m in Sources */,
 				27A6B63F0CAC254500482D5D /* RepoController_Actions.m in Sources */,
 				271CE8400CB18B5D000387BF /* HgUncommittedRevision.m in Sources */,
+				27AA81BC0FADF65500D4FCBB /* CollectionUtils.m in Sources */,
+				27AA81BD0FADF65500D4FCBB /* ExceptionUtils.m in Sources */,
+				27AA81BE0FADF65500D4FCBB /* Logging.m in Sources */,
+				27AA81BF0FADF65500D4FCBB /* Test.m in Sources */,
+				27C656880FAE01A200CFB909 /* MYErrorUtils.m in Sources */,
+				27C656890FAE01A200CFB909 /* MYTask.m in Sources */,
+				27C656B90FAE046B00CFB909 /* MYDirectoryWatcher.m in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
 			name = Repo.nib;
 			sourceTree = "<group>";
 		};
+		27C656FB0FAE0DC100CFB909 /* Credits.rtf */ = {
+			isa = PBXVariantGroup;
+			children = (
+				27C656FC0FAE0DC100CFB909 /* English */,
+			);
+			name = Credits.rtf;
+			sourceTree = "<group>";
+		};
 		29B97318FDCFA39411CA2CEA /* MainMenu.nib */ = {
 			isa = PBXVariantGroup;
 			children = (
 			isa = XCBuildConfiguration;
 			buildSettings = {
 				COPY_PHASE_STRIP = NO;
-				GCC_DYNAMIC_NO_PIC = NO;
-				GCC_ENABLE_FIX_AND_CONTINUE = YES;
-				GCC_MODEL_TUNING = G5;
-				GCC_OPTIMIZATION_LEVEL = 0;
-				GCC_PRECOMPILE_PREFIX_HEADER = YES;
-				GCC_PREFIX_HEADER = Source/Murky_Prefix.pch;
 				INFOPLIST_FILE = Resources/Info.plist;
 				INSTALL_PATH = "$(HOME)/Applications";
 				PRODUCT_NAME = Murky;
 		C01FCF4C08A954540054247B /* Release */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
-				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
-				GCC_MODEL_TUNING = G5;
-				GCC_PRECOMPILE_PREFIX_HEADER = YES;
-				GCC_PREFIX_HEADER = Source/Murky_Prefix.pch;
 				INFOPLIST_FILE = Resources/Info.plist;
 				INSTALL_PATH = "$(HOME)/Applications";
 				PRODUCT_NAME = Murky;
 		};
 		C01FCF4F08A954540054247B /* Debug */ = {
 			isa = XCBuildConfiguration;
+			baseConfigurationReference = 27AA81C50FADF83000D4FCBB /* MYUtilities_Debug.xcconfig */;
 			buildSettings = {
-				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_DYNAMIC_NO_PIC = YES;
 				GCC_ENABLE_OBJC_GC = required;
-				GCC_TREAT_WARNINGS_AS_ERRORS = YES;
-				GCC_WARN_ABOUT_RETURN_TYPE = YES;
-				GCC_WARN_UNUSED_VARIABLE = YES;
-				HEADER_SEARCH_PATHS = Source;
-				PREBINDING = NO;
+				GCC_PRECOMPILE_PREFIX_HEADER = YES;
+				GCC_PREFIX_HEADER = Source/Murky_Prefix.pch;
+				GCC_VERSION = 4.2;
 				SDKROOT = "$(DEVELOPER_SDK_DIR)/MacOSX10.5.sdk";
-				WARNING_CFLAGS = "-Wall";
 			};
 			name = Debug;
 		};
 		C01FCF5008A954540054247B /* Release */ = {
 			isa = XCBuildConfiguration;
+			baseConfigurationReference = 27AA81C60FADF83000D4FCBB /* MYUtilities_Release.xcconfig */;
 			buildSettings = {
 				ARCHS = (
 					ppc,
 					i386,
 				);
-				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_DYNAMIC_NO_PIC = YES;
 				GCC_ENABLE_OBJC_GC = required;
-				GCC_TREAT_WARNINGS_AS_ERRORS = YES;
-				GCC_WARN_ABOUT_RETURN_TYPE = YES;
-				GCC_WARN_UNUSED_VARIABLE = YES;
-				HEADER_SEARCH_PATHS = Source;
-				PREBINDING = NO;
+				GCC_PRECOMPILE_PREFIX_HEADER = YES;
+				GCC_PREFIX_HEADER = Source/Murky_Prefix.pch;
+				GCC_VERSION = 4.2;
 				SDKROOT = "$(DEVELOPER_SDK_DIR)/MacOSX10.5.sdk";
-				WARNING_CFLAGS = "-Wall";
 			};
 			name = Release;
 		};
+M U R K Y
+
+Murky is a GUI client app for the Mercurial distributed version-control system. 
+It lets you manage repositories and source files without using a command-line.
+
+Website:  http://bitbucket.org/snej/murky/
+
+
+= BUILDING IT =
+
+System requirements:
+    - Mac OS X 10.5+
+    - Apple's Xcode tools, version 3.1+
+
+Dependencies:
+    - MYUtilities <http://bitbucket.org/snej/myutilities/>
+
+First-Time Configuration:
+
+    *** PLEASE READ THIS FIRST! ***
+    Before the first time you build, you'll need to tell Xcode where the MYUtilities sources are. 
+    You do this by setting up a named 'Source Tree':
+
+ 0. Clone or download MYUtilities
+ 1. Open Xcode's Preferences panel
+ 2. Click the "Source Trees" icon at the top
+ 3. Click the "+" button to add a new item to the list
+ 4. Fill in the Setting Name as "MYUtilities", 
+    the Display Name also as "MYUtilities", 
+    and the Path as the absolute filesystem path to where you put MYUtilities. 
+    (Do not use a "~" (tilde) in this path! The compiler won't understand it.)
+    
+Once you're configured, just open Murky.xcodeproj and choose "Build".
+
+
+= LICENSE =
+
+This is a BSD license:
+
+ Copyright (c) 2008-2009, Jens Alfke <jens@mooseyard.com>. All rights reserved.
+ 
+ Redistribution and use in source and binary forms, with or without modification, are permitted
+ provided that the following conditions are met:
+ 
+ * Redistributions of source code must retain the above copyright notice, this list of conditions
+ and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
+ and the following disclaimer in the documentation and/or other materials provided with the
+ distribution.
+ 
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
+ BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
+  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
+ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Resources/Info.plist

 	<key>CFBundleSignature</key>
 	<string>????</string>
 	<key>CFBundleVersion</key>
-	<string>d2</string>
+	<string>0.4</string>
 	<key>NSMainNibFile</key>
 	<string>MainMenu</string>
 	<key>NSPrincipalClass</key>
-	<string>ExceptionReportingApplication</string>
+	<string>MYExceptionReportingApplication</string>
 </dict>
 </plist>

Source/DirectoryWatcher.h

-//
-//  DirectoryWatcher.h
-//  Murky
-//
-//  Copyright 2008-2009 Jens Alfke. All rights reserved.
-//
-
-#import <Cocoa/Cocoa.h>
-
-
-/* A wrapper for FSEvents, which notifies its delegate when filesystem changes occur. */
-@interface DirectoryWatcher : NSObject 
-{
-    NSString *_path;
-    id _target;
-    SEL _action;
-    UInt64 _lastEventID;
-    BOOL _historyDone;
-    CFTimeInterval _latency;
-    FSEventStreamRef _stream;
-}
-
-- (id) initWithDirectory: (NSString*)path target: (id)target action: (SEL)action;
-
-@property (readonly,nonatomic) NSString* path;
-
-@property UInt64 lastEventID;
-@property CFTimeInterval latency;
-
-- (BOOL) start;
-- (void) pause;
-- (void) stop;
-- (void) stopTemporarily;               // stop, but re-start on next runloop cycle
-
-@end
-
-
-
-@interface DirectoryEvent : NSObject
-{
-    DirectoryWatcher *watcher;
-    NSString *path;
-    UInt64 eventID;
-    UInt32 flags;
-}
-
-@property (readonly, nonatomic) DirectoryWatcher *watcher;
-@property (readonly, nonatomic) NSString *path, *relativePath;
-@property (readonly, nonatomic) UInt64 eventID;
-@property (readonly, nonatomic) UInt32 flags;
-
-@property (readonly, nonatomic) BOOL mustScanSubdirectories;
-@property (readonly, nonatomic) BOOL eventsWereDropped;
-@property (readonly, nonatomic) BOOL isHistorical;   
-@property (readonly, nonatomic) BOOL rootChanged;
-
-@end

Source/DirectoryWatcher.m

-//
-//  DirectoryWatcher.m
-//  Murky
-//
-//  Copyright 2008-2009 Jens Alfke. All rights reserved.
-//
-
-#import "DirectoryWatcher.h"
-#import <CoreServices/CoreServices.h>
-
-
-static void directoryWatcherCallback(ConstFSEventStreamRef streamRef,
-                                     void *clientCallBackInfo,
-                                     size_t numEvents,
-                                     void *eventPaths,
-                                     const FSEventStreamEventFlags eventFlags[],
-                                     const FSEventStreamEventId eventIds[]);
-
-@interface DirectoryEvent ()
-- (id) _initWithWatcher: (DirectoryWatcher*)itsWatcher
-                   path: (NSString*)itsPath 
-                  flags: (FSEventStreamEventFlags)itsFlags
-                eventID: (FSEventStreamEventId)itsEventID;
-@end
-
-
-@implementation DirectoryWatcher
-
-
-- (id) initWithDirectory: (NSString*)path target: (id)target action: (SEL)action
-{
-    NSParameterAssert(path);
-    self = [super init];
-    if (self != nil) {
-        _path = path.copy;
-        _target = target;
-        _action = action;
-        _latency = 5.0;
-        _lastEventID = kFSEventStreamEventIdSinceNow;
-    }
-    return self;
-}
-
-- (void) dealloc
-{
-    [self stop];
-    [_path release];
-    [super dealloc];
-}
-
-- (void) finalize
-{
-    [self stop];
-    [super finalize];
-}
-
-
-@synthesize path=_path, latency=_latency, lastEventID=_lastEventID;
-
-
-- (BOOL) start
-{
-    if( ! _stream ) {
-        FSEventStreamContext context = {0,self,NULL,NULL,NULL};
-        _stream = FSEventStreamCreate(NULL, 
-                                      &directoryWatcherCallback, &context,
-                                      (CFArrayRef)[NSArray arrayWithObject: _path], 
-                                      _lastEventID, 
-                                      _latency, 
-                                      kFSEventStreamCreateFlagUseCFTypes);
-        if( ! _stream )
-            return NO;
-        FSEventStreamScheduleWithRunLoop(_stream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
-        if( ! FSEventStreamStart(_stream) ) {
-            [self stop];
-            return NO;
-        }
-        _historyDone = (_lastEventID == kFSEventStreamEventIdSinceNow);
-        NSLog(@"DirectoryWatcher: Started on %@ (latency=%g, lastEvent=%llu)",_path,_latency,_lastEventID);
-    }
-    return YES;
-}
-
-- (void) pause
-{
-    if( _stream ) {
-        FSEventStreamStop(_stream);
-        FSEventStreamInvalidate(_stream);
-        FSEventStreamRelease(_stream);
-        _stream = NULL;
-        NSLog(@"DirectoryWatcher: Stopped on %@ (lastEvent=%llu)",_path,_lastEventID);
-    }
-}
-
-- (void) stop
-{
-    [self pause];
-    _lastEventID = kFSEventStreamEventIdSinceNow;   // so events from now till next start will be dropped
-    [NSObject cancelPreviousPerformRequestsWithTarget: self selector: @selector(start) object: nil];
-}
-
-- (void) stopTemporarily
-{
-    if( _stream ) {
-        [self stop];
-        [self performSelector: @selector(start) withObject: nil afterDelay: 0.0];
-    }
-}
-
-
-- (void) _notifyEvents: (size_t)numEvents
-                 paths: (NSArray*)paths
-                 flags: (const FSEventStreamEventFlags[])eventFlags
-              eventIDs: (const FSEventStreamEventId[])eventIDs
-{
-    for (size_t i=0; i<numEvents; i++) {
-        NSString *path = [paths objectAtIndex: i];
-        FSEventStreamEventFlags flags = eventFlags[i];
-        FSEventStreamEventId eventID = eventIDs[i];
-        if( flags & (kFSEventStreamEventFlagMount | kFSEventStreamEventFlagUnmount) ) {
-            if( flags & kFSEventStreamEventFlagMount )
-                NSLog(@"DirectoryWatcher: Volume mounted: %@",path);
-            else
-                NSLog(@"DirectoryWatcher: Volume unmounted: %@",path);
-        } else if( flags & kFSEventStreamEventFlagHistoryDone ) {
-            NSLog(@"DirectoryWatcher: Event #%llu History done",eventID);
-            _historyDone = YES;
-        } else {
-            NSLog(@"DirectoryWatcher: Event #%llu flags=%02x path=%@",eventID,flags,path);
-            if( _historyDone )
-                flags |= kFSEventStreamEventFlagHistoryDone;
-            
-            DirectoryEvent *event = [[DirectoryEvent alloc] _initWithWatcher: self
-                                                                        path: path 
-                                                                       flags: flags
-                                                                     eventID: eventID];
-            [_target performSelector: _action withObject: event];
-            [event release];
-        }
-        _lastEventID = eventIDs[i];
-    }
-}
-
-
-static void directoryWatcherCallback(ConstFSEventStreamRef streamRef,
-                                     void *watcher,
-                                     size_t numEvents,
-                                     void *eventPaths,
-                                     const FSEventStreamEventFlags eventFlags[],
-                                     const FSEventStreamEventId eventIDs[])
-{
-    [(DirectoryWatcher*)watcher _notifyEvents: numEvents
-                                        paths: (NSArray*)eventPaths
-                                        flags: eventFlags
-                                     eventIDs: eventIDs];
-}
-
-
-
-@end
-
-
-
-
-@implementation DirectoryEvent
-
-- (id) _initWithWatcher: (DirectoryWatcher*)itsWatcher
-                   path: (NSString*)itsPath 
-                  flags: (FSEventStreamEventFlags)itsFlags
-                eventID: (FSEventStreamEventId)itsEventID
-{
-    self = [super init];
-    if (self != nil) {
-        watcher = itsWatcher;
-        path = itsPath.copy;
-        flags = itsFlags;
-        eventID = itsEventID;
-    }
-    return self;
-}
-
-- (void) dealloc
-{
-    [path release];
-    [super dealloc];
-}
-
-@synthesize watcher,path,flags,eventID;
-
-- (NSString*) relativePath
-{
-    NSString *base = watcher.path;
-    if( ! [path hasPrefix: base] )
-        return nil;
-    int length = base.length;
-    while( length < path.length && [path characterAtIndex: length]=='/' )
-        length++;
-    return [path substringFromIndex: length];
-}
-
-- (BOOL) mustScanSubdirectories     {return (flags & kFSEventStreamEventFlagMustScanSubDirs) != 0;}
-- (BOOL) eventsWereDropped          {return (flags & (kFSEventStreamEventFlagUserDropped|kFSEventStreamEventFlagKernelDropped)) != 0;}
-- (BOOL) isHistorical               {return (flags & kFSEventStreamEventFlagHistoryDone)==0;}
-- (BOOL) rootChanged                {return (flags & kFSEventStreamEventFlagRootChanged)!=0;}
-
-@end

Source/HgConfigFile.m

 //
 
 #import "HgConfigFile.h"
-#import "HgTask.h"
+#import "MYTask.h"
 
 
 @implementation HgConfigFile
 - (void) _readFile
 {
     // See hgrc(5) man-page for details of format.
-    NSLog(@"Reading config file %@",_path);
+    Log(@"Reading config file %@",_path);
     _stanzas = [NSMutableDictionary dictionary];
 
     NSStringEncoding encoding;
     for( NSString *line in statusLines ) {
         if( line.length > 0 ) {
             if( line.length<3 || [line characterAtIndex: 1] != ' ' ) {
-                NSLog(@"WARNING: Unknown line from hg status: \"%@\"",line);
+                Warn(@"Unknown line from hg status: \"%@\"",line);
                 continue;
             }
             HgStatus status = (HgStatus) [line characterAtIndex: 0];
                 HgFile *file = [self addFileWithPath: path];
                 file.status = status;
                 [oldFiles removeObject: file];
-                //NSLog(@"    %c %@", file.status,file.path);
+                //Log(@"    %c %@", file.status,file.path);
             }
         }
     }

Source/HgLogOperation.m

             break;
         case kHgLogModeMinimal: {
             NSString *stylePath = [[NSBundle bundleForClass: [self class]] pathForResource: @"xmlminimal" ofType: @"style"];
-            NSAssert(stylePath,@"Missing xmlminimal.style");
+            Assert(stylePath,@"Missing xmlminimal.style");
             [self prependArguments: @"--style", stylePath,nil];
             break;
         }
         case kHgLogModeFull: {
             NSString *stylePath = [[NSBundle bundleForClass: [self class]] pathForResource: @"xml" ofType: @"style"];
-            NSAssert(stylePath,@"Missing xml.style");
+            Assert(stylePath,@"Missing xml.style");
             [self prependArguments: @"--verbose", @"--style", stylePath,nil];
             break;
         }
 - (void) finished
 {
     if( ! self.error ) {
-        NSLog(@"HgLogOperation is parsing...");
+        LogTo(HgLog,@"Parsing...");
         CFAbsoluteTime time = CFAbsoluteTimeGetCurrent();
         if( _mode == kHgLogModeListRevs )
             [self _parseRevNumbers];
         else
             [self _parseFullXML];
         time = CFAbsoluteTimeGetCurrent() - time;
-        NSLog(@"HgLogOperation took %.1f sec to parse %u revs", time, _revisions.count);
+        LogTo(HgLog,@"took %.1f sec to parse %u revs", time, _revisions.count);
     }
 }
 
     NSError *error = nil;
     NSArray *nodes = [xml nodesForXPath: xpath error: &error];
     if( nodes == nil ) {
-        NSLog(@"Error: Couldn't parse '%@': %@",xpath,[error localizedDescription]);
+        Warn(@"HgLogOperation: Couldn't parse XPath '%@': %@",xpath,[error localizedDescription]);
     }
     return nodes;
 }
     if( nodes == nil )
         return nil;
     if( [nodes count] == 0 ) {
-        //NSLog(@"No results for '%@'",xpath);
+        //Log(@"No results for '%@'",xpath);
         return nil;
     }
-    return [[nodes valueForKey:@"stringValue"] componentsJoinedByString:@""];
+    NSMutableString *str = [NSMutableString string];
+    for( NSXMLNode *node in nodes )
+        [str appendString: node.stringValue];
+    return [str stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceAndNewlineCharacterSet]];
 }
 
 /* Follow an XPath, returning the result as an array of strings */
     NSMutableArray *strings = [NSMutableArray array];
     for( NSXMLNode *node in nodes ) {
         NSString *str = node.stringValue;
+        str = [str stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceAndNewlineCharacterSet]];
         [strings addObject: str];
     }
     return strings;
     unsigned len = str.length;
     if( len != 40 ) {
         if( len>0 )
-            NSLog(@"Revision ID has wrong length (%u)",len);
+            Warn(@"Revision ID has wrong length (%u)",len);
         return NO;
     }
     const char *cStr = [str cStringUsingEncoding: NSASCIIStringEncoding];
     if( ! cStr ) {
-        NSLog(@"Invalid revision ID '%@'",str);
+        Warn(@"Invalid revision ID '%@'",str);
         return NO;
     }
     for( size_t i=0; i<20; i++ )
                 return [NSDate dateWithTimeIntervalSince1970: time];
             }
         }
-        NSLog(@"Warning: Failed to parse date '%@'",hgDateStr);
+        Warn(@"Failed to parse date '%@'",hgDateStr);
     }
     return nil;
 }
     if( revNo < 0 )
         return nil;
     NSArray *revs = _repository.revisions;
-    if( revNo < revs.count ) {
+    if( (unsigned)revNo < revs.count ) {
         HgRevision *rev = [revs objectAtIndex: revNo];
         if (!rev.isUncommitted)
             return rev;
             [_revisions addObject: revision];
             [_revsByNumber setObject: revision forKey: [NSNumber numberWithInt: revNo]];
         }
-        //NSLog(@"    Added revision #%i",revNo);
+        //Log(@"    Added revision #%i",revNo);
     }
     return YES;
 }

Source/HgOperation.h

 //  Copyright 2008-2009 Jens Alfke. All rights reserved.
 //
 
-#import "HgTask.h"
+#import "MYTask.h"
 @class HgDir;
 
 
-/** An HgTask specialized for running the 'hg' command. */
-@interface HgOperation : HgTask 
+/** An MYTask specialized for running the 'hg' command. */
+@interface HgOperation : MYTask 
 {
     NSString *_subcommand;
 }

Source/HgOperation.m

 
 
 static NSString* runShell( NSString* command, NSError **outError) {
-    HgTask *sh = [[HgTask alloc] initWithCommand: [sEnvironment objectForKey: @"SHELL"]
+    MYTask *sh = [[MYTask alloc] initWithCommand: [sEnvironment objectForKey: @"SHELL"]
                                        arguments: [NSArray arrayWithObjects: @"-c", command ,nil]];
     if ([sh run: outError])
         return [sh.output stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceAndNewlineCharacterSet]];
     else {
         if (outError)
-            NSLog(@"Warning: Shell command '%@' failed with output: '%@'", command,sh.output);
+            Warn(@"Shell command '%@' failed with output: '%@'", command,sh.output);
         return nil;
     }
 }
     // hg may need a custom PYTHONPATH. If so, the user's shell will set up that variable, so
     // to get it, fire up a shell and ask it:
     NSString *pythonPath = runShell(@"echo $PYTHONPATH", NULL);
-    NSLog(@"PYTHONPATH = '%@'", pythonPath);
+    Log(@"PYTHONPATH = '%@'", pythonPath);
     if (pythonPath.length > 0)
         [sEnvironment setObject: pythonPath forKey: @"PYTHONPATH"];
 }
     NSError *error = nil;
     hgPath = runShell(@"which hg", &error);
     if (hgPath) {
-        NSLog(@"'hg' path = '%@'", hgPath);
+        Log(@"'hg' path = '%@'", hgPath);
         if ([hgPath hasPrefix: @"/"])
             return hgPath;
         else
-            NSLog(@"...which isn't a path! Ignoring it");
+            Log(@"...which isn't a path! Ignoring it");
     }
     
     // As a last resort, guess that it's /usr/local/bin/hg:
     hgPath = @"/usr/local/bin/hg";
-    NSLog(@"Warning: Couldn't locate hg via shell ... assuming it's at %@", hgPath);
+    Warn(@"Couldn't locate hg via shell ... assuming it's at %@", hgPath);
     return hgPath;
 }
 
                  command: (NSString*)subcommand
                arguments: (NSArray*)arguments
 {
-    NSParameterAssert(subcommand);
+    Assert(subcommand);
     self = [super initWithCommand: sHgToolPath arguments: arguments];
     if (self != nil) {
         _subcommand = subcommand;
         if( dir ) {
             NSString *absPath = getAbsolutePath(dir);
-            NSAssert2(absPath.length>0, @"Bad absolutePath for %@ %@",[dir class],dir);
+            Assert(absPath.length>0, @"Bad absolutePath for %@ %@",[dir class],dir);
             self.currentDirectoryPath = absPath;
         }
     }

Source/HgProject.m

 
 - (id) _initWithName: (NSString*)name children: (NSArray*)children repositoryURL: (NSURL*)repositoryURL
 {
-    NSParameterAssert(name);
+    Assert(name);
     self = [super init];
     if( self ) {
         _name = name;
 
 + (HgProject*) projectWithName: (NSString*)name repositoryURL: (NSURL*)url
 {
-    NSParameterAssert(url);
+    Assert(url);
     return [[self alloc] _initWithName: name children: nil repositoryURL: url];
 }
 
 + (HgProject*) projectWithRepositoryURL: (NSURL*)url
 {
-    NSParameterAssert(url);
+    Assert(url);
     // Heuristics to make up a name from the last URL path component:
     NSString *path = url.path;
     NSString *name = url.path.lastPathComponent;

Source/HgRepository.h

 //
 
 #import "HgRevision.h"
-@class HgConfigFile, HgRevision, HgUncommittedRevision, HgOperation, DirectoryWatcher;
+@class HgConfigFile, HgRevision, HgUncommittedRevision, HgOperation, MYDirectoryWatcher;
 
 
 /** The three types of repo transfers: pull, push and clone. */
     HgRevision *_currentRevision;
     HgUncommittedRevision *_uncommittedRevision;
     HgConfigFile *_hgrc;
-    DirectoryWatcher *_watcher;
+    MYDirectoryWatcher *_watcher;
     NSMutableSet *_changedPaths;
 }
 

Source/HgRepository.m

 #import "HgOperation.h"
 #import "HgLogOperation.h"
 #import "HgConfigFile.h"
-#import "DirectoryWatcher.h"
+#import "MYDirectoryWatcher.h"
 
 
 @interface HgRepository (Internal)
 - (id) initWithPath: (NSString*)path
           localPath: (NSString**)localPath
 {
-    NSParameterAssert([path hasPrefix: @"/"]);
+    Assert([path hasPrefix: @"/"]);
     
     self = [super init];
     if (self != nil) {
         _uncommittedRevision = [[HgUncommittedRevision alloc] initWithRepository: self];
         
         _changedPaths = [NSMutableSet set];
-        _watcher = [[DirectoryWatcher alloc] initWithDirectory: _absolutePath
+        _watcher = [[MYDirectoryWatcher alloc] initWithDirectory: _absolutePath
                                                         target: self action: @selector(_dirChanged:)];
         _watcher.latency = 5;
         if( ! [_watcher start] )
-            NSLog(@"HgRepository: Couldn't start DirectoryWatcher on %@",_absolutePath);
+            Warn(@"HgRepository: Couldn't start MYDirectoryWatcher on %@",_absolutePath);
     }
     return self;
 }
 #pragma mark WORKING TREE TRACKING:
 
 
-- (void) _dirChanged: (DirectoryEvent*)event
+- (void) _dirChanged: (MYDirectoryEvent*)event
 {
     NSString *path=event.relativePath;
     if( [path hasPrefix: @".hg/"] )
         if( [path hasPrefix: changedPath] )
             return;                                 // ...or an ancestor of it
     }
-    NSLog(@"HgRepository: dir changed: %@", event.path);
+    LogTo(HgRepository, @"dir changed: %@", event.path);
     if( _changedPaths.count==0 )
         [self performSelector: @selector(_updateChangedDirs) withObject: nil afterDelay: 0.25];
     [_changedPaths addObject: path];
 
 - (void) _updateChangedDirs
 {
-    NSLog(@"HgRepository: Updating changed dirs %@",[[_changedPaths allObjects] componentsJoinedByString: @", "]);
+    LogTo(HgRepository, @"Updating changed dirs %@",[[_changedPaths allObjects] componentsJoinedByString: @", "]);
     NSSet *changedPaths = _changedPaths;
     _changedPaths = [NSMutableSet set];
     
     int curTip = _revisions.count>0 ?self.tipRevision.localNumber :-1;
     if( tip != curTip ) {
         // Revisions have changed!
-        NSLog(@"Tip changed from %i to %i ... updating revisions", curTip,tip);
+        LogTo(HgRepository,@"Tip changed from %i to %i ... updating revisions", curTip,tip);
 
         // Run "hg log" to get all revisions of this repository:
         if (!_revisions)
             _revisions = [NSArray array];   // Because HgLogOperation will call my -revisions
+        HgLogMode mode = kHgLogModeFull;
+        if (tip-curTip > 100)
+            mode = kHgLogModeMinimal;       // Speeds up initial open of large repos
         HgLogOperation *op = [[HgLogOperation alloc] initWithRepository: self 
                                                                    file: nil 
-                                                                   mode: kHgLogModeMinimal];
+                                                                   mode: mode];
         if( curTip >= 0 )
             op.range = NSMakeRange(curTip+1, tip-curTip); // only need to ask about the new revisions
         if( ! [op run] )
             return NO;
-        NSAssert([[op.revisions objectAtIndex: 0] localNumber]==curTip+1,@"Unexpected revision numbers from log");
+        Assert([[op.revisions objectAtIndex: 0] localNumber]==curTip+1,
+                  @"Unexpected revision numbers from log: expected starting %u, got %u", 
+                  curTip+1, [[op.revisions objectAtIndex: 0] localNumber]);
         
         // Add the new revisions, but before the uncommitted one if any:
         NSMutableArray *nuRevisions = [_revisions mutableCopy];
     unsigned nRevisions = _revisions.count;
     if (nRevisions > 0 && [[_revisions lastObject] isUncommitted])
         nRevisions--;
-    NSAssert(revNoRange.location < nRevisions, @"Invalid start revision");
+    Assert(revNoRange.location < nRevisions, @"Invalid start revision");
     revNoRange.length = MIN(revNoRange.length, nRevisions - revNoRange.location);
     
-    NSLog(@"HgRepository: Getting details of revisions [%u..%u]", 
+    LogTo(HgRepository, @"Getting details of revisions [%u..%u]", 
             revNoRange.location, revNoRange.location+revNoRange.length-1);
     HgLogOperation *op = [[HgLogOperation alloc] initWithRepository: self 
                                                                file: nil 
                          toURL: (NSURL*)dstURL
                        options: (HgTransferOptions)options
 {
-    NSParameterAssert(dstURL);
+    Assert(dstURL);
     if( dstURL.isFileURL ) {
         NSString *dstPath = dstURL.path;
         if( [[NSFileManager defaultManager] fileExistsAtPath: dstPath] )
             return [[HgOperation alloc] initWithError: @"The path to clone into already exists"];
         NSString *root = [[self class] findRootOf: dstPath localPath: NULL];
-        if( root )
-            return  [[HgOperation alloc] initWithError: @"The path to clone into is already inside a Mercurial repository at %@",root];
+        if( root ) {
+            NSError *error;
+            MYMiscError(&error, @"The path to clone into is already inside a Mercurial repository at %@",root);
+            return  [[HgOperation alloc] initWithError: error];
+        }
     }
     
     NSMutableArray *args = [NSMutableArray arrayWithObjects: @"--", stringForURL(srcURL), stringForURL(dstURL), nil];
 {
     NSArray *args = nil;
     if( rev ) {
-        NSAssert(!rev.isUncommitted,@"Can't update to uncommitted revision");
+        Assert(!rev.isUncommitted,@"Can't update to uncommitted revision");
         args = [NSArray arrayWithObjects: @"--rev", rev.identifierString, nil];
     }
     HgOperation *op = [[HgOperation alloc] initWithDirectory: self

Source/HgRevision.m

 const HgRevisionID kUncommittedRevisionID = {{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
                                               0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}};
 
-NSString* StringFromHgRevisionID( HgRevisionID r )
+static NSString* StringFromHgRevisionID( HgRevisionID r )
 {
     NSMutableString *str = [NSMutableString string];
     for( int i=0; i<20; i++ ) {
               localNumber: (int)revision
                identifier: (HgRevisionID)myID
 {
-    NSParameterAssert(repository);
-    NSParameterAssert(revision>=0);
+    Assert(repository);
+    Assert(revision>=0);
     self = [super init];
     if( self ) {
         _repository = repository;
 - (void) setParent: (HgRevision*)parent {
     if (parent != _parent) {
         if (parent) {
-            NSParameterAssert(parent!=self);
-            NSParameterAssert(parent!=_parent2);
-            NSParameterAssert(!parent.isUncommitted);
+            Assert(parent!=self);
+            Assert(parent!=_parent2);
+            Assert(!parent.isUncommitted);
         }
         [_parent release];
         _parent = [parent retain];
 - (void) setParent2: (HgRevision*)parent {
     if (parent != _parent2) {
         if (parent) {
-            NSParameterAssert(parent!=self);
-            NSParameterAssert(parent!=_parent);
-            NSParameterAssert(!parent.isUncommitted);
+            Assert(parent!=self);
+            Assert(parent!=_parent);
+            Assert(!parent.isUncommitted);
         }
         [_parent2 release];
         _parent2 = [parent retain];
         HgDir *root = [[HgDir alloc] initRootOfRevision: self];
         NSError *error;
         if( ! [self updateStatus: root error: &error] )
-            NSLog(@"WARNING: -[HgRevision root] failed! %@",error);
+            Warn(@"-[HgRevision root] failed! %@",error);
         _root = root;
     }
     return _root;
 
 - (NSString*) getPathToFileContents: (HgFile*)file inTempDir: (HgTempDir*)tempDir error: (NSError**)outError
 {
-    NSParameterAssert(tempDir);
+    Assert(tempDir);
     NSString *contents = [self getFileContents: file error: outError];
     if( ! contents )
         return nil;
 
 - (NSString*) diffFile: (HgFile*)file withRevisionNumber: (int)otherRev error: (NSError**)outError
 {
-    NSParameterAssert(otherRev>=0 && otherRev!=NSNotFound);
+    Assert(otherRev>=0 && otherRev!=NSNotFound);
     if( otherRev==_localNumber )
         return @"";
     [file.repository ignoreNextFileChanges];       // ignore temp file that "hg diff" creates in the repo root dir
 
 - (NSString*) compareFile: (HgFile*)file withRevisionNumber: (int)otherRev error: (NSError**)outError
 {
-    NSParameterAssert(otherRev>=0 && otherRev!=NSNotFound);
+    Assert(otherRev>=0 && otherRev!=NSNotFound);
     if( otherRev==_localNumber )
         return @"";
     [file.repository ignoreNextFileChanges];       // ignore temp file that "hg diff" creates in the repo root dir

Source/HgTask.h

-//
-//  HgTask.h
-//  Murky
-//
-//  Copyright 2008-2009 Jens Alfke. All rights reserved.
-//
-
-#import <Cocoa/Cocoa.h>
-
-
-/** NSError domain for Mercurial related errors. */
-extern NSString* const HgErrorDomain;
-
-/** "hg" exit code, in the error's userInfo dict. */
-extern NSString* const HgErrorTaskExitCodeKey;
- 
-/** The HgTask object itself, in the error's userInfo dict. */
-extern NSString* const HgErrorTaskObjectKey;
-enum {
-    kHgGeneralError = 1,
-    kHgTaskError = 2
-};
-
-/** Utility to create an NSError object, to be returned by methods that follow
-    the usual convention of setting an "out" NSError** parameter and returning NO.
-    This function stuffs the error into *outError and returns NO, so you can
-    directly return it. */
-BOOL HgMakeError( NSError **outError, NSString *format, ... );
-
-
-/** A generic souped-up NSTask, for running external command-line processes.
-    Makes it easy to mess with the argument list before starting,
-    and to capture the task output while it runs asynchronously. */
-@interface HgTask : NSObject 
-{
-    @private
-    NSString *_command;
-    NSMutableArray *_arguments;
-    NSString *_currentDirectoryPath;
-    NSTask *_task;
-    int _resultCode;
-    NSError *_error;
-    BOOL _ignoreOutput;
-    NSFileHandle *_outHandle, *_errHandle;
-    NSMutableData *_outputData, *_errorData;
-    NSString *_output;
-    NSMutableArray *_modes;
-    BOOL _isRunning, _taskRunning;
-}
-
-- (id) initWithCommand: (NSString*)subcommand, ... NS_REQUIRES_NIL_TERMINATION;
-
-/* designated initializer (subclasses can override) */
-- (id) initWithCommand: (NSString*)subcommand
-             arguments: (NSArray*)arguments;
-
-- (id) initWithError: (NSString*)format, ...;
-
-- (void) addArgument: (id)argument;
-- (void) addArguments: (id)arg1, ... NS_REQUIRES_NIL_TERMINATION;
-- (void) addArgumentsFromArray: (NSArray*)arguments;
-- (void) prependArguments: (id)arg1, ... NS_REQUIRES_NIL_TERMINATION;
-
-- (void) ignoreOutput;
-
-@property (copy) NSString* currentDirectoryPath;
-
-/** Prettified description of command string. Doesn't do full shell-style quoting, though. */
-- (NSString*) commandLine;
-
-- (BOOL) run;
-- (BOOL) run: (NSError**)outError;
-
-- (BOOL) start;
-- (void) stop;
-- (BOOL) waitTillFinished;
-
-@property (readonly,nonatomic) BOOL isRunning;
-@property (readonly,retain,nonatomic) NSError* error;
-@property (readonly,nonatomic) NSString *output, *outputAndError;
-@property (readonly,nonatomic) NSData *outputData;
-
-// protected:
-
-/** Subclasses can override this to add arguments or customize the task */
-- (NSTask*) createTask;
-
-/** Sets the error based on the message and parameters. Always returns NO. */
-- (BOOL) makeError: (NSString*)fmt, ...;
-
-/** Called when the task finishes, just before the isRunning property changes back to NO.
-    You can override this to do your own post-processing. */
-- (void) finished;
-
-@end

Source/HgTask.m

-//
-//  HgTask.m
-//  Murky
-//
-//  Copyright 2008-2009 Jens Alfke. All rights reserved.
-//
-
-#import "HgTask.h"
-
-
-NSString* const HgErrorDomain = @"HgError";
-NSString* const HgErrorTaskExitCodeKey = @"exitCode";
-NSString* const HgErrorTaskObjectKey = @"HgTask";
-
-#define HgTaskSynchronousRunLoopMode @"HgTask"
-
-#define sLogVerbose NO
-#define LogVerbose  if(!sLogVerbose) ; else NSLog
-
-
-BOOL HgMakeErrorV( NSError **outError, NSString *format, va_list args )
-{
-    NSString *message = [[NSString alloc] initWithFormat: format arguments: args];
-    NSLog(@"HgError: %@",message);
-    
-    if( outError ) {
-        NSMutableDictionary *info = [NSMutableDictionary dictionaryWithObject: message
-                                                                       forKey: NSLocalizedDescriptionKey];
-        *outError = [NSError errorWithDomain: HgErrorDomain code: kHgGeneralError userInfo: info];
-    }
-    return NO;
-}
-
-BOOL HgMakeError( NSError **outError, NSString *format, ... )
-{
-    va_list args;
-    va_start(args,format);
-    HgMakeErrorV(outError,format,args);
-    va_end(args);
-    return NO;
-}
-
-
-@interface HgTask ()
-@property (readwrite,nonatomic) BOOL isRunning;
-@property (readwrite,retain,nonatomic) NSError *error;
-- (void) _finishUp;
-@end
-
-
-@implementation HgTask
-
-
-- (id) initWithCommand: (NSString*)command
-             arguments: (NSArray*)arguments
-{
-    NSParameterAssert(command);
-    self = [super init];
-    if (self != nil) {
-        _command = command;
-        _arguments = arguments ?[arguments mutableCopy] :[NSMutableArray array];
-        _modes = [NSMutableArray arrayWithObjects: NSDefaultRunLoopMode, NSModalPanelRunLoopMode, nil];
-    }
-    return self;
-}
-
-
-- (id) initWithCommand: (NSString*)command, ...
-{
-    NSMutableArray *arguments = [NSMutableArray array];
-    va_list args;
-    va_start(args,command);
-    id arg;
-    while( nil != (arg=va_arg(args,id)) )
-        [arguments addObject: [arg description]];
-    va_end(args);
-    
-    return [self initWithCommand: command arguments: arguments];
-}
-
-
-- (id) initWithError: (NSString*)format, ...
-{
-    NSParameterAssert(format);
-    self = [super init];
-    if( self ) {
-        va_list args;
-        va_start(args,format);
-        HgMakeErrorV(&_error,format,args);
-        va_end(args);
-    }
-    return self;
-}
-
-
-- (NSString*) description
-{
-    return [NSString stringWithFormat: @"%@ %@", 
-            _command, [_arguments componentsJoinedByString: @" "]];
-}
-
-
-- (void) addArgument: (id)argument
-{
-    [_arguments addObject: [argument description]];
-}
-
-- (void) addArgumentsFromArray: (NSArray*)arguments
-{
-    for( id arg in arguments )
-        [_arguments addObject: [arg description]];
-}
-
-- (void) addArguments: (id)arg, ...
-{
-    va_list args;
-    va_start(args,arg);
-    while( arg ) {
-        [_arguments addObject: [arg description]];
-        arg = va_arg(args,id);
-    }
-    va_end(args);
-}
-
-- (void) prependArguments: (id)arg, ...
-{
-    va_list args;
-    va_start(args,arg);
-    int i=0;
-    while( arg ) {
-        [_arguments insertObject: [arg description] atIndex: i++];
-        arg = va_arg(args,id);
-    }
-    va_end(args);
-}
-
-
-- (NSString*) commandLine {
-    NSMutableString *desc = [NSMutableString stringWithString: _command];
-    for (NSString *arg in _arguments) {
-        [desc appendString: @" "];
-        if ([arg rangeOfString: @" "].length > 0)
-            arg = [NSString stringWithFormat: @"'%@'", arg];
-        [desc appendString: arg];
-    }
-    return desc;
-}
-
-
-- (void) ignoreOutput
-{
-    _ignoreOutput = YES;
-}
-
-
-- (BOOL) makeError: (NSString*)fmt, ...
-{
-    va_list args;
-    va_start(args,fmt);
-    HgMakeErrorV(&_error,fmt,args);
-    va_end(args);
-    return NO;
-}
-
-
-- (NSPipe*) _openPipeAndHandle: (NSFileHandle**)handle notifying: (SEL)selector
-{
-    NSPipe *pipe = [NSPipe pipe];
-    *handle = [pipe fileHandleForReading];
-    [[NSNotificationCenter defaultCenter] addObserver: self selector: selector
-                                                 name: NSFileHandleReadCompletionNotification
-                                               object: *handle];
-    [*handle readInBackgroundAndNotifyForModes: _modes];
-    return pipe;
-}
-
-
-- (void) _close
-{
-    // No need to call -closeFile on file handles obtained from NSPipe (in fact, it can hang)
-    _outHandle = nil;
-    _errHandle = nil;
-    [[NSNotificationCenter defaultCenter] removeObserver: self 
-                                                    name: NSFileHandleReadCompletionNotification
-                                                  object: nil];
-}
-
-
-/** Subclasses can override this. */
-- (NSTask*) createTask
-{
-    NSAssert(!_task,@"createTask called twice");
-    NSTask *task = [[NSTask alloc] init];
-    task.launchPath = _command;
-    task.arguments = _arguments;
-    if( _currentDirectoryPath )
-        task.currentDirectoryPath = _currentDirectoryPath;
-    return task;
-}    
-
-
-- (BOOL) start
-{
-    NSAssert(!_task, @"Task has already been run");
-    if( _error )
-        return NO;
-    
-    _task = [self createTask];
-    NSAssert(_task,@"createTask returned nil");
-    
-    NSLog(@"Task: %@", self.commandLine);
-    
-    _task.standardOutput = [self _openPipeAndHandle: &_outHandle notifying: @selector(_gotOutput:)];
-    _outputData =  [[NSMutableData alloc] init];
-    _task.standardError  = [self _openPipeAndHandle: &_errHandle notifying: @selector(_gotStderr:)];
-    _errorData =  [[NSMutableData alloc] init];
-    
-    [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(_exited:)
-                                                 name: NSTaskDidTerminateNotification
-                                               object: _task];
-    
-    @try{
-        [_task launch];
-    }@catch( id x ) {
-        NSLog(@"Task failed to launch: %@",x);
-        _resultCode = 666;
-        [self _close];
-        return [self makeError: @"Exception launching %@: %@",_task.launchPath,x];
-    }
-    _taskRunning = YES;
-    self.isRunning = YES;
-    
-    return YES;
-}
-
-
-- (void) stop
-{
-    [_task interrupt];
-    [self _close];
-    _taskRunning = NO;
-    self.isRunning = NO;
-}
-
-
-- (BOOL) _shouldFinishUp
-{
-    return !_task.isRunning && (_ignoreOutput || (!_outHandle && !_errHandle));
-}
-
-
-- (void) _gotOutput: (NSNotification*)n
-{
-    NSData *data = [n.userInfo objectForKey: NSFileHandleNotificationDataItem];
-    if( n.object == _outHandle ) {
-        if( data.length > 0 ) {
-            [_outHandle readInBackgroundAndNotifyForModes: _modes];
-            LogVerbose(@"HgTask: Got %u bytes of output",data.length);
-            if( _outputData ) {
-                [self willChangeValueForKey: @"output"];
-                [self willChangeValueForKey: @"outputData"];
-                [_outputData appendData: data];
-                _output = nil;
-                [self didChangeValueForKey: @"outputData"];
-                [self didChangeValueForKey: @"output"];
-            }
-        } else {
-            LogVerbose(@"HgTask: Closed output");
-            _outHandle = nil;
-            if( [self _shouldFinishUp] )
-                [self _finishUp];
-        }
-    }
-}
-
-- (void) _gotStderr: (NSNotification*)n
-{
-    if( n.object == _errHandle ) {
-        NSData *data = [n.userInfo objectForKey: NSFileHandleNotificationDataItem];
-        if( data.length > 0 ) {
-            [_errHandle readInBackgroundAndNotifyForModes: _modes];
-            LogVerbose(@"HgTask: Got %u bytes of stderr",data.length);
-            [self willChangeValueForKey: @"errorData"];
-            [_errorData appendData: data];
-            [self didChangeValueForKey: @"errorData"];
-        } else {
-            LogVerbose(@"HgTask: Closed stderr");
-            _errHandle = nil;
-            if( [self _shouldFinishUp] )
-                [self _finishUp];
-        }
-    }
-}
-
-- (void) _exited: (NSNotification*)n
-{
-    _resultCode = _task.terminationStatus;
-    LogVerbose(@"HgTask: Exited with result=%i",_resultCode);
-    _taskRunning = NO;
-    if( [self _shouldFinishUp] )
-        [self _finishUp];
-    else
-        [self performSelector: @selector(_finishUp) withObject: nil afterDelay: 1.0];
-}
-
-
-- (void) _finishUp
-{
-    [NSObject cancelPreviousPerformRequestsWithTarget: self selector: @selector(_finishUp) object: nil];
-    [self _close];
-
-    LogVerbose(@"HgTask: Finished!");
-
-    if( _resultCode != 0 ) {
-        // Handle errors:
-        NSString *errStr = nil;
-        if( _errorData.length > 0 )
-            errStr = [[NSString alloc] initWithData: _errorData encoding: NSUTF8StringEncoding];
-        NSLog(@"    *** task returned %i: %@",_resultCode,errStr);
-        if( errStr.length == 0 )
-            errStr = [NSString stringWithFormat: @"Command returned status %i",_resultCode];
-        NSString *desc = [NSString stringWithFormat: @"%@ command error", _task.launchPath.lastPathComponent];
-        // For some reason the body text in the alert shown by -presentError: is taken from the
-        // NSLocalizedRecoverySuggestionErrorKey, not the NSLocalizedFailureReasonKey...
-        NSMutableDictionary *info = [NSMutableDictionary dictionaryWithObjectsAndKeys:
-                                     desc,                                  NSLocalizedDescriptionKey,
-                                     errStr,                                NSLocalizedRecoverySuggestionErrorKey,
-                                     [NSNumber numberWithInt: _resultCode], HgErrorTaskExitCodeKey,
-                                     self,                                  HgErrorTaskObjectKey,
-                                     nil];
-        self.error = [[NSError alloc] initWithDomain: HgErrorDomain 
-                                                code: kHgTaskError
-                                            userInfo: info];
-    }
-
-    [self finished];
-
-    self.isRunning = NO;
-}
-
-- (void) finished
-{
-    // This is a hook that subclasses can override to do post-processing.
-}
-
-
-- (BOOL) _waitTillFinishedInMode: (NSString*)runLoopMode
-{
-    // wait for task to exit:
-    while( _task.isRunning || self.isRunning )
-        [[NSRunLoop currentRunLoop] runMode: HgTaskSynchronousRunLoopMode
-                                 beforeDate: [NSDate dateWithTimeIntervalSinceNow: 1.0]];
-    return (_resultCode==0);
-}
-
-- (BOOL) waitTillFinished
-{
-    return [self _waitTillFinishedInMode: _modes.lastObject];
-}
-
-
-- (BOOL) run
-{
-    [_modes addObject: HgTaskSynchronousRunLoopMode];
-    return [self start] && [self _waitTillFinishedInMode: HgTaskSynchronousRunLoopMode];
-    
-}    
-
-
-- (BOOL) run: (NSError**)outError
-{
-    BOOL result = [self run];
-    if( outError ) *outError = self.error;
-    return result;
-}
-
-
-@synthesize currentDirectoryPath=_currentDirectoryPath, outputData=_outputData, error=_error, isRunning=_isRunning;
-
-
-- (NSString*) output
-{
-    if( ! _output && _outputData )
-        _output = [[NSString alloc] initWithData: _outputData encoding: NSUTF8StringEncoding];
-    return _output;
-}
-
-- (NSString*) outputAndError
-{
-    NSString *result = self.output ?: @"";
-    NSString *errorStr = nil;
-    if( _error )
-        errorStr = [NSString stringWithFormat: @"%@:\n%@",
-                    _error.localizedDescription,_error.localizedRecoverySuggestion];
-    else if( _errorData.length > 0 )
-        errorStr = [[NSString alloc] initWithData: _errorData encoding: NSUTF8StringEncoding];
-    if( errorStr )
-        result = [NSString stringWithFormat: @"%@\n\n%@", errorStr,result];
-    return result;
-}
-
-+ (NSArray*) keyPathsForValuesAffectingOutputAndError
-{
-    return [NSArray arrayWithObjects: @"output", @"error", @"errorData",nil];
-}
-
-
-@end

Source/HgUncommittedRevision.m

         // If I haven't loaded my files at all, just load 'em and return. Otherwise
         // the code below will end up doing that and then calling -updateStatus again,
         // which is inefficient.
-        self.root;
+        [self root];
         return YES;
     }
     
 
 - (BOOL) removeFiles: (NSArray*)files error: (NSError**)outError
 {
-    NSParameterAssert(files);
+    Assert(files);
     NSMutableArray *realFiles = [NSMutableArray array], *missingFiles = [NSMutableArray array];
     for( HgFile *file in files ) {
         switch( file.status ) {
                error: (NSError**)outError
 {
     if( message.length==0 )
-        return HgMakeError(outError, @"Missing commit message");
+        return MYMiscError(outError, @"Missing commit message");
     if( ! [self applyCommand: @"commit" 
                     arguments: [NSArray arrayWithObjects: @"--message", message, nil]
                       toFiles: files

Source/ImageAndTextCell.m

         result.size = [image size];
         result.origin = cellFrame.origin;
         result.origin.x += 3;
-        result.origin.y += ceil((cellFrame.size.height - result.size.height) / 2);
+        result.origin.y += ceilf((cellFrame.size.height - result.size.height) / 2);
     } else {
         result = NSZeroRect;
     }
         imageFrame.size = imageSize;
 
         if ([controlView isFlipped])
-            imageFrame.origin.y += ceil((cellFrame.size.height + imageFrame.size.height) / 2);
+            imageFrame.origin.y += ceilf((cellFrame.size.height + imageFrame.size.height) / 2);
         else
-            imageFrame.origin.y += ceil((cellFrame.size.height - imageFrame.size.height) / 2);
+            imageFrame.origin.y += ceilf((cellFrame.size.height - imageFrame.size.height) / 2);
 
         [image compositeToPoint:imageFrame.origin operation:NSCompositeSourceOver];
     }

Source/MercurialApp.h

 
 
 extern MercurialApp *gMercurialApp;
-
-
-@interface ExceptionReportingApplication : NSApplication
-@end

Source/MercurialApp.m

 #import "HgRepository.h"
 #import "HgOperation.h"
 #import "URLFormatter.h"
+#import "ExceptionUtils.h"
 
 
 /** User defaults: */
 #define kPrefRecentRepositories @"RecentRepositories"
 
 
+int main(int argc, const char** argv)
+{
+    RunTestCases(argc,argv);
+    return NSApplicationMain(argc, argv);
+}
+
+
+
+
 MercurialApp *gMercurialApp;
 
 
             NSBeep();
             return;
         }
-        NSLog(@"Clone from <%@> to <%@>",srcURL,dstURL);
+        Log(@"Clone from <%@> to <%@>",srcURL,dstURL);
         NSError *error = nil;
         HgOperation *op = [HgRepository cloneRevision: nil fromURL: srcURL toURL: dstURL
                                               options: kHgUpdateAfterwards];
     for( NSString *path in [[NSUserDefaults standardUserDefaults] objectForKey: kPrefOpenRepositories]) {
         @try{
             [self openRepository: path remember: NO];
-        }@catch( NSException *x ) {
-            NSLog(@"Exception re-opening recent repository: %@",x);
-        }
+        }catchAndReport(@"Exception re-opening recent repository %@", path)
     }    
 }
 
 
 
 @end
-
-
-
-@implementation ExceptionReportingApplication
-
-- (void)reportException:(NSException *)x
-{
-    [super reportException: x];
-    [self performSelector: @selector(_showExceptionAlert:) withObject: x afterDelay: 0.0];
-}
-
-- (void) _showExceptionAlert: (NSException*)x
-{
-    NSRunCriticalAlertPanel( @"Internal Error!",
-                            [NSString stringWithFormat: @"Uncaught exception:\n\n%@",x],
-                            @"Sorry",nil,nil);
-}
-
-@end

Source/Murky_Prefix.pch

 
 #ifdef __OBJC__
     #import <Cocoa/Cocoa.h>
+
+    // Common MYUtilities:
+    #import "Logging.h"
+    #import "Test.h"
+    #import "CollectionUtils.h"
+    #import "MYErrorUtils.h"
 #endif

Source/Predicate.m

 }
 
 
-BOOL TruePredicateInvoker(Predicate p,id objectToTest)
+static BOOL TruePredicateInvoker(Predicate p,id objectToTest)
 {
     return YES;
 }
     if( chars )
         *malloced = NO;
     else {
-        /*NSLog(@"getCharsPtr failed on \"%@\":",str); CFShowStr(str);
-        NSLog(@"fastestEncoding = %i", CFStringGetFastestEncoding(str));
-        NSLog(@"getCStringPtr would have returned %p", CFStringGetCStringPtr(str, kCFStringEncodingUTF8));*/
+        /*Log(@"getCharsPtr failed on \"%@\":",str); CFShowStr(str);
+        Log(@"fastestEncoding = %i", CFStringGetFastestEncoding(str));
+        Log(@"getCStringPtr would have returned %p", CFStringGetCStringPtr(str, kCFStringEncodingUTF8));*/
         chars = malloc(*length*sizeof(unichar));
         CFStringGetCharacters(str,(CFRange){0,*length},(unichar*)chars);
         *malloced = YES;

Source/RegExTest.m

     
     while([matcher findNextMatch]) {
         NSRange r = [matcher rangeOfMatch];
-        NSLog(@"match = %@ (%u-%u)", matcher.matchedString,r.location,NSMaxRange(r));
+        Log(@"match = %@ (%u-%u)", matcher.matchedString,r.location,NSMaxRange(r));
     }
 }
 /*
     RegEx *p = REGEX("([庭庢]+)");
     RegExMatcher *matcher = [p matcherForString:searchString];
     NSString *result = [matcher replaceFirstWithString:[NSString stringWithUTF8String:"弇弈弇弊"]];
-    NSLog(@"result = %@", result);
+    Log(@"result = %@", result);
 }
 
 void findAndReplaceAll() {
     RegEx *p = REGEX("(❸➈➈➈➈➈➈)");
     RegExMatcher *matcher = [p matcherForString:searchString];
     NSString *result = [matcher replaceAllWithString:[NSString stringWithUTF8String:"ŞŞËËËËààààä"]];
-    NSLog(@"result = %@", result);
+    Log(@"result = %@", result);
 }
 
 void split() {
     NSString *searchString = @"bbdfdbbababababaklsdjfababababab";
     RegEx *p = REGEX("[ab]+");
     NSArray *r = [p componentsSplitFromString:searchString];
-    NSLog(@"result = %@", r);
+    Log(@"result = %@", r);
 }
 
 void unicodeFind() {
     RegEx *p = REGEX("ä+");
     RegExMatcher *matcher = [p matcherForString:searchString];
     while([matcher findNextMatch]) {
-        NSLog(@"match = %@", [searchString substringWithRange:[matcher rangeOfMatch]]);
+        Log(@"match = %@", [searchString substringWithRange:[matcher rangeOfMatch]]);
     }
 }
 
     while([matcher findNextMatch]) {
         int i;
         for(i=0;i<=[matcher numberOfGroups];i++) {
-            NSLog(@"group %i : %@", i, [matcher groupAtIndex:i]);
+            Log(@"group %i : %@", i, [matcher groupAtIndex:i]);
         }
     }
 }
     NSString *searchString = @"aabbcc";
     NSString *patternString = @"(a+)..(c+)";
     NSString *replacedText = [searchString replaceOccurrencesOfPattern:patternString withString:@" $2  $1"];
-    NSLog(@"%@", replacedText);
+    Log(@"%@", replacedText);
 }
 */

Source/RepoController.m

 #import "HgUncommittedRevision.h"
 #import "HgTempDir.h"
 #import "RevisionGraphColumn.h"
-#import "HgTask.h"
+#import "MYTask.h"
 
 
 /** Repository-relative path to where Murky stores its per-repository settings */
 {
     BOOL isDir;
     if( ! [[NSFileManager defaultManager] fileExistsAtPath: path isDirectory: &isDir] ) {
-        HgMakeError(error, @"No such directory %@",path);
+        MYMiscError(error, @"No such directory %@",path);
         return nil;
     } else if( ! isDir ) {
-        HgMakeError(error, @"%@ is not a directory",path);
+        MYMiscError(error, @"%@ is not a directory",path);
         return nil;
     }
     HgRepository *repo = [[HgRepository alloc] initWithPath: path localPath: NULL];
 
 - (id) initWithRepository: (HgRepository*)repo;
 {
-    NSParameterAssert(repo);
+    Assert(repo);
     self = [super initWithWindowNibName: @"Repo"];
     if (self != nil) {
         _repo = repo;
 - (void) saveSettings
 {
     if( _settingsChanged ) {
-        NSLog(@"RepoController: Saving settings");
+        Log(@"RepoController: Saving settings");
         [_repo ignoreNextFileChanges];
         [_settings writeToFile: [_repo.absolutePath stringByAppendingPathComponent: kSettingsFilePath]
                     atomically: YES];
 {
     id oldValue = [_settings objectForKey: setting];
     if( value!=oldValue && ![value isEqual: oldValue] ) {
-        NSLog(@"Setting: %@ = %@",setting,value);
+        Log(@"Setting: %@ = %@",setting,value);
         if( value )
             [_settings setObject: value forKey: setting];
         else
                     if( node )
                         [_outline expandItem: node];
                     else
-                        NSLog(@"? Couldn't find tree node for %@",file);
+                        Log(@"? Couldn't find tree node for %@",file);
                 } else
-                    NSLog(@"? Couldn't find HgFile for path %@",path);
+                    Log(@"? Couldn't find HgFile for path %@",path);
             }
         }
     }
 #if 0
     NSMutableString *dump = [NSMutableString string];
     [_repo dumpTo: dump];
-    NSLog(@"*** Revision list changed: ***\n%@", dump);
+    Log(@"*** Revision list changed: ***\n%@", dump);
 #endif
     
     // Update the graph column's list of revisions:
 
 - (CGFloat)splitView:(NSSplitView *)splitView constrainMinCoordinate:(CGFloat)proposedMinimumPosition ofSubviewAt:(NSInteger)dividerIndex
 {
-    float minSize = (splitView==_splitter ?75.0 :150.0);
+    float minSize = (splitView==_splitter ?75.0f :150.0f);
     return MAX(proposedMinimumPosition,minSize);
 }
 
         normalColor = [NSColor controlTextColor];
         unrelatedColor = [NSColor grayColor];
         uncommittedColor = [NSColor darkGrayColor];
-        containsFileColor = [NSColor colorWithCalibratedRed: 0.75 green: 0 blue: 0 alpha: 1.0];
+        containsFileColor = [NSColor colorWithCalibratedRed: 0.75f green: 0 blue: 0 alpha: 1];
         normalFont = cell.font;
         currentFont = [[NSFontManager sharedFontManager] convertFont: normalFont 
                                                          toHaveTrait: NSBoldFontMask];
 
 - (void) _fileSelectionChanged: (NSTreeController*)controller change: (NSDictionary*)change
 {
-    //NSLog(@"File Selection = %@",self.selectedFile);
+    //Log(@"File Selection = %@",self.selectedFile);
     //[_revisionTable setNeedsDisplay: YES];
 }
 
 - (void) _revisionSelectionChanged: (NSTreeController*)controller change: (NSDictionary*)change
 {
-    //NSLog(@"Revision Selection = %@",self.selectedRevision);
+    //Log(@"Revision Selection = %@",self.selectedRevision);
     [self _updateInfoView];
     [self _updateWindowTitle];
 }

Source/RepoController_Actions.m

 - (IBAction) chooseRevisionFromPopUp: (id)sender
 {
     HgRevision *rev = ((NSPopUpButton*)sender).selectedItem.representedObject;
-    NSLog(@"Pop-up selected revision %@",rev);
+    Log(@"Pop-up selected revision %@",rev);
     //[_revisions setSelectedObjects: [NSArray arrayWithObject: rev]];
 }
 
 {
     if( ! file.isFile ) {
         //FIX: Can't compare directories yet
-        return HgMakeError(outError, @"Can't compare directories yet, sorry!");
+        return MYMiscError(outError, @"Can't compare directories yet, sorry!");
     }
     NSString *pathOld = [revOld getPathToFileContents: file inTempDir: self.tempDir error: outError];
     if( ! pathOld ) return NO;
     NSString *pathNew = [revNew getPathToFileContents: file inTempDir: self.tempDir error: outError];
     if( ! pathNew ) return NO;
     
-    HgTask *task = [[HgTask alloc] initWithCommand: @"/usr/bin/opendiff", pathOld,pathNew, nil];
+    MYTask *task = [[MYTask alloc] initWithCommand: @"/usr/bin/opendiff", pathOld,pathNew, nil];
     [task ignoreOutput];
     BOOL ok = [task start];
     *outError = task.error;
             defaultURL = [defaultURL stringByAppendingString: @"_clone"];
             break;
         default:
-            NSAssert1(NO,@"Invalid op %i",op);
+            Assert(NO,@"Invalid op %i",op);
             return;
     }
     [_pushURLField setStringValue: (defaultURL ?:@"")];

Source/RevisionGraphColumn.h

 
 @property (readonly) NSArray *revisions;
 
-- (void) drawRevisionNumber: (int)revNo inRect: (NSRect)bounds flipped: (BOOL)flipped;
+- (void) drawRevisionNumber: (unsigned)revNo inRect: (NSRect)bounds flipped: (BOOL)flipped;
 - (void) drawRevision: (HgRevision*)rev inRect: (NSRect)bounds flipped: (BOOL)flipped;
 
 @end

Source/RevisionGraphColumn.m

 
 @implementation RevisionGraphColumn
 
-- (BOOL) _addLineFrom: (int)rev0 to: (int)rev1
+- (BOOL) _addLineFrom: (unsigned)rev0 to: (unsigned)rev1
 {
-    NSAssert1(rev0>=0&&rev0<_nRevisions,@"bad rev0: %i",rev0);
-    NSAssert1(rev1>rev0&&rev1<_nRevisions,@"bad rev1: %i",rev1);
+    Assert(rev0>=0&&rev0<_nRevisions,@"bad rev0: %i",rev0);
+    Assert(rev1>rev0&&rev1<_nRevisions,@"bad rev1: %i",rev1);
     
     UInt64 used = 0;
-    for( int r=rev0+1; r<rev1; r++ )
+    for( unsigned r=rev0+1; r<rev1; r++ )
         used |= _used[r];
     
     int x;
     
     _array[rev0*_maxWidth + x] |= kDotMask | kNextMask;
     _used[rev0] |= mask; 
-    for( int r=rev0+1; r<rev1; r++ ) {
+    for( unsigned r=rev0+1; r<rev1; r++ ) {
         _array[r*_maxWidth + x] |= kPrevMask | kNextMask;
         _used[r] |= mask; 
     }
     _array[rev1*_maxWidth + x] |= kPrevMask | kDotMask;
     _used[rev1] |= mask; 
     
-    //NSLog(@"Line from %i to %i at x=%i",rev0,rev1,x);
+    //Log(@"Line from %i to %i at x=%i",rev0,rev1,x);
     return YES;
 }
 
     while(rev){
         if( [_laidOut containsObject: rev] )
             return YES;
-        //NSLog(@"Layout %@",rev);
+        //Log(@"Layout %@",rev);