Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Updating to 2.2.7

  • Loading branch information...
commit 9d709421bb9df14f0082c4125b7e5542265c138f 1 parent 97707b4
@justinanderson justinanderson authored
Showing with 8,612 additions and 5,026 deletions.
  1. +2 −2 README.markdown
  2. +0 −38 mobi-config/mobi_lib_config.php
  3. +95 −88 mobi-config/mobi_lib_constants.php
  4. +95 −72 mobi-config/mobi_lib_constants.php.init
  5. +4 −5 mobi-config/mobi_web_constants.php
  6. +4 −5 mobi-config/mobi_web_constants.php.init
  7. +126 −68 mobi-lib/AcademicCalendar.php
  8. +177 −0 mobi-lib/DiskCache.php
  9. +912 −0 mobi-lib/GTFSReader.php
  10. +13 −2 mobi-lib/LibraryInfo.php
  11. +333 −0 mobi-lib/NewsOffice.php
  12. +450 −420 mobi-lib/NextBusReader.php
  13. +626 −0 mobi-lib/ShuttleObjects.php
  14. +57 −26 mobi-lib/ShuttleSchedule.php
  15. +41 −54 mobi-lib/StellarData.php
  16. +0 −1  mobi-lib/cache/NEXTBUS_ROUTE_saferidebostonall
  17. +0 −1  mobi-lib/cache/NEXTBUS_ROUTE_saferidecamball
  18. +209 −0 mobi-lib/campus_map.php
  19. +0 −38 mobi-lib/crons/mail_errors.php
  20. +234 −33 mobi-lib/mit_calendar.php
  21. +20 −1 mobi-lib/mit_ical_lib.php
  22. +0 −86 mobi-lib/setup.sh
  23. +8 −8 mobi-lib/shuttle_schedule.json
  24. +87 −12 mobi-lib/testShuttleSchedule.php
  25. +83 −0 mobi-scripts/mobi-daemons.sh
  26. +142 −0 mobi-scripts/mobi-maptiles-download.php
  27. +72 −0 mobi-scripts/mobi-maptiles.sh
  28. +1 −3 mobi-web/Basic/base.html
  29. +0 −368 mobi-web/Basic/core.css
  30. +5 −4 mobi-web/Touch/base.html
  31. +4 −936 mobi-web/Touch/core.css
  32. +0 −904 mobi-web/Touch/core.css.old
  33. BIN  mobi-web/Touch/images/button-zoom-in2.gif
  34. BIN  mobi-web/Touch/images/email-share.gif
  35. BIN  mobi-web/Touch/images/title-news.gif
  36. BIN  mobi-web/Touch/images/title-news2.gif
  37. +10 −5 mobi-web/Webkit/base.html
  38. +5 −5 mobi-web/Webkit/core.css
  39. BIN  mobi-web/Webkit/images/button-zoom-in2.png
  40. BIN  mobi-web/Webkit/images/cancel-float.png
  41. BIN  mobi-web/Webkit/images/email-share.png
  42. BIN  mobi-web/Webkit/images/search-float.png
  43. BIN  mobi-web/Webkit/images/title-news.png
  44. +6 −2 mobi-web/Webkit/uiscripts.js
  45. +345 −0 mobi-web/about/androidapp.css
  46. +89 −0 mobi-web/about/androidapp.html
  47. +9 −10 mobi-web/about/helpsite.css
  48. BIN  mobi-web/about/images/androidapp/back.jpg
  49. BIN  mobi-web/about/images/androidapp/droid.gif
  50. BIN  mobi-web/about/images/androidapp/droid.png
  51. BIN  mobi-web/about/images/androidapp/emergency.jpg
  52. BIN  mobi-web/about/images/androidapp/emergency.png
  53. BIN  mobi-web/about/images/androidapp/events.jpg
  54. BIN  mobi-web/about/images/androidapp/events.png
  55. BIN  mobi-web/about/images/androidapp/home.jpg
  56. BIN  mobi-web/about/images/androidapp/istlogo-footer.gif
  57. BIN  mobi-web/about/images/androidapp/map.jpg
  58. BIN  mobi-web/about/images/androidapp/map.png
  59. BIN  mobi-web/about/images/androidapp/module-back.gif
  60. BIN  mobi-web/about/images/androidapp/news-story.jpg
  61. BIN  mobi-web/about/images/androidapp/news.jpg
  62. BIN  mobi-web/about/images/androidapp/news.png
  63. BIN  mobi-web/about/images/androidapp/people.jpg
  64. BIN  mobi-web/about/images/androidapp/people.png
  65. BIN  mobi-web/about/images/androidapp/qrcode.png
  66. BIN  mobi-web/about/images/androidapp/shuttle.jpg
  67. BIN  mobi-web/about/images/androidapp/shuttle.png
  68. BIN  mobi-web/about/images/androidapp/startup.jpg
  69. BIN  mobi-web/about/images/androidapp/stellar.jpg
  70. BIN  mobi-web/about/images/androidapp/stellar.png
  71. BIN  mobi-web/about/images/androidapp/title-logo.gif
  72. BIN  mobi-web/about/images/androidapp/title.gif
  73. BIN  mobi-web/about/images/iphoneapp/emergency.jpg
  74. BIN  mobi-web/about/images/iphoneapp/emergency.png
  75. BIN  mobi-web/about/images/iphoneapp/events.jpg
  76. BIN  mobi-web/about/images/iphoneapp/events.png
  77. BIN  mobi-web/about/images/iphoneapp/map.jpg
  78. BIN  mobi-web/about/images/iphoneapp/map.png
  79. BIN  mobi-web/about/images/iphoneapp/news.jpg
  80. BIN  mobi-web/about/images/iphoneapp/people.jpg
  81. BIN  mobi-web/about/images/iphoneapp/shuttle-map4.jpg
  82. BIN  mobi-web/about/images/iphoneapp/shuttle-route.jpg
  83. BIN  mobi-web/about/images/iphoneapp/stellar-detail.jpg
  84. BIN  mobi-web/about/images/iphoneapp/stellar.png
  85. +5 −8 mobi-web/about/index.php
  86. +8 −8 mobi-web/about/iphoneapp.html
  87. +21 −0 mobi-web/api/api_header.php
  88. +65 −0 mobi-web/api/apns_push.php
  89. +186 −0 mobi-web/api/calendar.php
  90. +16 −0 mobi-web/api/emergency.php
  91. +11 −245 mobi-web/api/index.php
  92. +155 −32 mobi-web/api/map/index.php
  93. +1 −0  mobi-web/api/map/tile2
  94. +1 −0  mobi-web/api/map/tiles_last_updated.txt
  95. +7 −131 mobi-web/api/newsoffice-dev/index.php
  96. +5 −130 mobi-web/api/newsoffice/index.php
  97. +15 −0 mobi-web/api/people.php
  98. +2 −1  mobi-web/api/push/apns_feedback_daemon.php
  99. +15 −11 mobi-web/api/push/apns_lib.php
  100. +2 −0  mobi-web/api/push/emergency_daemon.php
  101. +19 −32 mobi-web/api/push/shuttle_daemon.php
  102. +54 −69 mobi-web/api/shuttles/index.php
  103. +102 −0 mobi-web/api/stellar.php
  104. +2 −2 mobi-web/calendar/Basic/detail.html
  105. +1 −1  mobi-web/calendar/Basic/holidays.html
  106. +1 −1  mobi-web/calendar/Basic/index.html
  107. +2 −2 mobi-web/calendar/Touch/detail.html
  108. +1 −1  mobi-web/calendar/Touch/holidays.html
  109. +1 −1  mobi-web/calendar/Touch/index.html
  110. +2 −2 mobi-web/calendar/Webkit/detail.html
  111. +1 −1  mobi-web/calendar/Webkit/holidays.html
  112. +1 −1  mobi-web/calendar/Webkit/index.html
  113. +1 −1  mobi-web/calendar/academic.php
  114. +11 −3 mobi-web/calendar/category.php
  115. +1 −29 mobi-web/calendar/detail.php
  116. +1 −1  mobi-web/calendar/help.php
  117. +10 −20 mobi-web/calendar/holidays.php
  118. +7 −1 mobi-web/calendar/search.php
  119. +0 −17 mobi-web/careers/Basic/index.html
  120. +0 −20 mobi-web/careers/Touch/index.html
  121. +0 −20 mobi-web/careers/Webkit/index.html
  122. +0 −14 mobi-web/careers/help.php
  123. BIN  mobi-web/customize/Webkit/images/news-tiny.png
  124. +3 −0  mobi-web/e/.htaccess
  125. +11 −0 mobi-web/e/index.php
  126. +1 −0  mobi-web/error-page/index.php
  127. +0 −2  mobi-web/home/Basic/index.html
  128. +15 −157 mobi-web/home/Modules.php
  129. BIN  mobi-web/home/Touch/images/news.gif
  130. BIN  mobi-web/home/Webkit/images/news.png
  131. +1 −1  mobi-web/home/index.php
  132. +1 −2  mobi-web/libraries/libraries_lib.php
  133. +1 −0  mobi-web/libraries/location-detail.php
  134. +0 −2  mobi-web/libraries/locations.php
  135. +1 −1  mobi-web/map/Basic/buildings.html
  136. +1 −1  mobi-web/map/Basic/drilldown.html
  137. +1 −1  mobi-web/map/Basic/index.html
  138. +1 −1  mobi-web/map/Touch/buildings.html
  139. +1 −1  mobi-web/map/Touch/drilldown.html
  140. +1 −1  mobi-web/map/Touch/index.html
  141. +3 −3 mobi-web/map/Webkit/buildings.html
  142. +9 −6 mobi-web/map/Webkit/detail-fullscreen.html
  143. +4 −4 mobi-web/map/Webkit/direction.html
  144. +3 −3 mobi-web/map/Webkit/drilldown.html
  145. +1 −1  mobi-web/map/Webkit/index.html
  146. +54 −28 mobi-web/map/Webkit/map.css
  147. +15 −11 mobi-web/map/Webkit/map.js
  148. +2 −2 mobi-web/map/Webkit/names.html
  149. +2 −2 mobi-web/map/Webkit/places.html
  150. +0 −60 mobi-web/map/buildings.php
  151. +0 −148 mobi-web/map/buildings_lib.php
  152. +2 −7 mobi-web/map/detail-fullscreen.php
  153. +115 −137 mobi-web/map/detail.php
  154. +3 −3 mobi-web/map/directions.php
  155. +46 −52 mobi-web/map/index.php
  156. +0 −2  mobi-web/mobile-about/Basic/background.html
  157. +3 −4 mobi-web/mobile-about/Basic/credits.html
  158. +1 −1  mobi-web/mobile-about/Basic/requirements.html
  159. +12 −4 mobi-web/mobile-about/Basic/statistics.html
  160. +0 −3  mobi-web/mobile-about/Touch/background.html
  161. +3 −4 mobi-web/mobile-about/Touch/credits.html
  162. +1 −1  mobi-web/mobile-about/Touch/requirements.html
  163. +0 −3  mobi-web/mobile-about/Webkit/background.html
  164. +3 −4 mobi-web/mobile-about/Webkit/credits.html
  165. +2 −2 mobi-web/mobile-about/Webkit/requirements.html
  166. +1 −1  mobi-web/mobile-about/Webkit/statistics.html
  167. +43 −129 mobi-web/mobile-about/statistics.php
  168. +3 −0  mobi-web/n/.htaccess
  169. +11 −0 mobi-web/n/index.php
  170. +5 −0 mobi-web/news/Basic/channel_nav_links.php
  171. +48 −0 mobi-web/news/Basic/detail.html
  172. +78 −0 mobi-web/news/Basic/index.html
  173. +81 −0 mobi-web/news/Basic/news.css
  174. +37 −0 mobi-web/news/Basic/photo.html
  175. +20 −0 mobi-web/news/Touch/channels.html
  176. +49 −0 mobi-web/news/Touch/detail.html
  177. +80 −0 mobi-web/news/Touch/index.html
  178. +206 −0 mobi-web/news/Touch/news.css
  179. +39 −0 mobi-web/news/Touch/photo.html
  180. +46 −0 mobi-web/news/Webkit/detail.html
  181. BIN  mobi-web/news/Webkit/iPhoneBusybox.gif
  182. +79 −0 mobi-web/news/Webkit/index.html
  183. +7 −0 mobi-web/news/Webkit/items.html
  184. +113 −0 mobi-web/news/Webkit/load_next_ten.js
  185. +257 −0 mobi-web/news/Webkit/news.css
  186. +21 −0 mobi-web/news/Webkit/news.js
  187. +45 −0 mobi-web/news/Webkit/photo.html
  188. +6 −3 mobi-web/{careers/index.php → news/channels.php}
  189. +45 −0 mobi-web/news/detail.php
  190. +24 −0 mobi-web/news/help.php
  191. +168 −0 mobi-web/news/index.php
  192. BIN  mobi-web/news/news-placeholder.gif
  193. +46 −0 mobi-web/news/photo.php
  194. +25 −0 mobi-web/news/shared/photo_pagination.html
  195. +126 −0 mobi-web/news/story_request_lib.php
  196. +20 −2 mobi-web/page_builder/Page.php
  197. +7 −1 mobi-web/page_builder/TouchPage.php
  198. +7 −1 mobi-web/page_builder/WebkitPage.php
  199. +55 −19 mobi-web/page_builder/counter.php
  200. +141 −16 mobi-web/page_builder/page_tools.php
  201. +27 −0 mobi-web/page_builder/url_decoder.php
  202. +0 −62 mobi-web/setup/generate_stats_from_logs.php
  203. +0 −100 mobi-web/setup/setup.sh
  204. +2 −6 mobi-web/shuttleschedule/Basic/times.html
  205. +2 −4 mobi-web/shuttleschedule/Touch/times.html
  206. +101 −0 mobi-web/shuttleschedule/Webkit/shuttletrack-tablet.css
  207. +4 −4 mobi-web/shuttleschedule/Webkit/shuttletrack.css
  208. +6 −11 mobi-web/shuttleschedule/Webkit/times.html
  209. BIN  mobi-web/shuttleschedule/gtfs/gtfs.zip
  210. +139 −0 mobi-web/shuttleschedule/gtfs/index.php
  211. +185 −0 mobi-web/shuttleschedule/gtfs/labeled_marker.js
  212. BIN  mobi-web/shuttleschedule/gtfs/mm_20_blue.png
  213. BIN  mobi-web/shuttleschedule/gtfs/mm_20_blue_trans.png
  214. BIN  mobi-web/shuttleschedule/gtfs/mm_20_red_trans.png
  215. BIN  mobi-web/shuttleschedule/gtfs/mm_20_shadow.png
  216. BIN  mobi-web/shuttleschedule/gtfs/mm_20_shadow_trans.png
  217. BIN  mobi-web/shuttleschedule/gtfs/mm_20_yellow.png
  218. +165 −0 mobi-web/shuttleschedule/gtfs/style.css
  219. +7 −0 mobi-web/shuttleschedule/gtfs/svgcheck.vbs
  220. +715 −0 mobi-web/shuttleschedule/gtfs/template.html
  221. BIN  mobi-web/shuttleschedule/images/200/boston-a.gif
  222. BIN  mobi-web/shuttleschedule/images/200/boston-b.gif
  223. BIN  mobi-web/shuttleschedule/images/200/boston-c.gif
  224. BIN  mobi-web/shuttleschedule/images/200/boston-d.gif
  225. BIN  mobi-web/shuttleschedule/images/200/boston-e.gif
  226. BIN  mobi-web/shuttleschedule/images/200/boston-f.gif
  227. BIN  mobi-web/shuttleschedule/images/200/boston-g.gif
  228. BIN  mobi-web/shuttleschedule/images/200/boston.gif
  229. BIN  mobi-web/shuttleschedule/images/200/cambridge-west-j.gif
  230. BIN  mobi-web/shuttleschedule/images/200/cambridge-west-l.gif
  231. BIN  mobi-web/shuttleschedule/images/200/northwest-a.gif
  232. BIN  mobi-web/shuttleschedule/images/200/northwest-ab.gif
  233. BIN  mobi-web/shuttleschedule/images/200/northwest-ac.gif
  234. BIN  mobi-web/shuttleschedule/images/200/northwest-ad.gif
  235. BIN  mobi-web/shuttleschedule/images/200/northwest-ae.gif
  236. BIN  mobi-web/shuttleschedule/images/200/northwest-af.gif
  237. BIN  mobi-web/shuttleschedule/images/200/northwest-ag.gif
  238. BIN  mobi-web/shuttleschedule/images/200/northwest-ah.gif
  239. BIN  mobi-web/shuttleschedule/images/200/northwest-ai.gif
  240. BIN  mobi-web/shuttleschedule/images/200/northwest-b.gif
  241. BIN  mobi-web/shuttleschedule/images/200/northwest-ba.gif
  242. BIN  mobi-web/shuttleschedule/images/200/northwest-bc.gif
  243. BIN  mobi-web/shuttleschedule/images/200/northwest-bd.gif
  244. BIN  mobi-web/shuttleschedule/images/200/northwest-be.gif
  245. BIN  mobi-web/shuttleschedule/images/200/northwest-bf.gif
  246. BIN  mobi-web/shuttleschedule/images/200/northwest-bg.gif
  247. BIN  mobi-web/shuttleschedule/images/200/northwest-bh.gif
  248. BIN  mobi-web/shuttleschedule/images/200/northwest-bi.gif
  249. BIN  mobi-web/shuttleschedule/images/200/northwest-c.gif
  250. BIN  mobi-web/shuttleschedule/images/200/northwest-ca.gif
  251. BIN  mobi-web/shuttleschedule/images/200/northwest-cb.gif
  252. BIN  mobi-web/shuttleschedule/images/200/northwest-cd.gif
  253. BIN  mobi-web/shuttleschedule/images/200/northwest-ce.gif
  254. BIN  mobi-web/shuttleschedule/images/200/northwest-cf.gif
  255. BIN  mobi-web/shuttleschedule/images/200/northwest-cg.gif
  256. BIN  mobi-web/shuttleschedule/images/200/northwest-ch.gif
  257. BIN  mobi-web/shuttleschedule/images/200/northwest-ci.gif
  258. BIN  mobi-web/shuttleschedule/images/200/northwest-d.gif
  259. BIN  mobi-web/shuttleschedule/images/200/northwest-da.gif
  260. BIN  mobi-web/shuttleschedule/images/200/northwest-db.gif
  261. BIN  mobi-web/shuttleschedule/images/200/northwest-dc.gif
  262. BIN  mobi-web/shuttleschedule/images/200/northwest-de.gif
  263. BIN  mobi-web/shuttleschedule/images/200/northwest-df.gif
  264. BIN  mobi-web/shuttleschedule/images/200/northwest-dg.gif
  265. BIN  mobi-web/shuttleschedule/images/200/northwest-dh.gif
  266. BIN  mobi-web/shuttleschedule/images/200/northwest-di.gif
  267. BIN  mobi-web/shuttleschedule/images/200/northwest-e.gif
  268. BIN  mobi-web/shuttleschedule/images/200/northwest-ea.gif
  269. BIN  mobi-web/shuttleschedule/images/200/northwest-eb.gif
  270. BIN  mobi-web/shuttleschedule/images/200/northwest-ec.gif
  271. BIN  mobi-web/shuttleschedule/images/200/northwest-ed.gif
  272. BIN  mobi-web/shuttleschedule/images/200/northwest-ef.gif
  273. BIN  mobi-web/shuttleschedule/images/200/northwest-eg.gif
  274. BIN  mobi-web/shuttleschedule/images/200/northwest-eh.gif
  275. BIN  mobi-web/shuttleschedule/images/200/northwest-ei.gif
  276. BIN  mobi-web/shuttleschedule/images/200/northwest-f.gif
  277. BIN  mobi-web/shuttleschedule/images/200/northwest-fa.gif
  278. BIN  mobi-web/shuttleschedule/images/200/northwest-fb.gif
  279. BIN  mobi-web/shuttleschedule/images/200/northwest-fc.gif
  280. BIN  mobi-web/shuttleschedule/images/200/northwest-fd.gif
  281. BIN  mobi-web/shuttleschedule/images/200/northwest-fe.gif
  282. BIN  mobi-web/shuttleschedule/images/200/northwest-fg.gif
  283. BIN  mobi-web/shuttleschedule/images/200/northwest-fh.gif
  284. BIN  mobi-web/shuttleschedule/images/200/northwest-fi.gif
  285. BIN  mobi-web/shuttleschedule/images/200/northwest-g.gif
  286. BIN  mobi-web/shuttleschedule/images/200/northwest-ga.gif
  287. BIN  mobi-web/shuttleschedule/images/200/northwest-gb.gif
  288. BIN  mobi-web/shuttleschedule/images/200/northwest-gc.gif
  289. BIN  mobi-web/shuttleschedule/images/200/northwest-gd.gif
  290. BIN  mobi-web/shuttleschedule/images/200/northwest-ge.gif
  291. BIN  mobi-web/shuttleschedule/images/200/northwest-gf.gif
  292. BIN  mobi-web/shuttleschedule/images/200/northwest-gh.gif
  293. BIN  mobi-web/shuttleschedule/images/200/northwest-gi.gif
  294. BIN  mobi-web/shuttleschedule/images/200/northwest-h.gif
  295. BIN  mobi-web/shuttleschedule/images/200/northwest-ha.gif
  296. BIN  mobi-web/shuttleschedule/images/200/northwest-hb.gif
  297. BIN  mobi-web/shuttleschedule/images/200/northwest-hc.gif
  298. BIN  mobi-web/shuttleschedule/images/200/northwest-hd.gif
  299. BIN  mobi-web/shuttleschedule/images/200/northwest-he.gif
  300. BIN  mobi-web/shuttleschedule/images/200/northwest-hf.gif
Sorry, we could not display the entire diff because too many files (773) changed.
View
4 README.markdown
@@ -1,6 +1,6 @@
-MIT Mobile Web 2.1
+MIT Mobile Web 2.2.7
-This is the MIT Mobile Web 2.1 code running on http://m.mit.edu/ as of February 2010, minus the mobile device detection server. That will have its own repository on GitHub.
+This is the same code running on http://m.mit.edu/ as of October 2010, minus the mobile device detection server. That will have its own repository on GitHub.
The MIT Mobile Web is an open source project released under the MIT License, detailed in the file named LICENSE.
View
38 mobi-config/mobi_lib_config.php
@@ -1,38 +0,0 @@
-<?
-
-/*
- * use this file to store all sensitive info (passwords etc) in one place
- *
- * please put non-sensitive information in constants.php
- * as much as possible, so that if people need to change things we don't
- * have to touch this file
- */
-
-// database parameters
-define("MYSQL_USER", 'mysql_user');
-define("MYSQL_PASS", 'mysql_pass');
-define("MYSQL_DBNAME", 'mysql_dbname');
-define("MYSQL_HOST", 'localhost');
-
-/* TECHCASH
- * the techcash file in lib contains information about the structure of
- * databases in techcash and mit data warehouse.
- * it may or may not be sensitive but if it is, we should remove the
- * techcash module and all related references (including this section
- * of this file) if/when we pack up our code for open source.
- */
-define("ORACLE_HOME", '/oracle/product/10.2.0/client');
-define("TECHCASH_ORACLE_USER", 'techcash_oracle_user');
-define("TECHCASH_ORACLE_PASS", 'techcash_oracle_pass');
-define("TECHCASH_ORACLE_DB", 'techcash_oracle_db');
-define("WAREHOUSE_ORACLE_USER", 'warehouse_oracle_user');
-define("WAREHOUSE_ORACLE_PASS", 'warehouse_oracle_pass');
-define("WAREHOUSE_ORACLE_DB", 'warehouse_oracle_db');
-
-// DRUPAL
-define("DRUPAL_MYSQL_USER", 'drupal_user');
-define("DRUPAL_MYSQL_PASS", 'drupal_pass');
-define("DRUPAL_MYSQL_DBNAME", 'drupal_db');
-define("DRUPAL_MYSQL_HOST", 'localhost');
-
-?>
View
183 mobi-config/mobi_lib_constants.php
@@ -1,88 +1,95 @@
-<?
-$docRoot = getenv("DOCUMENT_ROOT");
-
-require_once($docRoot . '/mobi-config/mobi_lib_config.php');
-
-/*
- * use this file for storing constants that are used in multiple files
- * DO NOT STORE sensitive info like passwords
- * those go in config.php
- * which should not be committed
- */
-
-// file/directory locations
-if (version_compare(phpversion(), '5.3') == -1) {
- define("CACHE_DIR", '/var/www/html/mobi-lib/cache/');
- define("LIBDIR", '/var/www/html/mobi-lib/');
-} else {
- define("CACHE_DIR", __DIR__ . '/cache/');
- define("LIBDIR", __DIR__);
-}
-
-/* debug preferences
- * not really all constants but whatever
- */
-define("DEBUG_LEVEL_ERROR", 0);
-define("DEBUG_LEVEL_WARNING", 1);
-define("DEBUG_LEVEL_DEBUG", 2);
-define("DEBUG_LEVEL", DEBUG_LEVEL_ERROR);
-
-function warn($mesg) {
- if (DEBUG_LEVEL >= DEBUG_LEVEL_WARNING) echo $mesg . "\n";
-}
-
-function debug($mesg) {
- if (DEBUG_LEVEL >= DEBUG_LEVEL_DEBUG) echo $mesg . "\n";
-}
-
-/* misc */
-define("TIMEZONE", "America/New_York");
-
-/* SHUTTLESCHEDULE */
-define("NEXTBUS_FEED_URL", 'http://www.nextbus.com/s/xmlFeed?');
-define("NEXTBUS_AGENCY", 'mit');
-define("NEXTBUS_ROUTE_CACHE_TIMEOUT", 86400); // max age, routeConfig data
-define("NEXTBUS_PREDICTION_CACHE_TIMEOUT", 20); // max age, predictions
-define("NEXTBUS_VEHICLE_CACHE_TIMEOUT", 10); // max age, vehicle locations
-define("NEXTBUS_CACHE_MAX_TOLERANCE", 90); // when to revert to pub schedule
-define("NEXTBUS_DAEMON_PID_FILE", CACHE_DIR . 'NEXTBUS_DAEMON_PID');
-
-/* STELLAR */
-define("STELLAR_COURSE_DIR", CACHE_DIR . 'STELLAR_COURSE/'); // dir for subject listing files
-define("STELLAR_COURSE_CACHE_TIMEOUT", 86400); // how long to keep cached subject files
-define("STELLAR_FEED_DIR", CACHE_DIR . 'STELLAR_FEEDS/'); // dir for cached rss data
-define("STELLAR_FEED_CACHE_TIMEOUT", 10); // how long to keep cached rss files
-define("STELLAR_SUBSCRIPTIONS_FILE", CACHE_DIR . 'STELLAR_SUBSCRIPTIONS');
-define("STELLAR_USE_PRODUCTION", True);
-if(STELLAR_USE_PRODUCTION) {
- define("STELLAR_BASE_URL", "http://stellar.mit.edu/courseguide/course/");
- define("STELLAR_RSS_URL", "http://stellar.mit.edu/SRSS/rss");
-} else {
- define("STELLAR_BASE_URL", "http://stellar-dev.mit.edu/courseguide/course/");
- define("STELLAR_RSS_URL", "http://stellar-dev.mit.edu/SRSS/rss");
-}
-
-/* LIBRARIES */
-define("ICS_CACHE_LIFESPAN", 900);
-
-// EMERGENCY
-define("EMERGENCY_USE_PRODUCTION", True);
-if(EMERGENCY_USE_PRODUCTION) {
- define("EMERGENCY_RSS_URL", 'http://emergency.mit.net/emergency/mobirss');
-} else {
- define("EMERGENCY_RSS_URL", 'http://emergency.mit.net/emtest/mobirss');
-}
-
-// 3DOWN
-define("THREEDOWN_RSS_URL", 'http://3down.mit.edu/3down/index.php?rss=1');
-
-/*
-// these aren't being used, just keeping a record of what may
-
-// PEOPLE DIRECTORY
-define("LDAP_SERVER", 'ldap.mit.edu');
-
-*/
-
-
-?>
+<?
+$docRoot = getenv("DOCUMENT_ROOT");
+
+require_once($docRoot . '/mobi-config/mobi_lib_config.php');
+
+/*
+ * use this file for storing constants that are used in multiple files
+ * DO NOT STORE sensitive info like passwords
+ * those go in config.php
+ * which should not be committed
+ */
+
+// file/directory locations
+if (version_compare(phpversion(), '5.3') == -1) {
+ define("CACHE_DIR", '/var/www/html/mobi-lib/cache/');
+ define("LIBDIR", '/var/www/html/mobi-lib/');
+} else {
+ define("CACHE_DIR", __DIR__ . '/cache/');
+ define("LIBDIR", __DIR__);
+}
+
+/* debug preferences
+ * not really all constants but whatever
+ */
+define("DEBUG_LEVEL_ERROR", 0);
+define("DEBUG_LEVEL_WARNING", 1);
+define("DEBUG_LEVEL_DEBUG", 2);
+define("DEBUG_LEVEL", DEBUG_LEVEL_ERROR);
+
+function warn($mesg) {
+ if (DEBUG_LEVEL >= DEBUG_LEVEL_WARNING) echo $mesg . "\n";
+}
+
+function debug($mesg) {
+ if (DEBUG_LEVEL >= DEBUG_LEVEL_DEBUG) echo $mesg . "\n";
+}
+
+/* misc */
+define("TIMEZONE", "America/New_York");
+
+/* SHUTTLESCHEDULE */
+define("NEXTBUS_FEED_URL", 'http://www.nextbus.com/s/xmlFeed?');
+define("NEXTBUS_AGENCY", 'mit');
+define("NEXTBUS_ROUTE_CACHE_TIMEOUT", 86400); // max age, routeConfig data
+define("NEXTBUS_PREDICTION_CACHE_TIMEOUT", 20); // max age, predictions
+define("NEXTBUS_VEHICLE_CACHE_TIMEOUT", 10); // max age, vehicle locations
+define("NEXTBUS_CACHE_MAX_TOLERANCE", 90); // when to revert to pub schedule
+define("NEXTBUS_DAEMON_PID_FILE", CACHE_DIR . 'NEXTBUS_DAEMON_PID');
+
+/* STELLAR */
+define("STELLAR_COURSE_DIR", CACHE_DIR . 'STELLAR_COURSE/'); // dir for subject listing files
+define("STELLAR_COURSE_CACHE_TIMEOUT", 86400); // how long to keep cached subject files
+define("STELLAR_FEED_DIR", CACHE_DIR . 'STELLAR_FEEDS/'); // dir for cached rss data
+define("STELLAR_FEED_CACHE_TIMEOUT", 10); // how long to keep cached rss files
+define("STELLAR_SUBSCRIPTIONS_FILE", CACHE_DIR . 'STELLAR_SUBSCRIPTIONS');
+define("STELLAR_USE_PRODUCTION", True);
+if(STELLAR_USE_PRODUCTION) {
+ define("STELLAR_BASE_URL", "http://stellar.mit.edu/courseguide/course/");
+ define("STELLAR_RSS_URL", "http://stellar.mit.edu/SRSS/rss");
+} else {
+ define("STELLAR_BASE_URL", "http://stellar-dev.mit.edu/courseguide/course/");
+ define("STELLAR_RSS_URL", "http://stellar-dev.mit.edu/SRSS/rss");
+}
+
+/* LIBRARIES */
+define("ICS_CACHE_LIFESPAN", 900);
+
+// EMERGENCY
+define("EMERGENCY_USE_PRODUCTION", True);
+if(EMERGENCY_USE_PRODUCTION) {
+ define("EMERGENCY_RSS_URL", 'http://emergency.mit.net/emergency/mobirss');
+} else {
+ define("EMERGENCY_RSS_URL", 'http://emergency.mit.net/emtest/mobirss');
+}
+
+// 3DOWN
+define("THREEDOWN_RSS_URL", 'http://3down.mit.edu/3down/index.php?rss=1');
+
+/*
+// these aren't being used, just keeping a record of what may
+
+// PEOPLE DIRECTORY
+define("LDAP_SERVER", 'ldap.mit.edu');
+
+*/
+
+/* Events Calendar */
+define("EVENTS_CALENDAR_UNIQUE_EVENT_URL", "http://events.mit.edu/event.html?id=");
+
+/* news office */
+define("NEWSOFFICE_FEED_URL", 'http://web.mit.edu/newsoffice/feeds/iphone.php');
+define("NEWSOFFICE_STORY_URL", 'http://web.mit.edu/newsoffice/index.php?option=com_content&view=article&id=');
+define("NEWSOFFICE_SEARCH_URL", 'http://web.mit.edu/newsoffice/index.php?option=com_search&view=isearch');
+
+?>
View
167 mobi-config/mobi_lib_constants.php.init
@@ -1,72 +1,95 @@
-<?
-
-require_once('config.php');
-
-/*
- * use this file for storing constants that are used in multiple files
- * DO NOT STORE sensitive info like passwords
- * those go in config.php
- * which should not be committed
- */
-
-// file/directory locations
-if (version_compare(phpversion(), '5.3') == -1) {
- define("CACHE_DIR", '/var/lib/trunk/cache/');
- define("LIBDIR", '/var/lib/trunk/');
-} else {
- define("CACHE_DIR", __DIR__ . '/cache/');
- define("LIBDIR", __DIR__);
-}
-
-/* debug preferences
- * not really all constants but whatever
- */
-define("DEBUG_LEVEL_ERROR", 0);
-define("DEBUG_LEVEL_WARNING", 1);
-define("DEBUG_LEVEL_DEBUG", 2);
-define("DEBUG_LEVEL", DEBUG_LEVEL_ERROR);
-
-function warn($mesg) {
- if (DEBUG_LEVEL >= DEBUG_LEVEL_WARNING) echo $mesg . "\n";
-}
-
-function debug($mesg) {
- if (DEBUG_LEVEL >= DEBUG_LEVEL_DEBUG) echo $mesg . "\n";
-}
-
-/* misc */
-define("TIMEZONE", "America/New_York");
-
-/* SHUTTLESCHEDULE */
-define("NEXTBUS_FEED_URL", 'http://www.nextbus.com/s/xmlFeed?');
-define("NEXTBUS_AGENCY", 'mit');
-define("NEXTBUS_ROUTE_CACHE_TIMEOUT", 86400); // max age, routeConfig data
-define("NEXTBUS_PREDICTION_CACHE_TIMEOUT", 20); // max age, predictions
-define("NEXTBUS_CACHE_MAX_TOLERANCE", 90); // when to revert to pub schedule
-define("NEXTBUS_DAEMON_PID_FILE", CACHE_DIR . 'NEXTBUS_DAEMON_PID');
-
-/* STELLAR */
-define("STELLAR_COURSE_DIR", CACHE_DIR . 'STELLAR_COURSE/'); // dir for subject listing files
-define("STELLAR_COURSE_CACHE_TIMEOUT", 86400); // how long to keep cached subject files
-define("STELLAR_FEED_DIR", CACHE_DIR . 'STELLAR_FEEDS/'); // dir for cached rss data
-define("STELLAR_FEED_CACHE_TIMEOUT", 10); // how long to keep cached rss files
-define("STELLAR_SUBSCRIPTIONS_FILE", CACHE_DIR . 'STELLAR_SUBSCRIPTIONS');
-
-/* LIBRARIES */
-define("ICS_CACHE_LIFESPAN", 900);
-
-/*
-// these aren't being used, just keeping a record of what may
-
-// PEOPLE DIRECTORY
-define("LDAP_SERVER", 'ldap.mit.edu');
-
-// EMERGENCY
-define("EMERGENCY_RSS_URL", 'http://emergency.mit.edu/emergency/rss.php');
-
-// 3DOWN
-define("THREEDOWN_RSS_URL", 'http://3down.mit.edu/3down/index.php?rss=1');
-*/
-
-
-?>
+<?
+$docRoot = getenv("DOCUMENT_ROOT");
+
+require_once($docRoot . '/mobi-config/mobi_lib_config.php');
+
+/*
+ * use this file for storing constants that are used in multiple files
+ * DO NOT STORE sensitive info like passwords
+ * those go in config.php
+ * which should not be committed
+ */
+
+// file/directory locations
+if (version_compare(phpversion(), '5.3') == -1) {
+ define("CACHE_DIR", '/var/www/html/mobi-lib/cache/');
+ define("LIBDIR", '/var/www/html/mobi-lib/');
+} else {
+ define("CACHE_DIR", __DIR__ . '/cache/');
+ define("LIBDIR", __DIR__);
+}
+
+/* debug preferences
+ * not really all constants but whatever
+ */
+define("DEBUG_LEVEL_ERROR", 0);
+define("DEBUG_LEVEL_WARNING", 1);
+define("DEBUG_LEVEL_DEBUG", 2);
+define("DEBUG_LEVEL", DEBUG_LEVEL_ERROR);
+
+function warn($mesg) {
+ if (DEBUG_LEVEL >= DEBUG_LEVEL_WARNING) echo $mesg . "\n";
+}
+
+function debug($mesg) {
+ if (DEBUG_LEVEL >= DEBUG_LEVEL_DEBUG) echo $mesg . "\n";
+}
+
+/* misc */
+define("TIMEZONE", "America/New_York");
+
+/* SHUTTLESCHEDULE */
+define("NEXTBUS_FEED_URL", 'http://www.nextbus.com/s/xmlFeed?');
+define("NEXTBUS_AGENCY", 'mit');
+define("NEXTBUS_ROUTE_CACHE_TIMEOUT", 86400); // max age, routeConfig data
+define("NEXTBUS_PREDICTION_CACHE_TIMEOUT", 20); // max age, predictions
+define("NEXTBUS_VEHICLE_CACHE_TIMEOUT", 10); // max age, vehicle locations
+define("NEXTBUS_CACHE_MAX_TOLERANCE", 90); // when to revert to pub schedule
+define("NEXTBUS_DAEMON_PID_FILE", CACHE_DIR . 'NEXTBUS_DAEMON_PID');
+
+/* STELLAR */
+define("STELLAR_COURSE_DIR", CACHE_DIR . 'STELLAR_COURSE/'); // dir for subject listing files
+define("STELLAR_COURSE_CACHE_TIMEOUT", 86400); // how long to keep cached subject files
+define("STELLAR_FEED_DIR", CACHE_DIR . 'STELLAR_FEEDS/'); // dir for cached rss data
+define("STELLAR_FEED_CACHE_TIMEOUT", 10); // how long to keep cached rss files
+define("STELLAR_SUBSCRIPTIONS_FILE", CACHE_DIR . 'STELLAR_SUBSCRIPTIONS');
+define("STELLAR_USE_PRODUCTION", True);
+if(STELLAR_USE_PRODUCTION) {
+ define("STELLAR_BASE_URL", "http://stellar.mit.edu/courseguide/course/");
+ define("STELLAR_RSS_URL", "http://stellar.mit.edu/SRSS/rss");
+} else {
+ define("STELLAR_BASE_URL", "http://stellar-dev.mit.edu/courseguide/course/");
+ define("STELLAR_RSS_URL", "http://stellar-dev.mit.edu/SRSS/rss");
+}
+
+/* LIBRARIES */
+define("ICS_CACHE_LIFESPAN", 900);
+
+// EMERGENCY
+define("EMERGENCY_USE_PRODUCTION", True);
+if(EMERGENCY_USE_PRODUCTION) {
+ define("EMERGENCY_RSS_URL", 'http://emergency.mit.net/emergency/mobirss');
+} else {
+ define("EMERGENCY_RSS_URL", 'http://emergency.mit.net/emtest/mobirss');
+}
+
+// 3DOWN
+define("THREEDOWN_RSS_URL", 'http://3down.mit.edu/3down/index.php?rss=1');
+
+/*
+// these aren't being used, just keeping a record of what may
+
+// PEOPLE DIRECTORY
+define("LDAP_SERVER", 'ldap.mit.edu');
+
+*/
+
+/* Events Calendar */
+define("EVENTS_CALENDAR_UNIQUE_EVENT_URL", "http://events.mit.edu/event.html?id=");
+
+/* news office */
+define("NEWSOFFICE_FEED_URL", 'http://web.mit.edu/newsoffice/feeds/iphone.php');
+define("NEWSOFFICE_STORY_URL", 'http://web.mit.edu/newsoffice/index.php?option=com_content&view=article&id=');
+define("NEWSOFFICE_SEARCH_URL", 'http://web.mit.edu/newsoffice/index.php?option=com_search&view=isearch');
+
+?>
View
9 mobi-config/mobi_web_constants.php
@@ -10,7 +10,7 @@
* of the people the server should email when something
* goes wrong
*/
-define("DEVELOPER_EMAIL", "nobody@mit.edu");
+define("DEVELOPER_EMAIL", "mobile-project-errors@mit.edu");
/** log file locations
*
@@ -52,6 +52,7 @@
* index 7: set to TRUE if needed for processing (non display), otherwise FALSE
*/
$appError = 0;
+global $personDisplayMapping;
$personDisplayMapping = array(array("surname", "sn", null, null, FALSE, FALSE, FALSE, TRUE),
array("givenname", "givenname", null, null, FALSE, FALSE, FALSE, TRUE),
array("name", "cn", null, null, TRUE, TRUE, FALSE, FALSE),
@@ -116,9 +117,7 @@
/* mqp searchserver */
define("MAP_SEARCH_URL", 'http://whereis.mit.edu/search');
-
-/* news office */
-define("NEWSOFFICE_FEED_URL", 'http://web.mit.edu/newsoffice/feeds/iphone.php');
+define("MAP_TILE_CACHE_DATE", 'tiles_last_updated.txt');
// cookie expire times
define("MODULE_ORDER_COOKIE_LIFESPAN", 160 * 86400);
@@ -135,7 +134,7 @@
define("APNS_CERTIFICATE_DEV_PASSWORD", '');
define("APNS_CERTIFICATE_PROD", '/usr/local/etc/was/certs/apns_prod.pem');
define("APNS_CERTIFICATE_PROD_PASSWORD", '');
-define("APNS_SANDBOX", True);
+define("APNS_SANDBOX", False);
define("APPLE_RELEASE_APP_ID", "edu.mit.mitmobile");
define("APNS_CONNECTIONS_LIMIT", 100);
View
9 mobi-config/mobi_web_constants.php.init
@@ -10,7 +10,7 @@ define("USE_PRODUCTION_ERROR_HANDLER", True);
* of the people the server should email when something
* goes wrong
*/
-define("DEVELOPER_EMAIL", "nobody@mit.edu");
+define("DEVELOPER_EMAIL", "mobile-project-errors@mit.edu");
/** log file locations
*
@@ -52,6 +52,7 @@ define("UID_SEARCH_FILTER", "(&(objectClass=person)%s)");
* index 7: set to TRUE if needed for processing (non display), otherwise FALSE
*/
$appError = 0;
+global $personDisplayMapping;
$personDisplayMapping = array(array("surname", "sn", null, null, FALSE, FALSE, FALSE, TRUE),
array("givenname", "givenname", null, null, FALSE, FALSE, FALSE, TRUE),
array("name", "cn", null, null, TRUE, TRUE, FALSE, FALSE),
@@ -116,9 +117,7 @@ define("MOBI_SERVICE_URL", 'http://mobile-service-dev.mit.edu/mobi-service/');
/* mqp searchserver */
define("MAP_SEARCH_URL", 'http://whereis.mit.edu/search');
-
-/* news office */
-define("NEWSOFFICE_FEED_URL", 'http://web.mit.edu/newsoffice/feeds/iphone.php');
+define("MAP_TILE_CACHE_DATE", 'tiles_last_updated.txt');
// cookie expire times
define("MODULE_ORDER_COOKIE_LIFESPAN", 160 * 86400);
@@ -135,7 +134,7 @@ define("APNS_CERTIFICATE_DEV", '/usr/local/etc/was/certs/apns_dev.pem');
define("APNS_CERTIFICATE_DEV_PASSWORD", '');
define("APNS_CERTIFICATE_PROD", '/usr/local/etc/was/certs/apns_prod.pem');
define("APNS_CERTIFICATE_PROD_PASSWORD", '');
-define("APNS_SANDBOX", True);
+define("APNS_SANDBOX", False);
define("APPLE_RELEASE_APP_ID", "edu.mit.mitmobile");
define("APNS_CONNECTIONS_LIMIT", 100);
View
194 mobi-lib/AcademicCalendar.php
@@ -4,55 +4,76 @@
require_once $docRoot . "/mobi-config/mobi_lib_constants.php";
require_once "mit_ical_lib.php";
+require_once "rss_services.php";
-define("ACADEMIC_CALENDAR_ICS", 'http://web.mit.edu/registrar/calendar/AcademicCalendar.ics');
-define("ACADEMIC_CALENDAR_CACHE_FILE", CACHE_DIR . "ACADEMIC_CALENDAR");
+define("ACADEMIC_CALENDAR_CACHE_DIR", CACHE_DIR . "ACADEMIC_CALENDAR/");
+define("ACADEMIC_CALENDAR_RSS", "http://localhost/drupal/academic_calendar/rss.xml");
define("ACADEMIC_CALENDAR_CACHE_LIFESPAN", 86400 * 30);
+class AcademicCalendarRSS extends RSS {
+ protected $rss_url = ACADEMIC_CALENDAR_RSS;
+ protected $custom_tags = array('fiscal_year', 'ics_url');
+}
+
+AcademicCalendar::init();
+
class AcademicCalendar {
- private static $ical;
+ private static $icals = array();
+ //private static $ical;
private static $terms = NULL;
public static function is_holiday($time) {
self::init();
- $events = self::$ical->get_day_events($time);
- foreach ($events as $event) {
- if (stripos($event->get_summary(), 'holiday') !== FALSE
- || stripos($event->get_summary(), 'vacation') !== FALSE)
- return TRUE;
+
+ $year = date('Y', $time);
+ $month = date('n', $time);
+ $fiscal_year = ($month <= 6) ? $year : $year + 1;
+ if (array_key_exists($fiscal_year, self::$icals)) {
+ $ical = self::$icals[$fiscal_year];
+
+ $events = $ical->get_day_events($time);
+ foreach ($events as $event) {
+ $summary = $event->get_summary();
+ if (stripos($summary, 'holiday') !== FALSE
+ || stripos($summary, 'vacation') !== FALSE) {
+ if ($event->get_end() - $event->get_start() < 86400 * 3)
+ return TRUE;
+ }
+ }
}
return FALSE;
}
- public static function get_holidays($year) {
- self::init();
- $holidays = self::$ical->search_by_title('holiday');
- $vacation = self::$ical->search_by_title('vacation');
+ public static function get_holidays($year, $month=NULL) {
$data = Array();
+ if ($month && $month > 6) {
+ $year += 1;
+ }
+
+ if (array_key_exists($year, self::$icals)) {
+ $ical = self::$icals[$year];
+
+ $holidays = $ical->search_by_title('holiday');
+ $vacation = $ical->search_by_title('vacation');
- // here we take advantage of the fact that the acad calendar
- // does not have overlapping dates for vacations and holidays
- // if they do we need to account for that
- foreach ($holidays as $day) {
- $start = $day->get_start();
- if (date('Y', $start) == $year) {
+ // here we take advantage of the fact that the acad calendar
+ // does not have overlapping dates for vacations and holidays
+ // if they do we need to account for that
+ foreach ($holidays as $day) {
+ $start = $day->get_start();
$data[$start] = $day;
}
- }
- foreach ($vacation as $day) {
- $start = $day->get_start();
- if (date('Y', $start) == $year) {
+ foreach ($vacation as $day) {
+ $start = $day->get_start();
$data[$start] = $day;
}
- }
- ksort($data);
+ ksort($data);
+ }
return array_values($data);
}
- public static function get_events($month=NULL, $year=NULL) {
- self::init();
-
+ public static function search_events($searchTerms, $month=NULL, $year=NULL) {
if ($year === NULL) {
$year = date('Y');
}
@@ -61,13 +82,29 @@ public static function get_events($month=NULL, $year=NULL) {
$month = date('n');
}
+ $fiscal_year = ($month <= 6) ? $year : $year + 1;
+ if (array_key_exists($fiscal_year, self::$icals)) {
+ $ical = self::$icals[$fiscal_year];
+ } else {
+ return array();
+ }
+
// adjust day starts for time zones
// honestly i am not 100% sure these are the right params
$month_start = day_of(mktime(0, 0, 0, $month, 1, $year));
$month_end = increment_month($month_start);
$monthRange = new TimeRange($month_start, $month_end);
- return self::$ical->search_by_range($monthRange);
+ //$result = array();
+ //foreach (self::$icals as $ical) {
+ // $result = array_merge($result, $ical->search_events($searchTerms, $monthRange));
+ //}
+ $result = $ical->search_events($searchTerms, $monthRange);
+ return $result;
+ }
+
+ public static function get_events($month=NULL, $year=NULL) {
+ return self::search_events(NULL, $month, $year);
}
public static function get_term($time=NULL) {
@@ -75,69 +112,90 @@ public static function get_term($time=NULL) {
$time = time();
if (self::$terms === NULL) {
- // if we're in the first half of the year, use last year as base year
- $year = (date('n', $time) < 7) ? date('Y', $time) - 1 : date('Y', $time);
+ // if we're in the second half of the year, use next year's calendar
+ $year = (date('n', $time) < 7) ? date('Y', $time) : date('Y', $time) + 1;
// start with crude lower-bound guesses for ranges
- $fall_start = mktime(0, 0, 0, 8, 15, $year);
- $iap_start = mktime(0, 0, 0, 1, 1, $year+1);
- $spring_start = mktime(0, 0, 0, 2, 1, $year+1);
- $summer_start = mktime(0, 0, 0, 6, 1, $year+1);
- $summer_end = mktime(0, 0, 0, 8, 15, $year+1);
-
+ $last_summer_start = mktime(0, 0, 0, 6, 1, $year-1);
+ $fall_start = mktime(0, 0, 0, 8, 15, $year-1);
+ $iap_start = mktime(0, 0, 0, 1, 1, $year);
+ $spring_start = mktime(0, 0, 0, 2, 1, $year);
+ $summer_start = mktime(0, 0, 0, 6, 1, $year);
+ $summer_end = mktime(0, 0, 0, 8, 15, $year);
+
+ // academic calendars cover the second half of the summer after
+ // july 1 of the previous year and the first half before july 1
+ // of the current fiscal year
self::$terms = Array(
+ 'su2' => new TimeRange($last_summer_start, $fall_start),
'fa' => new TimeRange($fall_start, $iap_start),
'ia' => new TimeRange($iap_start, $spring_start),
'sp' => new TimeRange($spring_start, $summer_start),
- 'su' => new TimeRange($summer_start, $summer_end),
+ 'su1' => new TimeRange($summer_start, $summer_end),
);
- $events = self::$ical->search_by_title("first day of");
-
- foreach ($events as $event) {
- $event_start = increment_day($event->get_start(), -1);
- foreach (self::$terms as $term => $range) {
- if ($range->contains_point($event_start)) {
- self::$terms[$term]->set_start($event_start);
- switch ($term) {
- case 'ia':
- self::$terms['fa']->set_end($event_start);
+ if (array_key_exists($year, self::$icals)) {
+ $ical = self::$icals[$year];
+ $events = $ical->search_by_title("first day of");
+
+ foreach ($events as $event) {
+ $event_start = increment_day($event->get_start(), -1);
+ foreach (self::$terms as $term => $range) {
+ if ($range->contains_point($event_start)) {
+ self::$terms[$term]->set_start($event_start);
+ switch ($term) {
+ case 'fa':
+ self::$terms['su2']->set_end($event_start);
+ break;
+ case 'ia':
+ self::$terms['fa']->set_end($event_start);
+ break;
+ case 'sp':
+ self::$terms['ia']->set_end($event_start);
+ break;
+ case 'su1':
+ self::$terms['sp']->set_end($event_start);
+ break;
+ } // switch
break;
- case 'sp':
- self::$terms['ia']->set_end($event_start);
- break;
- case 'su':
- self::$terms['sp']->set_end($event_start);
- break;
- } // switch
- break;
- } // if
- } // foreach term
- } // foreach event
+ } // if
+ } // foreach term
+ } // foreach event
- } // done creating terms
+ } // done creating terms
+ }
foreach (self::$terms as $term => $range) {
if ($range->contains_point($time)) {
+ if ($term == 'su1' || $term == 'su2') {
+ return 'su';
+ }
return $term;
- break;
}
}
+ return NULL;
}
public static function init() {
- if (!self::$ical) {
- if (!file_exists(ACADEMIC_CALENDAR_CACHE_FILE)
- || filemtime(ACADEMIC_CALENDAR_CACHE_FILE) < time() - ACADEMIC_CALENDAR_CACHE_LIFESPAN) {
- $fh = fopen(ACADEMIC_CALENDAR_CACHE_FILE, 'w');
- fwrite($fh, file_get_contents(ACADEMIC_CALENDAR_ICS));
- fclose($fh);
+ if (!self::$icals) {
+ $rss = new AcademicCalendarRSS();
+ $items = $rss->get_feed();
+ foreach ($items as $item) {
+ $fy = $item['fiscal_year'];
+ $ics_url = $item['ics_url'];
+
+ $filename = ACADEMIC_CALENDAR_CACHE_DIR . $fy . '.ics';
+ if (!file_exists($filename) || filemtime($filename) < time() - ACADEMIC_CALENDAR_CACHE_LIFESPAN) {
+ $fh = fopen($filename, 'w');
+ fwrite($fh, file_get_contents($ics_url));
+ fclose($fh);
+ }
+ self::$icals[$fy] = new ICalendar($filename);
}
- self::$ical = new ICalendar(ACADEMIC_CALENDAR_CACHE_FILE);
}
}
}
-?>
+?>
View
177 mobi-lib/DiskCache.php
@@ -0,0 +1,177 @@
+<?php
+
+class DiskCache {
+
+ private $path;
+ private $timeout = PHP_INT_MAX;
+ private $error;
+ private $prefix = "";
+ private $suffix = "";
+ private $serialize = TRUE;
+
+ public function __construct($path, $timeout=NULL, $mkdir=FALSE) {
+ $this->path = $path;
+
+ if ($mkdir) {
+ if (!file_exists($path)) {
+ if (!mkdir($path, 0775)) // want cache files to be group writeable
+ error_log("could not create $path");
+ chmod($path, 0775); // also setting mode in mkdir doesn't seem to work
+ chgrp($path, 'apache');
+ }
+ }
+
+ if ($timeout !== NULL)
+ $this->timeout = $timeout;
+ }
+
+ public function preserveFormat() {
+ $this->serialize = FALSE;
+ }
+
+ public function setTimeout($timeout) {
+ $this->timeout = $timeout;
+ }
+
+ public function setPrefix($prefix) {
+ $this->prefix = $prefix;
+ }
+
+ public function getPrefix() {
+ return $this->prefix;
+ }
+
+ public function getSuffix() {
+ return $this->suffix;
+ }
+
+ public function setSuffix($suffix) {
+ $this->suffix = $suffix;
+ }
+
+ public function getError() {
+ return $this->error;
+ }
+
+ public function getFullPath($filename=NULL) {
+ if ($filename === NULL) {
+ return $this->path;
+ } else {
+ // this replaces %20 with + signs
+ $filename = urlencode(urldecode($filename));
+
+ return $this->path . '/'
+ . $this->prefix
+ . $filename
+ . $this->suffix;
+ }
+ }
+
+ public function writeImage($image, $filename) {
+ $success = FALSE;
+ $path = $this->getFullPath($filename);
+ $suffix = $this->suffix ? $this->suffix : substr($filename, -4);
+ switch ($suffix) {
+ case '.png':
+ $success = imagepng($image, $path);
+ break;
+ case '.jpg':
+ $success = imagejpeg($image, $path);
+ break;
+ case '.gif':
+ $success = imagegif($image, $path);
+ break;
+ }
+ return $success;
+ }
+
+ public function readImage($filename) {
+ $path = $this->getFullPath($filename);
+ $suffix = $this->suffix ? $this->suffix : substr($filename, -4);
+ switch ($suffix) {
+ case '.png':
+ $success = imagecreatefrompng($image, $path);
+ break;
+ case '.jpg':
+ $success = imagecreatefromjpeg($image, $path);
+ break;
+ case '.gif':
+ $success = imagecreatefromgif($image, $path);
+ break;
+ }
+ }
+
+ public function write($object, $filename=NULL) {
+ if (!$object) {
+ $this->error = "tried to cache a non-object";
+ }
+
+ $path = $this->getFullPath($filename);
+ if (!file_exists($path)) {
+ touch($path);
+ chmod($path, 0664); // want cache files to be group writeable
+ chgrp($path, 'apache');
+ }
+ $fh = fopen($path, 'w');
+ if ($fh !== FALSE) {
+ if ($this->serialize) {
+ fwrite($fh, serialize($object));
+ } else {
+ fwrite($fh, $object);
+ }
+ fclose($fh);
+ return TRUE;
+
+ } else {
+ $this->error = "could not open $path for writing";
+ }
+
+ // stop doing this here after users handle error on their own
+ if ($this->error)
+ error_log($this->error);
+
+ return FALSE;
+ }
+
+ public function read($filename=NULL) {
+ $path = $this->getFullPath($filename);
+ if (file_exists($path) && $this->isFresh($filename)) {
+ if ($contents = file_get_contents($path)) {
+ if ($this->serialize) {
+ return unserialize($contents);
+ } else {
+ return $contents;
+ }
+ }
+ $this->error = "could not get contents of $path";
+ error_log($this->error, 0);
+ }
+ return FALSE;
+ }
+
+ public function exists($filename) {
+ $path = $this->getFullPath($filename);
+ return (file_exists($path) && filesize($path) > 0);
+ }
+
+ public function isFresh($filename=NULL, $timeout=NULL) {
+ $path = $this->getFullPath($filename);
+ if ($timeout === NULL)
+ $timeout = $this->timeout;
+ return ($this->getAge($filename) < $timeout);
+ }
+
+ public function getAge($filename=NULL) {
+ if ($this->exists($filename)) {
+ $path = $this->getFullPath($filename);
+ return time() - filemtime($path);
+ }
+ return PHP_INT_MAX;
+ }
+
+}
+
+
+
+
+
View
912 mobi-lib/GTFSReader.php
@@ -0,0 +1,912 @@
+<?php
+
+/* this file interacts with a GTFS feed based on the schedule
+ * published by Parking & Transportation and NextBus' routeConfig
+ *
+ * php must be compiled with support for Zip files.
+ */
+
+$docRoot = getenv("DOCUMENT_ROOT");
+
+require_once $docRoot . "/mobi-config/mobi_lib_constants.php";
+require_once $docRoot . "/mobi-config/mobi_web_constants.php";
+
+define("SHUTTLE_GTFS_FEED", WEBROOT . "shuttleschedule/gtfs/gtfs.zip");
+
+require_once 'ShuttleObjects.php';
+require_once 'TimeRange.php';
+require_once 'datetime_lib.php';
+require_once 'NextBusReader.php';
+
+// encoding a polyline in base64
+// http://code.google.com/apis/maps/documentation/utilities/polylinealgorithm.html
+// (don't know if php has something more built-in to do this)
+function base64EncodeNumber($number) {
+ $num = round($number * 100000, 0);
+ if ($num > 0) {
+ $bin = base_convert($num << 1, 10, 2);
+ $bin = ltrim($bin, '0');
+ } else if ($num < 0) {
+ $bin = base_convert(($num << 1) + 1, 10, 2);
+ $bin = ltrim($bin, '0');
+ } else {
+ $bin = '0';
+ }
+
+ $chunks = ceil(strlen($bin) / 5);
+ $len = $chunks * 5;
+ $bin = str_pad($bin, $len, '0', STR_PAD_LEFT);
+ $result = '';
+ for ($i = $chunks; $i > 0; $i--) {
+ $chunk = substr($bin, ($i-1)*5, 5);
+ if ($i > 1) {
+ $value = (base_convert($chunk, 2, 10) | 0x20) + 63;
+ } else {
+ $value = base_convert($chunk, 2, 10) + 63;
+ }
+ $result .= chr($value);
+ }
+ return $result;
+}
+
+class ShuttleSchedule {
+
+ private static $agencies = array();
+ private static $gtfs;
+
+ // backward compatibility
+
+ public static function is_running($route_id, $time=NULL) {
+ if ($time === NULL)
+ $time = time();
+ return self::$gtfs->getRoute($route_id)->isRunning($time);
+ }
+
+ public static function get_title($route_id) {
+ return self::$gtfs->getRoute($route_id)->long_name;
+ }
+
+ public static function list_stop_times($route_id) {
+ $nextLoop = self::getNextLoop($route_id);
+ $time = time();
+ $prevTime = 0;
+ $stops = array();
+ $predicted = FALSE;
+ foreach ($nextLoop as $stop_id => $predictions) {
+ if ($stop_id == 'lastUpdate') {
+ $predicted = TRUE;
+ continue;
+ }
+
+ $lastIndex++;
+ $stop = self::getStop($stop_id);
+ $nextTime = $predictions[0];
+ if ($nextTime === NULL) $nextTime = 0;
+ $stopData = array(
+ 'id' => $stop_id,
+ 'title' => $stop->name,
+ 'lat' => $stop->lat,
+ 'lon' => $stop->lon,
+ 'next' => $nextTime,
+ );
+
+ if ($nextTime < $prevTime)
+ $stopData['upcoming'] = TRUE;
+ $prevTime = $nextTime;
+
+ if (count($predictions) > 1) {
+ $offsets = array();
+ foreach (array_slice($predictions, 1) as $aTime) {
+ $offsets[] = $aTime - $time;
+ }
+ $stopData['predictions'] = $offsets;
+ }
+
+ $stops[] = $stopData;
+ }
+
+ $lastIndex = count($stops) - 1;
+
+ if ($stops[0]['next'] < $stops[$lastIndex]['next']) {
+ $stops[0]['upcoming'] = TRUE;
+ }
+
+ $stops[] = array('gps' => $predicted);
+
+ return $stops;
+ }
+
+ public static function image_tag($size, $trip, $upcoming_stops) {
+ $tag = '';
+
+ $url = "http://maps.google.com/maps/api/staticmap?";
+
+ $center = '42.35904, -71.09355';
+ $zoom = 13;
+
+ $markers = "color:red";
+ foreach ($upcoming_stops as $stop) {
+ $stop = ShuttleSchedule::getStop($stop);
+ $markers .= '|' . $stop->lat . ',' . $stop->lon;
+ }
+
+ $params = array(
+ 'size' => $size . 'x' . $size,
+ 'markers' => $markers,
+ 'sensor' => 'false',
+ );
+
+ if (count($trip->shape->points) > 1) {
+ $path = 'weight:3|color:red|enc:';
+ $numPoints = count($trip->shape->points);
+ $totalCount = 0;
+ $usedCount = 0;
+ $prevLat = 0;
+ $prevLon = 0;
+ $latSum = 0;
+ $lonSum = 0;
+
+ foreach ($trip->shape->points as $point) {
+ $latSum += $point[0];
+ $lonSum += $point[1];
+
+ $lat = $point[0] - $prevLat;
+ $lon = $point[1] - $prevLon;
+
+ $prevLat = $point[0];
+ $prevLon = $point[1];
+ $path .= base64EncodeNumber($lat) . base64EncodeNumber($lon);
+ $usedCount++;
+ }
+
+ $center = strval($latSum / $usedCount) . ',' . strval($lonSum / $usedCount);
+ $params['path'] = $path;
+
+ } else {
+ $params['zoom'] = $zoom;
+ }
+
+ $params['center']= $center;
+
+ $query = $url . http_build_query($params);
+ $tag = '<img src="' . $query . '" width="' . $size
+ . '" height="' . $size . '" id="mapimage" alt="Map" />';
+ return $tag;
+ }
+
+ //
+
+ public static function getAllStops() {
+ $results = array();
+ $stops = self::$gtfs->getAllStops();
+ foreach ($stops as $stop) {
+ $results[] = array(
+ 'title' => $stop->name,
+ 'lon' => $stop->lon,
+ 'lat' => $stop->lat,
+ 'id' => $stop->id,
+ 'routes' => $stop->routes,
+ );
+ }
+ return $results;
+ }
+
+ public static function getVehicleLocations($route_id) {
+ $route = self::getRoute($route_id);
+ $agency = self::$agencies[$route->agency_id];
+ return $agency->vehicleLocations($route_id);
+ }
+
+ // functions for upcoming schedule
+ // use predictions if exist; schedule otherwise
+
+ public static function getNextLoop($route_id) {
+ $route = self::$gtfs->getRoute($route_id);
+ $agency = self::$agencies[$route->agency_id];
+ if ($agency) {
+ $agency->routeConfig($route_id);
+ }
+
+ $nextLoop = NULL;
+ if ($route->isRunning()) {
+ $nextLoop = self::getNextPredictedLoop($route_id);
+ }
+
+ if (!$nextLoop) {
+ $nextLoop = self::getNextScheduledLoop($route_id, time());
+ }
+ return $nextLoop;
+ }
+
+ public static function getNextPredictedLoop($route_id) {
+ $predictions = array();
+ $time = time();
+ $route = self::$gtfs->getRoute($route_id);
+ $agency = self::$agencies[$route->agency_id];
+ if ($agency) {
+ $predictions = $agency->predictionsForRoute($route_id);
+ }
+ return $predictions;
+ }
+
+ public static function getNextScheduledLoop($route_id, $time) {
+ if ($time === NULL)
+ $time = time();
+
+ $route = self::$gtfs->getRoute($route_id);
+ $result = array();
+ if ($route->lastUpdate) {
+ // if we've gone through routeConfig, trips are just
+ // different directions on the same route
+
+ $loop_start = NULL;
+ foreach ($route->trips as $trip) {
+ if (!$loop_start)
+ $loop_start = $trip->nextTripStart($time);
+
+ foreach ($trip->stop_times as $stop_id => $stop_time) {
+ list($arrive, $depart) = $stop_time;
+ $result[$stop_id] = array($arrive + $loop_start);
+ }
+ }
+
+ asort($result);
+
+ } else {
+ // otherwise we have trips that differ by day of week
+ // in the future we will change the schedule to
+ // conform more to nextbus
+ $earliest = PHP_INT_MAX;
+ $trip = NULL;
+
+ foreach ($route->trips as $atrip) {
+ $trip_start = $atrip->nextTripStart($time);
+ if ($trip_start < $earliest) {
+ $loop_start = $trip_start;
+ $trip = $atrip;
+ }
+ }
+
+ foreach ($trip->stop_times as $stop_id => $stop_time) {
+ list($arrive, $depart) = $stop_time;
+ $result[$stop_id] = array($arrive + $loop_start);
+ }
+ }
+
+ return $result;
+ }
+
+ public static function getTimesForStop($stop_id) {
+ $stop = self::getStop($stop_id);
+ $schedule = self::getScheduledTimesForStop($stop_id);
+ $predicted = self::getPredictedTimesForStop($stop_id);
+ $time = time();
+ $results = array();
+ foreach ($schedule as $route_id => $times) {
+ $data = array(
+ 'id' => $stop->id,
+ 'route_id' => $route_id,
+ 'lat' => $stop->lat,
+ 'lon' => $stop->lon,
+ 'next' => $times[0],
+ );
+
+ if (array_key_exists($route_id, $predicted)
+ && $predicted[$route_id])
+ {
+ $predictions = $predicted[$route_id];
+ $data['next'] = $predictions[0];
+ foreach (array_slice($predictions, 1) as $aTime) {
+ $data['predictions'][] = $aTime - $time;
+ }
+ $data['gps'] = TRUE;
+ } else {
+ $data['gps'] = FALSE;
+ }
+
+ $results[] = $data;
+ }
+ return $results;
+ }
+
+ public static function getPredictedTimesForStop($stop_id) {
+ $time = time();
+ $stop = self::getStop($stop_id);
+ $agencies = array(); // though unlikely that multiple agencies share stops
+ foreach ($stop->routes as $route_id) {
+ $route = self::getRoute($route_id);
+ if (array_key_exists($route->agency_id, self::$agencies)) {
+ $agency = self::$agencies[$route->agency_id];
+ $agencies[$route->agency_id] = $agency;
+ }
+ }
+ $result = array();
+ foreach ($agencies as $id => $agency) {
+ $predictions = $agency->predictionsForStop($stop_id);
+ foreach ($predictions as $route_id => $seconds) {
+ $result[$route_id] = $seconds;
+ }
+ }
+ return $result;
+ }
+
+ public static function getScheduledTimesForStop($stop_id) {
+ $stop = self::getStop($stop_id);
+ $time = time();
+ $result = array();
+ foreach ($stop->routes as $route_id) {
+ $route = self::getRoute($route_id);
+ if ($route->isInService($time)) {
+ foreach ($route->trips as $trip) {
+ //if ($trip->isRunningToday($time)) {
+ $start = $trip->nextTripStart($time);
+ if (array_key_exists($stop_id, $trip->stop_times)) {
+ list($arrive, $depart) = $trip->stop_times[$stop_id];
+ $result[$route_id][] = $start + $arrive;
+ }
+ //}
+ }
+ }
+ }
+ return $result;
+ }
+
+ // various getters
+
+ public static function getRouteList($agency_id=NULL) {
+ return self::$gtfs->getRouteList($agency_id);
+ }
+
+ public static function getActiveRoutes($agency_id=NULL, $time=NULL) {
+ return self::$gtfs->getActiveRoutes($agency_id, $time);
+ }
+
+ public static function getRunningRoutes($agency_id=NULL, $time=NULL) {
+ return self::$gtfs->getRunningRoutes($agency_id, $time);
+ }
+
+ public static function getRoute($route_id) {
+ $route = self::$gtfs->getRoute($route_id);
+ return $route;
+ }
+
+ public static function getStop($stop_id) {
+ return self::$gtfs->getStop($stop_id);
+ }
+
+ public static function setStop($stop_id, ShuttleStop $stop) {
+ self::$gtfs->setStop($stop_id, $stop);
+ }
+
+ public static function getAgency($agency_id) {
+ return self::$agencies[$agency_id];
+ }
+
+ public static function getService($service_id) {
+ return self::$gtfs->getService($service_id);
+ }
+
+ public static function numShuttlesOnTrip($trip_id, $time) {
+ $trip = self::getTrip($trip_id);
+ return $trip->numShuttlesRunning($time);
+ }
+
+ public static function numShuttlesOnRoute($route_id, $time) {
+ $route = self::getRoute($route_id);
+ $numshuttles = 0;
+ foreach ($route->trips as $trip) {
+ $numshuttles += $trip->numShuttlesRunning($time);
+ }
+ return $numshuttles;
+ }
+
+ public static function routesForStop($stop_id, $time) {
+ $result = array();
+ $midnight = day_of(time(), TIMEZONE);
+ foreach (self::$trips as $trip) {
+ $offset = NULL;
+
+ foreach ($trip->stop_times as $stop_time) {
+ if ($stop_time[0] == $stop_id) {
+ $offset = $stop_time[1];
+ break;
+ }
+ }
+
+ if ($offset !== NULL) {
+ $next_start = $trip->nextTripStart($time);
+ $next_stop_time = $next_start + $offset;
+ $route_id = $trip->route_id;
+ $route = self::$gtfs->getRoute($route_id);
+ $result[] = array(
+ $next_stop_time,
+ array(
+ $trip->id,
+ $route->short_name . ' - ' . $route->long_name,
+ $trip->getService()->id,
+ ),
+ TRUE,
+ );
+ }
+ }
+
+ return $result;
+ }
+
+ public static function getBboxStops($north, $east, $south, $west, $limit) {
+ $result = array();
+ foreach (self::$gtfs->getAllStops as $stop_id => $stop) {
+ if ($stop->lon >= $west && $stop->lon < $east
+ && $stop->lat >= $south && $stop->lat < $north) {
+ $result[] = array($stop_id, $stop->name, $stop->lat, $stop->lon, 0);
+ }
+ }
+ return $result;
+ }
+
+ public static function init() {
+ if (!self::$gtfs) {
+ self::$gtfs = new GTFSReader(SHUTTLE_GTFS_FEED, 'r');
+ self::$gtfs->parse();
+
+ self::$agencies = array(
+ 'mit' => new NextBusAgency('mit'),
+ 'charles-river' => new NextBusAgency('charles-river'),
+ 'saferide' => new NextBusAgency('mit', 'saferide'),
+ );
+
+ $saferide = array(
+ 'saferidebostone', 'saferidebostonw', 'saferidebostonall',
+ 'saferidecambeast', 'saferidecambwest', 'saferidecamball',
+ );
+
+ // the 'mit' agency should catch new routes from nextbus
+ self::$agencies['mit']->blackList($saferide);
+ self::$agencies['saferide']->whiteList($saferide);
+
+ $time = time();
+ foreach (self::$agencies as $agency_id => $nbAgency) {
+ $gtfsAgency = self::$gtfs->getAgency($agency_id);
+ foreach ($gtfsAgency->routes as $route_id => $route) {
+ if ($route->isInService($time)) {
+ $nbAgency->addRoute($route);
+ }
+ }
+ foreach ($nbAgency->getAllStops() as $stop_id => $stop) {
+ self::$gtfs->setStop($stop_id, $stop);
+ }
+ }
+
+ // start writing contents if we can sync up
+ // nextbus direction id's with trip id's
+ //self::$gtfs->write('routes.txt');
+ //self::$gtfs->write('trips.txt');
+ //self::$gtfs->write('stop_times.txt');
+ }
+ }
+
+
+
+}
+
+class GTFSReader {
+
+ // file handling
+ private $filename;
+ private $mode;
+
+ private $errors = array();
+
+ // shuttle object representation
+ private $agencies = array();
+ private $routes = array();
+ private $stops = array();
+ private $trips = array();
+ private $services = array();
+ private $shapes = array();
+
+ public function getRouteList($agency_id=NULL) {
+ $routes = array();
+
+ if ($agency_id !== NULL) {
+ $agency = $this->getAgency($agency_id);
+ return array_keys($agency->routes);
+ } else {
+ return array_keys($this->routes);
+ }
+ }
+
+ public function getRunningRoutes($agency_id=NULL, $time=NULL) {
+ return $this->filterRoutes($agency_id, $time, 'isRunning');
+ }
+
+ public function getActiveRoutes($agency_id=NULL, $time=NULL) {
+ return $this->filterRoutes($agency_id, $time, 'isInService');
+ }
+
+ private function filterRoutes($agency_id, $time, $userFunc) {
+ $routes = array();
+ if ($time === NULL) $time = time();
+
+ if ($agency_id !== NULL) {
+ $agency = $this->getAgency($agency_id);
+ $routeList = $agency->routes;
+ } else {
+ $routeList = $this->routes;
+ }
+
+ foreach ($routeList as $routeId => $route) {
+ if ($userFunc == 'isRunning') {
+ if ($route->isRunning($time)) {
+ $routes[] = $routeId;
+ }
+ } else if ($userFunc == 'isInService') {
+ if ($route->isInService($time)) {
+ $routes[] = $routeId;
+ }
+ }
+ }
+
+ return $routes;
+ }
+
+ public function getAllStops($agency_id=NULL) {
+ if ($agency_id === NULL) {
+ return $this->stops;
+ } else {
+ $agency = $this->getAgency($agency_id);
+ $stops = array();
+ foreach ($agency->routes as $route) {
+ foreach ($route->trips as $trip) {
+ foreach ($trip->stop_times as $stop_id => $time) {
+ $stops[$stop_id] = $this->getStop($stop_id);
+ }
+ }
+ }
+ return $stops;
+ }
+ }
+
+ // this function reads GTFS file and populates data in memory
+ public function __construct($filename) {
+ $this->filename = $filename;
+ }
+
+ // getter and setters
+
+ public function getAgency($id) {
+ if (array_key_exists($id, $this->agencies)) {
+ return $this->agencies[$id];
+ }
+ $this->error("agency_id $id not found");
+ return FALSE;
+ }
+
+ public function getRoute($id) {
+ if (array_key_exists($id, $this->routes)) {
+ return $this->routes[$id];
+ }
+ $this->error("route_id $id not found");
+ return FALSE;
+ }
+
+ public function getStop($id) {
+ if (array_key_exists($id, $this->stops)) {
+ return $this->stops[$id];
+ }
+ $this->error("stop_id $id not found");
+ return FALSE;
+ }
+
+ public function setStop($id, $stop) {
+ $this->stops[$id] = $stop;
+ }
+
+ public function getTrip($id) {
+ if (array_key_exists($id, $this->trips)) {
+ return $this->trips[$id];
+ }
+ $this->error("trip_id $id not found");
+ return FALSE;
+ }
+
+ public function getShape($id) {
+ if (array_key_exists($id, $this->shapes)) {
+ return $this->shapes[$id];
+ }
+ $this->error("shape_id $id not found");
+ return FALSE;
+ }
+
+ public function getService($id) {
+ if (array_key_exists($id, $this->services)) {
+ return $this->services[$id];
+ }
+ $this->error("service_id $id not found");
+ return FALSE;
+ }
+
+ private function error($msg) {
+ $this->errors[] = $msg;
+ }
+
+ // io
+
+ public function dumpErrors() {
+ var_dump($this->errors);
+ }
+
+ public function write($filename, $headers=NULL) {
+
+ $zip = new ZipArchive();
+
+ if ($zip->open($this->filename, ZIPARCHIVE::OVERWRITE) !== TRUE) {
+ $this->errMsg = "failed to open zip archive for writing";
+ }
+
+ switch ($filename) {
+ case 'agency.txt':
+ $headers = ShuttleAgency::headers($filename);
+ $iterator = $this->agencies;
+ break;
+ case 'routes.txt':
+ $headers = ShuttleRoute::headers($filename);
+ $iterator = $this->routes;
+ break;
+ case 'stops.txt':
+ $headers = ShuttleStop::headers($filename);
+ $iterator = $this->stops;
+ break;
+ case 'trips.txt': case 'stop_times.txt': case 'frequencies.txt':
+ $headers = ShuttleTrip::headers($filename);
+ $iterator = $this->trips;
+ break;
+ case 'calendar.txt': case 'calendar_dates.txt':
+ $headers = ShuttleService::headers($filename);
+ $iterator = $this->services;
+ break;
+ case 'shapes.txt':
+ $headers = ShuttleShape::headers($filename);
+ $iterator = $this->shapes;
+ break;
+ default:
+ break;
+ }
+
+ $csv = new CsvWrapper($filename, $zip, $headers, 'w');
+ foreach ($iterator as $id => $object) {
+ $rows = $object->csvdump($filename);
+ foreach ($rows as $row) {
+ $csv->add($row);
+ }
+ }
+ $csv->save();
+ }
+
+ public function parse() {
+ if ($this->mode == 'w') {
+ $this->errMsg = "file opened in writeonly mode";
+ return FALSE;
+ }
+
+ $zip = new ZipArchive();
+ if ($zip->open($this->filename) !== TRUE) {
+ $this->errMsg = "failed to open zip archive for reading";
+ return FALSE;
+ }
+
+ // create agency objects
+ $csv = new CsvWrapper('agency.txt', $zip);
+ while ($fields = $csv->next()) {
+ $agency_id = $fields['agency_id'];
+ $agency = new ShuttleAgency($fields);
+ $this->agencies[$agency_id] = $agency;
+ }
+
+ // create all route objects
+ $csv->reset_file('routes.txt');
+ while ($fields = $csv->next()) {
+ $route_id = $fields['route_id'];
+ $agency_id = $fields['agency_id'];
+ $route = new ShuttleRoute($fields);
+ if ($agency = $this->getAgency($agency_id)) {
+ $agency->addRoute($route);
+ }
+ $this->routes[$route_id] = $route;
+ }
+
+ // get attributes of physical stops
+ $csv->reset_file('stops.txt');
+ while ($fields = $csv->next()) {
+ $stop_id = $fields['stop_id'];
+ if (array_key_exists($stop_id, $this->stops)) {
+ $this->errMsg = "warning: stop_id $stop_id multiply defined";
+ }
+ $this->stops[$stop_id] = new ShuttleStop($fields);
+ }
+
+ // setup service calendar
+ $csv->reset_file('calendar.txt');
+ while ($fields = $csv->next()) {
+ $service_id = $fields['service_id'];
+ if (!array_key_exists($service_id, $this->services)) {
+ $this->services[$service_id] = new ShuttleService($service_id);
+ }
+ $this->services[$service_id]->addRange($fields);
+ }
+
+ $csv->reset_file('calendar_dates.txt');
+ while ($fields = $csv->next()) {
+ $service_id = $fields['service_id'];
+ if ($service = $this->getService($service_id)) {
+ $service->addException($fields);
+ }
+ }
+
+ // get shapes, if any
+ $csv->reset_file('shapes.txt');
+ while ($fields = $csv->next()) {
+ $shape_id = $fields['shape_id'];
+ if (!array_key_exists($shape_id, $this->shapes)) {
+ $this->shapes[$shape_id] = new ShuttleShape();
+ }
+ $this->shapes[$shape_id]->addPoint($fields);
+ }
+
+ // create all trip objects; associate route, shape, and service
+ $csv->reset_file('trips.txt');
+ while ($fields = $csv->next()) {
+ $trip_id = $fields['trip_id'];
+ $trip = new ShuttleTrip($fields);
+ $this->trips[$trip_id] = $trip;
+
+ $route_id = $fields['route_id'];
+ if ($route = $this->getRoute($route_id)) {
+ $route->addTrip($trip);
+ }
+
+ $service_id = $fields['service_id'];
+ if ($service = $this->getService($service_id)) {
+ $trip->setService($service);
+ }
+
+ $shape_id = $fields['shape_id'];
+ if ($shape = $this->getShape($shape_id)) {
+ $trip->shape = $shape;
+ }
+ }
+
+ // create stop list for each trips
+ $csv->reset_file('stop_times.txt');
+ while ($fields = $csv->next()) {
+ $trip_id = $fields['trip_id'];
+ $stop_id = $fields['stop_id'];
+ if ($trip = $this->getTrip($trip_id)) {
+ $trip->addStopTime($fields);
+ }
+ if ($stop = $this->getStop($stop_id)) {
+ $stop->addRouteId($trip->route_id);
+ }
+ }
+
+ // get interval and today's runs
+ $csv->reset_file('frequencies.txt');
+ while ($fields = $csv->next()) {
+ $trip_id = $fields['trip_id'];
+ if ($trip = $this->getTrip($trip_id)) {
+ $trip->addFrequency($fields);
+ }
+ }
+
+ $csv->close();
+ return TRUE;
+ }
+
+
+}
+
+class CsvWrapper {
+
+ private $fp;
+ private $zip;
+ private $headers;
+
+ private $tmpFile;
+ private $currenFile;
+
+ public function __construct($filename, ZipArchive $zip=NULL, $headers=TRUE, $mode='r') {
+ if ($zip !== NULL) {