Skip to content
Browse files

Initial Upload

  • Loading branch information...
0 parents commit d73d78ba602889b66cf0427757ebf3eb87da12ef @ljuba committed Feb 15, 2012
Showing with 19,489 additions and 0 deletions.
  1. +13 −0 .gitignore
  2. +183 −0 Appirater.h
  3. +370 −0 Appirater.m
  4. +32 −0 Classes/Agency.h
  5. +20 −0 Classes/Agency.m
  6. +35 −0 Classes/BartColorsView.h
  7. +81 −0 Classes/BartColorsView.m
  8. +16 −0 Classes/BartStopDelegate.h
  9. +20 −0 Classes/BartStopDelegate.m
  10. +20 −0 Classes/BartStopDetails.h
  11. +488 −0 Classes/BartStopDetails.m
  12. +44 −0 Classes/ButtonBarCell.h
  13. +95 −0 Classes/ButtonBarCell.m
  14. +609 −0 Classes/ButtonBarCell.xib
  15. +31 −0 Classes/Classes-1.moved-aside/Agency.h
  16. +19 −0 Classes/Classes-1.moved-aside/Agency.m
  17. +35 −0 Classes/Classes-1.moved-aside/Direction.h
  18. +23 −0 Classes/Classes-1.moved-aside/Direction.m
  19. +34 −0 Classes/Classes-1.moved-aside/Stop.h
  20. +22 −0 Classes/Classes-1.moved-aside/Stop.m
  21. +31 −0 Classes/Classes-2.moved-aside/Agency.h
  22. +19 −0 Classes/Classes-2.moved-aside/Agency.m
  23. +35 −0 Classes/Classes-2.moved-aside/Direction.h
  24. +23 −0 Classes/Classes-2.moved-aside/Direction.m
  25. +37 −0 Classes/Classes-2.moved-aside/Route.h
  26. +25 −0 Classes/Classes-2.moved-aside/Route.m
  27. +34 −0 Classes/Classes-2.moved-aside/Stop.h
  28. +22 −0 Classes/Classes-2.moved-aside/Stop.m
  29. +37 −0 Classes/Classes-3.moved-aside/DirectionsVC.m
  30. +34 −0 Classes/Classes-4.moved-aside/Stop.h
  31. +22 −0 Classes/Classes-4.moved-aside/Stop.m
  32. +35 −0 Classes/Classes-5.moved-aside/Stop.h
  33. +23 −0 Classes/Classes-5.moved-aside/Stop.m
  34. +26 −0 Classes/Constants.h
  35. +6 −0 Classes/Constants.m
  36. +21 −0 Classes/CustomButton.h
  37. +64 −0 Classes/CustomButton.m
  38. +53 −0 Classes/DataHelper.h
  39. +461 −0 Classes/DataHelper.m
  40. +27 −0 Classes/DataImporter.h
  41. +395 −0 Classes/DataImporter.m
  42. +37 −0 Classes/Destination.h
  43. +104 −0 Classes/Destination.m
  44. +27 −0 Classes/DestinationCellView.h
  45. +111 −0 Classes/DestinationCellView.m
  46. +36 −0 Classes/Direction.h
  47. +24 −0 Classes/Direction.m
  48. +47 −0 Classes/DirectionAnnotationView.h
  49. +159 −0 Classes/DirectionAnnotationView.m
  50. +601 −0 Classes/DirectionAnnotationView.xib
  51. +25 −0 Classes/DirectionCellView.h
  52. +113 −0 Classes/DirectionCellView.m
  53. +42 −0 Classes/DirectionsMapView.h
  54. +294 −0 Classes/DirectionsMapView.m
  55. +484 −0 Classes/DirectionsMapView.xib
  56. +45 −0 Classes/DirectionsVC.h
  57. +297 −0 Classes/DirectionsVC.m
  58. +343 −0 Classes/DirectionsVC.xib
  59. +26 −0 Classes/FavoriteStops.h
  60. +320 −0 Classes/FavoriteStops.m
  61. +25 −0 Classes/FavoriteStopsDelegate.h
  62. +343 −0 Classes/FavoriteStopsDelegate.m
  63. +16 −0 Classes/FavoriteTripsDelegate.h
  64. +43 −0 Classes/FavoriteTripsDelegate.m
  65. +23 −0 Classes/FavoritesDelegate.h
  66. +44 −0 Classes/FavoritesDelegate.m
  67. +29 −0 Classes/FavoritesManager.h
  68. +526 −0 Classes/FavoritesManager.m
  69. +20 −0 Classes/FavoritesTest.h
  70. +18 −0 Classes/FavoritesTest.m
  71. +51 −0 Classes/FavoritesVC.h
  72. +416 −0 Classes/FavoritesVC.m
  73. +469 −0 Classes/FavoritesVC.xib
  74. +23 −0 Classes/LegControlCell.h
  75. +53 −0 Classes/LegControlCell.m
  76. +20 −0 Classes/LineCell.h
  77. +34 −0 Classes/LineCell.m
  78. +60 −0 Classes/LineCellView.h
  79. +521 −0 Classes/LineCellView.m
  80. +63 −0 Classes/LineRow.h
  81. +290 −0 Classes/LineRow.m
  82. +16 −0 Classes/LinesTableView.h
  83. +22 −0 Classes/LinesTableView.m
  84. +40 −0 Classes/LinesVC.h
  85. +239 −0 Classes/LinesVC.m
  86. +424 −0 Classes/LinesVC.xib
  87. +87 −0 Classes/LiveRouteTVC.h
  88. +741 −0 Classes/LiveRouteTVC.m
  89. +536 −0 Classes/LiveRouteTVC.xib
  90. +1,067 −0 Classes/MainWindow.xib
  91. +15 −0 Classes/NSString+PercentEncode.h
  92. +33 −0 Classes/NSString+PercentEncode.m
  93. +42 −0 Classes/NearMeVC.h
  94. +418 −0 Classes/NearMeVC.m
  95. +450 −0 Classes/NearMeVC.xib
  96. +23 −0 Classes/NextBusStopDetails.h
  97. +707 −0 Classes/NextBusStopDetails.m
  98. +22 −0 Classes/ParticipateVC.h
  99. +155 −0 Classes/ParticipateVC.m
  100. +245 −0 Classes/ParticipateVC.xib
  101. +26 −0 Classes/Prediction.h
  102. +38 −0 Classes/Prediction.m
  103. +34 −0 Classes/PredictionLabel.h
  104. +165 −0 Classes/PredictionLabel.m
  105. +30 −0 Classes/PredictionRequest.h
  106. +26 −0 Classes/PredictionRequest.m
  107. +43 −0 Classes/PredictionsManager.h
  108. +320 −0 Classes/PredictionsManager.m
  109. +16 −0 Classes/PredictionsManagerDelegate.h
  110. +14 −0 Classes/PredictionsManagerDelegate.m
  111. +30 −0 Classes/PredictorOperation.h
  112. +350 −0 Classes/PredictorOperation.m
  113. +36 −0 Classes/Route.h
  114. +24 −0 Classes/Route.m
  115. +20 −0 Classes/RoutesCell.h
  116. +36 −0 Classes/RoutesCell.m
  117. +21 −0 Classes/RowDivider.h
  118. +144 −0 Classes/RowDivider.m
  119. +20 −0 Classes/SettingsVC.h
  120. +58 −0 Classes/SettingsVC.m
  121. +477 −0 Classes/SettingsVC.xib
  122. +37 −0 Classes/Stop.h
  123. +25 −0 Classes/Stop.m
  124. +34 −0 Classes/StopAnnotation.h
  125. +108 −0 Classes/StopAnnotation.m
  126. +88 −0 Classes/StopDetails.h
  127. +380 −0 Classes/StopDetails.m
  128. +29 −0 Classes/StopNameRow.h
  129. +81 −0 Classes/StopNameRow.m
  130. +36 −0 Classes/StopsTVC.h
  131. +295 −0 Classes/StopsTVC.m
  132. +33 −0 Classes/TransitDelegate.h
  133. +190 −0 Classes/TransitDelegate.m
  134. +56 −0 Classes/TransitLeg.h
  135. +71 −0 Classes/TransitLeg.m
  136. +23 −0 Classes/TransitLegCell.h
  137. +51 −0 Classes/TransitLegCell.m
  138. +45 −0 Classes/TransitLegView.h
  139. +570 −0 Classes/TransitLegView.m
  140. +36 −0 Classes/Trip.h
  141. +214 −0 Classes/Trip.m
  142. +35 −0 Classes/TripDetailsTVC.h
Sorry, we could not display the entire diff because too many files (597) changed.
13 .gitignore
@@ -0,0 +1,13 @@
+
+.DS_Store
+
+transporter.xcodeproj/project.xcworkspace/xcuserdata/*.xcuserdatad/UserInterfaceState.xcuserstate
+
+transporter.xcodeproj/xcuserdata/*.xcuserdatad/xcschemes/transporter.xcscheme
+
+transporter.xcodeproj/xcuserdata/*.xcuserdatad/xcschemes/xcschememanagement.plist
+
+transporter.xcodeproj/project.xcworkspace/contents.xcworkspacedata
+
+config.plist
+
183 Appirater.h
@@ -0,0 +1,183 @@
+/*
+ This file is part of Appirater.
+
+ Copyright (c) 2010, Arash Payan
+ All rights reserved.
+
+ Permission is hereby granted, free of charge, to any person
+ obtaining a copy of this software and associated documentation
+ files (the "Software"), to deal in the Software without
+ restriction, including without limitation the rights to use,
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following
+ conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ OTHER DEALINGS IN THE SOFTWARE.
+ */
+/*
+ * Appirater.h
+ * appirater
+ *
+ * Created by Arash Payan on 9/5/09.
+ * http://arashpayan.com
+ * Copyright 2010 Arash Payan. All rights reserved.
+ */
+
+#import <Foundation/Foundation.h>
+
+extern NSString *const kAppiraterFirstUseDate;
+extern NSString *const kAppiraterUseCount;
+extern NSString *const kAppiraterSignificantEventCount;
+extern NSString *const kAppiraterCurrentVersion;
+extern NSString *const kAppiraterRatedCurrentVersion;
+extern NSString *const kAppiraterDeclinedToRate;
+
+/*
+ Place your Apple generated software id here.
+ */
+#define APPIRATER_APP_ID 373726282
+
+/*
+ Your app's name.
+ */
+#define APPIRATER_APP_NAME @"Transporter"
+
+/*
+ This is the message your users will see once they've passed the day+launches
+ threshold.
+ */
+#define APPIRATER_MESSAGE [NSString stringWithFormat:@"Find %@ useful? Why not rate it on the App Store? It take less than a minute. Thanks for your support!", APPIRATER_APP_NAME]
+
+/*
+ This is the title of the message alert that users will see.
+ */
+#define APPIRATER_MESSAGE_TITLE [NSString stringWithFormat:@"Rate %@", APPIRATER_APP_NAME]
+
+/*
+ The text of the button that rejects reviewing the app.
+ */
+#define APPIRATER_CANCEL_BUTTON @"No, Thanks"
+
+/*
+ Text of button that will send user to app review page.
+ */
+#define APPIRATER_RATE_BUTTON [NSString stringWithFormat:@"Rate %@", APPIRATER_APP_NAME]
+
+/*
+ Text for button to remind the user to review later.
+ */
+#define APPIRATER_RATE_LATER @"Remind me later"
+
+/*
+ Users will need to have the same version of your app installed for this many
+ days before they will be prompted to rate it.
+ */
+#define APPIRATER_DAYS_UNTIL_PROMPT 0 // double
+
+/*
+ An example of a 'use' would be if the user launched the app. Bringing the app
+ into the foreground (on devices that support it) would also be considered
+ a 'use'. You tell Appirater about these events using the two methods:
+ [Appirater appLaunched:]
+ [Appirater appEnteredForeground:]
+
+ Users need to 'use' the same version of the app this many times before
+ before they will be prompted to rate it.
+ */
+#define APPIRATER_USES_UNTIL_PROMPT 10 // integer
+
+/*
+ A significant event can be anything you want to be in your app. In a
+ telephone app, a significant event might be placing or receiving a call.
+ In a game, it might be beating a level or a boss. This is just another
+ layer of filtering that can be used to make sure that only the most
+ loyal of your users are being prompted to rate you on the app store.
+ If you leave this at a value of -1, then this won't be a criteria
+ used for rating. To tell Appirater that the user has performed
+ a significant event, call the method:
+ [Appirater userDidSignificantEvent:];
+ */
+#define APPIRATER_SIG_EVENTS_UNTIL_PROMPT -1 // integer
+
+/*
+ Once the rating alert is presented to the user, they might select
+ 'Remind me later'. This value specifies how long (in days) Appirater
+ will wait before reminding them.
+ */
+#define APPIRATER_TIME_BEFORE_REMINDING 1 // double
+
+/*
+ 'YES' will show the Appirater alert everytime. Useful for testing how your message
+ looks and making sure the link to your app's review page works.
+ */
+#define APPIRATER_DEBUG NO
+
+@interface Appirater : NSObject <UIAlertViewDelegate> {
+
+}
+
+/*
+ DEPRECATED: While still functional, it's better to use
+ appLaunched:(BOOL)canPromptForRating instead.
+
+ Calls [Appirater appLaunched:YES]. See appLaunched: for details of functionality.
+ */
++ (void)appLaunched;
+
+/*
+ Tells Appirater that the app has launched, and on devices that do NOT
+ support multitasking, the 'uses' count will be incremented. You should
+ call this method at the end of your application delegate's
+ application:didFinishLaunchingWithOptions: method.
+
+ If the app has been used enough to be rated (and enough significant events),
+ you can suppress the rating alert
+ by passing NO for canPromptForRating. The rating alert will simply be postponed
+ until it is called again with YES for canPromptForRating. The rating alert
+ can also be triggered by appEnteredForeground: and userDidSignificantEvent:
+ (as long as you pass YES for canPromptForRating in those methods).
+ */
++ (void)appLaunched:(BOOL)canPromptForRating;
+
+/*
+ Tells Appirater that the app was brought to the foreground on multitasking
+ devices. You should call this method from the application delegate's
+ applicationWillEnterForeground: method.
+
+ If the app has been used enough to be rated (and enough significant events),
+ you can suppress the rating alert
+ by passing NO for canPromptForRating. The rating alert will simply be postponed
+ until it is called again with YES for canPromptForRating. The rating alert
+ can also be triggered by appLaunched: and userDidSignificantEvent:
+ (as long as you pass YES for canPromptForRating in those methods).
+ */
++ (void)appEnteredForeground:(BOOL)canPromptForRating;
+
+/*
+ Tells Appirater that the user performed a significant event. A significant
+ event is whatever you want it to be. If you're app is used to make VoIP
+ calls, then you might want to call this method whenever the user places
+ a call. If it's a game, you might want to call this whenever the user
+ beats a level boss.
+
+ If the user has performed enough significant events and used the app enough,
+ you can suppress the rating alert by passing NO for canPromptForRating. The
+ rating alert will simply be postponed until it is called again with YES for
+ canPromptForRating. The rating alert can also be triggered by appLaunched:
+ and appEnteredForeground: (as long as you pass YES for canPromptForRating
+ in those methods).
+ */
++ (void)userDidSignificantEvent:(BOOL)canPromptForRating;
+
+@end
370 Appirater.m
@@ -0,0 +1,370 @@
+/*
+ This file is part of Appirater.
+
+ Copyright (c) 2010, Arash Payan
+ All rights reserved.
+
+ Permission is hereby granted, free of charge, to any person
+ obtaining a copy of this software and associated documentation
+ files (the "Software"), to deal in the Software without
+ restriction, including without limitation the rights to use,
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following
+ conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ OTHER DEALINGS IN THE SOFTWARE.
+ */
+/*
+ * Appirater.m
+ * appirater
+ *
+ * Created by Arash Payan on 9/5/09.
+ * http://arashpayan.com
+ * Copyright 2010 Arash Payan. All rights reserved.
+ */
+
+#import "Appirater.h"
+#import <SystemConfiguration/SCNetworkReachability.h>
+#include <netinet/in.h>
+
+NSString *const kAppiraterFirstUseDate = @"kAppiraterFirstUseDate";
+NSString *const kAppiraterUseCount = @"kAppiraterUseCount";
+NSString *const kAppiraterSignificantEventCount = @"kAppiraterSignificantEventCount";
+NSString *const kAppiraterCurrentVersion = @"kAppiraterCurrentVersion";
+NSString *const kAppiraterRatedCurrentVersion = @"kAppiraterRatedCurrentVersion";
+NSString *const kAppiraterDeclinedToRate = @"kAppiraterDeclinedToRate";
+NSString *const kAppiraterReminderRequestDate = @"kAppiraterReminderRequestDate";
+
+NSString *templateReviewURL = @"itms-apps://itunes.apple.com/WebObjects/MZStore.woa/wa/viewContentsUserReviews?id=APP_ID&onlyLatestVersion=true&pageNumber=0&sortOrdering=1&type=Purple+Software";
+NSString *templateReviewURLIpad = @"itms-apps://ax.itunes.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=APP_ID";
+
+
+@interface Appirater (hidden)
+- (BOOL)connectedToNetwork;
++ (Appirater*)sharedInstance;
+- (void)showRatingAlert;
+- (BOOL)ratingConditionsHaveBeenMet;
+- (void)incrementUseCount;
+@end
+
+@implementation Appirater (hidden)
+
+- (BOOL)connectedToNetwork {
+ // Create zero addy
+ struct sockaddr_in zeroAddress;
+ bzero(&zeroAddress, sizeof(zeroAddress));
+ zeroAddress.sin_len = sizeof(zeroAddress);
+ zeroAddress.sin_family = AF_INET;
+
+ // Recover reachability flags
+ SCNetworkReachabilityRef defaultRouteReachability = SCNetworkReachabilityCreateWithAddress(NULL, (struct sockaddr *)&zeroAddress);
+ SCNetworkReachabilityFlags flags;
+
+ BOOL didRetrieveFlags = SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags);
+ CFRelease(defaultRouteReachability);
+
+ if (!didRetrieveFlags)
+ {
+ NSLog(@"Error. Could not recover network reachability flags");
+ return NO;
+ }
+
+ BOOL isReachable = flags & kSCNetworkFlagsReachable;
+ BOOL needsConnection = flags & kSCNetworkFlagsConnectionRequired;
+ BOOL nonWiFi = flags & kSCNetworkReachabilityFlagsTransientConnection;
+
+ NSURL *testURL = [NSURL URLWithString:@"http://www.apple.com/"];
+ NSURLRequest *testRequest = [NSURLRequest requestWithURL:testURL cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:20.0];
+ NSURLConnection *testConnection = [[NSURLConnection alloc] initWithRequest:testRequest delegate:self];
+
+ return ((isReachable && !needsConnection) || nonWiFi) ? (testConnection ? YES : NO) : NO;
+}
+
++ (Appirater*)sharedInstance {
+ static Appirater *appirater = nil;
+ if (appirater == nil)
+ {
+ @synchronized(self) {
+ if (appirater == nil)
+ appirater = [[Appirater alloc] init];
+ }
+ }
+
+ return appirater;
+}
+
+- (void)showRatingAlert {
+ UIAlertView *alertView = [[[UIAlertView alloc] initWithTitle:APPIRATER_MESSAGE_TITLE
+ message:APPIRATER_MESSAGE
+ delegate:self
+ cancelButtonTitle:APPIRATER_CANCEL_BUTTON
+ otherButtonTitles:APPIRATER_RATE_BUTTON, APPIRATER_RATE_LATER, nil] autorelease];
+ [alertView show];
+}
+
+- (BOOL)ratingConditionsHaveBeenMet {
+ if (APPIRATER_DEBUG)
+ return YES;
+
+ NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
+
+ NSDate *dateOfFirstLaunch = [NSDate dateWithTimeIntervalSince1970:[userDefaults doubleForKey:kAppiraterFirstUseDate]];
+ NSTimeInterval timeSinceFirstLaunch = [[NSDate date] timeIntervalSinceDate:dateOfFirstLaunch];
+ NSTimeInterval timeUntilRate = 60 * 60 * 24 * APPIRATER_DAYS_UNTIL_PROMPT;
+ if (timeSinceFirstLaunch < timeUntilRate)
+ return NO;
+
+ // check if the app has been used enough
+ int useCount = [userDefaults integerForKey:kAppiraterUseCount];
+ if (useCount <= APPIRATER_USES_UNTIL_PROMPT)
+ return NO;
+
+ // check if the user has done enough significant events
+ int sigEventCount = [userDefaults integerForKey:kAppiraterSignificantEventCount];
+ if (sigEventCount <= APPIRATER_SIG_EVENTS_UNTIL_PROMPT)
+ return NO;
+
+ // has the user previously declined to rate this version of the app?
+ if ([userDefaults boolForKey:kAppiraterDeclinedToRate])
+ return NO;
+
+ // has the user already rated the app?
+ if ([userDefaults boolForKey:kAppiraterRatedCurrentVersion])
+ return NO;
+
+ // if the user wanted to be reminded later, has enough time passed?
+ NSDate *reminderRequestDate = [NSDate dateWithTimeIntervalSince1970:[userDefaults doubleForKey:kAppiraterReminderRequestDate]];
+ NSTimeInterval timeSinceReminderRequest = [[NSDate date] timeIntervalSinceDate:reminderRequestDate];
+ NSTimeInterval timeUntilReminder = 60 * 60 * 24 * APPIRATER_TIME_BEFORE_REMINDING;
+ if (timeSinceReminderRequest < timeUntilReminder)
+ return NO;
+
+ return YES;
+}
+
+- (void)incrementUseCount {
+
+ // get the app's version
+ NSString *version = [[[NSBundle mainBundle] infoDictionary] objectForKey:(NSString*)kCFBundleVersionKey];
+
+ // get the version number that we've been tracking
+ NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
+ NSString *trackingVersion = [userDefaults stringForKey:kAppiraterCurrentVersion];
+ if (trackingVersion == nil)
+ {
+ trackingVersion = version;
+ [userDefaults setObject:version forKey:kAppiraterCurrentVersion];
+ }
+
+ if (APPIRATER_DEBUG)
+ NSLog(@"APPIRATER Tracking version: %@", trackingVersion);
+
+ if ([trackingVersion isEqualToString:version])
+ {
+
+ // check if the first use date has been set. if not, set it.
+ NSTimeInterval timeInterval = [userDefaults doubleForKey:kAppiraterFirstUseDate];
+ if (timeInterval == 0)
+ {
+ timeInterval = [[NSDate date] timeIntervalSince1970];
+ [userDefaults setDouble:timeInterval forKey:kAppiraterFirstUseDate];
+ }
+
+ // increment the use count
+ int useCount = [userDefaults integerForKey:kAppiraterUseCount];
+ useCount++;
+ [userDefaults setInteger:useCount forKey:kAppiraterUseCount];
+
+ if (APPIRATER_DEBUG)
+ NSLog(@"APPIRATER Use count: %d", useCount);
+ }
+ else
+ {
+ // it's a new version of the app, so restart tracking
+ [userDefaults setObject:version forKey:kAppiraterCurrentVersion];
+ [userDefaults setDouble:[[NSDate date] timeIntervalSince1970] forKey:kAppiraterFirstUseDate];
+ [userDefaults setInteger:1 forKey:kAppiraterUseCount];
+ [userDefaults setInteger:0 forKey:kAppiraterSignificantEventCount];
+ [userDefaults setBool:NO forKey:kAppiraterRatedCurrentVersion];
+ [userDefaults setBool:NO forKey:kAppiraterDeclinedToRate];
+ [userDefaults setDouble:0 forKey:kAppiraterReminderRequestDate];
+ }
+
+ [userDefaults synchronize];
+}
+
+- (void)incrementSignificantEventCount {
+ // get the app's version
+ NSString *version = [[[NSBundle mainBundle] infoDictionary] objectForKey:(NSString*)kCFBundleVersionKey];
+
+ // get the version number that we've been tracking
+ NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
+ NSString *trackingVersion = [userDefaults stringForKey:kAppiraterCurrentVersion];
+ if (trackingVersion == nil)
+ {
+ trackingVersion = version;
+ [userDefaults setObject:version forKey:kAppiraterCurrentVersion];
+ }
+
+ if (APPIRATER_DEBUG)
+ NSLog(@"APPIRATER Tracking version: %@", trackingVersion);
+
+ if ([trackingVersion isEqualToString:version])
+ {
+ // check if the first use date has been set. if not, set it.
+ NSTimeInterval timeInterval = [userDefaults doubleForKey:kAppiraterFirstUseDate];
+ if (timeInterval == 0)
+ {
+ timeInterval = [[NSDate date] timeIntervalSince1970];
+ [userDefaults setDouble:timeInterval forKey:kAppiraterFirstUseDate];
+ }
+
+ // increment the significant event count
+ int sigEventCount = [userDefaults integerForKey:kAppiraterSignificantEventCount];
+ sigEventCount++;
+ [userDefaults setInteger:sigEventCount forKey:kAppiraterSignificantEventCount];
+ if (APPIRATER_DEBUG)
+ NSLog(@"APPIRATER Significant event count: %d", sigEventCount);
+ }
+ else
+ {
+ // it's a new version of the app, so restart tracking
+ [userDefaults setObject:version forKey:kAppiraterCurrentVersion];
+ [userDefaults setDouble:0 forKey:kAppiraterFirstUseDate];
+ [userDefaults setInteger:0 forKey:kAppiraterUseCount];
+ [userDefaults setInteger:1 forKey:kAppiraterSignificantEventCount];
+ [userDefaults setBool:NO forKey:kAppiraterRatedCurrentVersion];
+ [userDefaults setBool:NO forKey:kAppiraterDeclinedToRate];
+ [userDefaults setDouble:0 forKey:kAppiraterReminderRequestDate];
+ }
+
+ [userDefaults synchronize];
+}
+
+@end
+
+
+@implementation Appirater
+
+- (void)incrementAndRate:(NSNumber*)_canPromptForRating {
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+ [self incrementUseCount];
+
+ if ([_canPromptForRating boolValue] == YES &&
+ [self ratingConditionsHaveBeenMet] &&
+ [self connectedToNetwork])
+ {
+ [self performSelectorOnMainThread:@selector(showRatingAlert) withObject:nil waitUntilDone:NO];
+ }
+
+ [pool release];
+}
+
+- (void)incrementSignificantEventAndRate:(NSNumber*)_canPromptForRating {
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+ [self incrementSignificantEventCount];
+
+ if ([_canPromptForRating boolValue] == YES &&
+ [self ratingConditionsHaveBeenMet] &&
+ [self connectedToNetwork])
+ {
+ [self performSelectorOnMainThread:@selector(showRatingAlert) withObject:nil waitUntilDone:NO];
+ }
+
+ [pool release];
+}
+
++ (void)appLaunched {
+ [Appirater appLaunched:YES];
+}
+
++ (void)appLaunched:(BOOL)canPromptForRating {
+ /* We only count launches on non-multitasking devices, because
+ multitasking devices also get a usage call when they come
+ into the foreground and we don't want to count app launches
+ as two uses on multitasking devices. */
+ UIDevice *device = [UIDevice currentDevice];
+ if ([device respondsToSelector:@selector(multitaskingSupported)] &&
+ device.multitaskingSupported)
+ {
+ return;
+ }
+
+ NSNumber *_canPromptForRating = [[NSNumber alloc] initWithBool:canPromptForRating];
+ [NSThread detachNewThreadSelector:@selector(incrementAndRate:)
+ toTarget:[Appirater sharedInstance]
+ withObject:_canPromptForRating];
+ [_canPromptForRating release];
+}
+
++ (void)appEnteredForeground:(BOOL)canPromptForRating {
+ NSNumber *_canPromptForRating = [[NSNumber alloc] initWithBool:canPromptForRating];
+ [NSThread detachNewThreadSelector:@selector(incrementAndRate:)
+ toTarget:[Appirater sharedInstance]
+ withObject:_canPromptForRating];
+ [_canPromptForRating release];
+}
+
++ (void)userDidSignificantEvent:(BOOL)canPromptForRating {
+ NSNumber *_canPromptForRating = [[NSNumber alloc] initWithBool:canPromptForRating];
+ [NSThread detachNewThreadSelector:@selector(incrementSignificantEventAndRate:)
+ toTarget:[Appirater sharedInstance]
+ withObject:_canPromptForRating];
+ [_canPromptForRating release];
+}
+
+- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
+ NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
+
+ switch (buttonIndex) {
+ case 0:
+ {
+ // they don't want to rate it
+ [userDefaults setBool:YES forKey:kAppiraterDeclinedToRate];
+ [userDefaults synchronize];
+ break;
+ }
+ case 1:
+ {
+ // they want to rate it
+ NSString *reviewURL = nil;
+ // figure out which URL to use. iPad only apps have to use a different app store URL
+ NSDictionary *bundleDictionary = [[NSBundle mainBundle] infoDictionary];
+ if ([bundleDictionary objectForKey:@"UISupportedInterfaceOrientations"] != nil &&
+ [bundleDictionary objectForKey:@"UISupportedInterfaceOrientations~ipad"] == nil)
+ {
+ // it's an iPad only app, so use the iPad url
+ reviewURL = [templateReviewURLIpad stringByReplacingOccurrencesOfString:@"APP_ID" withString:[NSString stringWithFormat:@"%d", APPIRATER_APP_ID]];
+ }
+ else // iPhone or Universal app, so we can use the direct url
+ reviewURL = [templateReviewURL stringByReplacingOccurrencesOfString:@"APP_ID" withString:[NSString stringWithFormat:@"%d", APPIRATER_APP_ID]];
+ [userDefaults setBool:YES forKey:kAppiraterRatedCurrentVersion];
+ [userDefaults synchronize];
+
+ [[UIApplication sharedApplication] openURL:[NSURL URLWithString:reviewURL]];
+ break;
+ }
+ case 2:
+ // remind them later
+ [userDefaults setDouble:[[NSDate date] timeIntervalSince1970] forKey:kAppiraterReminderRequestDate];
+ [userDefaults synchronize];
+ break;
+ default:
+ break;
+ }
+}
+
+@end
32 Classes/Agency.h
@@ -0,0 +1,32 @@
+//
+// Agency.h
+// transporter
+//
+// Created by Ljuba Miljkovic on 6/13/10.
+// Copyright 2010 __MyCompanyName__. All rights reserved.
+//
+
+#import <CoreData/CoreData.h>
+
+@class Route;
+
+@interface Agency : NSManagedObject
+{
+}
+
+@property (nonatomic, retain) NSString * shortTitle;
+@property (nonatomic, retain) NSString * title;
+@property (nonatomic, retain) NSNumber * lastUpdate;
+@property (nonatomic, retain) NSSet* routes;
+
+@end
+
+
+@interface Agency (CoreDataGeneratedAccessors)
+- (void)addRoutesObject:(Route *)value;
+- (void)removeRoutesObject:(Route *)value;
+- (void)addRoutes:(NSSet *)value;
+- (void)removeRoutes:(NSSet *)value;
+
+@end
+
20 Classes/Agency.m
@@ -0,0 +1,20 @@
+//
+// Agency.m
+// transporter
+//
+// Created by Ljuba Miljkovic on 6/13/10.
+// Copyright 2010 __MyCompanyName__. All rights reserved.
+//
+
+#import "Agency.h"
+
+#import "Route.h"
+
+@implementation Agency
+
+@dynamic shortTitle;
+@dynamic title;
+@dynamic lastUpdate;
+@dynamic routes;
+
+@end
35 Classes/BartColorsView.h
@@ -0,0 +1,35 @@
+//
+// BartColorsView.h
+// kronos
+//
+// Created by Ljuba Miljkovic on 4/17/10.
+// Copyright 2010 __MyCompanyName__. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+#define kBartColorSpacer 3
+
+@interface BartColorsView : UIView {
+
+ NSArray *colors;
+
+ UIImage *redImage;
+ UIImage *orangeImage;
+ UIImage *yellowImage;
+ UIImage *blueImage;
+ UIImage *greenImage;
+
+}
+
+- (id)initWithColors:(NSArray *)_colors atPoint:(CGPoint)point;
+
+@property (nonatomic, retain) NSArray *colors;
+
+@property (nonatomic, retain) UIImage *redImage;
+@property (nonatomic, retain) UIImage *orangeImage;
+@property (nonatomic, retain) UIImage *yellowImage;
+@property (nonatomic, retain) UIImage *blueImage;
+@property (nonatomic, retain) UIImage *greenImage;
+
+@end
81 Classes/BartColorsView.m
@@ -0,0 +1,81 @@
+//
+// BartColorsView.m
+// kronos
+//
+// Created by Ljuba Miljkovic on 4/17/10.
+// Copyright 2010 __MyCompanyName__. All rights reserved.
+//
+
+#import "BartColorsView.h"
+
+
+@implementation BartColorsView
+
+@synthesize redImage, orangeImage, yellowImage, greenImage, blueImage, colors;
+
+- (id)initWithColors:(NSArray *)_colors atPoint:(CGPoint)point {
+
+ if ((self = [super init])) {
+
+ self.redImage = [[UIImage imageNamed:@"bart-red.png"] retain];
+ self.orangeImage = [[UIImage imageNamed:@"bart-orange.png"] retain];
+ self.yellowImage = [[UIImage imageNamed:@"bart-yellow.png"] retain];
+ self.greenImage = [[UIImage imageNamed:@"bart-green.png"] retain];
+ self.blueImage = [[UIImage imageNamed:@"bart-blue.png"] retain];
+
+ self.opaque = NO;
+
+ colors = _colors;
+
+ CGSize size = CGSizeMake(5*redImage.size.width + 5*kBartColorSpacer, redImage.size.height);
+
+ self.frame = CGRectMake(point.x, point.y, size.width, size.height);
+
+ }
+ return self;
+}
+
+- (void)drawRect:(CGRect)rect {
+
+ int x = 0;
+ int y = 0;
+
+ for (NSString *color in colors) {
+
+ x = [colors indexOfObject:color] * (redImage.size.width + kBartColorSpacer);
+
+ CGPoint point = CGPointMake(x,y);
+
+ if ([color isEqual:@"red"]) {
+ [redImage drawAtPoint:point];
+ }
+ else if ([color isEqual:@"orange"]) {
+ [orangeImage drawAtPoint:point];
+ }
+ else if ([color isEqual:@"yellow"]) {
+ [yellowImage drawAtPoint:point];
+ }
+ else if ([color isEqual:@"green"]) {
+ [greenImage drawAtPoint:point];
+ }
+ else if ([color isEqual:@"blue"]) {
+ [blueImage drawAtPoint:point];
+ }
+ }
+
+}
+
+
+- (void)dealloc {
+
+ [redImage release];
+ [orangeImage release];
+ [yellowImage release];
+ [greenImage release];
+ [blueImage release];
+
+ [super dealloc];
+}
+
+
+@end
16 Classes/BartStopDelegate.h
@@ -0,0 +1,16 @@
+//
+// BartStopDelegate.h
+// kronos
+//
+// Created by Ljuba Miljkovic on 4/5/10.
+// Copyright 2010 __MyCompanyName__. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+
+@interface BartStopDelegate : NSObject <UITableViewDelegate, UITableViewDataSource> {
+
+}
+
+@end
20 Classes/BartStopDelegate.m
@@ -0,0 +1,20 @@
+//
+// BartStopDelegate.m
+// kronos
+//
+// Created by Ljuba Miljkovic on 4/5/10.
+// Copyright 2010 __MyCompanyName__. All rights reserved.
+//
+
+#import "BartStopDelegate.h"
+
+
+@implementation BartStopDelegate
+
+
+
+
+
+
+
+@end
20 Classes/BartStopDetails.h
@@ -0,0 +1,20 @@
+//
+// BartStopDetails.h
+// transporter
+//
+// Created by Ljuba Miljkovic on 4/26/10.
+// Copyright 2010 __MyCompanyName__. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+#import "StopDetails.h"
+
+@interface BartStopDetails : StopDetails {
+
+ NSMutableArray *platforms;
+
+}
+
+@property (nonatomic, retain) NSMutableArray *platforms;
+
+@end
488 Classes/BartStopDetails.m
@@ -0,0 +1,488 @@
+ //
+// BartStopDetails.m
+// transporter
+//
+// Created by Ljuba Miljkovic on 4/26/10.
+// Copyright 2010 __MyCompanyName__. All rights reserved.
+//
+
+#import "BartStopDetails.h"
+#import "TouchXML.h"
+#import "DestinationCellView.h"
+
+@implementation BartStopDetails
+
+@synthesize platforms;
+
+// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
+- (void)viewDidLoad {
+ [super viewDidLoad];
+
+ stopTitleImageView.image = [UIImage imageNamed:@"stop-name-background-bart.png"];
+
+ //SETUP THE CONTENTS ARRAY WITH SHOW=TRUE DIRECTIONS AND FAVORITED DIRECTIONS
+ [self setupInitialContents];
+
+}
+
+- (void)setupInitialContents {
+
+ [super setupInitialContents];
+
+ //setup stop name
+ self.stopTitleLabel.text = stop.title;
+
+ //CREATE A DICTIONARY OF PLATFORM NUMBERS AND STOP TAGS
+ NSMutableDictionary *platformsDict = [[NSMutableDictionary alloc] init];
+
+ //load platforms xml file
+ NSString *platformsPath = [[NSBundle mainBundle] pathForResource:@"bart-platforms" ofType:@"xml"];
+ NSData *platformsData = [NSData dataWithContentsOfFile:platformsPath];
+
+ CXMLDocument *platformParser = [[[CXMLDocument alloc] initWithData:platformsData options:0 error:nil] autorelease];
+
+ NSString *xPath = [NSString stringWithFormat:@"//agency/stop[@tag='%@']/platform", stop.tag];
+
+ NSArray *platformNodes = [platformParser nodesForXPath:xPath error:nil];
+
+ for (CXMLElement *platformElement in platformNodes) {
+
+ //add each destination in the platform to the platformsDict for that platform number
+ NSMutableArray *destinationStopTags = [[NSMutableArray alloc] init];
+ NSArray *destinationNodes = [platformElement nodesForXPath:@"./destination" error:nil];
+
+ for (CXMLElement *destinationNode in destinationNodes) {
+
+ NSString *stopTag = [destinationNode stringValue];
+ [destinationStopTags addObject:stopTag];
+
+ }
+
+ NSString *platformNumber = [[platformElement attributeForName:@"number"] stringValue];
+ [platformsDict setObject:destinationStopTags forKey:platformNumber];
+ [destinationStopTags release];
+ }
+
+ //CREATE ARRAY OF SORTED PLATFORMS FROM THE NUMBERS AT THIS STOP
+ self.platforms = [NSMutableArray arrayWithArray:[platformsDict allKeys]];
+ NSSortDescriptor *platformSorter = [[NSSortDescriptor alloc] initWithKey:@"" ascending:YES];
+ [platforms sortUsingDescriptors:[NSArray arrayWithObject:platformSorter]];
+ [platformSorter release];
+
+
+ NSLog(@"PLATFORMS: %@", platforms); /* DEBUG LOG */
+
+ NSLog(@"PLATFORM DICTIONARY: %@", platformsDict);
+
+ //CREATE A CONTENTS ARRAY WITH AN ARRAY FOR EACH PLATFORM, WITH DESTINATIONS ORDERED ALPHABETICALLY
+ for (NSString *platformNumber in platforms) {
+
+ NSArray *destinationStopTags = [platformsDict objectForKey:platformNumber];
+
+ NSMutableArray *platformDestinations = [[NSMutableArray alloc] init];
+ for (NSString *destinationStopTag in destinationStopTags) {
+
+ Agency *agency = [DataHelper agencyFromStop:stop];
+ Stop *destinationStop = [DataHelper stopWithTag:destinationStopTag inAgency:agency];
+
+ Destination *dest = [[Destination alloc] initWithDestinationStop:destinationStop forStop:stop];
+ [platformDestinations addObject:dest];
+ [dest release];
+
+ }
+
+ //sort the destination objects by the stop title
+ NSSortDescriptor *alphabeticSorter = [[NSSortDescriptor alloc] initWithKey:@"destinationStop.title" ascending:YES];
+ [platformDestinations sortUsingDescriptors:[NSArray arrayWithObject:alphabeticSorter]];
+ [alphabeticSorter release];
+
+ [contents addObject:platformDestinations];
+
+ [platformDestinations release];
+
+
+ }
+ [platformsDict release];
+
+
+}
+
+#pragma mark -
+#pragma mark Navigation Buttons
+
+- (void)goToPreviousStop:(NSNotification *)note {
+
+ [super goToPreviousStop:note];
+
+ cellStatus = kCellStatusSpinner;
+ isFirstPredictionsFetch = YES;
+
+ ButtonBarCell *cell = (ButtonBarCell *)note.object;
+
+ CATransition *pushTransition = [CATransition animation];
+ pushTransition.duration = 0.5;
+ pushTransition.type = kCATransitionPush;
+ pushTransition.subtype = kCATransitionFromLeft;
+ pushTransition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
+ pushTransition.delegate = self;
+
+ self.view.userInteractionEnabled = NO;
+ self.navigationController.navigationBar.userInteractionEnabled = NO;
+
+ [tableView.layer addAnimation:pushTransition forKey:nil];
+ [stopTitleLabel.layer addAnimation:pushTransition forKey:nil];
+
+ self.stop = cell.previousStop;
+
+ [self setupInitialContents];
+
+ [tableView reloadData];
+ [timer fire];
+
+}
+
+
+- (void)goToNextStop:(NSNotification *)note {
+
+ [super goToNextStop:note];
+
+ isFirstPredictionsFetch = YES;
+ cellStatus = kCellStatusSpinner;
+
+ ButtonBarCell *cell = (ButtonBarCell *)note.object;
+
+ CATransition *pushTransition = [CATransition animation];
+ pushTransition.duration = 0.5;
+ pushTransition.type = kCATransitionPush;
+ pushTransition.subtype = kCATransitionFromRight;
+ pushTransition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
+ pushTransition.delegate = self;
+
+ self.view.userInteractionEnabled = NO;
+ self.navigationController.navigationBar.userInteractionEnabled = NO;
+
+ [tableView.layer addAnimation:pushTransition forKey:nil];
+
+ CATransition *stopNameFadeTransition = [CATransition animation];
+ stopNameFadeTransition.duration = 0.5;
+ stopNameFadeTransition.type = kCATransitionFade;
+ stopNameFadeTransition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
+
+ [stopTitleLabel.layer addAnimation:pushTransition forKey:nil];
+
+ self.stop = cell.nextStop;
+
+ [self setupInitialContents];
+
+ [tableView reloadData];
+ [timer fire];
+
+}
+
+- (void)loadLiveRoute:(NSNotification *)note {
+
+ ButtonBarCell *cell = (ButtonBarCell *)note.object;
+ LiveRouteTVC *liveRouteTVC = [[LiveRouteTVC alloc] init];
+ liveRouteTVC.direction = cell.direction;
+ liveRouteTVC.startingStop = stop;
+
+ [self.navigationController pushViewController:liveRouteTVC animated:YES];
+
+ [liveRouteTVC release];
+
+}
+
+
+#pragma mark -
+#pragma mark Predictions
+
+//submits a request to the PredictionsManager for predictions of the displayed routes. results will be sent to didReceivePredictions
+- (void)requestPredictions {
+
+ kronosAppDelegate *appDelegate = (kronosAppDelegate *)[[UIApplication sharedApplication] delegate];
+ PredictionsManager *predictionsManager = appDelegate.predictionsManager;
+
+ NSMutableArray *requests = [NSMutableArray array];
+
+ //for bart, a single request contains just the stopTag and agencyShortTitle
+ PredictionRequest *request = [[PredictionRequest alloc] init];
+
+ request.agencyShortTitle = @"bart";
+ request.stopTag = self.stop.tag;
+ request.isMainRoute = NO;
+
+ [requests addObject:request];
+ [request release];
+
+ //request predictions for the stops in the favorites screen
+ [NSThread detachNewThreadSelector:@selector(requestPredictionsForRequests:) toTarget:predictionsManager withObject:requests];
+
+ //[predictionsManager requestPredictionsForRequests:requests];
+ NSLog(@"BartStopDetails: predictions requested"); /* DEBUG LOG */
+
+}
+
+//method called when PredictionsManager returns predictions. set the predictions variable in the favoritestops delegate and reload the tableview
+- (void)didReceivePredictions:(NSDictionary *)_predictions {
+
+ //show error message if there is one
+ if ([_predictions objectForKey:@"error"] != nil) {
+
+ cellStatus = kCellStatusInternetFail;
+
+ NSError *error = [_predictions objectForKey:@"error"];
+
+
+ NSLog(@"%d", [errors containsObject:error.userInfo]); /* DEBUG LOG */
+
+ //only show the error if it hasn't been shown before
+ if (![errors containsObject:error.userInfo]){
+
+ NSLog(@"BartStopDetails: %@", @"ERROR"); /* DEBUG LOG */
+ UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Error" message:[error.userInfo objectForKey:@"message"] delegate:self cancelButtonTitle:@"Dismiss" otherButtonTitles:nil];
+ [alertView show];
+ [alertView release];
+
+
+ }
+
+ //store the error in the errors array
+ [errors addObject:error.userInfo];
+ [tableView reloadData];
+ return;
+
+ }
+ else {
+
+ cellStatus = kCellStatusDefault;
+
+ //FILTER PREDICTIONS FOR THIS STOP
+ Prediction *newPrediction = [_predictions objectForKey:stop.tag];
+
+ //view controllers need to be ready to receive predictions for any stop/agency. if there are non for this stop, do not proceed
+ if (newPrediction == nil) {
+
+ NSLog(@"BartStopDetails: IGNORED NON-THIS-STOP PREDICTIONS"); /* DEBUG LOG */
+ return;
+ }
+
+ [predictions setObject:newPrediction forKey:stop.tag];
+
+ //we've recieved predictions (grouped by route) for all the routes that serve this stop. we now have to rejigger the
+ //table contents to reflect this new data b/c we can't know which directions for which routes will have predictions
+
+ //but only the first time
+ if (isFirstPredictionsFetch) {
+
+ [self setupContentsBasedOnPredictions];
+ isFirstPredictionsFetch = NO;
+
+ }
+ //every subsquent time, just add the predictions to the predictions dictionary and reload the table
+ //unless it's bart, in which case, just do what you'd otherwise do, recreate the contents array from the predictions
+ else {
+
+ [self.tableView reloadData];
+
+ }
+ }
+
+}
+
+- (void)setupContentsBasedOnPredictions {
+
+ //LIKE WITH NEXTBUS STOPS, WE WANT TO FIND OUT IF THERE ARE ANY DESTINATIONS IN THE PREDICTIONS THAT AREN'T ALREADY IN THE CONTENTS
+ //IF THERE ARE ANY LEFTOVER PREDICTIONS, SAVE THEM TO A DICTIONARY
+ NSMutableDictionary *leftoverDestinationArrivals = [[NSMutableDictionary alloc] init];
+
+ Prediction *prediction = [predictions objectForKey:stop.tag];
+ NSDictionary *arrivals = prediction.arrivals;
+
+ NSArray *destinationTags = [prediction.arrivals allKeys];
+
+ for (NSString *destinationTag in destinationTags) {
+
+ [leftoverDestinationArrivals setObject:[arrivals objectForKey:destinationTag] forKey:destinationTag];
+
+ //go through each section in the contents looking for this destination tag
+ for (NSMutableArray *tableSection in contents) {
+
+ for (Destination *destination in tableSection) {
+
+ if ([destination.destinationStop.tag isEqualToString:destinationTag]) {
+
+ [leftoverDestinationArrivals removeObjectForKey:destinationTag];
+
+ }
+
+
+ }
+
+
+ }
+
+ }
+
+
+ NSLog(@"Leftover Destination Arrivals: %@", leftoverDestinationArrivals); /* DEBUG LOG */
+
+ //THE DESTINATIONS IN THE LEFTOVER PREDICTIONS DICTIONARY ARE NON-STANDARD DESTINATIONS (E.G. 24TH ST, CONCORD, ETC.)
+ //WE ONLY WANT TO ADD THEM IF THE FIRST ARRIVAL IS < 20 MINUTES AWAY.
+ //SO, DON'T ADD ANY PREDICTIONS FROM THE DICTIONARY THAT DON'T MEET THIS CRITERION
+
+ //create a direction object for each arrivals key
+ for (NSString *arrivalsKey in [leftoverDestinationArrivals allKeys]) {
+
+ NSArray *arrivals = [leftoverDestinationArrivals objectForKey:arrivalsKey];
+
+ NSDictionary *firstArrivalDict = [arrivals objectAtIndex:0];
+
+
+ int firstArrival = [[firstArrivalDict objectForKey:@"minutes"] intValue];
+
+ //don't add this destination if it's first predictions is more then 20 minutes away
+ if (firstArrival > 20) {
+
+ NSLog(@"Destination not added b/c to far away: %@", arrivalsKey); /* DEBUG LOG */
+ continue;
+ }
+
+ NSString *platformNumber = [firstArrivalDict objectForKey:@"platform"];
+
+ int sectionIndex = [platforms indexOfObject:platformNumber];
+
+
+ //CREATE THE PREDICTION OBJECT TO ADD TO THE CONTENTS
+
+ Stop *destinationStop = [DataHelper stopWithTag:arrivalsKey inAgencyWithShortTitle:@"bart"];
+ Destination *destinationToAdd = [[Destination alloc] initWithDestinationStop:destinationStop forStop:stop];
+
+ [[contents objectAtIndex:sectionIndex] addObject:destinationToAdd];
+ [destinationToAdd release];
+
+ NSSortDescriptor *destinationTitleSorter = [[NSSortDescriptor alloc] initWithKey:@"destinationStop.title" ascending:YES];
+
+ [[contents objectAtIndex:sectionIndex] sortUsingDescriptors:[NSMutableArray arrayWithObject:destinationTitleSorter]];
+
+ [destinationTitleSorter release];
+
+ }
+
+ [leftoverDestinationArrivals release];
+
+ //NSLog(@"PREDICTIONS: %@", predictions); /* DEBUG LOG */
+
+ [tableView reloadData];
+
+}
+
+
+
+#pragma mark -
+#pragma mark Table
+
+- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
+
+ RowDivider *header = [[[RowDivider alloc] initWithFrame:CGRectMake(0, 0, 320, kRowDividerHeight)] autorelease];
+
+ NSString *platformNumber = [platforms objectAtIndex:section];
+ header.title = [NSString stringWithFormat:@"Platform %@",platformNumber];
+ return header;
+
+}
+
+- (UITableViewCell *)tableView:(UITableView *)_tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
+
+ int row = indexPath.row;
+ int section = indexPath.section;
+
+ //contents object
+ id object = [[contents objectAtIndex:section] objectAtIndex:row];
+
+ //BUTTON ROW
+ if([object isMemberOfClass:[NSNull class]]){
+
+ static NSString *ButtonBarCellIdentifier = @"ButtonBarCellIdentifier";
+
+ ButtonBarCell *cell = (ButtonBarCell *)[tableView dequeueReusableCellWithIdentifier:ButtonBarCellIdentifier];
+ if (cell == nil) {
+ NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"ButtonBarCell" owner:self options:nil];
+
+ for (id object in nib) {
+ if ([object isKindOfClass:[ButtonBarCell class]]) {
+ cell = (ButtonBarCell *)object;
+ cell.selectionStyle = UITableViewCellSelectionStyleNone;
+ }
+ }
+ }
+
+ cell.stop = stop;
+
+ Destination *destination = (Destination *)[[contents objectAtIndex:indexPath.section] objectAtIndex:indexPath.row-1];
+ cell.direction = destination.direction;
+
+ [cell configureButtons];
+
+ return cell;
+ }
+
+ //DESTINATION ROW
+ else if ([object isMemberOfClass:[Destination class]]) {
+
+ static NSString *LineCellIdentifier = @"LineCellIdentifier";
+ LineCell *cell = (LineCell *)[tableView dequeueReusableCellWithIdentifier:LineCellIdentifier];
+
+ if (cell == nil) {
+
+ cell = [[[LineCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:LineCellIdentifier] autorelease];
+ cell.lineCellView = [[[DestinationCellView alloc] init] autorelease];
+ [cell.contentView addSubview:cell.lineCellView];
+ [cell.lineCellView release];
+ }
+
+ Destination *destination = (Destination *)object;
+
+ DestinationCellView *destinationCellView = (DestinationCellView *)cell.lineCellView;
+
+ //style the favorite button
+ destinationCellView.stop = stop;
+ [destinationCellView setDestination:destination];
+
+ [destinationCellView setFavoriteStatus]; //sets the star image depending on whether that direction/stop combo is a favorite
+
+ destinationCellView.majorTitle = destination.destinationStop.title;
+
+ //all cell statuses are the same for every cell on the screen, except the PredictionFail status
+ if ([[predictions objectForKey:stop.tag] isError]) {
+ [destinationCellView setCellStatus:kCellStatusPredictionFail withArrivals:nil];
+ }
+ else {
+
+ //temporary: find the arrivals for the given direction cell, if it exists
+ NSArray *arrivals = [[[predictions objectForKey:stop.tag] arrivals] objectForKey:destination.destinationStop.tag];
+
+ [destinationCellView setCellStatus:cellStatus withArrivals:arrivals];
+ }
+
+ return cell;
+
+
+ }
+
+
+
+ return nil;
+}
+
+#pragma mark -
+#pragma mark Memory
+
+- (void)dealloc {
+
+
+ [platforms release];
+ [super dealloc];
+}
+
+
+@end
44 Classes/ButtonBarCell.h
@@ -0,0 +1,44 @@
+//
+// ButtonBarCell.h
+//
+// Created by Ljuba Miljkovic on 3/16/10.
+// Copyright 2010 __MyCompanyName__. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+#import <Foundation/Foundation.h>
+#import "Direction.h"
+#import "Stop.h"
+#import "DataHelper.h"
+
+@interface ButtonBarCell : UITableViewCell {
+
+ UIButton *previousStopButton;
+ UIButton *nextStopButton;
+ UIButton *liveRouteButton;
+
+ Direction *direction;
+ Stop *stop;
+ Stop *nextStop;
+ Stop *previousStop;
+
+}
+
+@property (nonatomic, retain) IBOutlet UIButton *previousStopButton;
+@property (nonatomic, retain) IBOutlet UIButton *nextStopButton;
+@property (nonatomic, retain) IBOutlet UIButton *liveRouteButton;
+
+@property (nonatomic, retain) Direction *direction;
+@property (nonatomic, retain) Stop *stop;
+@property (nonatomic, retain) Stop *nextStop;
+@property (nonatomic, retain) Stop *previousStop;
+
+- (IBAction)goToPreviousStop:(id)sender;
+- (IBAction)goToNextStop:(id)sender;
+- (IBAction)loadLiveRoute:(id)sender;
+- (void)configureButtons;
+
+- (BOOL)thereIsPreviousStop;
+- (BOOL)thereIsNextStop;
+
+@end
95 Classes/ButtonBarCell.m
@@ -0,0 +1,95 @@
+//
+// ButtonBarCell.m
+//
+// Created by Ljuba Miljkovic on 3/16/10.
+// Copyright 2010 __MyCompanyName__. All rights reserved.
+//
+
+#import "ButtonBarCell.h"
+
+@implementation ButtonBarCell
+
+@synthesize nextStopButton, previousStopButton, liveRouteButton, direction, stop, nextStop, previousStop;
+
+- (IBAction)goToPreviousStop:(id)sender {
+ NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
+ [notificationCenter postNotificationName:@"goToPreviousStop" object:self];
+}
+
+- (IBAction)goToNextStop:(id)sender {
+ NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
+ [notificationCenter postNotificationName:@"goToNextStop" object:self];
+}
+
+- (IBAction)loadLiveRoute:(id)sender {
+ NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
+ [notificationCenter postNotificationName:@"loadLiveRoute" object:self];
+}
+
+//configure whether next/prev/switch buttons are active or not
+- (void)configureButtons {
+
+ nextStopButton.enabled = [self thereIsNextStop];
+ previousStopButton.enabled = [self thereIsPreviousStop];
+
+}
+
+
+- (BOOL)thereIsNextStop {
+
+ NSArray *stopOrder = direction.stopOrder;
+ NSString *stopTag = [NSString stringWithFormat:@"%@",stop.tag];
+
+ //if this is the last stop in the direction, the button should be disabled
+ if ([[stopOrder lastObject] isEqual:stopTag]) {
+ return NO;
+ }
+ else {
+
+ int indexOfNextStop = [stopOrder indexOfObject:stopTag]+1;
+
+ NSString *nextStopTag = [NSString stringWithFormat:@"%@",[stopOrder objectAtIndex:indexOfNextStop]];
+ NSLog(@"Current Stop: %@", stopTag); /* DEBUG LOG */
+ NSLog(@"Next Stop: %@", nextStopTag); /* DEBUG LOG */
+
+ NSMutableSet *stops = [NSMutableSet setWithSet:direction.stops];
+
+ //filter all but the next stop
+ NSPredicate *filterPredicate = [NSPredicate predicateWithFormat:@"tag == %@", nextStopTag];
+ [stops filterUsingPredicate:filterPredicate];
+
+ nextStop = [stops anyObject];
+
+ return YES;
+ }
+
+}
+
+- (BOOL)thereIsPreviousStop {
+
+ NSArray *stopOrder = direction.stopOrder;
+ NSString *stopTag = [NSString stringWithFormat:@"%@",stop.tag];
+
+ //if this is the first stop in the direction, the button should be disabled
+ if ([[stopOrder objectAtIndex:0] isEqual:stopTag]) {
+ return NO;
+ }
+ else {
+
+ NSString *previousStopTag = [NSString stringWithFormat:@"%@",[stopOrder objectAtIndex:[stopOrder indexOfObject:stopTag]-1]];
+ NSLog(@"Current Stop: %@", stopTag); /* DEBUG LOG */
+ NSLog(@"Previous Stop: %@", previousStopTag); /* DEBUG LOG */
+
+ NSMutableSet *stops = [NSMutableSet setWithSet:direction.stops];
+
+ //filter all but the next stop
+ NSPredicate *filterPredicate = [NSPredicate predicateWithFormat:@"tag == %@", previousStopTag];
+ [stops filterUsingPredicate:filterPredicate];
+
+ previousStop = [stops anyObject];
+
+ return YES;
+ }
+}
+
+@end
609 Classes/ButtonBarCell.xib
@@ -0,0 +1,609 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<archive type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="7.10">
+ <data>
+ <int key="IBDocument.SystemTarget">1024</int>
+ <string key="IBDocument.SystemVersion">10F569</string>
+ <string key="IBDocument.InterfaceBuilderVersion">804</string>
+ <string key="IBDocument.AppKitVersion">1038.29</string>
+ <string key="IBDocument.HIToolboxVersion">461.00</string>
+ <object class="NSMutableDictionary" key="IBDocument.PluginVersions">
+ <string key="NS.key.0">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
+ <string key="NS.object.0">123</string>
+ </object>
+ <object class="NSMutableArray" key="IBDocument.EditedObjectIDs">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <integer value="2"/>
+ </object>
+ <object class="NSArray" key="IBDocument.PluginDependencies">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
+ </object>
+ <object class="NSMutableDictionary" key="IBDocument.Metadata">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys" id="0">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ </object>
+ <object class="NSMutableArray" key="IBDocument.RootObjects" id="1000">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBProxyObject" id="841351856">
+ <string key="IBProxiedObjectIdentifier">IBFilesOwner</string>
+ <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
+ </object>
+ <object class="IBProxyObject" id="371349661">
+ <string key="IBProxiedObjectIdentifier">IBFirstResponder</string>
+ <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
+ </object>
+ <object class="IBUITableViewCell" id="150616063">
+ <reference key="NSNextResponder"/>
+ <int key="NSvFlags">292</int>
+ <object class="NSMutableArray" key="NSSubviews">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBUIView" id="597690695">
+ <reference key="NSNextResponder" ref="150616063"/>
+ <int key="NSvFlags">256</int>
+ <object class="NSMutableArray" key="NSSubviews">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBUIButton" id="663075898">
+ <reference key="NSNextResponder" ref="597690695"/>
+ <int key="NSvFlags">292</int>
+ <string key="NSFrameSize">{97, 46}</string>
+ <reference key="NSSuperview" ref="597690695"/>
+ <bool key="IBUIClearsContextBeforeDrawing">NO</bool>
+ <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
+ <int key="IBUIContentHorizontalAlignment">0</int>
+ <int key="IBUIContentVerticalAlignment">0</int>
+ <object class="NSFont" key="IBUIFont" id="534283843">
+ <string key="NSName">Helvetica-Bold</string>
+ <double key="NSSize">15</double>
+ <int key="NSfFlags">16</int>
+ </object>
+ <string key="IBUINormalTitle">prev</string>
+ <object class="NSColor" key="IBUIHighlightedTitleColor" id="497598625">
+ <int key="NSColorSpace">3</int>
+ <bytes key="NSWhite">MQA</bytes>
+ </object>
+ <object class="NSColor" key="IBUINormalTitleColor">
+ <int key="NSColorSpace">1</int>
+ <bytes key="NSRGB">MC4xOTYwNzg0MyAwLjMwOTgwMzkzIDAuNTIxNTY4NjYAA</bytes>
+ </object>
+ <object class="NSColor" key="IBUINormalTitleShadowColor" id="787491772">
+ <int key="NSColorSpace">3</int>
+ <bytes key="NSWhite">MC41AA</bytes>
+ </object>
+ <object class="NSCustomResource" key="IBUIHighlightedImage" id="484791290">
+ <string key="NSClassName">NSImage</string>
+ <string key="NSResourceName">prev-stop-button-highlighted.png</string>
+ </object>
+ <object class="NSCustomResource" key="IBUIDisabledImage">
+ <string key="NSClassName">NSImage</string>
+ <string key="NSResourceName">prev-stop-button-disabled.png</string>
+ </object>
+ <reference key="IBUISelectedImage" ref="484791290"/>
+ <object class="NSCustomResource" key="IBUINormalImage">
+ <string key="NSClassName">NSImage</string>
+ <string key="NSResourceName">prev-stop-button-enabled.png</string>
+ </object>
+ </object>
+ <object class="IBUIButton" id="916321245">
+ <reference key="NSNextResponder" ref="597690695"/>
+ <int key="NSvFlags">292</int>
+ <string key="NSFrame">{{97, 0}, {126, 46}}</string>
+ <reference key="NSSuperview" ref="597690695"/>
+ <bool key="IBUIClearsContextBeforeDrawing">NO</bool>
+ <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
+ <int key="IBUIContentHorizontalAlignment">0</int>
+ <int key="IBUIContentVerticalAlignment">0</int>
+ <reference key="IBUIFont" ref="534283843"/>
+ <string key="IBUINormalTitle">live</string>
+ <reference key="IBUIHighlightedTitleColor" ref="497598625"/>
+ <object class="NSColor" key="IBUINormalTitleColor">
+ <int key="NSColorSpace">1</int>
+ <bytes key="NSRGB">MC4xOTYwNzg0MyAwLjMwOTgwMzkzIDAuNTIxNTY4NjYAA</bytes>
+ </object>
+ <reference key="IBUINormalTitleShadowColor" ref="787491772"/>
+ <object class="NSCustomResource" key="IBUIHighlightedImage" id="925179976">
+ <string key="NSClassName">NSImage</string>
+ <string key="NSResourceName">live-route-button-highlighted.png</string>
+ </object>
+ <object class="NSCustomResource" key="IBUIDisabledImage">
+ <string key="NSClassName">NSImage</string>
+ <string key="NSResourceName">live-route-button-disabled.png</string>
+ </object>
+ <reference key="IBUISelectedImage" ref="925179976"/>
+ <object class="NSCustomResource" key="IBUINormalImage">
+ <string key="NSClassName">NSImage</string>
+ <string key="NSResourceName">live-route-button-enabled.png</string>
+ </object>
+ </object>
+ <object class="IBUIButton" id="77086337">
+ <reference key="NSNextResponder" ref="597690695"/>
+ <int key="NSvFlags">292</int>
+ <string key="NSFrame">{{223, 0}, {97, 46}}</string>
+ <reference key="NSSuperview" ref="597690695"/>
+ <bool key="IBUIClearsContextBeforeDrawing">NO</bool>
+ <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
+ <int key="IBUIContentHorizontalAlignment">0</int>
+ <int key="IBUIContentVerticalAlignment">0</int>
+ <reference key="IBUIFont" ref="534283843"/>
+ <string key="IBUINormalTitle">next</string>
+ <reference key="IBUIHighlightedTitleColor" ref="497598625"/>
+ <object class="NSColor" key="IBUINormalTitleColor">
+ <int key="NSColorSpace">1</int>
+ <bytes key="NSRGB">MC4xOTYwNzg0MyAwLjMwOTgwMzkzIDAuNTIxNTY4NjYAA</bytes>
+ </object>
+ <reference key="IBUINormalTitleShadowColor" ref="787491772"/>
+ <object class="NSCustomResource" key="IBUIHighlightedImage" id="889682838">
+ <string key="NSClassName">NSImage</string>
+ <string key="NSResourceName">next-stop-button-highlighted.png</string>
+ </object>
+ <object class="NSCustomResource" key="IBUIDisabledImage">
+ <string key="NSClassName">NSImage</string>
+ <string key="NSResourceName">next-stop-button-disabled.png</string>
+ </object>
+ <reference key="IBUISelectedImage" ref="889682838"/>
+ <object class="NSCustomResource" key="IBUINormalImage">
+ <string key="NSClassName">NSImage</string>
+ <string key="NSResourceName">next-stop-button-enabled.png</string>
+ </object>
+ </object>
+ </object>
+ <string key="NSFrameSize">{320, 46}</string>
+ <reference key="NSSuperview" ref="150616063"/>
+ <object class="NSColor" key="IBUIBackgroundColor">
+ <int key="NSColorSpace">3</int>
+ <bytes key="NSWhite">MCAwAA</bytes>
+ </object>
+ <bool key="IBUIOpaque">NO</bool>
+ <bool key="IBUIClipsSubviews">YES</bool>
+ <int key="IBUIContentMode">4</int>
+ <bool key="IBUIMultipleTouchEnabled">YES</bool>
+ <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
+ </object>
+ </object>
+ <string key="NSFrameSize">{320, 46}</string>
+ <reference key="NSSuperview"/>
+ <object class="NSColor" key="IBUIBackgroundColor">
+ <int key="NSColorSpace">1</int>
+ <bytes key="NSRGB">MSAxIDEAA</bytes>
+ </object>
+ <bool key="IBUIClearsContextBeforeDrawing">NO</bool>
+ <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
+ <int key="IBUISeparatorStyle">1</int>
+ <reference key="IBUIContentView" ref="597690695"/>
+ <int key="IBUITextAlignment">1</int>
+ </object>
+ </object>
+ <object class="IBObjectContainer" key="IBDocument.Objects">
+ <object class="NSMutableArray" key="connectionRecords">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBConnectionRecord">
+ <object class="IBCocoaTouchOutletConnection" key="connection">
+ <string key="label">previousStopButton</string>
+ <reference key="source" ref="150616063"/>
+ <reference key="destination" ref="663075898"/>
+ </object>
+ <int key="connectionID">12</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBCocoaTouchOutletConnection" key="connection">
+ <string key="label">liveRouteButton</string>
+ <reference key="source" ref="150616063"/>
+ <reference key="destination" ref="916321245"/>
+ </object>
+ <int key="connectionID">14</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBCocoaTouchOutletConnection" key="connection">
+ <string key="label">nextStopButton</string>
+ <reference key="source" ref="150616063"/>
+ <reference key="destination" ref="77086337"/>
+ </object>
+ <int key="connectionID">15</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBCocoaTouchEventConnection" key="connection">
+ <string key="label">goToPreviousStop:</string>
+ <reference key="source" ref="663075898"/>
+ <reference key="destination" ref="150616063"/>
+ <int key="IBEventType">7</int>
+ </object>
+ <int key="connectionID">16</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBCocoaTouchEventConnection" key="connection">
+ <string key="label">loadLiveRoute:</string>
+ <reference key="source" ref="916321245"/>
+ <reference key="destination" ref="150616063"/>
+ <int key="IBEventType">7</int>
+ </object>
+ <int key="connectionID">18</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBCocoaTouchEventConnection" key="connection">
+ <string key="label">goToNextStop:</string>
+ <reference key="source" ref="77086337"/>
+ <reference key="destination" ref="150616063"/>
+ <int key="IBEventType">7</int>
+ </object>
+ <int key="connectionID">19</int>
+ </object>
+ </object>
+ <object class="IBMutableOrderedSet" key="objectRecords">
+ <object class="NSArray" key="orderedObjects">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBObjectRecord">
+ <int key="objectID">0</int>
+ <reference key="object" ref="0"/>
+ <reference key="children" ref="1000"/>
+ <nil key="parent"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">-1</int>
+ <reference key="object" ref="841351856"/>
+ <reference key="parent" ref="0"/>
+ <string key="objectName">File's Owner</string>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">-2</int>
+ <reference key="object" ref="371349661"/>
+ <reference key="parent" ref="0"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">2</int>
+ <reference key="object" ref="150616063"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="77086337"/>
+ <reference ref="916321245"/>
+ <reference ref="663075898"/>
+ </object>
+ <reference key="parent" ref="0"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">8</int>
+ <reference key="object" ref="663075898"/>
+ <reference key="parent" ref="150616063"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">10</int>
+ <reference key="object" ref="916321245"/>
+ <reference key="parent" ref="150616063"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">11</int>
+ <reference key="object" ref="77086337"/>
+ <reference key="parent" ref="150616063"/>
+ </object>
+ </object>
+ </object>
+ <object class="NSMutableDictionary" key="flattenedProperties">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>-2.CustomClassName</string>
+ <string>10.IBPluginDependency</string>
+ <string>11.IBPluginDependency</string>
+ <string>2.CustomClassName</string>
+ <string>2.IBEditorWindowLastContentRect</string>
+ <string>2.IBPluginDependency</string>
+ <string>8.IBPluginDependency</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>UIResponder</string>
+ <string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
+ <string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
+ <string>ButtonBarCell</string>
+ <string>{{697, 715}, {320, 46}}</string>
+ <string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
+ <string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
+ </object>
+ </object>
+ <object class="NSMutableDictionary" key="unlocalizedProperties">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference key="dict.sortedKeys" ref="0"/>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ </object>
+ <nil key="activeLocalization"/>
+ <object class="NSMutableDictionary" key="localizations">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference key="dict.sortedKeys" ref="0"/>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ </object>
+ <nil key="sourceID"/>
+ <int key="maxID">22</int>
+ </object>
+ <object class="IBClassDescriber" key="IBDocument.Classes">
+ <object class="NSMutableArray" key="referencedPartialClassDescriptions">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBPartialClassDescription">
+ <string key="className">ButtonBarCell</string>
+ <string key="superclassName">UITableViewCell</string>
+ <object class="NSMutableDictionary" key="actions">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>goToNextStop:</string>
+ <string>goToPreviousStop:</string>
+ <string>loadLiveRoute:</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>id</string>
+ <string>id</string>
+ <string>id</string>
+ </object>
+ </object>
+ <object class="NSMutableDictionary" key="actionInfosByName">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>goToNextStop:</string>
+ <string>goToPreviousStop:</string>
+ <string>loadLiveRoute:</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBActionInfo">
+ <string key="name">goToNextStop:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo">
+ <string key="name">goToPreviousStop:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo">
+ <string key="name">loadLiveRoute:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ </object>
+ </object>
+ <object class="NSMutableDictionary" key="outlets">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>liveRouteButton</string>
+ <string>nextStopButton</string>
+ <string>previousStopButton</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>UIButton</string>
+ <string>UIButton</string>
+ <string>UIButton</string>
+ </object>
+ </object>
+ <object class="NSMutableDictionary" key="toOneOutletInfosByName">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>liveRouteButton</string>
+ <string>nextStopButton</string>
+ <string>previousStopButton</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBToOneOutletInfo">
+ <string key="name">liveRouteButton</string>
+ <string key="candidateClassName">UIButton</string>
+ </object>
+ <object class="IBToOneOutletInfo">
+ <string key="name">nextStopButton</string>
+ <string key="candidateClassName">UIButton</string>
+ </object>
+ <object class="IBToOneOutletInfo">
+ <string key="name">previousStopButton</string>
+ <string key="candidateClassName">UIButton</string>
+ </object>
+ </object>
+ </object>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">Classes/ButtonBarCell.h</string>
+ </object>
+ </object>
+ </object>
+ <object class="NSMutableArray" key="referencedPartialClassDescriptionsV3.2+">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSError.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSFileManager.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSKeyValueCoding.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSKeyValueObserving.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSKeyedArchiver.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSObject.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSRunLoop.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSThread.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSURL.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSURLConnection.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">QuartzCore.framework/Headers/CAAnimation.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">QuartzCore.framework/Headers/CALayer.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">UIKit.framework/Headers/UIAccessibility.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">UIKit.framework/Headers/UINibLoading.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier" id="605512061">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">UIKit.framework/Headers/UIResponder.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">UIButton</string>
+ <string key="superclassName">UIControl</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">UIKit.framework/Headers/UIButton.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">UIControl</string>
+ <string key="superclassName">UIView</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">UIKit.framework/Headers/UIControl.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">UIResponder</string>
+ <string key="superclassName">NSObject</string>
+ <reference key="sourceIdentifier" ref="605512061"/>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">UITableViewCell</string>
+ <string key="superclassName">UIView</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">UIKit.framework/Headers/UITableViewCell.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">UIView</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">UIKit.framework/Headers/UITextField.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">UIView</string>
+ <string key="superclassName">UIResponder</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">UIKit.framework/Headers/UIView.h</string>
+ </object>
+ </object>
+ </object>
+ </object>
+ <int key="IBDocument.localizationMode">0</int>
+ <string key="IBDocument.TargetRuntimeIdentifier">IBCocoaTouchFramework</string>
+ <object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDependencyDefaults">
+ <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS</string>
+ <integer value="1024" key="NS.object.0"/>
+ </object>