Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Add support for submitting crash reports.

Based on SFBCrashReporter from https://github.com/sbooth/SFBCrashReporter
  • Loading branch information...
commit 967aca5d7574cd37017c53b443eed2aea57f49c1 1 parent c993e92
@martinh martinh authored
View
39 Makefile
@@ -338,8 +338,23 @@ RESOURCES = \
par/par.doc \
Credits.txt
-ifneq ($(CONFIGURATION),DEBUG)
+ifeq ($(CONFIGURATION),BETA)
+CRASH_REPORTER = 1
+endif
+ifeq ($(CONFIGURATION),SNAPSHOT)
+CRASH_REPORTER = 1
+endif
+
+ifeq ($(CRASH_REPORTER),1)
+OBJC_SRCS += \
+ GenerateFormData.m \
+ SFBCrashReporter.m \
+ SFBCrashReporterWindowController.m \
+ SFBSystemInformation.m
+XIBS += SFBCrashReporterWindow.xib
+endif
+ifneq ($(CONFIGURATION),DEBUG)
BUNDLE_USERS = vicoapp textmate kswedberg
BUNDLE_REPOS = $(addprefix $(RESDIR)/,$(addsuffix -bundles.json,$(BUNDLE_USERS)))
.PHONY: $(BUNDLE_REPOS)
@@ -455,18 +470,21 @@ CPPFLAGS = -Iapp -Ijson -Ioniguruma -Iuniversalchardet -I$(DERIVEDDIR) -F. -Iplb
LDFLAGS += -F.
TOOL_LDLIBS = -framework ApplicationServices -framework Foundation
-APP_LDLIBS = -lcrypto -lresolv -lffi -framework Carbon -framework WebKit -framework Cocoa
+APP_LDLIBS = -lcrypto -lresolv -lffi
+APP_FRAMEWORKS = Carbon WebKit Cocoa
PAR_LDLIBS =
XORKEY_LDLIBS =
# Use Sparkle updates for all but release builds
ifneq ($(CONFIGURATION),RELEASE)
CFLAGS += -DUSE_SPARKLE
-FRAMEWORKS = \
- Sparkle.framework
-APP_LDLIBS += -framework Sparkle
-else
-FRAMEWORKS =
+APP_FRAMEWORKS += Sparkle
+endif
+
+# Crash Reporter requires AddressBook framework for getting the users email address
+ifeq ($(CRASH_REPORTER),1)
+APP_FRAMEWORKS += AddressBook
+CFLAGS += -DCRASH_REPORTER=1
endif
# paths
@@ -541,7 +559,9 @@ app: $(NIBS) $(RESOURCES) $(BUNDLE_REPOS) $(INFOPLIST) help $(APPDIR)/Contents/P
dsymutil $(BINDIR)/Vico -o $(BUILDDIR)/Vico.app.dSYM; \
fi
rsync -a --delete --exclude ".git" --exclude ".DS_Store" $(RESOURCES) $(RESDIR)
- if test -n "$(FRAMEWORKS)"; then rsync -a --delete --exclude ".git" --exclude ".DS_Store" $(FRAMEWORKS) $(FWDIR); fi
+ifneq ($(CONFIGURATION),RELEASE)
+ rsync -a --delete --exclude ".git" --exclude ".DS_Store" Sparkle.framework $(FWDIR)
+endif
cp -f app/en.lproj/Credits.rtf $(RESDIR)/en.lproj/Credits.rtf
cp -f app/en.lproj/InfoPlist.strings $(RESDIR)/en.lproj/InfoPlist.strings
# find $(RESDIR)/Bundles \( -iname "*.plist" -or -iname "*.tmCommand" -or -iname "*.tmSnippet" -or -iname "*.tmPreferences" \) -exec /usr/bin/plutil -convert binary1 "{}" \;
@@ -550,6 +570,7 @@ app: $(NIBS) $(RESOURCES) $(BUNDLE_REPOS) $(INFOPLIST) help $(APPDIR)/Contents/P
ifeq ($(CONFIGURATION),RELEASE)
/usr/libexec/PlistBuddy -c "Delete :SUPublicDSAKeyFile" $(INFOPLIST)
/usr/libexec/PlistBuddy -c "Delete :SUFeedURL" $(INFOPLIST)
+ /usr/libexec/PlistBuddy -c "Delete :SFBCrashReporterCrashSubmissionURL" $(INFOPLIST)
endif
binaries: $(OBJDIR)/Vico $(OBJDIR)/vicotool $(OBJDIR)/par
@@ -606,7 +627,7 @@ $(OBJDIR)/NSString-scopeSelector.o: app/scope_selector.h
$(OBJDIR)/Vico: $(OBJS)
mkdir -p $(OBJDIR)
- $(CXX) $(LDFLAGS) $(LDLIBS) $(APP_LDLIBS) $^ -o $@
+ $(CXX) $(LDFLAGS) $(LDLIBS) $(APP_LDLIBS) $(addprefix -framework ,$(APP_FRAMEWORKS)) $^ -o $@
$(OBJDIR)/vicotool: $(TOOL_OBJS)
mkdir -p $(OBJDIR)
View
13 app/GenerateFormData.h
@@ -0,0 +1,13 @@
+/*
+ * Copyright (C) 2009 Stephen F. Booth <me@sbooth.org>
+ * All Rights Reserved
+ */
+
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+// ========================================
+// Generates multipart/form-data from the given dictionary using the specified boundary
+// ========================================
+NSData * GenerateFormData(NSDictionary *formValues, NSString *boundary);
View
57 app/GenerateFormData.m
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2009 Stephen F. Booth <me@sbooth.org>
+ * All Rights Reserved
+ */
+
+#import "GenerateFormData.h"
+
+NSData *
+GenerateFormData(NSDictionary *formValues, NSString *boundary)
+{
+ NSCParameterAssert(nil != formValues);
+ NSCParameterAssert(nil != boundary);
+
+ NSMutableData *result = [[NSMutableData alloc] init];
+
+ // Iterate over the form elements' keys and append their values
+ NSArray *keys = [formValues allKeys];
+ for(NSString *key in keys) {
+ id value = [formValues valueForKey:key];
+
+ [result appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSASCIIStringEncoding]];
+
+ // String value
+ if([value isKindOfClass:[NSString class]]) {
+ NSString *string = (NSString *)value;
+ [result appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n", key] dataUsingEncoding:NSASCIIStringEncoding]];
+ [result appendData:[@"Content-Type: text/plain; charset=utf-8\r\n" dataUsingEncoding:NSASCIIStringEncoding]];
+ [result appendData:[@"\r\n" dataUsingEncoding:NSASCIIStringEncoding]];
+ [result appendData:[string dataUsingEncoding:NSUTF8StringEncoding]];
+ }
+ // Number value
+ else if([value isKindOfClass:[NSNumber class]]) {
+ NSNumber *number = (NSNumber *)value;
+ [result appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n", key] dataUsingEncoding:NSASCIIStringEncoding]];
+ [result appendData:[@"Content-Type: text/plain; charset=utf-8\r\n" dataUsingEncoding:NSASCIIStringEncoding]];
+ [result appendData:[@"\r\n" dataUsingEncoding:NSASCIIStringEncoding]];
+ [result appendData:[[number stringValue] dataUsingEncoding:NSUTF8StringEncoding]];
+ }
+ // URL value (only file URLs are supported)
+ else if([value isKindOfClass:[NSURL class]] && [(NSURL *)value isFileURL]) {
+ NSURL *url = (NSURL *)value;
+ [result appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"\r\n", key, [[url path] lastPathComponent]] dataUsingEncoding:NSASCIIStringEncoding]];
+ [result appendData:[@"Content-Type: application/octet-stream\r\n" dataUsingEncoding:NSASCIIStringEncoding]];
+ [result appendData:[@"\r\n" dataUsingEncoding:NSASCIIStringEncoding]];
+ [result appendData:[NSData dataWithContentsOfURL:url]];
+ }
+ // Illegal class
+ else
+ NSLog(@"SFBCrashReporterError: formValues contained illegal object %@ of class %@", value, [value class]);
+
+ [result appendData:[@"\r\n" dataUsingEncoding:NSASCIIStringEncoding]];
+ }
+
+ [result appendData:[[NSString stringWithFormat:@"--%@--\r\n", boundary] dataUsingEncoding:NSASCIIStringEncoding]];
+
+ return [result autorelease];
+}
View
19 app/SFBCrashReporter.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2009 Stephen F. Booth <me@sbooth.org>
+ * All Rights Reserved
+ */
+
+#import <Cocoa/Cocoa.h>
+
+// ========================================
+// The main interface
+// ========================================
+@interface SFBCrashReporter : NSObject
+{
+}
+
+// Ensure that SFBCrashReporterCrashSubmissionURL is set to a string in either your application's Info.plist
+// or NSUserDefaults and call this
++ (void) checkForNewCrashes;
+
+@end
View
115 app/SFBCrashReporter.m
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2009, 2010 Stephen F. Booth <me@sbooth.org>
+ * All Rights Reserved
+ */
+
+#import "SFBCrashReporter.h"
+#import "SFBCrashReporterWindowController.h"
+
+@interface SFBCrashReporter (Private)
++ (NSArray *) crashLogPaths;
+@end
+
+@implementation SFBCrashReporter
+
++ (void) checkForNewCrashes
+{
+ // If no URL is found for the submission, we can't do anything
+ NSString *crashSubmissionURLString = [[NSUserDefaults standardUserDefaults] stringForKey:@"SFBCrashReporterCrashSubmissionURL"];
+ if(!crashSubmissionURLString) {
+ crashSubmissionURLString = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"SFBCrashReporterCrashSubmissionURL"];
+ if(!crashSubmissionURLString)
+ [NSException raise:@"Missing SFBCrashReporterCrashSubmissionURL" format:@"You must specify the URL for crash log submission as the SFBCrashReporterCrashSubmissionURL in either Info.plist or the user defaults!"];
+ }
+
+ // Determine when the last crash was reported
+ NSDate *lastCrashReportDate = [[NSUserDefaults standardUserDefaults] objectForKey:@"SFBCrashReporterLastCrashReportDate"];
+
+ // If a crash was never reported, use now as the starting point
+ if(!lastCrashReportDate) {
+ lastCrashReportDate = [NSDate date];
+ [[NSUserDefaults standardUserDefaults] setObject:lastCrashReportDate forKey:@"SFBCrashReporterLastCrashReportDate"];
+ }
+
+ // Determine if it is even necessary to show the window (by comparing file modification dates to the last time a crash was reported)
+ NSArray *crashLogPaths = [self crashLogPaths];
+ for(NSString *path in crashLogPaths) {
+ NSDictionary *fileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:[path stringByResolvingSymlinksInPath] error:nil];
+ NSDate *fileModificationDate = [fileAttributes fileModificationDate];
+
+ // If the last time a crash was reported is earlier than the file's modification date, allow the user to report the crash
+ if(NSOrderedAscending == [lastCrashReportDate compare:fileModificationDate]) {
+ [SFBCrashReporterWindowController showWindowForCrashLogPath:path submissionURL:[NSURL URLWithString:crashSubmissionURLString]];
+
+ // Don't prompt more than once
+ break;
+ }
+ }
+}
+
+@end
+
+@implementation SFBCrashReporter (Private)
+
++ (NSArray *) crashLogDirectories
+{
+ // Determine which directories contain crash logs based on the OS version
+ // See http://developer.apple.com/technotes/tn2004/tn2123.html
+
+ // Determine the OS version
+ SInt32 versionMajor = 0;
+ OSErr err = Gestalt(gestaltSystemVersionMajor, &versionMajor);
+ if(noErr != err)
+ NSLog(@"SFBCrashReporter: Unable to determine major system version (%i)", err);
+
+ SInt32 versionMinor = 0;
+ err = Gestalt(gestaltSystemVersionMinor, &versionMinor);
+ if(noErr != err)
+ NSLog(@"SFBCrashReporter: Unable to determine minor system version (%i)", err);
+
+ NSArray *libraryPaths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask | NSLocalDomainMask, YES);
+ NSString *crashLogDirectory = nil;
+
+ // Snow Leopard (10.6) or later
+ // Snow Leopard crash logs are located in ~/Library/Logs/DiagnosticReports with aliases placed in the Leopard location
+ if(10 == versionMajor && 6 <= versionMinor)
+ crashLogDirectory = @"Logs/DiagnosticReports";
+ // Leopard (10.5) or earlier
+ // Leopard crash logs have the form APPNAME_YYYY-MM-DD-hhmm_MACHINE.crash and are located in ~/Library/Logs/CrashReporter
+ else if(10 == versionMajor && 5 >= versionMinor)
+ crashLogDirectory = @"Logs/CrashReporter";
+
+ NSMutableArray *crashFolderPaths = [[NSMutableArray alloc] init];
+
+ for(NSString *libraryPath in libraryPaths) {
+ NSString *path = [libraryPath stringByAppendingPathComponent:crashLogDirectory];
+
+ BOOL isDir = NO;
+ if([[NSFileManager defaultManager] fileExistsAtPath:path isDirectory:&isDir] && isDir) {
+ [crashFolderPaths addObject:path];
+ break;
+ }
+ }
+
+ return [crashFolderPaths autorelease];
+}
+
++ (NSArray *) crashLogPaths
+{
+ NSString *applicationName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleName"];
+ NSArray *crashLogDirectories = [self crashLogDirectories];
+
+ NSMutableArray *paths = [[NSMutableArray alloc] init];
+
+ for(NSString *crashLogDirectory in crashLogDirectories) {
+ NSString *file = nil;
+ NSDirectoryEnumerator *dirEnum = [[NSFileManager defaultManager] enumeratorAtPath:crashLogDirectory];
+ while((file = [dirEnum nextObject]))
+ if([file hasPrefix:applicationName])
+ [paths addObject:[crashLogDirectory stringByAppendingPathComponent:file]];
+ }
+
+ return [paths autorelease];
+}
+
+@end
View
44 app/SFBCrashReporterWindowController.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2009 Stephen F. Booth <me@sbooth.org>
+ * All Rights Reserved
+ */
+
+#import <Cocoa/Cocoa.h>
+
+// ========================================
+// The main class for SFBCrashReporter
+// ========================================
+@interface SFBCrashReporterWindowController : NSWindowController
+{
+ IBOutlet NSTextView *_commentsTextView;
+ IBOutlet NSButton *_reportButton;
+ IBOutlet NSButton *_ignoreButton;
+ IBOutlet NSButton *_discardButton;
+ IBOutlet NSProgressIndicator *_progressIndicator;
+
+@private
+ NSString *_emailAddress;
+ NSString *_crashLogPath;
+ NSURL *_submissionURL;
+
+ NSURLConnection *_urlConnection;
+ NSMutableData *_responseData;
+}
+
+// ========================================
+// Properties
+@property (copy) NSString * emailAddress;
+@property (copy) NSString * crashLogPath;
+@property (copy) NSURL * submissionURL;
+
+// ========================================
+// Always use this to show the window- do not alloc/init directly
++ (void) showWindowForCrashLogPath:(NSString *)path submissionURL:(NSURL *)submissionURL;
+
+// ========================================
+// Action methods
+- (IBAction) sendReport:(id)sender;
+- (IBAction) ignoreReport:(id)sender;
+- (IBAction) discardReport:(id)sender;
+
+@end
View
421 app/SFBCrashReporterWindowController.m
@@ -0,0 +1,421 @@
+/*
+ * Copyright (C) 2009, 2010 Stephen F. Booth <me@sbooth.org>
+ * All Rights Reserved
+ */
+
+#import "SFBCrashReporterWindowController.h"
+#import "SFBSystemInformation.h"
+#import "GenerateFormData.h"
+
+#import <AddressBook/AddressBook.h>
+
+@interface SFBCrashReporterWindowController (Callbacks)
+- (void) showSubmissionSheetDidEnd:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo;
+@end
+
+@interface SFBCrashReporterWindowController (Private)
+- (NSString *) applicationName;
+- (void) sendCrashReport;
+- (void) showSubmissionSucceededSheet;
+- (void) showSubmissionFailedSheet:(NSError *)error;
+@end
+
+@implementation SFBCrashReporterWindowController
+
+@synthesize emailAddress = _emailAddress;
+@synthesize crashLogPath = _crashLogPath;
+@synthesize submissionURL = _submissionURL;
+
++ (void) initialize
+{
+ // Register reasonable defaults for most preferences
+ NSMutableDictionary *defaultsDictionary = [NSMutableDictionary dictionary];
+
+ [defaultsDictionary setObject:[NSNumber numberWithBool:YES] forKey:@"SFBCrashReporterIncludeAnonymousSystemInformation"];
+ [defaultsDictionary setObject:[NSNumber numberWithBool:NO] forKey:@"SFBCrashReporterIncludeEmailAddress"];
+
+ [[NSUserDefaults standardUserDefaults] registerDefaults:defaultsDictionary];
+}
+
++ (void) showWindowForCrashLogPath:(NSString *)crashLogPath submissionURL:(NSURL *)submissionURL
+{
+ NSParameterAssert(nil != crashLogPath);
+ NSParameterAssert(nil != submissionURL);
+
+ SFBCrashReporterWindowController *windowController = [[self alloc] init];
+
+ windowController.crashLogPath = crashLogPath;
+ windowController.submissionURL = submissionURL;
+
+ [[windowController window] center];
+ [windowController showWindow:self];
+
+ [windowController release], windowController = nil;
+}
+
+// Should not be called directly by anyone except this class
+- (id) init
+{
+ return [super initWithWindowNibName:@"SFBCrashReporterWindow" owner:self];
+}
+
+- (void) dealloc
+{
+ [_emailAddress release], _emailAddress = nil;
+ [_crashLogPath release], _crashLogPath = nil;
+ [_submissionURL release], _submissionURL = nil;
+ [_urlConnection release], _urlConnection = nil;
+ [_responseData release], _responseData = nil;
+
+ [super dealloc];
+}
+
+- (void) windowDidLoad
+{
+ [self retain];
+
+ // Set the window's title
+ NSString *applicationName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleName"];
+ NSString *applicationShortVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"];
+
+ NSString *windowTitle;
+ if(!applicationShortVersion)
+ windowTitle = [NSString stringWithFormat:NSLocalizedString(@"Crash Reporter: %@", @""), applicationName];
+ else
+ windowTitle = [NSString stringWithFormat:NSLocalizedString(@"Crash Reporter: %@ (%@)", @""), applicationName, applicationShortVersion];
+
+ [[self window] setTitle:windowTitle];
+
+ // Populate the e-mail field with the user's primary e-mail address
+ ABMultiValue *emailAddresses = [[[ABAddressBook sharedAddressBook] me] valueForProperty:kABEmailProperty];
+ self.emailAddress = (NSString *)[emailAddresses valueForIdentifier:[emailAddresses primaryIdentifier]];
+
+ // Set the font for the comments
+ [_commentsTextView setTypingAttributes:[NSDictionary dictionaryWithObject:[NSFont systemFontOfSize:10.0] forKey:NSFontAttributeName]];
+
+ // Select the comments text
+ [_commentsTextView setSelectedRange:NSMakeRange(0, NSUIntegerMax)];
+}
+
+- (void) windowWillClose:(NSNotification *)notification
+{
+
+#pragma unused(notification)
+
+ // Ensure we don't leak memory
+ [self autorelease];
+}
+
+#pragma mark Action Methods
+
+// Send the report off
+- (IBAction) sendReport:(id)sender
+{
+
+#pragma unused(sender)
+
+ [self sendCrashReport];
+}
+
+// Don't do anything except dismiss our window
+- (IBAction) ignoreReport:(id)sender
+{
+
+#pragma unused(sender)
+
+ [[self window] orderOut:self];
+}
+
+// Move the crash log to the trash since the user isn't interested in submitting it
+- (IBAction) discardReport:(id)sender
+{
+
+#pragma unused(sender)
+
+ // Note: it is odd to use UTF8String here instead of fileSystemRepresentation, but FSPathMakeRef is explicitly
+ // documented to take an UTF-8 C string
+ FSRef ref;
+ OSStatus err = FSPathMakeRef((const UInt8 *)[self.crashLogPath UTF8String], &ref, NULL);
+ if(noErr == err) {
+ err = FSMoveObjectToTrashSync(&ref, NULL, kFSFileOperationDefaultOptions);
+ if(noErr != err)
+ NSLog(@"SFBCrashReporter: Unable to move %@ to trash: %li", self.crashLogPath, (long)err);
+ }
+ else
+ NSLog(@"SFBCrashReporter: Unable to create FSRef for file %@", self.crashLogPath);
+
+ [[self window] orderOut:self];
+}
+
+@end
+
+@implementation SFBCrashReporterWindowController (Callbacks)
+
+- (void) showSubmissionSheetDidEnd:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
+{
+
+#pragma unused(sheet)
+#pragma unused(returnCode)
+#pragma unused(contextInfo)
+
+ // Whether success or failure, all that remains is to close the window
+ [[self window] orderOut:self];
+}
+
+@end
+
+@implementation SFBCrashReporterWindowController (Private)
+
+// Convenience method for bindings
+- (NSString *) applicationName
+{
+ return [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleName"];
+}
+
+// Do the actual work of building the HTTP POST and submitting it
+- (void) sendCrashReport
+{
+ NSMutableDictionary *formValues = [NSMutableDictionary dictionary];
+
+ // Append system information, if specified
+ if([[NSUserDefaults standardUserDefaults] boolForKey:@"SFBCrashReporterIncludeAnonymousSystemInformation"]) {
+ SFBSystemInformation *systemInformation = [[SFBSystemInformation alloc] init];
+
+ id value = nil;
+
+ if((value = [systemInformation machine]))
+ [formValues setObject:value forKey:@"machine"];
+ if((value = [systemInformation model]))
+ [formValues setObject:value forKey:@"model"];
+ if((value = [systemInformation physicalMemory]))
+ [formValues setObject:value forKey:@"physicalMemory"];
+ if((value = [systemInformation numberOfCPUs]))
+ [formValues setObject:value forKey:@"numberOfCPUs"];
+ if((value = [systemInformation busFrequency]))
+ [formValues setObject:value forKey:@"busFrequency"];
+ if((value = [systemInformation CPUFrequency]))
+ [formValues setObject:value forKey:@"CPUFrequency"];
+ if((value = [systemInformation CPUFamily]))
+ [formValues setObject:value forKey:@"CPUFamily"];
+ if((value = [systemInformation modelName]))
+ [formValues setObject:value forKey:@"modelName"];
+ if((value = [systemInformation CPUFamilyName]))
+ [formValues setObject:value forKey:@"CPUFamilyName"];
+ if((value = [systemInformation systemVersion]))
+ [formValues setObject:value forKey:@"systemVersion"];
+ if((value = [systemInformation systemBuildVersion]))
+ [formValues setObject:value forKey:@"systemBuildVersion"];
+
+ [formValues setObject:[NSNumber numberWithBool:YES] forKey:@"systemInformationIncluded"];
+
+ [systemInformation release], systemInformation = nil;
+ }
+ else
+ [formValues setObject:[NSNumber numberWithBool:NO] forKey:@"systemInformationIncluded"];
+
+ // Include email address, if permitted
+ if([[NSUserDefaults standardUserDefaults] boolForKey:@"SFBCrashReporterIncludeEmailAddress"] && self.emailAddress)
+ [formValues setObject:self.emailAddress forKey:@"emailAddress"];
+
+ // Optional comments
+ NSAttributedString *attributedComments = [_commentsTextView attributedSubstringFromRange:NSMakeRange(0, NSUIntegerMax)];
+ if([[attributedComments string] length])
+ [formValues setObject:[attributedComments string] forKey:@"comments"];
+
+ // The most important item of all
+ [formValues setObject:[NSURL fileURLWithPath:self.crashLogPath] forKey:@"crashLog"];
+
+ // Add the application information
+ NSString *applicationName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleName"];
+ if(applicationName)
+ [formValues setObject:applicationName forKey:@"applicationName"];
+
+ NSString *applicationIdentifier = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleIdentifier"];
+ if(applicationIdentifier)
+ [formValues setObject:applicationIdentifier forKey:@"applicationIdentifier"];
+
+ NSString *applicationVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"];
+ if(applicationVersion)
+ [formValues setObject:applicationVersion forKey:@"applicationVersion"];
+
+ NSString *applicationShortVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"];
+ if(applicationShortVersion)
+ [formValues setObject:applicationShortVersion forKey:@"applicationShortVersion"];
+
+ // Create a date formatter
+ [NSDateFormatter setDefaultFormatterBehavior:NSDateFormatterBehavior10_4];
+ NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
+
+ // Determine which locale the developer would like dates/times in
+ NSString *localeName = [[NSUserDefaults standardUserDefaults] stringForKey:@"SFBCrashReporterPreferredReportingLocale"];
+ if(!localeName) {
+ localeName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"SFBCrashReporterPreferredReportingLocale"];
+ // US English is the default
+ if(!localeName)
+ localeName = @"en_US";
+ }
+
+ NSLocale *localeToUse = [[NSLocale alloc] initWithLocaleIdentifier:localeName];
+ [dateFormatter setLocale:localeToUse];
+
+ [dateFormatter setDateStyle:NSDateFormatterMediumStyle];
+ [dateFormatter setTimeStyle:NSDateFormatterMediumStyle];
+
+ // Include the date and time
+ [formValues setObject:[dateFormatter stringFromDate:[NSDate date]] forKey:@"date"];
+
+ [localeToUse release], localeToUse = nil;
+ [dateFormatter release], dateFormatter = nil;
+
+ // Generate the form data
+ NSString *boundary = @"0xKhTmLbOuNdArY";
+ NSData *formData = GenerateFormData(formValues, boundary);
+
+ // Set up the HTTP request
+ NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:self.submissionURL];
+
+ [urlRequest setHTTPMethod:@"POST"];
+
+ NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundary];
+ [urlRequest setValue:contentType forHTTPHeaderField:@"Content-Type"];
+
+ [urlRequest setValue:@"SFBCrashReporter" forHTTPHeaderField:@"User-Agent"];
+ [urlRequest setValue:[NSString stringWithFormat:@"%lu", [formData length]] forHTTPHeaderField:@"Content-Length"];
+
+ [urlRequest setHTTPBody:formData];
+
+ [_progressIndicator startAnimation:self];
+
+ [_reportButton setEnabled:NO];
+ [_ignoreButton setEnabled:NO];
+ [_discardButton setEnabled:NO];
+
+ // Submit the URL request
+ _urlConnection = [[NSURLConnection alloc] initWithRequest:urlRequest delegate:self];
+}
+
+- (void) showSubmissionSucceededSheet
+{
+ [_progressIndicator stopAnimation:self];
+
+ NSBeginAlertSheet(NSLocalizedString(@"The crash report was successfully submitted.", @""),
+ nil /* Use the default button title, */,
+ nil,
+ nil,
+ [self window],
+ self,
+ @selector(showSubmissionSheetDidEnd:returnCode:contextInfo:),
+ NULL,
+ NULL,
+ NSLocalizedString(@"Thank you for taking the time to help improve %@!", @""),
+ [self applicationName]);
+}
+
+- (void) showSubmissionFailedSheet:(NSError *)error
+{
+ NSParameterAssert(nil != error);
+
+ [_progressIndicator stopAnimation:self];
+
+ NSBeginAlertSheet(NSLocalizedString(@"An error occurred while submitting the crash report.", @""),
+ nil /* Use the default button title, */,
+ nil,
+ nil,
+ [self window],
+ self,
+ @selector(showSubmissionSheetDidEnd:returnCode:contextInfo:),
+ NULL,
+ NULL,
+ NSLocalizedString(@"The error was: %@", @""),
+ [error localizedDescription]);
+}
+
+#pragma mark NSTextView delegate methods
+
+- (BOOL) textView:(NSTextView *)textView doCommandBySelector:(SEL)commandSelector;
+{
+ if(commandSelector == @selector(insertTab:)) {
+ [[textView window] selectNextKeyView:self];
+ return YES;
+ }
+ else if(commandSelector == @selector(insertBacktab:)) {
+ [[textView window] selectPreviousKeyView:self];
+ return YES;
+ }
+
+ return NO;
+}
+
+#pragma mark NSURLConnection delegate methods
+
+- (void) connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
+{
+
+#pragma unused(connection)
+#pragma unused(response)
+
+ _responseData = [[NSMutableData alloc] init];
+}
+
+- (void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
+{
+
+#pragma unused(connection)
+
+ [_responseData appendData:data];
+}
+
+- (void) connectionDidFinishLoading:(NSURLConnection *)connection
+{
+
+#pragma unused(connection)
+
+ // A valid response is simply the string 'ok'
+ NSString *responseString = [[NSString alloc] initWithData:_responseData encoding:NSUTF8StringEncoding];
+ BOOL responseOK = [responseString isEqualToString:@"ok"];
+
+ [responseString release], responseString = nil;
+ [_urlConnection release], _urlConnection = nil;
+ [_responseData release], _responseData = nil;
+
+ if(responseOK) {
+ // Create our own instance since this method could be called from a background thread
+ NSFileManager *fileManager = [[NSFileManager alloc] init];
+
+ // Use the file's modification date as the last submitted crash date
+ NSDictionary *fileAttributes = [fileManager attributesOfItemAtPath:[self.crashLogPath stringByResolvingSymlinksInPath] error:nil];
+ NSDate *fileModificationDate = [fileAttributes fileModificationDate];
+
+ [[NSUserDefaults standardUserDefaults] setObject:fileModificationDate forKey:@"SFBCrashReporterLastCrashReportDate"];
+
+ // Delete the crash log since it is no longer needed
+ NSError *error = nil;
+ if(![fileManager removeItemAtPath:self.crashLogPath error:&error])
+ NSLog(@"SFBCrashReporter error: Unable to delete the submitted crash log (%@): %@", [self.crashLogPath lastPathComponent], [error localizedDescription]);
+
+ [fileManager release], fileManager = nil;
+
+ // Even though the log wasn't deleted, submission was still successful
+ [self performSelectorOnMainThread: @selector(showSubmissionSucceededSheet) withObject:nil waitUntilDone:NO];
+ }
+ // An error occurred on the server
+ else {
+ NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys:NSLocalizedString(@"Unrecognized response from the server", @""), NSLocalizedDescriptionKey, nil];
+ NSError *error = [NSError errorWithDomain:NSPOSIXErrorDomain code:EPROTO userInfo:userInfo];
+
+ [self performSelectorOnMainThread: @selector(showSubmissionFailedSheet:) withObject:error waitUntilDone:NO];
+ }
+}
+
+- (void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
+{
+
+#pragma unused(connection)
+
+ [_urlConnection release], _urlConnection = nil;
+ [_responseData release], _responseData = nil;
+
+ [self performSelectorOnMainThread:@selector(showSubmissionFailedSheet:) withObject:error waitUntilDone:NO];
+}
+
+@end
View
32 app/SFBSystemInformation.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2009 Stephen F. Booth <me@sbooth.org>
+ * All Rights Reserved
+ */
+
+#import <Cocoa/Cocoa.h>
+
+// ========================================
+// Utility class for accessing useful system information
+// ========================================
+@interface SFBSystemInformation : NSObject
+{
+}
+
+// Hardware information
+- (NSString *) machine;
+- (NSString *) model;
+- (NSNumber *) numberOfCPUs;
+- (NSNumber *) physicalMemory;
+- (NSNumber *) busFrequency;
+- (NSNumber *) CPUFrequency;
+- (NSNumber *) CPUFamily;
+
+// User-friendly versions
+- (NSString *) modelName;
+- (NSString *) CPUFamilyName;
+
+// Mac OS version information
+- (NSString *) systemVersion;
+- (NSString *) systemBuildVersion;
+
+@end
View
213 app/SFBSystemInformation.m
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2009 Stephen F. Booth <me@sbooth.org>
+ * All Rights Reserved
+ */
+
+#import "SFBSystemInformation.h"
+
+#include <sys/sysctl.h>
+#include <mach/machine.h>
+
+// ========================================
+// Utility functions for common sysctl to Cocoa tasks
+// ========================================
+static NSString * stringForMIB(int *mib, u_int mib_length, NSError **error)
+{
+ NSCParameterAssert(NULL != mib);
+
+ char *buffer = NULL;
+ size_t length = 0;
+
+ // Determine the size of the data
+ if(-1 == sysctl(mib, mib_length, NULL, &length, NULL, 0)) {
+ if(error)
+ *error = [NSError errorWithDomain:NSPOSIXErrorDomain code:errno userInfo:nil];
+ return nil;
+ }
+
+ // Allocate space (includes the terminator)
+ buffer = malloc(length);
+ if(!buffer) {
+ if(error)
+ *error = [NSError errorWithDomain:NSPOSIXErrorDomain code:ENOMEM userInfo:nil];
+ return nil;
+ }
+
+ // Fetch the property
+ if(-1 == sysctl(mib, mib_length, buffer, &length, NULL, 0)) {
+ free(buffer), buffer = NULL;
+ if(error)
+ *error = [NSError errorWithDomain:NSPOSIXErrorDomain code:errno userInfo:nil];
+ return nil;
+ }
+
+ // Ensure the memory is freed if an error occurs
+ NSString *result = [[NSString alloc] initWithBytesNoCopy:buffer length:(length - 1) encoding:NSASCIIStringEncoding freeWhenDone:YES];
+ if(!result) {
+ free(buffer), buffer = NULL;
+ if(error)
+ *error = [NSError errorWithDomain:NSPOSIXErrorDomain code:errno userInfo:nil];
+ return nil;
+ }
+
+ return [result autorelease];
+}
+
+static NSNumber * intForMIB(int *mib, u_int mib_length, NSError **error)
+{
+ NSCParameterAssert(NULL != mib);
+
+ int value = 0;
+ size_t length = sizeof(value);
+
+ // Fetch the property
+ if(-1 == sysctl(mib, mib_length, &value, &length, NULL, 0)) {
+ if(error)
+ *error = [NSError errorWithDomain:NSPOSIXErrorDomain code:errno userInfo:nil];
+ return nil;
+ }
+
+ return [NSNumber numberWithInt:value];
+}
+
+static NSNumber * int64ForMIB(int *mib, u_int mib_length, NSError **error)
+{
+ NSCParameterAssert(NULL != mib);
+
+ int64_t value = 0;
+ size_t length = sizeof(value);
+
+ // Fetch the property
+ if(-1 == sysctl(mib, mib_length, &value, &length, NULL, 0)) {
+ if(error)
+ *error = [NSError errorWithDomain:NSPOSIXErrorDomain code:errno userInfo:nil];
+ return nil;
+ }
+
+ return [NSNumber numberWithLongLong:value];
+}
+
+static NSNumber * int32ForSysctlName(const char *name, NSError **error)
+{
+ NSCParameterAssert(NULL != name);
+
+ int32_t value = 0;
+ size_t length = sizeof(value);
+
+ // Fetch the property
+ if(-1 == sysctlbyname(name, &value, &length, NULL, 0)) {
+ if(error)
+ *error = [NSError errorWithDomain:NSPOSIXErrorDomain code:errno userInfo:nil];
+ return nil;
+ }
+
+ return [NSNumber numberWithLong:value];
+}
+
+static NSNumber * int64ForSysctlName(const char *name, NSError **error)
+{
+ NSCParameterAssert(NULL != name);
+
+ int64_t value = 0;
+ size_t length = sizeof(value);
+
+ // Fetch the property
+ if(-1 == sysctlbyname(name, &value, &length, NULL, 0)) {
+ if(error)
+ *error = [NSError errorWithDomain:NSPOSIXErrorDomain code:errno userInfo:nil];
+ return nil;
+ }
+
+ return [NSNumber numberWithLongLong:value];
+}
+
+@implementation SFBSystemInformation
+
+- (NSString *) machine
+{
+ int mib [] = { CTL_HW, HW_MACHINE };
+ return stringForMIB(mib, 2, NULL);
+}
+
+- (NSString *) model
+{
+ int mib [] = { CTL_HW, HW_MODEL };
+ return stringForMIB(mib, 2, NULL);
+}
+
+- (NSString *) modelName
+{
+ return [self model];
+#if 0
+ NSString *model = [self model];
+ NSString *path = [[NSBundle mainBundle] pathForResource:@"macmodels" ofType:@"plist"];
+ if(model && path) {
+ NSDictionary *models = [NSDictionary dictionaryWithContentsOfFile:path];
+ return [models objectForKey:model];
+ }
+ else
+ return nil;
+#endif
+}
+
+- (NSNumber *) numberOfCPUs
+{
+ int mib [] = { CTL_HW, HW_NCPU };
+ return intForMIB(mib, 2, NULL);
+}
+
+- (NSNumber *) physicalMemory
+{
+ int mib [] = { CTL_HW, HW_MEMSIZE };
+ return int64ForMIB(mib, 2, NULL);
+}
+
+- (NSNumber *) busFrequency
+{
+ return int64ForSysctlName("hw.busfrequency", NULL);
+}
+
+- (NSNumber *) CPUFrequency
+{
+ return int64ForSysctlName("hw.cpufrequency", NULL);
+}
+
+- (NSNumber *) CPUFamily
+{
+ return int32ForSysctlName("hw.cpufamily", NULL);
+}
+
+- (NSString *) CPUFamilyName
+{
+ NSString *familyName = nil;
+ switch([[self CPUFamily] intValue]) {
+ case CPUFAMILY_POWERPC_G3: familyName = NSLocalizedString(@"PowerPC G3", @""); break;
+ case CPUFAMILY_POWERPC_G4: familyName = NSLocalizedString(@"PowerPC G4", @""); break;
+ case CPUFAMILY_POWERPC_G5: familyName = NSLocalizedString(@"PowerPC G5", @""); break;
+ case CPUFAMILY_INTEL_6_13: familyName = NSLocalizedString(@"Intel Core", @""); break;
+ case CPUFAMILY_INTEL_6_14: familyName = NSLocalizedString(@"Intel Core (Yonah)", @""); break;
+ case CPUFAMILY_INTEL_6_15: familyName = NSLocalizedString(@"Intel Core 2 (Merom)", @""); break;
+ case CPUFAMILY_INTEL_6_23: familyName = NSLocalizedString(@"Intel Core 2 (Penryn)", @""); break;
+ case CPUFAMILY_INTEL_6_26: familyName = NSLocalizedString(@"Intel Xeon (Nehalem)", @""); break;
+ case CPUFAMILY_ARM_9: familyName = NSLocalizedString(@"ARM 9", @""); break;
+ case CPUFAMILY_ARM_11: familyName = NSLocalizedString(@"ARM 11", @""); break;
+
+ default: familyName = nil; break;
+ }
+
+ return [[familyName retain] autorelease];
+}
+
+- (NSString *) systemVersion
+{
+ NSDictionary *systemVersionDictionary = [NSDictionary dictionaryWithContentsOfFile:@"/System/Library/CoreServices/SystemVersion.plist"];
+ return [systemVersionDictionary objectForKey:@"ProductVersion"];
+}
+
+- (NSString *) systemBuildVersion
+{
+ NSDictionary *systemVersionDictionary = [NSDictionary dictionaryWithContentsOfFile:@"/System/Library/CoreServices/SystemVersion.plist"];
+ return [systemVersionDictionary objectForKey:@"ProductBuildVersion"];
+}
+
+@end
View
8 app/ViAppController.m
@@ -22,6 +22,9 @@
#ifdef USE_SPARKLE
# import <Sparkle/SUUpdater.h>
#endif
+#ifdef CRASH_REPORTER
+#import "SFBCrashReporter.h"
+#endif
#import "ViFileURLHandler.h"
#import "ViSFTPURLHandler.h"
@@ -222,6 +225,11 @@ - (void)applicationWillFinishLaunching:(NSNotification *)aNotification
[Nu loadNuFile:@"keys" fromBundleWithIdentifier:@"se.bzero.Vico" withContext:nil];
[Nu loadNuFile:@"ex" fromBundleWithIdentifier:@"se.bzero.Vico" withContext:nil];
+#ifdef CRASH_REPORTER
+ [SFBCrashReporter checkForNewCrashes];
+#endif
+
+
#ifdef USE_SPARKLE
[checkForUpdatesMenuItem setAction:@selector(checkForUpdates:)];
[checkForUpdatesMenuItem setTarget:[SUUpdater sharedUpdater]];
View
2  app/Vico-Info.plist
@@ -360,5 +360,7 @@
<string>sparkle_pub.pem</string>
<key>SUFeedURL</key>
<string>http://www.vicoapp.com/appcast.xml</string>
+ <key>SFBCrashReporterCrashSubmissionURL</key>
+ <string>http://crash.vicoapp.com/handle_crash_report.php</string>
</dict>
</plist>
View
1,718 app/en.lproj/SFBCrashReporterWindow.xib
@@ -0,0 +1,1718 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.10">
+ <data>
+ <int key="IBDocument.SystemTarget">1050</int>
+ <string key="IBDocument.SystemVersion">10H574</string>
+ <string key="IBDocument.InterfaceBuilderVersion">823</string>
+ <string key="IBDocument.AppKitVersion">1038.35</string>
+ <string key="IBDocument.HIToolboxVersion">461.00</string>
+ <object class="NSMutableDictionary" key="IBDocument.PluginVersions">
+ <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="NS.object.0">823</string>
+ </object>
+ <object class="NSMutableArray" key="IBDocument.EditedObjectIDs">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ <object class="NSArray" key="IBDocument.PluginDependencies">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ </object>
+ <object class="NSMutableDictionary" key="IBDocument.Metadata">
+ <string key="NS.key.0">PluginDependencyRecalculationVersion</string>
+ <integer value="1" key="NS.object.0"/>
+ </object>
+ <object class="NSMutableArray" key="IBDocument.RootObjects" id="1000">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSCustomObject" id="1001">
+ <string key="NSClassName">SFBCrashReporterWindowController</string>
+ </object>
+ <object class="NSCustomObject" id="1003">
+ <string key="NSClassName">FirstResponder</string>
+ </object>
+ <object class="NSCustomObject" id="1004">
+ <string key="NSClassName">NSApplication</string>
+ </object>
+ <object class="NSWindowTemplate" id="1011234774">
+ <int key="NSWindowStyleMask">1</int>
+ <int key="NSWindowBacking">2</int>
+ <string key="NSWindowRect">{{196, 145}, {453, 365}}</string>
+ <int key="NSWTFlags">603979776</int>
+ <string key="NSWindowTitle">Crash Reporter</string>
+ <string key="NSWindowClass">NSWindow</string>
+ <nil key="NSViewClass"/>
+ <string key="NSWindowContentMaxSize">{3.40282e+38, 3.40282e+38}</string>
+ <object class="NSView" key="NSWindowView" id="1008541481">
+ <reference key="NSNextResponder"/>
+ <int key="NSvFlags">256</int>
+ <object class="NSMutableArray" key="NSSubviews">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSImageView" id="171360428">
+ <reference key="NSNextResponder" ref="1008541481"/>
+ <int key="NSvFlags">268</int>
+ <object class="NSMutableSet" key="NSDragTypes">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="set.sortedObjects">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>Apple PDF pasteboard type</string>
+ <string>Apple PICT pasteboard type</string>
+ <string>Apple PNG pasteboard type</string>
+ <string>NSFilenamesPboardType</string>
+ <string>NeXT Encapsulated PostScript v1.2 pasteboard type</string>
+ <string>NeXT TIFF v4.0 pasteboard type</string>
+ </object>
+ </object>
+ <string key="NSFrame">{{20, 281}, {64, 64}}</string>
+ <reference key="NSSuperview" ref="1008541481"/>
+ <reference key="NSWindow"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSImageCell" key="NSCell" id="207565027">
+ <int key="NSCellFlags">130560</int>
+ <int key="NSCellFlags2">33554432</int>
+ <object class="NSCustomResource" key="NSContents">
+ <string key="NSClassName">NSImage</string>
+ <string key="NSResourceName">NSApplicationIcon</string>
+ </object>
+ <int key="NSAlign">0</int>
+ <int key="NSScale">0</int>
+ <int key="NSStyle">0</int>
+ <bool key="NSAnimates">NO</bool>
+ </object>
+ <bool key="NSEditable">YES</bool>
+ </object>
+ <object class="NSButton" id="308533207">
+ <reference key="NSNextResponder" ref="1008541481"/>
+ <int key="NSvFlags">256</int>
+ <string key="NSFrame">{{18, 106}, {272, 18}}</string>
+ <reference key="NSSuperview" ref="1008541481"/>
+ <reference key="NSWindow"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSButtonCell" key="NSCell" id="520655900">
+ <int key="NSCellFlags">-2080244224</int>
+ <int key="NSCellFlags2">0</int>
+ <string key="NSContents">Include anonymous system information</string>
+ <object class="NSFont" key="NSSupport" id="770087649">
+ <string key="NSName">LucidaGrande</string>
+ <double key="NSSize">13</double>
+ <int key="NSfFlags">1044</int>
+ </object>
+ <reference key="NSControlView" ref="308533207"/>
+ <int key="NSButtonFlags">1211912703</int>
+ <int key="NSButtonFlags2">2</int>
+ <object class="NSButtonImageSource" key="NSAlternateImage" id="781101558">
+ <string key="NSImageName">NSSwitch</string>
+ </object>
+ <string key="NSAlternateContents"/>
+ <string key="NSKeyEquivalent"/>
+ <int key="NSPeriodicDelay">200</int>
+ <int key="NSPeriodicInterval">25</int>
+ </object>
+ </object>
+ <object class="NSTextField" id="857538445">
+ <reference key="NSNextResponder" ref="1008541481"/>
+ <int key="NSvFlags">256</int>
+ <string key="NSFrame">{{17, 256}, {281, 17}}</string>
+ <reference key="NSSuperview" ref="1008541481"/>
+ <reference key="NSWindow"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSTextFieldCell" key="NSCell" id="281384146">
+ <int key="NSCellFlags">67239424</int>
+ <int key="NSCellFlags2">272629760</int>
+ <string key="NSContents">What were you doing when the application crashed?</string>
+ <object class="NSFont" key="NSSupport">
+ <string key="NSName">LucidaGrande</string>
+ <double key="NSSize">11</double>
+ <int key="NSfFlags">3100</int>
+ </object>
+ <reference key="NSControlView" ref="857538445"/>
+ <object class="NSColor" key="NSBackgroundColor" id="228994734">
+ <int key="NSColorSpace">6</int>
+ <string key="NSCatalogName">System</string>
+ <string key="NSColorName">controlColor</string>
+ <object class="NSColor" key="NSColor" id="895313721">
+ <int key="NSColorSpace">3</int>
+ <bytes key="NSWhite">MC42NjY2NjY2ODY1AA</bytes>
+ </object>
+ </object>
+ <object class="NSColor" key="NSTextColor" id="304014618">
+ <int key="NSColorSpace">6</int>
+ <string key="NSCatalogName">System</string>
+ <string key="NSColorName">controlTextColor</string>
+ <object class="NSColor" key="NSColor" id="317317829">
+ <int key="NSColorSpace">3</int>
+ <bytes key="NSWhite">MAA</bytes>
+ </object>
+ </object>
+ </object>
+ </object>
+ <object class="NSTextField" id="791730315">
+ <reference key="NSNextResponder" ref="1008541481"/>
+ <int key="NSvFlags">268</int>
+ <string key="NSFrame">{{137, 58}, {211, 22}}</string>
+ <reference key="NSSuperview" ref="1008541481"/>
+ <reference key="NSWindow"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSTextFieldCell" key="NSCell" id="948496255">
+ <int key="NSCellFlags">-1804468671</int>
+ <int key="NSCellFlags2">272630784</int>
+ <string key="NSContents"/>
+ <reference key="NSSupport" ref="770087649"/>
+ <reference key="NSControlView" ref="791730315"/>
+ <bool key="NSDrawsBackground">YES</bool>
+ <object class="NSColor" key="NSBackgroundColor">
+ <int key="NSColorSpace">6</int>
+ <string key="NSCatalogName">System</string>
+ <string key="NSColorName">textBackgroundColor</string>
+ <object class="NSColor" key="NSColor" id="711590557">
+ <int key="NSColorSpace">3</int>
+ <bytes key="NSWhite">MQA</bytes>
+ </object>
+ </object>
+ <object class="NSColor" key="NSTextColor">
+ <int key="NSColorSpace">6</int>
+ <string key="NSCatalogName">System</string>
+ <string key="NSColorName">textColor</string>
+ <reference key="NSColor" ref="317317829"/>
+ </object>
+ </object>
+ </object>
+ <object class="NSButton" id="591012855">
+ <reference key="NSNextResponder" ref="1008541481"/>
+ <int key="NSvFlags">268</int>
+ <string key="NSFrame">{{343, 12}, {96, 32}}</string>
+ <reference key="NSSuperview" ref="1008541481"/>
+ <reference key="NSWindow"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSButtonCell" key="NSCell" id="455453558">
+ <int key="NSCellFlags">67239424</int>
+ <int key="NSCellFlags2">134217728</int>
+ <string key="NSContents">Report</string>
+ <reference key="NSSupport" ref="770087649"/>
+ <reference key="NSControlView" ref="591012855"/>
+ <int key="NSButtonFlags">-2038284033</int>
+ <int key="NSButtonFlags2">129</int>
+ <string key="NSAlternateContents"/>
+ <string type="base64-UTF8" key="NSKeyEquivalent">DQ</string>
+ <int key="NSPeriodicDelay">200</int>
+ <int key="NSPeriodicInterval">25</int>
+ </object>
+ </object>
+ <object class="NSButton" id="248581071">
+ <reference key="NSNextResponder" ref="1008541481"/>
+ <int key="NSvFlags">268</int>
+ <string key="NSFrame">{{247, 12}, {96, 32}}</string>
+ <reference key="NSSuperview" ref="1008541481"/>
+ <reference key="NSWindow"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSButtonCell" key="NSCell" id="892486541">
+ <int key="NSCellFlags">67239424</int>
+ <int key="NSCellFlags2">134217728</int>
+ <string key="NSContents">Ignore</string>
+ <reference key="NSSupport" ref="770087649"/>
+ <reference key="NSControlView" ref="248581071"/>
+ <int key="NSButtonFlags">-2038284033</int>
+ <int key="NSButtonFlags2">129</int>
+ <string key="NSAlternateContents"/>
+ <string type="base64-UTF8" key="NSKeyEquivalent">Gw</string>
+ <int key="NSPeriodicDelay">200</int>
+ <int key="NSPeriodicInterval">25</int>
+ </object>
+ </object>
+ <object class="NSTextField" id="971799704">
+ <reference key="NSNextResponder" ref="1008541481"/>
+ <int key="NSvFlags">268</int>
+ <string key="NSFrame">{{29, 60}, {103, 17}}</string>
+ <reference key="NSSuperview" ref="1008541481"/>
+ <reference key="NSWindow"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSTextFieldCell" key="NSCell" id="96646874">
+ <int key="NSCellFlags">67239488</int>
+ <int key="NSCellFlags2">272630784</int>
+ <string key="NSContents">E-mail address:</string>
+ <reference key="NSSupport" ref="770087649"/>
+ <reference key="NSControlView" ref="971799704"/>
+ <reference key="NSBackgroundColor" ref="228994734"/>
+ <reference key="NSTextColor" ref="304014618"/>
+ </object>
+ </object>
+ <object class="NSButton" id="1027152778">
+ <reference key="NSNextResponder" ref="1008541481"/>
+ <int key="NSvFlags">268</int>
+ <string key="NSFrame">{{18, 86}, {190, 18}}</string>
+ <reference key="NSSuperview" ref="1008541481"/>
+ <reference key="NSWindow"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSButtonCell" key="NSCell" id="91295116">
+ <int key="NSCellFlags">-2080244224</int>
+ <int key="NSCellFlags2">0</int>
+ <string key="NSContents">Include my e-mail address</string>
+ <reference key="NSSupport" ref="770087649"/>
+ <reference key="NSControlView" ref="1027152778"/>
+ <int key="NSButtonFlags">1211912703</int>
+ <int key="NSButtonFlags2">2</int>
+ <object class="NSCustomResource" key="NSNormalImage">
+ <string key="NSClassName">NSImage</string>
+ <string key="NSResourceName">NSSwitch</string>
+ </object>
+ <reference key="NSAlternateImage" ref="781101558"/>
+ <string key="NSAlternateContents"/>
+ <string key="NSKeyEquivalent"/>
+ <int key="NSPeriodicDelay">200</int>
+ <int key="NSPeriodicInterval">25</int>
+ </object>
+ </object>
+ <object class="NSTextField" id="481714230">
+ <reference key="NSNextResponder" ref="1008541481"/>
+ <int key="NSvFlags">268</int>
+ <string key="NSFrame">{{89, 294}, {344, 51}}</string>
+ <reference key="NSSuperview" ref="1008541481"/>
+ <reference key="NSWindow"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSTextFieldCell" key="NSCell" id="779402884">
+ <int key="NSCellFlags">67239424</int>
+ <int key="NSCellFlags2">272629760</int>
+ <string key="NSContents">APPNAME crashed the last time it was run. Would you like to submit a crash report to the developers?</string>
+ <object class="NSFont" key="NSSupport">
+ <string key="NSName">LucidaGrande-Bold</string>
+ <double key="NSSize">13</double>
+ <int key="NSfFlags">16</int>
+ </object>
+ <reference key="NSControlView" ref="481714230"/>
+ <reference key="NSBackgroundColor" ref="228994734"/>
+ <reference key="NSTextColor" ref="304014618"/>
+ </object>
+ </object>
+ <object class="NSButton" id="426936469">
+ <reference key="NSNextResponder" ref="1008541481"/>
+ <int key="NSvFlags">268</int>
+ <string key="NSFrame">{{14, 12}, {96, 32}}</string>
+ <reference key="NSSuperview" ref="1008541481"/>
+ <reference key="NSWindow"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSButtonCell" key="NSCell" id="523152477">
+ <int key="NSCellFlags">67239424</int>
+ <int key="NSCellFlags2">134217728</int>
+ <string key="NSContents">Discard</string>
+ <reference key="NSSupport" ref="770087649"/>
+ <reference key="NSControlView" ref="426936469"/>
+ <int key="NSButtonFlags">-2038284033</int>
+ <int key="NSButtonFlags2">268435585</int>
+ <string key="NSAlternateContents"/>
+ <string key="NSKeyEquivalent">d</string>
+ <int key="NSPeriodicDelay">200</int>
+ <int key="NSPeriodicInterval">25</int>
+ </object>
+ </object>
+ <object class="NSScrollView" id="39129981">
+ <reference key="NSNextResponder" ref="1008541481"/>
+ <int key="NSvFlags">256</int>
+ <object class="NSMutableArray" key="NSSubviews">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSClipView" id="168425014">
+ <reference key="NSNextResponder" ref="39129981"/>
+ <int key="NSvFlags">2304</int>
+ <object class="NSMutableArray" key="NSSubviews">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSTextView" id="686222272">
+ <reference key="NSNextResponder" ref="168425014"/>
+ <int key="NSvFlags">2322</int>
+ <object class="NSMutableSet" key="NSDragTypes">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="set.sortedObjects">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>Apple HTML pasteboard type</string>
+ <string>Apple PDF pasteboard type</string>
+ <string>Apple PICT pasteboard type</string>
+ <string>Apple PNG pasteboard type</string>
+ <string>Apple URL pasteboard type</string>
+ <string>CorePasteboardFlavorType 0x6D6F6F76</string>
+ <string>NSColor pasteboard type</string>
+ <string>NSFilenamesPboardType</string>
+ <string>NSStringPboardType</string>
+ <string>NeXT Encapsulated PostScript v1.2 pasteboard type</string>
+ <string>NeXT RTFD pasteboard type</string>
+ <string>NeXT Rich Text Format v1.0 pasteboard type</string>
+ <string>NeXT TIFF v4.0 pasteboard type</string>
+ <string>NeXT font pasteboard type</string>
+ <string>NeXT ruler pasteboard type</string>
+ <string>WebURLsWithTitlesPboardType</string>
+ <string>public.url</string>
+ </object>
+ </object>
+ <string key="NSFrameSize">{396, 12}</string>
+ <reference key="NSSuperview" ref="168425014"/>
+ <reference key="NSWindow"/>
+ <object class="NSTextContainer" key="NSTextContainer" id="908270618">
+ <object class="NSLayoutManager" key="NSLayoutManager">
+ <object class="NSTextStorage" key="NSTextStorage">
+ <object class="NSMutableString" key="NSString">
+ <characters key="NS.bytes">Please enter a brief description of the actions which caused the crash.</characters>
+ </object>
+ <object class="NSDictionary" key="NSAttributes">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>NSFont</string>
+ <string>NSParagraphStyle</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSFont">
+ <string key="NSName">LucidaGrande</string>
+ <double key="NSSize">10</double>
+ <int key="NSfFlags">16</int>
+ </object>
+ <object class="NSParagraphStyle">
+ <int key="NSAlignment">4</int>
+ <object class="NSArray" key="NSTabStops">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSTextTab">
+ <double key="NSLocation">28</double>
+ </object>
+ <object class="NSTextTab">
+ <double key="NSLocation">56</double>
+ </object>
+ <object class="NSTextTab">
+ <double key="NSLocation">84</double>
+ </object>
+ <object class="NSTextTab">
+ <double key="NSLocation">112</double>
+ </object>
+ <object class="NSTextTab">
+ <double key="NSLocation">140</double>
+ </object>
+ <object class="NSTextTab">
+ <double key="NSLocation">168</double>
+ </object>
+ <object class="NSTextTab">
+ <double key="NSLocation">196</double>
+ </object>
+ <object class="NSTextTab">
+ <double key="NSLocation">224</double>
+ </object>
+ <object class="NSTextTab">
+ <double key="NSLocation">252</double>
+ </object>
+ <object class="NSTextTab">
+ <double key="NSLocation">280</double>
+ </object>
+ <object class="NSTextTab">
+ <double key="NSLocation">308</double>
+ </object>
+ <object class="NSTextTab">
+ <double key="NSLocation">336</double>
+ </object>
+ </object>
+ </object>
+ </object>
+ </object>
+ <nil key="NSDelegate"/>
+ </object>
+ <object class="NSMutableArray" key="NSTextContainers">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="908270618"/>
+ </object>
+ <int key="NSLMFlags">6</int>
+ <nil key="NSDelegate"/>
+ </object>
+ <reference key="NSTextView" ref="686222272"/>
+ <double key="NSWidth">396</double>
+ <int key="NSTCFlags">1</int>
+ </object>
+ <object class="NSTextViewSharedData" key="NSSharedData">
+ <int key="NSFlags">11235</int>
+ <int key="NSTextCheckingTypes">0</int>
+ <nil key="NSMarkedAttributes"/>
+ <reference key="NSBackgroundColor" ref="711590557"/>
+ <object class="NSDictionary" key="NSSelectedAttributes">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>NSBackgroundColor</string>
+ <string>NSColor</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSColor">
+ <int key="NSColorSpace">6</int>
+ <string key="NSCatalogName">System</string>
+ <string key="NSColorName">selectedTextBackgroundColor</string>
+ <reference key="NSColor" ref="895313721"/>
+ </object>
+ <object class="NSColor">
+ <int key="NSColorSpace">6</int>
+ <string key="NSCatalogName">System</string>
+ <string key="NSColorName">selectedTextColor</string>
+ <reference key="NSColor" ref="317317829"/>
+ </object>
+ </object>
+ </object>
+ <reference key="NSInsertionColor" ref="317317829"/>
+ <object class="NSDictionary" key="NSLinkAttributes">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>NSColor</string>
+ <string>NSUnderline</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSColor">
+ <int key="NSColorSpace">1</int>
+ <bytes key="NSRGB">MCAwIDEAA</bytes>
+ </object>
+ <integer value="1"/>
+ </object>
+ </object>
+ <nil key="NSDefaultParagraphStyle"/>
+ </object>
+ <int key="NSTVFlags">6</int>
+ <string key="NSMaxSize">{809, 1e+07}</string>
+ <string key="NSMinize">{223, 0}</string>
+ <nil key="NSDelegate"/>
+ </object>
+ </object>
+ <string key="NSFrame">{{1, 1}, {396, 116}}</string>
+ <reference key="NSSuperview" ref="39129981"/>
+ <reference key="NSWindow"/>
+ <reference key="NSNextKeyView" ref="686222272"/>
+ <reference key="NSDocView" ref="686222272"/>
+ <reference key="NSBGColor" ref="711590557"/>
+ <object class="NSCursor" key="NSCursor">
+ <string key="NSHotSpot">{4, -5}</string>
+ <int key="NSCursorType">1</int>
+ </object>
+ <int key="NScvFlags">4</int>
+ </object>
+ <object class="NSScroller" id="582856565">
+ <reference key="NSNextResponder" ref="39129981"/>
+ <int key="NSvFlags">256</int>
+ <string key="NSFrame">{{397, 1}, {15, 116}}</string>
+ <reference key="NSSuperview" ref="39129981"/>
+ <reference key="NSWindow"/>
+ <reference key="NSTarget" ref="39129981"/>
+ <string key="NSAction">_doScroller:</string>
+ <double key="NSPercent">0.88549619913101196</double>
+ </object>
+ <object class="NSScroller" id="698223792">
+ <reference key="NSNextResponder" ref="39129981"/>
+ <int key="NSvFlags">-2147483392</int>
+ <string key="NSFrame">{{-100, -100}, {396, 15}}</string>
+ <reference key="NSSuperview" ref="39129981"/>
+ <reference key="NSWindow"/>
+ <int key="NSsFlags">1</int>
+ <reference key="NSTarget" ref="39129981"/>
+ <string key="NSAction">_doScroller:</string>
+ <double key="NSCurValue">1</double>
+ <double key="NSPercent">0.94565218687057495</double>
+ </object>
+ </object>
+ <string key="NSFrame">{{20, 130}, {413, 118}}</string>
+ <reference key="NSSuperview" ref="1008541481"/>
+ <reference key="NSWindow"/>
+ <reference key="NSNextKeyView" ref="168425014"/>
+ <int key="NSsFlags">18</int>
+ <reference key="NSVScroller" ref="582856565"/>
+ <reference key="NSHScroller" ref="698223792"/>
+ <reference key="NSContentView" ref="168425014"/>
+ </object>
+ <object class="NSProgressIndicator" id="827576648">
+ <reference key="NSNextResponder" ref="1008541481"/>
+ <int key="NSvFlags">1292</int>
+ <object class="NSPSMatrix" key="NSDrawMatrix"/>
+ <string key="NSFrame">{{414, 256}, {16, 16}}</string>
+ <reference key="NSSuperview" ref="1008541481"/>
+ <reference key="NSWindow"/>
+ <int key="NSpiFlags">28938</int>
+ <double key="NSMinValue">16</double>
+ <double key="NSMaxValue">100</double>
+ </object>
+ </object>
+ <string key="NSFrameSize">{453, 365}</string>
+ <reference key="NSSuperview"/>
+ <reference key="NSWindow"/>
+ </object>
+ <string key="NSScreenRect">{{0, 0}, {1440, 878}}</string>
+ <string key="NSMaxSize">{3.40282e+38, 3.40282e+38}</string>
+ <string key="NSFrameAutosaveName">SFBCrashReporterWindow</string>
+ </object>
+ <object class="NSUserDefaultsController" id="51142963">
+ <bool key="NSSharedInstance">YES</bool>
+ </object>
+ </object>
+ <object class="IBObjectContainer" key="IBDocument.Objects">
+ <object class="NSMutableArray" key="connectionRecords">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">window</string>
+ <reference key="source" ref="1001"/>
+ <reference key="destination" ref="1011234774"/>
+ </object>
+ <int key="connectionID">35</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBBindingConnection" key="connection">
+ <string key="label">value: emailAddress</string>
+ <reference key="source" ref="791730315"/>
+ <reference key="destination" ref="1001"/>
+ <object class="NSNibBindingConnector" key="connector">
+ <reference key="NSSource" ref="791730315"/>
+ <reference key="NSDestination" ref="1001"/>
+ <string key="NSLabel">value: emailAddress</string>
+ <string key="NSBinding">value</string>
+ <string key="NSKeyPath">emailAddress</string>
+ <int key="NSNibBindingConnectorVersion">2</int>
+ </object>
+ </object>
+ <int key="connectionID">37</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">sendReport:</string>
+ <reference key="source" ref="1001"/>
+ <reference key="destination" ref="591012855"/>
+ </object>
+ <int key="connectionID">53</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">ignoreReport:</string>
+ <reference key="source" ref="1001"/>
+ <reference key="destination" ref="248581071"/>
+ </object>
+ <int key="connectionID">54</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">discardReport:</string>
+ <reference key="source" ref="1001"/>
+ <reference key="destination" ref="426936469"/>
+ </object>
+ <int key="connectionID">55</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBBindingConnection" key="connection">
+ <string key="label">displayPatternValue1: applicationName</string>
+ <reference key="source" ref="481714230"/>
+ <reference key="destination" ref="1001"/>
+ <object class="NSNibBindingConnector" key="connector">
+ <reference key="NSSource" ref="481714230"/>
+ <reference key="NSDestination" ref="1001"/>
+ <string key="NSLabel">displayPatternValue1: applicationName</string>
+ <string key="NSBinding">displayPatternValue1</string>
+ <string key="NSKeyPath">applicationName</string>
+ <object class="NSDictionary" key="NSOptions">
+ <string key="NS.key.0">NSDisplayPattern</string>
+ <string key="NS.object.0">%{value1}@ crashed the last time it was run. Would you like to submit a crash report to the developers?</string>
+ </object>
+ <int key="NSNibBindingConnectorVersion">2</int>
+ </object>
+ </object>
+ <int key="connectionID">59</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">_commentsTextView</string>
+ <reference key="source" ref="1001"/>
+ <reference key="destination" ref="686222272"/>
+ </object>
+ <int key="connectionID">64</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">_progressIndicator</string>
+ <reference key="source" ref="1001"/>
+ <reference key="destination" ref="827576648"/>
+ </object>
+ <int key="connectionID">66</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">_discardButton</string>
+ <reference key="source" ref="1001"/>
+ <reference key="destination" ref="426936469"/>
+ </object>
+ <int key="connectionID">67</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">_ignoreButton</string>
+ <reference key="source" ref="1001"/>
+ <reference key="destination" ref="248581071"/>
+ </object>
+ <int key="connectionID">68</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">_reportButton</string>
+ <reference key="source" ref="1001"/>
+ <reference key="destination" ref="591012855"/>
+ </object>
+ <int key="connectionID">69</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBBindingConnection" key="connection">
+ <string key="label">value: values.SFBCrashReporterIncludeEmailAddress</string>
+ <reference key="source" ref="1027152778"/>
+ <reference key="destination" ref="51142963"/>
+ <object class="NSNibBindingConnector" key="connector">
+ <reference key="NSSource" ref="1027152778"/>
+ <reference key="NSDestination" ref="51142963"/>
+ <string key="NSLabel">value: values.SFBCrashReporterIncludeEmailAddress</string>
+ <string key="NSBinding">value</string>
+ <string key="NSKeyPath">values.SFBCrashReporterIncludeEmailAddress</string>
+ <int key="NSNibBindingConnectorVersion">2</int>
+ </object>
+ </object>
+ <int key="connectionID">80</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBBindingConnection" key="connection">
+ <string key="label">value: values.SFBCrashReporterIncludeAnonymousSystemInformation</string>
+ <reference key="source" ref="308533207"/>
+ <reference key="destination" ref="51142963"/>
+ <object class="NSNibBindingConnector" key="connector">
+ <reference key="NSSource" ref="308533207"/>
+ <reference key="NSDestination" ref="51142963"/>
+ <string key="NSLabel">value: values.SFBCrashReporterIncludeAnonymousSystemInformation</string>
+ <string key="NSBinding">value</string>
+ <string key="NSKeyPath">values.SFBCrashReporterIncludeAnonymousSystemInformation</string>
+ <int key="NSNibBindingConnectorVersion">2</int>
+ </object>
+ </object>
+ <int key="connectionID">82</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBBindingConnection" key="connection">
+ <string key="label">enabled: values.SFBCrashReporterIncludeEmailAddress</string>
+ <reference key="source" ref="791730315"/>
+ <reference key="destination" ref="51142963"/>
+ <object class="NSNibBindingConnector" key="connector">
+ <reference key="NSSource" ref="791730315"/>
+ <reference key="NSDestination" ref="51142963"/>
+ <string key="NSLabel">enabled: values.SFBCrashReporterIncludeEmailAddress</string>
+ <string key="NSBinding">enabled</string>
+ <string key="NSKeyPath">values.SFBCrashReporterIncludeEmailAddress</string>
+ <int key="NSNibBindingConnectorVersion">2</int>
+ </object>
+ </object>
+ <int key="connectionID">84</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">delegate</string>
+ <reference key="source" ref="1011234774"/>
+ <reference key="destination" ref="1001"/>
+ </object>
+ <int key="connectionID">85</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">delegate</string>
+ <reference key="source" ref="686222272"/>
+ <reference key="destination" ref="1001"/>
+ </object>
+ <int key="connectionID">86</int>
+ </object>
+ </object>
+ <object class="IBMutableOrderedSet" key="objectRecords">
+ <object class="NSArray" key="orderedObjects">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBObjectRecord">
+ <int key="objectID">0</int>
+ <object class="NSArray" key="object" id="0">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ <reference key="children" ref="1000"/>
+ <nil key="parent"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">-2</int>
+ <reference key="object" ref="1001"/>
+ <reference key="parent" ref="0"/>
+ <string key="objectName">File's Owner</string>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">-1</int>
+ <reference key="object" ref="1003"/>
+ <reference key="parent" ref="0"/>
+ <string key="objectName">First Responder</string>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">-3</int>
+ <reference key="object" ref="1004"/>
+ <reference key="parent" ref="0"/>
+ <string key="objectName">Application</string>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">1</int>
+ <reference key="object" ref="1011234774"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="1008541481"/>
+ </object>
+ <reference key="parent" ref="0"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">2</int>
+ <reference key="object" ref="1008541481"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="171360428"/>
+ <reference ref="481714230"/>
+ <reference ref="308533207"/>
+ <reference ref="857538445"/>
+ <reference ref="791730315"/>
+ <reference ref="591012855"/>
+ <reference ref="248581071"/>
+ <reference ref="971799704"/>
+ <reference ref="1027152778"/>
+ <reference ref="426936469"/>
+ <reference ref="39129981"/>
+ <reference ref="827576648"/>
+ </object>
+ <reference key="parent" ref="1011234774"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">4</int>
+ <reference key="object" ref="171360428"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="207565027"/>
+ </object>
+ <reference key="parent" ref="1008541481"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">5</int>
+ <reference key="object" ref="207565027"/>
+ <reference key="parent" ref="171360428"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">9</int>
+ <reference key="object" ref="308533207"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="520655900"/>
+ </object>
+ <reference key="parent" ref="1008541481"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">10</int>
+ <reference key="object" ref="857538445"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="281384146"/>
+ </object>
+ <reference key="parent" ref="1008541481"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">11</int>
+ <reference key="object" ref="791730315"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="948496255"/>
+ </object>
+ <reference key="parent" ref="1008541481"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">12</int>
+ <reference key="object" ref="591012855"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="455453558"/>
+ </object>
+ <reference key="parent" ref="1008541481"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">13</int>
+ <reference key="object" ref="248581071"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="892486541"/>
+ </object>
+ <reference key="parent" ref="1008541481"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">16</int>
+ <reference key="object" ref="971799704"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="96646874"/>
+ </object>
+ <reference key="parent" ref="1008541481"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">19</int>
+ <reference key="object" ref="96646874"/>
+ <reference key="parent" ref="971799704"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">21</int>
+ <reference key="object" ref="892486541"/>
+ <reference key="parent" ref="248581071"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">22</int>
+ <reference key="object" ref="455453558"/>
+ <reference key="parent" ref="591012855"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">23</int>
+ <reference key="object" ref="948496255"/>
+ <reference key="parent" ref="791730315"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">24</int>
+ <reference key="object" ref="281384146"/>
+ <reference key="parent" ref="857538445"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">25</int>
+ <reference key="object" ref="520655900"/>
+ <reference key="parent" ref="308533207"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">33</int>
+ <reference key="object" ref="1027152778"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="91295116"/>
+ </object>
+ <reference key="parent" ref="1008541481"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">34</int>
+ <reference key="object" ref="91295116"/>
+ <reference key="parent" ref="1027152778"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">38</int>
+ <reference key="object" ref="481714230"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="779402884"/>
+ </object>
+ <reference key="parent" ref="1008541481"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">39</int>
+ <reference key="object" ref="779402884"/>
+ <reference key="parent" ref="481714230"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">44</int>
+ <reference key="object" ref="426936469"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="523152477"/>
+ </object>
+ <reference key="parent" ref="1008541481"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">45</int>
+ <reference key="object" ref="523152477"/>
+ <reference key="parent" ref="426936469"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">60</int>
+ <reference key="object" ref="39129981"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="582856565"/>
+ <reference ref="698223792"/>
+ <reference ref="686222272"/>
+ </object>
+ <reference key="parent" ref="1008541481"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">61</int>
+ <reference key="object" ref="582856565"/>
+ <reference key="parent" ref="39129981"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">62</int>
+ <reference key="object" ref="698223792"/>
+ <reference key="parent" ref="39129981"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">63</int>
+ <reference key="object" ref="686222272"/>
+ <reference key="parent" ref="39129981"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">65</int>
+ <reference key="object" ref="827576648"/>
+ <reference key="parent" ref="1008541481"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">70</int>
+ <reference key="object" ref="51142963"/>
+ <reference key="parent" ref="0"/>
+ </object>
+ </object>
+ </object>
+ <object class="NSMutableDictionary" key="flattenedProperties">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>-3.IBPluginDependency</string>
+ <string>1.IBEditorWindowLastContentRect</string>
+ <string>1.IBPluginDependency</string>
+ <string>1.IBWindowTemplateEditedContentRect</string>
+ <string>1.NSWindowTemplate.visibleAtLaunch</string>
+ <string>10.IBPluginDependency</string>
+ <string>10.ImportedFromIB2</string>
+ <string>11.IBPluginDependency</string>
+ <string>11.ImportedFromIB2</string>
+ <string>12.IBPluginDependency</string>
+ <string>12.ImportedFromIB2</string>
+ <string>13.IBPluginDependency</string>
+ <string>13.ImportedFromIB2</string>
+ <string>16.IBPluginDependency</string>
+ <string>16.ImportedFromIB2</string>
+ <string>19.IBPluginDependency</string>
+ <string>2.IBPluginDependency</string>
+ <string>21.IBPluginDependency</string>
+ <string>22.IBPluginDependency</string>
+ <string>23.IBPluginDependency</string>
+ <string>24.IBPluginDependency</string>
+ <string>25.IBPluginDependency</string>
+ <string>33.IBPluginDependency</string>
+ <string>34.IBPluginDependency</string>
+ <string>38.IBPluginDependency</string>
+ <string>39.IBPluginDependency</string>
+ <string>4.IBPluginDependency</string>
+ <string>44.IBPluginDependency</string>
+ <string>44.ImportedFromIB2</string>
+ <string>45.IBPluginDependency</string>
+ <string>5.IBPluginDependency</string>
+ <string>60.IBPluginDependency</string>
+ <string>61.IBPluginDependency</string>
+ <string>62.IBPluginDependency</string>
+ <string>63.IBPluginDependency</string>
+ <string>65.IBPluginDependency</string>
+ <string>70.IBPluginDependency</string>
+ <string>9.IBPluginDependency</string>
+ <string>9.ImportedFromIB2</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>{{288, 37}, {453, 365}}</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>{{288, 37}, {453, 365}}</string>
+ <boolean value="YES"/>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <boolean value="YES"/>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <boolean value="YES"/>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <boolean value="YES"/>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <boolean value="YES"/>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <boolean value="YES"/>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <boolean value="YES"/>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.Interf