Index: /trunk/Cocoa/Pester/Source/English.lproj/Credits.html
===================================================================
--- /trunk/Cocoa/Pester/Source/English.lproj/Credits.html	(revision 117)
+++ /trunk/Cocoa/Pester/Source/English.lproj/Credits.html	(revision 118)
@@ -1,3 +1,3 @@
 <font face="Lucida Grande" size="-1"><b>Icon by</b> <a href="mailto:excellence@global.co.za">Diederik Vemer</a>.</font><br>
-<font face="Lucida Grande" size="-1"><b>Thanks to</b> <a href="mailto:ryanwilcox@mac.com">Ryan Wilcox</a>, <a href="mailto:bhines@alumni.ucsd.edu">Ben Hines</a><br>
-and <a href="mailto:qdc@eckysoft.com">Quentin D. Carnicelli</a>.</font>
+<font face="Lucida Grande" size="-1"><b>Thanks to</b> <a href="mailto:ryanwilcox@mac.com">Ryan Wilcox</a>, <a href="mailto:bhines@alumni.ucsd.edu">Ben Hines</a>,<br>
+<a href="mailto:fdj@elgato.com">Florian Dejako</a> and <a href="mailto:qdc@eckysoft.com">Quentin D. Carnicelli</a>.</font>
Index: /trunk/Cocoa/Pester/Source/MoreSecurity/MoreCFQ.c
===================================================================
--- /trunk/Cocoa/Pester/Source/MoreSecurity/MoreCFQ.c	(revision 118)
+++ /trunk/Cocoa/Pester/Source/MoreSecurity/MoreCFQ.c	(revision 118)
@@ -0,0 +1,836 @@
+/*
+	File:		MoreCFQ.c
+
+	Contains:	Core Foundation utility Routines.
+
+	Written by:	Quinn
+
+	Copyright:	Copyright (c) 2001 by Apple Computer, Inc., All Rights Reserved.
+
+	Disclaimer:	IMPORTANT:  This Apple software is supplied to you by Apple Computer, Inc.
+				("Apple") in consideration of your agreement to the following terms, and your
+				use, installation, modification or redistribution of this Apple software
+				constitutes acceptance of these terms.  If you do not agree with these terms,
+				please do not use, install, modify or redistribute this Apple software.
+
+				In consideration of your agreement to abide by the following terms, and subject
+				to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs
+				copyrights in this original Apple software (the "Apple Software"), to use,
+				reproduce, modify and redistribute the Apple Software, with or without
+				modifications, in source and/or binary forms; provided that if you redistribute
+				the Apple Software in its entirety and without modifications, you must retain
+				this notice and the following text and disclaimers in all such redistributions of
+				the Apple Software.  Neither the name, trademarks, service marks or logos of
+			 	Apple Computer, Inc. may be used to endorse or promote products derived from the
+				Apple Software without specific prior written permission from Apple.  Except as
+				expressly stated in this notice, no other rights or licenses, express or implied,
+				are granted by Apple herein, including but not limited to any patent rights that
+				may be infringed by your derivative works or by other works in which the Apple
+				Software may be incorporated.
+
+				The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO
+				WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+				WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+				PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
+				COMBINATION WITH YOUR PRODUCTS.
+
+				IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+				CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+				GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+				ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
+				OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
+				(INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
+				ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+	Change History (most recent first):
+
+$Log: MoreCFQ.c,v $
+Revision 1.5  2002/12/12 15:22:25  eskimo1
+Added CFQDictionaryMerge.
+
+Revision 1.4  2002/11/08 23:08:47  eskimo1
+Convert nil to NULL. Added CFQStringCopyCString. Convert MoreAssertQ to assert.
+
+Revision 1.3  2002/10/24 11:46:07  eskimo1
+Added CFQError routines.
+
+Revision 1.2  2002/01/22 06:14:19  eskimo1
+Change CFQDictionaryAddNumber to CFQDictionarySetNumber.
+
+Revision 1.1  2002/01/16 22:51:31  eskimo1
+First checked in.
+
+
+*/
+
+/////////////////////////////////////////////////////////////////
+
+// Our prototypes
+
+#include "MoreCFQ.h"
+
+// System interfaces
+
+#if ! MORE_FRAMEWORK_INCLUDES
+	#include <MacErrors.h>
+	#include <CFNumber.h>
+	#include <CFURLAccess.h>
+#endif
+
+#include <stdlib.h>
+
+/////////////////////////////////////////////////////////////////
+#pragma mark ***** Trivial Utilities
+
+extern pascal OSStatus CFQErrorBoolean(Boolean shouldBeTrue)
+{
+	OSStatus err;
+	
+	err = noErr;
+	if (!shouldBeTrue) {
+		err = coreFoundationUnknownErr;
+	}
+	return err;
+}
+
+extern pascal OSStatus CFQError(const void *shouldBeNotNULL)
+{
+	return CFQErrorBoolean(shouldBeNotNULL != NULL);
+}
+
+extern pascal CFTypeRef CFQRetain(CFTypeRef cf)
+	// See comment in header.
+{
+	if (cf != NULL) {
+		(void) CFRetain(cf);
+	}
+	return cf;
+}
+
+extern pascal void CFQRelease(CFTypeRef cf)
+	// See comment in header.
+{
+	if (cf != NULL) {
+		CFRelease(cf);
+	}
+}
+
+extern pascal OSStatus CFQDictionaryCreateMutable(CFMutableDictionaryRef *result)
+	// See comment in header.
+{
+	OSStatus err;
+	
+	assert( result != NULL);
+	assert(*result == NULL);
+
+	err = noErr;
+	*result = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+	if (*result == NULL) {
+		err = coreFoundationUnknownErr;
+	}
+	assert( (err == noErr) == (*result != NULL) );
+	return err;
+}
+
+extern pascal OSStatus CFQArrayCreateMutable(CFMutableArrayRef *result)
+	// See comment in header.
+{
+	OSStatus err;
+	
+	assert( result != NULL);
+	assert(*result == NULL);
+
+	err = noErr;
+	*result = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+	if (*result == NULL) {
+		err = coreFoundationUnknownErr;
+	}
+	assert( (err == noErr) == (*result != NULL) );
+	return err;
+}
+
+extern pascal OSStatus CFQArrayCreateWithDictionaryKeys(CFDictionaryRef dict, CFArrayRef *result)
+	// See comment in header.
+{
+	OSStatus 	err;
+	CFTypeRef *	keys;
+	
+	assert( dict   != NULL);
+	assert( result != NULL);
+	assert(*result == NULL);
+
+	// Allocate a buffer for the keys, get the keys into the buffer, and 
+	// create the array from that buffer.
+		
+	err = noErr;
+	keys = (CFTypeRef *) malloc( CFDictionaryGetCount(dict) * sizeof(CFTypeRef) );
+	if (keys == NULL) {
+		err = memFullErr;
+	}
+	if (err == noErr) {
+		CFDictionaryGetKeysAndValues(dict, (const void **) keys, NULL);
+		
+		*result = CFArrayCreate(NULL, keys, CFDictionaryGetCount(dict), &kCFTypeArrayCallBacks);
+		if (*result == NULL) {
+			err = coreFoundationUnknownErr;
+		}
+	}
+
+	// Clean up.
+		
+	if (keys != NULL) {
+		free(keys);
+	}
+	
+	assert( (err == noErr) == (*result != NULL) );
+	assert( (*result == NULL) || (CFDictionaryGetCount(dict) == CFArrayGetCount(*result)) );
+	
+	return err;
+}
+
+extern pascal OSStatus CFQArrayCreateWithDictionaryValues(CFDictionaryRef dict, CFArrayRef *result)
+	// See comment in header.
+{
+	OSStatus 	err;
+	CFTypeRef *	values;
+	
+	assert( dict   != NULL);
+	assert( result != NULL);
+	assert(*result == NULL);
+	
+	// Allocate a buffer for the values, get the values into the buffer, and 
+	// create the array from that buffer.
+
+	err = noErr;
+	values = (CFTypeRef *) malloc( CFDictionaryGetCount(dict) * sizeof(CFTypeRef) );
+	if (values == NULL) {
+		err = memFullErr;
+	}
+	if (err == noErr) {
+		CFDictionaryGetKeysAndValues(dict, NULL, (const void **) values);
+		
+		*result = CFArrayCreate(NULL, values, CFDictionaryGetCount(dict), &kCFTypeArrayCallBacks);
+		if (*result == NULL) {
+			err = coreFoundationUnknownErr;
+		}
+	}
+	
+	// Clean up.
+	
+	if (values != NULL) {
+		free(values);
+	}
+	
+	assert( (err == noErr) == (*result != NULL) );
+	assert( (*result == NULL) || (CFDictionaryGetCount(dict) == CFArrayGetCount(*result)) );
+	
+	return err;
+}
+
+extern pascal OSStatus CFQDictionaryCreateWithArrayOfKeysAndValues(CFArrayRef keys, 
+																   CFArrayRef values, 
+																   CFDictionaryRef *result)
+	// See comment in header.
+{
+	OSStatus    err;
+	CFIndex 	count;
+	CFTypeRef * keysBuffer;
+	CFTypeRef * valuesBuffer;
+	
+	assert(keys != NULL);
+	assert(values != NULL);
+	assert( CFArrayGetCount(keys) == CFArrayGetCount(values) );
+	assert( result != NULL);
+	assert(*result == NULL);
+	
+	keysBuffer   = NULL;
+	valuesBuffer = NULL;
+
+	// Check that the arrays are of a like size.
+		
+	err = noErr;
+	count = CFArrayGetCount(keys);
+	if ( count != CFArrayGetCount(values) ) {
+		err = paramErr;
+	}
+	
+	// Allocate a buffer for both keys and values.
+	
+	if (err == noErr) {
+		keysBuffer   = (CFTypeRef *) malloc( sizeof(CFTypeRef) * count );
+		valuesBuffer = (CFTypeRef *) malloc( sizeof(CFTypeRef) * count );
+		if (keysBuffer == NULL || valuesBuffer == NULL) {
+			err = memFullErr;
+		}
+	}
+	
+	// Get the keys and values into their buffers, and create a 
+	// dictionary based on the buffer.
+	
+	if (err == noErr) {
+		CFArrayGetValues(keys,   CFRangeMake(0, count), keysBuffer);
+		CFArrayGetValues(values, CFRangeMake(0, count), valuesBuffer);
+		
+		*result = CFDictionaryCreate(NULL, keysBuffer, valuesBuffer, count, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+		if (*result == NULL) {
+			err = coreFoundationUnknownErr;
+		}
+	}
+	
+	// Clean up.
+	
+	if (keysBuffer != NULL) {
+		free(keysBuffer);
+	}
+	if (valuesBuffer != NULL) {
+		free(valuesBuffer);
+	}
+	
+	return err;
+}
+
+extern pascal OSStatus CFQDictionarySetNumber(CFMutableDictionaryRef dict, const void *key, long value)
+	// See comment in header.
+{
+	OSStatus    err;
+	CFNumberRef valueNum;
+
+	// Create a CFNumber and add it to the dictionary.
+		
+	err = noErr;
+	valueNum = CFNumberCreate(NULL, kCFNumberLongType, &value);
+	if (valueNum == NULL) {
+		err = coreFoundationUnknownErr;
+	}
+	if (err == noErr) {
+		CFDictionarySetValue(dict, key, valueNum);
+	}
+	CFQRelease(valueNum);
+	
+	return err;
+}
+
+extern pascal OSStatus CFQStringCopyCString(CFStringRef str, CFStringEncoding encoding, char **cStrPtr)
+{
+	OSStatus		err;
+	CFIndex			cStrLen;
+	CFRange 		range;
+	
+	assert( str     != NULL);
+	assert( cStrPtr != NULL);
+	assert(*cStrPtr == NULL);
+
+	err = noErr;
+	
+	range = CFRangeMake(0, CFStringGetLength(str));
+		
+	(void) CFStringGetBytes(str, range, encoding, 0, false, NULL, 0, &cStrLen);
+
+	*cStrPtr = (char *) malloc( ((size_t) cStrLen) + 1);
+	if (*cStrPtr == NULL) {
+		err = memFullErr;
+	}
+
+	if (err == NULL) {
+		#if MORE_DEBUG
+			(*cStrPtr)[cStrLen] = '¥';
+		#endif
+		
+		if ( CFStringGetBytes(str, range, encoding, 0, false, (UInt8 *) *cStrPtr, cStrLen, &cStrLen) != range.length ) {
+			err = kCFQDataErr;
+		}
+	}
+	if (err == noErr) {		
+		assert((*cStrPtr)[cStrLen] == '¥');
+		(*cStrPtr)[cStrLen] = 0;
+	} else {
+		free(*cStrPtr);
+		*cStrPtr = NULL;
+	}
+
+	assert( (err == noErr) == (*cStrPtr != NULL) );
+
+	return err;
+}
+
+/////////////////////////////////////////////////////////////////
+#pragma mark ***** Dictionary Path Routines
+
+extern pascal OSStatus CFQDictionaryGetValueAtPath(CFDictionaryRef dict, 
+												   const void *path[], CFIndex pathElementCount, 
+												   const void **result)
+	// See comment in header.
+{
+	OSStatus 		err;
+	CFDictionaryRef parent;
+	CFIndex 		thisElement;
+	const void *	child;
+
+	assert( dict   != NULL);
+	assert( path   != NULL);
+	assert( pathElementCount > 0 );		// 0 length paths aren't allowed
+	assert( result != NULL);
+	assert(*result == NULL);
+
+	// This code hasn't been tested yet.
+	assert(false);
+	
+	// Some subtleties in the following loop.
+	//
+	// o It's possible for dictionaries to contain NULL values, so we use 
+	//   CFDictionaryGetValueIfPresent to test for the presence of the 
+	//   child rather than CFDictionaryGetValue.
+	//
+	// o We use CFDictionaryGetValueIfPresent in place of the combination of
+	//   CFDictionaryContainsKey and CFDictionaryGetValue because it does 
+	//   both operations in one hit.
+	// 
+	// o Loop terminates in one of three ways:
+	//     i) a path element isn't found (kCFQKeyNotFoundErr)
+	//    ii) we find the last path element
+	//   iii) we proceed to the next path element but the child we 
+	//        found isn't valid (kCFQDataErr)
+	//
+	// o There are no releases or retains in this loop because all values are 
+	//    got with "Get" operations.
+
+	err = noErr;		
+	thisElement = 0;
+	parent = dict;
+
+	while (true) {
+		if ( ! CFDictionaryGetValueIfPresent(parent, path[thisElement], &child) ) {
+			err = kCFQKeyNotFoundErr;
+			break;
+		}
+	
+		if (thisElement == (pathElementCount - 1)) {
+			break;
+		}
+		
+		if ( (child == NULL) || (CFGetTypeID(child) != CFDictionaryGetTypeID()) ) {
+			err = kCFQDataErr;
+			break;
+		}
+
+		parent = (CFDictionaryRef) child;
+		thisElement += 1;
+	}
+	
+	if (err == noErr) {
+		*result = child;
+	}
+	
+	assert( (err == noErr) == (*result != NULL) );
+	
+	return err;
+}
+
+static OSStatus PathArrayHelper(CFArrayRef path, CFTypeRef **pathElements)
+	// pathElements is a pointer to an array of CFTypeRefs. 
+	// On return, *pathElements is set to a newly allocated 
+	// array which you must free using "free".
+{
+	OSStatus err;
+	CFIndex  pathElementCount;
+
+	assert(path != NULL);
+	assert(pathElements != NULL);
+	// We don't assert that *pathElements is NULL because part of 
+	// our semantics is that we always set it to NULL.
+
+	pathElementCount = CFArrayGetCount(path);
+	assert(pathElementCount > 0);
+	
+	err = noErr;
+	*pathElements = (CFTypeRef *) malloc(sizeof(CFTypeRef) * pathElementCount);
+	if (*pathElements == NULL) {
+		err = memFullErr;
+	}
+	if (err == noErr) {
+		CFArrayGetValues(path, CFRangeMake(0, pathElementCount), *pathElements);
+	}
+	
+	assert( (err == noErr) == (*pathElements != NULL) );
+	
+	return err;
+}
+
+extern pascal OSStatus CFQDictionaryGetValueAtPathArray(CFDictionaryRef dict, 
+												   CFArrayRef path, 
+												   const void **result)
+	// See comment in header.
+{
+	OSStatus 	err;
+	CFTypeRef * pathElements;
+	
+	assert( dict   != NULL);
+	assert( path   != NULL);
+	assert( result != NULL);
+	assert(*result == NULL);
+
+	err = PathArrayHelper(path, &pathElements);
+	if (err == noErr) {
+		err = CFQDictionaryGetValueAtPath(dict, pathElements, CFArrayGetCount(path), result);
+	}
+	if (pathElements != NULL) {
+		free(pathElements);
+	}
+
+	assert( (err == noErr) == (*result != NULL) );
+
+	return err;
+}
+
+static OSStatus CFQMutableDictionaryGetParentForPath(CFMutableDictionaryRef dict,
+											   const void *path[], CFIndex pathElementCount, 
+											   CFMutableDictionaryRef *result)
+{
+	OSStatus 				err;
+	CFIndex 				thisElement;
+	CFMutableDictionaryRef 	parent;
+	CFDictionaryRef 		child;
+	
+	assert( dict   != NULL);
+	assert( path   != NULL);
+	assert( pathElementCount > 0 );		// 0 length paths aren't allowed
+	assert( result != NULL);
+
+	// Some subtleties in the following loop.
+	//
+	// o It's possible for dictionaries to contain NULL values, so we use 
+	//   CFDictionaryGetValueIfPresent to test for the presence of the 
+	//   child rather than CFDictionaryGetValue.
+	//
+	// o We use CFDictionaryGetValueIfPresent in place of the combination of
+	//   CFDictionaryContainsKey and CFDictionaryGetValue because it does 
+	//   both operations in one hit.
+	// 
+	// o Loop terminates in one of three ways:
+	//     i) we reach the last path element
+	//    ii) a path element isn't found (kCFQKeyNotFoundErr)
+	//   iii) we proceed to the next path element but the child we 
+	//        found isn't valid (kCFQDataErr)
+	//    iv) we get an error when creating a mutable dictionary
+	//
+	// o Memory tracking is very tricky.  Specifically, we have to be 
+	//   very careful with the mutableChild variable.  We create this 
+	//   each time we progress through a dictionary in the loop.  Each 
+	//   time we create it we then immediately add it to the parent 
+	//   dictionary, thus ensuring a continued reference count after 
+	//   we release our reference count.
+
+	err = noErr;
+	thisElement = 0;
+	parent = dict;
+
+	while (true) {
+		if (thisElement == (pathElementCount - 1)) {
+			break;
+		}
+
+		if ( ! CFDictionaryGetValueIfPresent(parent, path[thisElement], (const void **) &child) ) {
+			err = kCFQKeyNotFoundErr;
+			break;
+		}
+	
+		if ( (child == NULL) || (CFGetTypeID(child) != CFDictionaryGetTypeID()) ) {
+			err = kCFQDataErr;
+			break;
+		}
+		
+		{
+			CFMutableDictionaryRef mutableChild;
+			
+			mutableChild = CFDictionaryCreateMutableCopy(NULL, 0, child);
+			if (mutableChild == NULL) {
+				err = coreFoundationUnknownErr;
+			}
+			if (err == noErr) {
+				CFDictionarySetValue(parent, path[thisElement], mutableChild);
+				
+				assert( CFGetRetainCount(mutableChild) >= 2 );
+				
+				parent = mutableChild;
+				thisElement += 1;
+			}
+			
+			CFQRelease(mutableChild);
+		}
+		if (err != noErr) {
+			break;
+		}
+	}
+	if (err == noErr) {
+		*result = parent;
+	}
+	
+	assert( (err == noErr) == (*result != NULL) );
+	
+	return err;
+}
+
+extern pascal OSStatus CFQDictionarySetValueAtPath(CFMutableDictionaryRef dict, 
+												   const void *path[], CFIndex pathElementCount, 
+												   const void *value)
+	// See comment in header.
+{
+	OSStatus 				err;
+	CFMutableDictionaryRef 	parent;
+	
+	assert( dict   != NULL);
+	assert( path   != NULL);
+	assert( pathElementCount > 0 );		// 0 length paths aren't allowed
+
+	err = CFQMutableDictionaryGetParentForPath(dict, path, pathElementCount, &parent);
+	if (err == noErr) {
+		CFDictionarySetValue(parent, path[pathElementCount - 1], value);
+	}
+
+	return err;	
+}
+
+extern pascal OSStatus CFQDictionarySetValueAtPathArray(CFMutableDictionaryRef dict, 
+												   CFArrayRef path, 
+												   const void *value)
+	// See comment in header.
+{
+	OSStatus 	err;
+	CFTypeRef *	pathElements;
+	
+	assert( dict   != NULL);
+	assert( path   != NULL);
+
+	err = PathArrayHelper(path, &pathElements);
+	if (err == noErr) {
+		err = CFQDictionarySetValueAtPath(dict, pathElements, CFArrayGetCount(path), value);
+	}
+	if (pathElements != NULL) {
+		free(pathElements);
+	}
+
+	return err;
+}
+
+extern pascal OSStatus CFQDictionaryRemoveValueAtPath(CFMutableDictionaryRef dict, 
+												   const void *path[], CFIndex pathElementCount)
+	// See comment in header.
+{
+	OSStatus 				err;
+	CFMutableDictionaryRef 	parent;
+	
+	assert( dict   != NULL);
+	assert( path   != NULL);
+	assert( pathElementCount > 0 );		// 0 length paths aren't allowed
+
+	err = CFQMutableDictionaryGetParentForPath(dict, path, pathElementCount, &parent);
+	if ( ! CFDictionaryContainsKey(parent, path[pathElementCount - 1]) ) {
+		err = kCFQKeyNotFoundErr;
+	}
+	if (err == noErr) {
+		CFDictionaryRemoveValue(parent, path[pathElementCount - 1]);
+	}
+
+	return err;	
+}
+
+extern pascal OSStatus CFQDictionaryRemoveValueAtPathArray(CFMutableDictionaryRef dict, 
+												   CFArrayRef path)
+	// See comment in header.
+{
+	OSStatus 	err;
+	CFTypeRef *	pathElements;
+	
+	assert( dict   != NULL);
+	assert( path   != NULL);
+
+	err = PathArrayHelper(path, &pathElements);
+	if (err == noErr) {
+		err = CFQDictionaryRemoveValueAtPath(dict, pathElements, CFArrayGetCount(path));
+	}
+	if (pathElements != NULL) {
+		free(pathElements);
+	}
+
+	return err;
+}
+
+/////////////////////////////////////////////////////////////////
+#pragma mark ***** Property List Traversal Routines
+
+extern pascal void CFQPropertyListDeepApplyFunction(CFPropertyListRef propList, 
+													CFQPropertyListDeepApplierFunction func,
+													void *context)
+	// See comment in header.
+{
+	assert(propList != NULL);
+	assert(func     != NULL);
+	
+	// Call "func" for this node.
+	
+	func(propList, context);
+	
+	// If this node is a dictionary or an array, call func for 
+	// each element.
+	
+	if ( CFGetTypeID(propList) == CFDictionaryGetTypeID() ) {
+		CFIndex count;
+		CFIndex index;
+		const void **keys;
+		
+		count = CFDictionaryGetCount( (CFDictionaryRef) propList);
+		
+		keys = (const void **) malloc( count * sizeof(const void *));
+		if (keys != NULL) {
+			CFDictionaryGetKeysAndValues( (CFDictionaryRef) propList, keys, NULL);
+			
+			for (index = 0; index < count; index++) {
+				CFQPropertyListDeepApplyFunction(CFDictionaryGetValue( (CFDictionaryRef) propList, keys[index]), func, context);
+			}
+			free(keys);
+		}
+	} else if ( CFGetTypeID(propList) == CFArrayGetTypeID() ) {
+		CFIndex count;
+		long    index;
+		
+		count = CFArrayGetCount( (CFArrayRef) propList);
+		for (index = 0; index < count; index++) {
+			CFQPropertyListDeepApplyFunction(CFArrayGetValueAtIndex( (CFArrayRef) propList, index), func, context);
+		}
+	}
+}
+
+extern pascal Boolean CFQPropertyListIsLeaf(CFTypeRef node)
+	// See comment in header.
+{
+	return ! (	   (CFGetTypeID(node) == CFDictionaryGetTypeID())
+				|| (CFGetTypeID(node) == CFArrayGetTypeID())      );
+}
+
+extern pascal void CFQPropertyListShallowApplyFunction(CFPropertyListRef propList, 
+													   CFQPropertyListShallowApplierFunction func,
+													   void *context)
+	// See comment in header.
+{
+	assert(propList != NULL);
+	assert(func     != NULL);
+
+	// If this node is a dictionary, call "func" for each element.
+	//
+	// If this node is an array, call "func" for each element and 
+	// pass a CFNumber of the element's array index to its "key" 
+	// parameter.
+	
+	if ( CFGetTypeID(propList) == CFDictionaryGetTypeID() ) {
+		CFIndex count;
+		CFIndex index;
+		const void **keys;
+		
+		count = CFDictionaryGetCount( (CFDictionaryRef) propList);
+		
+		keys = (const void **) malloc( count * sizeof(const void *));
+		if (keys != NULL) {
+			CFDictionaryGetKeysAndValues( (CFDictionaryRef) propList, keys, NULL);
+			
+			for (index = 0; index < count; index++) {
+				func(keys[index], CFDictionaryGetValue( (CFDictionaryRef) propList, keys[index]), context);
+			}
+			free(keys);
+		}
+	} else if ( CFGetTypeID(propList) == CFArrayGetTypeID() ) {
+		CFIndex count;
+		CFIndex index;
+		
+		count = CFArrayGetCount( (CFArrayRef) propList);
+		for (index = 0; index < count; index++) {
+			CFNumberRef key;
+			
+			key = CFNumberCreate(NULL, kCFNumberLongType, &index);
+			if (key != NULL) {
+				func(key, CFArrayGetValueAtIndex( (CFArrayRef) propList, index), context);
+				CFRelease(key);
+			}
+		}
+	} else {
+		assert(false);
+	}
+}
+
+extern pascal OSStatus CFQPropertyListCreateFromXMLFSRef(const FSRef *xmlFile, CFPropertyListMutabilityOptions options, CFPropertyListRef *result)
+	// See comment in header.
+{
+	OSStatus  err;
+	CFURLRef  xmlURL;
+	
+	assert(xmlFile != NULL);
+	assert( result != NULL);
+	assert(*result == NULL);
+	
+	xmlURL = CFURLCreateFromFSRef(NULL, xmlFile);
+	err = CFQError(xmlURL);
+	if (err == noErr) {
+		err = CFQPropertyListCreateFromXMLCFURL(xmlURL, options, result);
+	}
+	
+	CFQRelease(xmlURL);
+	
+	assert( (err == noErr) == (*result != NULL) );
+
+	return err;
+}
+
+extern pascal OSStatus CFQPropertyListCreateFromXMLCFURL(CFURLRef xmlFile, CFPropertyListMutabilityOptions options, CFPropertyListRef *result)
+	// See comment in header.
+{
+	OSStatus  err;
+	CFDataRef xmlData;
+	
+	assert(xmlFile != NULL);
+	assert( result != NULL);
+	assert(*result == NULL);
+
+	xmlData = NULL;
+
+	err = noErr;
+	if ( ! CFURLCreateDataAndPropertiesFromResource(NULL, xmlFile, &xmlData, NULL, NULL, &err) && (err == noErr) ) {
+		err = coreFoundationUnknownErr;
+	}
+	
+	if (err == noErr) {
+		*result = CFPropertyListCreateFromXMLData(NULL, xmlData, options, NULL);
+		if (*result == NULL) {
+			err = coreFoundationUnknownErr;
+		}
+	}
+
+	CFQRelease(xmlData);
+
+	assert( (err == noErr) == (*result != NULL) );
+	
+	return err;
+}
+
+static void MergeOne(const void *key, const void *value, void *context)
+{
+	CFMutableDictionaryRef 	dst;
+	
+	assert(context != NULL);
+	
+	dst = (CFMutableDictionaryRef) context;
+	assert( CFGetTypeID(dst) == CFDictionaryGetTypeID() );
+	
+	CFDictionarySetValue(dst, key, value);
+}
+
+extern pascal OSStatus CFQDictionaryMerge(CFMutableDictionaryRef dst, CFDictionaryRef src)
+{
+	OSStatus err;
+	
+	assert(dst != NULL);
+	assert(src != NULL);
+	
+	err = noErr;
+	CFDictionaryApplyFunction(src, MergeOne, dst);
+	
+	return err;
+}
Index: /trunk/Cocoa/Pester/Source/MoreSecurity/MoreCFQ.h
===================================================================
--- /trunk/Cocoa/Pester/Source/MoreSecurity/MoreCFQ.h	(revision 118)
+++ /trunk/Cocoa/Pester/Source/MoreSecurity/MoreCFQ.h	(revision 118)
@@ -0,0 +1,334 @@
+/*
+	File:		MoreCFQ.h
+
+	Contains:	Core Foundation utility Routines.
+
+	Written by:	Quinn
+
+	Copyright:	Copyright (c) 2001 by Apple Computer, Inc., All Rights Reserved.
+
+	Disclaimer:	IMPORTANT:  This Apple software is supplied to you by Apple Computer, Inc.
+				("Apple") in consideration of your agreement to the following terms, and your
+				use, installation, modification or redistribution of this Apple software
+				constitutes acceptance of these terms.  If you do not agree with these terms,
+				please do not use, install, modify or redistribute this Apple software.
+
+				In consideration of your agreement to abide by the following terms, and subject
+				to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs
+				copyrights in this original Apple software (the "Apple Software"), to use,
+				reproduce, modify and redistribute the Apple Software, with or without
+				modifications, in source and/or binary forms; provided that if you redistribute
+				the Apple Software in its entirety and without modifications, you must retain
+				this notice and the following text and disclaimers in all such redistributions of
+				the Apple Software.  Neither the name, trademarks, service marks or logos of
+				Apple Computer, Inc. may be used to endorse or promote products derived from the
+				Apple Software without specific prior written permission from Apple.  Except as
+				expressly stated in this notice, no other rights or licenses, express or implied,
+				are granted by Apple herein, including but not limited to any patent rights that
+				may be infringed by your derivative works or by other works in which the Apple
+				Software may be incorporated.
+
+				The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO
+				WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+				WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+				PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
+				COMBINATION WITH YOUR PRODUCTS.
+
+				IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+				CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+				GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+				ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
+				OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
+				(INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
+				ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+	Change History (most recent first):
+
+$Log: MoreCFQ.h,v $
+Revision 1.6  2002/12/12 15:22:29  eskimo1
+Added CFQDictionaryMerge.
+
+Revision 1.5  2002/11/25 18:08:31  eskimo1
+Allow non-Carbon builds.
+
+Revision 1.4  2002/11/08 23:07:22  eskimo1
+When using framework includes, explicitly include the frameworks we need. Convert nil to NULL. Added CFQStringCopyCString.
+
+Revision 1.3  2002/10/24 11:46:27  eskimo1
+Added CFQError routines. Fixed non-framework includes build.
+
+Revision 1.2  2002/01/22 06:14:21  eskimo1
+Change CFQDictionaryAddNumber to CFQDictionarySetNumber.
+
+Revision 1.1  2002/01/16 22:51:32  eskimo1
+First checked in.
+
+
+*/
+
+#pragma once
+
+/////////////////////////////////////////////////////////////////
+
+// MoreIsBetter Setup
+
+#include "MoreSetup.h"
+
+// System Interfaces
+
+#if MORE_FRAMEWORK_INCLUDES
+	#include <CoreServices/CoreServices.h>
+#else
+	#include <CFBase.h>
+	#include <CFURL.h>
+	#include <CFPropertyList.h>
+	#include <Files.h>
+#endif
+
+/////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/////////////////////////////////////////////////////////////////
+// Trivial Utilities
+
+enum {
+	kCFQKeyNotFoundErr = 5400,
+	kCFQDataErr = 5401
+};
+
+extern pascal OSStatus CFQErrorBoolean(Boolean shouldBeTrue);
+extern pascal OSStatus CFQError(const void *shouldBeNotNULL);
+
+// Two wrappers around CFRelease/Retain that allow you to pass in NULL.
+
+extern pascal CFTypeRef CFQRetain(CFTypeRef cf);
+	// CFRetain if cf is not NULL.  Returns cf.
+	
+extern pascal void CFQRelease(CFTypeRef cf);
+	// CFRelease if cf is not NULL.
+
+extern pascal OSStatus CFQArrayCreateMutable(CFMutableArrayRef *result);
+	// Creates an empty CFMutableArray that holds other CFTypes.
+	//
+	// result must not be NULL.
+	// On input, *result must be NULL.
+	// On error, *result will be NULL.
+	// On success, *result will be an empty mutable array.
+
+extern pascal OSStatus CFQArrayCreateWithDictionaryKeys(CFDictionaryRef dict, CFArrayRef *result);
+extern pascal OSStatus CFQArrayCreateWithDictionaryValues(CFDictionaryRef dict, CFArrayRef *result);
+	// Creates an array that holds all of the keys (or values) of dict.
+	//
+	// dict must not be NULL.
+	// result must not be NULL.
+	// On input, *result must be NULL.
+	// On error, *result will be NULL.
+	// On success, *result will be an array.
+
+extern pascal OSStatus CFQDictionaryCreateMutable(CFMutableDictionaryRef *result);
+	// Creates an empty CFMutableDictionary that holds other CFTypes.
+	//
+	// result must not be NULL.
+	// On input, *result must be NULL.
+	// On error, *result will be NULL.
+	// On success, *result will be an empty mutable dictionary.
+
+extern pascal OSStatus CFQDictionaryCreateWithArrayOfKeysAndValues(CFArrayRef keys, 
+																   CFArrayRef values, 
+																   CFDictionaryRef *result);
+	// Creates a dictionary with the specified keys and values.
+	//
+	// keys must not be NULL.
+	// values must not be NULL.
+	// The length of keys and values must be the same.
+	// result must not be NULL.
+	// On input, *result must be NULL.
+	// On error, *result will be NULL.
+	// On success, *result will be an empty mutable dictionary.
+
+extern pascal OSStatus CFQDictionarySetNumber(CFMutableDictionaryRef dict, const void *key, long value);
+	// Set a CFNumber (created using kCFNumberLongType) in the 
+	// dictionary with the specified key.  If an error is returned 
+	// the dictionary will be unmodified.
+
+extern pascal OSStatus CFQStringCopyCString(CFStringRef str, CFStringEncoding encoding, char **cStrPtr);
+	// Extracts a C string from an arbitrary length CFString. 
+	// The caller must free the resulting string using "free".
+	// Returns kCFQDataErr if the CFString contains characters 
+	// that can't be encoded in encoding.
+	// 
+	// str must not be NULL
+	// On input,  cStrPtr must not be NULL
+	// On input, *cStrPtr must be NULL
+	// On error, *cStrPtr will be NULL
+	// On success, *cStrPtr will be a C string that you must free
+
+/////////////////////////////////////////////////////////////////
+// Dictionary Path Routines
+
+extern pascal OSStatus CFQDictionaryGetValueAtPath(CFDictionaryRef dict, 
+												   const void *path[], CFIndex pathElementCount, 
+												   const void **result);
+	// Given a dictionary possibly containing nested dictionaries, 
+	// this routine returns the value specified by path.  path is 
+	// unbounded array of dictionary keys.  The first element of 
+	// path must be the key of a property in dict.  If path has 
+	// more than one element then the value of the property must 
+	// be a dictionary and the next element of path must be a 
+	// key in that dictionary.  And so on.  The routine returns 
+	// the value of the dictionary property found at the end 
+	// of the path.
+	//
+	// For example, if path is "A"/"B"/"C", then dict must contain 
+	// a property whose key is "A" and whose value is a dictionary. 
+	// That dictionary must contain a property whose key is "B" and 
+	// whose value is a dictionary.  That dictionary must contain 
+	// a property whose key is "C" and whose value this routine 
+	// returns.
+	//
+	// dict must not be NULL.
+	// path must not be NULL.
+	// pathElementCount must be greater than 0.
+	// result must not be NULL.
+	// On input, *result must be NULL.
+	// On error, *result will be NULL.
+	// On success, *result is the value from the dictionary.
+
+extern pascal OSStatus CFQDictionaryGetValueAtPathArray(CFDictionaryRef dict, 
+												   CFArrayRef path, 
+												   const void **result);
+	// This routine is identical to CFQDictionaryGetValueAtPath except 
+	// that you supply path as a CFArray instead of a C array.
+	//
+	// dict must not be NULL.
+	// path must not be NULL.
+	// path must have at least one element.
+	// result must not be NULL.
+	// On input, *result must be NULL.
+	// On error, *result will be NULL.
+	// On success, *result is the value from the dictionary.
+	
+extern pascal OSStatus CFQDictionarySetValueAtPath(CFMutableDictionaryRef dict, 
+												   const void *path[], CFIndex pathElementCount, 
+												   const void *value);
+	// This routines works much like CFQDictionaryGetValueAtPath 
+	// except that it sets the value at the end of the path 
+	// instead of returning it.  For the set to work, 
+	// dict must be mutable.  However, the dictionaries 
+	// nested inside dict may not be mutable.  To make this 
+	// work this routine makes a mutable copy of any nested 
+	// dictionaries it traverses and replaces the (possibly) 
+	// immutable nested dictionaries with these mutable versions. 
+	//
+	// The path need not necessarily denote an existing node 
+	// in the nested dictionary tree.  However, this routine 
+	// will only create a leaf node.  It won't create any 
+	// parent nodes required to holf that leaf.
+	//
+	// dict must not be NULL.
+	// path must not be NULL.
+	// pathElementCount must be greater than 0.
+
+extern pascal OSStatus CFQDictionarySetValueAtPathArray(CFMutableDictionaryRef dict, 
+												   CFArrayRef path, 
+												   const void *value);
+	// This routine is identical to CFQDictionarySetValueAtPath except 
+	// that you supply path as a CFArray instead of a C array.
+	// 
+	// dict must not be NULL.
+	// path must not be NULL.
+	// path must have at least one element.
+
+extern pascal OSStatus CFQDictionaryRemoveValueAtPath(CFMutableDictionaryRef dict, 
+												   const void *path[], CFIndex pathElementCount);
+	// This routines works much like CFQDictionarySetValueAtPath 
+	// except that it removes the value at the end of the path. 
+	//
+	// Unlike CFQDictionarySetValueAtPath, this routine requires 
+	// that path denote an existing node in the nested dictionary 
+	// tree.  Removing a non-existant node, even a leaf node, 
+	// results in an error.
+	// 
+	// dict must not be NULL.
+	// path must not be NULL.
+	// pathElementCount must be greater than 0.
+	
+extern pascal OSStatus CFQDictionaryRemoveValueAtPathArray(CFMutableDictionaryRef dict, 
+												   CFArrayRef path);
+	// This routine is identical to CFQDictionaryRemoveValueAtPathArray 
+	// except that you supply path as a CFArray instead of a C array.
+	// 
+	// dict must not be NULL.
+	// path must not be NULL.
+	// path must have at least one element.
+
+/////////////////////////////////////////////////////////////////
+// Property List Traversal Routines
+
+typedef pascal void (*CFQPropertyListDeepApplierFunction)(CFTypeRef node, void *context);
+	// A callback function for CFQPropertyListDeepApplyFunction.
+
+extern pascal void CFQPropertyListDeepApplyFunction(CFPropertyListRef propList, 
+													CFQPropertyListDeepApplierFunction func,
+													void *context);
+	// Calls "func" for every node in the property list.
+	// 
+	// propList must not be NULL.
+	// func must not be NULL.
+
+extern pascal Boolean CFQPropertyListIsLeaf(CFTypeRef node);
+	// Given a node in a property list, this routine returns 
+	// true if the node is a leaf (ie not a dictionary or an 
+	// array).
+
+typedef pascal void (*CFQPropertyListShallowApplierFunction)(CFTypeRef key, CFTypeRef node, void *context);
+	// A callback function for CFQPropertyListShallowApplyFunction. 
+	// 
+	// node must be an element of either a dictionary or an array. 
+	// If node is an element of a dictionary, key is its key within 
+	// the dictionary.  If node is an element of an array, key 
+	// is a CFNumber of its index in the array.
+
+extern pascal void CFQPropertyListShallowApplyFunction(CFPropertyListRef propList, 
+													   CFQPropertyListShallowApplierFunction func,
+													   void *context);
+	// Calls "func" for every node in the first level of the 
+	// property list.  propList must be either a dictionary 
+	// or an array.  To continue to lower levels, "func" should 
+	// call CFQPropertyListApplyFunctionShallow again (only if 
+	// CFQPropertyListIsLeaf is false).
+	// 
+	// propList must not be NULL.
+	// func must not be NULL.
+
+extern pascal OSStatus CFQPropertyListCreateFromXMLFSRef(const FSRef *xmlFile, CFPropertyListMutabilityOptions options, CFPropertyListRef *result);
+	// Creates a property list based on the XML in the file.
+	//
+	// xmlFile must not be NULL
+	// result must not be NULL
+	// *result must be NULL
+	// on success, *result will be a valid property list
+	// on error, *result will be NULL
+	
+extern pascal OSStatus CFQPropertyListCreateFromXMLCFURL(CFURLRef xmlFile, CFPropertyListMutabilityOptions options, CFPropertyListRef *result);
+	// Creates a property list based on the XML in the file.
+	//
+	// xmlFile must not be NULL
+	// result must not be NULL
+	// *result must be NULL
+	// on success, *result will be a valid property list
+	// on error, *result will be NULL
+
+extern pascal OSStatus CFQDictionaryMerge(CFMutableDictionaryRef dst, CFDictionaryRef src);
+	// Adds every key/value pair from src into dst, overwriting any 
+	// current value for the key.
+	//
+	// dst must not be NULL
+	// src must not be NULL
+	
+#ifdef __cplusplus
+}
+#endif
Index: /trunk/Cocoa/Pester/Source/MoreSecurity/MoreSecurity.c
===================================================================
--- /trunk/Cocoa/Pester/Source/MoreSecurity/MoreSecurity.c	(revision 118)
+++ /trunk/Cocoa/Pester/Source/MoreSecurity/MoreSecurity.c	(revision 118)
@@ -0,0 +1,1723 @@
+/*
+	File:		MoreSecurity.c
+
+	Contains:	Security utilities.
+
+	Written by:	Quinn
+
+	Copyright:	Copyright (c) 2002 by Apple Computer, Inc., All Rights Reserved.
+
+	Disclaimer:	IMPORTANT:  This Apple software is supplied to you by Apple Computer, Inc.
+				("Apple") in consideration of your agreement to the following terms, and your
+				use, installation, modification or redistribution of this Apple software
+				constitutes acceptance of these terms.  If you do not agree with these terms,
+				please do not use, install, modify or redistribute this Apple software.
+
+				In consideration of your agreement to abide by the following terms, and subject
+				to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs
+				copyrights in this original Apple software (the "Apple Software"), to use,
+				reproduce, modify and redistribute the Apple Software, with or without
+				modifications, in source and/or binary forms; provided that if you redistribute
+				the Apple Software in its entirety and without modifications, you must retain
+				this notice and the following text and disclaimers in all such redistributions of
+				the Apple Software.  Neither the name, trademarks, service marks or logos of
+				Apple Computer, Inc. may be used to endorse or promote products derived from the
+				Apple Software without specific prior written permission from Apple.  Except as
+				expressly stated in this notice, no other rights or licenses, express or implied,
+				are granted by Apple herein, including but not limited to any patent rights that
+				may be infringed by your derivative works or by other works in which the Apple
+				Software may be incorporated.
+
+				The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO
+				WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+				WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+				PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
+				COMBINATION WITH YOUR PRODUCTS.
+
+				IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+				CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+				GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+				ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
+				OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
+				(INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
+				ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+	Change History (most recent first):
+
+$Log: MoreSecurity.c,v $
+Revision 1.5  2002/12/12 23:15:23  eskimo1
+Switch EUID back to RUID after we return from the commandProc, just in case the client left it set the wrong way.
+
+Revision 1.4  2002/12/12 15:41:53  eskimo1
+Eliminate MoreAuthCopyRightCFString because it makes no sense.  A helper tool should always have the right name hard-wired into it, and hardwiring a C string is even easier than hardwiring a CFString.  Also added some more debugging printfs.
+
+Revision 1.3  2002/11/25 16:42:25  eskimo1
+Significant changes. Handle more edge cases better (for example, volumes with the "ignore permissions" flag turned on). Also brought MoreSecurity more into the CoreServices world.
+
+Revision 1.2  2002/11/14 20:27:59  eskimo1
+Compare time stamps in MoreSecCopyHelperToolURLRef to decide whether to throw away the tool and revert to the backup.  This greatly improves the debugging experience.  Also, in MoreSecExecuteRequestInHelperTool, add code to dispose of a partial response if we get an error (prevents a memory leak in some very specific error conditions). Finally, in MoreSecGetErrorFromResponse, eliminate an unnecessary CFRelease.
+
+Revision 1.1  2002/11/09 00:08:36  eskimo1
+First checked in. A module containing security helpers.
+
+
+*/
+
+/////////////////////////////////////////////////////////////////
+
+// Our prototypes
+
+#include "MoreSecurity.h"
+
+// System interfaces
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+
+// MIB Interfaces
+
+#include "MoreUNIX.h"
+#include "MoreCFQ.h"
+
+/////////////////////////////////////////////////////////////////
+#pragma mark ***** UID Management
+
+extern int MoreSecPermanentlySetNonPrivilegedEUID(void)
+	// See comment in header.
+{
+	int err;
+                           
+    err = setuid(getuid());
+    if (err != 0) {
+        err = errno;
+    }
+    return err;
+}    
+    
+extern int MoreSecTemporarilySetNonPrivilegedEUID(void)
+	// See comment in header.
+{
+	int err;
+                           
+    err = seteuid(getuid());
+    if (err != 0) {
+        err = errno;
+    }
+    return err;
+}
+
+extern int MoreSecSetPrivilegedEUID(void)
+	// See comment in header.
+{                           
+	int err;
+
+    err = seteuid(0);
+    if (err != 0) {
+        err = errno;
+    }
+	return err;
+}
+    
+/////////////////////////////////////////////////////////////////
+#pragma mark ***** MoreSecDestroyInheritedEnvironment
+
+static int GetPathToSelf(char **pathToSelfPtr)
+	// A simple wrapper around MoreGetExecutablePath which returns 
+	// the path in a memory block that you must free.
+{
+	int 		err;
+    size_t 		pathSize;
+    char		junkChar;
+
+	assert( pathToSelfPtr != NULL);
+	assert(*pathToSelfPtr == NULL);
+
+	*pathToSelfPtr = &junkChar;
+	
+	pathSize = 0;
+	err = MoreGetExecutablePath(*pathToSelfPtr, &pathSize);
+	if (pathSize == 0) {
+		assert(err != 0);
+		if (err != 0) {
+			err = -1;
+		}
+		*pathToSelfPtr = NULL;
+	} else {
+		pathSize += 1;
+		
+		err = 0;
+		*pathToSelfPtr = (char *) malloc(pathSize);
+		if ( *pathToSelfPtr == NULL ) {
+			err = ENOMEM;
+		}
+
+		if (err == 0) {
+			err = MoreGetExecutablePath(*pathToSelfPtr, &pathSize);
+		}
+		
+		if (err != 0) {
+			free(*pathToSelfPtr);
+			*pathToSelfPtr = NULL;
+		}
+	}
+
+	assert( (err == 0) == (*pathToSelfPtr != NULL) );
+	
+	return err;
+}
+
+static int ResetArgvZero(const char **argv)
+    // Sets argv[0] to be the true path to the executable 
+    // rather than a potentially hostile value supplied by 
+    // our parent process.
+{
+    int     err;
+    char *  execPath;
+    
+    execPath = NULL;
+    
+    err = GetPathToSelf(&execPath);
+    
+    // Copy the real executable path into argv[0].
+    
+    if (err == 0) {
+        argv[0] = execPath;
+    }
+    
+    // If we got an error then free any buffer we may have 
+    // allocated.  On no error we end up leaking execPath, but 
+    // that's acceptable because this function is usually only 
+    // called once at process startup.
+    
+    if (err != 0) {
+        free(execPath);
+    }
+    
+    return err;
+}
+
+extern char **environ;
+
+static int ResetEnvironment(void)
+    // Clears all environment variables.  There are circumstances 
+    // where your process might depend on certain environment 
+    // variables being set correctly, but if that's the case you 
+    // shouldn't be relying on inheriting good values from an 
+    // untrusted parent. You should, instead, set the environment 
+    // variables explicitly after calling 
+    // MoreSecDestroyInheritedEnvironment.
+{
+    while ( environ[0] != NULL ) {
+        unsetenv(environ[0]);
+    }
+    return 0;
+}
+
+static int CloseOpenFileDescriptorsInRange(int start, int limit)
+    // Closes all the file descriptor in the range 
+    // start <= fd < limit. 
+{
+    int err;
+    int fd;
+    
+    err = 0;
+    for (fd = start; fd < limit; fd++) {
+        err = close(fd);
+        if (err == -1) {
+            err = errno;
+        }
+        if (err == EBADF) {
+            err = 0;
+        }
+        if (err != 0) {
+            break;
+        }
+    }
+    return err;
+}
+
+static int ResetAllSignalsToDefault(void)
+    // Resets all signals to their default actions and the signal 
+    // mask to its default value (empty). If you use signals in 
+    // your program you should establish your signal handlers 
+    // after calling MoreSecDestroyInheritedEnvironment.
+{
+    int         err;
+    int         sig;
+    sigset_t    empty;
+
+    // First set all of the signals to their default actions.
+
+    err = 0;
+    for (sig = 0; sig < NSIG; sig++) {
+        if ( signal(sig, SIG_DFL) == SIG_ERR ) {
+            if (    sig == 0 
+                 || sig == SIGKILL 
+                 || sig == SIGSTOP) {
+                // ignore the error
+            } else {
+                err = errno;
+                break;
+            }
+        }
+    }
+
+    // Then set the signal mask to its default value (empty).
+    
+    if (err == 0) {
+        err = sigemptyset(&empty);
+        if (err == -1) {
+            err = errno;
+        }
+    }
+    if (err == 0) {
+        err = sigprocmask(SIG_SETMASK, &empty, NULL);
+        if (err == -1) {
+            err = errno;
+        }
+    }
+    
+    return err;
+}
+
+// The following is a table of resource limits established 
+// by this program. This table is based on the default values 
+// from Mac OS X 10.1.x.  Unfortunately there's no way to 
+// determine the system-wide defaults programmatically.
+
+typedef struct {
+    int     resource;
+    rlim_t  rlim_cur;
+    rlim_t  rlim_max;
+} ResourceLimitTemplate;
+
+static ResourceLimitTemplate kResourceLimits[9] = {
+    {RLIMIT_CPU,     RLIM_INFINITY, RLIM_INFINITY},
+    {RLIMIT_FSIZE,   RLIM_INFINITY, RLIM_INFINITY},
+    {RLIMIT_DATA,    0x600000,      RLIM_INFINITY},
+    {RLIMIT_STACK,   0x80000,       0x4000000    },
+    {RLIMIT_CORE,    0,             RLIM_INFINITY},
+    {RLIMIT_RSS,     RLIM_INFINITY, RLIM_INFINITY},
+    {RLIMIT_MEMLOCK, RLIM_INFINITY, RLIM_INFINITY},
+    {RLIMIT_NPROC,   100,           RLIM_INFINITY},
+    {RLIMIT_NOFILE,  256,           RLIM_INFINITY}
+};
+
+// The upper bound for RLIMIT_NPROC is really 100, 
+// or 532 if you're EUID 0.
+//
+// The upper bound for RLIMIT_NOFILE is really 10240, 
+// or 12288 if you're EUID 0.
+
+static const int kResourceLimitsCount = 
+        sizeof(kResourceLimits) / sizeof(kResourceLimits[0]);
+
+static int ResetAllResourceLimitsToDefault(void)
+    // Resets all resource limits to their defaults, 
+    // based on the kResourceLimits table.  Note that we 
+    // only attempt to set the rlim_max if we're EUID 0 
+    // because getrlimit sometimes does not return the 
+    // real maximum limit [2941095].
+{
+    int err;
+    int i;
+    
+    err = 0;
+    for (i = 0; i < kResourceLimitsCount; i++) {
+        struct rlimit thisLimit;
+        
+        err = getrlimit(kResourceLimits[i].resource, 
+                        &thisLimit);
+        if (err == -1) {
+            err = errno;
+        }
+        if (err == 0) {
+            thisLimit.rlim_cur = kResourceLimits[i].rlim_cur;
+            if (geteuid() == 0) {
+                thisLimit.rlim_max = kResourceLimits[i].rlim_max;
+            }
+            err = setrlimit(kResourceLimits[i].resource, 
+                            &thisLimit);
+            if (err == -1 ) {
+                err = errno;
+            }
+        }
+        if (err != 0) {
+            break;
+        }
+    }
+    
+    return err;
+}
+
+static int ResetAllTimers(void)
+    // Disables all interval timers that might have 
+    // been inherited from the parent process.
+{
+    int                 err;
+    struct itimerval    disable;
+
+    timerclear(&disable.it_interval);
+    timerclear(&disable.it_value);
+    
+    err = setitimer(ITIMER_REAL,    &disable, NULL);
+    if (err == -1) {
+        err = errno;
+    }
+    err = setitimer(ITIMER_VIRTUAL, &disable, NULL);
+    if (err == -1) {
+        err = errno;
+    }
+    err = setitimer(ITIMER_PROF,    &disable, NULL);
+    if (err == -1) {
+        err = errno;
+    }
+    return err;
+}
+
+extern int MoreSecDestroyInheritedEnvironment(int whatToDubya, const char **argv)
+	// See comment in header.
+{
+    int err;
+    
+    assert(    (argv != NULL) 
+            || ((whatToDubya & kMoreSecKeepArg0Mask) != 0) );
+    
+    err = 0;
+    
+    if (    (err == 0) 
+         && !(whatToDubya & kMoreSecKeepArg0Mask) ) {
+        err = ResetArgvZero(argv);
+    }
+    if (    (err == 0) 
+         && !(whatToDubya & kMoreSecKeepEnvironmentMask) ) {
+        err = ResetEnvironment();
+    }
+    if (    (err == 0) 
+         && !(whatToDubya & kMoreSecKeepStandardFilesMask) ) {
+        err = CloseOpenFileDescriptorsInRange(0, 3);
+    }
+    if (    (err == 0) 
+         && !(whatToDubya & kMoreSecKeepOtherFilesMask) ) {
+        err = CloseOpenFileDescriptorsInRange(
+                              3, 
+                              getdtablesize());
+    }
+    if (    (err == 0) 
+         && !(whatToDubya & kMoreSecKeepSignalsMask) ) {
+        err = ResetAllSignalsToDefault();
+    }
+    if (    (err == 0) 
+         && !(whatToDubya & kMoreSecKeepUmaskMask) ) {
+        (void) umask(S_IRWXG | S_IRWXO);
+    }
+    if (    (err == 0) 
+         && !(whatToDubya & kMoreSecKeepNiceMask) ) {
+        err = nice(0);
+        if (err == -1) {
+            err = errno;
+        }
+    }
+    if (    (err == 0) 
+         && !(whatToDubya & kMoreSecKeepResourceLimitsMask) ) {
+        err = ResetAllResourceLimitsToDefault();
+    }
+    if (    (err == 0) 
+         && !(whatToDubya & kMoreSecKeepCurrentDirMask) ) {
+        err = chdir("/");
+        if (err == -1) {
+            err = errno;
+        }
+    }
+    if (    (err == 0) 
+         && !(whatToDubya & kMoreSecKeepTimersMask) ) {
+        err = ResetAllTimers();
+    }
+    
+    return err;
+}
+
+/////////////////////////////////////////////////////////////////
+#pragma mark ***** Helper Tool Common
+
+static OSStatus CopyDictionaryFromDescriptor(int fdIn, CFDictionaryRef *dictResult)
+	// Create a CFDictionary by reading the XML data from fdIn. 
+	// It first reads the size of the XML data, then allocates a 
+	// buffer for that data, then reads the data in, and finally 
+	// unflattens the data into a CFDictionary.
+	//
+	// See also the companion routine, WriteDictionaryToDescriptor, below.
+{
+	OSStatus			err;
+	CFIndex				dictSize;
+	UInt8 *				dictBuffer;
+	CFDataRef			dictData;
+	CFPropertyListRef 	dict;
+
+	assert(fdIn >= 0);
+	assert( dictResult != NULL);
+	assert(*dictResult == NULL);
+	
+	dictBuffer = NULL;
+	dictData   = NULL;
+	dict       = NULL;
+
+	// Read the data size and allocate a buffer.
+	
+	err = EXXXToOSStatus( MoreUNIXRead(fdIn, &dictSize, sizeof(dictSize), NULL) );
+	if (err == noErr) {
+		// Abitrary limit to prevent potentially hostile client overwhelming us with data.
+		if (dictSize > (1 * 1024 * 1024)) {
+			err = memFullErr;
+		}
+	}
+	if (err == noErr) {
+		dictBuffer = (UInt8 *) malloc( (size_t) dictSize);
+		if (dictBuffer == NULL) {
+			err = memFullErr;
+		}
+	}
+	
+	// Read the data and unflatten.
+	
+	if (err == noErr) {
+		err = EXXXToOSStatus( MoreUNIXRead(fdIn, dictBuffer, (size_t) dictSize, NULL) );
+	}
+	if (err == noErr) {
+		dictData = CFDataCreateWithBytesNoCopy(NULL, dictBuffer, dictSize, kCFAllocatorNull);
+		err = CFQError(dictData);
+	}
+	if (err == noErr) {
+		dict = CFPropertyListCreateFromXMLData(NULL, dictData, kCFPropertyListImmutable, NULL);
+		err = CFQError(dict);
+	}
+	if ( (err == noErr) && (CFGetTypeID(dict) != CFDictionaryGetTypeID()) ) {
+		err = paramErr;		// only CFDictionaries need apply
+	}
+	// CFShow(dict);
+	
+	// Clean up.
+	
+	if (err != noErr) {
+		CFQRelease(dict);
+		dict = NULL;
+	}
+	*dictResult = (CFDictionaryRef) dict;
+
+	free(dictBuffer);
+	CFQRelease(dictData);
+	
+	assert( (err == noErr) == (*dictResult != NULL) );
+	
+	return err;
+}
+
+static OSStatus WriteDictionaryToDescriptor(CFDictionaryRef dict, int fdOut)
+	// Write a dictionary to a file descriptor by flattening 
+	// it into XML.  Send the size of the XML before sending 
+	// the data so that CopyDictionaryFromDescriptor knows 
+	// how much to read.
+{
+	OSStatus			err;
+	CFDataRef			dictData;
+	CFIndex				dictSize;
+	UInt8 *				dictBuffer;
+
+	assert(dict != NULL);
+	assert(fdOut >= 0);
+	
+	dictData   = NULL;
+	dictBuffer = NULL;
+	
+	dictData = CFPropertyListCreateXMLData(NULL, dict);
+	err = CFQError(dictData);
+	
+	// Allocate sizeof(size_t) extra bytes in the buffer so that we can 
+	// prepend the dictSize.  This allows us to write the entire 
+	// dict with one MoreUNIXWrite call, which definitely speeds 
+	// things up, especially if this is was going over a real wire.
+	// Of course, if I was to send this over a real wire, I would 
+	// have to guarantee that dictSize was sent in network byte order (-:
+	
+	if (err == noErr) {
+		dictSize = CFDataGetLength(dictData);
+		dictBuffer = (UInt8 *) malloc( sizeof(size_t) + dictSize );
+		if (dictBuffer == NULL) {
+			err = memFullErr;
+		}
+	}
+	
+	if (err == noErr) {
+		// Copy dictSize into the first size_t bytes of the buffer.
+		
+		*((size_t *) dictBuffer) = (size_t) dictSize;
+		
+		// Copy the data into the remaining bytes.
+		//
+		// Can't use CFDataGetBytePtr because there's no guarantee that 
+		// it will succeed.  If it doesn't, we have to copy the bytes anyway,
+		// so the allocation code has to exist.  Given that this isn't a 
+		// performance critical path, I might as well minimise my code size by 
+		// always running the allocation code.
+		
+		CFDataGetBytes(dictData, CFRangeMake(0, dictSize), dictBuffer + sizeof(size_t));
+		
+		err = EXXXToOSStatus( MoreUNIXWrite(fdOut, dictBuffer, sizeof(size_t) + dictSize, NULL) );
+	}
+
+	free(dictBuffer);
+	CFQRelease(dictData);
+		
+	return err;
+}
+
+extern int MoreSecErrorToHelperToolResult(int errNum)
+	// See comment in header.
+{
+	int result;
+	
+	switch (errNum) {
+		case 0:
+			result = 0;
+			break;
+		case errAuthorizationDenied:
+			result = (kMoreSecResultPrivilegesErr - kMoreSecResultBase);
+			break;
+		case errAuthorizationCanceled:
+			result = (kMoreSecResultCanceledErr - kMoreSecResultBase);
+			break;
+		default:
+			if ( (errNum >= kMoreSecFirstResultErr) && (errNum <= kMoreSecLastResultErr) ) {
+				result = (errNum - kMoreSecResultBase);
+			} else {
+				result = (kMoreSecResultInternalErrorErr - kMoreSecResultBase);
+			}
+			break;
+	}
+	return result;
+}
+
+extern int MoreSecHelperToolResultToError(int toolResult)
+	// See comment in header.
+{
+	int err;
+	
+	if (toolResult == 0) {
+		err = 0;
+	} else {
+		if ( (toolResult > 0) && (toolResult <= (kMoreSecLastResultErr - kMoreSecResultBase)) ) {
+			err = (toolResult + kMoreSecResultBase);
+		} else {
+			err = kMoreSecResultInternalErrorErr;
+		}
+	}
+	return err;
+}
+
+/////////////////////////////////////////////////////////////////
+#pragma mark ***** Implementation Helper Tool
+
+// Notes on Code Signing
+// ---------------------
+// I've decided *not* to implementing a digital signature verification 
+// as part of this library.  There are a number of technical reasons 
+// that would make digitally signing the code tricky (such as prebinding), 
+// but I believe that all of those are surmountable.  The reasons I didn't 
+// implementing digital signatures are:
+// 
+// A) it doesn't improve the security if I implement it here, 
+// B) it's extra work for me, and 
+// C) its presence might lead folks to believe that this is more 
+//    secure than it really is.
+//
+// The most critical point is point A.  I'll spend a little time explaining 
+// that here.
+//
+// No matter what you do, the current AuthorizationExecuteWithPrivileges 
+// model allows for security violations [3093666].  Specifically, AEWP lets 
+// you run a non-privileged helper tool as if it was privileged.  However, in 
+// the time between the point where you call AEWP (at the point, SigCheck1, 
+// below) and the point where the helper tool runs and changes its own 
+// permissions to prevent tampering (SigCheck2), there's a window of opportunity 
+// where an attacker can modify the tool at will, and the modified tool will be 
+// run as root.  They could, for example, open a read/write file descriptor 
+// that allows them to modify the tool.  Even if the tool checks its own 
+// integrity with a digital signature (at the point SigCheck2, below), there's 
+// no way it can revoke the read/write file descriptor, so the attacker could 
+// just modify the tool after the digital signature check.
+//
+// Moreover, there are even simpler attacks.  For example, an attacker 
+// could just delete the application's current helper tool and replace 
+// the application's template copy of the tool with its own.  The application 
+// will quite happily launch that tool, at which point the tool can use  
+// AEWP to prompt for the admin password and can launch any program in 
+// privileged mode.  The user is not going to be be able to distinguish 
+// between the attacker's tool call AEWP and the real helper tool.
+//
+// You could defeat this second attack by digitally signing the helper tool, 
+// but that doesn't really help because if the attacker can change the 
+// application program (which is a precondition of being able to substitute 
+// a helper tool), they can replace your digital signature with theirs. 
+// One way around this would be to use a certificate to verify the 
+// authenticity of the digital signature, but that's beyond what I'm 
+// prepared to do for sample code.
+//
+// So, rather than write a lot of code to provide a false sense of security, 
+// I've decided to simply ignore the issue of digital signatures altogether.
+
+// File Modes
+// ----------
+// The following is a declaration of constants that I use when setting and checking
+// the file mode (ie permissions).  It's an extreme use of whitespace, but 
+// I found the layout helpful.
+
+enum {
+	// The mode_t that we set for the helper tool via fchmod.
+	
+	kSetHelperToolPerms = 0				// r-sr-xr-x
+						| S_ISUID
+//						| S_ISGID
+//						| S_ISVTX
+
+						| S_IRUSR
+//						| S_IWUSR
+						| S_IXUSR
+
+						| S_IRGRP
+//						| S_IWGRP
+						| S_IXGRP
+
+						| S_IROTH
+//						| S_IWOTH
+						| S_IXOTH
+						,
+
+	// The mode_t that we check, via stat, to see if the helper tool is valid.
+
+	kRequiredHelperToolPerms = S_IFREG | kSetHelperToolPerms,
+
+	kRequiredHelperToolMask = 0
+							| S_IFMT
+
+							| S_ISUID
+							| S_ISGID
+							| S_ISVTX
+
+							| S_IRWXU
+							| S_IRWXG
+							| S_IRWXO
+};
+
+static int RepairOurPrivileges(const char *pathToSelf)
+    // Self-repair code.  We ran ourselves using AuthorizationExecuteWithPrivileges
+    // so we need to make ourselves setuid root to avoid the need for this the 
+    // next time around.
+{
+	int			err;    
+	int			junk;    
+    int 		fd;
+
+	assert(pathToSelf != NULL);
+	
+	// We don't supply O_EXLOCK to open because that's only an advisory 
+	// lock so it doesn't buy us anything.  [AuthSample makes the claim 
+	// that this lock is mandatory, but that's just wrong [3090303].]
+	
+    fd = open(pathToSelf, O_RDONLY, 0);
+    err = MoreUNIXErrno(fd);
+	
+	if (err == 0) {
+		// SigCheck2
+		//
+		// If I was to implement digital signing of the code, this is the 
+		// second place I would check the signature.  See note above for 
+		// more information on this.
+	}
+
+	if (err == 0) {
+		// Switch to EUID 0 to do the chown/chmod.
+		
+		err = MoreSecSetPrivilegedEUID();    
+
+	    // Make it owned by root.
+	    
+	    if (err == 0) {
+	    	// GID = -1 implies no change
+	        err = fchown(fd, 0, -1);
+	        err = MoreUNIXErrno(err);
+	    }
+
+	    // Force the mode flags.
+
+	    if (err == 0) {
+		    err = fchmod(fd, kRequiredHelperToolPerms);
+		    err = MoreUNIXErrno(err);
+	    }
+
+		// Switch back to EUID != 0 once we're done.
+		
+		junk = MoreSecTemporarilySetNonPrivilegedEUID();
+		assert(junk == 0);
+	}
+    
+	// Clean up.
+	
+	if (fd != -1) {
+		junk = close(fd);
+		assert(junk == 0);
+	}
+
+    return err;
+}
+
+static int ExecuteSelfInPrivilegedSelfRepairMode(int fdIn, int fdOut, AuthorizationRef auth, const char *pathToSelf)
+	// Execute another copy of the tool in privileged mode via 
+	// AuthorizationExecuteWithPrivileges.  Route the command request 
+	// from fdIn to the second instance of the tool, and route the
+	// command response from the second instance of the tool to fdOut.
+{
+	int		err;
+	int		err2;
+	int		status;
+	int		junk;
+    FILE *	fileConnToChild;
+    int		fdConnToChild;
+    pid_t	childPID;
+    static const char * const kSelfRepairArguments[] = { "--self-repair", NULL };
+
+	assert(fdIn    >= 0);
+	assert(fdOut   >= 0);
+	assert(auth       != NULL);
+	assert(pathToSelf != NULL);
+
+	fileConnToChild = NULL;
+	childPID = -1;
+	
+	err = 0;
+	
+	// SigCheck1
+	//
+	// If I was to implement digital signing of the code, this is the 
+	// first place I would check the signature.  See note above for 
+	// more information on this.
+	
+	if (err == 0) {
+		#if MORE_DEBUG
+			fprintf(stderr, "MoreSecurity: Calling AEWP\n");
+		#endif
+	    err = OSStatusToEXXX( AuthorizationExecuteWithPrivileges(auth, pathToSelf, 
+										kAuthorizationFlagDefaults, (char * const *) kSelfRepairArguments, &fileConnToChild) );
+		#if MORE_DEBUG
+			fprintf(stderr, "MoreSecurity: AEWP returned %d\n", err);
+		#endif
+
+		// The cast for kSelfRepairArguments is required because of a bug in the prototype
+		// for AuthorizationExecuteWithPrivileges [3090294].
+	}
+	
+	if (err == 0) {
+		// Extract the descriptor for the returned FILE *.  As we 
+		// never use the FILE * again and there is no data buffered
+		// in it, it's safe for us to use the descriptor as if it had 
+		// never been embedded in a FILE *.
+		
+		fdConnToChild = fileno(fileConnToChild);
+		err = MoreUNIXErrno(fdConnToChild);
+
+		// Get the PID sent to us by the child.  We need to do this because 
+		// AuthorizationExecuteWithPrivileges does not return us the child's 
+		// PID [3090277], and we need the child PID in order to properly wait 
+		// for the child to terminate.
+		
+		if (err == 0) {
+			err = MoreUNIXRead(fdConnToChild, &childPID, sizeof(childPID), NULL);
+		}
+			
+		// At this point we're just acting as a router between the application 
+		// and the second instance of the tool we launched using AEWP.  All we 
+		// do is copy the request data to the tool, and then copy the result 
+		// back to the app.  This works because we implement a simple 
+		// request/response protocol.  If the protocol was more complex 
+		// (for example, if the tool handled multiple requests per 
+		// session), we would have to implement a more complex copying 
+		// algorithm using "select".
+		
+		if (err == 0) {
+			err = MoreUNIXCopyDescriptorToDescriptor(fdIn, fdConnToChild);
+		}
+
+		// Close the write side of our connection to the child.  We do this so that 
+		// if the child makes a mistake and tries to do a blocking read on its 
+		// input for more data that we're sending it, it will see the closed socket 
+		// and get EPIPE instead of blocking forever.
+
+		if (err == 0) {
+			err = shutdown(fdConnToChild, 1);
+			err = MoreUNIXErrno(err);
+		}
+
+		// Copy the response back to the app.
+		
+		if (err == 0) {
+			err = MoreUNIXCopyDescriptorToDescriptor(fdConnToChild, fdOut);
+		}
+
+		// Close the connection to the child, which also closes fdConnToChild.
+		
+	    if (fileConnToChild != NULL) {
+			junk = fclose(fileConnToChild);
+			assert(junk == 0);
+		}
+
+		// Wait for the child to terminate.  We have to do this, regardless 
+		// of whether we get an error, in order to clear the zombie process.
+		// 
+		// Note that we don't get the pid of the child back from 
+		// AuthorizationExecuteWithPrivileges, so we have to have the child 
+		// send us its PID via fdConnToChild (see the MoreUNIXRead above).
+		// Also note that there's no guarantee that the MoreUNIXRead will 
+		// execute without error, thus there's no guarantee that childPID 
+		// will be valid.  We handle that by initialising childPID to -1 
+		// in the error case, which makes "waitpid" work just like "wait", 
+		// that is, wait for any child to terminate.  Of course, there's 
+		// no guarantee that in that case the terminating child will actually 
+		// be the child we launched with AEWP.  That's sad, but its
+		// the best we can do given the current problems with AEWP [3090277].
+		
+	    err2 = waitpid(childPID, &status, 0);
+	    err2 = MoreUNIXErrno(err);
+	    if (err == 0) {
+	    	err = err2;
+	    }
+
+		// If we successfully got a wait status from the client (or 
+		// our communications with the client failed because of 
+		// a generic communications error), let's go see whether 
+		// the child's wait status is a more appropriate source of 
+		// error information.
+		
+		if ( (err == 0) || (err == EPIPE) ) {
+			if ( ! WIFEXITED(status) ) {
+				// If we got a wait status but it's not a valid exit status (perhaps 
+				// WIFSIGNALED, indication that the child terminated because of a signal),
+				// that's an unexpected error we can't handle.
+				
+				err = kMoreSecResultInternalErrorErr;
+			} else {
+				// If we got a valid exit status from the child, map its exit status 
+				// into our range so that we return an equivalent status.  The helper 
+				// tool's main function can use MoreSecErrorToHelperToolResult to map 
+				// this back to a status code.
+				
+				err = MoreSecHelperToolResultToError(WEXITSTATUS(status));
+			}
+		}
+	}
+
+	return err;
+}
+
+static int ReadAndDispatchCommand(int fdIn, int fdOut, AuthorizationRef auth, MoreSecCommandProc commandProc)
+	// Read a command from fdIn, execute the command by calling commandProc,
+	// and then return the response via fdOut.
+{
+	int 				err;
+	int 				junk;
+	CFDictionaryRef 	request;
+	CFDictionaryRef		response;
+	
+	assert(fdIn    >= 0);
+	assert(fdOut   >= 0);
+	assert(auth    != NULL);
+	assert(commandProc != NULL);
+	
+	request		= NULL;
+	response	= NULL;
+	
+	// Read the request and convert it a CFDictionary.
+
+	err = OSStatusToEXXX( CopyDictionaryFromDescriptor(fdIn, &request) );
+
+	// Call the client's commandProc to actually execute the request.  
+	// Note that we automatically put the commandProc's function result 
+	// into a response dictionary if the commandProc hasn't already done so. 
+	// An error from the commandProc does not indicate a failure of the 
+	// helper tool itself.
+	
+	if (err == 0) {
+		OSStatus    commandErr;
+		CFStringRef errorKey = kMoreSecErrorNumberKey;
+		
+		commandErr = commandProc(auth, (CFDictionaryRef) request, (CFDictionaryRef *) &response);
+		// fprintf(stderr, "commandErr = %ld\n", commandErr);
+		
+		// If the commandProc switched to EUID 0, let's go back to EUID == RUID.
+		
+		junk = MoreSecTemporarilySetNonPrivilegedEUID();
+		assert(junk == 0);
+		
+		assert( (response == NULL) || (CFGetTypeID(response) == CFDictionaryGetTypeID()) );
+		
+		if ( (response == NULL) || ! CFDictionaryContainsKey(response, errorKey) ) {
+			CFNumberRef commandErrNum;
+
+			commandErrNum = CFNumberCreate(NULL, kCFNumberSInt32Type, &commandErr);
+			err = OSStatusToEXXX( CFQError(commandErrNum) );
+			
+			if (err == 0) {
+				if (response == NULL) {
+					response = CFDictionaryCreate(NULL, (const void **) &errorKey, (const void **) &commandErrNum, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+					err = OSStatusToEXXX( CFQError(response) );
+				} else {
+					CFMutableDictionaryRef temp;
+					
+					temp = CFDictionaryCreateMutableCopy(NULL, 0, response);
+					err = OSStatusToEXXX( CFQError(temp) );
+					if (err == 0) {
+						CFDictionarySetValue(temp, errorKey, commandErrNum);
+						
+						CFQRelease(response);
+						response = temp;
+					}
+				}
+			}
+
+			CFQRelease(commandErrNum);
+		}
+		
+	}
+	
+	assert( (err == 0) == (response != NULL) );
+	
+	// Pass the response back.
+	
+	if (err == 0) {
+		err = OSStatusToEXXX( WriteDictionaryToDescriptor(response, fdOut) );
+	}
+
+	CFQRelease(request);
+	CFQRelease(response);
+	
+	return err;
+}
+
+extern AuthorizationRef MoreSecHelperToolCopyAuthRef(void)
+	// See comment in header.
+{
+	AuthorizationRef result;
+	
+	result = NULL;
+
+	(void) AuthorizationCopyPrivilegedReference(&result, kAuthorizationFlagDefaults);
+
+	return result;
+}
+
+extern int MoreSecHelperToolMain(int fdIn, int fdOut, AuthorizationRef auth, MoreSecCommandProc commandProc, int argc, const char *argv[])
+	// See comment in header.
+{
+	int					err;
+	OSStatus			junk;
+    char *				pathToSelf;
+    Boolean				privileged;
+
+	assert(fdIn    >= 0);
+	assert(fdOut   >= 0);
+	assert(commandProc != NULL);
+	assert( (argc == 1) || (argc == 2) );
+	assert(argv    != NULL);
+	assert(argv[0] != NULL);
+
+	err        = 0;
+	pathToSelf = NULL;
+
+	// Note whether we're privileged, and then switch the EUID to the RUID 
+	// so that the rest of the tool runs with a non-zero EUID unless it 
+	// specifically requests privileges via MoreSecSetPrivilegedEUID.  
+	// This makes things just a little bit safer.
+	
+	privileged = (geteuid() == 0);
+	err = MoreSecTemporarilySetNonPrivilegedEUID();
+	
+	// We need pathToSelf in both of the following cases, so let's get it here.
+	
+	if (err == 0) {
+		err = GetPathToSelf(&pathToSelf);
+	}
+	
+	// There are three cases:
+	//
+	// 1a. No command line arguments, privileged -- We can just call 
+	//     ReadAndDispatchCommand to execute the request.
+	//
+	// 1b. No command line arguments, not privileged -- We need to self 
+	//     repair by calling ExecuteSelfInPrivilegedSelfRepairMode.
+	//     This will launch another copy of the tool, and that copy 
+	//     of the tool will actually execute the request using
+	//     ReadAndDispatchCommand.
+	//
+	// 2.  --self-repair command line argument -- We got here by 
+	//     step 1b above.  We must be privileged.  If not, bail out. 
+	//     We make ourselve setuid root (RepairOurPrivileges) and then 
+	//     execute the command via ReadAndDispatchCommand.
+	
+	if (err == 0) {
+	    if (argc == 1) {
+		    AuthorizationExternalForm extAuth;
+
+			// The caller gave us a AuthorizationRef, but we're don't use 
+			// it in this case.  Just throw it away.
+			
+			if (auth != NULL) {
+				junk = AuthorizationFree(auth, kAuthorizationFlagDefaults);
+				assert(junk == noErr);
+				
+				auth = NULL;
+			}
+			
+			// Started directly by the application.  Read the authorization 
+			// "byte blob" from our input, and use that to create our 
+			// AuthorizationRef.  
+			
+			err = MoreUNIXRead(fdIn, &extAuth, sizeof(extAuth), NULL);
+		    if (err == 0) {
+			    err = OSStatusToEXXX( AuthorizationCreateFromExternalForm(&extAuth, &auth) );
+		    }
+
+			// If we're running as root, we can just read the command 
+			// and execute it.  Otherwise, we have to self-repair.  
+			// Note that this will launch a second instance of this 
+			// tool, which is the one that actually reads and executes  
+			// the command.
+			
+		    if (err == 0) {
+			    if (privileged) {
+					err = ReadAndDispatchCommand(fdIn, fdOut, auth, commandProc);
+			    } else {
+			    	err = ExecuteSelfInPrivilegedSelfRepairMode(fdIn, fdOut, auth, pathToSelf);
+			    }
+			}
+	    } else if ( (argc == 2) && (strcmp(argv[1], "--self-repair") == 0) ) {
+	    	pid_t myPID;
+	    
+	    	// We get here if we've been launched in self-repair mode by 
+	    	// ourselves (see ExecuteSelfInPrivilegedSelfRepairMode).  First we 
+	    	// send our parent our PID.  This is needed for reasons that are 
+	    	// explained above (in ExecuteSelfInPrivilegedSelfRepairMode).  Then we 
+	    	// verify that we're actually been run with EUID 0.  Then we grab our 
+	    	// AuthorizationRef from our parent.  Next we self-repair, that is, 
+	    	// make our executable setuid root so that the next time around we won't 
+	    	// need to run this code path.  Finally, we actually read and 
+	    	// dispatch the command.
+	    	//
+	    	// Note that we don't read the authorization "byte 
+	    	// blob" because it's already been read by our parent.
+			
+			myPID = getpid();
+			err = MoreUNIXWrite(fdOut, &myPID, sizeof(myPID), NULL);
+			
+	    	if (err == 0 && ! privileged ) {
+	    		err = kMoreSecResultParamErr;
+	    	}
+	    	if ( (err == 0) && (auth == NULL) ) {
+	    		err = kMoreSecResultParamErr;
+	    	}
+		    if (err == 0) {
+		    	err = RepairOurPrivileges(pathToSelf);
+			}
+	    	if (err == 0) {
+				err = ReadAndDispatchCommand(fdIn, fdOut, auth, commandProc);
+			}
+	    } else {
+	    	err = kMoreSecResultParamErr;
+	    }
+	}
+	
+	// Clean up and pass results back to caller.
+	
+    free(pathToSelf);
+	if (auth != NULL) {
+		junk = AuthorizationFree(auth, kAuthorizationFlagDefaults);
+		assert(junk == noErr);
+	}
+	return err;
+}
+
+/////////////////////////////////////////////////////////////////
+#pragma mark ***** Calling Helper Tool
+
+extern OSStatus MoreSecIsFolderIgnoringPrivileges(const FSRef *folder, Boolean *ignoringPrivs)
+	// See comment in header.
+{
+	OSStatus		err;
+	OSStatus		junk;
+	int				tries;
+	FSRef			fileRef;
+	FSCatalogInfo 	info;
+	static int   kPermissionsGroupIDIndex   = 1;
+	static gid_t kPermissionsUnknownGroupID = 99;
+	static gid_t kPermissionsStaffGroupID   = 20;
+	
+	assert(folder != NULL);
+	assert(ignoringPrivs != NULL);
+	
+	// Create a temporary file.
+	
+	tries = 1;
+	do {
+		AbsoluteTime	now;
+		CFStringRef 	tmpStr;
+		HFSUniStr255 	tmpStrU;
+		
+		now = UpTime();
+		tmpStr = CFStringCreateWithFormat(NULL, NULL, CFSTR("MoreSecIsFolderIgnoringPrivileges Temp %lx%lx"), now.hi, now.lo);
+		err = CFQError(tmpStr);
+		
+		if (err == noErr) {
+			assert(CFStringGetLength(tmpStr) <= (sizeof(tmpStrU.unicode) / sizeof(UniChar)) );
+			tmpStrU.length = (UInt16) CFStringGetLength(tmpStr);
+			CFStringGetCharacters(tmpStr, CFRangeMake(0, tmpStrU.length), tmpStrU.unicode);
+		
+			err = FSCreateFileUnicode(folder, tmpStrU.length, tmpStrU.unicode, kFSCatInfoNone, NULL, &fileRef, NULL);
+		}
+		
+		CFQRelease(tmpStr);
+
+		tries += 1;
+	} while ( (tries < 1000) && (err == dupFNErr) );
+
+	// Probe that temporary file to see if permissions are being ignored.
+		
+	if (err == noErr) {
+		err = FSGetCatalogInfo(&fileRef, kFSCatInfoPermissions, &info, NULL, NULL, NULL);
+		if (err == noErr) {
+
+			// If the FGID is not "unknown", then we already know that the volume 
+			// is not ignoring privileges.  Otherwise we have to test.
+
+			if (info.permissions[kPermissionsGroupIDIndex] != kPermissionsUnknownGroupID) {
+				*ignoringPrivs = false;
+			} else {
+			
+				// Change the FGID to "staff".  If that change is effective, we're 
+				// not ignoring privileges.
+				
+				info.permissions[kPermissionsGroupIDIndex] = kPermissionsStaffGroupID;
+				err = FSSetCatalogInfo(&fileRef, kFSCatInfoPermissions, &info);
+				if (err == noErr) {
+					err = FSGetCatalogInfo(&fileRef, kFSCatInfoPermissions, &info, NULL, NULL, NULL);
+				}
+				if (err == noErr) {
+					*ignoringPrivs = (info.permissions[kPermissionsGroupIDIndex] != kPermissionsStaffGroupID);
+				}
+			}
+			assert( (err != noErr) || (*ignoringPrivs == (info.permissions[kPermissionsGroupIDIndex] == kPermissionsUnknownGroupID)) );
+		}
+		junk = FSDeleteObject(&fileRef);
+		assert(junk == noErr);
+	}
+	
+	return err;
+}
+
+static OSStatus MoreSecCheckHelperTool(CFURLRef templateTool, CFURLRef tool, Boolean *looksOK)
+	// Checks that the working tool is a reasonably accurate copy of the 
+	// templateTool.  This checks that the tool exists, is setuid root, 
+	// and has the same size and modification date as the template tool. 
+{
+	OSStatus      	err;
+	char			toolPath[MAXPATHLEN];			// 2K on the stack!
+	char			templateToolPath[MAXPATHLEN];	// I'm going to burn in hell.
+	struct stat 	toolStat;
+	struct stat 	templateToolStat;
+	struct timeval	toolStamp;
+	struct timeval  templateToolStamp;
+	
+	assert(templateTool != NULL);
+	assert(tool         != NULL);
+	assert(looksOK      != NULL);
+	
+	// Check that the template tool is present.  If the template tool is missing, 
+	// we're doooommmmeeeedddd!
+
+	err = CFQErrorBoolean( CFURLGetFileSystemRepresentation(templateTool, true, (UInt8 *)templateToolPath, sizeof(templateToolPath)) );
+	if (err == noErr) {
+		err = stat(templateToolPath, &templateToolStat);
+		err = MoreUNIXErrno(err);
+	}
+
+	// If we successfully found the template tool, go looking for the primary tool. 
+		
+	err = CFQErrorBoolean( CFURLGetFileSystemRepresentation(tool, true, (UInt8 *)toolPath, sizeof(toolPath)) );
+	if (err == 0) {
+		err = stat(toolPath, &toolStat);
+		err = EXXXToOSStatus( MoreUNIXErrno(err) );
+
+		// If the primary tool is either missing, has dropped its 
+		// owner or setuid or permissions, or is the wrong size, 
+		// or the wrong time stamp (the last two checks help debugging), 
+		// then try to restore the tool.
+		
+		TIMESPEC_TO_TIMEVAL(&templateToolStamp, &templateToolStat.st_mtimespec);
+		TIMESPEC_TO_TIMEVAL(&toolStamp, &toolStat.st_mtimespec);
+
+		*looksOK = (err == noErr) 
+				&& (toolStat.st_uid == 0) 
+				&& ((toolStat.st_mode & kRequiredHelperToolMask) == kRequiredHelperToolPerms) 
+				&& (toolStat.st_size  == templateToolStat.st_size)
+				&& (toolStamp.tv_sec  == templateToolStamp.tv_sec) 
+				&& (toolStamp.tv_usec == toolStamp.tv_usec);
+		err = noErr;
+	}
+	
+	return err;
+}
+
+static OSStatus MoreSecCheckAndFixHelperTool(CFURLRef templateTool, CFURLRef tool)
+	// Checks that the working tool is a reasonably accurate copy of the 
+	// templateTool, using MoreSecCheckHelperTool, and if these checks fail, 
+	// restores tool from the template tool.
+	//
+	// the tool referenced by templateTool must exist
+	//
+	// tool must not be NULL; if tool does not exist, the directory in 
+	// which tool would be contained must exist
+{
+	int      		err;
+	char			toolPath[MAXPATHLEN];			// 2K on the stack!
+	char			templateToolPath[MAXPATHLEN];	// I'm going to burn in hell.
+	struct stat 	toolStat;
+	Boolean			looksOK;
+	
+	assert(templateTool != NULL);
+	assert(tool         != NULL);
+	
+	err = MoreSecCheckHelperTool(templateTool, tool, &looksOK);
+	if (err == noErr && !looksOK) {
+		err = CFQErrorBoolean( CFURLGetFileSystemRepresentation(templateTool, true, (UInt8 *)templateToolPath, sizeof(templateToolPath)) );
+		if (err == noErr) {
+			err = CFQErrorBoolean( CFURLGetFileSystemRepresentation(tool, true, (UInt8 *)toolPath, sizeof(toolPath)) );
+		}
+		if (err == noErr) {
+			if ( stat(toolPath, &toolStat) == 0 ) {
+				err = unlink(toolPath);
+				err = MoreUNIXErrno(err);
+				if (err == EPERM) {			// just in case the file name is being used by a directory
+					err = rmdir(toolPath);
+					err = MoreUNIXErrno(err);
+				}
+			}
+		}
+		
+		if (err == noErr) {
+			err = MoreUNIXCopyFile(templateToolPath, toolPath);
+		}
+	}
+		
+	return err;
+}
+
+static OSStatus MoreSecCopyHelperToolURL(short domain, OSType folder, CFStringRef subFolderName, CFStringRef toolName, Boolean createFolder, CFURLRef *tool)
+	// Create a URL that points to a helper tool named toolName within the 
+	// Folder Manager folder specified by domain and folder.  If subFolderName is 
+	// not NULL, the URL points to the tool within that folder, otherwise it 
+	// points to the tool directly within the Folder Manager folder.
+	// The URL might point to a file that does not exist, but if the call 
+	// is successful then the parent folder will exist.
+	// 
+	// If createFolder is false, this routine will not create any folders; 
+	// if it needs to create a folder, it will error instead.
+{
+	OSStatus		err;
+	FSRef 			folderRef;
+	CFURLRef		folderURL;
+
+	assert(toolName != NULL);
+	assert( tool    != NULL);
+	assert(*tool    == NULL);
+		
+	folderURL = NULL;
+	
+	err = FSFindFolder(domain, folder, createFolder, &folderRef);
+	if (err == noErr && subFolderName != NULL) {
+		FSRef 			tmp;
+		HFSUniStr255 	subFolderNameU;
+		
+		tmp = folderRef;
+
+		// Extract the Unicode characters from subFolderName.
+		
+		assert(CFStringGetLength(subFolderName) <= (sizeof(subFolderNameU.unicode) / sizeof(UniChar)) );
+		subFolderNameU.length = (UInt16) CFStringGetLength(subFolderName);
+		CFStringGetCharacters(subFolderName, CFRangeMake(0, subFolderNameU.length), subFolderNameU.unicode);
+
+		// If the sub-folder doesn't exist, try to create it.  We can't just create it 
+		// and ignore the dupFNErr if it already exists because we need to set up 
+		// folderRef.
+		
+		err = FSMakeFSRefUnicode(&tmp, subFolderNameU.length, subFolderNameU.unicode, kTextEncodingUnknown, &folderRef);
+		if (err != noErr && createFolder) {
+			err = FSCreateDirectoryUnicode(&tmp, subFolderNameU.length, subFolderNameU.unicode, kFSCatInfoNone, NULL, 
+										   &folderRef, NULL, NULL);
+		}
+	}
+	
+	// Create a URL to the parent folder, then append the tool name.
+	
+	if (err == noErr) {
+		folderURL = CFURLCreateFromFSRef(NULL, &folderRef);
+		err = CFQError(folderURL);
+	}
+	if (err == noErr) {
+		*tool = CFURLCreateCopyAppendingPathComponent(NULL, folderURL, toolName, false);
+		err = CFQError(*tool);
+	}
+	
+	CFQRelease(folderURL);
+
+	assert( (err == noErr) == (*tool != NULL) );
+		
+	return err;
+}
+
+extern OSStatus MoreSecCopyHelperToolURLAndCheck(CFURLRef templateTool, 
+										 OSType folder, CFStringRef subFolderName, CFStringRef toolName, 
+										 CFURLRef *tool, Boolean *toolFound)
+	// See comment in header.
+{
+	OSStatus			err;
+	CFURLRef			result;
+	UInt32   			domainIndex;
+	Boolean				found;
+	static const SInt16 kFolderDomains[] = {kUserDomain, kLocalDomain, kNetworkDomain, kSystemDomain, 0};
+
+	assert(templateTool != NULL);
+	assert(toolName != NULL);
+	assert( tool != NULL);
+	assert(*tool == NULL);
+	
+	result = NULL;
+	
+	// For each folder domain, check whether there's an appropriate helper tool 
+	// present.  This allows a sysadmin to put the helper tool in any of the 
+	// "Application Support" folders (ie ~/Library, /Library, /Network/Library, 
+	// /System/Library) and we'll find it and run without trying to create 
+	// another copy of the tool.
+
+	found = false;
+	domainIndex = 0;
+	do {
+		assert(result == NULL);
+		
+		// Note that we pass false to the createFolder parameter of the 
+		// MoreSecCopyHelperToolURL so that it doesn't create any folders 
+		// that are missing.  That's because at this stage we're just looking 
+		// for the file, not trying to create it.
+		
+		err = MoreSecCopyHelperToolURL(kFolderDomains[domainIndex], folder, subFolderName, toolName, false, &result);
+		if (err == noErr) {
+			err = MoreSecCheckHelperTool(templateTool, result, &found);
+		}
+		err = noErr;		// we don't care about the specific error, just whether we found the tool or not
+		
+		if (!found) {
+			CFQRelease(result);
+			result = NULL;
+		}
+		
+		domainIndex += 1;
+	} while (!found && kFolderDomains[domainIndex] != 0);
+
+	// At this point either we found the tool, and result is set to its 
+	// URL, or we haven't found the tool and result is NULL.
+	
+	assert( err == noErr );
+	assert( found == (result != NULL) );
+	
+	if (found) {
+		// Do nothing; result will be copied out to *tool during clean up (below).
+	} else {
+		FSRef 		folderRef;
+		Boolean 	ignoringPrivs;
+		
+		// Let's try to create the tool in the user's "Application Support" folder 
+		// (ie ~/Library/Application Support).  However, before we do that, make sure 
+		// that the user isn't ignoring privileges on the volume containing that folder.  
+		// If so, we have no idea where to put the tool, so we fail with a very specific 
+		// error code.
+
+		err = FSFindFolder(kUserDomain, folder, true, &folderRef);
+		if (err == noErr) {
+			err = MoreSecIsFolderIgnoringPrivileges(&folderRef, &ignoringPrivs);
+		}
+		if (err == noErr && ignoringPrivs) {
+			err = kMoreSecIgnoringPrivsInFolderErr;
+		}
+
+		// Now we pass true to the createFolder parameter of MoreSecCopyHelperToolURL 
+		// because we want to create the tool (and any enclosing folders).
+		
+		if (err == noErr) {
+			err = MoreSecCopyHelperToolURL(kUserDomain, folder, subFolderName, toolName, true, &result);
+		}
+		if (err == noErr) {
+			err = MoreSecCheckAndFixHelperTool(templateTool, result);
+		}
+	}
+
+	// Clean up.
+
+	if (err == noErr) {
+		*tool = result;
+	} else {
+		CFQRelease(result);
+	}
+	assert( (err == 0) == (*tool != NULL) );
+
+    if (toolFound != NULL) *toolFound = found;
+
+    return err;
+}
+
+extern OSStatus MoreSecCopyHelperToolURLAndCheckBundled(CFBundleRef inBundle, CFStringRef templateToolName, 
+											  	OSType folder, CFStringRef subFolderName, CFStringRef toolName, 
+											  	CFURLRef *tool, Boolean *toolFound)
+	// See comment in header.
+{
+	OSStatus		err;
+	CFURLRef 		templateTool;
+
+	assert(inBundle != NULL);
+	assert(templateToolName != NULL);
+	assert(toolName != NULL);
+	assert( tool != NULL);
+	assert(*tool == NULL);
+	
+	// Lots of folks use CFBundleCopyResourceURL, but CFBundleCopyAuxiliaryExecutableURL 
+	// is preferred if the resource is an executable because it allows for bundles 
+	// to contain multiple different types of executable (Mach-O and CFM, for example).
+	
+	templateTool = CFBundleCopyAuxiliaryExecutableURL(inBundle, templateToolName);
+	err = CFQError(templateTool);
+	if (err == noErr) {
+		err = MoreSecCopyHelperToolURLAndCheck(templateTool, folder, subFolderName, toolName, tool, toolFound);
+	}
+
+	// Clean up.
+	
+	CFQRelease(templateTool);
+
+	assert( (err == 0) == (*tool != NULL) );
+	
+	return err;
+}
+
+extern OSStatus MoreSecExecuteRequestInHelperTool(CFURLRef helperTool, AuthorizationRef auth, CFDictionaryRef request, CFDictionaryRef *response)
+	// See comment in header.
+{
+	OSStatus 					err;
+	OSStatus 					err2;
+	int 						junk;
+	char						toolPath[MAXPATHLEN];
+    AuthorizationExternalForm 	extAuth;				// spot the Mac OS type!
+    int							fdChild;
+    int							fdParent;
+    int							childPID;
+    int							status;
+
+	assert(helperTool != NULL);
+    assert(auth       != NULL);
+	assert(request    != NULL);
+	assert( response  != NULL);
+	assert(*response  == NULL);
+	
+	childPID = -1;
+	fdChild  = -1;
+	fdParent = -1;
+	
+	// Preparatory work.  Stuff we want to do before forking, like getting the 
+	// tool's path and creating auth's external form.  If either of these fail, 
+	// we want to bail out before the fork.
+	
+	err = CFQErrorBoolean( CFURLGetFileSystemRepresentation(helperTool, true, (UInt8 *)toolPath, sizeof(toolPath)) );
+    if (err == noErr) {
+		err = AuthorizationMakeExternalForm(auth, &extAuth);
+	}
+	
+	// Create a pair of anonymous UNIX domain sockets for communication between 
+	// the us and the tool.  Name them fdChild and fdParent, just to make things 
+	// clear.  It does't make any difference which is which because UNIX domain 
+	// sockets are bidirectional.
+	
+	if (err == noErr) {
+		int comm[2];
+		
+		err = socketpair(AF_UNIX, SOCK_STREAM, 0, comm);
+		err = EXXXToOSStatus( MoreUNIXErrno(err) );
+		
+		if (err == noErr) {
+			fdChild  = comm[0];
+			fdParent = comm[1];
+		}
+	}
+	
+	// Fork.  In the child, replace stdin and stdout with fdChild 
+	// (bidirectional, remember).  Then close the child's extra 
+	// copy of fdChild and fdParent.  Finally, exec the helper tool.
+	// Execution continues in the child's "main" function, which 
+	// calls MoreSecHelperToolMain (defined above).
+	
+	if (err == noErr) {
+		childPID = fork();
+
+		if (childPID == 0) {						// Child
+			err = dup2(fdChild, STDIN_FILENO);
+			err = EXXXToOSStatus( MoreUNIXErrno(err) );
+			
+			if (err == noErr) {
+				err = dup2(fdChild, STDOUT_FILENO);
+				err = EXXXToOSStatus( MoreUNIXErrno(err) );
+			}
+
+			if (err == noErr) {
+				junk = close(fdChild);
+				assert(junk == 0);
+				junk = close(fdParent);
+				assert(junk == 0);
+
+			    err = execl(toolPath, toolPath, NULL);
+			    err = EXXXToOSStatus( MoreUNIXErrno(err) );
+			}
+		    assert(err != noErr);	// otherwise we wouldn't be here
+		    
+		    // Use "_exit" rather than "exit" because we're still in the 
+		    // same address space as the parent, so exit's closing 
+		    // of stdio streams will not be helpful.
+
+		    _exit(MoreSecErrorToHelperToolResult(OSStatusToEXXX(err)));
+			
+			assert(false);			// unreached
+		} else if (childPID == -1) {				// Error, Parent
+			err = EXXXToOSStatus( MoreUNIXErrno(childPID) );
+		} else {
+			assert(childPID > 0);					// Parent
+		}
+	}
+	
+	// In the parent, things are a little more complex.  First we 
+	// close our redundant copy of fdChild.  Then we sent the 
+	// authorization external form to the child via the socket. 
+	// Finally, we send the request to the child, also via the 
+	// socket.
+	
+	if (fdChild != -1) {
+		junk = close(fdChild);
+		assert(junk == 0);
+		fdChild = -1;
+	}
+    if (err == noErr) {
+		err = EXXXToOSStatus( MoreUNIXWrite(fdParent, &extAuth, sizeof(extAuth), NULL) );
+	}
+	if (err == noErr) {
+		err = WriteDictionaryToDescriptor(request, fdParent);
+	}
+
+	// Close the write side of our connection to the child. 
+	// We need to this because it self repair mode 
+	// (ExecuteSelfInPrivilegedSelfRepairMode) the child simply 
+	// copies its input to its output, and doesn't leave its copy 
+	// loop until EOF on input.  This shutdown triggers that EOF.
+
+	if (err == noErr) {
+		err = shutdown(fdParent, 1);
+		err = EXXXToOSStatus( MoreUNIXErrno(err) );
+	}
+	
+	// Read the response back from the child.
+
+	if (err == noErr) {
+		err = CopyDictionaryFromDescriptor(fdParent, response);
+	}
+	
+	// We're all done with our socket, so close it.  It's important 
+	// that we do this here, before the waitpid, so that, if the child 
+	// is broken and is block waiting on input, it'll get an EPIPE 
+	// and quit.
+	
+	if (fdParent != -1) {
+		junk = close(fdParent);
+		junk = MoreUNIXErrno(junk);
+		assert(junk == 0);
+		fdParent = -1;
+	}
+
+	// If we started a child, we have to reap it, always, regardless of 
+	// whether we have encountered an error so far.
+	
+	if (childPID != -1) {
+	    err2 = waitpid(childPID, &status, 0);
+	    err2 = EXXXToOSStatus( MoreUNIXErrno(err2) );
+	    
+	    if (err == noErr) {
+	    	err = err2;
+	    }
+
+		// If we successfully got a wait status from the client (or 
+		// our communications with the client failed because of 
+		// a generic communications error), let's go see whether 
+		// the child's wait status is a more appropriate source of 
+		// error information.
+		
+		if ( (err == noErr) || (err == EPIPE) ) {
+			if ( ! WIFEXITED(status) ) {
+				// If we got a wait status but it's not a valid exit status (perhaps 
+				// WIFSIGNALED, indication that the child terminated because of a signal),
+				// that's an unexpected error we can't handle.
+				
+				err = kMoreSecResultInternalErrorErr;
+			} else {
+				// If we got a valid exit status from the child, map its exit status 
+				// into our range so that we return an equivalent status.
+				
+				err = EXXXToOSStatus( MoreSecHelperToolResultToError(WEXITSTATUS(status)) );
+			}
+		}
+	}
+	
+	if (err != noErr) {
+		CFQRelease(*response);
+		*response = NULL;
+	}
+	
+	assert( (err == noErr) == (*response != NULL) );
+	
+	return err;
+}
+
+extern OSStatus MoreSecGetErrorFromResponse(CFDictionaryRef response)
+	// See comment in header.
+{
+	OSStatus	err;
+	CFNumberRef num;
+	OSStatus	tmp;
+	
+	assert(response != NULL);
+	
+	num = (CFNumberRef) CFDictionaryGetValue(response, kMoreSecErrorNumberKey);
+	err = CFQError(num);
+	
+	if (err == noErr) {
+		err = CFQErrorBoolean( CFNumberGetValue(num, kCFNumberSInt32Type, &tmp) );
+	}
+	if (err == noErr) {	
+		err = OSStatusToEXXX(tmp);
+	}
+	
+	return err;
+}
Index: /trunk/Cocoa/Pester/Source/MoreSecurity/MoreSecurity.h
===================================================================
--- /trunk/Cocoa/Pester/Source/MoreSecurity/MoreSecurity.h	(revision 118)
+++ /trunk/Cocoa/Pester/Source/MoreSecurity/MoreSecurity.h	(revision 118)
@@ -0,0 +1,549 @@
+/*
+	File:		MoreSecurity.h
+
+	Contains:	Security utilities.
+
+	Written by:	Quinn
+
+	Copyright:	Copyright (c) 2002 by Apple Computer, Inc., All Rights Reserved.
+
+	Disclaimer:	IMPORTANT:  This Apple software is supplied to you by Apple Computer, Inc.
+				("Apple") in consideration of your agreement to the following terms, and your
+				use, installation, modification or redistribution of this Apple software
+				constitutes acceptance of these terms.  If you do not agree with these terms,
+				please do not use, install, modify or redistribute this Apple software.
+
+				In consideration of your agreement to abide by the following terms, and subject
+				to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs
+				copyrights in this original Apple software (the "Apple Software"), to use,
+				reproduce, modify and redistribute the Apple Software, with or without
+				modifications, in source and/or binary forms; provided that if you redistribute
+				the Apple Software in its entirety and without modifications, you must retain
+				this notice and the following text and disclaimers in all such redistributions of
+				the Apple Software.  Neither the name, trademarks, service marks or logos of
+				Apple Computer, Inc. may be used to endorse or promote products derived from the
+				Apple Software without specific prior written permission from Apple.  Except as
+				expressly stated in this notice, no other rights or licenses, express or implied,
+				are granted by Apple herein, including but not limited to any patent rights that
+				may be infringed by your derivative works or by other works in which the Apple
+				Software may be incorporated.
+
+				The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO
+				WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+				WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+				PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
+				COMBINATION WITH YOUR PRODUCTS.
+
+				IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+				CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+				GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+				ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
+				OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
+				(INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
+				ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+	Change History (most recent first):
+
+$Log: MoreSecurity.h,v $
+Revision 1.5  2003/01/20 07:58:32  eskimo1
+Corrected some misspellings.
+
+Revision 1.4  2002/12/12 17:47:57  eskimo1
+There should only be one point 5 in the "how to use" comment.
+
+Revision 1.3  2002/12/12 15:40:19  eskimo1
+Eliminate MoreAuthCopyRightCFString because it makes no sense.  A helper tool should always have the right name hard-wired into it, and hardwiring a C string is even easier than hardwiring a CFString.
+
+Revision 1.2  2002/11/25 16:42:29  eskimo1
+Significant changes. Handle more edge cases better (for example, volumes with the "ignore permissions" flag turned on). Also brought MoreSecurity more into the CoreServices world.
+
+Revision 1.1  2002/11/09 00:08:40  eskimo1
+First checked in. A module containing security helpers.
+
+
+*/
+
+#pragma once
+
+/////////////////////////////////////////////////////////////////
+
+// MoreIsBetter Setup
+
+#include "MoreSetup.h"
+
+#if !TARGET_RT_MAC_MACHO
+	#error MoreSecurity requires the use of Mach-O
+#endif
+
+// System prototypes
+
+#include <Security/Security.h>
+#include <CoreServices/CoreServices.h>
+
+/////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/////////////////////////////////////////////////////////////////
+#pragma mark ***** UID Management
+
+// Basic utilities to manage your UIDs in setuid root programs.
+
+// RUID = real user id      = ID of user who is running program
+// EUID = effective user id = ID used to restrict privileged operations
+// SUID = saved user id     = extra ID to allow setuid programs to switch in and out of privileged mode
+
+extern int MoreSecPermanentlySetNonPrivilegedEUID(void);
+    // Relinquish privileges by setting RUID, EUID, and SUID 
+    // to the RUID.
+
+extern int MoreSecTemporarilySetNonPrivilegedEUID(void);
+    // Set the EUID to the RUID, which means that subsequent 
+    // code runs with a non-zero EUID.  The process can 
+    // still switch back to EUID when needed because the 
+    // SUID is still 0.
+
+extern int MoreSecSetPrivilegedEUID(void);
+	// Set the EUID to 0.  This is only possible if either 
+	// the EUID is already 0 or the SUID is 0.
+
+// Typical Usage Patterns
+// ----------------------
+// #1 -- Do privileged operation and then drop privs
+// 
+//       DoPrivilegedStuff();
+//       MoreSecPermanentlySetNonPrivilegedEUID();
+//       DoNonPrivilegedStuff();
+//
+// #2 -- Switch in and out of privileged mode
+//
+//       MoreSecTemporarilySetNonPrivilegedEUID();
+//       DoNonPrivilegedStuff();
+//       MoreSecSetPrivilegedEUID();
+//       DoPrivilegedStuff();
+//       ... repeat as necessary ...
+//       MoreSecPermanentlySetNonPrivilegedEUID();
+//       DoNonPrivilegedStuff();
+//
+
+/////////////////////////////////////////////////////////////////
+#pragma mark **** Environment Management
+
+// This is a utility routine to destroy any environment that you might have 
+// inherited from your parent.  It's most useful in a setuid root program, 
+// which has to be careful that it doesn't rely on untrusted information 
+// that it inherited.  Also useful for any privileged program which wants 
+// to execute a non-privileged program and ensure that no privileged 
+// information leaks to that program.
+
+// The following is a set of bit masks used for the whatToDubya parameter 
+// of the MoreSecDestroyInheritedEnvironment function.
+
+enum {
+    kMoreSecKeepNothingMask           = 0x0000,
+    
+    kMoreSecKeepArg0Mask              = 0x0001,
+        // if set, don't reset argv[0] to the real 
+        // executable path
+    kMoreSecKeepEnvironmentMask       = 0x0002,
+        // if set, don't clear environment
+    kMoreSecKeepStandardFilesMask     = 0x0004,
+        // if set, don't close stdin, stdout, stderr
+    kMoreSecKeepOtherFilesMask        = 0x0008,
+        // if set, don't close other file descriptors
+    kMoreSecKeepSignalsMask           = 0x0010,
+        // if set, don't reset signals to default
+    kMoreSecKeepUmaskMask             = 0x0020,
+        // if set, don't reset umask
+    kMoreSecKeepNiceMask              = 0x0040,
+        // if set, don't reset process nice values
+    kMoreSecKeepResourceLimitsMask    = 0x0080,
+        // if set, don't reset resource limits
+    kMoreSecKeepCurrentDirMask        = 0x0100, 
+        // if set, don't set CWD to "/"
+    kMoreSecKeepTimersMask            = 0x0200, 
+        // if set, don't reset all interval timers
+        
+    kMoreSecKeepEverythingMask        = 0x03FF
+};
+
+extern int MoreSecDestroyInheritedEnvironment(int whatToDubya, const char **argv);
+    // This function eliminates most of the environmental 
+    // factors that you have inherited from your parent 
+    // process.  The function is intended for use by setuid 
+    // root programs, who shouldn't trust any information 
+    // supplied by a potentially malicious parent process.
+    // 
+    // The whatToDubya parameter is a bit mask that 
+    // specifies what environmental factors to *keep*.  The 
+    // most secure option is to pass kMoreSecKeepNothingMask 
+    // (ie 0), which means you keep no environmental factors.
+    //
+    // The argv parameter allows the function to access argv 
+    // without any special magic.  You can pass NULL if you 
+    // whatToDubya has kMoreSecKeepArg0Mask set, which 
+    // indicates that you don't want to reset argv[0].
+    //
+    // The function returns a errno-style error.  If it's 
+    // non-zero you probably should err on the side of 
+    // caution and refuse to start up.
+
+/////////////////////////////////////////////////////////////////
+#pragma mark **** Helper Tool Big Picture
+
+// These utilities let you easily implement a setuid helper tool.
+// This design is largely stolen from the DTS sample code "AuthSample", 
+// with refinements to cover more cases and allow easy code reuse.
+// 
+// <http://developer.apple.com/samplecode/Sample_Code/Security/AuthSample.htm>
+//
+// To create a setuid root help tool, follow these simple instructions.
+//
+// 1. Define a request/response protocol based around CFDictionaries.
+//    This is as simple as defining the set of keys in the request 
+//    that describe the operation you want to do, and the set of 
+//    keys in the response that hold the results of those operations 
+//    (if any).
+//
+// 2. Create a helper tool whose "main" function looks like:
+//
+//  	int main(int argc, const char *argv[])
+//  	{	
+//  		int 				err;
+//  		int 				result;
+//  		AuthorizationRef 	auth;
+//  		
+//  		auth = MoreSecHelperToolCopyAuthRef();
+//  	
+//  		err = MoreSecDestroyInheritedEnvironment(kMoreSecKeepStandardFilesMask, argv);
+//  		if (err == 0) {
+//  			err = MoreUNIXIgnoreSIGPIPE();
+//  		}
+//  		if (err == 0) {
+//  			err = MoreSecHelperToolMain(STDIN_FILENO, STDOUT_FILENO, auth, MyCommandProc, argc, argv);
+//  		}
+//  	
+//  		return MoreSecErrorToHelperToolResult(err);
+//  	}
+// 
+//    MyCommandProc is a callback that is executed when a request is 
+//    passed to the tool.  It can do privileged operations, such as 
+//    committing changes to System Configuration framework.  Its 
+//    parameters are passed to it as a CFDictionary.  It can pass results 
+//    back to the application by creating a response dictionary.
+//
+// 3. Put the tool in the "MacOS" folder inside your application package.
+//    Decide on two tool names, one for the original template tool 
+//    (for example, "HelperToolTemplate") and one for the working copy 
+//    of the tool (for example, "HelperTool").
+//
+// 4. In your application, use MoreSecCopyHelperToolURLAndCheckBundled to find 
+//    (or create) the working copy of your tool.  
+// 
+//		err = MoreSecCopyHelperToolURLAndCheckBundled(CFBundleGetMainBundle(), CFSTR("HelperToolTemplate"), 
+//											  	 	  kApplicationSupportFolderType, CFSTR("My Application Name"), CFSTR("HelperTool"), 
+//											  	 	  &tool);
+//    
+//    The working copy of the helper tool will exist within the user's 
+//    Application Support folder.  See the description of 
+//    MoreSecCopyHelperToolURLAndCheck[Bundled] for an explanation of this.
+// 
+// 5. Then use MoreSecExecuteRequestInHelperTool to execute the tool, passing it 
+//    a request dictionary.  On success, you'll get back a response dictionary.  Use 
+//    MoreSecGetErrorFromResponse to extract the error result from your tool's 
+//    MyCommandProc routine.
+//
+// 6. For extra credit, use AuthorizationCopyRights to have your tool 
+//    be self-limiting, as described in the Authorization Services docs.
+//
+//    <http://developer.apple.com/techpubs/macosx/CoreTechnologies/securityservices/authorizationservices/authservices.html>
+// 
+//              *              *              *              *
+//
+// This complex design is required for a number of reasons.
+// 
+//  o The technique of using a self-limiting setuid root helper tool is 
+//    recommended by Apple's security team.
+// 
+//  o You need to use a working helper tool and a backup helper tool 
+//    because of the problems in the Mac OS X Finder.  The problems 
+//    are as follows:
+//
+//    - In Mac OS X 10.0.x, the Finder will silently not copy the  
+//      setuid root attribute of a helper program within your bundle.
+//
+//    - In Mac OS X 10.1.x, the Finder will not copy the setuid root 
+//      helper program within your bundle (and display a wacky error 
+//      dialog).
+//
+//    - In Mac OS X 10.2.x, the Finder will refuse to copy an application 
+//      that contains a setuid root helper tool.
+//
+//  o It's a general requirement that a Mac OS X application be 
+//    self-contained, that is, it should be drag installable and not 
+//    require the user to run an installer.
+//
+//  o It's a general requirement that a Mac OS X application be runnable 
+//    from a read-only volume (like a CD-ROM).  Thus, you can't place 
+//    the helper tool within the application bundle because copying it 
+//    there would require the volume be writable.
+//
+//  o Users can choose to ignore privileges on a particular volume 
+//    by checking a checkbox in the Finder Get Info window.  A setuid 
+//    program on an volume that's ignoring privileges will not be 
+//    effective (ie it won't run as EUID 0).
+//
+// By placing the setuid root helper tool within the Application Support 
+// folder, this code allows you to copy the application bundle from 
+// one disk to another without breaking it and without any weird error 
+// dialogs.  In addition, you can copy the program to another machine 
+// entirely, and the only thing the user has to do is to reenter their 
+// admin password when they first run the application.  Finally, the 
+// user's Application Support folder is typically inside their home 
+// directory, which is typically on the system volume, and thus is 
+// not ignoring privileges.
+
+/////////////////////////////////////////////////////////////////
+#pragma mark **** Helper Tool Implementation
+
+// The following are special error codes used by the helper tool code. 
+// These error codes can be mapped to the helper tool return status 
+// (ie the result from main).  For example, kMoreSecResultParamErr maps 
+// to a return status of 1, kMoreSecResultPrivilegesErr maps to 2, 
+// and so on.
+
+enum {
+	kMoreSecResultBase			   = 5360,
+
+	kMoreSecResultParamErr         = 5361,
+	kMoreSecResultPrivilegesErr    = 5362,
+	kMoreSecResultCanceledErr      = 5363, 
+	kMoreSecResultInternalErrorErr = 5364,
+	
+	kMoreSecFirstResultErr = kMoreSecResultParamErr,
+	kMoreSecLastResultErr  = kMoreSecResultInternalErrorErr
+	
+	// other errors defined below
+};
+
+extern int MoreSecErrorToHelperToolResult(int errNum);
+	// A function to map an errno/OSStatus to a helper tool return 
+	// status.  The MoreSec error codes are mapped as described 
+	// above, and there is a minimal amount of mapping of other 
+	// OSStatus values to those codes.
+	
+extern int MoreSecHelperToolResultToError(int toolResult);
+	// This function maps a helper tool status to the corresponding 
+	// errno/OSStatus value.
+
+extern AuthorizationRef MoreSecHelperToolCopyAuthRef(void);
+	// When started by AuthorizationExecuteWithPrivileges, a helper tool 
+	// gets some important parameters via its environment.  However, 
+	// a helper tool is *supposed* to blow away its environment 
+	// (using MoreSecDestroyInheritedEnvironment) to minimise security 
+	// risks.  This routine allows the tool to recover the parameters 
+	// supplied by AuthorizationExecuteWithPrivileges before it 
+	// calls MoreSecDestroyInheritedEnvironment to destroy the environment.
+	// 
+	// IMPORTANT: It's quite normal for this routine to return NULL.
+	// You should just pass the result straight to MoreSecHelperToolMain.
+
+typedef OSStatus (*MoreSecCommandProc)(AuthorizationRef auth, 
+									   CFDictionaryRef request, CFDictionaryRef *response);
+	// This is a callback type, called by MoreSecHelperToolMain to 
+	// actually execute commands.
+	// 
+	// auth will not be NULL
+	// request will not be NULL
+	// response will not be NULL
+	// *response will be NULL
+	//
+	// The EUID will be set to the RUID, while the SUID will be 0.
+	// If you need to do a privileged operation, you should 
+	// temporarily set the EUID to 0 via MoreSecSetPrivilegedEUID,
+	// and set it back whenh you're done via MoreSecTemporarilySetNonPrivilegedEUID.
+	//
+	// If you don't need to return anything other than a function 
+	// result to your client, you don't need to mess with response.
+	// MoreSecHelperToolMain will create a dictionary containing 
+	// your function result and pass that back to the client.
+	// Even if you do return a dictionary in *response, 
+	// MoreSecHelperToolMain will still put your function result into the 
+	// kMoreSecErrorNumberKey key unless you've set up that key yourself.
+	//
+	// If you want to self-limit the capabilities of your helper tool, 
+	// you might consider using AuthorizationCopyRights to make sure 
+	// that the user has authorization to do specific operations.
+	// 
+	// If you do create a response, it must be it must be flattenable via 
+	// the CFPropertyList APIs.
+
+extern int MoreSecHelperToolMain(int fdIn, int fdOut, AuthorizationRef auth, 
+								 MoreSecCommandProc commandProc, int argc, const char *argv[]);
+	// This function is the helper tool half of MoreSecExecuteRequestInHelperTool.
+	// It's designed to be called directly from your helper tool's "main" function, 
+	// and to implement the entire tool, calling commandProc to handle the specific 
+	// command.
+	//
+	// IMPORTANT: Contrary to the usual rules, this routine disposes of 
+	// auth before returning.  This makes sense when you consider the 
+	// standard "main" function, described above.
+	//
+	// fdIn  must be non-negative, typically you pass in STDIN_FILENO
+	// fdOut must be non-negative, typically you pass in STDOUT_FILENO
+	// auth may be NULL, typically you just pass in the result of MoreSecHelperToolCopyAuthRef
+	// commandProc must not be NULL
+	// argc must be 1 or 2, depending on whether the tool is running in self-repair mode, 
+	// typically you just pass in the argc that was supplied to main
+	// argv must not be NULL, typically you just pass in the value that was supplied to main
+
+/////////////////////////////////////////////////////////////////
+#pragma mark **** Calling Helper Tool
+
+enum {
+	kMoreSecIgnoringPrivsInFolderErr = 5370
+};
+
+extern OSStatus MoreSecIsFolderIgnoringPrivileges(const FSRef *folder, Boolean *ignoringPrivs);
+	// Determines whether the specified folder is on a volume that's 
+	// ignoring privileges (as per the "Ignore ownership on this volume" 
+	// checkbox in the Finder's Get Info dialog).  There is a real API to 
+	// do this but it's currently private. I've filed a request to get 
+	// this made public [3061192].  Until that's done, I use a workaround 
+	// that involves creating a temporary file within the folder and 
+	// seeing if I can manipulate its permissions.  For this workaround to 
+	// work the folder must be read/write accessible.
+	//
+	// folder must not be NULL; folder must reference a folder
+	// ignoringPrivs must not be NULL;
+	// on success, *ignoringPrivs is true if the volume on which the folder 
+	// resides is ignoring privileges; on error, *ignoringPrivs is undefined
+
+extern OSStatus MoreSecCopyHelperToolURLAndCheck(CFURLRef templateTool,
+                                                 OSType folder, CFStringRef subFolderName, CFStringRef toolName,
+                                                 CFURLRef *tool, Boolean *toolFound);
+    // This routine returns a CFURL to your helper tool.  This CFURL typically 
+	// points to a working copy of the tool inside the Application Support 
+	// folder.  This routine confirms that the tool exists and is valid in that 
+	// location.  If that check fails, it restores the tool from the template. 
+	// Thus, the tool pointed to by the returned CFURL will be a valid copy of the 
+	// template tool specified by templateTool.
+	//
+	// templateTool must not be NULL; the tool referenced by templateTool 
+	// must exist; templateTool is a reference to your original helper tool; 
+	// if your template tool is bundled within your application package, you might 
+	// want to use the MoreSecCopyHelperToolURLAndCheckBundled wrapper routine 
+	// (see below)
+	//
+	// folder is a Folder Manager folder selector; typically you pass kApplicationSupportFolderType
+	//
+	// subFolderName is the name of an optional sub-folder within the 
+	// folder specified above; if this is not NULL, the returned URL 
+	// points to within the named folder; if it is NULL, the URL points 
+	// directly within the Folder Manager folder; if you don't want to 
+	// pass NULL, you typically use the name of your application
+	//
+	// toolName is the name of the helper tool itself
+	//
+	// tool must not be NULL; *tool must be NULL; on success, *tool 
+	// is a newly created CFURL that you must release; on error, *tool 
+	// will be NULL
+	//
+	// On current systems, the returned URL will point to one of the 
+	// following if the tool already exists.
+	//
+	//   ~/Library/Application Support/<subFolderName>/<toolName>
+	//   /Library/Application Support/<subFolderName>/<toolName>
+	//   /Network/Library/Application Support/<subFolderName>/<toolName>
+	//   /System/Library/Application Support/<subFolderName>/<toolName>
+	//
+	// If the tool doesn't already exist, a copy will be made in:
+	//
+	//   ~/Library/Application Support/<subFolderName>/<toolName>
+	//
+	// and that URL will be return.d
+	//
+	// In all cases, you can treat <subFolderName> as the empty string 
+	// if subFolderName is NULL.
+	//
+	// An error result of kMoreSecIgnoringPrivsInFolderErr means that 
+	// the helper tool could not be created because the folder is 
+	// on a volume that's ignoring privileges.
+	//
+	// IMPORTANT:
+	// When create the helper tool from the template tool, this only copies the 
+	// data fork of the tool.  If you the helper tool needs to access resources, 
+	// you should either pass those resources in the request dictionary or 
+	// pass it the URL of your bundle in the request dictionary.
+	//
+	// Note:
+	// This does not verify any tool checksum or digital signature, 
+	// for the reasons outlined in the comment "Notes on Code Signing"
+	// (in "MoreSecurity.c").
+
+extern OSStatus MoreSecCopyHelperToolURLAndCheckBundled(CFBundleRef inBundle, CFStringRef templateToolName, 
+														OSType folder, CFStringRef subFolderName, CFStringRef toolName, 
+														CFURLRef *tool, Boolean *toolFound);
+	// Finds (or creates) a helper tool in a bundled application.  
+	// inBundle and templateToolName describe the location of the template 
+	// tool.  folder, subFolderName, and toolName describe the location of the 
+	// working copy of the tool. 
+	//
+	// This routine is a simple composition of CFBundleCopyAuxiliaryExecutableURL and 
+	// MoreSecCopyHelperToolURLAndCheck.
+	//
+	// inBundle must not be NULL; typically you just pass in CFBundleGetMainBundle()
+	// 
+	// templateToolName must not be NULL; the tool must exist within the executable 
+	// folder of inBundle
+	//
+	// See MoreSecCopyHelperToolURLAndCheck for a full description of the folder, 
+	// subFolderName, and toolName parameters.  Typically you pass 
+	// kApplicationSupportFolderType for folder and your application name for 
+	// subFolderName.
+	//
+	// tool must not be NULL; *tool must be NULL; on success, *tool will be 
+	// a URL to the helper tool; on error, *tool will be NULL
+
+extern OSStatus MoreSecExecuteRequestInHelperTool(CFURLRef helperTool, AuthorizationRef auth, 
+											 	  CFDictionaryRef request, CFDictionaryRef *response);
+	// Executes a privileged request in a helper tool.  helperTool is 
+	// a reference to the helper tool to run.  You typically gets its value 
+	// using MoreSecCopyHelperToolURLAndCheckBundled, although it's passed in as a 
+	// parameter to allow flexibility.
+	//
+	// auth is your application's connection to Authorization Services. 
+	// It's likely that you've used this connection to pre-authorization 
+	// this operation, as described in the Authorization Services docs.
+	//
+	// <http://developer.apple.com/techpubs/macosx/CoreTechnologies/securityservices/authorizationservices/authservices.html>
+	//
+	// request specifies what you want the helper tool to do.  Its 
+	// contents are not interpreted by MoreSecExecuteRequestInHelperTool, 
+	// however, it must be flattenable via the CFPropertyList APIs.
+	//
+	// response is the reply from the helper tool.  It is not interpreted 
+	// by MoreSecExecuteRequestInHelperTool other than to add a key
+	// (kMoreSecErrorNumberKey) which contains the error from the 
+	// helper tool's commandProc.
+	//
+	// helperTool must not be NULL
+	// auth must not be NULL
+	// request must not be NULL
+	//  response must not be NULL
+	// *response must be NULL
+
+extern OSStatus MoreSecGetErrorFromResponse(CFDictionaryRef response);
+	// this function returns the error stored in a helper tool 
+	// response obtained via MoreSecExecuteRequestInHelperTool.
+	//
+	// response must not be NULL
+
+#define kMoreSecErrorNumberKey CFSTR("com.apple.dts.MoreIsBetter.MoreSec.ErrorNumber")		// CFNumberRef, OSStatus
+	// The dictionary key where the helper tool error is stored.
+	
+#ifdef __cplusplus
+}
+#endif
Index: /trunk/Cocoa/Pester/Source/MoreSecurity/MoreSetup.h
===================================================================
--- /trunk/Cocoa/Pester/Source/MoreSecurity/MoreSetup.h	(revision 118)
+++ /trunk/Cocoa/Pester/Source/MoreSecurity/MoreSetup.h	(revision 118)
@@ -0,0 +1,249 @@
+/*
+	File:		MoreSetup.h
+
+	Contains:	Sets up conditions etc for MoreIsBetter.
+
+	Written by:	Pete Gontier
+
+	Copyright:	Copyright (c) 1998-2001 by Apple Computer, Inc., All Rights Reserved.
+
+	Disclaimer:	IMPORTANT:  This Apple software is supplied to you by Apple Computer, Inc.
+				("Apple") in consideration of your agreement to the following terms, and your
+				use, installation, modification or redistribution of this Apple software
+				constitutes acceptance of these terms.  If you do not agree with these terms,
+				please do not use, install, modify or redistribute this Apple software.
+
+				In consideration of your agreement to abide by the following terms, and subject
+				to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs
+				copyrights in this original Apple software (the "Apple Software"), to use,
+				reproduce, modify and redistribute the Apple Software, with or without
+				modifications, in source and/or binary forms; provided that if you redistribute
+				the Apple Software in its entirety and without modifications, you must retain
+				this notice and the following text and disclaimers in all such redistributions of
+				the Apple Software.  Neither the name, trademarks, service marks or logos of
+				Apple Computer, Inc. may be used to endorse or promote products derived from the
+				Apple Software without specific prior written permission from Apple.  Except as
+				expressly stated in this notice, no other rights or licenses, express or implied,
+				are granted by Apple herein, including but not limited to any patent rights that
+				may be infringed by your derivative works or by other works in which the Apple
+				Software may be incorporated.
+
+				The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO
+				WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+				WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+				PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
+				COMBINATION WITH YOUR PRODUCTS.
+
+				IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+				CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+				GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+				ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
+				OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
+				(INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
+				ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+	Change History (most recent first):
+
+$Log: MoreSetup.h,v $
+Revision 1.14  2002/11/08 22:43:02  eskimo1
+A bunch of key changes. We no longer include <Carbon/Carbon.h> in the Mach-O builds, which means that individual MoreIsBetter modules can decide what frameworks they're dependent on. Also changed MoreIsBetter to use the standard C assert mechanism.
+
+Revision 1.13  2001/11/07 15:55:15  eskimo1
+Tidy up headers, add CVS logs, update copyright.
+
+
+        <12>     21/9/01    Quinn   Fix CF framework includes workaround.
+        <11>     21/9/01    Quinn   Changes for CWPro7 Mach-O build.
+        <10>     15/2/01    Quinn   MoreIsBetter now requires UI 3.4 (pre-release) or later.
+         <9>      8/2/01    Quinn   Modern versions of MIB require UI 3.3.2 or higher.
+         <8>    22/11/00    Quinn   Switch to "MacErrors.h".
+         <7>     22/4/99    Quinn   Add a check for the Universal Interfaces version.  MoreIsBetter
+                                    requires Universal Interfaces 3.2 or higher (because many of its
+                                    component parts do).
+         <6>     2/11/99    PCG     add comments because Andy rightfully pointed out my original
+                                    attempts sucked; also, remove some excessive TARGET_CARBON
+                                    gymnastics
+         <5>     1/22/99    PCG     TARGET_CARBON
+         <4>    11/11/98    PCG     fix header
+         <3>    11/10/98    PCG     separate change histories
+         <2>    10/11/98    Quinn   Convert "MorePrefix.h" to "MoreSetup.h".
+         <1>    10/11/98    Quinn   Changed name from "MorePrefix.h" to "MoreSetup.h".
+
+	Start of "MorePrefix.h" change history (most recent first):
+
+         <3>     5/11/98    Quinn   Use MoreAssertQ instead of MoreAssert.
+         <2>     7/24/98    PCG	    rid of triplet #includes
+         <2>     6/23/98    PCG     add copyright disclaimer stuff
+         <1>     6/23/98    PCG     initial checkin
+*/
+
+#pragma once
+
+	//
+	//	We never want to use old names or locations.
+	//	Since these settings must be consistent all the way through
+	//	a compilation unit, and since we don't want to silently
+	//	change them out from under a developer who uses a prefix
+	//	file (C/C++ panel of Target Settings), we simply complain
+	//	if they are already set in a way we don't like.
+	//
+
+#ifndef OLDROUTINELOCATIONS
+	#define OLDROUTINELOCATIONS 0
+#elif OLDROUTINELOCATIONS
+	#error OLDROUTINELOCATIONS must be FALSE when compiling MoreIsBetter.
+#endif
+
+#ifndef OLDROUTINENAMES
+	#define OLDROUTINENAMES 0
+#elif OLDROUTINENAMES
+	#error OLDROUTINENAMES must be FALSE when compiling MoreIsBetter.
+#endif
+
+	//
+	//	The next statement sets up the various TARGET_xxx 
+	//	variables needed later in this file.
+	//
+	
+#include <TargetConditionals.h>
+
+	//
+	//  "TargetConditionals.h" on Mac OS X doesn't define 
+	//  TARGET_API_MAC_CARBON, which is kinda annoying.  So, 
+	//  if we're building for Mach-O and it hasn't been set, 
+	//  set it.  All Mach-O builds are inherently Carbon builds.
+	//
+	//  Note that we *have* to set TARGET_API_MAC_CARBON because 
+	//  MoreIsBetter code tests it.  However, we also want to set 
+	//  the other values because otherwise GCC won't use its 
+	//  precompiled header.  I thought about fixing this by 
+	//  including <ConditionalMacros.h> via <CoreServices/CoreServices.h>, 
+	//  but the whole goal of using <TargetConditionals.h> was to 
+	//  allow MoreIsBetter projects to have no dependencies on 
+	//  frameworks beyond System.framework.
+	//
+
+#if TARGET_RT_MAC_MACHO
+	#define TARGET_API_MAC_OS8 0
+	#define TARGET_API_MAC_CARBON 1
+	#define TARGET_API_MAC_OSX 1
+#endif
+
+	//
+	//	We need a master conditional to determine whether to use 
+	//	framework notation to reference include files.  There is 
+	//  no good way to determine whether the source tree 
+	//  is using framework includes or not, so we make a guess and 
+	//  say that Mach-O implies framework includes.  However, 
+	//  if you're building CFM with framework includes (which is 
+	//  possible, although somewhat tricky), you'll have to 
+	//  override this.
+	//
+
+#if !defined(MORE_FRAMEWORK_INCLUDES)
+	#if TARGET_RT_MAC_MACHO
+		#define MORE_FRAMEWORK_INCLUDES 1
+	#else
+		#define MORE_FRAMEWORK_INCLUDES 0
+	#endif
+#endif
+
+	//
+	//	The following works around a problem in <CoreFoundation/CFBase.h>
+	//	in Mac OS X.  CF is assuming that the CW Mach-O compiler 
+	//	would not use framework includes, which is not the case for the 
+	//	CWPro7 and later compilers.  We only do this for the CW build 
+    //	because otherwise the presence of the define prevents Project Builder 
+    //	from using Carbon's precompiled header.
+	//
+	
+#if MORE_FRAMEWORK_INCLUDES
+	#if defined(__MWERKS__)
+		#if !defined(__CF_USE_FRAMEWORK_INCLUDES__)
+		    #define __CF_USE_FRAMEWORK_INCLUDES__ 1
+		#endif
+	#endif
+#endif
+
+	// 
+	//	Previouly we would bring in <MacErrors.h> at this point.
+	//	However, that's somewhat counter to the idea behind flat 
+	//	includes, so I've eliminated it.
+	//
+
+	//
+	//	Now that we've included a Mac OS interface file,
+	//	we know that the Universal Interfaces environment
+	//	is set up.  MoreIsBetter requires Universal Interfaces
+	//	3.4 or higher.  Check for it.  Of course, "TargetConditionals.h" 
+	//  on Mac OS X doesn't set UNIVERSAL_INTERFACES_VERSION, so 
+	//  we only check this if we're not using framework includes.
+	//
+
+#if !MORE_FRAMEWORK_INCLUDES
+	#if !defined(UNIVERSAL_INTERFACES_VERSION) || UNIVERSAL_INTERFACES_VERSION < 0x0341
+		#error MoreIsBetter requires Universal Interfaces 3.4.1 or higher.
+	#endif
+#endif
+
+	//
+	//	We usually want assertions and other debugging code
+	//	turned on, but you can turn it all off if you like
+	//	by setting MORE_DEBUG to 0.  Also, now that we use 
+	//  the standard C assertion mechanism, we default to 
+	//  have MORE_DEBUG off if NDEBUG is set.
+	//
+
+#if !defined(MORE_DEBUG)
+	#if defined(NDEBUG)
+		#define MORE_DEBUG 0
+	#else
+		#define MORE_DEBUG 1
+	#endif
+#endif
+
+	//
+	//  We now use standard C assertions throughout MoreIsBetter.
+	//  Previously we would declare two custom assertion macros, 
+	//  MoreAssert and MoreAssertQ.
+	//
+	//	Our assertion macros compile down to nothing if
+	//	MORE_DEBUG is not true. MoreAssert produces a
+	//	value indicating whether the assertion succeeded
+	//	or failed. MoreAssertQ is Quinn's flavor of
+	//	MoreAssert which does not produce a value.
+	//
+
+#include <assert.h>
+
+	//
+	//  Chances are that if you're building CFM then you'd much 
+	//  rather have assert triggered DebugStr that abort.  The 
+	//  following redefines assert that way.  We don't do this 
+	//  for Mach-O because you might be building a Mach-O tool that 
+	//  doesn't have access to DebugStr.
+	// 
+	
+#if TARGET_RT_MAC_CFM && !defined(NDEBUG)
+	#undef assert
+	#define assert(x) ((x) ? ((void) 0) : DebugStr("\pMoreIsBetter assertion failure: " #x))
+#endif
+
+	// 
+	//  Finally, we define MoreAssertPCG, to accomodate some 
+	//  older MoreIsBetter code that tests the result of its 
+	//  assertions.  This doesn't fit in with the standard C 
+	//  assert model, so I've deprecated the approach.  However
+	//  there's a bunch of existing code that works that way 
+	//  and reworking it would be likely to generate errors. 
+	//  Fortunately, all of the old code that uses this is 
+	//  Carbon based, so I don't have to worry about not having 
+	//  access to DebugStr.
+	// 
+	
+#if MORE_DEBUG
+	#define MoreAssertPCG(x) \
+		((x) ? true : (DebugStr ("\pMoreIsBetter assertion failure: " #x), false))
+#else
+	#define MoreAssertPCG(x) (true)
+#endif
Index: /trunk/Cocoa/Pester/Source/MoreSecurity/MoreUNIX.c
===================================================================
--- /trunk/Cocoa/Pester/Source/MoreSecurity/MoreUNIX.c	(revision 118)
+++ /trunk/Cocoa/Pester/Source/MoreSecurity/MoreUNIX.c	(revision 118)
@@ -0,0 +1,431 @@
+/*
+	File:		MoreUNIX.c
+
+	Contains:	Generic UNIX utilities.
+
+	Written by:	Quinn
+
+	Copyright:	Copyright (c) 2002 by Apple Computer, Inc., All Rights Reserved.
+
+	Disclaimer:	IMPORTANT:  This Apple software is supplied to you by Apple Computer, Inc.
+				("Apple") in consideration of your agreement to the following terms, and your
+				use, installation, modification or redistribution of this Apple software
+				constitutes acceptance of these terms.  If you do not agree with these terms,
+				please do not use, install, modify or redistribute this Apple software.
+
+				In consideration of your agreement to abide by the following terms, and subject
+				to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs
+				copyrights in this original Apple software (the "Apple Software"), to use,
+				reproduce, modify and redistribute the Apple Software, with or without
+				modifications, in source and/or binary forms; provided that if you redistribute
+				the Apple Software in its entirety and without modifications, you must retain
+				this notice and the following text and disclaimers in all such redistributions of
+				the Apple Software.  Neither the name, trademarks, service marks or logos of
+				Apple Computer, Inc. may be used to endorse or promote products derived from the
+				Apple Software without specific prior written permission from Apple.  Except as
+				expressly stated in this notice, no other rights or licenses, express or implied,
+				are granted by Apple herein, including but not limited to any patent rights that
+				may be infringed by your derivative works or by other works in which the Apple
+				Software may be incorporated.
+
+				The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO
+				WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+				WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+				PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
+				COMBINATION WITH YOUR PRODUCTS.
+
+				IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+				CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+				GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+				ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
+				OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
+				(INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
+				ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+	Change History (most recent first):
+
+$Log: MoreUNIX.c,v $
+Revision 1.4  2002/12/13 00:30:18  eskimo1
+10.1 compatibility. futimes isn't available in 10.1. Drat! Also, in NSGetExecutablePathOnTenOneAndEarlierOnly, have to skip over multiple NULLs between the environment and the relative path point, in case someone (like MoreSecDestroyInheritedEnvironment perhaps) has called unsetenv.
+
+Revision 1.3  2002/12/12 23:14:29  eskimo1
+C++ compatibility.
+
+Revision 1.2  2002/11/14 20:15:20  eskimo1
+In MoreUNIXCopyFile, correctly set the modified and accessed times of the resulting file.
+
+Revision 1.1  2002/11/09 00:15:21  eskimo1
+A collection of useful UNIX-level routines.
+
+
+*/
+
+/////////////////////////////////////////////////////////////////
+
+// Our prototypes
+
+#include "MoreUNIX.h"
+
+// System interfaces
+
+#include <sys/param.h>
+#include <mach-o/dyld.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <stdbool.h>
+
+// "crt_externs.h" has no C++ guards [3126393], so we have to provide them 
+// ourself otherwise we get a link error.
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <crt_externs.h>
+
+#ifdef __cplusplus
+}
+#endif
+
+// MIB Interfaces
+
+/////////////////////////////////////////////////////////////////
+
+#if MORE_DEBUG
+
+	// There's a macro version of this in the header.
+	
+	extern int MoreUNIXErrno(int result)
+	{
+		int err;
+		
+		err = 0;
+		if (result < 0) {
+			err = errno;
+			assert(err != 0);
+		}
+		return err;
+	}
+
+#endif
+
+/////////////////////////////////////////////////////////////////
+
+static int NSGetExecutablePathOnTenOneAndEarlierOnly(char *execPath, size_t *execPathSize)
+{
+    int  	err = 0;
+    char 	**cursor;
+    char 	*possiblyRelativePath;
+    char 	absolutePath[MAXPATHLEN];
+    size_t 	absolutePathSize;
+    
+    assert(execPath != NULL);
+    assert(execPathSize != NULL);
+    
+    cursor = (char **) (*(_NSGetArgv()) + *(_NSGetArgc()));
+    
+    // There should be a NULL after the argv array.
+    // If not, error out.
+    
+    if (*cursor != 0) {
+        err = -1;
+	}
+    
+    if (err == 0) {
+        // Skip past the NULL after the argv array.
+        
+        cursor += 1;
+        
+        // Now, skip over the entire kernel-supplied environment, 
+        // which is an array of char * terminated by a NULL.
+        
+        while (*cursor != 0) {
+            cursor += 1;
+        }
+        
+        // Skip over the NULL terminating the environment.  Actually, 
+        // there can be multiple NULLs if the program has called 
+        // unsetenv, so we skip along until we find a the next non-NULL.
+        
+        while (*cursor == 0) {
+            cursor += 1;
+        }
+
+        // Now we have the path that was passed to exec 
+        // (not the argv[0] path, but the path that the kernel 
+        // actually executed).
+        
+        possiblyRelativePath = *cursor;
+
+        // Convert the possibly relative path to an absolute 
+        // path.  We use realpath for expedience, although 
+        // the real implementation of _NSGetExecutablePath
+        // uses getcwd and can return a path with symbolic links 
+        // etc in it.
+        
+        if (realpath(possiblyRelativePath, absolutePath) == NULL) {
+            err = errno;
+		}
+    }
+    
+    // Now copy the path out into the client's buffer, returning 
+    // an error if the buffer isn't big enough.
+    
+    if (err == 0) {
+        absolutePathSize = (strlen(absolutePath) + 1);
+        
+        if (absolutePathSize <= *execPathSize) {
+            strcpy(execPath, absolutePath);
+        } else {
+            err = -1;
+        }
+        
+        *execPathSize = absolutePathSize;
+    }
+
+    return err;
+}
+
+typedef int (*NSGetExecutablePathProcPtr)(char *buf, size_t *bufsize);
+
+extern int MoreGetExecutablePath(char *execPath, size_t *execPathSize)
+{
+    if (NSIsSymbolNameDefined("__NSGetExecutablePath")) {
+        return ((NSGetExecutablePathProcPtr) NSAddressOfSymbol(NSLookupAndBindSymbol("__NSGetExecutablePath")))(execPath, execPathSize);
+    } else {
+        // The function _NSGetExecutablePath() is new in Mac OS X 10.2, 
+        // so use this custom version when running on 10.1.x and earlier.
+        return NSGetExecutablePathOnTenOneAndEarlierOnly(execPath, execPathSize);
+    }
+}
+
+/////////////////////////////////////////////////////////////////
+
+extern int MoreUNIXRead( int fd,       void *buf, size_t bufSize, size_t *bytesRead   )
+	// See comment in header.
+{
+	int 	err;
+	char *	cursor;
+	size_t	bytesLeft;
+	ssize_t bytesThisTime;
+
+	assert(fd >= 0);
+	assert(buf != NULL);
+	
+	err = 0;
+	bytesLeft = bufSize;
+	cursor = (char *) buf;
+	while ( (err == 0) && (bytesLeft != 0) ) {
+		bytesThisTime = read(fd, cursor, bytesLeft);
+		if (bytesThisTime > 0) {
+			cursor    += bytesThisTime;
+			bytesLeft -= bytesThisTime;
+		} else if (bytesThisTime == 0) {
+			err = EPIPE;
+		} else {
+			assert(bytesThisTime == -1);
+			
+			err = errno;
+			assert(err != 0);
+			if (err == EINTR) {
+				err = 0;		// let's loop again
+			}
+		}
+	}
+	if (bytesRead != NULL) {
+		*bytesRead = bufSize - bytesLeft;
+	}
+	
+	return err;
+}
+
+extern int MoreUNIXWrite(int fd, const void *buf, size_t bufSize, size_t *bytesWritten)
+	// See comment in header.
+{
+	int 	err;
+	char *	cursor;
+	size_t	bytesLeft;
+	ssize_t bytesThisTime;
+	
+	assert(fd >= 0);
+	assert(buf != NULL);
+	
+	// SIGPIPE occurs when you write to pipe or socket 
+	// whose other end has been closed.  The default action 
+	// for SIGPIPE is to terminate the process.  That's 
+	// probably not what you wanted.  So, in the debug build, 
+	// we check that you've set the signal action to SIG_IGN 
+	// (ignore).  Of course, you could be building a program 
+	// that needs SIGPIPE to work in some special way, in 
+	// which case you should define MORE_UNIX_WRITE_CHECK_SIGPIPE 
+	// to 0 to bypass this check.
+	//
+	// MoreUNIXIgnoreSIGPIPE, a helper routine defined below, 
+	// lets you disable SIGPIPE easily.
+	
+	#if !defined(MORE_UNIX_WRITE_CHECK_SIGPIPE)
+		#define MORE_UNIX_WRITE_CHECK_SIGPIPE 1
+	#endif
+	#if MORE_DEBUG && MORE_UNIX_WRITE_CHECK_SIGPIPE
+		{
+			int junk;
+			struct sigaction currentSignalState;
+			
+			junk = sigaction(SIGPIPE, NULL, &currentSignalState);
+			assert(junk == 0);
+			
+			assert( currentSignalState.sa_handler == SIG_IGN );
+		}
+	#endif
+
+	err = 0;
+	bytesLeft = bufSize;
+	cursor = (char *) buf;
+	while ( (err == 0) && (bytesLeft != 0) ) {
+		bytesThisTime = write(fd, cursor, bytesLeft);
+		if (bytesThisTime > 0) {
+			cursor    += bytesThisTime;
+			bytesLeft -= bytesThisTime;
+		} else if (bytesThisTime == 0) {
+			assert(false);
+			err = EPIPE;
+		} else {
+			assert(bytesThisTime == -1);
+			
+			err = errno;
+			assert(err != 0);
+			if (err == EINTR) {
+				err = 0;		// let's loop again
+			}
+		}
+	}
+	if (bytesWritten != NULL) {
+		*bytesWritten = bufSize - bytesLeft;
+	}
+	
+	return err;
+}
+
+extern int MoreUNIXIgnoreSIGPIPE(void)
+	// See comment in header.
+{
+	int err;
+	struct sigaction signalState;
+	
+	err = sigaction(SIGPIPE, NULL, &signalState);
+	err = MoreUNIXErrno(err);
+	if (err == 0) {
+		signalState.sa_handler = SIG_IGN;
+		
+		err = sigaction(SIGPIPE, &signalState, NULL);
+		err = MoreUNIXErrno(err);
+	}
+	
+	return err;
+}
+
+extern int MoreUNIXCopyDescriptorToDescriptor(int source, int dest)
+	// See comment in header.
+{
+	int		err;
+	bool    done;
+	char *  buffer;
+	static const size_t kBufferSize = 64 * 1024;
+	
+	assert(source >= 0);
+	assert(dest   >= 0);
+	
+	err = 0;
+	buffer = (char *) malloc(kBufferSize);
+	if (buffer == NULL) {
+		err = ENOMEM;
+	}
+
+	if (err == 0) {	
+		done = false;
+		do {
+			size_t bytesRead;
+			
+			err = MoreUNIXRead(source, buffer, kBufferSize, &bytesRead);
+			if (err == EPIPE) {
+				done = true;
+				err = 0;
+			}
+			if (err == 0) {
+				err = MoreUNIXWrite(dest, buffer, bytesRead, NULL);
+			}
+		} while (err == 0 && !done);
+	}
+	
+	free(buffer);
+	
+	return err;
+}
+
+extern int MoreUNIXCopyFile(const char *source, const char *dest)
+	// See comment in header.
+{
+	int 		err;
+	int 		junk;
+	int 		sourceFD;
+	int 		destFD;
+	struct stat sb;
+	
+	assert(source != NULL);
+	assert(dest   != NULL);
+	
+	sourceFD = -1;
+	destFD   = -1;
+
+	err = stat(source, &sb);
+	err = MoreUNIXErrno(err);
+	
+	if (err == 0) {
+		sourceFD = open(source, O_RDONLY, 0);
+		err = MoreUNIXErrno(sourceFD);
+	}
+	
+	if (err == 0) {
+		destFD = open(dest, O_WRONLY | O_CREAT | O_TRUNC, sb.st_mode & ~(S_ISUID | S_ISGID | S_ISVTX));
+		err = MoreUNIXErrno(destFD);
+	}
+	
+	if (err == 0) {
+		err = MoreUNIXCopyDescriptorToDescriptor(sourceFD, destFD);
+	}
+
+	// Close the descriptors.
+	
+	if (sourceFD != -1) {
+		junk = close(sourceFD);
+		assert(junk == 0);
+	}
+	if (destFD != -1) {
+		junk = close(destFD);
+		assert(junk == 0);
+	}
+
+	// Set the access and modification times of the destination 
+	// to match the source.  I originally did this using futimes, 
+	// but hey, that's not available on 10.1, so now I do it 
+	// using utimes.  *sigh*
+	
+	if (err == 0) {
+		struct timeval times[2];
+		
+		TIMESPEC_TO_TIMEVAL(&times[0], &sb.st_atimespec);
+		TIMESPEC_TO_TIMEVAL(&times[1], &sb.st_mtimespec);
+		
+		err = utimes(dest, times);
+		err = MoreUNIXErrno(err);
+	}
+
+	return err;
+}
Index: /trunk/Cocoa/Pester/Source/MoreSecurity/MoreUNIX.h
===================================================================
--- /trunk/Cocoa/Pester/Source/MoreSecurity/MoreUNIX.h	(revision 118)
+++ /trunk/Cocoa/Pester/Source/MoreSecurity/MoreUNIX.h	(revision 118)
@@ -0,0 +1,154 @@
+/*
+	File:		MoreUNIX.h
+
+	Contains:	Generic UNIX utilities.
+
+	Written by:	Quinn
+
+	Copyright:	Copyright (c) 2002 by Apple Computer, Inc., All Rights Reserved.
+
+	Disclaimer:	IMPORTANT:  This Apple software is supplied to you by Apple Computer, Inc.
+				("Apple") in consideration of your agreement to the following terms, and your
+				use, installation, modification or redistribution of this Apple software
+				constitutes acceptance of these terms.  If you do not agree with these terms,
+				please do not use, install, modify or redistribute this Apple software.
+
+				In consideration of your agreement to abide by the following terms, and subject
+				to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs
+				copyrights in this original Apple software (the "Apple Software"), to use,
+				reproduce, modify and redistribute the Apple Software, with or without
+				modifications, in source and/or binary forms; provided that if you redistribute
+				the Apple Software in its entirety and without modifications, you must retain
+				this notice and the following text and disclaimers in all such redistributions of
+				the Apple Software.  Neither the name, trademarks, service marks or logos of
+				Apple Computer, Inc. may be used to endorse or promote products derived from the
+				Apple Software without specific prior written permission from Apple.  Except as
+				expressly stated in this notice, no other rights or licenses, express or implied,
+				are granted by Apple herein, including but not limited to any patent rights that
+				may be infringed by your derivative works or by other works in which the Apple
+				Software may be incorporated.
+
+				The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO
+				WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+				WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+				PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
+				COMBINATION WITH YOUR PRODUCTS.
+
+				IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+				CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+				GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+				ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
+				OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
+				(INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
+				ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+	Change History (most recent first):
+
+$Log: MoreUNIX.h,v $
+Revision 1.2  2002/11/14 20:15:23  eskimo1
+In MoreUNIXCopyFile, correctly set the modified and accessed times of the resulting file.
+
+Revision 1.1  2002/11/09 00:15:24  eskimo1
+A collection of useful UNIX-level routines.
+
+
+*/
+
+#pragma once
+
+/////////////////////////////////////////////////////////////////
+
+// MoreIsBetter Setup
+
+#include "MoreSetup.h"
+
+#if !TARGET_RT_MAC_MACHO
+	#error MoreUNIX requires the use of Mach-O
+#endif
+
+// System prototypes
+
+#include <stdlib.h>
+
+/////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Macros that act like functions to convert OSStatus error codes to errno-style 
+// error codes, and vice versa.  Right now these are just pass throughs because 
+// OSStatus errors are 32 bit signed values that are generally negative, and 
+// errno errors are 32 bit signed values that are small positive.
+
+#define OSStatusToEXXX(os) ((int) (os))
+#define EXXXToOSStatus(ex) ((OSStatus) (ex))
+
+// A mechanism to extra errno if a function fails.  You typically use this as 
+//
+//   fd = open(...);
+//   err = MoreUNIXErrno(fd);
+//
+// or
+//
+//   err = setuid(0);
+//   err = MoreUNIXErrno(err);
+
+#if MORE_DEBUG
+
+	extern int MoreUNIXErrno(int result);
+
+#else
+
+	#define MoreUNIXErrno(err) (((err) < 0) ? errno : 0)
+
+#endif
+
+/////////////////////////////////////////////////////////////////
+
+extern int MoreGetExecutablePath(char *execPath, size_t *execPathSize);
+	// Returns the path to the current executable in execPath. 
+	// On input, execPathSize is the size of the execPath buffer.
+	// On output, execPathSize is the size of the path placed in 
+	// that buffer.
+	// Result is an errno error code.
+
+/////////////////////////////////////////////////////////////////
+
+extern int MoreUNIXRead( int fd,       void *buf, size_t bufSize, size_t *bytesRead   );
+	// A wrapper around "read" that keeps reading until either 
+	// bufSize bytes are read or until EOF is encountered, 
+	// in which case you get EPIPE.
+	//
+	// If bytesRead is not NULL, *bytesRead will be set to the number 
+	// of bytes successfully read.
+
+extern int MoreUNIXWrite(int fd, const void *buf, size_t bufSize, size_t *bytesWritten);
+	// A wrapper around "write" that keeps writing until either 
+	// all the data is written or an error occurs, in which case 
+	// you get EPIPE.
+	//
+	// If bytesWritten is not NULL, *bytesWritten will be set to the number 
+	// of bytes successfully written.
+
+extern int MoreUNIXIgnoreSIGPIPE(void);
+	// Sets the handler for SIGPIPE to SIG_IGN.  If you don't call 
+	// this, writing to a broken pipe will cause SIGPIPE (rather 
+	// than having "write" return EPIPE), which is hardly ever 
+	// what you want.
+
+extern int MoreUNIXCopyDescriptorToDescriptor(int source, int dest);
+	// A naive copy engine, that copies from source to dest 
+	// until EOF is encountered on source.  Not meant for 
+	// copying large amounts of data.
+	
+extern int MoreUNIXCopyFile(const char *source, const char *dest);
+	// A very naive file copy implementation, that just opens 
+	// up source and dest and copies the contents across 
+	// using MoreUNIXCopyDescriptorToDescriptor.
+	// It does, however, handle setting the mode and access/modification 
+	// times of dest properly.
+
+#ifdef __cplusplus
+}
+#endif
Index: /trunk/Cocoa/Pester/Source/PSPowerManager.h
===================================================================
--- /trunk/Cocoa/Pester/Source/PSPowerManager.h	(revision 117)
+++ /trunk/Cocoa/Pester/Source/PSPowerManager.h	(revision 118)
@@ -10,4 +10,6 @@
 #import <IOKit/IOKitLib.h>
 
+extern NSString * const PSPowerManagerException;
+
 @interface PSPowerManager : NSObject {
     id delegate;
@@ -19,6 +21,8 @@
 
 + (BOOL)autoWakeSupported;
++ (void)authorize;
 + (NSDate *)wakeTime;
-+ (void)setWakeTime:(NSDate *)time;
++ (void)setWakeInterval:(unsigned long)wakeInterval;
++ (void)setWakeTime:(NSDate *)time overrideIfEarlier:(BOOL)override;
 + (void)clearWakeTime;
 
Index: /trunk/Cocoa/Pester/Source/PSPowerManager.m
===================================================================
--- /trunk/Cocoa/Pester/Source/PSPowerManager.m	(revision 117)
+++ /trunk/Cocoa/Pester/Source/PSPowerManager.m	(revision 118)
@@ -8,8 +8,17 @@
 
 #import "PSPowerManager.h"
+#import "wakein.h"
 
 #import <IOKit/pwr_mgt/IOPMLib.h>
 #import <IOKit/IOMessage.h>
 #import <CoreFoundation/CoreFoundation.h>
+
+// MoreIsBetter interfaces
+#include "MoreUNIX.h"
+#include "MoreSecurity.h"
+#include "MoreCFQ.h"
+
+// exceptions
+NSString * const PSPowerManagerException = @"PSPowerManagerException";
 
 /*
@@ -52,5 +61,12 @@
 // for superusers
 
-#define PMU_MAGIC_PASSWORD	0x0101FACE // BEEF
+// njr 2003.03.12: both seem to be interchangeable now, and the sleep time is
+// no longer settable as non-root.
+
+#ifdef WAKEIN
+#define PMU_MAGIC_PASSWORD	0x0101BEEF
+#else
+#define PMU_MAGIC_PASSWORD	0x0101FACE
+#endif
 
 /* ==========================================
@@ -173,4 +189,9 @@
     if (pmuReference == NULL) return NO;
     closePMUComPort(pmuReference);
+    NS_DURING
+        [self authorize];
+    NS_HANDLER
+        return NO; // XXX display error?
+    NS_ENDHANDLER
     return YES;
 }
@@ -196,25 +217,87 @@
     if (rawWakeTime == 0) return nil;
     // XXX no idea what the epoch is supposed to be, but this works...
-    return [NSDate dateWithTimeIntervalSinceReferenceDate: rawWakeTime - 18446744072475718320LLU];
-}
-
-+ (void)setWakeTime:(NSDate *)time;
-{
+    return [NSDate dateWithTimeIntervalSinceReferenceDate: rawWakeTime - [[NSTimeZone systemTimeZone] secondsFromGMT] - 18446744072475736320LLU];
+}
+
++ (void)_execWakeToolWithRequestDictionary:(NSDictionary *)request;
+{
+    AuthorizationRef auth = NULL;
+    NSException *exception = NULL;
+
+    NS_DURING
+        CFURLRef tool = NULL;
+        Boolean toolFound;
+        OSStatus err = MoreSecCopyHelperToolURLAndCheckBundled(
+                                                      CFBundleGetMainBundle(), CFSTR("wakeinTemplate"), kApplicationSupportFolderType, CFSTR("Pester"), CFSTR("wakein"), &tool, &toolFound);
+        if (err != noErr) [NSException raise: PSPowerManagerException format: NSLocalizedString(@"Can't set up timed wake from sleep: unable to copy helper tool to Application Support folder (error %u)", "MoreSecCopyHelperToolURLAndCheckBundled failure"), err];
+        [(NSURL *)tool autorelease];
+
+        // if we've found the tool (and it's setuid root), still get an AuthorizationRef, but don't bother to obtain additional rights
+        err = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, toolFound ? kAuthorizationFlagExtendRights | kAuthorizationFlagInteractionAllowed : kAuthorizationFlagDefaults, &auth);
+        if (err != noErr) [NSException raise: PSPowerManagerException format: NSLocalizedString(@"Can't set up timed wake from sleep: AuthorizationCreate failed (error %u)", "AuthorizationCreate failure"), err];
+
+        NSDictionary *response;
+        err = MoreSecExecuteRequestInHelperTool(tool, auth, (CFDictionaryRef)request, (CFDictionaryRef *)&response);
+        [response autorelease];
+        if (err != noErr) [NSException raise: PSPowerManagerException format: NSLocalizedString(@"Can't set up timed wake from sleep: can't obtain response from helper tool (error %u)", "MoreSecExecuteRequestInHelperTool failure"), err];
+
+        NSLog(@"%@", response);
+
+        NSString *wakeinException = [response objectForKey: kPesterWakeException];
+        if (wakeinException != nil) [NSException raise: PSPowerManagerException format: NSLocalizedString(@"Can't set up timed wake from sleep: helper tool reported the error '%@'", "kPesterWakeException"), wakeinException];
+
+        err = MoreSecGetErrorFromResponse((CFDictionaryRef)response);
+        if (err != noErr) [NSException raise: PSPowerManagerException format: NSLocalizedString(@"Can't set up timed wake from sleep: helper tool reported an error of type %u", "MoreSecGetErrorFromResponse"), err];
+        
+    NS_HANDLER
+        exception = localException;
+    NS_ENDHANDLER
+
+    if (auth != NULL) AuthorizationFree(auth, kAuthorizationFlagDestroyRights);
+    if (exception != NULL) [exception raise];
+}
+
++ (void)authorize;
+{
+    [self _execWakeToolWithRequestDictionary: [NSDictionary dictionary]];
+}
+
++ (void)setWakeInterval:(unsigned long)wakeInterval;
+{
+#ifdef WAKEIN
     io_service_t pmuReference = [self _pmuReference];
-    unsigned long wakeTime;
-
-    if (time == nil) wakeTime = 0;
-    else {
-        wakeTime = [time timeIntervalSinceNow];
-        if (wakeTime == 0) wakeTime++; // 0 will disable
+    NSLog(@"writePMUProperty[%u] 0x%lX AutoWake = %lu", pmuReference, PMU_MAGIC_PASSWORD, wakeInterval);
+    writePMUProperty(pmuReference, CFSTR("AutoWake"), (unsigned long *)&wakeInterval, sizeof(wakeInterval));
+
+    closePMUComPort(pmuReference);
+#else
+    [self _execWakeToolWithRequestDictionary: [NSDictionary dictionaryWithObject: [NSNumber numberWithUnsignedLong: wakeInterval] forKey: kPesterWakeTime]];
+#endif
+}
+
++ (void)setWakeTime:(NSDate *)time overrideIfEarlier:(BOOL)override;
+{
+    unsigned long wakeInterval;
+
+    if (time == nil) {
+        wakeInterval = 0;
+        override = YES;
+    } else {
+        wakeInterval = [time timeIntervalSinceNow];
+        if (wakeInterval == 0) wakeInterval++; // 0 will disable
+        if (!override) {
+            NSDate *wakeTime = [self wakeTime];
+            override = (wakeTime == nil || [wakeTime compare: time] == NSOrderedDescending);
+        }
     }
-    writePMUProperty(pmuReference, CFSTR("AutoWake"), (unsigned long *)&wakeTime, sizeof(wakeTime));
-    
-    closePMUComPort(pmuReference);
+
+    if (override) {
+        [self setWakeInterval: wakeInterval];
+    }
 }
 
 + (void)clearWakeTime;
 {
-    [self setWakeTime: nil];
+    [self setWakeTime: nil overrideIfEarlier: YES];
 }
 
Index: /trunk/Cocoa/Pester/Source/PSTimer.m
===================================================================
--- /trunk/Cocoa/Pester/Source/PSTimer.m	(revision 117)
+++ /trunk/Cocoa/Pester/Source/PSTimer.m	(revision 118)
@@ -225,5 +225,5 @@
         if ([date timeIntervalSinceNow] > 30) {
             // NSLog(@"going to sleep, setting timer %@", PSTimerOnWake);
-            [PSPowerManager setWakeTime: [[PSTimerOnWake fireDate] addTimeInterval: -15]];
+            [PSPowerManager setWakeTime: [[PSTimerOnWake fireDate] addTimeInterval: -15] overrideIfEarlier: NO];
             return YES;
         } else {
Index: /trunk/Cocoa/Pester/Source/PSWakeAlert.m
===================================================================
--- /trunk/Cocoa/Pester/Source/PSWakeAlert.m	(revision 117)
+++ /trunk/Cocoa/Pester/Source/PSWakeAlert.m	(revision 118)
@@ -8,4 +8,5 @@
 
 #import "PSWakeAlert.h"
+#import "PSPowerManager.h"
 
 static PSWakeAlert *PSWakeAlertShared;
Index: /trunk/Cocoa/Pester/Source/Pester.pbproj/nicholas.pbxuser
===================================================================
--- /trunk/Cocoa/Pester/Source/Pester.pbproj/nicholas.pbxuser	(revision 117)
+++ /trunk/Cocoa/Pester/Source/Pester.pbproj/nicholas.pbxuser	(revision 118)
@@ -6,5 +6,5 @@
 		activeTarget = 29B97326FDCFA39411CA2CEA;
 		addToTargets = (
-			29B97326FDCFA39411CA2CEA,
+			E14A56EA041DD6B600050002,
 		);
 		breakpoints = (
@@ -18,263 +18,8 @@
 		executables = (
 			F59B967103538BE201154278,
+			E14A56EC041DD6B600050002,
 		);
 		perUserDictionary = {
-			PBXPerProjectTemplateStateSaveDate = 68968119;
-			"PBXTemplateGeometry-F5314676015831810DCA290F" = {
-				ContentSize = "{685, 434}";
-				LeftSlideOut = {
-					Collapsed = NO;
-					Frame = "{{0, 23}, {685, 411}}";
-					Split0 = {
-						ActiveTab = 2;
-						ActiveTabName = PBXBuildResultsModule;
-						Collapsed = NO;
-						Frame = "{{0, 0}, {685, 411}}";
-						Split0 = {
-							Frame = "{{0, 301}, {685, 110}}";
-						};
-						SplitCount = 1;
-						Tab0 = {
-							Frame = "{{0, 0}, {952, 321}}";
-						};
-						Tab1 = {
-							Debugger = {
-								Collapsed = NO;
-								Frame = "{{0, 0}, {781, 452}}";
-								Split0 = {
-									Frame = "{{0, 24}, {781, 428}}";
-									Split0 = {
-										Frame = "{{0, 0}, {383, 428}}";
-									};
-									Split1 = {
-										DebugVariablesTableConfiguration = (
-											Name,
-											123,
-											Value,
-											85,
-											Summary,
-											155.123,
-										);
-										Frame = "{{392, 0}, {389, 428}}";
-									};
-									SplitCount = 2;
-								};
-								SplitCount = 1;
-								Tab0 = {
-									Frame = "{{0, 0}, {100, 50}}";
-								};
-								Tab1 = {
-									Frame = "{{0, 0}, {100, 50}}";
-								};
-								TabCount = 2;
-								TabsVisible = YES;
-							};
-							Frame = "{{0, 0}, {781, 452}}";
-							LauncherConfigVersion = 7;
-						};
-						Tab2 = {
-							Frame = "{{0, 0}, {685, 215}}";
-							LauncherConfigVersion = 3;
-							Runner = {
-								Frame = "{{0, 0}, {685, 215}}";
-							};
-						};
-						Tab3 = {
-							BuildMessageFrame = "{{0, 0}, {687, 262}}";
-							BuildTranscriptFrame = "{{0, 271}, {687, 2}}";
-							BuildTranscriptFrameExpanded = YES;
-							Frame = "{{0, 0}, {685, 295}}";
-						};
-						Tab4 = {
-							Frame = "{{0, 0}, {612, 295}}";
-						};
-						TabCount = 5;
-						TabsVisible = NO;
-					};
-					SplitCount = 1;
-					Tab0 = {
-						Frame = "{{0, 0}, {300, 533}}";
-						GroupTreeTableConfiguration = (
-							TargetStatusColumn,
-							18,
-							MainColumn,
-							267,
-						);
-					};
-					Tab1 = {
-						ClassesFrame = "{{0, 0}, {280, 398}}";
-						ClassesTreeTableConfiguration = (
-							PBXBookColumnIdentifier,
-							20,
-							PBXClassColumnIdentifier,
-							237,
-						);
-						Frame = "{{0, 0}, {278, 659}}";
-						MembersFrame = "{{0, 407}, {280, 252}}";
-						MembersTreeTableConfiguration = (
-							PBXBookColumnIdentifier,
-							20,
-							PBXMethodColumnIdentifier,
-							236,
-						);
-					};
-					Tab2 = {
-						Frame = "{{0, 0}, {200, 100}}";
-					};
-					Tab3 = {
-						Frame = "{{0, 0}, {200, 100}}";
-						TargetTableConfiguration = (
-							ActiveObject,
-							16,
-							ObjectNames,
-							202.296,
-						);
-					};
-					Tab4 = {
-						BreakpointsTreeTableConfiguration = (
-							breakpointColumn,
-							197,
-							enabledColumn,
-							31,
-						);
-						Frame = "{{0, 0}, {250, 100}}";
-					};
-					TabCount = 5;
-					TabsVisible = NO;
-				};
-				NavBarShownByDefault = YES;
-				StatusViewVisible = YES;
-				Template = F5314676015831810DCA290F;
-				ToolbarVisible = YES;
-				WindowLocation = "{209, 187}";
-			};
-			"PBXTemplateGeometry-F5534CB2020F3F8A0DCA290F" = {
-				ContentSize = "{993, 281}";
-				LeftSlideOut = {
-					Collapsed = NO;
-					Frame = "{{0, 23}, {993, 258}}";
-					Split0 = {
-						ActiveTab = 1;
-						ActiveTabName = PBXRunSessionModule;
-						Collapsed = YES;
-						Frame = "{{0, 0}, {993, 258}}";
-						Split0 = {
-							Frame = "{{1e+06, 1e+06}, {993, 0}}";
-						};
-						SplitCount = 1;
-						Tab0 = {
-							Frame = "{{0, 0}, {804, 321}}";
-						};
-						Tab1 = {
-							Debugger = {
-								Collapsed = NO;
-								Frame = "{{0, 0}, {594, 274}}";
-								Split0 = {
-									Frame = "{{0, 24}, {594, 250}}";
-									Split0 = {
-										Frame = "{{0, 0}, {290, 250}}";
-									};
-									Split1 = {
-										DebugVariablesTableConfiguration = (
-											Name,
-											123,
-											Value,
-											85,
-											Summary,
-											62.123,
-										);
-										Frame = "{{299, 0}, {295, 250}}";
-									};
-									SplitCount = 2;
-								};
-								SplitCount = 1;
-								Tab0 = {
-									Frame = "{{0, 0}, {100, 50}}";
-								};
-								Tab1 = {
-									Frame = "{{0, 0}, {100, 50}}";
-								};
-								TabCount = 2;
-								TabsVisible = YES;
-							};
-							Frame = "{{0, 0}, {594, 274}}";
-							LauncherConfigVersion = 7;
-						};
-						Tab2 = {
-							Frame = "{{0, 0}, {993, 252}}";
-							LauncherConfigVersion = 3;
-							Runner = {
-								Frame = "{{0, 0}, {993, 252}}";
-							};
-						};
-						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}, {300, 533}}";
-						GroupTreeTableConfiguration = (
-							TargetStatusColumn,
-							18,
-							MainColumn,
-							267,
-						);
-					};
-					Tab1 = {
-						ClassesFrame = "{{0, 0}, {280, 398}}";
-						ClassesTreeTableConfiguration = (
-							PBXBookColumnIdentifier,
-							20,
-							PBXClassColumnIdentifier,
-							237,
-						);
-						Frame = "{{0, 0}, {278, 659}}";
-						MembersFrame = "{{0, 407}, {280, 252}}";
-						MembersTreeTableConfiguration = (
-							PBXBookColumnIdentifier,
-							20,
-							PBXMethodColumnIdentifier,
-							236,
-						);
-					};
-					Tab2 = {
-						Frame = "{{0, 0}, {200, 100}}";
-					};
-					Tab3 = {
-						Frame = "{{0, 0}, {200, 386}}";
-						TargetTableConfiguration = (
-							ActiveObject,
-							16,
-							ObjectNames,
-							202.296,
-						);
-					};
-					Tab4 = {
-						BreakpointsTreeTableConfiguration = (
-							breakpointColumn,
-							197,
-							enabledColumn,
-							31,
-						);
-						Frame = "{{0, 0}, {250, 386}}";
-					};
-					TabCount = 5;
-					TabsVisible = NO;
-				};
-				NavBarShownByDefault = YES;
-				StatusViewVisible = YES;
-				Template = F5534CB2020F3F8A0DCA290F;
-				ToolbarVisible = YES;
-				WindowLocation = "{18, 179}";
-			};
+			PBXPerProjectTemplateStateSaveDate = 69196942;
 			PBXWorkspaceContents = (
 				{
@@ -283,5 +28,5 @@
 							Split0 = {
 								NavContent0 = {
-									bookmark = E1F7C65B041C623100FEF34D;
+									bookmark = E14789AB041FCB3800050002;
 									history = (
 										E1D2937B03BD418200F9204E,
@@ -305,8 +50,6 @@
 										E19DCB8203BE4A0A00B934BF,
 										E19DCB8303BE4A0A00B934BF,
-										E19DCC8703BE900300B934BF,
 										E19DCC8903BE900300B934BF,
 										E19DCC8A03BE900300B934BF,
-										E19DCC8E03BE900300B934BF,
 										E19DCC9203BE900300B934BF,
 										E1A9DEEE03BF480F0089E8B2,
@@ -317,8 +60,6 @@
 										E11CD2D203BF9B3300C49BEF,
 										E11CD2D303BF9B3300C49BEF,
-										E11CD2D403BF9B3300C49BEF,
 										E11CD2D603BF9B3300C49BEF,
 										E11CD2D803BF9B3300C49BEF,
-										E11CD2E003BF9B3300C49BEF,
 										E17AED7403C0F5D300B89ACF,
 										E17AED7503C0F5D300B89ACF,
@@ -335,11 +76,6 @@
 										E1FCECFD03C972CF001509F3,
 										E1AFB0DA03C9A59C001509F3,
-										E1AFB0DB03C9A59C001509F3,
-										E1C6414503C9AC4B001509F3,
-										E1C6405F03CF0A7A00050002,
 										E1C6408B03CF1DB600050002,
 										E143438703DB475300050002,
-										E143439503DB479900050002,
-										E120347403EDEBC000000ABE,
 										E17F2F7403FE0DCC00050002,
 										E17F2F7803FE0DCC00050002,
@@ -351,5 +87,4 @@
 										E1DEF13004003A5F00050002,
 										E1DEF13304003A5F00050002,
-										E1DEF13404003A5F00050002,
 										E1DEF13704003A5F00050002,
 										E1DEF13804003A5F00050002,
@@ -367,6 +102,4 @@
 										E1DEF15204003A5F00050002,
 										E1DEF15304003A5F00050002,
-										E1DEF15404003A5F00050002,
-										E1DEF15B04003A5F00050002,
 										E1DEF15D04003A5F00050002,
 										E1DEF15E04003A5F00050002,
@@ -380,5 +113,4 @@
 										E16A0E6904005B0E00050002,
 										E16A0E6A04005B0E00050002,
-										E104866704018CF400050002,
 										E104866D04018CF400050002,
 										E104866F04018CF400050002,
@@ -392,7 +124,5 @@
 										E1B46F5904053C4F00050002,
 										E1B46F5B04053C4F00050002,
-										E1B46F5C04053C4F00050002,
 										E1B46F5D04053C4F00050002,
-										E1B46F5E04053C4F00050002,
 										E1B46F6004053C4F00050002,
 										E1B46F6104053C4F00050002,
@@ -426,5 +156,4 @@
 										E1A6017A040C8C6B00050002,
 										E1A6017B040C8C6B00050002,
-										E1669BB70412965E00050002,
 										E1669BBD0412965E00050002,
 										E15E6A6104188ABA00050002,
@@ -434,5 +163,4 @@
 										E120D663041952EF00050002,
 										E120D664041952EF00050002,
-										E120D665041952EF00050002,
 										E120D669041952EF00050002,
 										E1F7C5E7041B3C6E00FEF34D,
@@ -441,22 +169,63 @@
 										E1F7C5EC041B3C6E00FEF34D,
 										E1F7C5EE041B3C6E00FEF34D,
-										E1F7C61A041C5B0000FEF34D,
 										E1F7C61B041C5B0000FEF34D,
 										E1F7C61C041C5B0000FEF34D,
 										E1F7C61D041C5B0000FEF34D,
 										E1F7C61E041C5B0000FEF34D,
-										E1F7C61F041C5B0000FEF34D,
 										E1F7C620041C5B0000FEF34D,
-										E1F7C621041C5B0000FEF34D,
 										E1F7C622041C5B0000FEF34D,
 										E1F7C623041C5B0000FEF34D,
 										E1F7C624041C5B0000FEF34D,
 										E1F7C625041C5B0000FEF34D,
-										E1F7C626041C5B0000FEF34D,
 										E1F7C627041C5B0000FEF34D,
-										E1F7C655041C623100FEF34D,
 										E1F7C656041C623100FEF34D,
-										E1F7C657041C623100FEF34D,
-										E16A0E6604005B0E00050002,
+										E14A56F104E785DC00050002,
+										E14A56F304E785DC00050002,
+										E14A56F404E785DC00050002,
+										E14A56F504E785DC00050002,
+										E14A56F604E785DC00050002,
+										E14A56F704E785DC00050002,
+										E14A56F904E785DC00050002,
+										E14A56FA04E785DC00050002,
+										E14A56FC04E785DC00050002,
+										E14A56FD04E785DC00050002,
+										E1DC3E39041F2CF600050002,
+										E1DC3E3B041F2CF600050002,
+										E14788F9041FC51900050002,
+										E14788FA041FC51900050002,
+										E14788FB041FC51900050002,
+										E14788FC041FC51900050002,
+										E14788FD041FC51900050002,
+										E14788FE041FC51900050002,
+										E14788FF041FC51900050002,
+										E1478900041FC51900050002,
+										E1478901041FC51900050002,
+										E1478902041FC51900050002,
+										E1478903041FC51900050002,
+										E1478904041FC51900050002,
+										E1478905041FC51900050002,
+										E1478906041FC51900050002,
+										E1478907041FC51900050002,
+										E1478908041FC51900050002,
+										E1478909041FC51900050002,
+										E147890A041FC51900050002,
+										E147890B041FC51900050002,
+										E147890C041FC51900050002,
+										E147890D041FC51900050002,
+										E147890E041FC51900050002,
+										E147890F041FC51900050002,
+										E1478910041FC51900050002,
+										E1478911041FC51900050002,
+										E1478912041FC51900050002,
+										E1478913041FC51900050002,
+										E1478914041FC51900050002,
+										E1478915041FC51900050002,
+										E1478916041FC51900050002,
+										E1478917041FC51900050002,
+										E1478918041FC51900050002,
+										E1478919041FC51900050002,
+										E14789A7041FCB3800050002,
+										E14789A8041FCB3800050002,
+										E1F7C61F041C5B0000FEF34D,
 									);
 									prevStack = (
@@ -1599,4 +1368,140 @@
 										E1F7C659041C623100FEF34D,
 										E1F7C65A041C623100FEF34D,
+										E14A56FF04E785DC00050002,
+										E14A570004E785DC00050002,
+										E14A570104E785DC00050002,
+										E14A570204E785DC00050002,
+										E14A570304E785DC00050002,
+										E14A570404E785DC00050002,
+										E14A570604E785DC00050002,
+										E14A570804E785DC00050002,
+										E14A570A04E785DC00050002,
+										E14A570B04E785DC00050002,
+										E14A570C04E785DC00050002,
+										E14A570D04E785DC00050002,
+										E14A570E04E785DC00050002,
+										E14A570F04E785DC00050002,
+										E14A571004E785DC00050002,
+										E14A571104E785DC00050002,
+										E14A571204E785DC00050002,
+										E1DC3E3E041F2CF600050002,
+										E1DC3E3F041F2CF600050002,
+										E1DC3E40041F2CF600050002,
+										E1DC3E41041F2CF600050002,
+										E1DC3E42041F2CF600050002,
+										E1DC3E43041F2CF600050002,
+										E1DC3E44041F2CF600050002,
+										E1DC3E45041F2CF600050002,
+										E147891B041FC51900050002,
+										E147891C041FC51900050002,
+										E147891D041FC51900050002,
+										E147891E041FC51900050002,
+										E147891F041FC51900050002,
+										E1478920041FC51900050002,
+										E1478921041FC51900050002,
+										E1478922041FC51900050002,
+										E1478923041FC51900050002,
+										E1478924041FC51900050002,
+										E1478925041FC51900050002,
+										E1478926041FC51900050002,
+										E1478927041FC51900050002,
+										E1478928041FC51900050002,
+										E1478929041FC51900050002,
+										E147892A041FC51900050002,
+										E147892B041FC51900050002,
+										E147892C041FC51900050002,
+										E147892D041FC51900050002,
+										E147892E041FC51900050002,
+										E147892F041FC51900050002,
+										E1478930041FC51900050002,
+										E1478931041FC51900050002,
+										E1478932041FC51900050002,
+										E1478933041FC51900050002,
+										E1478934041FC51900050002,
+										E1478935041FC51900050002,
+										E1478936041FC51900050002,
+										E1478937041FC51900050002,
+										E1478938041FC51900050002,
+										E1478939041FC51900050002,
+										E147893A041FC51900050002,
+										E147893B041FC51900050002,
+										E147893C041FC51900050002,
+										E147893D041FC51900050002,
+										E147893E041FC51900050002,
+										E147893F041FC51900050002,
+										E1478940041FC51900050002,
+										E1478941041FC51900050002,
+										E1478942041FC51900050002,
+										E1478943041FC51900050002,
+										E1478944041FC51900050002,
+										E1478945041FC51900050002,
+										E1478946041FC51900050002,
+										E1478947041FC51900050002,
+										E1478948041FC51900050002,
+										E1478949041FC51900050002,
+										E147894A041FC51900050002,
+										E147894B041FC51900050002,
+										E147894C041FC51900050002,
+										E147894D041FC51900050002,
+										E147894E041FC51900050002,
+										E147894F041FC51900050002,
+										E1478950041FC51900050002,
+										E1478951041FC51900050002,
+										E1478952041FC51900050002,
+										E1478953041FC51900050002,
+										E1478954041FC51900050002,
+										E1478955041FC51900050002,
+										E1478956041FC51900050002,
+										E1478957041FC51900050002,
+										E1478958041FC51900050002,
+										E1478959041FC51900050002,
+										E147895A041FC51900050002,
+										E147895B041FC51900050002,
+										E147895C041FC51900050002,
+										E147895D041FC51900050002,
+										E147895E041FC51900050002,
+										E147895F041FC51900050002,
+										E1478960041FC51900050002,
+										E1478961041FC51900050002,
+										E1478962041FC51900050002,
+										E1478963041FC51900050002,
+										E1478964041FC51900050002,
+										E1478965041FC51900050002,
+										E1478966041FC51900050002,
+										E1478967041FC51900050002,
+										E1478968041FC51900050002,
+										E1478969041FC51900050002,
+										E147896A041FC51900050002,
+										E147896B041FC51900050002,
+										E147896C041FC51900050002,
+										E147896D041FC51900050002,
+										E147896E041FC51900050002,
+										E147896F041FC51900050002,
+										E1478970041FC51900050002,
+										E1478971041FC51900050002,
+										E1478972041FC51900050002,
+										E1478973041FC51900050002,
+										E1478974041FC51900050002,
+										E1478975041FC51900050002,
+										E1478976041FC51900050002,
+										E1478977041FC51900050002,
+										E1478978041FC51900050002,
+										E1478979041FC51900050002,
+										E147897A041FC51900050002,
+										E147897B041FC51900050002,
+										E147897C041FC51900050002,
+										E147897D041FC51900050002,
+										E147897E041FC51900050002,
+										E147897F041FC51900050002,
+										E1478980041FC51900050002,
+										E1478981041FC51900050002,
+										E1478982041FC51900050002,
+										E1478983041FC51900050002,
+										E1478984041FC51900050002,
+										E1478985041FC51900050002,
+										E1478986041FC51900050002,
+										E1478987041FC51900050002,
+										E14789A9041FCB3800050002,
+										E14789AA041FCB3800050002,
 									);
 								};
@@ -1639,5 +1544,89 @@
 								NavCount = 1;
 								NavGeometry0 = {
+									Frame = "{{0, 0}, {594, 150}}";
+									NavBarVisible = YES;
+								};
+								NavSplitVertical = NO;
+							};
+							SplitCount = 1;
+							Tab1 = {
+								Debugger = {
+									Split0 = {
+										SplitCount = 2;
+									};
+									SplitCount = 1;
+									TabCount = 2;
+								};
+								LauncherConfigVersion = 7;
+							};
+							Tab2 = {
+								LauncherConfigVersion = 3;
+								Runner = {
+								};
+							};
+							TabCount = 5;
+						};
+						SplitCount = 1;
+						Tab1 = {
+							OptionsSetName = "Hierarchy, all classes";
+						};
+						TabCount = 5;
+					};
+				},
+				{
+					LeftSlideOut = {
+						Split0 = {
+							Split0 = {
+								NavContent0 = {
+									bookmark = E14789AC041FCB3800050002;
+									history = (
+										E147898D041FC51900050002,
+									);
+								};
+								NavCount = 1;
+								NavGeometry0 = {
 									Frame = "{{0, 0}, {685, 150}}";
+									NavBarVisible = YES;
+								};
+								NavSplitVertical = NO;
+							};
+							SplitCount = 1;
+							Tab1 = {
+								Debugger = {
+									Split0 = {
+										SplitCount = 2;
+									};
+									SplitCount = 1;
+									TabCount = 2;
+								};
+								LauncherConfigVersion = 7;
+							};
+							Tab2 = {
+								LauncherConfigVersion = 3;
+								Runner = {
+								};
+							};
+							TabCount = 5;
+						};
+						SplitCount = 1;
+						Tab1 = {
+							OptionsSetName = "Hierarchy, all classes";
+						};
+						TabCount = 5;
+					};
+				},
+				{
+					LeftSlideOut = {
+						Split0 = {
+							Split0 = {
+								NavContent0 = {
+									bookmark = E14789AD041FCB3800050002;
+									history = (
+										E147898F041FC51900050002,
+									);
+								};
+								NavCount = 1;
+								NavGeometry0 = {
+									Frame = "{{0, 0}, {668, 621}}";
 									NavBarVisible = YES;
 								};
@@ -1770,8 +1759,8 @@
 						};
 						Tab2 = {
-							Frame = "{{0, 0}, {217, 554}}";
+							Frame = "{{0, 0}, {217, 562}}";
 						};
 						Tab3 = {
-							Frame = "{{0, 0}, {239, 554}}";
+							Frame = "{{0, 0}, {239, 562}}";
 							TargetTableConfiguration = (
 								ActiveObject,
@@ -1797,5 +1786,133 @@
 					Template = 64ABBB4501FA494900185B06;
 					ToolbarVisible = YES;
-					WindowLocation = "{5, 185}";
+					WindowLocation = "{-1, 181}";
+				},
+				{
+					ContentSize = "{594, 303}";
+					LeftSlideOut = {
+						Collapsed = NO;
+						Frame = "{{0, 23}, {594, 280}}";
+						Split0 = {
+							ActiveTab = 1;
+							ActiveTabName = PBXRunSessionModule;
+							Collapsed = YES;
+							Frame = "{{0, 0}, {594, 280}}";
+							Split0 = {
+								Frame = "{{1e+06, 1e+06}, {594, 0}}";
+							};
+							SplitCount = 1;
+							Tab0 = {
+								Frame = "{{0, 0}, {804, 321}}";
+							};
+							Tab1 = {
+								Debugger = {
+									Collapsed = NO;
+									Frame = "{{0, 0}, {594, 274}}";
+									Split0 = {
+										Frame = "{{0, 24}, {594, 250}}";
+										Split0 = {
+											Frame = "{{0, 0}, {290, 250}}";
+										};
+										Split1 = {
+											DebugVariablesTableConfiguration = (
+												Name,
+												123,
+												Value,
+												85,
+												Summary,
+												62.123,
+											);
+											Frame = "{{299, 0}, {295, 250}}";
+										};
+										SplitCount = 2;
+									};
+									SplitCount = 1;
+									Tab0 = {
+										Frame = "{{0, 0}, {100, 50}}";
+									};
+									Tab1 = {
+										Frame = "{{0, 0}, {100, 50}}";
+									};
+									TabCount = 2;
+									TabsVisible = YES;
+								};
+								Frame = "{{0, 0}, {594, 274}}";
+								LauncherConfigVersion = 7;
+							};
+							Tab2 = {
+								Frame = "{{0, 0}, {594, 274}}";
+								LauncherConfigVersion = 3;
+								Runner = {
+									Frame = "{{0, 0}, {594, 274}}";
+								};
+							};
+							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}, {300, 533}}";
+							GroupTreeTableConfiguration = (
+								TargetStatusColumn,
+								18,
+								MainColumn,
+								267,
+							);
+						};
+						Tab1 = {
+							ClassesFrame = "{{0, 0}, {280, 398}}";
+							ClassesTreeTableConfiguration = (
+								PBXBookColumnIdentifier,
+								20,
+								PBXClassColumnIdentifier,
+								237,
+							);
+							Frame = "{{0, 0}, {278, 659}}";
+							MembersFrame = "{{0, 407}, {280, 252}}";
+							MembersTreeTableConfiguration = (
+								PBXBookColumnIdentifier,
+								20,
+								PBXMethodColumnIdentifier,
+								236,
+							);
+						};
+						Tab2 = {
+							Frame = "{{0, 0}, {200, 100}}";
+						};
+						Tab3 = {
+							Frame = "{{0, 0}, {200, 386}}";
+							TargetTableConfiguration = (
+								ActiveObject,
+								16,
+								ObjectNames,
+								202.296,
+							);
+						};
+						Tab4 = {
+							BreakpointsTreeTableConfiguration = (
+								breakpointColumn,
+								197,
+								enabledColumn,
+								31,
+							);
+							Frame = "{{0, 0}, {250, 386}}";
+						};
+						TabCount = 5;
+						TabsVisible = NO;
+					};
+					NavBarShownByDefault = YES;
+					StatusViewVisible = YES;
+					Template = F5534CB2020F3F8A0DCA290F;
+					ToolbarVisible = YES;
+					WindowLocation = "{117, 67}";
 				},
 				{
@@ -1810,5 +1927,5 @@
 							Frame = "{{0, 0}, {685, 411}}";
 							Split0 = {
-								Frame = "{{0, 301}, {685, 110}}";
+								Frame = "{{0, 273}, {685, 138}}";
 							};
 							SplitCount = 1;
@@ -1859,8 +1976,8 @@
 							};
 							Tab3 = {
-								BuildMessageFrame = "{{0, 0}, {687, 262}}";
-								BuildTranscriptFrame = "{{0, 271}, {687, 2}}";
+								BuildMessageFrame = "{{0, 0}, {687, 236}}";
+								BuildTranscriptFrame = "{{0, 245}, {687, 0}}";
 								BuildTranscriptFrameExpanded = YES;
-								Frame = "{{0, 0}, {685, 295}}";
+								Frame = "{{0, 0}, {685, 267}}";
 							};
 							Tab4 = {
@@ -1925,11 +2042,136 @@
 					Template = F5314676015831810DCA290F;
 					ToolbarVisible = YES;
-					WindowLocation = "{209, 187}";
+					WindowLocation = "{353, 75}";
+				},
+				{
+					ContentSize = "{668, 621}";
+					LeftSlideOut = {
+						Collapsed = NO;
+						Frame = "{{0, 0}, {668, 621}}";
+						Split0 = {
+							Collapsed = NO;
+							Frame = "{{0, 0}, {668, 621}}";
+							Split0 = {
+								Frame = "{{0, 0}, {668, 621}}";
+							};
+							SplitCount = 1;
+							Tab0 = {
+								Frame = "{{0, 0}, {484, 208}}";
+							};
+							Tab1 = {
+								Debugger = {
+									Collapsed = NO;
+									Frame = "{{0, 0}, {664, 208}}";
+									Split0 = {
+										Frame = "{{0, 24}, {664, 184}}";
+										Split0 = {
+											Frame = "{{0, 0}, {325, 184}}";
+										};
+										Split1 = {
+											DebugVariablesTableConfiguration = (
+												Name,
+												123,
+												Value,
+												85,
+												Summary,
+												96.123,
+											);
+											Frame = "{{334, 0}, {330, 184}}";
+										};
+										SplitCount = 2;
+									};
+									SplitCount = 1;
+									Tab0 = {
+										Frame = "{{0, 0}, {100, 50}}";
+									};
+									Tab1 = {
+										Frame = "{{0, 0}, {100, 50}}";
+									};
+									TabCount = 2;
+									TabsVisible = YES;
+								};
+								Frame = "{{0, 0}, {664, 208}}";
+								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 = NO;
+					};
+					NavBarShownByDefault = YES;
+					StatusViewVisible = NO;
+					Template = F5CA7ECB015C094F0DCA290F;
+					ToolbarVisible = NO;
+					WindowLocation = "{23, 90}";
 				},
 			);
-			PBXWorkspaceStateSaveDate = 68968119;
+			PBXWorkspaceStateSaveDate = 69196942;
 		};
 		perUserProjectItems = {
-			E104866704018CF400050002 = E104866704018CF400050002;
 			E104866D04018CF400050002 = E104866D04018CF400050002;
 			E104866F04018CF400050002 = E104866F04018CF400050002;
@@ -1964,8 +2206,6 @@
 			E11CD2D203BF9B3300C49BEF = E11CD2D203BF9B3300C49BEF;
 			E11CD2D303BF9B3300C49BEF = E11CD2D303BF9B3300C49BEF;
-			E11CD2D403BF9B3300C49BEF = E11CD2D403BF9B3300C49BEF;
 			E11CD2D603BF9B3300C49BEF = E11CD2D603BF9B3300C49BEF;
 			E11CD2D803BF9B3300C49BEF = E11CD2D803BF9B3300C49BEF;
-			E11CD2E003BF9B3300C49BEF = E11CD2E003BF9B3300C49BEF;
 			E11CD2E303BF9B3300C49BEF = E11CD2E303BF9B3300C49BEF;
 			E11CD2E503BF9B3300C49BEF = E11CD2E503BF9B3300C49BEF;
@@ -1978,10 +2218,8 @@
 			E11CD2ED03BF9B3300C49BEF = E11CD2ED03BF9B3300C49BEF;
 			E11CD2EF03BF9B3300C49BEF = E11CD2EF03BF9B3300C49BEF;
-			E120347403EDEBC000000ABE = E120347403EDEBC000000ABE;
 			E120347603EDEBC000000ABE = E120347603EDEBC000000ABE;
 			E120347703EDEBC000000ABE = E120347703EDEBC000000ABE;
 			E120D663041952EF00050002 = E120D663041952EF00050002;
 			E120D664041952EF00050002 = E120D664041952EF00050002;
-			E120D665041952EF00050002 = E120D665041952EF00050002;
 			E120D669041952EF00050002 = E120D669041952EF00050002;
 			E120D66B041952EF00050002 = E120D66B041952EF00050002;
@@ -2003,9 +2241,186 @@
 			E143438703DB475300050002 = E143438703DB475300050002;
 			E143438903DB475300050002 = E143438903DB475300050002;
-			E143439503DB479900050002 = E143439503DB479900050002;
 			E143439603DB479900050002 = E143439603DB479900050002;
 			E14343C203DB52FA00050002 = E14343C203DB52FA00050002;
 			E14343C303DB52FA00050002 = E14343C303DB52FA00050002;
 			E14343C403DB52FA00050002 = E14343C403DB52FA00050002;
+			E14788F9041FC51900050002 = E14788F9041FC51900050002;
+			E14788FA041FC51900050002 = E14788FA041FC51900050002;
+			E14788FB041FC51900050002 = E14788FB041FC51900050002;
+			E14788FC041FC51900050002 = E14788FC041FC51900050002;
+			E14788FD041FC51900050002 = E14788FD041FC51900050002;
+			E14788FE041FC51900050002 = E14788FE041FC51900050002;
+			E14788FF041FC51900050002 = E14788FF041FC51900050002;
+			E1478900041FC51900050002 = E1478900041FC51900050002;
+			E1478901041FC51900050002 = E1478901041FC51900050002;
+			E1478902041FC51900050002 = E1478902041FC51900050002;
+			E1478903041FC51900050002 = E1478903041FC51900050002;
+			E1478904041FC51900050002 = E1478904041FC51900050002;
+			E1478905041FC51900050002 = E1478905041FC51900050002;
+			E1478906041FC51900050002 = E1478906041FC51900050002;
+			E1478907041FC51900050002 = E1478907041FC51900050002;
+			E1478908041FC51900050002 = E1478908041FC51900050002;
+			E1478909041FC51900050002 = E1478909041FC51900050002;
+			E147890A041FC51900050002 = E147890A041FC51900050002;
+			E147890B041FC51900050002 = E147890B041FC51900050002;
+			E147890C041FC51900050002 = E147890C041FC51900050002;
+			E147890D041FC51900050002 = E147890D041FC51900050002;
+			E147890E041FC51900050002 = E147890E041FC51900050002;
+			E147890F041FC51900050002 = E147890F041FC51900050002;
+			E1478910041FC51900050002 = E1478910041FC51900050002;
+			E1478911041FC51900050002 = E1478911041FC51900050002;
+			E1478912041FC51900050002 = E1478912041FC51900050002;
+			E1478913041FC51900050002 = E1478913041FC51900050002;
+			E1478914041FC51900050002 = E1478914041FC51900050002;
+			E1478915041FC51900050002 = E1478915041FC51900050002;
+			E1478916041FC51900050002 = E1478916041FC51900050002;
+			E1478917041FC51900050002 = E1478917041FC51900050002;
+			E1478918041FC51900050002 = E1478918041FC51900050002;
+			E1478919041FC51900050002 = E1478919041FC51900050002;
+			E147891B041FC51900050002 = E147891B041FC51900050002;
+			E147891C041FC51900050002 = E147891C041FC51900050002;
+			E147891D041FC51900050002 = E147891D041FC51900050002;
+			E147891E041FC51900050002 = E147891E041FC51900050002;
+			E147891F041FC51900050002 = E147891F041FC51900050002;
+			E1478920041FC51900050002 = E1478920041FC51900050002;
+			E1478921041FC51900050002 = E1478921041FC51900050002;
+			E1478922041FC51900050002 = E1478922041FC51900050002;
+			E1478923041FC51900050002 = E1478923041FC51900050002;
+			E1478924041FC51900050002 = E1478924041FC51900050002;
+			E1478925041FC51900050002 = E1478925041FC51900050002;
+			E1478926041FC51900050002 = E1478926041FC51900050002;
+			E1478927041FC51900050002 = E1478927041FC51900050002;
+			E1478928041FC51900050002 = E1478928041FC51900050002;
+			E1478929041FC51900050002 = E1478929041FC51900050002;
+			E147892A041FC51900050002 = E147892A041FC51900050002;
+			E147892B041FC51900050002 = E147892B041FC51900050002;
+			E147892C041FC51900050002 = E147892C041FC51900050002;
+			E147892D041FC51900050002 = E147892D041FC51900050002;
+			E147892E041FC51900050002 = E147892E041FC51900050002;
+			E147892F041FC51900050002 = E147892F041FC51900050002;
+			E1478930041FC51900050002 = E1478930041FC51900050002;
+			E1478931041FC51900050002 = E1478931041FC51900050002;
+			E1478932041FC51900050002 = E1478932041FC51900050002;
+			E1478933041FC51900050002 = E1478933041FC51900050002;
+			E1478934041FC51900050002 = E1478934041FC51900050002;
+			E1478935041FC51900050002 = E1478935041FC51900050002;
+			E1478936041FC51900050002 = E1478936041FC51900050002;
+			E1478937041FC51900050002 = E1478937041FC51900050002;
+			E1478938041FC51900050002 = E1478938041FC51900050002;
+			E1478939041FC51900050002 = E1478939041FC51900050002;
+			E147893A041FC51900050002 = E147893A041FC51900050002;
+			E147893B041FC51900050002 = E147893B041FC51900050002;
+			E147893C041FC51900050002 = E147893C041FC51900050002;
+			E147893D041FC51900050002 = E147893D041FC51900050002;
+			E147893E041FC51900050002 = E147893E041FC51900050002;
+			E147893F041FC51900050002 = E147893F041FC51900050002;
+			E1478940041FC51900050002 = E1478940041FC51900050002;
+			E1478941041FC51900050002 = E1478941041FC51900050002;
+			E1478942041FC51900050002 = E1478942041FC51900050002;
+			E1478943041FC51900050002 = E1478943041FC51900050002;
+			E1478944041FC51900050002 = E1478944041FC51900050002;
+			E1478945041FC51900050002 = E1478945041FC51900050002;
+			E1478946041FC51900050002 = E1478946041FC51900050002;
+			E1478947041FC51900050002 = E1478947041FC51900050002;
+			E1478948041FC51900050002 = E1478948041FC51900050002;
+			E1478949041FC51900050002 = E1478949041FC51900050002;
+			E147894A041FC51900050002 = E147894A041FC51900050002;
+			E147894B041FC51900050002 = E147894B041FC51900050002;
+			E147894C041FC51900050002 = E147894C041FC51900050002;
+			E147894D041FC51900050002 = E147894D041FC51900050002;
+			E147894E041FC51900050002 = E147894E041FC51900050002;
+			E147894F041FC51900050002 = E147894F041FC51900050002;
+			E1478950041FC51900050002 = E1478950041FC51900050002;
+			E1478951041FC51900050002 = E1478951041FC51900050002;
+			E1478952041FC51900050002 = E1478952041FC51900050002;
+			E1478953041FC51900050002 = E1478953041FC51900050002;
+			E1478954041FC51900050002 = E1478954041FC51900050002;
+			E1478955041FC51900050002 = E1478955041FC51900050002;
+			E1478956041FC51900050002 = E1478956041FC51900050002;
+			E1478957041FC51900050002 = E1478957041FC51900050002;
+			E1478958041FC51900050002 = E1478958041FC51900050002;
+			E1478959041FC51900050002 = E1478959041FC51900050002;
+			E147895A041FC51900050002 = E147895A041FC51900050002;
+			E147895B041FC51900050002 = E147895B041FC51900050002;
+			E147895C041FC51900050002 = E147895C041FC51900050002;
+			E147895D041FC51900050002 = E147895D041FC51900050002;
+			E147895E041FC51900050002 = E147895E041FC51900050002;
+			E147895F041FC51900050002 = E147895F041FC51900050002;
+			E1478960041FC51900050002 = E1478960041FC51900050002;
+			E1478961041FC51900050002 = E1478961041FC51900050002;
+			E1478962041FC51900050002 = E1478962041FC51900050002;
+			E1478963041FC51900050002 = E1478963041FC51900050002;
+			E1478964041FC51900050002 = E1478964041FC51900050002;
+			E1478965041FC51900050002 = E1478965041FC51900050002;
+			E1478966041FC51900050002 = E1478966041FC51900050002;
+			E1478967041FC51900050002 = E1478967041FC51900050002;
+			E1478968041FC51900050002 = E1478968041FC51900050002;
+			E1478969041FC51900050002 = E1478969041FC51900050002;
+			E147896A041FC51900050002 = E147896A041FC51900050002;
+			E147896B041FC51900050002 = E147896B041FC51900050002;
+			E147896C041FC51900050002 = E147896C041FC51900050002;
+			E147896D041FC51900050002 = E147896D041FC51900050002;
+			E147896E041FC51900050002 = E147896E041FC51900050002;
+			E147896F041FC51900050002 = E147896F041FC51900050002;
+			E1478970041FC51900050002 = E1478970041FC51900050002;
+			E1478971041FC51900050002 = E1478971041FC51900050002;
+			E1478972041FC51900050002 = E1478972041FC51900050002;
+			E1478973041FC51900050002 = E1478973041FC51900050002;
+			E1478974041FC51900050002 = E1478974041FC51900050002;
+			E1478975041FC51900050002 = E1478975041FC51900050002;
+			E1478976041FC51900050002 = E1478976041FC51900050002;
+			E1478977041FC51900050002 = E1478977041FC51900050002;
+			E1478978041FC51900050002 = E1478978041FC51900050002;
+			E1478979041FC51900050002 = E1478979041FC51900050002;
+			E147897A041FC51900050002 = E147897A041FC51900050002;
+			E147897B041FC51900050002 = E147897B041FC51900050002;
+			E147897C041FC51900050002 = E147897C041FC51900050002;
+			E147897D041FC51900050002 = E147897D041FC51900050002;
+			E147897E041FC51900050002 = E147897E041FC51900050002;
+			E147897F041FC51900050002 = E147897F041FC51900050002;
+			E1478980041FC51900050002 = E1478980041FC51900050002;
+			E1478981041FC51900050002 = E1478981041FC51900050002;
+			E1478982041FC51900050002 = E1478982041FC51900050002;
+			E1478983041FC51900050002 = E1478983041FC51900050002;
+			E1478984041FC51900050002 = E1478984041FC51900050002;
+			E1478985041FC51900050002 = E1478985041FC51900050002;
+			E1478986041FC51900050002 = E1478986041FC51900050002;
+			E1478987041FC51900050002 = E1478987041FC51900050002;
+			E147898D041FC51900050002 = E147898D041FC51900050002;
+			E147898F041FC51900050002 = E147898F041FC51900050002;
+			E14789A7041FCB3800050002 = E14789A7041FCB3800050002;
+			E14789A8041FCB3800050002 = E14789A8041FCB3800050002;
+			E14789A9041FCB3800050002 = E14789A9041FCB3800050002;
+			E14789AA041FCB3800050002 = E14789AA041FCB3800050002;
+			E14789AB041FCB3800050002 = E14789AB041FCB3800050002;
+			E14789AC041FCB3800050002 = E14789AC041FCB3800050002;
+			E14789AD041FCB3800050002 = E14789AD041FCB3800050002;
+			E14A56F104E785DC00050002 = E14A56F104E785DC00050002;
+			E14A56F304E785DC00050002 = E14A56F304E785DC00050002;
+			E14A56F404E785DC00050002 = E14A56F404E785DC00050002;
+			E14A56F504E785DC00050002 = E14A56F504E785DC00050002;
+			E14A56F604E785DC00050002 = E14A56F604E785DC00050002;
+			E14A56F704E785DC00050002 = E14A56F704E785DC00050002;
+			E14A56F904E785DC00050002 = E14A56F904E785DC00050002;
+			E14A56FA04E785DC00050002 = E14A56FA04E785DC00050002;
+			E14A56FC04E785DC00050002 = E14A56FC04E785DC00050002;
+			E14A56FD04E785DC00050002 = E14A56FD04E785DC00050002;
+			E14A56FF04E785DC00050002 = E14A56FF04E785DC00050002;
+			E14A570004E785DC00050002 = E14A570004E785DC00050002;
+			E14A570104E785DC00050002 = E14A570104E785DC00050002;
+			E14A570204E785DC00050002 = E14A570204E785DC00050002;
+			E14A570304E785DC00050002 = E14A570304E785DC00050002;
+			E14A570404E785DC00050002 = E14A570404E785DC00050002;
+			E14A570604E785DC00050002 = E14A570604E785DC00050002;
+			E14A570804E785DC00050002 = E14A570804E785DC00050002;
+			E14A570A04E785DC00050002 = E14A570A04E785DC00050002;
+			E14A570B04E785DC00050002 = E14A570B04E785DC00050002;
+			E14A570C04E785DC00050002 = E14A570C04E785DC00050002;
+			E14A570D04E785DC00050002 = E14A570D04E785DC00050002;
+			E14A570E04E785DC00050002 = E14A570E04E785DC00050002;
+			E14A570F04E785DC00050002 = E14A570F04E785DC00050002;
+			E14A571004E785DC00050002 = E14A571004E785DC00050002;
+			E14A571104E785DC00050002 = E14A571104E785DC00050002;
+			E14A571204E785DC00050002 = E14A571204E785DC00050002;
 			E157230C04009B8300050002 = E157230C04009B8300050002;
 			E157230D04009B8300050002 = E157230D04009B8300050002;
@@ -2021,5 +2436,4 @@
 			E15E6A6C04188ABA00050002 = E15E6A6C04188ABA00050002;
 			E15E6A6D04188ABA00050002 = E15E6A6D04188ABA00050002;
-			E1669BB70412965E00050002 = E1669BB70412965E00050002;
 			E1669BBD0412965E00050002 = E1669BBD0412965E00050002;
 			E1669BC20412965E00050002 = E1669BC20412965E00050002;
@@ -2047,5 +2461,4 @@
 			E16A0E6204005B0E00050002 = E16A0E6204005B0E00050002;
 			E16A0E6504005B0E00050002 = E16A0E6504005B0E00050002;
-			E16A0E6604005B0E00050002 = E16A0E6604005B0E00050002;
 			E16A0E6704005B0E00050002 = E16A0E6704005B0E00050002;
 			E16A0E6904005B0E00050002 = E16A0E6904005B0E00050002;
@@ -2293,8 +2706,6 @@
 			E19DCBBC03BE4A0A00B934BF = E19DCBBC03BE4A0A00B934BF;
 			E19DCBBD03BE4A0A00B934BF = E19DCBBD03BE4A0A00B934BF;
-			E19DCC8703BE900300B934BF = E19DCC8703BE900300B934BF;
 			E19DCC8903BE900300B934BF = E19DCC8903BE900300B934BF;
 			E19DCC8A03BE900300B934BF = E19DCC8A03BE900300B934BF;
-			E19DCC8E03BE900300B934BF = E19DCC8E03BE900300B934BF;
 			E19DCC9203BE900300B934BF = E19DCC9203BE900300B934BF;
 			E19DCCA203BE900300B934BF = E19DCCA203BE900300B934BF;
@@ -2379,5 +2790,4 @@
 			E1A9DF0803BF480F0089E8B2 = E1A9DF0803BF480F0089E8B2;
 			E1AFB0DA03C9A59C001509F3 = E1AFB0DA03C9A59C001509F3;
-			E1AFB0DB03C9A59C001509F3 = E1AFB0DB03C9A59C001509F3;
 			E1AFB0E003C9A59C001509F3 = E1AFB0E003C9A59C001509F3;
 			E1AFB0E103C9A59C001509F3 = E1AFB0E103C9A59C001509F3;
@@ -2431,7 +2841,5 @@
 			E1B46F5904053C4F00050002 = E1B46F5904053C4F00050002;
 			E1B46F5B04053C4F00050002 = E1B46F5B04053C4F00050002;
-			E1B46F5C04053C4F00050002 = E1B46F5C04053C4F00050002;
 			E1B46F5D04053C4F00050002 = E1B46F5D04053C4F00050002;
-			E1B46F5E04053C4F00050002 = E1B46F5E04053C4F00050002;
 			E1B46F6004053C4F00050002 = E1B46F6004053C4F00050002;
 			E1B46F6104053C4F00050002 = E1B46F6104053C4F00050002;
@@ -2651,5 +3059,4 @@
 			E1BF6EDF03C95F4E00050002 = E1BF6EDF03C95F4E00050002;
 			E1BF6EEF03C95F4E00050002 = E1BF6EEF03C95F4E00050002;
-			E1C6405F03CF0A7A00050002 = E1C6405F03CF0A7A00050002;
 			E1C6406303CF0A7A00050002 = E1C6406303CF0A7A00050002;
 			E1C6406403CF0A7A00050002 = E1C6406403CF0A7A00050002;
@@ -2662,5 +3069,4 @@
 			E1C6409503CF1DB600050002 = E1C6409503CF1DB600050002;
 			E1C6409603CF1DB600050002 = E1C6409603CF1DB600050002;
-			E1C6414503C9AC4B001509F3 = E1C6414503C9AC4B001509F3;
 			E1C6414703C9AC4B001509F3 = E1C6414703C9AC4B001509F3;
 			E1C6414803C9AC4B001509F3 = E1C6414803C9AC4B001509F3;
@@ -2768,4 +3174,14 @@
 			E1D2943103BD418200F9204E = E1D2943103BD418200F9204E;
 			E1D2943903BD418200F9204E = E1D2943903BD418200F9204E;
+			E1DC3E39041F2CF600050002 = E1DC3E39041F2CF600050002;
+			E1DC3E3B041F2CF600050002 = E1DC3E3B041F2CF600050002;
+			E1DC3E3E041F2CF600050002 = E1DC3E3E041F2CF600050002;
+			E1DC3E3F041F2CF600050002 = E1DC3E3F041F2CF600050002;
+			E1DC3E40041F2CF600050002 = E1DC3E40041F2CF600050002;
+			E1DC3E41041F2CF600050002 = E1DC3E41041F2CF600050002;
+			E1DC3E42041F2CF600050002 = E1DC3E42041F2CF600050002;
+			E1DC3E43041F2CF600050002 = E1DC3E43041F2CF600050002;
+			E1DC3E44041F2CF600050002 = E1DC3E44041F2CF600050002;
+			E1DC3E45041F2CF600050002 = E1DC3E45041F2CF600050002;
 			E1DEF12A04003A5F00050002 = E1DEF12A04003A5F00050002;
 			E1DEF12B04003A5F00050002 = E1DEF12B04003A5F00050002;
@@ -2775,5 +3191,4 @@
 			E1DEF13004003A5F00050002 = E1DEF13004003A5F00050002;
 			E1DEF13304003A5F00050002 = E1DEF13304003A5F00050002;
-			E1DEF13404003A5F00050002 = E1DEF13404003A5F00050002;
 			E1DEF13704003A5F00050002 = E1DEF13704003A5F00050002;
 			E1DEF13804003A5F00050002 = E1DEF13804003A5F00050002;
@@ -2791,6 +3206,4 @@
 			E1DEF15204003A5F00050002 = E1DEF15204003A5F00050002;
 			E1DEF15304003A5F00050002 = E1DEF15304003A5F00050002;
-			E1DEF15404003A5F00050002 = E1DEF15404003A5F00050002;
-			E1DEF15B04003A5F00050002 = E1DEF15B04003A5F00050002;
 			E1DEF15D04003A5F00050002 = E1DEF15D04003A5F00050002;
 			E1DEF15E04003A5F00050002 = E1DEF15E04003A5F00050002;
@@ -3193,5 +3606,4 @@
 			E1F7C5F4041B3C6E00FEF34D = E1F7C5F4041B3C6E00FEF34D;
 			E1F7C5F5041B3C6E00FEF34D = E1F7C5F5041B3C6E00FEF34D;
-			E1F7C61A041C5B0000FEF34D = E1F7C61A041C5B0000FEF34D;
 			E1F7C61B041C5B0000FEF34D = E1F7C61B041C5B0000FEF34D;
 			E1F7C61C041C5B0000FEF34D = E1F7C61C041C5B0000FEF34D;
@@ -3200,10 +3612,8 @@
 			E1F7C61F041C5B0000FEF34D = E1F7C61F041C5B0000FEF34D;
 			E1F7C620041C5B0000FEF34D = E1F7C620041C5B0000FEF34D;
-			E1F7C621041C5B0000FEF34D = E1F7C621041C5B0000FEF34D;
 			E1F7C622041C5B0000FEF34D = E1F7C622041C5B0000FEF34D;
 			E1F7C623041C5B0000FEF34D = E1F7C623041C5B0000FEF34D;
 			E1F7C624041C5B0000FEF34D = E1F7C624041C5B0000FEF34D;
 			E1F7C625041C5B0000FEF34D = E1F7C625041C5B0000FEF34D;
-			E1F7C626041C5B0000FEF34D = E1F7C626041C5B0000FEF34D;
 			E1F7C627041C5B0000FEF34D = E1F7C627041C5B0000FEF34D;
 			E1F7C629041C5B0000FEF34D = E1F7C629041C5B0000FEF34D;
@@ -3236,11 +3646,8 @@
 			E1F7C644041C5B0000FEF34D = E1F7C644041C5B0000FEF34D;
 			E1F7C645041C5B0000FEF34D = E1F7C645041C5B0000FEF34D;
-			E1F7C655041C623100FEF34D = E1F7C655041C623100FEF34D;
 			E1F7C656041C623100FEF34D = E1F7C656041C623100FEF34D;
-			E1F7C657041C623100FEF34D = E1F7C657041C623100FEF34D;
 			E1F7C658041C623100FEF34D = E1F7C658041C623100FEF34D;
 			E1F7C659041C623100FEF34D = E1F7C659041C623100FEF34D;
 			E1F7C65A041C623100FEF34D = E1F7C65A041C623100FEF34D;
-			E1F7C65B041C623100FEF34D = E1F7C65B041C623100FEF34D;
 			E1FCECFD03C972CF001509F3 = E1FCECFD03C972CF001509F3;
 		};
@@ -3257,14 +3664,4 @@
 		);
 	};
-	E104866704018CF400050002 = {
-		fRef = E104868604018CF400050002;
-		isa = PBXTextBookmark;
-		name = "Files.h: 8270";
-		rLen = 0;
-		rLoc = 274009;
-		rType = 0;
-		vrLen = 825;
-		vrLoc = 273186;
-	};
 	E104866D04018CF400050002 = {
 		fRef = E1DEF116040014EB00050002;
@@ -3496,10 +3893,4 @@
 		vrLen = 1503;
 		vrLoc = 0;
-	};
-	E104868604018CF400050002 = {
-		isa = PBXFileReference;
-		name = Files.h;
-		path = /System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/CarbonCore.framework/Versions/A/Headers/Files.h;
-		refType = 0;
 	};
 	E104868A04018CF500050002 = {
@@ -3616,14 +4007,4 @@
 		vrLoc = 1630;
 	};
-	E11CD2D403BF9B3300C49BEF = {
-		fRef = E11CD31003BF9B3300C49BEF;
-		isa = PBXTextBookmark;
-		name = "NSFileManager.h: 32";
-		rLen = 7;
-		rLoc = 1066;
-		rType = 0;
-		vrLen = 1624;
-		vrLoc = 0;
-	};
 	E11CD2D603BF9B3300C49BEF = {
 		fRef = E1A18CB203B439CF00000028;
@@ -3645,14 +4026,4 @@
 		vrLen = 987;
 		vrLoc = 5329;
-	};
-	E11CD2E003BF9B3300C49BEF = {
-		fRef = E11CD31203BF9B3300C49BEF;
-		isa = PBXTextBookmark;
-		name = "NSException.h: 95";
-		rLen = 60;
-		rLoc = 2920;
-		rType = 0;
-		vrLen = 1659;
-		vrLoc = 2172;
 	};
 	E11CD2E303BF9B3300C49BEF = {
@@ -3774,26 +4145,4 @@
 		refType = 0;
 	};
-	E11CD31003BF9B3300C49BEF = {
-		isa = PBXFileReference;
-		name = NSFileManager.h;
-		path = /System/Library/Frameworks/Foundation.framework/Versions/C/Headers/NSFileManager.h;
-		refType = 0;
-	};
-	E11CD31203BF9B3300C49BEF = {
-		isa = PBXFileReference;
-		name = NSException.h;
-		path = /System/Library/Frameworks/Foundation.framework/Versions/C/Headers/NSException.h;
-		refType = 0;
-	};
-	E120347403EDEBC000000ABE = {
-		fRef = F59E47A7036AAA6D016B311C;
-		isa = PBXTextBookmark;
-		name = "PSAlert.m: 43";
-		rLen = 0;
-		rLoc = 805;
-		rType = 0;
-		vrLen = 912;
-		vrLoc = 0;
-	};
 	E120347603EDEBC000000ABE = {
 		fRef = F59E47A7036AAA6D016B311C;
@@ -3847,14 +4196,4 @@
 		vrLen = 1029;
 		vrLoc = 1222;
-	};
-	E120D665041952EF00050002 = {
-		fRef = F59DC6D40353C9E601AEEDB1;
-		isa = PBXTextBookmark;
-		name = "PSAlarmSetController.m: playSoundChanged:";
-		rLen = 41;
-		rLoc = 14170;
-		rType = 0;
-		vrLen = 1624;
-		vrLoc = 13315;
 	};
 	E120D669041952EF00050002 = {
@@ -4055,4 +4394,6 @@
 			E1B46F4304036DBC00050002,
 			E1B46F4E040374B400050002,
+			E14788F6041F627300050002,
+			E14788F7041F659F00050002,
 		);
 		isa = PBXBookmarkGroup;
@@ -4093,14 +4434,4 @@
 		vrLoc = 0;
 	};
-	E143439503DB479900050002 = {
-		fRef = E19DCBD203BE4AA200B934BF;
-		isa = PBXTextBookmark;
-		name = "Pester_Prefix.h: 8";
-		rLen = 0;
-		rLoc = 143;
-		rType = 0;
-		vrLen = 143;
-		vrLoc = 0;
-	};
 	E143439603DB479900050002 = {
 		fRef = E19DCBD203BE4AA200B934BF;
@@ -4143,4 +4474,1839 @@
 		vrLoc = 0;
 	};
+	E14788F6041F627300050002 = {
+		fRef = E130B9AC03B7C59700000028;
+		isa = PBXTextBookmark;
+		name = "PSPowerManager.h: setWakeInterval:";
+		rLen = 15;
+		rLoc = 492;
+		rType = 0;
+		vrLen = 883;
+		vrLoc = 0;
+	};
+	E14788F7041F659F00050002 = {
+		fRef = E14788F8041F65A900050002;
+		isa = PBXTextBookmark;
+		name = "IOTypes.h: 147";
+		rLen = 11;
+		rLoc = 2956;
+		rType = 0;
+		vrLen = 756;
+		vrLoc = 2752;
+	};
+	E14788F8041F65A900050002 = {
+		isa = PBXFileReference;
+		name = IOTypes.h;
+		path = /System/Library/Frameworks/IOKit.framework/Versions/A/Headers/IOTypes.h;
+		refType = 0;
+	};
+	E14788F9041FC51900050002 = {
+		exec = F59B967103538BE201154278;
+		isa = PBXExecutableBookmark;
+	};
+	E14788FA041FC51900050002 = {
+		exec = E14A56EC041DD6B600050002;
+		isa = PBXExecutableBookmark;
+	};
+	E14788FB041FC51900050002 = {
+		isa = PBXTargetBookmark;
+		trg = E14A56EA041DD6B600050002;
+	};
+	E14788FC041FC51900050002 = {
+		fRef = E14788D9041F2FF600050002;
+		isa = PBXTextBookmark;
+		name = "MoreCFQ.h: 30";
+		rLen = 0;
+		rLoc = 1686;
+		rType = 0;
+		vrLen = 2285;
+		vrLoc = 0;
+	};
+	E14788FD041FC51900050002 = {
+		fRef = E1478990041FC51900050002;
+		isa = PBXTextBookmark;
+		name = "MacErrors.h: 68";
+		rLen = 5;
+		rLoc = 2688;
+		rType = 0;
+		vrLen = 2373;
+		vrLoc = 1316;
+	};
+	E14788FE041FC51900050002 = {
+		fRef = E147899D041FC51A00050002;
+		isa = PBXTextBookmark;
+		name = "NSValue.h: 38";
+		rLen = 19;
+		rLoc = 806;
+		rType = 0;
+		vrLen = 1340;
+		vrLoc = 1246;
+	};
+	E14788FF041FC51900050002 = {
+		fRef = E1478995041FC51900050002;
+		isa = PBXTextBookmark;
+		name = "Files.h: 5429";
+		rLen = 0;
+		rLoc = 183960;
+		rType = 0;
+		vrLen = 1250;
+		vrLoc = 183262;
+	};
+	E1478900041FC51900050002 = {
+		fRef = F59DC6E90353F58B01AEEDB1;
+		isa = PBXTextBookmark;
+		name = "NJRIntegerFilter.h: 1";
+		rLen = 0;
+		rLoc = 0;
+		rType = 0;
+		vrLen = 255;
+		vrLoc = 0;
+	};
+	E1478901041FC51900050002 = {
+		fRef = E1478996041FC51A00050002;
+		isa = PBXTextBookmark;
+		name = "NSDictionary.h: 40";
+		rLen = 18;
+		rLoc = 1242;
+		rType = 0;
+		vrLen = 1716;
+		vrLoc = 450;
+	};
+	E1478902041FC51900050002 = {
+		fRef = E1478998041FC51A00050002;
+		isa = PBXTextBookmark;
+		name = "NSException.h: 56";
+		rLen = 85;
+		rLoc = 1745;
+		rType = 0;
+		vrLen = 1054;
+		vrLoc = 1266;
+	};
+	E1478903041FC51900050002 = {
+		fRef = E1478992041FC51900050002;
+		isa = PBXTextBookmark;
+		name = "NSBundle.h: 85";
+		rLen = 77;
+		rLoc = 2804;
+		rType = 0;
+		vrLen = 1624;
+		vrLoc = 1808;
+	};
+	E1478904041FC51900050002 = {
+		fRef = E1BF6E9103C928D200050002;
+		isa = PBXTextBookmark;
+		name = "PSTimer.m: 227";
+		rLen = 0;
+		rLoc = 6460;
+		rType = 0;
+		vrLen = 1104;
+		vrLoc = 5535;
+	};
+	E1478905041FC51900050002 = {
+		fRef = E1BF6E9003C928D200050002;
+		isa = PBXTextBookmark;
+		name = "PSTimer.h: 30";
+		rLen = 0;
+		rLoc = 987;
+		rType = 0;
+		vrLen = 1049;
+		vrLoc = 249;
+	};
+	E1478906041FC51900050002 = {
+		fRef = E19FD39E03C98645001509F3;
+		isa = PBXTextBookmark;
+		name = "PSWakeAlert.h: 1";
+		rLen = 0;
+		rLoc = 0;
+		rType = 0;
+		vrLen = 215;
+		vrLoc = 0;
+	};
+	E1478907041FC51900050002 = {
+		fRef = F59E47A7036AAA6D016B311C;
+		isa = PBXTextBookmark;
+		name = "PSAlert.m: 43";
+		rLen = 0;
+		rLoc = 805;
+		rType = 0;
+		vrLen = 757;
+		vrLoc = 0;
+	};
+	E1478908041FC51900050002 = {
+		fRef = E19FD39F03C98645001509F3;
+		isa = PBXTextBookmark;
+		name = "PSWakeAlert.m: prepareForAlarm:";
+		rLen = 0;
+		rLoc = 415;
+		rType = 0;
+		vrLen = 727;
+		vrLoc = 0;
+	};
+	E1478909041FC51900050002 = {
+		isa = PBXTargetBookmark;
+		trg = 29B97326FDCFA39411CA2CEA;
+	};
+	E147890A041FC51900050002 = {
+		fRef = E14788D6041F2FF600050002;
+		isa = PBXTextBookmark;
+		name = "MoreUNIX.c: 105";
+		rLen = 13;
+		rLoc = 4015;
+		rType = 0;
+		vrLen = 603;
+		vrLoc = 3752;
+	};
+	E147890B041FC51900050002 = {
+		fRef = E14788DB041F2FF600050002;
+		isa = PBXTextBookmark;
+		name = "MoreSetup.h: 219";
+		rLen = 0;
+		rLoc = 9022;
+		rType = 0;
+		vrLen = 1306;
+		vrLoc = 8845;
+	};
+	E147890C041FC51900050002 = {
+		fRef = E14788D5041F2FF600050002;
+		isa = PBXTextBookmark;
+		name = "MoreCFQ.c: 15";
+		rLen = 0;
+		rLoc = 571;
+		rType = 0;
+		vrLen = 2286;
+		vrLoc = 0;
+	};
+	E147890D041FC51900050002 = {
+		fRef = E1DC3E31041F27DA00050002;
+		isa = PBXTextBookmark;
+		name = "wakein.h: kPesterWakeException";
+		rLen = 0;
+		rLoc = 180;
+		rType = 0;
+		vrLen = 225;
+		vrLoc = 0;
+	};
+	E147890E041FC51900050002 = {
+		fRef = E10E71F4040C335800050002;
+		isa = PBXTextBookmark;
+		name = "English: 115";
+		rLen = 0;
+		rLoc = 6392;
+		rType = 0;
+		vrLen = 2153;
+		vrLoc = 4660;
+	};
+	E147890F041FC51900050002 = {
+		fRef = E14788D7041F2FF600050002;
+		isa = PBXTextBookmark;
+		name = "MoreUNIX.h: OSStatusToEXXX";
+		rLen = 0;
+		rLoc = 3526;
+		rType = 0;
+		vrLen = 937;
+		vrLoc = 2991;
+	};
+	E1478910041FC51900050002 = {
+		fRef = E14788D8041F2FF600050002;
+		isa = PBXTextBookmark;
+		name = "MoreSecurity.c: MoreSecExecuteRequestInHelperTool";
+		rLen = 0;
+		rLoc = 50840;
+		rType = 0;
+		vrLen = 1260;
+		vrLoc = 50405;
+	};
+	E1478911041FC51900050002 = {
+		fRef = E147899A041FC51A00050002;
+		glyphRangeLength = 1796;
+		glyphRangeLocation = 74;
+		isa = PBXDocBookmark;
+		name = "Authorization_Options.html: enum     kAu...";
+	};
+	E1478912041FC51900050002 = {
+		fRef = E1478997041FC51A00050002;
+		isa = PBXTextBookmark;
+		name = "Authorization.h: 88";
+		rLen = 36;
+		rLoc = 4047;
+		rType = 0;
+		vrLen = 1686;
+		vrLoc = 2769;
+	};
+	E1478913041FC51900050002 = {
+		fRef = E130B9AC03B7C59700000028;
+		isa = PBXTextBookmark;
+		name = "PSPowerManager.h: setWakeInterval:";
+		rLen = 15;
+		rLoc = 492;
+		rType = 0;
+		vrLen = 883;
+		vrLoc = 0;
+	};
+	E1478914041FC51900050002 = {
+		fRef = E14788DA041F2FF600050002;
+		isa = PBXTextBookmark;
+		name = "MoreSecurity.h: MoreSecHelperToolCopyAuthRef";
+		rLen = 28;
+		rLoc = 14565;
+		rType = 0;
+		vrLen = 1584;
+		vrLoc = 13416;
+	};
+	E1478915041FC51900050002 = {
+		fRef = E1478991041FC51900050002;
+		glyphRangeLength = 1626;
+		glyphRangeLocation = 71;
+		isa = PBXDocBookmark;
+		name = "Creating_and_n_References.html: Creates a ne...";
+	};
+	E1478916041FC51900050002 = {
+		fRef = E14A56ED041DD82F00050002;
+		isa = PBXTextBookmark;
+		name = "wakein.m: main";
+		rLen = 0;
+		rLoc = 2304;
+		rType = 0;
+		vrLen = 1112;
+		vrLoc = 1260;
+	};
+	E1478917041FC51900050002 = {
+		fRef = E147899B041FC51A00050002;
+		isa = PBXTextBookmark;
+		name = "vm_types.h: 77";
+		rLen = 32;
+		rLoc = 2601;
+		rType = 0;
+		vrLen = 965;
+		vrLoc = 2087;
+	};
+	E1478918041FC51900050002 = {
+		fRef = E1478994041FC51900050002;
+		isa = PBXTextBookmark;
+		name = "port.h: 91";
+		rLen = 9;
+		rLoc = 3209;
+		rType = 0;
+		vrLen = 1419;
+		vrLoc = 2563;
+	};
+	E1478919041FC51900050002 = {
+		fRef = E147899C041FC51A00050002;
+		isa = PBXTextBookmark;
+		name = "IOTypes.h: 147";
+		rLen = 11;
+		rLoc = 2956;
+		rType = 0;
+		vrLen = 756;
+		vrLoc = 2752;
+	};
+	E147891B041FC51900050002 = {
+		fRef = E130B9AD03B7C59700000028;
+		isa = PBXTextBookmark;
+		name = "PSPowerManager.m: pmuReference";
+		rLen = 0;
+		rLoc = 6334;
+		rType = 0;
+		vrLen = 909;
+		vrLoc = 5623;
+	};
+	E147891C041FC51900050002 = {
+		fRef = E1DC3E31041F27DA00050002;
+		isa = PBXTextBookmark;
+		name = "wakein.h: 12";
+		rLen = 0;
+		rLoc = 225;
+		rType = 0;
+		vrLen = 241;
+		vrLoc = 0;
+	};
+	E147891D041FC51900050002 = {
+		fRef = E14A56ED041DD82F00050002;
+		isa = PBXTextBookmark;
+		name = "wakein.m: usage";
+		rLen = 0;
+		rLoc = 2372;
+		rType = 0;
+		vrLen = 833;
+		vrLoc = 0;
+	};
+	E147891E041FC51900050002 = {
+		exec = F59B967103538BE201154278;
+		isa = PBXExecutableBookmark;
+	};
+	E147891F041FC51900050002 = {
+		isa = PBXTargetBookmark;
+		trg = 29B97326FDCFA39411CA2CEA;
+	};
+	E1478920041FC51900050002 = {
+		exec = E14A56EC041DD6B600050002;
+		isa = PBXExecutableBookmark;
+	};
+	E1478921041FC51900050002 = {
+		isa = PBXTargetBookmark;
+		trg = E14A56EA041DD6B600050002;
+	};
+	E1478922041FC51900050002 = {
+		isa = PBXTargetBookmark;
+		trg = 29B97326FDCFA39411CA2CEA;
+	};
+	E1478923041FC51900050002 = {
+		isa = PBXTargetBookmark;
+		trg = E14A56EA041DD6B600050002;
+	};
+	E1478924041FC51900050002 = {
+		fRef = E1DC3E31041F27DA00050002;
+		isa = PBXTextBookmark;
+		name = "wakein.h: 13";
+		rLen = 0;
+		rLoc = 225;
+		rType = 0;
+		vrLen = 241;
+		vrLoc = 0;
+	};
+	E1478925041FC51900050002 = {
+		fRef = E130B9AD03B7C59700000028;
+		isa = PBXTextBookmark;
+		name = "PSPowerManager.m: _pmuReference";
+		rLen = 0;
+		rLoc = 6334;
+		rType = 0;
+		vrLen = 1335;
+		vrLoc = 6384;
+	};
+	E1478926041FC51900050002 = {
+		fRef = E14A56ED041DD82F00050002;
+		isa = PBXTextBookmark;
+		name = "wakein.m: usage";
+		rLen = 0;
+		rLoc = 2372;
+		rType = 0;
+		vrLen = 833;
+		vrLoc = 0;
+	};
+	E1478927041FC51900050002 = {
+		fRef = E1DC3E31041F27DA00050002;
+		isa = PBXTextBookmark;
+		name = "wakein.h: 8";
+		rLen = 0;
+		rLoc = 225;
+		rType = 0;
+		vrLen = 143;
+		vrLoc = 0;
+	};
+	E1478928041FC51900050002 = {
+		fRef = E14A56ED041DD82F00050002;
+		isa = PBXTextBookmark;
+		name = "wakein.m: err";
+		rLen = 0;
+		rLoc = 373;
+		rType = 0;
+		vrLen = 956;
+		vrLoc = 0;
+	};
+	E1478929041FC51900050002 = {
+		fRef = E1DC3E31041F27DA00050002;
+		isa = PBXTextBookmark;
+		name = "wakein.h: 14";
+		rLen = 0;
+		rLoc = 225;
+		rType = 0;
+		vrLen = 439;
+		vrLoc = 0;
+	};
+	E147892A041FC51900050002 = {
+		fRef = E14A56ED041DD82F00050002;
+		isa = PBXTextBookmark;
+		name = "wakein.m: DoGetUIDsCommand";
+		rLen = 0;
+		rLoc = 373;
+		rType = 0;
+		vrLen = 1398;
+		vrLoc = 956;
+	};
+	E147892B041FC51900050002 = {
+		fRef = E14788D5041F2FF600050002;
+		isa = PBXTextBookmark;
+		name = "MoreCFQ.c: 11";
+		rLen = 0;
+		rLoc = 258;
+		rType = 0;
+		vrLen = 1557;
+		vrLoc = 0;
+	};
+	E147892C041FC51900050002 = {
+		fRef = E14788D9041F2FF600050002;
+		isa = PBXTextBookmark;
+		name = "MoreCFQ.h: 1";
+		rLen = 0;
+		rLoc = 0;
+		rType = 0;
+		vrLen = 2285;
+		vrLoc = 0;
+	};
+	E147892D041FC51900050002 = {
+		fRef = E14788D5041F2FF600050002;
+		isa = PBXTextBookmark;
+		name = "MoreCFQ.c: 11";
+		rLen = 0;
+		rLoc = 258;
+		rType = 0;
+		vrLen = 2285;
+		vrLoc = 0;
+	};
+	E147892E041FC51900050002 = {
+		fRef = E14788D6041F2FF600050002;
+		isa = PBXTextBookmark;
+		name = "MoreUNIX.c: __VERSION__";
+		rLen = 0;
+		rLoc = 0;
+		rType = 0;
+		vrLen = 1548;
+		vrLoc = 0;
+	};
+	E147892F041FC51900050002 = {
+		fRef = E14788D7041F2FF600050002;
+		isa = PBXTextBookmark;
+		name = "MoreUNIX.h: 10";
+		rLen = 0;
+		rLoc = 162;
+		rType = 0;
+		vrLen = 2276;
+		vrLoc = 0;
+	};
+	E1478930041FC51900050002 = {
+		fRef = E14788D9041F2FF600050002;
+		isa = PBXTextBookmark;
+		name = "MoreCFQ.h: 1";
+		rLen = 0;
+		rLoc = 0;
+		rType = 0;
+		vrLen = 2285;
+		vrLoc = 0;
+	};
+	E1478931041FC51900050002 = {
+		fRef = E14788D7041F2FF600050002;
+		isa = PBXTextBookmark;
+		name = "MoreUNIX.h: 10";
+		rLen = 0;
+		rLoc = 162;
+		rType = 0;
+		vrLen = 2276;
+		vrLoc = 0;
+	};
+	E1478932041FC51900050002 = {
+		fRef = E14788D8041F2FF600050002;
+		isa = PBXTextBookmark;
+		name = "MoreSecurity.c: __SIZE_TYPE__";
+		rLen = 0;
+		rLoc = 58;
+		rType = 0;
+		vrLen = 2276;
+		vrLoc = 0;
+	};
+	E1478933041FC51900050002 = {
+		fRef = E14788D9041F2FF600050002;
+		isa = PBXTextBookmark;
+		name = "MoreCFQ.h: 30";
+		rLen = 0;
+		rLoc = 1686;
+		rType = 0;
+		vrLen = 2285;
+		vrLoc = 0;
+	};
+	E1478934041FC51900050002 = {
+		fRef = E14788DA041F2FF600050002;
+		isa = PBXTextBookmark;
+		name = "MoreSecurity.h: 21";
+		rLen = 0;
+		rLoc = 1046;
+		rType = 0;
+		vrLen = 2276;
+		vrLoc = 0;
+	};
+	E1478935041FC51900050002 = {
+		fRef = E14788DB041F2FF600050002;
+		isa = PBXTextBookmark;
+		name = "MoreSetup.h: 15";
+		rLen = 0;
+		rLoc = 592;
+		rType = 0;
+		vrLen = 1306;
+		vrLoc = 8845;
+	};
+	E1478936041FC51900050002 = {
+		fRef = E14788DA041F2FF600050002;
+		isa = PBXTextBookmark;
+		name = "MoreSecurity.h: 21";
+		rLen = 0;
+		rLoc = 1046;
+		rType = 0;
+		vrLen = 2276;
+		vrLoc = 0;
+	};
+	E1478937041FC51900050002 = {
+		fRef = E14788DB041F2FF600050002;
+		isa = PBXTextBookmark;
+		name = "MoreSetup.h: 15";
+		rLen = 0;
+		rLoc = 592;
+		rType = 0;
+		vrLen = 1356;
+		vrLoc = 8795;
+	};
+	E1478938041FC51900050002 = {
+		fRef = E14788DA041F2FF600050002;
+		isa = PBXTextBookmark;
+		name = "MoreSecurity.h: 21";
+		rLen = 0;
+		rLoc = 1046;
+		rType = 0;
+		vrLen = 2276;
+		vrLoc = 0;
+	};
+	E1478939041FC51900050002 = {
+		fRef = E14788D8041F2FF600050002;
+		isa = PBXTextBookmark;
+		name = "MoreSecurity.c: __SIZE_TYPE__";
+		rLen = 0;
+		rLoc = 58;
+		rType = 0;
+		vrLen = 2276;
+		vrLoc = 0;
+	};
+	E147893A041FC51900050002 = {
+		fRef = E14788D9041F2FF600050002;
+		isa = PBXTextBookmark;
+		name = "MoreCFQ.h: 30";
+		rLen = 0;
+		rLoc = 1686;
+		rType = 0;
+		vrLen = 2285;
+		vrLoc = 0;
+	};
+	E147893B041FC51900050002 = {
+		fRef = E14788D5041F2FF600050002;
+		isa = PBXTextBookmark;
+		name = "MoreCFQ.c: 11";
+		rLen = 0;
+		rLoc = 258;
+		rType = 0;
+		vrLen = 2285;
+		vrLoc = 0;
+	};
+	E147893C041FC51900050002 = {
+		fRef = E14788D7041F2FF600050002;
+		isa = PBXTextBookmark;
+		name = "MoreUNIX.h: 10";
+		rLen = 0;
+		rLoc = 162;
+		rType = 0;
+		vrLen = 2276;
+		vrLoc = 0;
+	};
+	E147893D041FC51900050002 = {
+		fRef = E14788D6041F2FF600050002;
+		isa = PBXTextBookmark;
+		name = "MoreUNIX.c: MoreUNIXCopyFile";
+		rLen = 0;
+		rLoc = 11728;
+		rType = 0;
+		vrLen = 854;
+		vrLoc = 10891;
+	};
+	E147893E041FC51900050002 = {
+		fRef = E14A56ED041DD82F00050002;
+		isa = PBXTextBookmark;
+		name = "wakein.m: DoGetUIDsCommand";
+		rLen = 0;
+		rLoc = 1541;
+		rType = 0;
+		vrLen = 1299;
+		vrLoc = 968;
+	};
+	E147893F041FC51900050002 = {
+		fRef = E1DC3E31041F27DA00050002;
+		isa = PBXTextBookmark;
+		name = "wakein.h: 9";
+		rLen = 15;
+		rLoc = 152;
+		rType = 0;
+		vrLen = 267;
+		vrLoc = 0;
+	};
+	E1478940041FC51900050002 = {
+		fRef = E14A56ED041DD82F00050002;
+		isa = PBXTextBookmark;
+		name = "wakein.m: DoGetUIDsCommand";
+		rLen = 0;
+		rLoc = 1785;
+		rType = 0;
+		vrLen = 1556;
+		vrLoc = 236;
+	};
+	E1478941041FC51900050002 = {
+		fRef = E1DC3E31041F27DA00050002;
+		isa = PBXTextBookmark;
+		name = "wakein.h: kMoreSecurityTestGetUIDsResponseRUID";
+		rLen = 20;
+		rLoc = 188;
+		rType = 0;
+		vrLen = 267;
+		vrLoc = 0;
+	};
+	E1478942041FC51900050002 = {
+		fRef = E14A56ED041DD82F00050002;
+		isa = PBXTextBookmark;
+		name = "wakein.m: DoGetUIDsCommand";
+		rLen = 0;
+		rLoc = 1880;
+		rType = 0;
+		vrLen = 1486;
+		vrLoc = 372;
+	};
+	E1478943041FC51900050002 = {
+		fRef = E1DC3E31041F27DA00050002;
+		isa = PBXTextBookmark;
+		name = "wakein.h: kMoreSecurityTestGetUIDsCommand";
+		rLen = 0;
+		rLoc = 180;
+		rType = 0;
+		vrLen = 267;
+		vrLoc = 0;
+	};
+	E1478944041FC51900050002 = {
+		fRef = E14A56ED041DD82F00050002;
+		isa = PBXTextBookmark;
+		name = "wakein.m: DoGetUIDsCommand";
+		rLen = 0;
+		rLoc = 1880;
+		rType = 0;
+		vrLen = 1486;
+		vrLoc = 372;
+	};
+	E1478945041FC51900050002 = {
+		fRef = E1DC3E31041F27DA00050002;
+		isa = PBXTextBookmark;
+		name = "wakein.h: kMoreSecurityTestGetUIDsCommand";
+		rLen = 0;
+		rLoc = 180;
+		rType = 0;
+		vrLen = 225;
+		vrLoc = 0;
+	};
+	E1478946041FC51900050002 = {
+		fRef = E14A56ED041DD82F00050002;
+		isa = PBXTextBookmark;
+		name = "wakein.m: DoGetUIDsCommand";
+		rLen = 0;
+		rLoc = 1880;
+		rType = 0;
+		vrLen = 1486;
+		vrLoc = 372;
+	};
+	E1478947041FC51900050002 = {
+		fRef = E1DC3E31041F27DA00050002;
+		isa = PBXTextBookmark;
+		name = "wakein.h: kMoreSecurityTestGetUIDsCommand";
+		rLen = 0;
+		rLoc = 180;
+		rType = 0;
+		vrLen = 267;
+		vrLoc = 0;
+	};
+	E1478948041FC51900050002 = {
+		fRef = E14A56ED041DD82F00050002;
+		isa = PBXTextBookmark;
+		name = "wakein.m: auth";
+		rLen = 0;
+		rLoc = 1982;
+		rType = 0;
+		vrLen = 1261;
+		vrLoc = 1111;
+	};
+	E1478949041FC51900050002 = {
+		fRef = E14788D8041F2FF600050002;
+		isa = PBXTextBookmark;
+		name = "MoreSecurity.c: 129";
+		rLen = 0;
+		rLoc = 5111;
+		rType = 0;
+		vrLen = 855;
+		vrLoc = 4670;
+	};
+	E147894A041FC51900050002 = {
+		fRef = E14788DA041F2FF600050002;
+		isa = PBXTextBookmark;
+		name = "MoreSecurity.h: 549";
+		rLen = 0;
+		rLoc = 24721;
+		rType = 0;
+		vrLen = 1483;
+		vrLoc = 23128;
+	};
+	E147894B041FC51900050002 = {
+		fRef = F59DC6E90353F58B01AEEDB1;
+		isa = PBXTextBookmark;
+		name = "NJRIntegerFilter.h: 1";
+		rLen = 0;
+		rLoc = 0;
+		rType = 0;
+		vrLen = 255;
+		vrLoc = 0;
+	};
+	E147894C041FC51900050002 = {
+		fRef = E130B9AD03B7C59700000028;
+		isa = PBXTextBookmark;
+		name = "PSPowerManager.m: setWakeInterval:";
+		rLen = 0;
+		rLoc = 9937;
+		rType = 0;
+		vrLen = 1209;
+		vrLoc = 3938;
+	};
+	E147894D041FC51900050002 = {
+		fRef = E14788D6041F2FF600050002;
+		isa = PBXTextBookmark;
+		name = "MoreUNIX.c: MoreUNIXCopyFile";
+		rLen = 0;
+		rLoc = 11728;
+		rType = 0;
+		vrLen = 854;
+		vrLoc = 10891;
+	};
+	E147894E041FC51900050002 = {
+		fRef = E14A56ED041DD82F00050002;
+		isa = PBXTextBookmark;
+		name = "wakein.m: rights";
+		rLen = 0;
+		rLoc = 967;
+		rType = 0;
+		vrLen = 1566;
+		vrLoc = 195;
+	};
+	E147894F041FC51900050002 = {
+		fRef = E130B9AD03B7C59700000028;
+		isa = PBXTextBookmark;
+		name = "PSPowerManager.m: setWakeInterval:";
+		rLen = 5;
+		rLoc = 8414;
+		rType = 0;
+		vrLen = 1273;
+		vrLoc = 5905;
+	};
+	E1478950041FC51900050002 = {
+		fRef = E130B9AC03B7C59700000028;
+		isa = PBXTextBookmark;
+		name = "PSPowerManager.h: 34";
+		rLen = 0;
+		rLoc = 883;
+		rType = 0;
+		vrLen = 814;
+		vrLoc = 0;
+	};
+	E1478951041FC51900050002 = {
+		fRef = E130B9AD03B7C59700000028;
+		isa = PBXTextBookmark;
+		name = "PSPowerManager.m: setWakeInterval:";
+		rLen = 23;
+		rLoc = 8421;
+		rType = 0;
+		vrLen = 1297;
+		vrLoc = 5905;
+	};
+	E1478952041FC51900050002 = {
+		fRef = E130B9AC03B7C59700000028;
+		isa = PBXTextBookmark;
+		name = "PSPowerManager.h: 12";
+		rLen = 49;
+		rLoc = 214;
+		rType = 0;
+		vrLen = 864;
+		vrLoc = 0;
+	};
+	E1478953041FC51900050002 = {
+		fRef = E130B9AD03B7C59700000028;
+		isa = PBXTextBookmark;
+		name = "PSPowerManager.m: _execWakeToolWithRequestDictionary:";
+		rLen = 0;
+		rLoc = 9635;
+		rType = 0;
+		vrLen = 1903;
+		vrLoc = 7431;
+	};
+	E1478954041FC51900050002 = {
+		fRef = E1BF6E9103C928D200050002;
+		isa = PBXTextBookmark;
+		name = "PSTimer.m: 227";
+		rLen = 113;
+		rLoc = 6348;
+		rType = 0;
+		vrLen = 1181;
+		vrLoc = 5697;
+	};
+	E1478955041FC51900050002 = {
+		fRef = E1BF6E9003C928D200050002;
+		isa = PBXTextBookmark;
+		name = "PSTimer.h: 30";
+		rLen = 0;
+		rLoc = 987;
+		rType = 0;
+		vrLen = 1049;
+		vrLoc = 249;
+	};
+	E1478956041FC51900050002 = {
+		fRef = E130B9AD03B7C59700000028;
+		isa = PBXTextBookmark;
+		name = "PSPowerManager.m: _execWakeToolWithRequestDictionary:";
+		rLen = 9;
+		rLoc = 9635;
+		rType = 0;
+		vrLen = 1865;
+		vrLoc = 7431;
+	};
+	E1478957041FC51900050002 = {
+		fRef = E130B9AC03B7C59700000028;
+		isa = PBXTextBookmark;
+		name = "PSPowerManager.h: PSPowerManagerException";
+		rLen = 49;
+		rLoc = 214;
+		rType = 0;
+		vrLen = 864;
+		vrLoc = 0;
+	};
+	E1478958041FC51900050002 = {
+		fRef = E1DC3E31041F27DA00050002;
+		isa = PBXTextBookmark;
+		name = "wakein.h: kPesterWakeSuccess";
+		rLen = 0;
+		rLoc = 180;
+		rType = 0;
+		vrLen = 225;
+		vrLoc = 0;
+	};
+	E1478959041FC51900050002 = {
+		fRef = E14A56ED041DD82F00050002;
+		isa = PBXTextBookmark;
+		name = "wakein.m: SetAutoWake";
+		rLen = 0;
+		rLoc = 1863;
+		rType = 0;
+		vrLen = 1494;
+		vrLoc = 644;
+	};
+	E147895A041FC51900050002 = {
+		fRef = E19FD39E03C98645001509F3;
+		isa = PBXTextBookmark;
+		name = "PSWakeAlert.h: 1";
+		rLen = 0;
+		rLoc = 0;
+		rType = 0;
+		vrLen = 215;
+		vrLoc = 0;
+	};
+	E147895B041FC51900050002 = {
+		fRef = E19FD39F03C98645001509F3;
+		isa = PBXTextBookmark;
+		name = "PSWakeAlert.m: 17";
+		rLen = 0;
+		rLoc = 325;
+		rType = 0;
+		vrLen = 749;
+		vrLoc = 0;
+	};
+	E147895C041FC51900050002 = {
+		fRef = E19FD39E03C98645001509F3;
+		isa = PBXTextBookmark;
+		name = "PSWakeAlert.h: 1";
+		rLen = 0;
+		rLoc = 0;
+		rType = 0;
+		vrLen = 215;
+		vrLoc = 0;
+	};
+	E147895D041FC51900050002 = {
+		fRef = E19FD39F03C98645001509F3;
+		isa = PBXTextBookmark;
+		name = "PSWakeAlert.m: 26";
+		rLen = 0;
+		rLoc = 415;
+		rType = 0;
+		vrLen = 662;
+		vrLoc = 0;
+	};
+	E147895E041FC51900050002 = {
+		fRef = E130B9AD03B7C59700000028;
+		isa = PBXTextBookmark;
+		name = "PSPowerManager.m: authorize";
+		rLen = 19;
+		rLoc = 9843;
+		rType = 0;
+		vrLen = 1717;
+		vrLoc = 7711;
+	};
+	E147895F041FC51900050002 = {
+		fRef = E130B9AC03B7C59700000028;
+		isa = PBXTextBookmark;
+		name = "PSPowerManager.h: setWakeInterval:";
+		rLen = 0;
+		rLoc = 462;
+		rType = 0;
+		vrLen = 883;
+		vrLoc = 0;
+	};
+	E1478960041FC51900050002 = {
+		fRef = E19FD39F03C98645001509F3;
+		isa = PBXTextBookmark;
+		name = "PSWakeAlert.m: prepareForAlarm:";
+		rLen = 0;
+		rLoc = 415;
+		rType = 0;
+		vrLen = 727;
+		vrLoc = 0;
+	};
+	E1478961041FC51900050002 = {
+		fRef = E130B9AD03B7C59700000028;
+		isa = PBXTextBookmark;
+		name = "PSPowerManager.m: tool";
+		rLen = 0;
+		rLoc = 8587;
+		rType = 0;
+		vrLen = 1815;
+		vrLoc = 6779;
+	};
+	E1478962041FC51900050002 = {
+		fRef = E14788D6041F2FF600050002;
+		isa = PBXTextBookmark;
+		name = "MoreUNIX.c: MoreUNIXWrite";
+		rLen = 10;
+		rLoc = 8684;
+		rType = 0;
+		vrLen = 1134;
+		vrLoc = 7738;
+	};
+	E1478963041FC51900050002 = {
+		fRef = E14788DB041F2FF600050002;
+		isa = PBXTextBookmark;
+		name = "MoreSetup.h: 196";
+		rLen = 0;
+		rLoc = 8460;
+		rType = 0;
+		vrLen = 1230;
+		vrLoc = 7615;
+	};
+	E1478964041FC51900050002 = {
+		isa = PBXTargetBookmark;
+		trg = 29B97326FDCFA39411CA2CEA;
+	};
+	E1478965041FC51900050002 = {
+		fRef = E14788D6041F2FF600050002;
+		isa = PBXTextBookmark;
+		name = "MoreUNIX.c: 105";
+		rLen = 13;
+		rLoc = 4015;
+		rType = 0;
+		vrLen = 603;
+		vrLoc = 3752;
+	};
+	E1478966041FC51900050002 = {
+		fRef = E14788D7041F2FF600050002;
+		isa = PBXTextBookmark;
+		name = "MoreUNIX.h: 10";
+		rLen = 0;
+		rLoc = 162;
+		rType = 0;
+		vrLen = 2276;
+		vrLoc = 0;
+	};
+	E1478967041FC51900050002 = {
+		fRef = E14788D6041F2FF600050002;
+		isa = PBXTextBookmark;
+		name = "MoreUNIX.c: 105";
+		rLen = 13;
+		rLoc = 4015;
+		rType = 0;
+		vrLen = 603;
+		vrLoc = 3752;
+	};
+	E1478968041FC51900050002 = {
+		fRef = E14788D7041F2FF600050002;
+		isa = PBXTextBookmark;
+		name = "MoreUNIX.h: 93";
+		rLen = 0;
+		rLoc = 3756;
+		rType = 0;
+		vrLen = 986;
+		vrLoc = 3090;
+	};
+	E1478969041FC51900050002 = {
+		fRef = E14788D5041F2FF600050002;
+		isa = PBXTextBookmark;
+		name = "MoreCFQ.c: 24";
+		rLen = 0;
+		rLoc = 1238;
+		rType = 0;
+		vrLen = 2286;
+		vrLoc = 0;
+	};
+	E147896A041FC51900050002 = {
+		fRef = E14788D8041F2FF600050002;
+		isa = PBXTextBookmark;
+		name = "MoreSecurity.c: ExecuteSelfInPrivilegedSelfRepairMode";
+		rLen = 0;
+		rLoc = 24314;
+		rType = 0;
+		vrLen = 1141;
+		vrLoc = 23935;
+	};
+	E147896B041FC51900050002 = {
+		fRef = E14788DB041F2FF600050002;
+		isa = PBXTextBookmark;
+		name = "MoreSetup.h: 219";
+		rLen = 0;
+		rLoc = 9022;
+		rType = 0;
+		vrLen = 1306;
+		vrLoc = 8845;
+	};
+	E147896C041FC51900050002 = {
+		fRef = E14788D5041F2FF600050002;
+		isa = PBXTextBookmark;
+		name = "MoreCFQ.c: 15";
+		rLen = 0;
+		rLoc = 571;
+		rType = 0;
+		vrLen = 2286;
+		vrLoc = 0;
+	};
+	E147896D041FC51900050002 = {
+		fRef = E14788D8041F2FF600050002;
+		isa = PBXTextBookmark;
+		name = "MoreSecurity.c: 1389";
+		rLen = 32;
+		rLoc = 44003;
+		rType = 0;
+		vrLen = 1329;
+		vrLoc = 42568;
+	};
+	E147896E041FC51900050002 = {
+		fRef = E14788DA041F2FF600050002;
+		isa = PBXTextBookmark;
+		name = "MoreSecurity.h: 472";
+		rLen = 0;
+		rLoc = 21166;
+		rType = 0;
+		vrLen = 1706;
+		vrLoc = 20884;
+	};
+	E147896F041FC51900050002 = {
+		fRef = E14788D8041F2FF600050002;
+		isa = PBXTextBookmark;
+		name = "MoreSecurity.c: MoreSecCopyHelperToolURLAndCheck";
+		rLen = 28;
+		rLoc = 46869;
+		rType = 0;
+		vrLen = 1136;
+		vrLoc = 46110;
+	};
+	E1478970041FC51900050002 = {
+		fRef = E14788DA041F2FF600050002;
+		isa = PBXTextBookmark;
+		name = "MoreSecurity.h: MoreSecDestroyInheritedEnvironment";
+		rLen = 34;
+		rLoc = 7072;
+		rType = 0;
+		vrLen = 1821;
+		vrLoc = 6333;
+	};
+	E1478971041FC51900050002 = {
+		fRef = E14788D8041F2FF600050002;
+		isa = PBXTextBookmark;
+		name = "MoreSecurity.c: 1389";
+		rLen = 196;
+		rLoc = 43987;
+		rType = 0;
+		vrLen = 941;
+		vrLoc = 43583;
+	};
+	E1478972041FC51900050002 = {
+		fRef = E14788DA041F2FF600050002;
+		isa = PBXTextBookmark;
+		name = "MoreSecurity.h: MoreSecCopyHelperToolURLAndCheck";
+		rLen = 0;
+		rLoc = 19010;
+		rType = 0;
+		vrLen = 2149;
+		vrLoc = 17605;
+	};
+	E1478973041FC51900050002 = {
+		fRef = E14788D8041F2FF600050002;
+		isa = PBXTextBookmark;
+		name = "MoreSecurity.c: MoreSecCopyHelperToolURLAndCheckBundled";
+		rLen = 0;
+		rLoc = 48068;
+		rType = 0;
+		vrLen = 1224;
+		vrLoc = 47128;
+	};
+	E1478974041FC51900050002 = {
+		fRef = E130B9AD03B7C59700000028;
+		isa = PBXTextBookmark;
+		name = "PSPowerManager.m: _execWakeToolWithRequestDictionary:";
+		rLen = 0;
+		rLoc = 8183;
+		rType = 0;
+		vrLen = 1931;
+		vrLoc = 7238;
+	};
+	E1478975041FC51900050002 = {
+		fRef = E14A56ED041DD82F00050002;
+		isa = PBXTextBookmark;
+		name = "wakein.m: SetAutoWake";
+		rLen = 0;
+		rLoc = 1863;
+		rType = 0;
+		vrLen = 1494;
+		vrLoc = 644;
+	};
+	E1478976041FC51900050002 = {
+		fRef = E14788D8041F2FF600050002;
+		isa = PBXTextBookmark;
+		name = "MoreSecurity.c: MoreSecExecuteRequestInHelperTool";
+		rLen = 0;
+		rLoc = 49682;
+		rType = 0;
+		vrLen = 1317;
+		vrLoc = 48607;
+	};
+	E1478977041FC51900050002 = {
+		fRef = E1DC3E31041F27DA00050002;
+		isa = PBXTextBookmark;
+		name = "wakein.h: kPesterWakeException";
+		rLen = 0;
+		rLoc = 180;
+		rType = 0;
+		vrLen = 225;
+		vrLoc = 0;
+	};
+	E1478978041FC51900050002 = {
+		fRef = E14A56ED041DD82F00050002;
+		isa = PBXTextBookmark;
+		name = "wakein.m: SetAutoWake";
+		rLen = 0;
+		rLoc = 1389;
+		rType = 0;
+		vrLen = 1517;
+		vrLoc = 476;
+	};
+	E1478979041FC51900050002 = {
+		fRef = E130B9AD03B7C59700000028;
+		isa = PBXTextBookmark;
+		name = "PSPowerManager.m: setWakeInterval:";
+		rLen = 0;
+		rLoc = 10009;
+		rType = 0;
+		vrLen = 1616;
+		vrLoc = 8505;
+	};
+	E147897A041FC51900050002 = {
+		fRef = E14788DA041F2FF600050002;
+		isa = PBXTextBookmark;
+		name = "MoreSecurity.h: MoreSecHelperToolCopyAuthRef";
+		rLen = 28;
+		rLoc = 14565;
+		rType = 0;
+		vrLen = 1657;
+		vrLoc = 13416;
+	};
+	E147897B041FC51900050002 = {
+		fRef = E130B9AC03B7C59700000028;
+		isa = PBXTextBookmark;
+		name = "PSPowerManager.h: wakeTime";
+		rLen = 0;
+		rLoc = 462;
+		rType = 0;
+		vrLen = 883;
+		vrLoc = 0;
+	};
+	E147897C041FC51900050002 = {
+		fRef = E130B9AD03B7C59700000028;
+		isa = PBXTextBookmark;
+		name = "PSPowerManager.m: _execWakeToolWithRequestDictionary:";
+		rLen = 0;
+		rLoc = 8183;
+		rType = 0;
+		vrLen = 1923;
+		vrLoc = 7549;
+	};
+	E147897D041FC51900050002 = {
+		fRef = E14A56ED041DD82F00050002;
+		isa = PBXTextBookmark;
+		name = "wakein.m: SetAutoWake";
+		rLen = 0;
+		rLoc = 1182;
+		rType = 0;
+		vrLen = 1540;
+		vrLoc = 324;
+	};
+	E147897E041FC51900050002 = {
+		fRef = E130B9AC03B7C59700000028;
+		isa = PBXTextBookmark;
+		name = "PSPowerManager.h: setWakeInterval:";
+		rLen = 15;
+		rLoc = 492;
+		rType = 0;
+		vrLen = 883;
+		vrLoc = 0;
+	};
+	E147897F041FC51900050002 = {
+		fRef = E10E71F4040C335800050002;
+		isa = PBXTextBookmark;
+		name = "English: 115";
+		rLen = 0;
+		rLoc = 6392;
+		rType = 0;
+		vrLen = 2153;
+		vrLoc = 4660;
+	};
+	E1478980041FC51900050002 = {
+		fRef = E14788D8041F2FF600050002;
+		isa = PBXTextBookmark;
+		name = "MoreSecurity.c: MoreSecHelperToolMain";
+		rLen = 35;
+		rLoc = 33713;
+		rType = 0;
+		vrLen = 1380;
+		vrLoc = 33139;
+	};
+	E1478981041FC51900050002 = {
+		fRef = E14788DA041F2FF600050002;
+		isa = PBXTextBookmark;
+		name = "MoreSecurity.h: MoreSecHelperToolCopyAuthRef";
+		rLen = 28;
+		rLoc = 14565;
+		rType = 0;
+		vrLen = 1584;
+		vrLoc = 13416;
+	};
+	E1478982041FC51900050002 = {
+		fRef = E130B9AD03B7C59700000028;
+		isa = PBXTextBookmark;
+		name = "PSPowerManager.m: _execWakeToolWithRequestDictionary:";
+		rLen = 0;
+		rLoc = 8182;
+		rType = 0;
+		vrLen = 1905;
+		vrLoc = 6815;
+	};
+	E1478983041FC51900050002 = {
+		fRef = E14A56ED041DD82F00050002;
+		isa = PBXTextBookmark;
+		name = "wakein.m: SetAutoWake";
+		rLen = 0;
+		rLoc = 1140;
+		rType = 0;
+		vrLen = 1539;
+		vrLoc = 324;
+	};
+	E1478984041FC51900050002 = {
+		fRef = E130B9AD03B7C59700000028;
+		isa = PBXTextBookmark;
+		name = "PSPowerManager.m: _execWakeToolWithRequestDictionary:";
+		rLen = 0;
+		rLoc = 7852;
+		rType = 0;
+		vrLen = 2197;
+		vrLoc = 7324;
+	};
+	E1478985041FC51900050002 = {
+		fRef = E14A56ED041DD82F00050002;
+		isa = PBXTextBookmark;
+		name = "wakein.m: SetAutoWake";
+		rLen = 15;
+		rLoc = 1579;
+		rType = 0;
+		vrLen = 1390;
+		vrLoc = 644;
+	};
+	E1478986041FC51900050002 = {
+		fRef = E130B9AD03B7C59700000028;
+		isa = PBXTextBookmark;
+		name = "PSPowerManager.m: setWakeInterval:";
+		rLen = 0;
+		rLoc = 10168;
+		rType = 0;
+		vrLen = 1192;
+		vrLoc = 9235;
+	};
+	E1478987041FC51900050002 = {
+		fRef = E14A56ED041DD82F00050002;
+		isa = PBXTextBookmark;
+		name = "wakein.m: main";
+		rLen = 0;
+		rLoc = 2304;
+		rType = 0;
+		vrLen = 1112;
+		vrLoc = 1260;
+	};
+	E147898D041FC51900050002 = {
+		fRef = E130B9AD03B7C59700000028;
+		isa = PBXTextBookmark;
+		name = "PSPowerManager.m: _execWakeToolWithRequestDictionary:";
+		rLen = 0;
+		rLoc = 7353;
+		rType = 0;
+		vrLen = 494;
+		vrLoc = 6787;
+	};
+	E147898F041FC51900050002 = {
+		fRef = E10E71F4040C335800050002;
+		isa = PBXTextBookmark;
+		name = "English: 117";
+		rLen = 0;
+		rLoc = 6548;
+		rType = 0;
+		vrLen = 2232;
+		vrLoc = 4420;
+	};
+	E1478990041FC51900050002 = {
+		isa = PBXFileReference;
+		name = MacErrors.h;
+		path = /System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/CarbonCore.framework/Versions/A/Headers/MacErrors.h;
+		refType = 0;
+	};
+	E1478991041FC51900050002 = {
+		isa = PBXFileReference;
+		name = Creating_and_n_References.html;
+		path = /Developer/Documentation/CoreTechnologies/securityservices/authorizationservices/authorization_ref/Authorizatio_es_Reference/Functions/Creating_and_n_References.html;
+		refType = 0;
+	};
+	E1478992041FC51900050002 = {
+		isa = PBXFileReference;
+		name = NSBundle.h;
+		path = /System/Library/Frameworks/Foundation.framework/Versions/C/Headers/NSBundle.h;
+		refType = 0;
+	};
+	E1478994041FC51900050002 = {
+		isa = PBXFileReference;
+		name = port.h;
+		path = /usr/include/mach/port.h;
+		refType = 0;
+	};
+	E1478995041FC51900050002 = {
+		isa = PBXFileReference;
+		name = Files.h;
+		path = /System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/CarbonCore.framework/Versions/A/Headers/Files.h;
+		refType = 0;
+	};
+	E1478996041FC51A00050002 = {
+		isa = PBXFileReference;
+		name = NSDictionary.h;
+		path = /System/Library/Frameworks/Foundation.framework/Versions/C/Headers/NSDictionary.h;
+		refType = 0;
+	};
+	E1478997041FC51A00050002 = {
+		isa = PBXFileReference;
+		name = Authorization.h;
+		path = /System/Library/Frameworks/Security.framework/Versions/A/Headers/Authorization.h;
+		refType = 0;
+	};
+	E1478998041FC51A00050002 = {
+		isa = PBXFileReference;
+		name = NSException.h;
+		path = /System/Library/Frameworks/Foundation.framework/Versions/C/Headers/NSException.h;
+		refType = 0;
+	};
+	E147899A041FC51A00050002 = {
+		isa = PBXFileReference;
+		name = Authorization_Options.html;
+		path = /Developer/Documentation/CoreTechnologies/securityservices/authorizationservices/authorization_ref/Authorizatio_es_Reference/Enumerations/Authorization_Options.html;
+		refType = 0;
+	};
+	E147899B041FC51A00050002 = {
+		isa = PBXFileReference;
+		name = vm_types.h;
+		path = /usr/include/mach/ppc/vm_types.h;
+		refType = 0;
+	};
+	E147899C041FC51A00050002 = {
+		isa = PBXFileReference;
+		name = IOTypes.h;
+		path = /System/Library/Frameworks/IOKit.framework/Versions/A/Headers/IOTypes.h;
+		refType = 0;
+	};
+	E147899D041FC51A00050002 = {
+		isa = PBXFileReference;
+		name = NSValue.h;
+		path = /System/Library/Frameworks/Foundation.framework/Versions/C/Headers/NSValue.h;
+		refType = 0;
+	};
+	E14789A7041FCB3800050002 = {
+		fRef = E130B9AD03B7C59700000028;
+		isa = PBXTextBookmark;
+		name = "PSPowerManager.m: wakeTime";
+		rLen = 31;
+		rLoc = 6818;
+		rType = 0;
+		vrLen = 1280;
+		vrLoc = 6073;
+	};
+	E14789A8041FCB3800050002 = {
+		fRef = F59DC6D40353C9E601AEEDB1;
+		isa = PBXTextBookmark;
+		name = "PSAlarmSetController.m: playSoundChanged:";
+		rLen = 41;
+		rLoc = 14170;
+		rType = 0;
+		vrLen = 1624;
+		vrLoc = 13315;
+	};
+	E14789A9041FCB3800050002 = {
+		fRef = E130B9AD03B7C59700000028;
+		isa = PBXTextBookmark;
+		name = "PSPowerManager.m: wakeTime";
+		rLen = 31;
+		rLoc = 6818;
+		rType = 0;
+		vrLen = 1280;
+		vrLoc = 6073;
+	};
+	E14789AA041FCB3800050002 = {
+		fRef = F59DC6D40353C9E601AEEDB1;
+		isa = PBXTextBookmark;
+		name = "PSAlarmSetController.m: playSoundChanged:";
+		rLen = 41;
+		rLoc = 14170;
+		rType = 0;
+		vrLen = 1624;
+		vrLoc = 13315;
+	};
+	E14789AB041FCB3800050002 = {
+		fRef = F59E47B4036AAD55016B311C;
+		isa = PBXTextBookmark;
+		name = "PSAlarmAlertController.m: 71";
+		rLen = 38;
+		rLoc = 2800;
+		rType = 0;
+		vrLen = 1835;
+		vrLoc = 1269;
+	};
+	E14789AC041FCB3800050002 = {
+		fRef = E130B9AD03B7C59700000028;
+		isa = PBXTextBookmark;
+		name = "PSPowerManager.m: _localHandler";
+		rLen = 0;
+		rLoc = 7353;
+		rType = 0;
+		vrLen = 499;
+		vrLoc = 6781;
+	};
+	E14789AD041FCB3800050002 = {
+		fRef = E10E71F4040C335800050002;
+		isa = PBXTextBookmark;
+		name = "English: 117";
+		rLen = 0;
+		rLoc = 6548;
+		rType = 0;
+		vrLen = 2232;
+		vrLoc = 4420;
+	};
+	E14A56EA041DD6B600050002 = {
+		activeExec = 0;
+		executables = (
+			E14A56EC041DD6B600050002,
+		);
+	};
+	E14A56EC041DD6B600050002 = {
+		activeArgIndex = 2147483647;
+		activeArgIndices = (
+		);
+		argumentStrings = (
+		);
+		configStateDict = {
+		};
+		debuggerPlugin = GDBDebugging;
+		dylibVariantSuffix = "";
+		enableDebugStr = 1;
+		environmentEntries = (
+		);
+		isa = PBXExecutable;
+		name = wakein;
+		shlibInfoDictList = (
+		);
+		sourceDirectories = (
+		);
+	};
+	E14A56F104E785DC00050002 = {
+		fRef = E17F2F4103FDF67700050002;
+		isa = PBXTextBookmark;
+		name = "OACalendarView.m: setTarget:";
+		rLen = 0;
+		rLoc = 22368;
+		rType = 0;
+		vrLen = 1224;
+		vrLoc = 21855;
+	};
+	E14A56F304E785DC00050002 = {
+		fRef = E19DCBD203BE4AA200B934BF;
+		isa = PBXTextBookmark;
+		name = "Pester_Prefix.h: __WINT_TYPE__";
+		rLen = 0;
+		rLoc = 143;
+		rType = 0;
+		vrLen = 143;
+		vrLoc = 0;
+	};
+	E14A56F404E785DC00050002 = {
+		fRef = E14A571404E785DC00050002;
+		isa = PBXTextBookmark;
+		name = "NSTimeZone.h: 34";
+		rLen = 14;
+		rLoc = 725;
+		rType = 0;
+		vrLen = 875;
+		vrLoc = 165;
+	};
+	E14A56F504E785DC00050002 = {
+		fRef = E14A571504E785DC00050002;
+		isa = PBXTextBookmark;
+		name = "NSCalendarDate.h: 18";
+		rLen = 10;
+		rLoc = 517;
+		rType = 0;
+		vrLen = 1237;
+		vrLoc = 0;
+	};
+	E14A56F604E785DC00050002 = {
+		fRef = E14A571604E785DC00050002;
+		isa = PBXTextBookmark;
+		name = "NSDate.h: 43";
+		rLen = 67;
+		rLoc = 924;
+		rType = 0;
+		vrLen = 1044;
+		vrLoc = 303;
+	};
+	E14A56F704E785DC00050002 = {
+		fRef = E14A571704E785DC00050002;
+		glyphRangeLength = 1101;
+		glyphRangeLocation = 3899;
+		isa = PBXDocBookmark;
+		name = "NSTimeZone.html: resetSystemT...";
+	};
+	E14A56F904E785DC00050002 = {
+		fRef = 29B97316FDCFA39411CA2CEA;
+		isa = PBXTextBookmark;
+		name = "main.m: 15";
+		rLen = 0;
+		rLoc = 252;
+		rType = 0;
+		vrLen = 252;
+		vrLoc = 0;
+	};
+	E14A56FA04E785DC00050002 = {
+		fRef = F560E2F10357506401A4E466;
+		isa = PBXTextBookmark;
+		name = "PSApplication.m: 191";
+		rLen = 0;
+		rLoc = 7583;
+		rType = 0;
+		vrLen = 2152;
+		vrLoc = 6740;
+	};
+	E14A56FC04E785DC00050002 = {
+		fRef = F589C9C6035AA12B0155F4B2;
+		isa = PBXTextBookmark;
+		name = "Read Me.rtfd: 152";
+		rLen = 0;
+		rLoc = 12491;
+		rType = 0;
+		vrLen = 1329;
+		vrLoc = 3316;
+	};
+	E14A56FD04E785DC00050002 = {
+		fRef = F59DD4500358ABF4017318D0;
+		isa = PBXTextBookmark;
+		name = "English: 3";
+		rLen = 0;
+		rLoc = 412;
+		rType = 0;
+		vrLen = 412;
+		vrLoc = 0;
+	};
+	E14A56FF04E785DC00050002 = {
+		fRef = E17F2F4103FDF67700050002;
+		isa = PBXTextBookmark;
+		name = "OACalendarView.m: setTarget:";
+		rLen = 0;
+		rLoc = 22368;
+		rType = 0;
+		vrLen = 1224;
+		vrLoc = 21855;
+	};
+	E14A570004E785DC00050002 = {
+		fRef = E130B9AD03B7C59700000028;
+		isa = PBXTextBookmark;
+		name = "PSPowerManager.m: 31";
+		rLen = 0;
+		rLoc = 1313;
+		rType = 0;
+		vrLen = 1592;
+		vrLoc = 214;
+	};
+	E14A570104E785DC00050002 = {
+		isa = PBXTargetBookmark;
+		trg = E14A56EA041DD6B600050002;
+	};
+	E14A570204E785DC00050002 = {
+		fRef = E130B9AD03B7C59700000028;
+		isa = PBXTextBookmark;
+		name = "PSPowerManager.m: 70";
+		rLen = 0;
+		rLoc = 2778;
+		rType = 0;
+		vrLen = 1314;
+		vrLoc = 1294;
+	};
+	E14A570304E785DC00050002 = {
+		fRef = 29B97316FDCFA39411CA2CEA;
+		isa = PBXTextBookmark;
+		name = "main.m: __GNUC__";
+		rLen = 252;
+		rLoc = 0;
+		rType = 0;
+		vrLen = 252;
+		vrLoc = 0;
+	};
+	E14A570404E785DC00050002 = {
+		fRef = E19DCBD203BE4AA200B934BF;
+		isa = PBXTextBookmark;
+		name = "Pester_Prefix.h: __WINT_TYPE__";
+		rLen = 0;
+		rLoc = 143;
+		rType = 0;
+		vrLen = 143;
+		vrLoc = 0;
+	};
+	E14A570604E785DC00050002 = {
+		fRef = 29B97316FDCFA39411CA2CEA;
+		isa = PBXTextBookmark;
+		name = "main.m: 9";
+		rLen = 110;
+		rLoc = 142;
+		rType = 0;
+		vrLen = 252;
+		vrLoc = 0;
+	};
+	E14A570804E785DC00050002 = {
+		fRef = E130B9AD03B7C59700000028;
+		isa = PBXTextBookmark;
+		name = "PSPowerManager.m: 198";
+		rLen = 0;
+		rLoc = 7280;
+		rType = 0;
+		vrLen = 1289;
+		vrLoc = 5793;
+	};
+	E14A570A04E785DC00050002 = {
+		fRef = 29B97316FDCFA39411CA2CEA;
+		isa = PBXTextBookmark;
+		name = "main.m: 15";
+		rLen = 0;
+		rLoc = 252;
+		rType = 0;
+		vrLen = 252;
+		vrLoc = 0;
+	};
+	E14A570B04E785DC00050002 = {
+		fRef = E130B9AD03B7C59700000028;
+		isa = PBXTextBookmark;
+		name = "PSPowerManager.m: 259";
+		rLen = 0;
+		rLoc = 12544;
+		rType = 0;
+		vrLen = 1158;
+		vrLoc = 8011;
+	};
+	E14A570C04E785DC00050002 = {
+		fRef = F560E2F10357506401A4E466;
+		isa = PBXTextBookmark;
+		name = "PSApplication.m: 196";
+		rLen = 0;
+		rLoc = 7856;
+		rType = 0;
+		vrLen = 1954;
+		vrLoc = 7106;
+	};
+	E14A570D04E785DC00050002 = {
+		isa = PBXTargetBookmark;
+		trg = 29B97326FDCFA39411CA2CEA;
+	};
+	E14A570E04E785DC00050002 = {
+		fRef = F560E2F10357506401A4E466;
+		isa = PBXTextBookmark;
+		name = "PSApplication.m: 191";
+		rLen = 0;
+		rLoc = 7583;
+		rType = 0;
+		vrLen = 2152;
+		vrLoc = 6740;
+	};
+	E14A570F04E785DC00050002 = {
+		fRef = E130B9AD03B7C59700000028;
+		isa = PBXTextBookmark;
+		name = "PSPowerManager.m: 201";
+		rLen = 0;
+		rLoc = 10486;
+		rType = 0;
+		vrLen = 1124;
+		vrLoc = 6210;
+	};
+	E14A571004E785DC00050002 = {
+		isa = PBXTargetBookmark;
+		trg = 29B97326FDCFA39411CA2CEA;
+	};
+	E14A571104E785DC00050002 = {
+		fRef = F589C9C6035AA12B0155F4B2;
+		isa = PBXTextBookmark;
+		name = "Read Me.rtfd: 152";
+		rLen = 0;
+		rLoc = 12491;
+		rType = 0;
+		vrLen = 1329;
+		vrLoc = 3316;
+	};
+	E14A571204E785DC00050002 = {
+		fRef = F59DD4500358ABF4017318D0;
+		isa = PBXTextBookmark;
+		name = "English: 3";
+		rLen = 0;
+		rLoc = 412;
+		rType = 0;
+		vrLen = 412;
+		vrLoc = 0;
+	};
+	E14A571404E785DC00050002 = {
+		isa = PBXFileReference;
+		name = NSTimeZone.h;
+		path = /System/Library/Frameworks/Foundation.framework/Versions/C/Headers/NSTimeZone.h;
+		refType = 0;
+	};
+	E14A571504E785DC00050002 = {
+		isa = PBXFileReference;
+		name = NSCalendarDate.h;
+		path = /System/Library/Frameworks/Foundation.framework/Versions/C/Headers/NSCalendarDate.h;
+		refType = 0;
+	};
+	E14A571604E785DC00050002 = {
+		isa = PBXFileReference;
+		name = NSDate.h;
+		path = /System/Library/Frameworks/Foundation.framework/Versions/C/Headers/NSDate.h;
+		refType = 0;
+	};
+	E14A571704E785DC00050002 = {
+		isa = PBXFileReference;
+		name = NSTimeZone.html;
+		path = /System/Library/Frameworks/Foundation.framework/Versions/C/Resources/English.lproj/Documentation/Reference/ObjC_classic/Classes/NSTimeZone.html;
+		refType = 0;
+	};
 	E157230C04009B8300050002 = {
 		fRef = F59DD4500358ABF4017318D0;
@@ -4148,5 +6314,5 @@
 		name = "English: 3";
 		rLen = 0;
-		rLoc = 289;
+		rLoc = 341;
 		rType = 0;
 		vrLen = 360;
@@ -4276,14 +6442,4 @@
 		refType = 0;
 	};
-	E1669BB70412965E00050002 = {
-		fRef = E130B9AD03B7C59700000028;
-		isa = PBXTextBookmark;
-		name = "PSPowerManager.m: 13";
-		rLen = 0;
-		rLoc = 269;
-		rType = 0;
-		vrLen = 1364;
-		vrLoc = 0;
-	};
 	E1669BBD0412965E00050002 = {
 		fRef = F59E47A8036AAA6D016B311C;
@@ -4311,5 +6467,5 @@
 		name = "PSPowerManager.m: 13";
 		rLen = 0;
-		rLoc = 269;
+		rLoc = 288;
 		rType = 0;
 		vrLen = 1364;
@@ -4535,14 +6691,4 @@
 		vrLen = 1211;
 		vrLoc = 1834;
-	};
-	E16A0E6604005B0E00050002 = {
-		fRef = E17F2F4103FDF67700050002;
-		isa = PBXTextBookmark;
-		name = "OACalendarView.m: 545";
-		rLen = 0;
-		rLoc = 21556;
-		rType = 0;
-		vrLen = 1710;
-		vrLoc = 20144;
 	};
 	E16A0E6704005B0E00050002 = {
@@ -5437,5 +7583,5 @@
 		name = "PSPowerManager.m: 237";
 		rLen = 0;
-		rLoc = 8150;
+		rLoc = 12054;
 		rType = 0;
 		vrLen = 1226;
@@ -7163,14 +9309,4 @@
 		refType = 0;
 	};
-	E19DCC8703BE900300B934BF = {
-		fRef = 29B97316FDCFA39411CA2CEA;
-		isa = PBXTextBookmark;
-		name = "main.m: __VERSION__";
-		rLen = 0;
-		rLoc = 0;
-		rType = 0;
-		vrLen = 252;
-		vrLoc = 0;
-	};
 	E19DCC8903BE900300B934BF = {
 		fRef = E19DCCE403BE900300B934BF;
@@ -7192,14 +9328,4 @@
 		vrLen = 1095;
 		vrLoc = 0;
-	};
-	E19DCC8E03BE900300B934BF = {
-		fRef = E19DCCE503BE900300B934BF;
-		isa = PBXTextBookmark;
-		name = "NSValue.h: 88";
-		rLen = 46;
-		rLoc = 2491;
-		rType = 0;
-		vrLen = 1443;
-		vrLoc = 1143;
 	};
 	E19DCC9203BE900300B934BF = {
@@ -7649,10 +9775,4 @@
 		refType = 0;
 	};
-	E19DCCE503BE900300B934BF = {
-		isa = PBXFileReference;
-		name = NSValue.h;
-		path = /System/Library/Frameworks/Foundation.framework/Versions/C/Headers/NSValue.h;
-		refType = 0;
-	};
 	E19DCCE803BE900300B934BF = {
 		isa = PBXFileReference;
@@ -8058,14 +10178,4 @@
 		vrLoc = 668;
 	};
-	E1AFB0DB03C9A59C001509F3 = {
-		fRef = E19FD39F03C98645001509F3;
-		isa = PBXTextBookmark;
-		name = "PSWakeAlert.m: 24";
-		rLen = 0;
-		rLoc = 444;
-		rType = 0;
-		vrLen = 815;
-		vrLoc = 0;
-	};
 	E1AFB0E003C9A59C001509F3 = {
 		isa = PBXTargetBookmark;
@@ -8421,5 +10531,5 @@
 		name = "PSWakeAlert.m: 24";
 		rLen = 0;
-		rLoc = 444;
+		rLoc = 471;
 		rType = 0;
 		vrLen = 815;
@@ -8441,5 +10551,5 @@
 		name = "PSTimer.m: ";
 		rLen = 0;
-		rLoc = 6753;
+		rLoc = 6775;
 		rType = 0;
 		vrLen = 1086;
@@ -8451,5 +10561,5 @@
 		name = "PSPowerManager.m: 222";
 		rLen = 0;
-		rLoc = 7430;
+		rLoc = 11334;
 		rType = 0;
 		vrLen = 1665;
@@ -8471,5 +10581,5 @@
 		name = "PSPowerManager.m: 245";
 		rLen = 0;
-		rLoc = 7723;
+		rLoc = 11627;
 		rType = 0;
 		vrLen = 1673;
@@ -8481,5 +10591,5 @@
 		name = "PSWakeAlert.m: 24";
 		rLen = 0;
-		rLoc = 444;
+		rLoc = 471;
 		rType = 0;
 		vrLen = 815;
@@ -8501,5 +10611,5 @@
 		name = "PSPowerManager.h: 29";
 		rLen = 68;
-		rLoc = 527;
+		rLoc = 682;
 		rType = 0;
 		vrLen = 718;
@@ -8592,14 +10702,4 @@
 		vrLoc = 3394;
 	};
-	E1B46F5C04053C4F00050002 = {
-		fRef = F59DD4500358ABF4017318D0;
-		isa = PBXTextBookmark;
-		name = "English: 3";
-		rLen = 0;
-		rLoc = 289;
-		rType = 0;
-		vrLen = 360;
-		vrLoc = 0;
-	};
 	E1B46F5D04053C4F00050002 = {
 		fRef = E1B46FD904053C5000050002;
@@ -8611,14 +10711,4 @@
 		vrLen = 1558;
 		vrLoc = 1755;
-	};
-	E1B46F5E04053C4F00050002 = {
-		fRef = E1B46FDA04053C5000050002;
-		isa = PBXTextBookmark;
-		name = "NSDictionary.h: 50";
-		rLen = 22;
-		rLoc = 1813;
-		rType = 0;
-		vrLen = 1562;
-		vrLoc = 738;
 	};
 	E1B46F6004053C4F00050002 = {
@@ -9672,10 +11762,4 @@
 		name = NSFont.h;
 		path = /System/Library/Frameworks/AppKit.framework/Versions/C/Headers/NSFont.h;
-		refType = 0;
-	};
-	E1B46FDA04053C5000050002 = {
-		isa = PBXFileReference;
-		name = NSDictionary.h;
-		path = /System/Library/Frameworks/Foundation.framework/Versions/C/Headers/NSDictionary.h;
 		refType = 0;
 	};
@@ -10820,5 +12904,5 @@
 		name = "PSPowerManager.m: 35";
 		rLen = 0;
-		rLoc = 1215;
+		rLoc = 1418;
 		rType = 0;
 		vrLen = 1549;
@@ -10830,5 +12914,5 @@
 		name = "PSPowerManager.m: 34";
 		rLen = 0;
-		rLoc = 1185;
+		rLoc = 1388;
 		rType = 0;
 		vrLen = 1548;
@@ -10840,5 +12924,5 @@
 		name = "PSPowerManager.m: 270";
 		rLen = 0;
-		rLoc = 9118;
+		rLoc = 13021;
 		rType = 0;
 		vrLen = 1300;
@@ -10890,5 +12974,5 @@
 		name = "PSPowerManager.m: notificationPort";
 		rLen = 0;
-		rLoc = 7723;
+		rLoc = 11627;
 		rType = 0;
 		vrLen = 1717;
@@ -10960,8 +13044,4 @@
 		path = /System/Library/Frameworks/Foundation.framework/Versions/C/Headers/NSMethodSignature.h;
 		refType = 0;
-	};
-	E1C6405F03CF0A7A00050002 = {
-		isa = PBXTargetBookmark;
-		trg = 29B97326FDCFA39411CA2CEA;
 	};
 	E1C6406303CF0A7A00050002 = {
@@ -11068,14 +13148,4 @@
 		refType = 0;
 	};
-	E1C6414503C9AC4B001509F3 = {
-		fRef = E130B9AC03B7C59700000028;
-		isa = PBXTextBookmark;
-		name = "PSPowerManager.h: 33";
-		rLen = 0;
-		rLoc = 728;
-		rType = 0;
-		vrLen = 728;
-		vrLoc = 0;
-	};
 	E1C6414703C9AC4B001509F3 = {
 		fRef = E1BF6E9103C928D200050002;
@@ -11093,7 +13163,7 @@
 		name = "PSPowerManager.h: 29";
 		rLen = 136;
-		rLoc = 527;
-		rType = 0;
-		vrLen = 730;
+		rLoc = 682;
+		rType = 0;
+		vrLen = 728;
 		vrLoc = 0;
 	};
@@ -11102,6 +13172,6 @@
 		isa = PBXTextBookmark;
 		name = "PSPowerManager.m: 195";
-		rLen = 36;
-		rLoc = 6749;
+		rLen = 69;
+		rLoc = 10487;
 		rType = 0;
 		vrLen = 1382;
@@ -11113,7 +13183,7 @@
 		name = "PSPowerManager.h: 29";
 		rLen = 136;
-		rLoc = 527;
-		rType = 0;
-		vrLen = 730;
+		rLoc = 682;
+		rType = 0;
+		vrLen = 728;
 		vrLoc = 0;
 	};
@@ -11123,5 +13193,5 @@
 		name = "PSPowerManager.m: 229";
 		rLen = 0;
-		rLoc = 7684;
+		rLoc = 11588;
 		rType = 0;
 		vrLen = 1629;
@@ -11173,5 +13243,5 @@
 		name = "PSTimer.m: 224";
 		rLen = 0;
-		rLoc = 6459;
+		rLoc = 6481;
 		rType = 0;
 		vrLen = 1092;
@@ -11183,5 +13253,5 @@
 		name = "PSPowerManager.m: 223";
 		rLen = 27;
-		rLoc = 7546;
+		rLoc = 11450;
 		rType = 0;
 		vrLen = 1529;
@@ -11193,5 +13263,5 @@
 		name = "PSPowerManager.h: 29";
 		rLen = 0;
-		rLoc = 562;
+		rLoc = 717;
 		rType = 0;
 		vrLen = 728;
@@ -11203,5 +13273,5 @@
 		name = "PSPowerManager.m: 225";
 		rLen = 0;
-		rLoc = 7652;
+		rLoc = 11556;
 		rType = 0;
 		vrLen = 1591;
@@ -12183,4 +14253,110 @@
 		refType = 0;
 	};
+	E1DC3E39041F2CF600050002 = {
+		fRef = E1DC3E48041F2CF600050002;
+		isa = PBXTextBookmark;
+		name = "NSFileManager.h: 32";
+		rLen = 7;
+		rLoc = 1066;
+		rType = 0;
+		vrLen = 1827;
+		vrLoc = 2935;
+	};
+	E1DC3E3B041F2CF600050002 = {
+		fRef = E1DC3E47041F2CF600050002;
+		isa = PBXTextBookmark;
+		name = "unistd.h: 112";
+		rLen = 28;
+		rLoc = 4659;
+		rType = 0;
+		vrLen = 1343;
+		vrLoc = 3928;
+	};
+	E1DC3E3E041F2CF600050002 = {
+		isa = PBXTargetBookmark;
+		trg = 29B97326FDCFA39411CA2CEA;
+	};
+	E1DC3E3F041F2CF600050002 = {
+		fRef = E130B9AD03B7C59700000028;
+		isa = PBXTextBookmark;
+		name = "PSPowerManager.m: setWakeInterval:";
+		rLen = 0;
+		rLoc = 10486;
+		rType = 0;
+		vrLen = 1499;
+		vrLoc = 5994;
+	};
+	E1DC3E40041F2CF600050002 = {
+		fRef = E1DC3E31041F27DA00050002;
+		isa = PBXTextBookmark;
+		name = "wakein.h: 10";
+		rLen = 0;
+		rLoc = 225;
+		rType = 0;
+		vrLen = 169;
+		vrLoc = 0;
+	};
+	E1DC3E41041F2CF600050002 = {
+		fRef = E14A56ED041DD82F00050002;
+		isa = PBXTextBookmark;
+		name = "wakein.m: __VERSION__";
+		rLen = 0;
+		rLoc = 0;
+		rType = 0;
+		vrLen = 784;
+		vrLoc = 0;
+	};
+	E1DC3E42041F2CF600050002 = {
+		fRef = E1DC3E31041F27DA00050002;
+		isa = PBXTextBookmark;
+		name = "wakein.h: 11";
+		rLen = 0;
+		rLoc = 225;
+		rType = 0;
+		vrLen = 241;
+		vrLoc = 0;
+	};
+	E1DC3E43041F2CF600050002 = {
+		fRef = E14A56ED041DD82F00050002;
+		isa = PBXTextBookmark;
+		name = "wakein.m: __OBJC__";
+		rLen = 0;
+		rLoc = 168;
+		rType = 0;
+		vrLen = 890;
+		vrLoc = 0;
+	};
+	E1DC3E44041F2CF600050002 = {
+		fRef = E1DC3E31041F27DA00050002;
+		isa = PBXTextBookmark;
+		name = "wakein.h: 12";
+		rLen = 0;
+		rLoc = 225;
+		rType = 0;
+		vrLen = 241;
+		vrLoc = 0;
+	};
+	E1DC3E45041F2CF600050002 = {
+		fRef = E14A56ED041DD82F00050002;
+		isa = PBXTextBookmark;
+		name = "wakein.m: __OBJC__";
+		rLen = 0;
+		rLoc = 168;
+		rType = 0;
+		vrLen = 833;
+		vrLoc = 0;
+	};
+	E1DC3E47041F2CF600050002 = {
+		isa = PBXFileReference;
+		name = unistd.h;
+		path = /usr/include/unistd.h;
+		refType = 0;
+	};
+	E1DC3E48041F2CF600050002 = {
+		isa = PBXFileReference;
+		name = NSFileManager.h;
+		path = /System/Library/Frameworks/Foundation.framework/Versions/C/Headers/NSFileManager.h;
+		refType = 0;
+	};
 	E1DEF0FD03FE9F7C00050002 = {
 		fRef = E1DEF0FA03FE9F2C00050002;
@@ -12258,14 +14434,4 @@
 		vrLoc = 22427;
 	};
-	E1DEF13404003A5F00050002 = {
-		fRef = E1DEF32004003A6000050002;
-		isa = PBXTextBookmark;
-		name = "NSCalendarDate.h: 27";
-		rLen = 0;
-		rLoc = 928;
-		rType = 0;
-		vrLen = 1405;
-		vrLoc = 622;
-	};
 	E1DEF13704003A5F00050002 = {
 		fRef = E17F2F4303FDF67700050002;
@@ -12408,24 +14574,4 @@
 		vrLoc = 1492;
 	};
-	E1DEF15404003A5F00050002 = {
-		fRef = E1DEF31D04003A6000050002;
-		isa = PBXTextBookmark;
-		name = "NSDate.h: 22";
-		rLen = 40;
-		rLoc = 408;
-		rType = 0;
-		vrLen = 846;
-		vrLoc = 0;
-	};
-	E1DEF15B04003A5F00050002 = {
-		fRef = E1BF6E9003C928D200050002;
-		isa = PBXTextBookmark;
-		name = "PSTimer.h: 30";
-		rLen = 0;
-		rLoc = 987;
-		rType = 0;
-		vrLen = 1140;
-		vrLoc = 17;
-	};
 	E1DEF15D04003A5F00050002 = {
 		fRef = E1DEF30D04003A6000050002;
@@ -14024,5 +16170,5 @@
 		name = "English: 2";
 		rLen = 0;
-		rLoc = 325;
+		rLoc = 377;
 		rType = 0;
 		vrLen = 356;
@@ -16342,10 +18488,4 @@
 		refType = 0;
 	};
-	E1DEF31D04003A6000050002 = {
-		isa = PBXFileReference;
-		name = NSDate.h;
-		path = /System/Library/Frameworks/Foundation.framework/Versions/C/Headers/NSDate.h;
-		refType = 0;
-	};
 	E1DEF31E04003A6000050002 = {
 		isa = PBXFileReference;
@@ -16358,10 +18498,4 @@
 		name = CFString.h;
 		path = /System/Library/Frameworks/CoreFoundation.framework/Versions/A/Headers/CFString.h;
-		refType = 0;
-	};
-	E1DEF32004003A6000050002 = {
-		isa = PBXFileReference;
-		name = NSCalendarDate.h;
-		path = /System/Library/Frameworks/Foundation.framework/Versions/C/Headers/NSCalendarDate.h;
 		refType = 0;
 	};
@@ -16621,14 +18755,4 @@
 		refType = 0;
 	};
-	E1F7C61A041C5B0000FEF34D = {
-		fRef = E1F7C647041C5B0000FEF34D;
-		isa = PBXTextBookmark;
-		name = "NSBundle.h: 35";
-		rLen = 0;
-		rLoc = 892;
-		rType = 0;
-		vrLen = 1214;
-		vrLoc = 508;
-	};
 	E1F7C61B041C5B0000FEF34D = {
 		fRef = F5B79836035F64F80136A8DD;
@@ -16678,5 +18802,5 @@
 		rLoc = 3103;
 		rType = 0;
-		vrLen = 1479;
+		vrLen = 1416;
 		vrLoc = 1922;
 	};
@@ -16690,14 +18814,4 @@
 		vrLen = 1408;
 		vrLoc = 155;
-	};
-	E1F7C621041C5B0000FEF34D = {
-		fRef = F589C9C6035AA12B0155F4B2;
-		isa = PBXTextBookmark;
-		name = "Read Me.rtfd: 13";
-		rLen = 0;
-		rLoc = 542;
-		rType = 0;
-		vrLen = 2334;
-		vrLoc = 6515;
 	};
 	E1F7C622041C5B0000FEF34D = {
@@ -16738,14 +18852,4 @@
 		vrLoc = 1127;
 	};
-	E1F7C626041C5B0000FEF34D = {
-		fRef = E1BF6E9103C928D200050002;
-		isa = PBXTextBookmark;
-		name = "PSTimer.m: __GNUC__";
-		rLen = 0;
-		rLoc = 0;
-		rType = 0;
-		vrLen = 1502;
-		vrLoc = 1154;
-	};
 	E1F7C627041C5B0000FEF34D = {
 		fRef = F59F6CB50354E7DA01AEEDB1;
@@ -16845,5 +18949,5 @@
 		rLoc = 3103;
 		rType = 0;
-		vrLen = 1479;
+		vrLen = 1416;
 		vrLoc = 1922;
 	};
@@ -17047,10 +19151,4 @@
 		vrLen = 1053;
 		vrLoc = 1518;
-	};
-	E1F7C647041C5B0000FEF34D = {
-		isa = PBXFileReference;
-		name = NSBundle.h;
-		path = /System/Library/Frameworks/Foundation.framework/Versions/C/Headers/NSBundle.h;
-		refType = 0;
 	};
 	E1F7C648041C5B0000FEF34D = {
@@ -17072,5 +19170,15 @@
 		refType = 0;
 	};
-	E1F7C655041C623100FEF34D = {
+	E1F7C656041C623100FEF34D = {
+		fRef = 089C165DFE840E0CC02AAC07;
+		isa = PBXTextBookmark;
+		name = "English: 7";
+		rLen = 0;
+		rLoc = 229;
+		rType = 0;
+		vrLen = 229;
+		vrLoc = 0;
+	};
+	E1F7C658041C623100FEF34D = {
 		fRef = F560E2F10357506401A4E466;
 		isa = PBXTextBookmark;
@@ -17082,5 +19190,5 @@
 		vrLoc = 7442;
 	};
-	E1F7C656041C623100FEF34D = {
+	E1F7C659041C623100FEF34D = {
 		fRef = 089C165DFE840E0CC02AAC07;
 		isa = PBXTextBookmark;
@@ -17092,5 +19200,5 @@
 		vrLoc = 0;
 	};
-	E1F7C657041C623100FEF34D = {
+	E1F7C65A041C623100FEF34D = {
 		fRef = E10E71F4040C335800050002;
 		isa = PBXTextBookmark;
@@ -17101,44 +19209,4 @@
 		vrLen = 1654;
 		vrLoc = 4107;
-	};
-	E1F7C658041C623100FEF34D = {
-		fRef = F560E2F10357506401A4E466;
-		isa = PBXTextBookmark;
-		name = "PSApplication.m: 196";
-		rLen = 0;
-		rLoc = 8250;
-		rType = 0;
-		vrLen = 1793;
-		vrLoc = 7442;
-	};
-	E1F7C659041C623100FEF34D = {
-		fRef = 089C165DFE840E0CC02AAC07;
-		isa = PBXTextBookmark;
-		name = "English: 7";
-		rLen = 0;
-		rLoc = 229;
-		rType = 0;
-		vrLen = 229;
-		vrLoc = 0;
-	};
-	E1F7C65A041C623100FEF34D = {
-		fRef = E10E71F4040C335800050002;
-		isa = PBXTextBookmark;
-		name = "English: 95";
-		rLen = 0;
-		rLoc = 4713;
-		rType = 0;
-		vrLen = 1654;
-		vrLoc = 4107;
-	};
-	E1F7C65B041C623100FEF34D = {
-		fRef = E17F2F4103FDF67700050002;
-		isa = PBXTextBookmark;
-		name = "OACalendarView.m: 839";
-		rLen = 0;
-		rLoc = 34848;
-		rType = 0;
-		vrLen = 1399;
-		vrLoc = 34497;
 	};
 	E1FCECFD03C972CF001509F3 = {
Index: /trunk/Cocoa/Pester/Source/Pester.pbproj/project.pbxproj
===================================================================
--- /trunk/Cocoa/Pester/Source/Pester.pbproj/project.pbxproj	(revision 117)
+++ /trunk/Cocoa/Pester/Source/Pester.pbproj/project.pbxproj	(revision 118)
@@ -53,4 +53,6 @@
 				F59E4BEA036B33EC016B311C,
 				E14DB31203B8038300000028,
+				E14788E3041F3FFC00050002,
+				E14788E8041F40DE00050002,
 			);
 			isa = PBXGroup;
@@ -108,4 +110,5 @@
 				17587328FF379C6511CA2CBB,
 				F562F809037E5D0101AEEDB1,
+				E14A56EB041DD6B600050002,
 			);
 			isa = PBXGroup;
@@ -134,4 +137,5 @@
 			targets = (
 				29B97326FDCFA39411CA2CEA,
+				E14A56EA041DD6B600050002,
 			);
 		};
@@ -154,4 +158,7 @@
 				E19DCBD203BE4AA200B934BF,
 				29B97316FDCFA39411CA2CEA,
+				E14788D4041F2FBD00050002,
+				E1DC3E31041F27DA00050002,
+				E14A56ED041DD82F00050002,
 			);
 			isa = PBXGroup;
@@ -235,4 +242,5 @@
 				29B9732BFDCFA39411CA2CEA,
 				29B9732DFDCFA39411CA2CEA,
+				E11C0975041F1BBD00050002,
 				E130B9A903B7AEED00000028,
 			);
@@ -244,5 +252,5 @@
 				JAVA_COMPILER_DEBUGGING_SYMBOLS = NO;
 				LIBRARY_SEARCH_PATHS = "";
-				OTHER_CFLAGS = "";
+				OTHER_CFLAGS = "-DNDEBUG";
 				PRECOMPILE_PREFIX_HEADER = YES;
 				PREFIX_HEADER = Pester_Prefix.h;
@@ -256,4 +264,5 @@
 			};
 			dependencies = (
+				E11C096E041F1ABF00050002,
 			);
 			isa = PBXApplicationTarget;
@@ -285,5 +294,5 @@
 	<string>1.1b3</string>
 	<key>CFBundleSignature</key>
-	<string>Pstr</string>
+	<string>Pest</string>
 	<key>CFBundleVersion</key>
 	<string>12</string>
@@ -354,4 +363,8 @@
 				E10F2A400402E71400050002,
 				E1B46FEA04057E3400050002,
+				E14788EB041F4F7000050002,
+				E14788F0041F4F7600050002,
+				E14788F2041F4F8900050002,
+				E14788F4041F4F8A00050002,
 			);
 			isa = PBXHeadersBuildPhase;
@@ -438,4 +451,7 @@
 				E10F2A410402E71400050002,
 				E1B46FEB04057E3400050002,
+				E14788F1041F4F7600050002,
+				E14788F3041F4F8900050002,
+				E14788F5041F4F8A00050002,
 			);
 			isa = PBXSourcesBuildPhase;
@@ -458,4 +474,5 @@
 				F59E4C0C036B33EC016B311C,
 				E14DB31303B8038300000028,
+				E14788EA041F4F5400050002,
 			);
 			isa = PBXFrameworksBuildPhase;
@@ -568,4 +585,54 @@
 			};
 		};
+		E11C096E041F1ABF00050002 = {
+			isa = PBXTargetDependency;
+			target = E14A56EA041DD6B600050002;
+		};
+		E11C096F041F1AD600050002 = {
+			fileRef = E14A56ED041DD82F00050002;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		E11C0971041F1ADA00050002 = {
+			fileRef = E130B9AD03B7C59700000028;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		E11C0972041F1ADB00050002 = {
+			fileRef = E130B9AC03B7C59700000028;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		E11C0973041F1B1900050002 = {
+			fileRef = 29B97325FDCFA39411CA2CEA;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		E11C0974041F1B2300050002 = {
+			fileRef = E14DB31203B8038300000028;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		E11C0975041F1BBD00050002 = {
+			buildActionMask = 2147483647;
+			dstPath = "";
+			dstSubfolderSpec = 6;
+			files = (
+				E11C0976041F1BCA00050002,
+			);
+			isa = PBXCopyFilesBuildPhase;
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		E11C0976041F1BCA00050002 = {
+			fileRef = E14A56EB041DD6B600050002;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
 		E1271F040000012300000028 = {
 			fileRef = E130B9AD03B7C59700000028;
@@ -628,4 +695,281 @@
 			settings = {
 			};
+		};
+		E14788D4041F2FBD00050002 = {
+			children = (
+				E14788DB041F2FF600050002,
+				E14788D9041F2FF600050002,
+				E14788D5041F2FF600050002,
+				E14788D7041F2FF600050002,
+				E14788D6041F2FF600050002,
+				E14788DA041F2FF600050002,
+				E14788D8041F2FF600050002,
+			);
+			isa = PBXGroup;
+			name = MoreSecurity;
+			refType = 4;
+		};
+		E14788D5041F2FF600050002 = {
+			fileEncoding = 30;
+			indentWidth = 4;
+			isa = PBXFileReference;
+			name = MoreCFQ.c;
+			path = MoreSecurity/MoreCFQ.c;
+			refType = 4;
+			tabWidth = 4;
+			usesTabs = 0;
+		};
+		E14788D6041F2FF600050002 = {
+			fileEncoding = 30;
+			indentWidth = 4;
+			isa = PBXFileReference;
+			name = MoreUNIX.c;
+			path = MoreSecurity/MoreUNIX.c;
+			refType = 4;
+			tabWidth = 4;
+			usesTabs = 0;
+		};
+		E14788D7041F2FF600050002 = {
+			fileEncoding = 30;
+			indentWidth = 4;
+			isa = PBXFileReference;
+			name = MoreUNIX.h;
+			path = MoreSecurity/MoreUNIX.h;
+			refType = 4;
+			tabWidth = 4;
+			usesTabs = 0;
+		};
+		E14788D8041F2FF600050002 = {
+			fileEncoding = 30;
+			indentWidth = 4;
+			isa = PBXFileReference;
+			name = MoreSecurity.c;
+			path = MoreSecurity/MoreSecurity.c;
+			refType = 4;
+			tabWidth = 4;
+			usesTabs = 0;
+		};
+		E14788D9041F2FF600050002 = {
+			fileEncoding = 30;
+			indentWidth = 4;
+			isa = PBXFileReference;
+			name = MoreCFQ.h;
+			path = MoreSecurity/MoreCFQ.h;
+			refType = 4;
+			tabWidth = 4;
+			usesTabs = 0;
+		};
+		E14788DA041F2FF600050002 = {
+			fileEncoding = 30;
+			indentWidth = 4;
+			isa = PBXFileReference;
+			name = MoreSecurity.h;
+			path = MoreSecurity/MoreSecurity.h;
+			refType = 4;
+			tabWidth = 4;
+			usesTabs = 0;
+		};
+		E14788DB041F2FF600050002 = {
+			fileEncoding = 30;
+			indentWidth = 4;
+			isa = PBXFileReference;
+			name = MoreSetup.h;
+			path = MoreSecurity/MoreSetup.h;
+			refType = 4;
+			tabWidth = 4;
+			usesTabs = 0;
+		};
+		E14788DC041F2FF600050002 = {
+			fileRef = E14788D5041F2FF600050002;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		E14788DD041F2FF600050002 = {
+			fileRef = E14788D6041F2FF600050002;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		E14788DE041F2FF600050002 = {
+			fileRef = E14788D7041F2FF600050002;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		E14788DF041F2FF600050002 = {
+			fileRef = E14788D8041F2FF600050002;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		E14788E0041F2FF600050002 = {
+			fileRef = E14788D9041F2FF600050002;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		E14788E1041F2FF600050002 = {
+			fileRef = E14788DA041F2FF600050002;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		E14788E2041F2FF600050002 = {
+			fileRef = E14788DB041F2FF600050002;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		E14788E3041F3FFC00050002 = {
+			isa = PBXFrameworkReference;
+			name = Security.framework;
+			path = /System/Library/Frameworks/Security.framework;
+			refType = 0;
+		};
+		E14788E4041F3FFC00050002 = {
+			fileRef = E14788E3041F3FFC00050002;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		E14788E8041F40DE00050002 = {
+			isa = PBXFrameworkReference;
+			name = CoreServices.framework;
+			path = /System/Library/Frameworks/CoreServices.framework;
+			refType = 0;
+		};
+		E14788E9041F40DE00050002 = {
+			fileRef = E14788E8041F40DE00050002;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		E14788EA041F4F5400050002 = {
+			fileRef = E14788E3041F3FFC00050002;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		E14788EB041F4F7000050002 = {
+			fileRef = E14788DB041F2FF600050002;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		E14788F0041F4F7600050002 = {
+			fileRef = E14788DA041F2FF600050002;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		E14788F1041F4F7600050002 = {
+			fileRef = E14788D8041F2FF600050002;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		E14788F2041F4F8900050002 = {
+			fileRef = E14788D9041F2FF600050002;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		E14788F3041F4F8900050002 = {
+			fileRef = E14788D5041F2FF600050002;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		E14788F4041F4F8A00050002 = {
+			fileRef = E14788D7041F2FF600050002;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		E14788F5041F4F8A00050002 = {
+			fileRef = E14788D6041F2FF600050002;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		E14A56E6041DD6B600050002 = {
+			buildActionMask = 2147483647;
+			files = (
+				E11C0972041F1ADB00050002,
+				E1DC3E33041F27DA00050002,
+				E14788DE041F2FF600050002,
+				E14788E0041F2FF600050002,
+				E14788E1041F2FF600050002,
+				E14788E2041F2FF600050002,
+			);
+			isa = PBXHeadersBuildPhase;
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		E14A56E7041DD6B600050002 = {
+			buildActionMask = 2147483647;
+			files = (
+				E11C096F041F1AD600050002,
+				E11C0971041F1ADA00050002,
+				E14788DC041F2FF600050002,
+				E14788DD041F2FF600050002,
+				E14788DF041F2FF600050002,
+			);
+			isa = PBXSourcesBuildPhase;
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		E14A56E8041DD6B600050002 = {
+			buildActionMask = 2147483647;
+			files = (
+				E11C0973041F1B1900050002,
+				E11C0974041F1B2300050002,
+				E14788E4041F3FFC00050002,
+				E14788E9041F40DE00050002,
+			);
+			isa = PBXFrameworksBuildPhase;
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		E14A56E9041DD6B600050002 = {
+			buildActionMask = 2147483647;
+			files = (
+			);
+			isa = PBXRezBuildPhase;
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		E14A56EA041DD6B600050002 = {
+			buildPhases = (
+				E14A56E6041DD6B600050002,
+				E14A56E7041DD6B600050002,
+				E14A56E8041DD6B600050002,
+				E14A56E9041DD6B600050002,
+			);
+			buildSettings = {
+				FRAMEWORK_SEARCH_PATHS = "\"$(SYSTEM_LIBRARY_DIR)/Frameworks/CoreServices.framework/Versions/A/Frameworks\"";
+				OTHER_CFLAGS = "-DWAKEIN";
+				OTHER_LDFLAGS = "";
+				OTHER_REZFLAGS = "";
+				PRODUCT_NAME = wakeinTemplate;
+				REZ_EXECUTABLE = YES;
+				SECTORDER_FLAGS = "";
+				WARNING_CFLAGS = "-Wmost -Wno-four-char-constants -Wno-unknown-pragmas";
+			};
+			dependencies = (
+			);
+			isa = PBXToolTarget;
+			name = wakein;
+			productInstallPath = /usr/local/bin;
+			productName = wakein;
+			productReference = E14A56EB041DD6B600050002;
+		};
+		E14A56EB041DD6B600050002 = {
+			isa = PBXExecutableFileReference;
+			path = wakeinTemplate;
+			refType = 3;
+		};
+		E14A56ED041DD82F00050002 = {
+			fileEncoding = 4;
+			isa = PBXFileReference;
+			path = wakein.m;
+			refType = 4;
 		};
 		E14AFB7703B620FE00000028 = {
@@ -1034,4 +1378,16 @@
 		E1D358BC03C60CE900C8A18E = {
 			fileRef = E1D358BA03C60CE900C8A18E;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		E1DC3E31041F27DA00050002 = {
+			fileEncoding = 4;
+			isa = PBXFileReference;
+			path = wakein.h;
+			refType = 4;
+		};
+		E1DC3E33041F27DA00050002 = {
+			fileRef = E1DC3E31041F27DA00050002;
 			isa = PBXBuildFile;
 			settings = {
Index: /trunk/Cocoa/Pester/Source/wakein.h
===================================================================
--- /trunk/Cocoa/Pester/Source/wakein.h	(revision 117)
+++ /trunk/Cocoa/Pester/Source/wakein.h	(revision 118)
@@ -7,7 +7,4 @@
 //
 
-enum {
-    PSWakeErrorSyntax = 1,
-    PSWakeErrorException = 2,
-    PSWakeErrorPermissions = 3
-};
+#define kPesterWakeTime @"WakeTime"
+#define kPesterWakeException @"WakeException"
Index: /trunk/Cocoa/Pester/Source/wakein.m
===================================================================
--- /trunk/Cocoa/Pester/Source/wakein.m	(revision 117)
+++ /trunk/Cocoa/Pester/Source/wakein.m	(revision 118)
@@ -8,38 +8,68 @@
 
 #import <Cocoa/Cocoa.h>
+#import "PSPowerManager.h"
 #import "wakein.h"
-#import "unistd.h"
-#import "PSPowerManager.h"
 
-void usage() {
-    fprintf(stderr, "usage: wakein secs\n");
-    exit(PSWakeErrorSyntax);
+// System interfaces
+#include <stdio.h>
+#include <unistd.h>
+// MoreIsBetter interfaces
+#include "MoreUNIX.h"
+#include "MoreSecurity.h"
+#include "MoreCFQ.h"
+
+static OSStatus SetAutoWake(AuthorizationRef auth, CFDictionaryRef request, CFDictionaryRef *result) {
+    OSStatus 	err;
+    assert(auth != NULL);
+    assert(request != NULL);
+    assert( result != NULL);
+    assert(*result == NULL);
+    assert(geteuid() == getuid());
+    static const char *kRightName = "net.sabi.Pester.wakein.SetAutoWake";
+    static const AuthorizationFlags kAuthFlags = kAuthorizationFlagDefaults | kAuthorizationFlagInteractionAllowed | kAuthorizationFlagExtendRights;
+    AuthorizationItem   right  = { kRightName, 0, NULL, 0 };
+    AuthorizationRights rights = { 1, &right };
+    err = AuthorizationCopyRights(auth, &rights, kAuthorizationEmptyEnvironment, kAuthFlags, NULL);
+    // sometimes we don't get here via authexec, so ignore this
+    
+    err = MoreSecSetPrivilegedEUID();
+    if (err != noErr) return err;
+    
+    [[NSAutoreleasePool alloc] init];
+
+    NSNumber *wakeTime = [(NSDictionary *)request objectForKey: kPesterWakeTime];
+    NSLog(@"setting wake time: %@", wakeTime);
+    if (wakeTime == nil) return noErr;
+
+    long long secs = [wakeTime unsignedLongLongValue];
+    if (secs < 0 || secs > ULONG_MAX) return paramErr;
+
+    NS_DURING
+        [PSPowerManager setWakeInterval: (unsigned long)secs];
+    NS_HANDLER
+        *result = (CFDictionaryRef)[NSDictionary dictionaryWithObject: [localException description] forKey: kPesterWakeException];
+        return ioErr;
+    NS_ENDHANDLER
+
+    *result = (CFDictionaryRef)[NSDictionary dictionary];
+
+    return noErr;
 }
 
-int main(int argc, const char *argv[])
-{
-    [[NSAutoreleasePool alloc] init];
+int main(int argc, const char *argv[]) {
+    OSStatus err;
+    int result;
+    AuthorizationRef auth;
 
-    if (argc != 2) usage();
+    auth = MoreSecHelperToolCopyAuthRef();
+    err = MoreSecDestroyInheritedEnvironment(kMoreSecKeepStandardFilesMask, argv);
+    if (err == 0) {
+        err = MoreUNIXIgnoreSIGPIPE();
+    }
+    if (err == 0) {
+        err = MoreSecHelperToolMain(STDIN_FILENO, STDOUT_FILENO, auth, SetAutoWake, argc, argv);
+    }
+    result = MoreSecErrorToHelperToolResult(err);
 
-    long long secs;
-    if (![[NSScanner scannerWithString: [NSString stringWithUTF8String: argv[1]]] scanLongLong: &secs])
-        usage();
-
-    if (secs < 0 || secs > ULONG_MAX)
-        usage();
-
-    if (geteuid() != 0) {
-        fprintf(stderr, "wakein: must be root\n");
-        return PSWakeErrorPermissions;
-    }
-
-    NS_DURING
-        [PSPowerManager setWakeInterval: secs];
-    NS_HANDLER
-        fprintf(stderr, "%s\n", [[localException description] UTF8String]);
-        return PSWakeErrorException;
-    NS_ENDHANDLER
-
-    return 0;
+    return result;
 }
