├── .gitignore ├── .gitmodules ├── Classes ├── AppController.h ├── AppController.m ├── CSManagedRepository.h ├── CSManagedRepository.m ├── CollectionDelegate.h ├── CollectionDelegate.m ├── GithubNotifier_AppDelegate.h ├── GithubNotifier_AppDelegate.m ├── GithubUser.h ├── GithubUser.m ├── GrowlManager.h ├── GrowlManager.m ├── NSWorkspaceHelper.h ├── NSWorkspaceHelper.m ├── NetworkDataDelegate.h ├── NetworkDataDelegate.m ├── NetworkMetaDelegate.h ├── NetworkMetaDelegate.m ├── ObjectDelegate.h ├── ObjectDelegate.m ├── PreferencesWindowController.h ├── PreferencesWindowController.m ├── RepositoriesController.h ├── RepositoriesController.m ├── RepositoriesDelegate.h ├── RepositoriesDelegate.m ├── RepositoryWatchersDelegate.h └── RepositoryWatchersDelegate.m ├── Credits.html ├── English.lproj ├── InfoPlist.strings └── MainMenu.xib ├── GithubNotifier-Info.plist ├── GithubNotifier.xcodeproj ├── project.pbxproj └── project.xcworkspace │ └── contents.xcworkspacedata ├── GithubNotifier_DataModel.xcdatamodeld ├── .xccurrentversion ├── 1-3.xcmappingmodel │ └── xcmapping.xml ├── GithubNotifier_DataModel 3.xcdatamodel │ ├── elements │ └── layout └── GithubNotifier_DataModel.xcdatamodel │ ├── elements │ └── layout ├── GithubNotifier_Prefix.pch ├── Growl Registration Ticket.growlRegDict ├── Interface ├── AccountSetup.xib └── Preferences.xib ├── README.markdown ├── githubnotifier.icns ├── githubnotifier_inactive.png └── main.m /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | 3 | *.pbxuser 4 | *.perspectivev3 5 | *.mode1v3 6 | *.mode2v3 7 | xcuserdata 8 | !default.pbxuser 9 | !default.perspectivev3 10 | !default.mode1v3 11 | !default.mode2v3 12 | 13 | *~.nib 14 | *~.xib 15 | 16 | .DS_Store 17 | d.diff 18 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "EMKeychain"] 2 | path = EMKeychain 3 | url = git://github.com/ctshryock/EMKeychain.git 4 | [submodule "CocoaREST"] 5 | path = CocoaREST 6 | url = git://github.com/ctshryock/CocoaREST.git 7 | -------------------------------------------------------------------------------- /Classes/AppController.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppController.h 3 | // GithubNotifier 4 | // 5 | // Created by Clinton Shryock on 6/11/10. 6 | // Copyright 2010 scary-robot. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class RepositoriesController; 12 | @class GithubUser; 13 | @class GrowlManager; 14 | 15 | @interface AppController : NSObject { 16 | GrowlManager *growlManager; 17 | NSArrayController *repositoryArrayController; 18 | 19 | NSTimer *repeatingTimer; 20 | 21 | RepositoriesController *repositoriesController; 22 | } 23 | 24 | @property (nonatomic, retain) IBOutlet GrowlManager *growlManager; 25 | @property (nonatomic, retain) IBOutlet NSArrayController *repositoryArrayController; 26 | 27 | 28 | @property (nonatomic, retain) RepositoriesController *repositoriesController; 29 | 30 | @property (assign) NSTimer *repeatingTimer; 31 | 32 | 33 | - (void)run:(NSTimer *)timer; 34 | - (IBAction)showAbout:(id)sender; 35 | 36 | @end 37 | -------------------------------------------------------------------------------- /Classes/AppController.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppController.m 3 | // GithubNotifier 4 | // 5 | // Created by Clinton Shryock on 6/11/10. 6 | // Copyright 2010 scary-robot. All rights reserved. 7 | // 8 | 9 | #import "AppController.h" 10 | #import "NetworkMetaDelegate.h" 11 | #import "NetworkDataDelegate.h" 12 | #import "RepositoriesController.h" 13 | #import "GithubUser.h" 14 | #import "SDGithubTaskManager.h" 15 | 16 | #import "GrowlManager.h" 17 | 18 | @interface AppController (Private) 19 | - (void)resetTimer:(NSNotification *)aNotification; 20 | - (NSTimeInterval)refreshRate; 21 | @end 22 | 23 | @implementation AppController 24 | 25 | @synthesize growlManager; 26 | @synthesize repositoryArrayController; 27 | @synthesize repeatingTimer; 28 | @synthesize repositoriesController; 29 | 30 | 31 | - (id) init 32 | { 33 | self = [super init]; 34 | if (self != nil) { 35 | self.repeatingTimer = nil; 36 | } 37 | return self; 38 | } 39 | 40 | 41 | - (void) awakeFromNib 42 | { 43 | // Listen for when repositories have been merged, then update 44 | [[NSNotificationCenter defaultCenter] addObserver:self 45 | selector:@selector(updateRepositories:) 46 | name:@"RepositoriesMerged" 47 | object:nil]; 48 | 49 | [[NSNotificationCenter defaultCenter] addObserver:self 50 | selector:@selector(updateNetwork:) 51 | name:@"UpdateNetworkForRepository" 52 | object:nil]; 53 | 54 | // Used for new account setup, when app delegate sets up the GithubUser 55 | [[NSNotificationCenter defaultCenter] addObserver:self 56 | selector:@selector(resetTimer:) 57 | name:@"UserSet" 58 | object:nil]; 59 | 60 | // Used for new account setup, when app delegate sets up the GithubUser 61 | [[NSNotificationCenter defaultCenter] addObserver:self 62 | selector:@selector(resetTimer:) 63 | name:@"RefreshRateChanged" 64 | object:nil]; 65 | 66 | } 67 | 68 | - (IBAction)showAbout:(id)sender 69 | { 70 | [NSApp orderFrontStandardAboutPanel:self]; 71 | } 72 | 73 | #pragma mark - 74 | #pragma mark Main Run 75 | - (void)run:(NSTimer *)timer 76 | { 77 | GithubUser *githubUser = [GithubUser sharedInstance]; 78 | 79 | if ([githubUser.username isNotEqualTo:nil]) { 80 | if (!self.repositoriesController) { 81 | self.repositoriesController = [[RepositoriesController alloc] initWithGithubUser:githubUser]; 82 | } 83 | [self.repositoriesController fetchUpdates]; 84 | } 85 | } 86 | 87 | - (void)resetTimer:(NSNotification *)aNotification 88 | { 89 | NSTimer *repeat; 90 | NSDate *fireDate; 91 | NSTimeInterval interval = [self refreshRate]; 92 | if (!self.repeatingTimer) { 93 | NSDate *fireDate = [NSDate dateWithTimeIntervalSinceNow:1.0]; 94 | repeat = [[NSTimer alloc] initWithFireDate:fireDate 95 | interval:interval 96 | target:self 97 | selector:@selector(run:) 98 | userInfo:nil 99 | repeats:YES]; 100 | } else { 101 | [self.repeatingTimer invalidate]; 102 | self.repeatingTimer = nil; 103 | fireDate = [NSDate dateWithTimeIntervalSinceNow:interval]; 104 | repeat = [[NSTimer alloc] initWithFireDate:fireDate 105 | interval:interval 106 | target:self 107 | selector:@selector(run:) 108 | userInfo:nil 109 | repeats:YES]; 110 | } 111 | 112 | NSRunLoop *runLoop = [NSRunLoop currentRunLoop]; 113 | [runLoop addTimer:repeat forMode:NSDefaultRunLoopMode]; 114 | self.repeatingTimer = repeat; 115 | } 116 | 117 | - (NSTimeInterval)refreshRate 118 | { 119 | NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; 120 | NSNumber *refreshRateIndex = [defaults objectForKey:@"RefreshRateIndex"]; 121 | NSTimeInterval refreshRate; 122 | switch ([refreshRateIndex intValue]) { 123 | case 1: 124 | refreshRate = 900; 125 | break; 126 | case 2: 127 | refreshRate = 1800; 128 | break; 129 | case 3: 130 | refreshRate = 3600; 131 | break; 132 | default: 133 | refreshRate = 300; 134 | 135 | } 136 | return refreshRate; 137 | } 138 | /** 139 | * When we're done merging the collection of repositories, adding new ones and pruning old ones, 140 | * we go and grab the nethash value for each 141 | */ 142 | - (void)updateRepositories:(NSNotification *)aNotification 143 | { 144 | GithubUser *githubUser = [GithubUser sharedInstance]; 145 | NSArray *repositories = [self.repositoryArrayController arrangedObjects]; 146 | for (NSManagedObject *repository in repositories) { 147 | SDGithubTaskManager *netHashManager = [[SDGithubTaskManager manager] retain]; 148 | NetworkMetaDelegate *nethashDelegate = [[NetworkMetaDelegate alloc] init]; 149 | 150 | nethashDelegate.parentRepository = repository; 151 | 152 | netHashManager.delegate = nethashDelegate; 153 | netHashManager.successSelector = @selector(githubManager:resultsReadyForTask:); 154 | netHashManager.failSelector = @selector(githubManager:failedForTask:); 155 | netHashManager.maxConcurrentTasks = 3; 156 | netHashManager.username = githubUser.username; 157 | netHashManager.password = githubUser.apiToken; 158 | 159 | SDGithubTask *basicTask = [SDGithubTask taskWithManager:netHashManager]; 160 | basicTask.user = [repository valueForKey:@"owner"]; 161 | basicTask.repo = [repository valueForKey:@"name"]; 162 | basicTask.type = SDGithubTaskNetworkMeta; 163 | [basicTask run]; 164 | } 165 | } 166 | 167 | /** 168 | * When we're done merging the collection of repositories, adding new ones and pruning old ones, 169 | * we go and grab the nethash value for each 170 | */ 171 | - (void)updateNetwork:(NSNotification *)aNotification 172 | { 173 | GithubUser *githubUser = [GithubUser sharedInstance]; 174 | NSManagedObject *repository = [[aNotification userInfo] objectForKey:@"repository"]; 175 | 176 | SDGithubTaskManager *networkDataTaskManager = [[SDGithubTaskManager manager] retain]; 177 | 178 | NetworkDataDelegate *networkDataDelegate = [[NetworkDataDelegate alloc] init]; 179 | 180 | networkDataDelegate.repository = repository; 181 | 182 | networkDataTaskManager.delegate = networkDataDelegate; 183 | networkDataTaskManager.successSelector = @selector(githubManager:resultsReadyForTask:); 184 | networkDataTaskManager.failSelector = @selector(githubManager:failedForTask:); 185 | networkDataTaskManager.maxConcurrentTasks = 3; 186 | networkDataTaskManager.username = githubUser.username; 187 | networkDataTaskManager.password = githubUser.apiToken; 188 | 189 | SDGithubTask *basicTask = [SDGithubTask taskWithManager:networkDataTaskManager]; 190 | basicTask.user = [repository valueForKey:@"owner"]; 191 | basicTask.repo = [repository valueForKey:@"name"]; 192 | basicTask.type = SDGithubTaskNetworkData; 193 | [basicTask run]; 194 | } 195 | @end 196 | -------------------------------------------------------------------------------- /Classes/CSManagedRepository.h: -------------------------------------------------------------------------------- 1 | // 2 | // CSManagedRepository.h 3 | // GithubNotifier 4 | // 5 | // Created by Clint Shryock on 10/3/10. 6 | // Copyright 2010 scary-robot. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | @interface CSManagedRepository : NSManagedObject { 13 | 14 | } 15 | @property (nonatomic, retain) NSNumber * watcherCount; 16 | @property (nonatomic, retain) NSNumber * isFork; 17 | 18 | // Transformable Attributes 19 | @property (nonatomic, retain) NSMutableArray * watcherList; 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /Classes/CSManagedRepository.m: -------------------------------------------------------------------------------- 1 | // 2 | // CSManagedRepository.m 3 | // GithubNotifier 4 | // 5 | // Created by Clint Shryock on 10/3/10. 6 | // Copyright 2010 scary-robot. All rights reserved. 7 | // 8 | 9 | #import "CSManagedRepository.h" 10 | 11 | #import "SDGithubTaskManager.h" 12 | #import "RepositoryWatchersDelegate.h" 13 | #import "GithubUser.h" 14 | 15 | @interface CSManagedRepository (CoreDataGeneratedPrimitiveAccessors) 16 | 17 | - (NSNumber *)primitiveWatcherCount; 18 | - (void)setPrimitiveWatcherCount:(NSNumber *)value; 19 | - (NSNumber *)primitiveIsFork; 20 | - (void)setPrimitiveIsFork:(NSNumber *)value; 21 | - (id)primitiveWatcherList; 22 | - (void)setPrimitiveWatcherList:(id)value; 23 | 24 | @end 25 | 26 | @implementation CSManagedRepository 27 | 28 | @dynamic isFork; 29 | @dynamic watcherCount; 30 | @dynamic watcherList; 31 | 32 | 33 | - (NSNumber *)isFork 34 | { 35 | NSNumber * tmpValue; 36 | 37 | [self willAccessValueForKey:@"isFork"]; 38 | tmpValue = [self primitiveIsFork]; 39 | [self didAccessValueForKey:@"isFork"]; 40 | 41 | return tmpValue; 42 | } 43 | 44 | - (void)setIsFork:(NSNumber *)value 45 | { 46 | [self willChangeValueForKey:@"isFork"]; 47 | [self setPrimitiveIsFork:value]; 48 | [self didChangeValueForKey:@"isFork"]; 49 | } 50 | 51 | - (NSNumber *)watcherCount 52 | { 53 | NSNumber * tmpValue; 54 | 55 | [self willAccessValueForKey:@"watcherCount"]; 56 | tmpValue = [self primitiveWatcherCount]; 57 | [self didAccessValueForKey:@"watcherCount"]; 58 | 59 | return tmpValue; 60 | } 61 | 62 | - (void)setWatcherCount:(NSNumber *)value 63 | { 64 | NSNumber *watcherCount = ([self primitiveWatcherCount]) ? [self primitiveWatcherCount] : [NSNumber numberWithInt:0]; 65 | if (![value isEqualToNumber:watcherCount]) { 66 | GithubUser *githubUser = [GithubUser sharedInstance]; 67 | SDGithubTaskManager *watcherManager = [[SDGithubTaskManager manager] retain]; 68 | RepositoryWatchersDelegate *watcherDelegate = [[RepositoryWatchersDelegate alloc] init]; 69 | 70 | watcherDelegate.parentRepository = self; 71 | 72 | watcherManager.delegate = watcherDelegate; 73 | watcherManager.successSelector = @selector(githubManager:resultsReadyForTask:); 74 | watcherManager.failSelector = @selector(githubManager:failedForTask:); 75 | watcherManager.maxConcurrentTasks = 3; 76 | watcherManager.username = githubUser.username; 77 | watcherManager.password = githubUser.apiToken; 78 | 79 | SDGithubTask *basicTask = [SDGithubTask taskWithManager:watcherManager]; 80 | basicTask.user = [self valueForKey:@"owner"]; 81 | basicTask.repo = [self valueForKey:@"name"]; 82 | basicTask.type = SDGithubTaskGetRepoWatchers; 83 | [basicTask run]; 84 | } 85 | [self willChangeValueForKey:@"watcherCount"]; 86 | [self setPrimitiveWatcherCount:value]; 87 | [self didChangeValueForKey:@"watcherCount"]; 88 | } 89 | 90 | - (BOOL)validateWatcherCount:(id *)valueRef error:(NSError **)outError 91 | { 92 | // Insert custom validation logic here. 93 | return YES; 94 | } 95 | 96 | - (id)watcherList 97 | { 98 | id tmpValue; 99 | 100 | [self willAccessValueForKey:@"watcherList"]; 101 | tmpValue = [self primitiveWatcherList]; 102 | [self didAccessValueForKey:@"watcherList"]; 103 | 104 | return tmpValue; 105 | } 106 | 107 | - (void)setWatcherList:(id)value 108 | { 109 | [self willChangeValueForKey:@"watcherList"]; 110 | [self setPrimitiveWatcherList:value]; 111 | [self didChangeValueForKey:@"watcherList"]; 112 | } 113 | 114 | 115 | @end -------------------------------------------------------------------------------- /Classes/CollectionDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // CollectionDelegate.h 3 | // GithubNotifier 4 | // 5 | // Created by Clint Shryock on 10/5/10. 6 | // Copyright 2010 scary-robot. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "CSManagedRepository.h" 11 | #import "SDGithubTaskManager.h" 12 | #import "GrowlManager.h" 13 | 14 | 15 | @interface CollectionDelegate : NSObject { 16 | NSArray *results; 17 | CSManagedRepository *parentRepository; 18 | } 19 | 20 | @property (copy) NSArray *results; 21 | @property (nonatomic, retain) CSManagedRepository *parentRepository; 22 | 23 | // handle mergine a remote set with our local store 24 | - (NSDictionary *)mergeLocalStore:(NSArray *)local withRemoteResults:(NSArray *)remote; 25 | 26 | @end 27 | -------------------------------------------------------------------------------- /Classes/CollectionDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // CollectionDelegate.m 3 | // GithubNotifier 4 | // 5 | // Created by Clint Shryock on 10/5/10. 6 | // Copyright 2010 scary-robot. All rights reserved. 7 | // 8 | 9 | #import "CollectionDelegate.h" 10 | 11 | 12 | @implementation CollectionDelegate 13 | 14 | @synthesize results; 15 | @synthesize parentRepository; 16 | 17 | - (NSDictionary *)mergeLocalStore:(NSArray *)local withRemoteResults:(NSArray *)remote 18 | { 19 | NSLog(@"merging"); 20 | NSMutableSet *currentSet = [NSMutableSet setWithArray:local]; 21 | NSMutableSet *remoteSet = [NSMutableSet setWithArray:remote]; 22 | 23 | NSMutableDictionary *changes = [NSMutableDictionary dictionaryWithCapacity:2]; 24 | 25 | 26 | // Subtract the current set of repositories on disk from the list 27 | // retrieved from the server. If there are any left over, then 28 | // we've added new repositories since last update 29 | [remoteSet minusSet:currentSet]; 30 | if (0 < [remoteSet count]) { 31 | [changes setObject:[NSNumber numberWithInt:[remoteSet count]] forKey:@"additions"]; 32 | } 33 | 34 | currentSet = [NSMutableSet setWithArray:local]; 35 | remoteSet = [NSMutableSet setWithArray:remote]; 36 | 37 | NSManagedObjectContext *moc = [[NSApp delegate] managedObjectContext]; 38 | [currentSet minusSet:remoteSet]; 39 | if (0 < [currentSet count]) { 40 | [changes setObject:[NSNumber numberWithInt:[currentSet count]] forKey:@"subtractions"]; 41 | for (NSManagedObject *orphan in currentSet) { 42 | [moc deleteObject:orphan]; 43 | } 44 | } 45 | 46 | return changes; 47 | } 48 | 49 | 50 | @end 51 | -------------------------------------------------------------------------------- /Classes/GithubNotifier_AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // GithubNotifier_AppDelegate.h 3 | // GithubNotifier 4 | // 5 | // Created by Clinton Shryock on 6/11/10. 6 | // Copyright scary-robot 2010 . All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class GithubUser; 12 | @class PreferencesWindowController; 13 | 14 | @interface GithubNotifier_AppDelegate : NSObject 15 | { 16 | NSPersistentStoreCoordinator *persistentStoreCoordinator; 17 | NSManagedObjectModel *managedObjectModel; 18 | NSManagedObjectContext *managedObjectContext; 19 | 20 | NSStatusItem *appStatusItem; 21 | 22 | IBOutlet NSMenu *appMenu; 23 | 24 | IBOutlet NSArrayController *repositoryArrayController; 25 | 26 | PreferencesWindowController *preferencesWindowController; 27 | } 28 | 29 | 30 | @property (nonatomic, retain) NSArrayController *repositoryArrayController; 31 | 32 | @property (nonatomic, retain, readonly) NSPersistentStoreCoordinator *persistentStoreCoordinator; 33 | @property (nonatomic, retain, readonly) NSManagedObjectModel *managedObjectModel; 34 | @property (nonatomic, retain, readonly) NSManagedObjectContext *managedObjectContext; 35 | 36 | @property (nonatomic, retain) IBOutlet NSMenu *appMenu; 37 | 38 | @property (nonatomic, retain) PreferencesWindowController *preferencesWindowController; 39 | 40 | - (IBAction)saveAction:sender; 41 | - (IBAction)quitMenuAction:(id)sender; 42 | - (IBAction)showPreferences:(id)sender; 43 | 44 | @end 45 | -------------------------------------------------------------------------------- /Classes/GithubNotifier_AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // GithubNotifier_AppDelegate.m 3 | // GithubNotifier 4 | // 5 | // Created by Clinton Shryock on 6/11/10. 6 | // Copyright scary-robot 2010 . All rights reserved. 7 | // 8 | 9 | #import "GithubNotifier_AppDelegate.h" 10 | #import "GithubUser.h" 11 | #import "PreferencesWindowController.h" 12 | 13 | @implementation GithubNotifier_AppDelegate 14 | 15 | @synthesize appMenu; 16 | @synthesize repositoryArrayController,preferencesWindowController; 17 | 18 | 19 | /** 20 | Returns the support directory for the application, used to store the Core Data 21 | store file. This code uses a directory named "GithubNotifier" for 22 | the content, either in the NSApplicationSupportDirectory location or (if the 23 | former cannot be found), the system's temporary directory. 24 | */ 25 | 26 | - (NSString *)applicationSupportDirectory { 27 | 28 | NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES); 29 | NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : NSTemporaryDirectory(); 30 | return [basePath stringByAppendingPathComponent:@"GithubNotifier"]; 31 | } 32 | 33 | 34 | /** 35 | Creates, retains, and returns the managed object model for the application 36 | by merging all of the models found in the application bundle. 37 | */ 38 | 39 | - (NSManagedObjectModel *)managedObjectModel { 40 | 41 | if (managedObjectModel) return managedObjectModel; 42 | 43 | managedObjectModel = [[NSManagedObjectModel mergedModelFromBundles:nil] retain]; 44 | return managedObjectModel; 45 | } 46 | 47 | 48 | /** 49 | Returns the persistent store coordinator for the application. This 50 | implementation will create and return a coordinator, having added the 51 | store for the application to it. (The directory for the store is created, 52 | if necessary.) 53 | */ 54 | 55 | - (NSPersistentStoreCoordinator *) persistentStoreCoordinator { 56 | 57 | if (persistentStoreCoordinator) return persistentStoreCoordinator; 58 | 59 | NSManagedObjectModel *mom = [self managedObjectModel]; 60 | if (!mom) { 61 | NSAssert(NO, @"Managed object model is nil"); 62 | NSLog(@"%@:%s No model to generate a store from", [self class], _cmd); 63 | return nil; 64 | } 65 | 66 | NSFileManager *fileManager = [NSFileManager defaultManager]; 67 | NSString *applicationSupportDirectory = [self applicationSupportDirectory]; 68 | NSError *error = nil; 69 | 70 | if ( ![fileManager fileExistsAtPath:applicationSupportDirectory isDirectory:NULL] ) { 71 | if (![fileManager createDirectoryAtPath:applicationSupportDirectory withIntermediateDirectories:NO attributes:nil error:&error]) { 72 | NSAssert(NO, ([NSString stringWithFormat:@"Failed to create App Support directory %@ : %@", applicationSupportDirectory,error])); 73 | NSLog(@"Error creating application support directory at %@ : %@",applicationSupportDirectory,error); 74 | return nil; 75 | } 76 | } 77 | 78 | NSURL *url = [NSURL fileURLWithPath: [applicationSupportDirectory stringByAppendingPathComponent: @"storedata"]]; 79 | persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: mom]; 80 | NSDictionary *optionsDictionary = 81 | [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] 82 | forKey:NSMigratePersistentStoresAutomaticallyOption]; 83 | if (![persistentStoreCoordinator addPersistentStoreWithType:NSXMLStoreType 84 | configuration:nil 85 | URL:url 86 | options:optionsDictionary 87 | error:&error]){ 88 | [[NSApplication sharedApplication] presentError:error]; 89 | [persistentStoreCoordinator release], persistentStoreCoordinator = nil; 90 | return nil; 91 | } 92 | 93 | return persistentStoreCoordinator; 94 | } 95 | 96 | /** 97 | Returns the managed object context for the application (which is already 98 | bound to the persistent store coordinator for the application.) 99 | */ 100 | 101 | - (NSManagedObjectContext *) managedObjectContext { 102 | 103 | if (managedObjectContext) return managedObjectContext; 104 | 105 | NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator]; 106 | if (!coordinator) { 107 | NSMutableDictionary *dict = [NSMutableDictionary dictionary]; 108 | [dict setValue:@"Failed to initialize the store" forKey:NSLocalizedDescriptionKey]; 109 | [dict setValue:@"There was an error building up the data file." forKey:NSLocalizedFailureReasonErrorKey]; 110 | NSError *error = [NSError errorWithDomain:@"YOUR_ERROR_DOMAIN" code:9999 userInfo:dict]; 111 | [[NSApplication sharedApplication] presentError:error]; 112 | return nil; 113 | } 114 | managedObjectContext = [[NSManagedObjectContext alloc] init]; 115 | [managedObjectContext setPersistentStoreCoordinator: coordinator]; 116 | 117 | return managedObjectContext; 118 | } 119 | 120 | /** 121 | Returns the NSUndoManager for the application. In this case, the manager 122 | returned is that of the managed object context for the application. 123 | */ 124 | 125 | - (NSUndoManager *)windowWillReturnUndoManager:(NSWindow *)window { 126 | return [[self managedObjectContext] undoManager]; 127 | } 128 | 129 | 130 | /** 131 | Performs the save action for the application, which is to send the save: 132 | message to the application's managed object context. Any encountered errors 133 | are presented to the user. 134 | */ 135 | 136 | - (IBAction) saveAction:(id)sender { 137 | 138 | NSError *error = nil; 139 | 140 | if (![[self managedObjectContext] commitEditing]) { 141 | NSLog(@"%@:%s unable to commit editing before saving", [self class], _cmd); 142 | } 143 | 144 | if (![[self managedObjectContext] save:&error]) { 145 | [[NSApplication sharedApplication] presentError:error]; 146 | } 147 | } 148 | 149 | 150 | /** 151 | Implementation of the applicationShouldTerminate: method, used here to 152 | handle the saving of changes in the application managed object context 153 | before the application terminates. 154 | */ 155 | 156 | - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender { 157 | 158 | if (!managedObjectContext) return NSTerminateNow; 159 | 160 | if (![managedObjectContext commitEditing]) { 161 | return NSTerminateCancel; 162 | } 163 | 164 | if (![managedObjectContext hasChanges]) return NSTerminateNow; 165 | 166 | NSError *error = nil; 167 | if (![managedObjectContext save:&error]) { 168 | 169 | // This error handling simply presents error information in a panel with an 170 | // "Ok" button, which does not include any attempt at error recovery (meaning, 171 | // attempting to fix the error.) As a result, this implementation will 172 | // present the information to the user and then follow up with a panel asking 173 | // if the user wishes to "Quit Anyway", without saving the changes. 174 | 175 | // Typically, this process should be altered to include application-specific 176 | // recovery steps. 177 | 178 | BOOL result = [sender presentError:error]; 179 | if (result) return NSTerminateCancel; 180 | 181 | NSString *question = NSLocalizedString(@"Could not save changes while quitting. Quit anyway?", @"Quit without saves error question message"); 182 | NSString *info = NSLocalizedString(@"Quitting now will lose any changes you have made since the last successful save", @"Quit without saves error question info"); 183 | NSString *quitButton = NSLocalizedString(@"Quit anyway", @"Quit anyway button title"); 184 | NSString *cancelButton = NSLocalizedString(@"Cancel", @"Cancel button title"); 185 | NSAlert *alert = [[NSAlert alloc] init]; 186 | [alert setMessageText:question]; 187 | [alert setInformativeText:info]; 188 | [alert addButtonWithTitle:quitButton]; 189 | [alert addButtonWithTitle:cancelButton]; 190 | 191 | NSInteger answer = [alert runModal]; 192 | [alert release]; 193 | alert = nil; 194 | 195 | if (answer == NSAlertAlternateReturn) return NSTerminateCancel; 196 | 197 | } 198 | 199 | return NSTerminateNow; 200 | } 201 | 202 | 203 | /** 204 | Implementation of dealloc, to release the retained variables. 205 | */ 206 | 207 | - (void)dealloc { 208 | 209 | [managedObjectContext release]; 210 | [persistentStoreCoordinator release]; 211 | [managedObjectModel release]; 212 | 213 | [super dealloc]; 214 | } 215 | 216 | #pragma mark - 217 | #pragma mark Setup 218 | - (void)applicationDidFinishLaunching:(NSNotification *)aNotification 219 | { 220 | // register defaults, refresh rate to 30 minutes 221 | NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; 222 | NSMutableDictionary *appDefaults = [NSMutableDictionary 223 | dictionaryWithObject:[NSNumber numberWithInt:2] 224 | forKey:@"RefreshRateIndex"]; 225 | [appDefaults setValue:NO forKey:@"openAtLogin"]; 226 | 227 | [defaults registerDefaults:appDefaults]; 228 | 229 | NSStatusBar *bar = [NSStatusBar systemStatusBar]; 230 | 231 | appStatusItem = [bar statusItemWithLength:NSVariableStatusItemLength]; 232 | [appStatusItem retain]; 233 | 234 | // [appStatusItem setTitle:@"GH"]; 235 | [appStatusItem setImage:[NSImage imageNamed:@"githubnotifier_inactive.png"]]; 236 | [appStatusItem setHighlightMode:YES]; 237 | [appStatusItem setTarget:self]; 238 | [appStatusItem setMenu:self.appMenu]; 239 | 240 | GithubUser *githubUser = [GithubUser sharedInstance]; 241 | if (githubUser.username == nil) { 242 | PreferencesWindowController *preferencesController = [[PreferencesWindowController alloc] initWithWindowNibName:@"AccountSetup"]; 243 | [[preferencesController window] setLevel:NSModalPanelWindowLevel]; 244 | [preferencesController showWindow:nil]; 245 | } else { 246 | [[NSNotificationCenter defaultCenter] postNotificationName:@"UserSet" 247 | object:self 248 | userInfo:nil]; 249 | } 250 | } 251 | 252 | #pragma mark - 253 | #pragma mark Menu Actions 254 | - (IBAction)quitMenuAction:(id)sender 255 | { 256 | /** 257 | * Write Github User name to NSUserDefaults 258 | */ 259 | GithubUser *githubUser = [GithubUser sharedInstance]; 260 | [githubUser saveToDefaults]; 261 | [self applicationShouldTerminate:sender]; 262 | [NSApp terminate:self]; 263 | } 264 | 265 | - (IBAction)showPreferences:(id)sender 266 | { 267 | self.preferencesWindowController = [[PreferencesWindowController alloc] initWithWindowNibName:@"Preferences"]; 268 | 269 | [NSApp activateIgnoringOtherApps: YES]; 270 | [[self.preferencesWindowController window] makeKeyWindow]; 271 | 272 | } 273 | @end 274 | -------------------------------------------------------------------------------- /Classes/GithubUser.h: -------------------------------------------------------------------------------- 1 | // 2 | // GithubUser.h 3 | // GithubNotifier 4 | // 5 | // Created by Clinton Shryock on 6/11/10. 6 | // Copyright 2010 scary-robot. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | @interface GithubUser : NSObject { 13 | NSString *username; 14 | NSString *apiToken; 15 | } 16 | 17 | @property (copy) NSString *username; 18 | @property (copy) NSString *apiToken; 19 | 20 | 21 | + (GithubUser *)sharedInstance; 22 | 23 | - (BOOL)saveToDefaults; 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /Classes/GithubUser.m: -------------------------------------------------------------------------------- 1 | // 2 | // GithubUser.m 3 | // GithubNotifier 4 | // 5 | // Created by Clinton Shryock on 6/11/10. 6 | // Copyright 2010 scary-robot. All rights reserved. 7 | // 8 | 9 | #import "GithubUser.h" 10 | #import "EMKeychain.h" 11 | 12 | static GithubUser *sharedInstance = nil; 13 | 14 | @implementation GithubUser 15 | 16 | @synthesize username; 17 | @synthesize apiToken; 18 | 19 | - (id) init 20 | { 21 | self = [super init]; 22 | if (self != nil) { 23 | self.apiToken = nil; 24 | self.username = nil; 25 | NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; 26 | self.username = [defaults stringForKey:@"GithubNotifierUsername"]; 27 | } 28 | 29 | return self; 30 | } 31 | 32 | - (BOOL)saveToDefaults 33 | { 34 | NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; 35 | [defaults setObject:self.username forKey:@"GithubNotifierUsername"]; 36 | 37 | return YES; 38 | } 39 | 40 | - (void)setApiToken:(NSString *)aToken 41 | { 42 | EMGenericKeychainItem *keychainItem = [EMGenericKeychainItem genericKeychainItemForService:@"com.scary-robot.GithubNotifier" 43 | withUsername:self.username]; 44 | if(!keychainItem) { 45 | [EMGenericKeychainItem addGenericKeychainItemForService:@"com.scary-robot.GithubNotifier" 46 | withUsername:self.username 47 | password:aToken]; 48 | } else { 49 | [keychainItem setPassword:aToken]; 50 | } 51 | } 52 | 53 | - (NSString *)apiToken 54 | { 55 | if (!apiToken){ 56 | EMGenericKeychainItem *keychainItem = [EMGenericKeychainItem genericKeychainItemForService:@"com.scary-robot.GithubNotifier" 57 | withUsername:self.username]; 58 | 59 | apiToken = [keychainItem password]; 60 | } 61 | 62 | return apiToken; 63 | } 64 | 65 | #pragma mark - 66 | #pragma mark Singleton methods 67 | 68 | + (GithubUser *)sharedInstance 69 | { 70 | @synchronized(self) 71 | { 72 | if (sharedInstance == nil) 73 | sharedInstance = [[GithubUser alloc] init]; 74 | } 75 | return sharedInstance; 76 | } 77 | 78 | + (id)allocWithZone:(NSZone *)zone { 79 | @synchronized(self) { 80 | if (sharedInstance == nil) { 81 | sharedInstance = [super allocWithZone:zone]; 82 | return sharedInstance; // assignment and return on first allocation 83 | } 84 | } 85 | return nil; // on subsequent allocation attempts return nil 86 | } 87 | 88 | 89 | - (id)retain { 90 | return self; 91 | } 92 | 93 | @end -------------------------------------------------------------------------------- /Classes/GrowlManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // GrowlManager.h 3 | // GithubNotifier 4 | // 5 | // Created by Clinton Shryock on 6/15/10. 6 | // Copyright 2010 scary-robot. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | @class AppController; 12 | @class GithubUser; 13 | 14 | #define GITHUB_NOTIFICATION_REPOSITORIES_ADDED @"Repository Added" 15 | #define GITHUB_NOTIFICATION_REPOSITORIES_REMOVED @"Repository Removed" 16 | #define GITHUB_NOTIFICATION_COMMITS_PUSHED @"New Push" 17 | #define GITHUB_NOTIFICATION_WATCHERS_ADDED @"New Watchers Added" 18 | 19 | typedef enum _GithubTimelineObjectType { 20 | GithubTimelineObjectRepoAdded, 21 | GithubTimelineObjectRepoRemoved, 22 | 23 | GithubTimelineObjectCommit, 24 | 25 | GithubTimelineObjectForkAdded, 26 | GithubTimelineObjectForkRemoved, 27 | 28 | GithubTimelineObjectIssueAdded, 29 | GithubTimelineObjectIssueClosed, 30 | 31 | GithubTimelineObjectNewPush, 32 | GithubTimelineObjectWatchersAdded 33 | 34 | 35 | } GithubTimelineObjectType; 36 | 37 | @interface GrowlManager : NSObject { 38 | AppController *appController; 39 | } 40 | 41 | @property (nonatomic, retain) IBOutlet AppController *appController; 42 | 43 | @end -------------------------------------------------------------------------------- /Classes/GrowlManager.m: -------------------------------------------------------------------------------- 1 | // 2 | // GrowlManager.m 3 | // GithubNotifier 4 | // 5 | // Created by Clinton Shryock on 6/15/10. 6 | // Copyright 2010 scary-robot. All rights reserved. 7 | // 8 | 9 | #import "GrowlManager.h" 10 | #import "GithubUser.h" 11 | 12 | @interface GrowlManager (Private) 13 | - (void)notifyWithNewCommits:(NSNotification *)aNotification; 14 | - (void)notifyWithRepositoriesAdditions:(NSNotification *)aNotification; 15 | - (void)notifyWithRepositoriesRemovals:(NSNotification *)aNotification; 16 | - (void)notifyWithNewPush:(NSNotification *)aNotification; 17 | - (void)notifyWithWatchersAdded:(NSNotification *)aNotification; 18 | @end 19 | 20 | @implementation GrowlManager 21 | 22 | @synthesize appController; 23 | 24 | - (void) awakeFromNib { 25 | [[NSNotificationCenter defaultCenter] addObserver:self 26 | selector:@selector(notifyWithRepositoriesAdditions:) 27 | name:GITHUB_NOTIFICATION_REPOSITORIES_ADDED 28 | object:nil]; 29 | 30 | [[NSNotificationCenter defaultCenter] addObserver:self 31 | selector:@selector(notifyWithRepositoriesRemovals:) 32 | name:GITHUB_NOTIFICATION_REPOSITORIES_REMOVED 33 | object:nil]; 34 | 35 | 36 | [[NSNotificationCenter defaultCenter] addObserver:self 37 | selector:@selector(notifyWithNewPush:) 38 | name:GITHUB_NOTIFICATION_COMMITS_PUSHED 39 | object:nil]; 40 | 41 | [[NSNotificationCenter defaultCenter] addObserver:self 42 | selector:@selector(notifyWithWatchersAdded:) 43 | name:GITHUB_NOTIFICATION_WATCHERS_ADDED 44 | object:nil]; 45 | 46 | 47 | [GrowlApplicationBridge setGrowlDelegate:self]; 48 | } 49 | 50 | - (void)notifyWithRepositoriesAdditions:(NSNotification *)aNotification 51 | { 52 | NSDictionary *userInfo = [aNotification userInfo]; 53 | 54 | NSNumber *count = [userInfo objectForKey:@"additions"]; 55 | NSMutableDictionary *context = [NSMutableDictionary dictionary]; 56 | [context setObject:[userInfo objectForKey:@"username"] forKey:@"username"]; 57 | NSString *variableDesc = ([count intValue] > 1) ? @"repositories were" : @"repository was"; 58 | [GrowlApplicationBridge notifyWithTitle:@"Your repositories have changed" 59 | description:[NSString stringWithFormat:@"%@ %@ added", count, variableDesc] 60 | notificationName:@"Repositories Changed" 61 | iconData:nil 62 | priority:0 63 | isSticky:NO 64 | clickContext:context]; 65 | } 66 | 67 | 68 | - (void)notifyWithRepositoriesRemovals:(NSNotification *)aNotification 69 | { 70 | NSDictionary *userInfo = [aNotification userInfo]; 71 | 72 | NSNumber *count = [userInfo objectForKey:@"subtractions"]; 73 | 74 | NSString *variableDesc = ([count intValue] > 1) ? @"repositories were" : @"repository was"; 75 | [GrowlApplicationBridge notifyWithTitle:@"Your repositories have changed" 76 | description:[NSString stringWithFormat:@"%@ %@ removed", count, variableDesc] 77 | notificationName:@"Repositories Changed" 78 | iconData:nil 79 | priority:0 80 | isSticky:NO 81 | clickContext:nil]; 82 | } 83 | 84 | - (void)notifyWithNewPush:(NSNotification *)aNotification 85 | { 86 | NSDictionary *userInfo = [aNotification userInfo]; 87 | NSMutableArray *pushes = [userInfo objectForKey:@"payload"]; 88 | NSManagedObject *repository = [userInfo objectForKey:@"repository"]; 89 | 90 | [GrowlApplicationBridge setGrowlDelegate:self]; 91 | 92 | for (NSDictionary *commit in pushes) { 93 | NSString *linkTitle = ([[commit objectForKey:@"login"] isNotEqualTo:nil]) ? 94 | [NSString stringWithFormat:@"%@/", [commit objectForKey:@"login"]] : @""; 95 | 96 | NSString *title = [NSString stringWithFormat:@"New pushes to %@%@", 97 | linkTitle, 98 | [repository valueForKey:@"name"]]; 99 | NSMutableDictionary *context = [NSMutableDictionary dictionary]; 100 | [context setValue:[commit objectForKey:@"login"] forKey:@"author"]; 101 | [context setValue:[repository valueForKey:@"name"] forKey:@"repoName"]; 102 | [context setValue:[commit objectForKey:@"id"] forKey:@"commitId"]; 103 | [context setValue:[NSNumber numberWithInteger:GithubTimelineObjectNewPush] forKey:@"type"]; 104 | [GrowlApplicationBridge notifyWithTitle:title 105 | description:[commit objectForKey:@"message"] 106 | notificationName:GITHUB_NOTIFICATION_COMMITS_PUSHED 107 | iconData:nil 108 | priority:0 109 | isSticky:NO 110 | clickContext:context]; 111 | } 112 | 113 | } 114 | 115 | - (void) growlNotificationWasClicked:(id)clickContext 116 | { 117 | GithubUser *githubUser = [GithubUser sharedInstance]; 118 | 119 | NSNumber *type = [clickContext objectForKey:@"type"]; 120 | NSString *urlEnd; 121 | switch ([type integerValue]) { 122 | case GithubTimelineObjectNewPush: 123 | urlEnd = [NSString stringWithFormat:@"%@/%@/commits", 124 | ([[clickContext objectForKey:@"author"] isNotEqualTo:nil]) ? [clickContext objectForKey:@"author"] : githubUser.username, 125 | [clickContext objectForKey:@"repoName"]]; 126 | break; 127 | case GithubTimelineObjectWatchersAdded: 128 | urlEnd = [NSString stringWithFormat:@"%@", [clickContext objectForKey:@"name"]]; 129 | break; 130 | default: 131 | urlEnd = [NSString stringWithFormat:@"%@", [clickContext objectForKey:@"username"]]; 132 | 133 | } 134 | NSWorkspace * ws = [NSWorkspace sharedWorkspace]; 135 | NSURL * url = [NSURL URLWithString:[NSString stringWithFormat:@"http://github.com/%@", urlEnd]]; 136 | [ws openURL: url]; 137 | 138 | } 139 | 140 | 141 | 142 | - (void)notifyWithWatchersAdded:(NSNotification *)aNotification 143 | { 144 | NSDictionary *userInfo = [aNotification userInfo]; 145 | NSMutableArray *watchers = [userInfo objectForKey:@"additions"]; 146 | 147 | [GrowlApplicationBridge setGrowlDelegate:self]; 148 | 149 | if (3 < [watchers count]) { 150 | NSString *title = [NSString stringWithFormat:@"New watchers for %@/%@", 151 | [userInfo valueForKey:@"user"], 152 | [userInfo valueForKey:@"repo"]]; 153 | NSMutableString *message = [NSMutableString stringWithFormat:@"%d new watchers\n", [watchers count]]; 154 | [watchers enumerateObjectsUsingBlock:^(id obj, NSUInteger index, BOOL *stop) { 155 | [message appendFormat:@"%@\n", [obj valueForKey:@"name"]]; 156 | }]; 157 | 158 | [GrowlApplicationBridge notifyWithTitle:title 159 | description:message 160 | notificationName:GITHUB_NOTIFICATION_WATCHERS_ADDED 161 | iconData:nil 162 | priority:0 163 | isSticky:NO 164 | clickContext:nil]; 165 | } else { 166 | [watchers enumerateObjectsUsingBlock:^(id obj, NSUInteger index, BOOL *stop) { 167 | NSMutableDictionary *context = [NSMutableDictionary dictionary]; 168 | [context setValue:[obj objectForKey:@"name"] forKey:@"name"]; 169 | [context setValue:[NSNumber numberWithInteger:GithubTimelineObjectWatchersAdded] forKey:@"type"]; 170 | NSString *title = [NSString stringWithFormat:@"New watchers for %@", 171 | [userInfo valueForKey:@"repo"]]; 172 | [GrowlApplicationBridge notifyWithTitle:title 173 | description:[NSString stringWithFormat:@"%@ is now watching your fork", [obj valueForKey:@"name"]] 174 | notificationName:GITHUB_NOTIFICATION_WATCHERS_ADDED 175 | iconData:nil 176 | priority:0 177 | isSticky:NO 178 | clickContext:context]; 179 | }]; 180 | } 181 | 182 | 183 | } 184 | 185 | @end 186 | -------------------------------------------------------------------------------- /Classes/NSWorkspaceHelper.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSWorkspaceHelper.h 3 | // Enormego Helpers 4 | // 5 | // Created by Shaun Harrison on 11/18/09. 6 | // Copyright (c) 2009 enormego 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | // 26 | 27 | #import 28 | 29 | 30 | @interface NSWorkspace (Helper) 31 | 32 | - (void)registerLoginLaunchBundle:(NSBundle*)bundle; 33 | - (void)unregisterLoginLaunchBundle:(NSBundle*)bundle; 34 | 35 | - (void)unregisterLoginLaunchApplication:(NSString*)appName; 36 | 37 | @end -------------------------------------------------------------------------------- /Classes/NSWorkspaceHelper.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSWorkspaceHelper.m 3 | // Enormego Helpers 4 | // 5 | // Created by Shaun Harrison on 11/18/09. 6 | // Copyright (c) 2009 enormego 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | // 26 | 27 | #import "NSWorkspaceHelper.h" 28 | 29 | @implementation NSWorkspace (Helper) 30 | 31 | - (void)registerLoginLaunchBundle:(NSBundle*)bundle { 32 | [self unregisterLoginLaunchBundle:bundle]; // Removes the old bundle, incase the application location changed 33 | 34 | NSURL* bundleURL = [NSURL fileURLWithPath:[bundle bundlePath] isDirectory:YES]; 35 | if(!bundleURL) return; 36 | 37 | LSSharedFileListRef loginList = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL); 38 | if(!loginList) return; 39 | 40 | LSSharedFileListItemRef loginItem; 41 | 42 | if((loginItem = LSSharedFileListInsertItemURL(loginList, kLSSharedFileListItemLast, NULL, NULL, (CFURLRef)bundleURL, NULL, NULL))) { 43 | CFRelease(loginItem); 44 | } 45 | 46 | CFRelease(loginList); 47 | } 48 | 49 | - (void)unregisterLoginLaunchBundle:(NSBundle*)bundle { 50 | NSString* bundleIdentifier = [bundle bundleIdentifier]; 51 | 52 | LSSharedFileListRef loginList = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL); 53 | if(!loginList) return; 54 | 55 | UInt32 seedValue; 56 | NSArray* loginItemsArray = (NSArray *)LSSharedFileListCopySnapshot(loginList, &seedValue); 57 | if(!loginItemsArray) return; 58 | 59 | for (id item in loginItemsArray) { 60 | LSSharedFileListItemRef itemRef = (LSSharedFileListItemRef)item; 61 | CFURLRef bundleURL; 62 | 63 | if (LSSharedFileListItemResolve(itemRef, 0, &bundleURL, NULL) == noErr) { 64 | if([[[NSBundle bundleWithPath:(NSString*)CFURLGetString(bundleURL)] bundleIdentifier] isEqualToString:bundleIdentifier]) { 65 | LSSharedFileListItemRemove(loginList, itemRef); 66 | } 67 | } 68 | } 69 | 70 | [loginItemsArray release]; 71 | 72 | CFRelease(loginList); 73 | } 74 | 75 | - (void)unregisterLoginLaunchApplication:(NSString*)appName { 76 | LSSharedFileListRef loginList = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL); 77 | if(!loginList) return; 78 | 79 | UInt32 seedValue; 80 | NSArray* loginItemsArray = (NSArray *)LSSharedFileListCopySnapshot(loginList, &seedValue); 81 | if(!loginItemsArray) return; 82 | 83 | for (id item in loginItemsArray) { 84 | LSSharedFileListItemRef itemRef = (LSSharedFileListItemRef)item; 85 | NSString* itemName = (NSString*)LSSharedFileListItemCopyDisplayName(itemRef); 86 | 87 | if (itemName) { 88 | if([itemName isEqualToString:appName]) { 89 | LSSharedFileListItemRemove(loginList, itemRef); 90 | } 91 | 92 | [itemName release]; 93 | } 94 | } 95 | 96 | [loginItemsArray release]; 97 | 98 | CFRelease(loginList); 99 | } 100 | 101 | @end -------------------------------------------------------------------------------- /Classes/NetworkDataDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // NetworkDataDelegate.h 3 | // GithubNotifier 4 | // 5 | // Created by Clinton Shryock on 6/17/10. 6 | // Copyright 2010 scary-robot. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | @interface NetworkDataDelegate : NSObject { 13 | NSManagedObject *repository; 14 | } 15 | 16 | @property (retain) NSManagedObject *repository; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /Classes/NetworkDataDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // NetworkDataDelegate.m 3 | // GithubNotifier 4 | // 5 | // Created by Clinton Shryock on 6/17/10. 6 | // Copyright 2010 scary-robot. All rights reserved. 7 | // 8 | 9 | #import "NetworkDataDelegate.h" 10 | #import "GrowlManager.h" 11 | #import "SDGithubTaskManager.h" 12 | #import "SDGithubTask.h" 13 | 14 | 15 | @implementation NetworkDataDelegate 16 | 17 | @synthesize repository; 18 | 19 | - (void) githubManager:(SDGithubTaskManager*)manager resultsReadyForTask:(SDGithubTask*)task { 20 | NSNumber *space = nil; 21 | NSNumber *previousSpace = nil; 22 | NSMutableDictionary *previousCommit = nil; 23 | int pushCount = 0; 24 | int commitCount = 0; 25 | NSNumber *timeKey = [self.repository valueForKey:@"timeKey"]; 26 | NSLog(@"time key at start: %@", timeKey); 27 | if ([timeKey isNotEqualTo:[NSNumber numberWithInt:0]]) { 28 | NSMutableArray *networkPushes = [NSMutableArray array]; 29 | NSLog(@"%@ commits to parse: %lx", [self.repository valueForKey:@"name"], (unsigned long)[task.results count]); 30 | for (NSMutableDictionary *commit in [task.results objectForKey:@"commits"]) { 31 | NSNumber *key = [commit valueForKey:@"time"]; 32 | if ([key isGreaterThan:[self.repository valueForKey:@"timeKey"]]) { 33 | space = [commit valueForKey:@"space"]; 34 | 35 | if (previousSpace == nil) { // this is the first series of commits 36 | previousSpace = [commit valueForKey:@"space"]; 37 | commitCount = 1; 38 | pushCount++; 39 | } else if ([previousSpace isNotEqualTo:space]) { 40 | NSLog(@"new push"); 41 | previousSpace = [commit valueForKey:@"space"]; 42 | [networkPushes addObject:previousCommit]; 43 | pushCount++; 44 | commitCount=1; 45 | } else { 46 | commitCount++; 47 | } 48 | previousCommit = [commit copy]; 49 | } 50 | } 51 | /** 52 | * If timekey is not greater, than previousCommit is nil 53 | */ 54 | NSLog(@"previousCommit: \n%@", previousCommit); 55 | [networkPushes addObject:previousCommit]; 56 | 57 | NSMutableDictionary *dict = [NSMutableDictionary dictionary]; 58 | [dict setObject:networkPushes forKey:@"payload"]; 59 | [dict setObject:self.repository forKey:@"repository"]; 60 | 61 | [[NSNotificationCenter defaultCenter] postNotificationName:GITHUB_NOTIFICATION_COMMITS_PUSHED 62 | object:self 63 | userInfo:dict]; 64 | } 65 | 66 | NSLog(@"push count: %d", pushCount); 67 | 68 | NSDictionary *lastCommit = [[task.results objectForKey:@"commits"] lastObject]; 69 | [self.repository setValue:[lastCommit valueForKey:@"time"] forKey:@"timeKey"]; 70 | } 71 | 72 | - (void) githubManager:(SDGithubTaskManager*)manager failedForTask:(SDGithubTask*)task 73 | { 74 | NSLog(@"failed in NetworkDataDelegate"); 75 | } 76 | 77 | @end 78 | -------------------------------------------------------------------------------- /Classes/NetworkMetaDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // NetworkMetaDelegate.h 3 | // GithubNotifier 4 | // 5 | // Created by Clinton Shryock on 6/17/10. 6 | // Copyright 2010 scary-robot. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | @interface NetworkMetaDelegate : NSObject { 13 | NSManagedObject *parentRepository; 14 | } 15 | 16 | @property (retain) NSManagedObject *parentRepository; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /Classes/NetworkMetaDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // NetworkMetaDelegate.m 3 | // GithubNotifier 4 | // 5 | // Created by Clinton Shryock on 6/17/10. 6 | // Copyright 2010 scary-robot. All rights reserved. 7 | // 8 | 9 | #import "NetworkMetaDelegate.h" 10 | #import "SDGithubTaskManager.h" 11 | #import "SDGithubTask.h" 12 | 13 | 14 | @implementation NetworkMetaDelegate 15 | 16 | @synthesize parentRepository; 17 | 18 | - (void) githubManager:(SDGithubTaskManager*)manager resultsReadyForTask:(SDGithubTask*)task { 19 | NSString *nethash; 20 | nethash = [task.results valueForKey:@"nethash"]; 21 | if ([nethash isNotEqualTo:[self.parentRepository valueForKey:@"nethash"]]) { 22 | NSLog(@"nethash update"); 23 | [self.parentRepository setValue:nethash forKey:@"nethash"]; 24 | 25 | NSLog(@"Posting nethash change for :%@", [self.parentRepository valueForKey:@"name"]); 26 | NSDictionary *dict = [NSDictionary dictionaryWithObject:self.parentRepository forKey:@"repository"]; 27 | [[NSNotificationCenter defaultCenter] postNotificationName:@"UpdateNetworkForRepository" 28 | object:self 29 | userInfo:dict]; 30 | 31 | } 32 | } 33 | 34 | - (void) githubManager:(SDGithubTaskManager*)manager failedForTask:(SDGithubTask*)task 35 | { 36 | NSLog(@"error in NetworkMetaDelegate>githubManager:"); 37 | } 38 | 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /Classes/ObjectDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // ObjectDelegate.h 3 | // GithubNotifier 4 | // 5 | // Created by Clint Shryock on 10/5/10. 6 | // Copyright 2010 scary-robot. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | @interface ObjectDelegate : NSObject { 13 | 14 | } 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /Classes/ObjectDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // ObjectDelegate.m 3 | // GithubNotifier 4 | // 5 | // Created by Clint Shryock on 10/5/10. 6 | // Copyright 2010 scary-robot. All rights reserved. 7 | // 8 | 9 | #import "ObjectDelegate.h" 10 | 11 | 12 | @implementation ObjectDelegate 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /Classes/PreferencesWindowController.h: -------------------------------------------------------------------------------- 1 | // 2 | // PreferencesWindowController.h 3 | // GithubNotifier 4 | // 5 | // Created by Clinton Shryock on 7/7/10. 6 | // Copyright 2010 scary-robot. All rights reserved. 7 | // 8 | 9 | #import 10 | @class GithubUser; 11 | 12 | 13 | @interface PreferencesWindowController : NSWindowController { 14 | NSTextField *username; 15 | NSSecureTextField *apiToken; 16 | BOOL openAtLogin; 17 | 18 | GithubUser *githubUser; 19 | } 20 | 21 | @property (nonatomic, retain) IBOutlet NSTextField *username; 22 | @property (nonatomic, retain) IBOutlet NSSecureTextField *apiToken; 23 | @property (nonatomic, retain) GithubUser *githubUser; 24 | @property (assign) BOOL openAtLogin; 25 | 26 | - (IBAction)saveNewAccount:(id)sender; 27 | - (IBAction)updateRefreshRate:(id)sender; 28 | - (IBAction)toggleOpenAtLaunch:(id)sender; 29 | 30 | @end 31 | -------------------------------------------------------------------------------- /Classes/PreferencesWindowController.m: -------------------------------------------------------------------------------- 1 | // 2 | // PreferencesWindowController.m 3 | // GithubNotifier 4 | // 5 | // Created by Clinton Shryock on 7/7/10. 6 | // Copyright 2010 scary-robot. All rights reserved. 7 | // 8 | 9 | #import "PreferencesWindowController.h" 10 | #import "GithubUser.h" 11 | #import "NSWorkspaceHelper.h" 12 | 13 | 14 | @implementation PreferencesWindowController 15 | 16 | @synthesize username; 17 | @synthesize apiToken; 18 | @synthesize githubUser; 19 | @synthesize openAtLogin; 20 | 21 | - (void)awakeFromNib 22 | { 23 | self.githubUser = [GithubUser sharedInstance]; 24 | } 25 | 26 | - (IBAction)saveNewAccount:(id)sender 27 | { 28 | self.githubUser.username = [self.username stringValue]; 29 | self.githubUser.apiToken = [self.apiToken stringValue]; 30 | [[self window] close]; 31 | 32 | 33 | 34 | [[NSNotificationCenter defaultCenter] postNotificationName:@"UserSet" 35 | object:self 36 | userInfo:nil]; 37 | } 38 | 39 | - (IBAction)updateRefreshRate:(id)sender 40 | { 41 | [[NSNotificationCenter defaultCenter] postNotificationName:@"RefreshRateChanged" 42 | object:self 43 | userInfo:nil]; 44 | } 45 | 46 | - (IBAction)toggleOpenAtLaunch:(id)sender 47 | { 48 | NSWorkspace *workspace = [NSWorkspace sharedWorkspace]; 49 | NSBundle *bundle = [NSBundle mainBundle]; 50 | NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; 51 | BOOL shouldRegisterForLogin = [sender state]; 52 | if (shouldRegisterForLogin) { 53 | [workspace registerLoginLaunchBundle:bundle]; 54 | [defaults setBool:YES forKey:@"openAtLogin"]; 55 | } else { 56 | [workspace unregisterLoginLaunchBundle:bundle]; 57 | [defaults setBool:NO forKey:@"openAtLogin"]; 58 | } 59 | } 60 | 61 | 62 | @end -------------------------------------------------------------------------------- /Classes/RepositoriesController.h: -------------------------------------------------------------------------------- 1 | // 2 | // RepositoriesController.h 3 | // GithubNotifier 4 | // 5 | // Created by Clint Shryock on 9/30/10. 6 | // Copyright 2010 scary-robot. All rights reserved. 7 | // 8 | 9 | #import 10 | @class GithubUser; 11 | @class SDGithubTaskManager; 12 | @class RepositoriesDelegate; 13 | 14 | 15 | @interface RepositoriesController : NSObject { 16 | NSArrayController *repositoryArrayController; 17 | 18 | // Main Github task manager 19 | SDGithubTaskManager *mainTaskManager; 20 | 21 | // Delegate objects 22 | RepositoriesDelegate *mainRepositoriesDelegate; 23 | 24 | GithubUser *githubUser; 25 | 26 | } 27 | 28 | @property (nonatomic, retain) GithubUser *githubUser; 29 | @property (nonatomic, retain) IBOutlet NSArrayController *repositoryArrayController; 30 | 31 | @property (retain) SDGithubTaskManager *mainTaskManager; 32 | @property (retain) RepositoriesDelegate *mainRepositoriesDelegate; 33 | 34 | - (id)initWithGithubUser:(GithubUser *)_githubUser; 35 | 36 | - (void)fetchUpdates; 37 | 38 | @end 39 | -------------------------------------------------------------------------------- /Classes/RepositoriesController.m: -------------------------------------------------------------------------------- 1 | // 2 | // RepositoriesController.m 3 | // GithubNotifier 4 | // 5 | // Created by Clint Shryock on 9/30/10. 6 | // Copyright 2010 scary-robot. All rights reserved. 7 | // 8 | 9 | #import "RepositoriesController.h" 10 | #import "GithubUser.h" 11 | #import "SDGithubTaskManager.h" 12 | #import "RepositoriesDelegate.h" 13 | 14 | @interface RepositoriesController (private) 15 | - (void)updateRepositories:(NSNotification *)aNotification; 16 | @end 17 | 18 | 19 | @implementation RepositoriesController 20 | 21 | @synthesize repositoryArrayController; 22 | @synthesize githubUser; 23 | @synthesize mainTaskManager; 24 | @synthesize mainRepositoriesDelegate; 25 | 26 | - (id) initWithGithubUser:(GithubUser *)_githubUser 27 | { 28 | self = [super init]; 29 | if (self != nil) { 30 | self.githubUser = _githubUser; 31 | self.mainTaskManager = [SDGithubTaskManager new]; 32 | self.mainRepositoriesDelegate = [RepositoriesDelegate new]; 33 | 34 | self.mainTaskManager.delegate = mainRepositoriesDelegate; 35 | self.mainTaskManager.successSelector = @selector(githubManager:resultsReadyForTask:); 36 | self.mainTaskManager.failSelector = @selector(githubManager:failedForTask:); 37 | } 38 | return self; 39 | } 40 | 41 | - (void) fetchUpdates 42 | { 43 | self.mainTaskManager.username = githubUser.username; 44 | self.mainTaskManager.password = githubUser.apiToken; 45 | SDGithubTask *basicTask = [SDGithubTask taskWithManager:self.mainTaskManager]; 46 | basicTask.user = self.mainTaskManager.username; 47 | basicTask.name = self.mainTaskManager.username; 48 | basicTask.type = SDGithubTaskGetRepos; 49 | [basicTask run]; 50 | } 51 | 52 | @end 53 | -------------------------------------------------------------------------------- /Classes/RepositoriesDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // RepositoriesDelegate.h 3 | // GithubNotifier 4 | // 5 | // Created by Clinton Shryock on 6/13/10. 6 | // Copyright 2010 scary-robot. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | @interface RepositoriesDelegate : NSObject { 13 | NSArray *results; 14 | } 15 | 16 | @property (copy) NSArray *results; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /Classes/RepositoriesDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // RepositoriesDelegate.m 3 | // GithubNotifier 4 | // 5 | // Created by Clinton Shryock on 6/13/10. 6 | // Copyright 2010 scary-robot. All rights reserved. 7 | // 8 | 9 | #import "RepositoriesDelegate.h" 10 | #import "SDGithubTaskManager.h" 11 | #import "SDGithubTask.h" 12 | #import "CSManagedRepository.h" 13 | 14 | #import "GrowlManager.h" 15 | 16 | @interface RepositoriesDelegate (Private) 17 | 18 | - (NSArray *)fetchRepositories; 19 | - (void)mergeLocalRepositories:(NSArray *)local withRemoteRepositories:(NSArray *)remote forUser:(NSString *)username; 20 | - (NSMutableArray *)repositoriesForResults:(NSArray *)remoteResults; 21 | - (NSFetchRequest *)repositoryFetchRequestWithManangedObjectContext:(NSManagedObjectContext *)moc; 22 | - (NSManagedObject *)createRepositoryForData:(NSDictionary *)data; 23 | - (CSManagedRepository *)fetchRepositoryObjectByName:(NSString *)name; 24 | - (CSManagedRepository *)updateRepository:(CSManagedRepository *)repository withDictionary:(NSDictionary *)data; 25 | 26 | @end 27 | 28 | @implementation RepositoriesDelegate 29 | 30 | @synthesize results; 31 | 32 | - (id) init 33 | { 34 | self = [super init]; 35 | if (self != nil) { 36 | self.results = nil; 37 | } 38 | return self; 39 | } 40 | 41 | 42 | - (void) githubManager:(SDGithubTaskManager*)manager resultsReadyForTask:(SDGithubTask*)task { 43 | 44 | self.results = [task.results valueForKey:@"repositories"]; 45 | 46 | NSArray *localRepositories = [self fetchRepositories]; 47 | [self mergeLocalRepositories:localRepositories 48 | withRemoteRepositories:[self repositoriesForResults:self.results] 49 | forUser:task.user]; 50 | } 51 | 52 | - (void) githubManager:(SDGithubTaskManager*)manager failedForTask:(SDGithubTask*)task { 53 | self.results = nil; 54 | 55 | NSLog(@"failed to fetch repositories"); 56 | } 57 | 58 | #pragma mark - 59 | #pragma mark Private methods 60 | 61 | 62 | - (void)mergeLocalRepositories:(NSArray *)local withRemoteRepositories:(NSArray *)remote forUser:(NSString *)username 63 | { 64 | NSLog(@"merging"); 65 | NSMutableSet *currentSet = [NSMutableSet setWithArray:local]; 66 | NSMutableSet *remoteSet = [NSMutableSet setWithArray:remote]; 67 | 68 | NSMutableDictionary *repositoryChanges = [NSMutableDictionary dictionaryWithCapacity:2]; 69 | [repositoryChanges setObject:username forKey:@"username"]; 70 | 71 | 72 | // Subtract the current set of repositories on disk from the list 73 | // retrieved from the server. If there are any left over, then 74 | // we've added new repositories since last update 75 | [remoteSet minusSet:currentSet]; 76 | if (0 < [remoteSet count]) { 77 | [repositoryChanges setObject:[NSNumber numberWithInt:[remoteSet count]] forKey:@"additions"]; 78 | [[NSNotificationCenter defaultCenter] postNotificationName:GITHUB_NOTIFICATION_REPOSITORIES_ADDED 79 | object:self 80 | userInfo:repositoryChanges]; 81 | } 82 | 83 | currentSet = [NSMutableSet setWithArray:local]; 84 | remoteSet = [NSMutableSet setWithArray:remote]; 85 | 86 | NSManagedObjectContext *moc = [[NSApp delegate] managedObjectContext]; 87 | [currentSet minusSet:remoteSet]; 88 | for (NSManagedObject *orphan in currentSet) { 89 | [moc deleteObject:orphan]; 90 | } 91 | 92 | if (0 < [currentSet count]) { 93 | [repositoryChanges setObject:[NSNumber numberWithInt:[currentSet count]] forKey:@"subtractions"]; 94 | [[NSNotificationCenter defaultCenter] postNotificationName:GITHUB_NOTIFICATION_REPOSITORIES_REMOVED 95 | object:self 96 | userInfo:repositoryChanges]; 97 | } 98 | 99 | [[NSNotificationCenter defaultCenter] postNotificationName:@"RepositoriesMerged" 100 | object:self 101 | userInfo:nil]; 102 | } 103 | 104 | - (NSMutableArray *)repositoriesForResults:(NSArray *)remoteResults 105 | { 106 | NSMutableArray *repositories = [NSMutableArray arrayWithCapacity:0]; 107 | for (NSDictionary *dict in remoteResults) { 108 | CSManagedRepository *repo = [self fetchRepositoryObjectByName:[dict valueForKey:@"name"]]; 109 | if (repo) { 110 | [repositories addObject:[self updateRepository:repo withDictionary:dict]]; 111 | } else { 112 | [repositories addObject:[self createRepositoryForData:dict]]; 113 | } 114 | } 115 | return repositories; 116 | } 117 | 118 | - (CSManagedRepository *)updateRepository:(CSManagedRepository *)repository withDictionary:(NSDictionary *)data 119 | { 120 | [repository setValue:[data valueForKey:@"name"] forKey:@"name"]; 121 | [repository setValue:[data valueForKey:@"description"] forKey:@"desc"]; 122 | [repository setValue:[data valueForKey:@"owner"] forKey:@"owner"]; 123 | [repository setValue:[data valueForKey:@"url"] forKey:@"url"]; 124 | [repository setValue:[data valueForKey:@"parent"] forKey:@"parent"]; 125 | [repository setValue:[data valueForKey:@"source"] forKey:@"source"]; 126 | [repository setValue:[data valueForKey:@"forks"] forKey:@"forks"]; 127 | repository.watcherCount = [data valueForKey:@"watchers"]; 128 | // repository.watcherCount = [NSNumber numberWithInt:1]; 129 | // repository.watcherList = nil; 130 | [repository setValue:[data valueForKey:@"homepage"] forKey:@"homepage"]; 131 | NSNumber *isFork = [NSNumber numberWithUnsignedInt:[[data valueForKey:@"fork"] intValue]]; 132 | [repository setValue:isFork forKey:@"isFork"]; 133 | return repository; 134 | } 135 | 136 | - (NSManagedObject *)createRepositoryForData:(NSDictionary *)data 137 | { 138 | NSManagedObjectContext *moc = [[NSApp delegate] managedObjectContext]; 139 | CSManagedRepository *newRepo = [NSEntityDescription insertNewObjectForEntityForName:@"Repository" 140 | inManagedObjectContext:moc]; 141 | [newRepo setValue:[data valueForKey:@"name"] forKey:@"name"]; 142 | [newRepo setValue:[data valueForKey:@"description"] forKey:@"desc"]; 143 | [newRepo setValue:[data valueForKey:@"owner"] forKey:@"owner"]; 144 | [newRepo setValue:[data valueForKey:@"url"] forKey:@"url"]; 145 | [newRepo setValue:[data valueForKey:@"parent"] forKey:@"parent"]; 146 | [newRepo setValue:[data valueForKey:@"source"] forKey:@"source"]; 147 | [newRepo setValue:[data valueForKey:@"forks"] forKey:@"forks"]; 148 | newRepo.watcherCount = [data valueForKey:@"watchers"]; 149 | [newRepo setValue:[data valueForKey:@"homepage"] forKey:@"homepage"]; 150 | NSNumber *isFork = [NSNumber numberWithUnsignedInt:[[data valueForKey:@"fork"] intValue]]; 151 | [newRepo setValue:isFork forKey:@"isFork"]; 152 | return newRepo; 153 | } 154 | 155 | - (NSArray *)fetchRepositories 156 | { 157 | NSManagedObjectContext *moc = [[NSApp delegate] managedObjectContext]; 158 | NSFetchRequest *request = [self repositoryFetchRequestWithManangedObjectContext:moc]; 159 | 160 | NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] 161 | initWithKey:@"name" ascending:YES]; 162 | 163 | [request setSortDescriptors:[NSArray arrayWithObject:sortDescriptor]]; 164 | 165 | NSError *error = nil; 166 | NSArray *resultArray = [moc executeFetchRequest:request error:&error]; 167 | 168 | if(nil == resultArray) { 169 | return nil; 170 | } 171 | 172 | return resultArray; 173 | } 174 | 175 | - (CSManagedRepository *)fetchRepositoryObjectByName:(NSString *)name 176 | { 177 | NSManagedObjectContext *moc = [[NSApp delegate] managedObjectContext]; 178 | NSFetchRequest *request = [self repositoryFetchRequestWithManangedObjectContext:moc]; 179 | 180 | // setup predicate 181 | NSPredicate *predicate = [NSPredicate predicateWithFormat: 182 | @"name == %@", name]; 183 | [request setPredicate:predicate]; 184 | 185 | NSError *error = nil; 186 | NSArray *resultArray = [moc executeFetchRequest:request error:&error]; 187 | 188 | if (0 < [resultArray count]) { 189 | return [resultArray objectAtIndex:0]; 190 | } 191 | 192 | return nil; 193 | } 194 | 195 | - (NSFetchRequest *)repositoryFetchRequestWithManangedObjectContext:(NSManagedObjectContext *)moc 196 | { 197 | NSEntityDescription *entityDescription = [NSEntityDescription entityForName:@"Repository" 198 | inManagedObjectContext:moc]; 199 | 200 | NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease]; 201 | 202 | [request setEntity:entityDescription]; 203 | return request; 204 | } 205 | 206 | @end 207 | -------------------------------------------------------------------------------- /Classes/RepositoryWatchersDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // RepositoryWatchersDelegate.h 3 | // GithubNotifier 4 | // 5 | // Created by Clint Shryock on 10/5/10. 6 | // Copyright 2010 scary-robot. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "CollectionDelegate.h" 12 | 13 | 14 | @interface RepositoryWatchersDelegate : CollectionDelegate { 15 | 16 | } 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /Classes/RepositoryWatchersDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // RepositoryWatchersDelegate.m 3 | // GithubNotifier 4 | // 5 | // Created by Clint Shryock on 10/5/10. 6 | // Copyright 2010 scary-robot. All rights reserved. 7 | // 8 | 9 | #import "RepositoryWatchersDelegate.h" 10 | 11 | @interface RepositoryWatchersDelegate (Private) 12 | - (NSMutableDictionary *)mergeLocalStore:(NSArray *)local withRemoteResults:(NSArray *)_remote; 13 | @end 14 | 15 | 16 | @implementation RepositoryWatchersDelegate 17 | 18 | - (void) githubManager:(SDGithubTaskManager*)manager resultsReadyForTask:(SDGithubTask*)task 19 | { 20 | NSMutableDictionary *mergedWatchers = [self mergeLocalStore:self.parentRepository.watcherList 21 | withRemoteResults:[task.results objectForKey:@"watchers"]]; 22 | 23 | self.parentRepository.watcherList = [mergedWatchers objectForKey:@"watcherList"]; 24 | NSArray *additions = [mergedWatchers objectForKey:@"additions"]; 25 | 26 | if (0 < [additions count]) { 27 | [mergedWatchers setObject:task.user forKey:@"user"]; 28 | [mergedWatchers setObject:task.repo forKey:@"repo"]; 29 | [[NSNotificationCenter defaultCenter] postNotificationName:GITHUB_NOTIFICATION_WATCHERS_ADDED 30 | object:self 31 | userInfo:mergedWatchers]; 32 | } 33 | } 34 | 35 | - (void) githubManager:(SDGithubTaskManager*)manager failedForTask:(SDGithubTask*)task 36 | { 37 | NSLog(@"error in RepositoryWatchersDelegate>githubManager:"); 38 | } 39 | 40 | // Override mergeing function, because watchersList is a transformable attribute 41 | // and wont be deleted like a normal managed object 42 | - (NSMutableDictionary *)mergeLocalStore:(NSArray *)local withRemoteResults:(NSArray *)_remote 43 | { 44 | NSMutableArray *remote = [NSMutableArray arrayWithCapacity:0]; 45 | [_remote enumerateObjectsUsingBlock:^(id obj, NSUInteger index, BOOL *stop ){ 46 | [remote addObject:[NSDictionary dictionaryWithObject:obj forKey:@"name"]]; 47 | }]; 48 | NSMutableSet *currentSet = [NSMutableSet setWithArray:local]; 49 | NSMutableSet *remoteSet = [NSMutableSet setWithArray:remote]; 50 | 51 | NSMutableDictionary *changes = [NSMutableDictionary dictionaryWithCapacity:2]; 52 | [changes setObject:remote forKey:@"watcherList"]; 53 | 54 | // Subtract the current set of repositories on disk from the list 55 | // retrieved from the server. If there are any left over, then 56 | // we've added new repositories since last update 57 | [remoteSet minusSet:currentSet]; 58 | if (0 < [remoteSet count]) { 59 | [changes setObject:[remoteSet allObjects] forKey:@"additions"]; 60 | } 61 | return changes; 62 | } 63 | 64 | @end 65 | -------------------------------------------------------------------------------- /Credits.html: -------------------------------------------------------------------------------- 1 |

Thanks to:
2 |

3 | 4 |

Steven Degutis for CocoaREST

5 | 6 |

ExtendMac for EMKeychain
7 |

8 | 9 |

Shaun Harrison and or Enormego for NSWorkspaceHelper
10 |

11 | 12 |

Github for great git hosting and giving me an easy and centralized way to get involved with open source projects.

-------------------------------------------------------------------------------- /English.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/catsby/GithubNotifier/4f5826e4579091d4e416e9ee574c974304c41968/English.lproj/InfoPlist.strings -------------------------------------------------------------------------------- /GithubNotifier-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIconFile 12 | githubnotifier.icns 13 | CFBundleIdentifier 14 | com.scary-robot.${PRODUCT_NAME:rfc1034identifier} 15 | CFBundleInfoDictionaryVersion 16 | 6.0 17 | CFBundlePackageType 18 | APPL 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 3 23 | CFBundleShortVersionString 24 | 1.2 25 | LSMinimumSystemVersion 26 | ${MACOSX_DEPLOYMENT_TARGET} 27 | NSMainNibFile 28 | MainMenu 29 | NSPrincipalClass 30 | NSApplication 31 | LSUIElement 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /GithubNotifier.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 45; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 2F7446990DB6B7EA00F9684A /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2F7446970DB6B7EA00F9684A /* MainMenu.xib */; }; 11 | 77C8280E06725ACE000B614F /* GithubNotifier_AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 77C8280C06725ACE000B614F /* GithubNotifier_AppDelegate.m */; }; 12 | 8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */; }; 13 | 8D11072D0486CEB800E47090 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; settings = {ATTRIBUTES = (); }; }; 14 | 8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; }; 15 | F403150C1259105800BE7410 /* CSManagedRepository.m in Sources */ = {isa = PBXBuildFile; fileRef = F403150B1259105800BE7410 /* CSManagedRepository.m */; }; 16 | F403154A125912CC00BE7410 /* GithubNotifier_DataModel.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = F4031549125912CC00BE7410 /* GithubNotifier_DataModel.xcdatamodeld */; }; 17 | F40921C811E96048001550DC /* Preferences.xib in Resources */ = {isa = PBXBuildFile; fileRef = F40921C711E96048001550DC /* Preferences.xib */; }; 18 | F430F65711E36CA1000A7CFE /* NSColor+Hex.m in Sources */ = {isa = PBXBuildFile; fileRef = F430F63711E36CA1000A7CFE /* NSColor+Hex.m */; }; 19 | F430F65811E36CA1000A7CFE /* NSData+Base64.m in Sources */ = {isa = PBXBuildFile; fileRef = F430F63911E36CA1000A7CFE /* NSData+Base64.m */; }; 20 | F430F65911E36CA1000A7CFE /* NSString+UUID.m in Sources */ = {isa = PBXBuildFile; fileRef = F430F63B11E36CA1000A7CFE /* NSString+UUID.m */; }; 21 | F430F65A11E36CA1000A7CFE /* SDGithubTask.m in Sources */ = {isa = PBXBuildFile; fileRef = F430F63D11E36CA1000A7CFE /* SDGithubTask.m */; }; 22 | F430F65B11E36CA1000A7CFE /* SDGithubTaskManager.m in Sources */ = {isa = PBXBuildFile; fileRef = F430F63F11E36CA1000A7CFE /* SDGithubTaskManager.m */; }; 23 | F430F65C11E36CA1000A7CFE /* SDNetTask.m in Sources */ = {isa = PBXBuildFile; fileRef = F430F64111E36CA1000A7CFE /* SDNetTask.m */; }; 24 | F430F65D11E36CA1000A7CFE /* SDNetTaskManager.m in Sources */ = {isa = PBXBuildFile; fileRef = F430F64411E36CA1000A7CFE /* SDNetTaskManager.m */; }; 25 | F430F65E11E36CA1000A7CFE /* yajl_alloc.c in Sources */ = {isa = PBXBuildFile; fileRef = F430F64511E36CA1000A7CFE /* yajl_alloc.c */; }; 26 | F430F65F11E36CA1000A7CFE /* yajl_buf.c in Sources */ = {isa = PBXBuildFile; fileRef = F430F64711E36CA1000A7CFE /* yajl_buf.c */; }; 27 | F430F66011E36CA1000A7CFE /* yajl_encode.c in Sources */ = {isa = PBXBuildFile; fileRef = F430F64B11E36CA1000A7CFE /* yajl_encode.c */; }; 28 | F430F66111E36CA1000A7CFE /* yajl_gen.c in Sources */ = {isa = PBXBuildFile; fileRef = F430F64D11E36CA1000A7CFE /* yajl_gen.c */; }; 29 | F430F66211E36CA1000A7CFE /* yajl_lex.c in Sources */ = {isa = PBXBuildFile; fileRef = F430F64F11E36CA1000A7CFE /* yajl_lex.c */; }; 30 | F430F66311E36CA1000A7CFE /* yajl_parser.c in Sources */ = {isa = PBXBuildFile; fileRef = F430F65211E36CA1000A7CFE /* yajl_parser.c */; }; 31 | F430F66411E36CA1000A7CFE /* yajl.c in Sources */ = {isa = PBXBuildFile; fileRef = F430F65411E36CA1000A7CFE /* yajl.c */; }; 32 | F430F66511E36CA1000A7CFE /* YAJLDecoder.m in Sources */ = {isa = PBXBuildFile; fileRef = F430F65611E36CA1000A7CFE /* YAJLDecoder.m */; }; 33 | F43BF98E11E4AF81003346C7 /* PreferencesWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = F43BF98D11E4AF81003346C7 /* PreferencesWindowController.m */; }; 34 | F43BF99511E4B00C003346C7 /* GithubUser.m in Sources */ = {isa = PBXBuildFile; fileRef = F43BF99411E4B00C003346C7 /* GithubUser.m */; }; 35 | F43BF99C11E4B024003346C7 /* AppController.m in Sources */ = {isa = PBXBuildFile; fileRef = F43BF99B11E4B024003346C7 /* AppController.m */; }; 36 | F43BF9AB11E4B06C003346C7 /* Growl Registration Ticket.growlRegDict in Resources */ = {isa = PBXBuildFile; fileRef = F43BF9A111E4B06C003346C7 /* Growl Registration Ticket.growlRegDict */; }; 37 | F43BF9AC11E4B06C003346C7 /* GrowlManager.m in Sources */ = {isa = PBXBuildFile; fileRef = F43BF9A311E4B06C003346C7 /* GrowlManager.m */; }; 38 | F43BF9AD11E4B06C003346C7 /* NetworkDataDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = F43BF9A511E4B06C003346C7 /* NetworkDataDelegate.m */; }; 39 | F43BF9AE11E4B06C003346C7 /* NetworkMetaDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = F43BF9A711E4B06C003346C7 /* NetworkMetaDelegate.m */; }; 40 | F43BF9AF11E4B06C003346C7 /* RepositoriesDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = F43BF9A911E4B06C003346C7 /* RepositoriesDelegate.m */; }; 41 | F43BF9BC11E4B10F003346C7 /* EMKeychain.m in Sources */ = {isa = PBXBuildFile; fileRef = F43BF9BB11E4B10F003346C7 /* EMKeychain.m */; }; 42 | F43BF9C011E4B135003346C7 /* Growl.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F43BF9BF11E4B135003346C7 /* Growl.framework */; }; 43 | F43BF9CB11E4B14A003346C7 /* Growl.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = F43BF9BF11E4B135003346C7 /* Growl.framework */; }; 44 | F43BF9CD11E4B157003346C7 /* BWToolkitFramework.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F43BF9CC11E4B157003346C7 /* BWToolkitFramework.framework */; }; 45 | F43BF9FF11E4B15B003346C7 /* BWToolkitFramework.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = F43BF9CC11E4B157003346C7 /* BWToolkitFramework.framework */; }; 46 | F43BFA0511E4B1A7003346C7 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F43BFA0411E4B1A7003346C7 /* Security.framework */; }; 47 | F43BFAB611E4B26C003346C7 /* AccountSetup.xib in Resources */ = {isa = PBXBuildFile; fileRef = F43BFAB511E4B26C003346C7 /* AccountSetup.xib */; }; 48 | F464546D1254BDC100D17734 /* RepositoriesController.m in Sources */ = {isa = PBXBuildFile; fileRef = F464546C1254BDC100D17734 /* RepositoriesController.m */; }; 49 | F4A9426E125CA537001B8D57 /* 1-3.xcmappingmodel in Sources */ = {isa = PBXBuildFile; fileRef = F4A9426D125CA537001B8D57 /* 1-3.xcmappingmodel */; }; 50 | F4D7796B1328666B00A11773 /* githubnotifier.icns in Resources */ = {isa = PBXBuildFile; fileRef = F4D7796A1328666B00A11773 /* githubnotifier.icns */; }; 51 | F4D779B213286BCA00A11773 /* githubnotifier_inactive.png in Resources */ = {isa = PBXBuildFile; fileRef = F4D779B113286BCA00A11773 /* githubnotifier_inactive.png */; }; 52 | F4E0869311F0CA9300555607 /* NSWorkspaceHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = F4E0869211F0CA9300555607 /* NSWorkspaceHelper.m */; }; 53 | F4EAE8E4125B4FF400300F65 /* ObjectDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = F4EAE8E3125B4FF400300F65 /* ObjectDelegate.m */; }; 54 | F4EAE8E7125B4FFC00300F65 /* CollectionDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = F4EAE8E6125B4FFC00300F65 /* CollectionDelegate.m */; }; 55 | F4EAE91D125B51C600300F65 /* RepositoryWatchersDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = F4EAE91C125B51C600300F65 /* RepositoryWatchersDelegate.m */; }; 56 | F4F6974811FC95AA006FDF65 /* Credits.html in Resources */ = {isa = PBXBuildFile; fileRef = F4F6974711FC95AA006FDF65 /* Credits.html */; }; 57 | /* End PBXBuildFile section */ 58 | 59 | /* Begin PBXCopyFilesBuildPhase section */ 60 | F43BF9D011E4B157003346C7 /* Copy Frameworks */ = { 61 | isa = PBXCopyFilesBuildPhase; 62 | buildActionMask = 2147483647; 63 | dstPath = ""; 64 | dstSubfolderSpec = 10; 65 | files = ( 66 | F43BF9FF11E4B15B003346C7 /* BWToolkitFramework.framework in Copy Frameworks */, 67 | F43BF9CB11E4B14A003346C7 /* Growl.framework in Copy Frameworks */, 68 | ); 69 | name = "Copy Frameworks"; 70 | runOnlyForDeploymentPostprocessing = 0; 71 | }; 72 | /* End PBXCopyFilesBuildPhase section */ 73 | 74 | /* Begin PBXFileReference section */ 75 | 089C165DFE840E0CC02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = ""; }; 76 | 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = ""; }; 77 | 29B97316FDCFA39411CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 78 | 29B97324FDCFA39411CA2CEA /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = ""; }; 79 | 29B97325FDCFA39411CA2CEA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = ""; }; 80 | 2F7446980DB6B7EA00F9684A /* English */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = English; path = English.lproj/MainMenu.xib; sourceTree = ""; }; 81 | 32CA4F630368D1EE00C91783 /* GithubNotifier_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GithubNotifier_Prefix.pch; sourceTree = ""; }; 82 | 77C82804067257F0000B614F /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = /System/Library/Frameworks/CoreData.framework; sourceTree = ""; }; 83 | 77C8280B06725ACE000B614F /* GithubNotifier_AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GithubNotifier_AppDelegate.h; path = Classes/GithubNotifier_AppDelegate.h; sourceTree = ""; }; 84 | 77C8280C06725ACE000B614F /* GithubNotifier_AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GithubNotifier_AppDelegate.m; path = Classes/GithubNotifier_AppDelegate.m; sourceTree = ""; }; 85 | 8D1107320486CEB800E47090 /* GithubNotifier.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = GithubNotifier.app; sourceTree = BUILT_PRODUCTS_DIR; }; 86 | F403150A1259105800BE7410 /* CSManagedRepository.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CSManagedRepository.h; path = Classes/CSManagedRepository.h; sourceTree = ""; }; 87 | F403150B1259105800BE7410 /* CSManagedRepository.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CSManagedRepository.m; path = Classes/CSManagedRepository.m; sourceTree = ""; }; 88 | F40921C711E96048001550DC /* Preferences.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Preferences.xib; path = Interface/Preferences.xib; sourceTree = ""; }; 89 | F430F63611E36CA1000A7CFE /* NSColor+Hex.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSColor+Hex.h"; path = "CocoaREST/Source/NSColor+Hex.h"; sourceTree = ""; }; 90 | F430F63711E36CA1000A7CFE /* NSColor+Hex.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSColor+Hex.m"; path = "CocoaREST/Source/NSColor+Hex.m"; sourceTree = ""; }; 91 | F430F63811E36CA1000A7CFE /* NSData+Base64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSData+Base64.h"; path = "CocoaREST/Source/NSData+Base64.h"; sourceTree = ""; }; 92 | F430F63911E36CA1000A7CFE /* NSData+Base64.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSData+Base64.m"; path = "CocoaREST/Source/NSData+Base64.m"; sourceTree = ""; }; 93 | F430F63A11E36CA1000A7CFE /* NSString+UUID.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSString+UUID.h"; path = "CocoaREST/Source/NSString+UUID.h"; sourceTree = ""; }; 94 | F430F63B11E36CA1000A7CFE /* NSString+UUID.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSString+UUID.m"; path = "CocoaREST/Source/NSString+UUID.m"; sourceTree = ""; }; 95 | F430F63C11E36CA1000A7CFE /* SDGithubTask.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SDGithubTask.h; path = CocoaREST/Source/SDGithubTask.h; sourceTree = ""; }; 96 | F430F63D11E36CA1000A7CFE /* SDGithubTask.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SDGithubTask.m; path = CocoaREST/Source/SDGithubTask.m; sourceTree = ""; }; 97 | F430F63E11E36CA1000A7CFE /* SDGithubTaskManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SDGithubTaskManager.h; path = CocoaREST/Source/SDGithubTaskManager.h; sourceTree = ""; }; 98 | F430F63F11E36CA1000A7CFE /* SDGithubTaskManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SDGithubTaskManager.m; path = CocoaREST/Source/SDGithubTaskManager.m; sourceTree = ""; }; 99 | F430F64011E36CA1000A7CFE /* SDNetTask.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SDNetTask.h; path = CocoaREST/Source/SDNetTask.h; sourceTree = ""; }; 100 | F430F64111E36CA1000A7CFE /* SDNetTask.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SDNetTask.m; path = CocoaREST/Source/SDNetTask.m; sourceTree = ""; }; 101 | F430F64211E36CA1000A7CFE /* SDNetTask+Subclassing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "SDNetTask+Subclassing.h"; path = "CocoaREST/Source/SDNetTask+Subclassing.h"; sourceTree = ""; }; 102 | F430F64311E36CA1000A7CFE /* SDNetTaskManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SDNetTaskManager.h; path = CocoaREST/Source/SDNetTaskManager.h; sourceTree = ""; }; 103 | F430F64411E36CA1000A7CFE /* SDNetTaskManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SDNetTaskManager.m; path = CocoaREST/Source/SDNetTaskManager.m; sourceTree = ""; }; 104 | F430F64511E36CA1000A7CFE /* yajl_alloc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = yajl_alloc.c; path = CocoaREST/Source/yajl_alloc.c; sourceTree = ""; }; 105 | F430F64611E36CA1000A7CFE /* yajl_alloc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = yajl_alloc.h; path = CocoaREST/Source/yajl_alloc.h; sourceTree = ""; }; 106 | F430F64711E36CA1000A7CFE /* yajl_buf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = yajl_buf.c; path = CocoaREST/Source/yajl_buf.c; sourceTree = ""; }; 107 | F430F64811E36CA1000A7CFE /* yajl_buf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = yajl_buf.h; path = CocoaREST/Source/yajl_buf.h; sourceTree = ""; }; 108 | F430F64911E36CA1000A7CFE /* yajl_bytestack.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = yajl_bytestack.h; path = CocoaREST/Source/yajl_bytestack.h; sourceTree = ""; }; 109 | F430F64A11E36CA1000A7CFE /* yajl_common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = yajl_common.h; path = CocoaREST/Source/yajl_common.h; sourceTree = ""; }; 110 | F430F64B11E36CA1000A7CFE /* yajl_encode.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = yajl_encode.c; path = CocoaREST/Source/yajl_encode.c; sourceTree = ""; }; 111 | F430F64C11E36CA1000A7CFE /* yajl_encode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = yajl_encode.h; path = CocoaREST/Source/yajl_encode.h; sourceTree = ""; }; 112 | F430F64D11E36CA1000A7CFE /* yajl_gen.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = yajl_gen.c; path = CocoaREST/Source/yajl_gen.c; sourceTree = ""; }; 113 | F430F64E11E36CA1000A7CFE /* yajl_gen.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = yajl_gen.h; path = CocoaREST/Source/yajl_gen.h; sourceTree = ""; }; 114 | F430F64F11E36CA1000A7CFE /* yajl_lex.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = yajl_lex.c; path = CocoaREST/Source/yajl_lex.c; sourceTree = ""; }; 115 | F430F65011E36CA1000A7CFE /* yajl_lex.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = yajl_lex.h; path = CocoaREST/Source/yajl_lex.h; sourceTree = ""; }; 116 | F430F65111E36CA1000A7CFE /* yajl_parse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = yajl_parse.h; path = CocoaREST/Source/yajl_parse.h; sourceTree = ""; }; 117 | F430F65211E36CA1000A7CFE /* yajl_parser.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = yajl_parser.c; path = CocoaREST/Source/yajl_parser.c; sourceTree = ""; }; 118 | F430F65311E36CA1000A7CFE /* yajl_parser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = yajl_parser.h; path = CocoaREST/Source/yajl_parser.h; sourceTree = ""; }; 119 | F430F65411E36CA1000A7CFE /* yajl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = yajl.c; path = CocoaREST/Source/yajl.c; sourceTree = ""; }; 120 | F430F65511E36CA1000A7CFE /* YAJLDecoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = YAJLDecoder.h; path = CocoaREST/Source/YAJLDecoder.h; sourceTree = ""; }; 121 | F430F65611E36CA1000A7CFE /* YAJLDecoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = YAJLDecoder.m; path = CocoaREST/Source/YAJLDecoder.m; sourceTree = ""; }; 122 | F430F67511E36CEF000A7CFE /* GithubNotifier_DataModel.xcdatamodel */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = wrapper.xcdatamodel; path = GithubNotifier_DataModel.xcdatamodel; sourceTree = ""; }; 123 | F43BF98C11E4AF81003346C7 /* PreferencesWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PreferencesWindowController.h; path = Classes/PreferencesWindowController.h; sourceTree = ""; }; 124 | F43BF98D11E4AF81003346C7 /* PreferencesWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = PreferencesWindowController.m; path = Classes/PreferencesWindowController.m; sourceTree = ""; }; 125 | F43BF99311E4B00C003346C7 /* GithubUser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GithubUser.h; path = Classes/GithubUser.h; sourceTree = ""; }; 126 | F43BF99411E4B00C003346C7 /* GithubUser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GithubUser.m; path = Classes/GithubUser.m; sourceTree = ""; }; 127 | F43BF99A11E4B024003346C7 /* AppController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppController.h; path = Classes/AppController.h; sourceTree = ""; }; 128 | F43BF99B11E4B024003346C7 /* AppController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppController.m; path = Classes/AppController.m; sourceTree = ""; }; 129 | F43BF9A111E4B06C003346C7 /* Growl Registration Ticket.growlRegDict */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = "Growl Registration Ticket.growlRegDict"; sourceTree = ""; }; 130 | F43BF9A211E4B06C003346C7 /* GrowlManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GrowlManager.h; path = Classes/GrowlManager.h; sourceTree = ""; }; 131 | F43BF9A311E4B06C003346C7 /* GrowlManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GrowlManager.m; path = Classes/GrowlManager.m; sourceTree = ""; }; 132 | F43BF9A411E4B06C003346C7 /* NetworkDataDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NetworkDataDelegate.h; path = Classes/NetworkDataDelegate.h; sourceTree = ""; }; 133 | F43BF9A511E4B06C003346C7 /* NetworkDataDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = NetworkDataDelegate.m; path = Classes/NetworkDataDelegate.m; sourceTree = ""; }; 134 | F43BF9A611E4B06C003346C7 /* NetworkMetaDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NetworkMetaDelegate.h; path = Classes/NetworkMetaDelegate.h; sourceTree = ""; }; 135 | F43BF9A711E4B06C003346C7 /* NetworkMetaDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = NetworkMetaDelegate.m; path = Classes/NetworkMetaDelegate.m; sourceTree = ""; }; 136 | F43BF9A811E4B06C003346C7 /* RepositoriesDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RepositoriesDelegate.h; path = Classes/RepositoriesDelegate.h; sourceTree = ""; }; 137 | F43BF9A911E4B06C003346C7 /* RepositoriesDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RepositoriesDelegate.m; path = Classes/RepositoriesDelegate.m; sourceTree = ""; }; 138 | F43BF9B011E4B086003346C7 /* GithubNotifier-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GithubNotifier-Info.plist"; sourceTree = ""; }; 139 | F43BF9BA11E4B10F003346C7 /* EMKeychain.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = EMKeychain.h; path = EMKeychain/EMKeychain.h; sourceTree = ""; }; 140 | F43BF9BB11E4B10F003346C7 /* EMKeychain.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = EMKeychain.m; path = EMKeychain/EMKeychain.m; sourceTree = ""; }; 141 | F43BF9BF11E4B135003346C7 /* Growl.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Growl.framework; path = ThirdPartyFrameworks/Growl.framework; sourceTree = DEVELOPER_DIR; }; 142 | F43BF9CC11E4B157003346C7 /* BWToolkitFramework.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = BWToolkitFramework.framework; path = ThirdPartyFrameworks/BWToolkitFramework.framework; sourceTree = DEVELOPER_DIR; }; 143 | F43BFA0411E4B1A7003346C7 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; 144 | F43BFAB511E4B26C003346C7 /* AccountSetup.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = AccountSetup.xib; path = Interface/AccountSetup.xib; sourceTree = ""; }; 145 | F464546B1254BDC100D17734 /* RepositoriesController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RepositoriesController.h; path = Classes/RepositoriesController.h; sourceTree = ""; }; 146 | F464546C1254BDC100D17734 /* RepositoriesController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RepositoriesController.m; path = Classes/RepositoriesController.m; sourceTree = ""; }; 147 | F4A9426D125CA537001B8D57 /* 1-3.xcmappingmodel */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = wrapper.xcmappingmodel; path = "1-3.xcmappingmodel"; sourceTree = ""; }; 148 | F4D7796A1328666B00A11773 /* githubnotifier.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = githubnotifier.icns; sourceTree = ""; }; 149 | F4D779B113286BCA00A11773 /* githubnotifier_inactive.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = githubnotifier_inactive.png; sourceTree = ""; }; 150 | F4E0869111F0CA9300555607 /* NSWorkspaceHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NSWorkspaceHelper.h; path = Classes/NSWorkspaceHelper.h; sourceTree = ""; }; 151 | F4E0869211F0CA9300555607 /* NSWorkspaceHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = NSWorkspaceHelper.m; path = Classes/NSWorkspaceHelper.m; sourceTree = ""; }; 152 | F4EAE8C6125B4E2800300F65 /* GithubNotifier_DataModel 3.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "GithubNotifier_DataModel 3.xcdatamodel"; sourceTree = ""; }; 153 | F4EAE8E2125B4FF400300F65 /* ObjectDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ObjectDelegate.h; path = Classes/ObjectDelegate.h; sourceTree = ""; }; 154 | F4EAE8E3125B4FF400300F65 /* ObjectDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ObjectDelegate.m; path = Classes/ObjectDelegate.m; sourceTree = ""; }; 155 | F4EAE8E5125B4FFC00300F65 /* CollectionDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CollectionDelegate.h; path = Classes/CollectionDelegate.h; sourceTree = ""; }; 156 | F4EAE8E6125B4FFC00300F65 /* CollectionDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CollectionDelegate.m; path = Classes/CollectionDelegate.m; sourceTree = ""; }; 157 | F4EAE91B125B51C600300F65 /* RepositoryWatchersDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RepositoryWatchersDelegate.h; path = Classes/RepositoryWatchersDelegate.h; sourceTree = ""; }; 158 | F4EAE91C125B51C600300F65 /* RepositoryWatchersDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RepositoryWatchersDelegate.m; path = Classes/RepositoryWatchersDelegate.m; sourceTree = ""; }; 159 | F4F6974711FC95AA006FDF65 /* Credits.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = Credits.html; sourceTree = ""; }; 160 | /* End PBXFileReference section */ 161 | 162 | /* Begin PBXFrameworksBuildPhase section */ 163 | 8D11072E0486CEB800E47090 /* Frameworks */ = { 164 | isa = PBXFrameworksBuildPhase; 165 | buildActionMask = 2147483647; 166 | files = ( 167 | 8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */, 168 | F43BF9C011E4B135003346C7 /* Growl.framework in Frameworks */, 169 | F43BF9CD11E4B157003346C7 /* BWToolkitFramework.framework in Frameworks */, 170 | F43BFA0511E4B1A7003346C7 /* Security.framework in Frameworks */, 171 | ); 172 | runOnlyForDeploymentPostprocessing = 0; 173 | }; 174 | /* End PBXFrameworksBuildPhase section */ 175 | 176 | /* Begin PBXGroup section */ 177 | 080E96DDFE201D6D7F000001 /* Classes */ = { 178 | isa = PBXGroup; 179 | children = ( 180 | F43BF99311E4B00C003346C7 /* GithubUser.h */, 181 | F43BF99411E4B00C003346C7 /* GithubUser.m */, 182 | 77C8280B06725ACE000B614F /* GithubNotifier_AppDelegate.h */, 183 | 77C8280C06725ACE000B614F /* GithubNotifier_AppDelegate.m */, 184 | ); 185 | name = Classes; 186 | sourceTree = ""; 187 | }; 188 | 1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */ = { 189 | isa = PBXGroup; 190 | children = ( 191 | 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */, 192 | F43BF9BF11E4B135003346C7 /* Growl.framework */, 193 | F43BF9CC11E4B157003346C7 /* BWToolkitFramework.framework */, 194 | F43BFA0411E4B1A7003346C7 /* Security.framework */, 195 | ); 196 | name = "Linked Frameworks"; 197 | sourceTree = ""; 198 | }; 199 | 1058C7A2FEA54F0111CA2CBB /* Other Frameworks */ = { 200 | isa = PBXGroup; 201 | children = ( 202 | 77C82804067257F0000B614F /* CoreData.framework */, 203 | 29B97325FDCFA39411CA2CEA /* Foundation.framework */, 204 | 29B97324FDCFA39411CA2CEA /* AppKit.framework */, 205 | ); 206 | name = "Other Frameworks"; 207 | sourceTree = ""; 208 | }; 209 | 19C28FACFE9D520D11CA2CBB /* Products */ = { 210 | isa = PBXGroup; 211 | children = ( 212 | 8D1107320486CEB800E47090 /* GithubNotifier.app */, 213 | ); 214 | name = Products; 215 | sourceTree = ""; 216 | }; 217 | 29B97314FDCFA39411CA2CEA /* Boulevard */ = { 218 | isa = PBXGroup; 219 | children = ( 220 | F43BF99F11E4B02F003346C7 /* Delegates */, 221 | F43BF98B11E4AF6B003346C7 /* Controllers */, 222 | F430F63411E36C66000A7CFE /* lib */, 223 | 7756732906782D8800D1FEB8 /* Models */, 224 | 080E96DDFE201D6D7F000001 /* Classes */, 225 | 29B97315FDCFA39411CA2CEA /* Other Sources */, 226 | 29B97317FDCFA39411CA2CEA /* Resources */, 227 | 29B97323FDCFA39411CA2CEA /* Frameworks */, 228 | 19C28FACFE9D520D11CA2CBB /* Products */, 229 | ); 230 | name = Boulevard; 231 | sourceTree = ""; 232 | }; 233 | 29B97315FDCFA39411CA2CEA /* Other Sources */ = { 234 | isa = PBXGroup; 235 | children = ( 236 | 32CA4F630368D1EE00C91783 /* GithubNotifier_Prefix.pch */, 237 | 29B97316FDCFA39411CA2CEA /* main.m */, 238 | ); 239 | name = "Other Sources"; 240 | sourceTree = ""; 241 | }; 242 | 29B97317FDCFA39411CA2CEA /* Resources */ = { 243 | isa = PBXGroup; 244 | children = ( 245 | F4D779B113286BCA00A11773 /* githubnotifier_inactive.png */, 246 | F4D7796A1328666B00A11773 /* githubnotifier.icns */, 247 | F4F6974711FC95AA006FDF65 /* Credits.html */, 248 | F43BFAB511E4B26C003346C7 /* AccountSetup.xib */, 249 | F43BF9A111E4B06C003346C7 /* Growl Registration Ticket.growlRegDict */, 250 | F43BF9B011E4B086003346C7 /* GithubNotifier-Info.plist */, 251 | 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */, 252 | 2F7446970DB6B7EA00F9684A /* MainMenu.xib */, 253 | F40921C711E96048001550DC /* Preferences.xib */, 254 | ); 255 | name = Resources; 256 | sourceTree = ""; 257 | }; 258 | 29B97323FDCFA39411CA2CEA /* Frameworks */ = { 259 | isa = PBXGroup; 260 | children = ( 261 | 1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */, 262 | 1058C7A2FEA54F0111CA2CBB /* Other Frameworks */, 263 | ); 264 | name = Frameworks; 265 | sourceTree = ""; 266 | }; 267 | 7756732906782D8800D1FEB8 /* Models */ = { 268 | isa = PBXGroup; 269 | children = ( 270 | F40315091259105100BE7410 /* Classes */, 271 | F4031549125912CC00BE7410 /* GithubNotifier_DataModel.xcdatamodeld */, 272 | ); 273 | name = Models; 274 | sourceTree = ""; 275 | }; 276 | F40314D812590E6300BE7410 /* Main */ = { 277 | isa = PBXGroup; 278 | children = ( 279 | F43BF9A211E4B06C003346C7 /* GrowlManager.h */, 280 | F43BF9A311E4B06C003346C7 /* GrowlManager.m */, 281 | F43BF99A11E4B024003346C7 /* AppController.h */, 282 | F43BF99B11E4B024003346C7 /* AppController.m */, 283 | F43BF98C11E4AF81003346C7 /* PreferencesWindowController.h */, 284 | F43BF98D11E4AF81003346C7 /* PreferencesWindowController.m */, 285 | ); 286 | name = Main; 287 | sourceTree = ""; 288 | }; 289 | F40315091259105100BE7410 /* Classes */ = { 290 | isa = PBXGroup; 291 | children = ( 292 | F403150A1259105800BE7410 /* CSManagedRepository.h */, 293 | F403150B1259105800BE7410 /* CSManagedRepository.m */, 294 | ); 295 | name = Classes; 296 | sourceTree = ""; 297 | }; 298 | F430F63411E36C66000A7CFE /* lib */ = { 299 | isa = PBXGroup; 300 | children = ( 301 | F43BF9B911E4B103003346C7 /* EMKeychain */, 302 | F430F63511E36C6D000A7CFE /* CocoaREST */, 303 | F4E0869111F0CA9300555607 /* NSWorkspaceHelper.h */, 304 | F4E0869211F0CA9300555607 /* NSWorkspaceHelper.m */, 305 | ); 306 | name = lib; 307 | sourceTree = ""; 308 | }; 309 | F430F63511E36C6D000A7CFE /* CocoaREST */ = { 310 | isa = PBXGroup; 311 | children = ( 312 | F430F63611E36CA1000A7CFE /* NSColor+Hex.h */, 313 | F430F63711E36CA1000A7CFE /* NSColor+Hex.m */, 314 | F430F63811E36CA1000A7CFE /* NSData+Base64.h */, 315 | F430F63911E36CA1000A7CFE /* NSData+Base64.m */, 316 | F430F63A11E36CA1000A7CFE /* NSString+UUID.h */, 317 | F430F63B11E36CA1000A7CFE /* NSString+UUID.m */, 318 | F430F63C11E36CA1000A7CFE /* SDGithubTask.h */, 319 | F430F63D11E36CA1000A7CFE /* SDGithubTask.m */, 320 | F430F63E11E36CA1000A7CFE /* SDGithubTaskManager.h */, 321 | F430F63F11E36CA1000A7CFE /* SDGithubTaskManager.m */, 322 | F430F64011E36CA1000A7CFE /* SDNetTask.h */, 323 | F430F64111E36CA1000A7CFE /* SDNetTask.m */, 324 | F430F64211E36CA1000A7CFE /* SDNetTask+Subclassing.h */, 325 | F430F64311E36CA1000A7CFE /* SDNetTaskManager.h */, 326 | F430F64411E36CA1000A7CFE /* SDNetTaskManager.m */, 327 | F430F64511E36CA1000A7CFE /* yajl_alloc.c */, 328 | F430F64611E36CA1000A7CFE /* yajl_alloc.h */, 329 | F430F64711E36CA1000A7CFE /* yajl_buf.c */, 330 | F430F64811E36CA1000A7CFE /* yajl_buf.h */, 331 | F430F64911E36CA1000A7CFE /* yajl_bytestack.h */, 332 | F430F64A11E36CA1000A7CFE /* yajl_common.h */, 333 | F430F64B11E36CA1000A7CFE /* yajl_encode.c */, 334 | F430F64C11E36CA1000A7CFE /* yajl_encode.h */, 335 | F430F64D11E36CA1000A7CFE /* yajl_gen.c */, 336 | F430F64E11E36CA1000A7CFE /* yajl_gen.h */, 337 | F430F64F11E36CA1000A7CFE /* yajl_lex.c */, 338 | F430F65011E36CA1000A7CFE /* yajl_lex.h */, 339 | F430F65111E36CA1000A7CFE /* yajl_parse.h */, 340 | F430F65211E36CA1000A7CFE /* yajl_parser.c */, 341 | F430F65311E36CA1000A7CFE /* yajl_parser.h */, 342 | F430F65411E36CA1000A7CFE /* yajl.c */, 343 | F430F65511E36CA1000A7CFE /* YAJLDecoder.h */, 344 | F430F65611E36CA1000A7CFE /* YAJLDecoder.m */, 345 | ); 346 | name = CocoaREST; 347 | sourceTree = ""; 348 | }; 349 | F43BF98B11E4AF6B003346C7 /* Controllers */ = { 350 | isa = PBXGroup; 351 | children = ( 352 | F40314D812590E6300BE7410 /* Main */, 353 | F464546B1254BDC100D17734 /* RepositoriesController.h */, 354 | F464546C1254BDC100D17734 /* RepositoriesController.m */, 355 | ); 356 | name = Controllers; 357 | sourceTree = ""; 358 | }; 359 | F43BF99F11E4B02F003346C7 /* Delegates */ = { 360 | isa = PBXGroup; 361 | children = ( 362 | F43BF9A411E4B06C003346C7 /* NetworkDataDelegate.h */, 363 | F43BF9A511E4B06C003346C7 /* NetworkDataDelegate.m */, 364 | F43BF9A611E4B06C003346C7 /* NetworkMetaDelegate.h */, 365 | F43BF9A711E4B06C003346C7 /* NetworkMetaDelegate.m */, 366 | F43BF9A811E4B06C003346C7 /* RepositoriesDelegate.h */, 367 | F43BF9A911E4B06C003346C7 /* RepositoriesDelegate.m */, 368 | F4EAE8E2125B4FF400300F65 /* ObjectDelegate.h */, 369 | F4EAE8E3125B4FF400300F65 /* ObjectDelegate.m */, 370 | F4EAE8E5125B4FFC00300F65 /* CollectionDelegate.h */, 371 | F4EAE8E6125B4FFC00300F65 /* CollectionDelegate.m */, 372 | F4EAE91B125B51C600300F65 /* RepositoryWatchersDelegate.h */, 373 | F4EAE91C125B51C600300F65 /* RepositoryWatchersDelegate.m */, 374 | ); 375 | name = Delegates; 376 | sourceTree = ""; 377 | }; 378 | F43BF9B911E4B103003346C7 /* EMKeychain */ = { 379 | isa = PBXGroup; 380 | children = ( 381 | F43BF9BA11E4B10F003346C7 /* EMKeychain.h */, 382 | F43BF9BB11E4B10F003346C7 /* EMKeychain.m */, 383 | ); 384 | name = EMKeychain; 385 | sourceTree = ""; 386 | }; 387 | /* End PBXGroup section */ 388 | 389 | /* Begin PBXNativeTarget section */ 390 | 8D1107260486CEB800E47090 /* GithubNotifier */ = { 391 | isa = PBXNativeTarget; 392 | buildConfigurationList = 26FC0A840875C7B200E6366F /* Build configuration list for PBXNativeTarget "GithubNotifier" */; 393 | buildPhases = ( 394 | 8D1107290486CEB800E47090 /* Resources */, 395 | 8D11072C0486CEB800E47090 /* Sources */, 396 | 8D11072E0486CEB800E47090 /* Frameworks */, 397 | F43BF9D011E4B157003346C7 /* Copy Frameworks */, 398 | ); 399 | buildRules = ( 400 | ); 401 | dependencies = ( 402 | ); 403 | name = GithubNotifier; 404 | productInstallPath = "$(HOME)/Applications"; 405 | productName = Boulevard; 406 | productReference = 8D1107320486CEB800E47090 /* GithubNotifier.app */; 407 | productType = "com.apple.product-type.application"; 408 | }; 409 | /* End PBXNativeTarget section */ 410 | 411 | /* Begin PBXProject section */ 412 | 29B97313FDCFA39411CA2CEA /* Project object */ = { 413 | isa = PBXProject; 414 | attributes = { 415 | ORGANIZATIONNAME = "scary-robot"; 416 | }; 417 | buildConfigurationList = 26FC0A880875C7B200E6366F /* Build configuration list for PBXProject "GithubNotifier" */; 418 | compatibilityVersion = "Xcode 3.1"; 419 | developmentRegion = English; 420 | hasScannedForEncodings = 1; 421 | knownRegions = ( 422 | English, 423 | Japanese, 424 | French, 425 | German, 426 | ); 427 | mainGroup = 29B97314FDCFA39411CA2CEA /* Boulevard */; 428 | projectDirPath = ""; 429 | projectRoot = ""; 430 | targets = ( 431 | 8D1107260486CEB800E47090 /* GithubNotifier */, 432 | ); 433 | }; 434 | /* End PBXProject section */ 435 | 436 | /* Begin PBXResourcesBuildPhase section */ 437 | 8D1107290486CEB800E47090 /* Resources */ = { 438 | isa = PBXResourcesBuildPhase; 439 | buildActionMask = 2147483647; 440 | files = ( 441 | 8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */, 442 | 2F7446990DB6B7EA00F9684A /* MainMenu.xib in Resources */, 443 | F43BF9AB11E4B06C003346C7 /* Growl Registration Ticket.growlRegDict in Resources */, 444 | F43BFAB611E4B26C003346C7 /* AccountSetup.xib in Resources */, 445 | F40921C811E96048001550DC /* Preferences.xib in Resources */, 446 | F4F6974811FC95AA006FDF65 /* Credits.html in Resources */, 447 | F4D7796B1328666B00A11773 /* githubnotifier.icns in Resources */, 448 | F4D779B213286BCA00A11773 /* githubnotifier_inactive.png in Resources */, 449 | ); 450 | runOnlyForDeploymentPostprocessing = 0; 451 | }; 452 | /* End PBXResourcesBuildPhase section */ 453 | 454 | /* Begin PBXSourcesBuildPhase section */ 455 | 8D11072C0486CEB800E47090 /* Sources */ = { 456 | isa = PBXSourcesBuildPhase; 457 | buildActionMask = 2147483647; 458 | files = ( 459 | 8D11072D0486CEB800E47090 /* main.m in Sources */, 460 | 77C8280E06725ACE000B614F /* GithubNotifier_AppDelegate.m in Sources */, 461 | F430F65711E36CA1000A7CFE /* NSColor+Hex.m in Sources */, 462 | F430F65811E36CA1000A7CFE /* NSData+Base64.m in Sources */, 463 | F430F65911E36CA1000A7CFE /* NSString+UUID.m in Sources */, 464 | F430F65A11E36CA1000A7CFE /* SDGithubTask.m in Sources */, 465 | F430F65B11E36CA1000A7CFE /* SDGithubTaskManager.m in Sources */, 466 | F430F65C11E36CA1000A7CFE /* SDNetTask.m in Sources */, 467 | F430F65D11E36CA1000A7CFE /* SDNetTaskManager.m in Sources */, 468 | F430F65E11E36CA1000A7CFE /* yajl_alloc.c in Sources */, 469 | F430F65F11E36CA1000A7CFE /* yajl_buf.c in Sources */, 470 | F430F66011E36CA1000A7CFE /* yajl_encode.c in Sources */, 471 | F430F66111E36CA1000A7CFE /* yajl_gen.c in Sources */, 472 | F430F66211E36CA1000A7CFE /* yajl_lex.c in Sources */, 473 | F430F66311E36CA1000A7CFE /* yajl_parser.c in Sources */, 474 | F430F66411E36CA1000A7CFE /* yajl.c in Sources */, 475 | F430F66511E36CA1000A7CFE /* YAJLDecoder.m in Sources */, 476 | F403154A125912CC00BE7410 /* GithubNotifier_DataModel.xcdatamodeld in Sources */, 477 | F43BF98E11E4AF81003346C7 /* PreferencesWindowController.m in Sources */, 478 | F43BF99511E4B00C003346C7 /* GithubUser.m in Sources */, 479 | F43BF99C11E4B024003346C7 /* AppController.m in Sources */, 480 | F43BF9AC11E4B06C003346C7 /* GrowlManager.m in Sources */, 481 | F43BF9AD11E4B06C003346C7 /* NetworkDataDelegate.m in Sources */, 482 | F43BF9AE11E4B06C003346C7 /* NetworkMetaDelegate.m in Sources */, 483 | F43BF9AF11E4B06C003346C7 /* RepositoriesDelegate.m in Sources */, 484 | F43BF9BC11E4B10F003346C7 /* EMKeychain.m in Sources */, 485 | F4E0869311F0CA9300555607 /* NSWorkspaceHelper.m in Sources */, 486 | F464546D1254BDC100D17734 /* RepositoriesController.m in Sources */, 487 | F403150C1259105800BE7410 /* CSManagedRepository.m in Sources */, 488 | F4EAE8E4125B4FF400300F65 /* ObjectDelegate.m in Sources */, 489 | F4EAE8E7125B4FFC00300F65 /* CollectionDelegate.m in Sources */, 490 | F4EAE91D125B51C600300F65 /* RepositoryWatchersDelegate.m in Sources */, 491 | F4A9426E125CA537001B8D57 /* 1-3.xcmappingmodel in Sources */, 492 | ); 493 | runOnlyForDeploymentPostprocessing = 0; 494 | }; 495 | /* End PBXSourcesBuildPhase section */ 496 | 497 | /* Begin PBXVariantGroup section */ 498 | 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */ = { 499 | isa = PBXVariantGroup; 500 | children = ( 501 | 089C165DFE840E0CC02AAC07 /* English */, 502 | ); 503 | name = InfoPlist.strings; 504 | sourceTree = ""; 505 | }; 506 | 2F7446970DB6B7EA00F9684A /* MainMenu.xib */ = { 507 | isa = PBXVariantGroup; 508 | children = ( 509 | 2F7446980DB6B7EA00F9684A /* English */, 510 | ); 511 | name = MainMenu.xib; 512 | sourceTree = ""; 513 | }; 514 | /* End PBXVariantGroup section */ 515 | 516 | /* Begin XCBuildConfiguration section */ 517 | 26FC0A850875C7B200E6366F /* Debug */ = { 518 | isa = XCBuildConfiguration; 519 | buildSettings = { 520 | ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; 521 | COPY_PHASE_STRIP = NO; 522 | CURRENT_PROJECT_VERSION = 3; 523 | FRAMEWORK_SEARCH_PATHS = ( 524 | "$(inherited)", 525 | "\"$(DEVELOPER_DIR)/ThirdPartyFrameworks\"", 526 | "\"$(SYSTEM_LIBRARY_DIR)/Frameworks/CoreServices.framework/Versions/A/Frameworks\"", 527 | "\"$(SRCROOT)\"", 528 | ); 529 | GCC_DYNAMIC_NO_PIC = NO; 530 | GCC_ENABLE_FIX_AND_CONTINUE = YES; 531 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 532 | GCC_MODEL_TUNING = G5; 533 | GCC_OPTIMIZATION_LEVEL = 0; 534 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 535 | GCC_PREFIX_HEADER = GithubNotifier_Prefix.pch; 536 | INFOPLIST_FILE = "GithubNotifier-Info.plist"; 537 | INSTALL_PATH = "$(HOME)/Applications"; 538 | PRODUCT_NAME = GithubNotifier; 539 | VERSIONING_SYSTEM = "apple-generic"; 540 | WRAPPER_EXTENSION = app; 541 | }; 542 | name = Debug; 543 | }; 544 | 26FC0A860875C7B200E6366F /* Release */ = { 545 | isa = XCBuildConfiguration; 546 | buildSettings = { 547 | CURRENT_PROJECT_VERSION = 3; 548 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 549 | FRAMEWORK_SEARCH_PATHS = ( 550 | "$(inherited)", 551 | "\"$(DEVELOPER_DIR)/ThirdPartyFrameworks\"", 552 | "\"$(SYSTEM_LIBRARY_DIR)/Frameworks/CoreServices.framework/Versions/A/Frameworks\"", 553 | "\"$(SRCROOT)\"", 554 | ); 555 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 556 | GCC_MODEL_TUNING = G5; 557 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 558 | GCC_PREFIX_HEADER = GithubNotifier_Prefix.pch; 559 | INFOPLIST_FILE = "GithubNotifier-Info.plist"; 560 | INSTALL_PATH = "$(HOME)/Applications"; 561 | PRODUCT_NAME = GithubNotifier; 562 | VERSIONING_SYSTEM = "apple-generic"; 563 | WRAPPER_EXTENSION = app; 564 | }; 565 | name = Release; 566 | }; 567 | 26FC0A890875C7B200E6366F /* Debug */ = { 568 | isa = XCBuildConfiguration; 569 | buildSettings = { 570 | ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; 571 | CODE_SIGN_IDENTITY = "Don't Code Sign"; 572 | GCC_C_LANGUAGE_STANDARD = gnu99; 573 | GCC_ENABLE_OBJC_GC = required; 574 | GCC_VERSION = com.apple.compilers.llvm.clang.1_0; 575 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 576 | GCC_WARN_UNUSED_VARIABLE = YES; 577 | ONLY_ACTIVE_ARCH = YES; 578 | PREBINDING = NO; 579 | RUN_CLANG_STATIC_ANALYZER = YES; 580 | SDKROOT = macosx10.6; 581 | }; 582 | name = Debug; 583 | }; 584 | 26FC0A8A0875C7B200E6366F /* Release */ = { 585 | isa = XCBuildConfiguration; 586 | buildSettings = { 587 | ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; 588 | CODE_SIGN_IDENTITY = "scary-robot-development"; 589 | GCC_C_LANGUAGE_STANDARD = gnu99; 590 | GCC_ENABLE_OBJC_GC = required; 591 | GCC_VERSION = com.apple.compilers.llvm.clang.1_0; 592 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 593 | GCC_WARN_UNUSED_VARIABLE = YES; 594 | PREBINDING = NO; 595 | RUN_CLANG_STATIC_ANALYZER = YES; 596 | SDKROOT = macosx10.6; 597 | }; 598 | name = Release; 599 | }; 600 | /* End XCBuildConfiguration section */ 601 | 602 | /* Begin XCConfigurationList section */ 603 | 26FC0A840875C7B200E6366F /* Build configuration list for PBXNativeTarget "GithubNotifier" */ = { 604 | isa = XCConfigurationList; 605 | buildConfigurations = ( 606 | 26FC0A850875C7B200E6366F /* Debug */, 607 | 26FC0A860875C7B200E6366F /* Release */, 608 | ); 609 | defaultConfigurationIsVisible = 0; 610 | defaultConfigurationName = Release; 611 | }; 612 | 26FC0A880875C7B200E6366F /* Build configuration list for PBXProject "GithubNotifier" */ = { 613 | isa = XCConfigurationList; 614 | buildConfigurations = ( 615 | 26FC0A890875C7B200E6366F /* Debug */, 616 | 26FC0A8A0875C7B200E6366F /* Release */, 617 | ); 618 | defaultConfigurationIsVisible = 0; 619 | defaultConfigurationName = Release; 620 | }; 621 | /* End XCConfigurationList section */ 622 | 623 | /* Begin XCVersionGroup section */ 624 | F4031549125912CC00BE7410 /* GithubNotifier_DataModel.xcdatamodeld */ = { 625 | isa = XCVersionGroup; 626 | children = ( 627 | F430F67511E36CEF000A7CFE /* GithubNotifier_DataModel.xcdatamodel */, 628 | F4EAE8C6125B4E2800300F65 /* GithubNotifier_DataModel 3.xcdatamodel */, 629 | F4A9426D125CA537001B8D57 /* 1-3.xcmappingmodel */, 630 | ); 631 | currentVersion = F4EAE8C6125B4E2800300F65 /* GithubNotifier_DataModel 3.xcdatamodel */; 632 | path = GithubNotifier_DataModel.xcdatamodeld; 633 | sourceTree = ""; 634 | versionGroupType = wrapper.xcdatamodel; 635 | }; 636 | /* End XCVersionGroup section */ 637 | }; 638 | rootObject = 29B97313FDCFA39411CA2CEA /* Project object */; 639 | } 640 | -------------------------------------------------------------------------------- /GithubNotifier.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /GithubNotifier_DataModel.xcdatamodeld/.xccurrentversion: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | _XCCurrentVersionName 6 | GithubNotifier_DataModel 3.xcdatamodel 7 | 8 | 9 | -------------------------------------------------------------------------------- /GithubNotifier_DataModel.xcdatamodeld/GithubNotifier_DataModel 3.xcdatamodel/elements: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/catsby/GithubNotifier/4f5826e4579091d4e416e9ee574c974304c41968/GithubNotifier_DataModel.xcdatamodeld/GithubNotifier_DataModel 3.xcdatamodel/elements -------------------------------------------------------------------------------- /GithubNotifier_DataModel.xcdatamodeld/GithubNotifier_DataModel 3.xcdatamodel/layout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/catsby/GithubNotifier/4f5826e4579091d4e416e9ee574c974304c41968/GithubNotifier_DataModel.xcdatamodeld/GithubNotifier_DataModel 3.xcdatamodel/layout -------------------------------------------------------------------------------- /GithubNotifier_DataModel.xcdatamodeld/GithubNotifier_DataModel.xcdatamodel/elements: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/catsby/GithubNotifier/4f5826e4579091d4e416e9ee574c974304c41968/GithubNotifier_DataModel.xcdatamodeld/GithubNotifier_DataModel.xcdatamodel/elements -------------------------------------------------------------------------------- /GithubNotifier_DataModel.xcdatamodeld/GithubNotifier_DataModel.xcdatamodel/layout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/catsby/GithubNotifier/4f5826e4579091d4e416e9ee574c974304c41968/GithubNotifier_DataModel.xcdatamodeld/GithubNotifier_DataModel.xcdatamodel/layout -------------------------------------------------------------------------------- /GithubNotifier_Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'GithubNotifier' target in the 'GithubNotifier' project 3 | // 4 | 5 | #ifdef __OBJC__ 6 | #import 7 | #endif 8 | -------------------------------------------------------------------------------- /Growl Registration Ticket.growlRegDict: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | TicketVersion 6 | 1 7 | AllNotifications 8 | 9 | Repositories Changed 10 | New Push 11 | New Watchers Added 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Interface/AccountSetup.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1060 5 | 10F569 6 | 788 7 | 1038.29 8 | 461.00 9 | 10 | YES 11 | 12 | YES 13 | com.apple.InterfaceBuilder.CocoaPlugin 14 | com.brandonwalkin.BWToolkit 15 | 16 | 17 | YES 18 | 788 19 | 1.2.5 20 | 21 | 22 | 23 | YES 24 | 25 | 26 | 27 | YES 28 | com.apple.InterfaceBuilder.CocoaPlugin 29 | com.brandonwalkin.BWToolkit 30 | 31 | 32 | YES 33 | 34 | YES 35 | 36 | 37 | YES 38 | 39 | 40 | 41 | YES 42 | 43 | PreferencesWindowController 44 | 45 | 46 | FirstResponder 47 | 48 | 49 | NSApplication 50 | 51 | 52 | 7 53 | 2 54 | {{131, 197}, {524, 208}} 55 | 611844096 56 | Account Setup 57 | NSWindow 58 | 59 | {1.79769e+308, 1.79769e+308} 60 | 61 | 62 | 256 63 | 64 | YES 65 | 66 | 67 | 256 68 | 69 | YES 70 | 71 | YES 72 | Apple PDF pasteboard type 73 | Apple PICT pasteboard type 74 | Apple PNG pasteboard type 75 | NSFilenamesPboardType 76 | NeXT Encapsulated PostScript v1.2 pasteboard type 77 | NeXT TIFF v4.0 pasteboard type 78 | 79 | 80 | {{40, 40}, {128, 128}} 81 | 82 | YES 83 | 84 | 130560 85 | 33554432 86 | 87 | NSImage 88 | NSApplicationIcon 89 | 90 | 0 91 | 0 92 | 0 93 | YES 94 | 95 | YES 96 | 97 | 98 | 99 | 268 100 | {{173, 148}, {126, 17}} 101 | 102 | YES 103 | 104 | 68288064 105 | 71304192 106 | Username 107 | 108 | LucidaGrande 109 | 13 110 | 1044 111 | 112 | 113 | 114 | 6 115 | System 116 | controlColor 117 | 118 | 3 119 | MC42NjY2NjY2NjY3AA 120 | 121 | 122 | 123 | 6 124 | System 125 | controlTextColor 126 | 127 | 3 128 | MAA 129 | 130 | 131 | 132 | 133 | 134 | 135 | 268 136 | {{304, 146}, {200, 22}} 137 | 138 | YES 139 | 140 | -1804468671 141 | 272630784 142 | 143 | 144 | 145 | YES 146 | 147 | 6 148 | System 149 | textBackgroundColor 150 | 151 | 3 152 | MQA 153 | 154 | 155 | 156 | 6 157 | System 158 | textColor 159 | 160 | 161 | 162 | 163 | 164 | 165 | 268 166 | {{173, 120}, {126, 17}} 167 | 168 | YES 169 | 170 | 68288064 171 | 71304192 172 | API Token 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 268 182 | {{304, 55}, {200, 23}} 183 | 184 | YES 185 | 186 | 67239424 187 | 67108864 188 | Take me to my API Token 189 | 190 | 191 | openURLInBrowser: 192 | 193 | -2033434369 194 | 162 195 | 196 | 197 | 400 198 | 75 199 | 200 | https://github.com/account 201 | 202 | 203 | 204 | 268 205 | {{301, 53}, {25, 25}} 206 | 207 | YES 208 | 209 | 67239424 210 | 134217728 211 | 212 | 213 | 214 | -2038415105 215 | 161 216 | 217 | 218 | 200 219 | 25 220 | 221 | 222 | 223 | 224 | 268 225 | {{414, 78}, {96, 32}} 226 | 227 | YES 228 | 229 | 67239424 230 | 134217728 231 | Save 232 | 233 | 234 | -2038284033 235 | 129 236 | 237 | DQ 238 | 200 239 | 25 240 | 241 | 242 | 243 | 244 | 268 245 | {{304, 114}, {200, 22}} 246 | 247 | YES 248 | 249 | 343014976 250 | 272630848 251 | 252 | 253 | 254 | YES 255 | 256 | 257 | 258 | YES 259 | NSAllRomanInputSourcesLocaleIdentifier 260 | 261 | 262 | 263 | 264 | {524, 208} 265 | 266 | 267 | {{0, 0}, {1280, 778}} 268 | {1.79769e+308, 1.79769e+308} 269 | 270 | 271 | 272 | 273 | YES 274 | 275 | 276 | window 277 | 278 | 279 | 280 | 21 281 | 282 | 283 | 284 | username 285 | 286 | 287 | 288 | 22 289 | 290 | 291 | 292 | apiToken 293 | 294 | 295 | 296 | 23 297 | 298 | 299 | 300 | saveNewAccount: 301 | 302 | 303 | 304 | 180 305 | 306 | 307 | 308 | value: githubUser.username 309 | 310 | 311 | 312 | 313 | 314 | value: githubUser.username 315 | value 316 | githubUser.username 317 | 318 | NSValidatesImmediately 319 | 320 | 321 | 2 322 | 323 | 324 | 183 325 | 326 | 327 | 328 | value: githubUser.apiToken 329 | 330 | 331 | 332 | 333 | 334 | value: githubUser.apiToken 335 | value 336 | githubUser.apiToken 337 | 338 | NSValidatesImmediately 339 | 340 | 341 | 2 342 | 343 | 344 | 184 345 | 346 | 347 | 348 | 349 | YES 350 | 351 | 0 352 | 353 | 354 | 355 | 356 | 357 | -2 358 | 359 | 360 | File's Owner 361 | 362 | 363 | -1 364 | 365 | 366 | First Responder 367 | 368 | 369 | -3 370 | 371 | 372 | Application 373 | 374 | 375 | 3 376 | 377 | 378 | YES 379 | 380 | 381 | 382 | 383 | 384 | 4 385 | 386 | 387 | YES 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 5 401 | 402 | 403 | YES 404 | 405 | 406 | 407 | 408 | 409 | 6 410 | 411 | 412 | YES 413 | 414 | 415 | 416 | 417 | 418 | 7 419 | 420 | 421 | YES 422 | 423 | 424 | 425 | 426 | 427 | 8 428 | 429 | 430 | YES 431 | 432 | 433 | 434 | 435 | 436 | 9 437 | 438 | 439 | YES 440 | 441 | 442 | 443 | 444 | 445 | 10 446 | 447 | 448 | YES 449 | 450 | 451 | 452 | 453 | 454 | 11 455 | 456 | 457 | YES 458 | 459 | 460 | 461 | 462 | 463 | 12 464 | 465 | 466 | YES 467 | 468 | 469 | 470 | 471 | 472 | 13 473 | 474 | 475 | 476 | 477 | 14 478 | 479 | 480 | 481 | 482 | 15 483 | 484 | 485 | 486 | 487 | 16 488 | 489 | 490 | 491 | 492 | 17 493 | 494 | 495 | 496 | 497 | 18 498 | 499 | 500 | 501 | 502 | 19 503 | 504 | 505 | 506 | 507 | 20 508 | 509 | 510 | 511 | 512 | 513 | 514 | YES 515 | 516 | YES 517 | -3.IBPluginDependency 518 | 10.IBPluginDependency 519 | 11.IBPluginDependency 520 | 12.IBPluginDependency 521 | 13.IBPluginDependency 522 | 14.IBPluginDependency 523 | 15.IBPluginDependency 524 | 16.IBPluginDependency 525 | 17.IBPluginDependency 526 | 18.IBPluginDependency 527 | 19.IBPluginDependency 528 | 20.IBPluginDependency 529 | 3.IBEditorWindowLastContentRect 530 | 3.IBPluginDependency 531 | 3.IBWindowTemplateEditedContentRect 532 | 3.NSWindowTemplate.visibleAtLaunch 533 | 4.IBPluginDependency 534 | 5.IBPluginDependency 535 | 6.IBPluginDependency 536 | 7.IBPluginDependency 537 | 8.IBPluginDependency 538 | 9.IBPluginDependency 539 | 540 | 541 | YES 542 | com.apple.InterfaceBuilder.CocoaPlugin 543 | com.apple.InterfaceBuilder.CocoaPlugin 544 | com.apple.InterfaceBuilder.CocoaPlugin 545 | com.apple.InterfaceBuilder.CocoaPlugin 546 | com.apple.InterfaceBuilder.CocoaPlugin 547 | com.apple.InterfaceBuilder.CocoaPlugin 548 | com.apple.InterfaceBuilder.CocoaPlugin 549 | com.brandonwalkin.BWToolkit 550 | com.apple.InterfaceBuilder.CocoaPlugin 551 | com.apple.InterfaceBuilder.CocoaPlugin 552 | com.apple.InterfaceBuilder.CocoaPlugin 553 | com.apple.InterfaceBuilder.CocoaPlugin 554 | {{321, 359}, {524, 208}} 555 | com.apple.InterfaceBuilder.CocoaPlugin 556 | {{321, 359}, {524, 208}} 557 | 558 | com.apple.InterfaceBuilder.CocoaPlugin 559 | com.apple.InterfaceBuilder.CocoaPlugin 560 | com.apple.InterfaceBuilder.CocoaPlugin 561 | com.apple.InterfaceBuilder.CocoaPlugin 562 | com.apple.InterfaceBuilder.CocoaPlugin 563 | com.brandonwalkin.BWToolkit 564 | 565 | 566 | 567 | YES 568 | 569 | 570 | YES 571 | 572 | 573 | 574 | 575 | YES 576 | 577 | 578 | YES 579 | 580 | 581 | 582 | 184 583 | 584 | 585 | 586 | YES 587 | 588 | PreferencesWindowController 589 | NSWindowController 590 | 591 | YES 592 | 593 | YES 594 | saveNewAccount: 595 | toggleOpenAtLaunch: 596 | updateRefreshRate: 597 | 598 | 599 | YES 600 | id 601 | id 602 | id 603 | 604 | 605 | 606 | YES 607 | 608 | YES 609 | saveNewAccount: 610 | toggleOpenAtLaunch: 611 | updateRefreshRate: 612 | 613 | 614 | YES 615 | 616 | saveNewAccount: 617 | id 618 | 619 | 620 | toggleOpenAtLaunch: 621 | id 622 | 623 | 624 | updateRefreshRate: 625 | id 626 | 627 | 628 | 629 | 630 | YES 631 | 632 | YES 633 | apiToken 634 | username 635 | 636 | 637 | YES 638 | NSSecureTextField 639 | NSTextField 640 | 641 | 642 | 643 | YES 644 | 645 | YES 646 | apiToken 647 | username 648 | 649 | 650 | YES 651 | 652 | apiToken 653 | NSSecureTextField 654 | 655 | 656 | username 657 | NSTextField 658 | 659 | 660 | 661 | 662 | IBProjectSource 663 | PreferencesWindowController.h 664 | 665 | 666 | 667 | 668 | YES 669 | 670 | BWHyperlinkButton 671 | NSButton 672 | 673 | IBFrameworkSource 674 | BWToolkitFramework.framework/Headers/BWHyperlinkButton.h 675 | 676 | 677 | 678 | BWHyperlinkButtonCell 679 | NSButtonCell 680 | 681 | IBFrameworkSource 682 | BWToolkitFramework.framework/Headers/BWHyperlinkButtonCell.h 683 | 684 | 685 | 686 | NSActionCell 687 | NSCell 688 | 689 | IBFrameworkSource 690 | AppKit.framework/Headers/NSActionCell.h 691 | 692 | 693 | 694 | NSApplication 695 | NSResponder 696 | 697 | IBFrameworkSource 698 | AppKit.framework/Headers/NSApplication.h 699 | 700 | 701 | 702 | NSApplication 703 | 704 | IBFrameworkSource 705 | AppKit.framework/Headers/NSApplicationScripting.h 706 | 707 | 708 | 709 | NSApplication 710 | 711 | IBFrameworkSource 712 | AppKit.framework/Headers/NSColorPanel.h 713 | 714 | 715 | 716 | NSApplication 717 | 718 | IBFrameworkSource 719 | AppKit.framework/Headers/NSHelpManager.h 720 | 721 | 722 | 723 | NSApplication 724 | 725 | IBFrameworkSource 726 | AppKit.framework/Headers/NSPageLayout.h 727 | 728 | 729 | 730 | NSApplication 731 | 732 | IBFrameworkSource 733 | AppKit.framework/Headers/NSUserInterfaceItemSearching.h 734 | 735 | 736 | 737 | NSApplication 738 | 739 | IBFrameworkSource 740 | BWToolkitFramework.framework/Headers/NSApplication+BWAdditions.h 741 | 742 | 743 | 744 | NSButton 745 | NSControl 746 | 747 | IBFrameworkSource 748 | AppKit.framework/Headers/NSButton.h 749 | 750 | 751 | 752 | NSButtonCell 753 | NSActionCell 754 | 755 | IBFrameworkSource 756 | AppKit.framework/Headers/NSButtonCell.h 757 | 758 | 759 | 760 | NSCell 761 | NSObject 762 | 763 | IBFrameworkSource 764 | AppKit.framework/Headers/NSCell.h 765 | 766 | 767 | 768 | NSControl 769 | NSView 770 | 771 | IBFrameworkSource 772 | AppKit.framework/Headers/NSControl.h 773 | 774 | 775 | 776 | NSFormatter 777 | NSObject 778 | 779 | IBFrameworkSource 780 | Foundation.framework/Headers/NSFormatter.h 781 | 782 | 783 | 784 | NSImageCell 785 | NSCell 786 | 787 | IBFrameworkSource 788 | AppKit.framework/Headers/NSImageCell.h 789 | 790 | 791 | 792 | NSImageView 793 | NSControl 794 | 795 | IBFrameworkSource 796 | AppKit.framework/Headers/NSImageView.h 797 | 798 | 799 | 800 | NSMenu 801 | NSObject 802 | 803 | IBFrameworkSource 804 | AppKit.framework/Headers/NSMenu.h 805 | 806 | 807 | 808 | NSObject 809 | 810 | IBFrameworkSource 811 | AppKit.framework/Headers/NSAccessibility.h 812 | 813 | 814 | 815 | NSObject 816 | 817 | 818 | 819 | NSObject 820 | 821 | 822 | 823 | NSObject 824 | 825 | 826 | 827 | NSObject 828 | 829 | 830 | 831 | NSObject 832 | 833 | IBFrameworkSource 834 | AppKit.framework/Headers/NSDictionaryController.h 835 | 836 | 837 | 838 | NSObject 839 | 840 | IBFrameworkSource 841 | AppKit.framework/Headers/NSDragging.h 842 | 843 | 844 | 845 | NSObject 846 | 847 | IBFrameworkSource 848 | AppKit.framework/Headers/NSFontManager.h 849 | 850 | 851 | 852 | NSObject 853 | 854 | IBFrameworkSource 855 | AppKit.framework/Headers/NSFontPanel.h 856 | 857 | 858 | 859 | NSObject 860 | 861 | IBFrameworkSource 862 | AppKit.framework/Headers/NSKeyValueBinding.h 863 | 864 | 865 | 866 | NSObject 867 | 868 | 869 | 870 | NSObject 871 | 872 | IBFrameworkSource 873 | AppKit.framework/Headers/NSNibLoading.h 874 | 875 | 876 | 877 | NSObject 878 | 879 | IBFrameworkSource 880 | AppKit.framework/Headers/NSOutlineView.h 881 | 882 | 883 | 884 | NSObject 885 | 886 | IBFrameworkSource 887 | AppKit.framework/Headers/NSPasteboard.h 888 | 889 | 890 | 891 | NSObject 892 | 893 | IBFrameworkSource 894 | AppKit.framework/Headers/NSSavePanel.h 895 | 896 | 897 | 898 | NSObject 899 | 900 | IBFrameworkSource 901 | AppKit.framework/Headers/NSTableView.h 902 | 903 | 904 | 905 | NSObject 906 | 907 | IBFrameworkSource 908 | AppKit.framework/Headers/NSToolbarItem.h 909 | 910 | 911 | 912 | NSObject 913 | 914 | IBFrameworkSource 915 | AppKit.framework/Headers/NSView.h 916 | 917 | 918 | 919 | NSObject 920 | 921 | IBFrameworkSource 922 | Foundation.framework/Headers/NSArchiver.h 923 | 924 | 925 | 926 | NSObject 927 | 928 | IBFrameworkSource 929 | Foundation.framework/Headers/NSClassDescription.h 930 | 931 | 932 | 933 | NSObject 934 | 935 | IBFrameworkSource 936 | Foundation.framework/Headers/NSError.h 937 | 938 | 939 | 940 | NSObject 941 | 942 | IBFrameworkSource 943 | Foundation.framework/Headers/NSFileManager.h 944 | 945 | 946 | 947 | NSObject 948 | 949 | IBFrameworkSource 950 | Foundation.framework/Headers/NSKeyValueCoding.h 951 | 952 | 953 | 954 | NSObject 955 | 956 | IBFrameworkSource 957 | Foundation.framework/Headers/NSKeyValueObserving.h 958 | 959 | 960 | 961 | NSObject 962 | 963 | IBFrameworkSource 964 | Foundation.framework/Headers/NSKeyedArchiver.h 965 | 966 | 967 | 968 | NSObject 969 | 970 | IBFrameworkSource 971 | Foundation.framework/Headers/NSObject.h 972 | 973 | 974 | 975 | NSObject 976 | 977 | IBFrameworkSource 978 | Foundation.framework/Headers/NSObjectScripting.h 979 | 980 | 981 | 982 | NSObject 983 | 984 | IBFrameworkSource 985 | Foundation.framework/Headers/NSPortCoder.h 986 | 987 | 988 | 989 | NSObject 990 | 991 | IBFrameworkSource 992 | Foundation.framework/Headers/NSRunLoop.h 993 | 994 | 995 | 996 | NSObject 997 | 998 | IBFrameworkSource 999 | Foundation.framework/Headers/NSScriptClassDescription.h 1000 | 1001 | 1002 | 1003 | NSObject 1004 | 1005 | IBFrameworkSource 1006 | Foundation.framework/Headers/NSScriptKeyValueCoding.h 1007 | 1008 | 1009 | 1010 | NSObject 1011 | 1012 | IBFrameworkSource 1013 | Foundation.framework/Headers/NSScriptObjectSpecifiers.h 1014 | 1015 | 1016 | 1017 | NSObject 1018 | 1019 | IBFrameworkSource 1020 | Foundation.framework/Headers/NSScriptWhoseTests.h 1021 | 1022 | 1023 | 1024 | NSObject 1025 | 1026 | IBFrameworkSource 1027 | Foundation.framework/Headers/NSThread.h 1028 | 1029 | 1030 | 1031 | NSObject 1032 | 1033 | IBFrameworkSource 1034 | Foundation.framework/Headers/NSURL.h 1035 | 1036 | 1037 | 1038 | NSObject 1039 | 1040 | IBFrameworkSource 1041 | Foundation.framework/Headers/NSURLConnection.h 1042 | 1043 | 1044 | 1045 | NSObject 1046 | 1047 | IBFrameworkSource 1048 | Foundation.framework/Headers/NSURLDownload.h 1049 | 1050 | 1051 | 1052 | NSObject 1053 | 1054 | IBFrameworkSource 1055 | Growl.framework/Headers/GrowlApplicationBridge.h 1056 | 1057 | 1058 | 1059 | NSResponder 1060 | 1061 | IBFrameworkSource 1062 | AppKit.framework/Headers/NSInterfaceStyle.h 1063 | 1064 | 1065 | 1066 | NSResponder 1067 | NSObject 1068 | 1069 | IBFrameworkSource 1070 | AppKit.framework/Headers/NSResponder.h 1071 | 1072 | 1073 | 1074 | NSSecureTextField 1075 | NSTextField 1076 | 1077 | IBFrameworkSource 1078 | AppKit.framework/Headers/NSSecureTextField.h 1079 | 1080 | 1081 | 1082 | NSSecureTextFieldCell 1083 | NSTextFieldCell 1084 | 1085 | 1086 | 1087 | NSTextField 1088 | NSControl 1089 | 1090 | IBFrameworkSource 1091 | AppKit.framework/Headers/NSTextField.h 1092 | 1093 | 1094 | 1095 | NSTextFieldCell 1096 | NSActionCell 1097 | 1098 | IBFrameworkSource 1099 | AppKit.framework/Headers/NSTextFieldCell.h 1100 | 1101 | 1102 | 1103 | NSView 1104 | 1105 | IBFrameworkSource 1106 | AppKit.framework/Headers/NSClipView.h 1107 | 1108 | 1109 | 1110 | NSView 1111 | 1112 | IBFrameworkSource 1113 | AppKit.framework/Headers/NSMenuItem.h 1114 | 1115 | 1116 | 1117 | NSView 1118 | 1119 | IBFrameworkSource 1120 | AppKit.framework/Headers/NSRulerView.h 1121 | 1122 | 1123 | 1124 | NSView 1125 | NSResponder 1126 | 1127 | 1128 | 1129 | NSView 1130 | 1131 | IBFrameworkSource 1132 | BWToolkitFramework.framework/Headers/NSView+BWAdditions.h 1133 | 1134 | 1135 | 1136 | NSWindow 1137 | 1138 | IBFrameworkSource 1139 | AppKit.framework/Headers/NSDrawer.h 1140 | 1141 | 1142 | 1143 | NSWindow 1144 | NSResponder 1145 | 1146 | IBFrameworkSource 1147 | AppKit.framework/Headers/NSWindow.h 1148 | 1149 | 1150 | 1151 | NSWindow 1152 | 1153 | IBFrameworkSource 1154 | AppKit.framework/Headers/NSWindowScripting.h 1155 | 1156 | 1157 | 1158 | NSWindow 1159 | 1160 | IBFrameworkSource 1161 | BWToolkitFramework.framework/Headers/NSWindow+BWAdditions.h 1162 | 1163 | 1164 | 1165 | NSWindowController 1166 | NSResponder 1167 | 1168 | showWindow: 1169 | id 1170 | 1171 | 1172 | showWindow: 1173 | 1174 | showWindow: 1175 | id 1176 | 1177 | 1178 | 1179 | IBFrameworkSource 1180 | AppKit.framework/Headers/NSWindowController.h 1181 | 1182 | 1183 | 1184 | 1185 | 0 1186 | IBCocoaFramework 1187 | 1188 | com.apple.InterfaceBuilder.CocoaPlugin.macosx 1189 | 1190 | 1191 | 1192 | com.apple.InterfaceBuilder.CocoaPlugin.InterfaceBuilder3 1193 | 1194 | 1195 | YES 1196 | GithubNotifier.xcodeproj 1197 | 3 1198 | 1199 | NSApplicationIcon 1200 | {128, 128} 1201 | 1202 | 1203 | 1204 | -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 | #GithubNotifier 2 | 3 | GithubNotifier is a menu-bar app for Mac OS 10.6+ that polls Github for network activity on any of your repositories. 4 | 5 | #Release History 6 | 7 | - **[1.2]** [GithubNotifier-1.2.zip][8] 8 | - Better notifications 9 | - Updates on watcher count 10 | 11 | - **[1.1]** GithubNotifier-1.1.zip 12 | - Receive notifications when someone starts watching any of your repositories. 13 | 14 | - **[1.0]** GithubNotifier-1.0.zip 15 | 16 | #Development 17 | 18 | Patches / bugs welcome. 19 | To get setup for development, be sure to run 20 | `git submodule init` && `git submodule update` to pull down the latest `CocoaREST` and `EMKeychain` files 21 | 22 | #Building 23 | 24 | Releases are done by myself, so "release" configuration requires my 25 | private key for code-signing. If you'd like to compile and run your own 26 | release build go to project settings and under "release" 27 | configuration, remove `scary-robot-development` and either leave blank 28 | or use your own key 29 | 30 | #Future 31 | 32 | - Sparkle integration (or Mac App store... debating) 33 | - New notifications: 34 | - New forks of your repositories 35 | - New issues added to your repositories 36 | 37 | #Credits: 38 | [Steven Degutis][2] for [CocoaREST][3] 39 | 40 | [ExtendMac][4] for [EMKeychain][5] 41 | 42 | [Shaun Harrison and or Enormego][6] for [NSWorkspaceHelper][7] 43 | 44 | 45 | [2]: http://degutis.org/ 46 | [3]: http://github.com/sdegutis/CocoaREST 47 | [4]: http://extendmac.com 48 | [5]: http://extendmac.com/EMKeychain 49 | [6]: http://www.enormego.com 50 | [7]: http://github.com/enormego/cocoa-helpers 51 | [8]: https://github.com/downloads/ctshryock/GithubNotifier/GithubNotifier-1.2.zip 52 | -------------------------------------------------------------------------------- /githubnotifier.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/catsby/GithubNotifier/4f5826e4579091d4e416e9ee574c974304c41968/githubnotifier.icns -------------------------------------------------------------------------------- /githubnotifier_inactive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/catsby/GithubNotifier/4f5826e4579091d4e416e9ee574c974304c41968/githubnotifier_inactive.png -------------------------------------------------------------------------------- /main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // GithubNotifier 4 | // 5 | // Created by Clinton Shryock on 7/6/10. 6 | // Copyright scary-robot 2010. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | int main(int argc, char *argv[]) 12 | { 13 | return NSApplicationMain(argc, (const char **) argv); 14 | } 15 | --------------------------------------------------------------------------------