Fix geolocation
Include Amazon email SES
--- a/aws/awsStartup.sh
+++ b/aws/awsStartup.sh
@@ -5,6 +5,7 @@
#http://www.how2forge.org/installing-lighttpd-with-php5-and-mysql-support-on-fedora-12
cp -rfv /tmp/busui/* /var/www
+cp /root/aws.php /tmp/
chcon -h system_u:object_r:httpd_sys_content_t /var/www
chcon -R -h root:object_r:httpd_sys_content_t /var/www/*
chcon -R -t httpd_sys_content_rw_t /var/www/staticmaplite/cache
--- a/aws/fastcgi.conf
+++ b/aws/fastcgi.conf
--- a/aws/modules.conf
+++ b/aws/modules.conf
--- a/aws/php.ini
+++ b/aws/php.ini
--- a/aws/rc.local
+++ b/aws/rc.local
--- a/common.inc.php
+++ b/common.inc.php
@@ -11,20 +11,29 @@
// you have to open the session to be able to modify or remove it
session_start();
- if (isset($_REQUEST['service_period'])) $_SESSION['service_period'] = filter_var($_REQUEST['service_period'],FILTER_SANITIZE_STRING);
- if (isset($_REQUEST['time'])) $_SESSION['time'] = filter_var($_REQUEST['time'],FILTER_SANITIZE_STRING);
+ if (isset($_REQUEST['service_period'])) {
+ $_SESSION['service_period'] = filter_var($_REQUEST['service_period'],FILTER_SANITIZE_STRING);
+ }
+ if (isset($_REQUEST['time'])) {
+ $_SESSION['time'] = filter_var($_REQUEST['time'],FILTER_SANITIZE_STRING);
+ }
if (isset($_REQUEST['geolocate'])) {
- $contents = geocode(var_filter($_REQUEST['geolocate'],FILTER_SANITIZE_URL),true);
+ if (isset($_REQUEST['lat']) && isset($_REQUEST['lon'])) {
+ $_SESSION['lat'] = $_REQUEST['lat'];
+ $_SESSION['lon'] = $_REQUEST['lon'];
+ } else {
+ $contents = geocode(filter_var($_REQUEST['geolocate'],FILTER_SANITIZE_URL),true);
if (isset($contents[0]->centroid)) {
- $session['lat'] = $contents[0]->centroid->coordinates[0];
- $session['lon'] = $contents[0]->centroid->coordinates[1];
+ $_SESSION['lat'] = $contents[0]->centroid->coordinates[0];
+ $_SESSION['lon'] = $contents[0]->centroid->coordinates[1];
}
else {
- $session['lat'] = "";
- $session['lon'] = "";
- }
+ $_SESSION['lat'] = "";
+ $_SESSION['lon'] = "";
+ }
+ }
}
-//print_r ($_SESSION);
+debug(print_r($_SESSION,true));
function isDebug()
{
return $_SERVER['SERVER_NAME'] == "10.0.1.154" || $_SERVER['SERVER_NAME'] == "localhost" || $_SERVER['SERVER_NAME'] == "127.0.0.1" || !$_SERVER['SERVER_NAME'];
@@ -32,14 +41,16 @@
function isMetricsOn()
{
- return true;
+ return false;
}
function debug($msg) {
- if (isDebug()) echo "<!-- $msg -->";
+ if (isDebug()) echo "\n<!-- $msg -->\n";
}
function isFastDevice() {
+ $ua = $_SERVER['HTTP_USER_AGENT'];
$fastDevices = Array("Mozilla/5.0 (X11;", "Mozilla/5.0 (Windows;", "Mozilla/5.0 (iP", "Mozilla/5.0 (Linux; U; Android", "Mozilla/4.0 (compatible; MSIE");
+
$slowDevices = Array("J2ME","MIDP","Opera/","Mozilla/2.0 (compatible;","Mozilla/3.0 (compatible;");
return true;
}
@@ -96,7 +107,7 @@
function success(position) {
$('#geolocate').val(position.coords.latitude+','+position.coords.longitude);
-// setCookie('geolocate',position.coords.latitude+','+position.coords.longitude,1);
+$.ajax({ url: \"common.inc.php?geolocate=yes&lat=\"+position.coords.latitude+\"&lon=\"+position.coords.longitude });
$('#here').click(function(event) { $('#geolocate').val(doAJAXrequestForGeolocSessionHere()); return false;});
$('#here').show();
}
@@ -199,7 +210,7 @@
curl_setopt( $ch, CURLOPT_HEADER, 0 );
curl_setopt($ch,CURLOPT_TIMEOUT,30);
$page = curl_exec($ch);
- if(curl_errno($ch)) echo "<font color=red> Database temporarily unavailable: ".curl_errno($ch)." ".curl_error($ch)."</font>";
+ if(curl_errno($ch)) echo "<font color=red> Database temporarily unavailable: ".curl_errno($ch)." ".curl_error($ch)."</font><br>";
curl_close($ch);
return $page;
}
@@ -368,7 +379,7 @@
function geocode($query, $giveOptions) {
global $cloudmadeAPIkey;
- $url = "http://geocoding.cloudmade.com/$cloudmadeAPIkey/geocoding/v2/find.js?query=".$query."&bbox=-35.5,149.00,-35.15,149.1930&return_location=true&bbox_only=true";
+ $url = "http://geocoding.cloudmade.com/$cloudmadeAPIkey/geocoding/v2/find.js?query=".urlencode($query)."&bbox=-35.5,149.00,-35.15,149.1930&return_location=true&bbox_only=true";
$contents = json_decode(getPage($url));
if ($giveOptions) return $contents->features;
elseif (isset($contents->features[0]->centroid)) return $contents->features[0]->centroid->coordinates[0].",".$contents->features[0]->centroid->coordinates[1];
@@ -445,11 +456,11 @@
<div class="ui-body">
<div data-role="fieldcontain">
<label for="geolocate"> Current Location: </label>
- <input type="text" id="geolocate" name="geolocate" value="Enter co-ordinates or address here"/> <a href="#" style="display:none" name="here" id="here"/>Here?</a>
+ <input type="text" id="geolocate" name="geolocate" value="'. (isset($_SESSION['lat']) && isset($_SESSION['lon']) ? $_SESSION['lat'] .",". $_SESSION['lon'] :"Enter co-ordinates or address here"). '"/> <a href="#" style="display:none" name="here" id="here"/>Here?</a>
</div>
<div data-role="fieldcontain">
<label for="time"> Time: </label>
- <input type="time" name="time" id="time" value="'. ($_SESSION['time'] ? $_SESSION['time'] : date("H:m")).'"/> <a href="#" name="currentTime" id="currentTime"/>Current Time?</a>
+ <input type="time" name="time" id="time" value="'. (isset($_SESSION['time']) ? $_SESSION['time'] : date("H:m")).'"/> <a href="#" name="currentTime" id="currentTime"/>Current Time?</a>
</div>
<div data-role="fieldcontain">
<label for="service_period"> Service Period: </label>
Binary files a/css/images/ajax-loader.png and b/css/images/ajax-loader.png differ
Binary files a/css/images/form-check-off.png and b/css/images/form-check-off.png differ
Binary files a/css/images/form-check-on.png and b/css/images/form-check-on.png differ
Binary files a/css/images/form-radio-off.png and b/css/images/form-radio-off.png differ
Binary files a/css/images/form-radio-on.png and b/css/images/form-radio-on.png differ
Binary files a/css/images/icon-search-black.png and b/css/images/icon-search-black.png differ
Binary files a/css/images/icons-18-black.png and b/css/images/icons-18-black.png differ
Binary files a/css/images/icons-18-white.png and b/css/images/icons-18-white.png differ
Binary files a/css/images/icons-36-black.png and b/css/images/icons-36-black.png differ
Binary files a/css/images/icons-36-white.png and b/css/images/icons-36-white.png differ
--- a/css/jquery-mobile-1.0a3.css
+++ b/css/jquery-mobile-1.0a3.css
--- a/css/jquery.ui.datepicker.mobile.css
+++ b/css/jquery.ui.datepicker.mobile.css
--- a/feedback.php
+++ b/feedback.php
@@ -1,6 +1,32 @@
<?php
include('common.inc.php');
-include_header("Feedback","feedback")
+include_header("Feedback","feedback");
+function sendEmail($topic, $message) {
+ $address = "maxious@lambdacomplex.org";
+
+ if (file_exists("/tmp/aws.php") ) {
+ include_once('ses.php');
+ include_once("/tmp/aws.php");
+$con=new SimpleEmailService($accessKey,$secretKey);
+//$con->verifyEmailAddress($address);
+//$con->listVerifiedEmailAddresses();
+
+$m = new SimpleEmailServiceMessage();
+$m->addTo($address);
+$m->setFrom($address);
+$m->setSubject($topic);
+$m->setMessageFromString($message);
+$con->sendEmail($m);
+} else {
+// In case any of our lines are larger than 70 characters, we should use wordwrap()
+$message = wordwrap($message, 70);
+
+// Send
+mail($address, $topic, $message);
+}
+}
+
+
?>
<h3>Add/Move/Delete a Bus Stop Location</h3>
StopID:
@@ -8,7 +34,11 @@
Suggested Stop Location (lat/long or words):
+Submit!
+
<h3>Bug Report/Feedback</h3>
+<textarea id="feedback">
+</textarea>
<textarea id="extrainfo">
Referrer URL
User Agent
@@ -16,3 +46,5 @@
Current date/time
Dump of $_SESSION
</textarea>
+
+Submit!
--- a/js/jQuery.ui.datepicker.js
+++ b/js/jQuery.ui.datepicker.js
--- a/js/jquery-1.5.js
+++ b/js/jquery-1.5.js
--- a/js/jquery-mobile-1.0a3.js
+++ b/js/jquery-mobile-1.0a3.js
--- a/js/jquery.effects.core.js
+++ b/js/jquery.effects.core.js
--- a/js/jquery.ui.autocomplete.js
+++ b/js/jquery.ui.autocomplete.js
--- a/js/jquery.ui.datepicker.mobile.js
+++ b/js/jquery.ui.datepicker.mobile.js
--- a/js/jquery.ui.position.js
+++ b/js/jquery.ui.position.js
--- a/js/jquery.ui.widget.js
+++ b/js/jquery.ui.widget.js
--- a/layar_api.php
+++ b/layar_api.php
@@ -26,7 +26,7 @@
$hotspot['distance'] = distance($row[2], $row[3], $_REQUEST['lat'], $_REQUEST['lon']);
if (!isset($_REQUEST['radius']) || $hotspot['distance'] < $_REQUEST['radius']) {
$hotspot['actions'] = Array(Array("label" => 'View more trips/information', 'uri' => 'http://bus.lambdacomplex.org/'.'stop.php?stopid='.$row[0]));
- $url = $APIurl."/json/stoptrips?stop=".$row[0]."&time=".midnight_seconds()."&service_period=".service_period();
+ $url = $APIurl."/json/stoptrips?stop=".$row[0]."&time=".midnight_seconds()."&service_period=".service_period()."&limit=4";
$trips = json_decode(getPage($url));
debug(print_r($trips,true));
foreach ($trips as $key => $row)
--- a/schedule_viewer.py
+++ b/schedule_viewer.py
@@ -32,6 +32,7 @@
import simplejson
import socket
import time
+import datetime
import transitfeed
from transitfeed import util
import urllib
@@ -95,6 +96,8 @@
float(stop.stop_lon), stop.location_type, stop.stop_code, stop.zone_id)
class ScheduleRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
+ cache = {}
+
def do_GET(self):
scheme, host, path, x, params, fragment = urlparse.urlparse(self.path)
parsed_params = {}
@@ -114,7 +117,7 @@
handler_name = 'handle_json_GET_%s' % m.group(1)
handler = getattr(self, handler_name, None)
if callable(handler):
- return self.handle_json_wrapper_GET(handler, parsed_params)
+ return self.handle_json_wrapper_GET(handler, parsed_params, handler_name)
# Restrict allowable file names to prevent relative path attacks etc
m = re.match(r'/file/([a-z0-9_-]{1,64}\.?[a-z0-9_-]{1,64})$', path)
@@ -243,11 +246,22 @@
patterns.sort()
return patterns
- def handle_json_wrapper_GET(self, handler, parsed_params):
+ def handle_json_wrapper_GET(self, handler, parsed_params, handler_name):
"""Call handler and output the return value in JSON."""
schedule = self.server.schedule
- result = handler(parsed_params)
- content = ResultEncoder().encode(result)
+ # round times to nearest 100 seconds
+ if "time" in parsed_params:
+ parsed_params['time'] = int(round(float(parsed_params['time']),-2))
+ paramkey = tuple(sorted(parsed_params.items()))
+ if handler_name in self.cache and paramkey in self.cache[handler_name] :
+ print ("Cache hit for ",handler_name," params ",parsed_params)
+ else:
+ print ("Cache miss for ",handler_name," params ",parsed_params)
+ result = handler(parsed_params)
+ if not handler_name in self.cache:
+ self.cache[handler_name] = {}
+ self.cache[handler_name][paramkey] = ResultEncoder().encode(result)
+ content = self.cache[handler_name][paramkey]
self.send_response(200)
self.send_header('Content-Type', 'text/plain')
self.send_header('Content-Length', str(len(content)))
@@ -414,6 +428,7 @@
schedule = self.server.schedule
stop = schedule.GetStop(params.get('stop', None))
time = int(params.get('time', 0))
+ limit = int(params.get('limit', 15))
service_period = params.get('service_period', None)
time_trips = stop.GetStopTimeTrips(schedule)
time_trips.sort() # OPT: use bisect.insort to make this O(N*ln(N)) -> O(N)
@@ -423,6 +438,8 @@
time_trips = time_trips[:15]
result = []
for time, (trip, index), tp in time_trips:
+ if len(result) > limit:
+ break
headsign = None
# Find the most recent headsign from the StopTime objects
for stoptime in trip.GetStopTimes()[index::-1]:
@@ -566,12 +583,13 @@
if options.key and os.path.isfile(options.key):
options.key = open(options.key).read().strip()
-
+
schedule = transitfeed.Schedule(problem_reporter=transitfeed.ProblemReporter())
print 'Loading data from feed "%s"...' % options.feed_filename
print '(this may take a few minutes for larger cities)'
+ t0 = datetime.datetime.now()
schedule.Load(options.feed_filename)
-
+ print ("Loaded in", (datetime.datetime.now() - t0).seconds , "seconds")
server = StoppableHTTPServer(server_address=('', options.port),
RequestHandlerClass=RequestHandlerClass)
server.key = options.key
@@ -579,6 +597,8 @@
server.file_dir = options.file_dir
server.host = options.host
server.feed_path = options.feed_filename
+
+
print ("To view, point your browser at http://localhost:%d/" %
(server.server_port))
--- /dev/null
+++ b/ses.php
@@ -1,1 +1,704 @@
-
+<?php
+/**
+*
+* Copyright (c) 2011, Dan Myers.
+* Parts copyright (c) 2008, Donovan Schonknecht.
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are met:
+*
+* - Redistributions of source code must retain the above copyright notice,
+* this list of conditions and the following disclaimer.
+* - Redistributions in binary form must reproduce the above copyright
+* notice, this list of conditions and the following disclaimer in the
+* documentation and/or other materials provided with the distribution.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+* POSSIBILITY OF SUCH DAMAGE.
+*
+* This is a modified BSD license (the third clause has been removed).
+* The BSD license may be found here:
+* http://www.opensource.org/licenses/bsd-license.php
+*
+* Amazon Simple Email Service is a trademark of Amazon.com, Inc. or its affiliates.
+*
+* SimpleEmailService is based on Donovan Schonknecht's Amazon S3 PHP class, found here:
+* http://undesigned.org.za/2007/10/22/amazon-s3-php-class
+*
+*/
+
+/**
+* Amazon SimpleEmailService PHP class
+*
+* @link http://sourceforge.net/projects/php-aws-ses/
+* version 0.8.1
+*
+*/
+class SimpleEmailService
+{
+ protected $__accessKey; // AWS Access key
+ protected $__secretKey; // AWS Secret key
+ protected $__host;
+
+ public function getAccessKey() { return $this->__accessKey; }
+ public function getSecretKey() { return $this->__secretKey; }
+ public function getHost() { return $this->__host; }
+
+ protected $__verifyHost = 1;
+ protected $__verifyPeer = 1;
+
+ // verifyHost and verifyPeer determine whether curl verifies ssl certificates.
+ // It may be necessary to disable these checks on certain systems.
+ // These only have an effect if SSL is enabled.
+ public function verifyHost() { return $this->__verifyHost; }
+ public function enableVerifyHost($enable = true) { $this->__verifyHost = $enable; }
+
+ public function verifyPeer() { return $this->__verifyPeer; }
+ public function enableVerifyPeer($enable = true) { $this->__verifyPeer = $enable; }
+
+ /**
+ * Constructor
+ *
+ * @param string $accessKey Access key
+ * @param string $secretKey Secret key
+ * @return void
+ */
+ public function __construct($accessKey = null, $secretKey = null, $host = 'email.us-east-1.amazonaws.com') {
+ if ($accessKey !== null && $secretKey !== null) {
+ $this->setAuth($accessKey, $secretKey);
+ }
+ $this->__host = $host;
+ }
+
+ /**
+ * Set AWS access key and secret key
+ *
+ * @param string $accessKey Access key
+ * @param string $secretKey Secret key
+ * @return void
+ */
+ public function setAuth($accessKey, $secretKey) {
+ $this->__accessKey = $accessKey;
+ $this->__secretKey = $secretKey;
+ }
+
+ /**
+ * Lists the email addresses that have been verified and can be used as the 'From' address
+ *
+ * @return An array containing two items: a list of verified email addresses, and the request id.
+ */
+ public function listVerifiedEmailAddresses() {
+ $rest = new SimpleEmailServiceRequest($this, 'GET');
+ $rest->setParameter('Action', 'ListVerifiedEmailAddresses');
+
+ $rest = $rest->getResponse();
+ if($rest->error === false && $rest->code !== 200) {
+ $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
+ }
+ if($rest->error !== false) {
+ $this->__triggerError('listVerifiedEmailAddresses', $rest->error);
+ return false;
+ }
+
+ $response = array();
+ if(!isset($rest->body)) {
+ return $response;
+ }
+
+ $addresses = array();
+ foreach($rest->body->ListVerifiedEmailAddressesResult->VerifiedEmailAddresses->member as $address) {
+ $addresses[] = (string)$address;
+ }
+
+ $response['Addresses'] = $addresses;
+ $response['RequestId'] = (string)$rest->body->ResponseMetadata->RequestId;
+
+ return $response;
+ }
+
+ /**
+ * Requests verification of the provided email address, so it can be used
+ * as the 'From' address when sending emails through SimpleEmailService.
+ *
+ * After submitting this request, you should receive a verification email
+ * from Amazon at the specified address containing instructions to follow.
+ *
+ * @param string email The email address to get verified
+ * @return The request id for this request.
+ */
+ public function verifyEmailAddress($email) {
+ $rest = new SimpleEmailServiceRequest($this, 'POST');
+ $rest->setParameter('Action', 'VerifyEmailAddress');
+ $rest->setParameter('EmailAddress', $email);
+
+ $rest = $rest->getResponse();
+ if($rest->error === false && $rest->code !== 200) {
+ $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
+ }
+ if($rest->error !== false) {
+ $this->__triggerError('verifyEmailAddress', $rest->error);
+ return false;
+ }
+
+ $response['RequestId'] = (string)$rest->body->ResponseMetadata->RequestId;
+ return $response;
+ }
+
+ /**
+ * Removes the specified email address from the list of verified addresses.
+ *
+ * @param string email The email address to remove
+ * @return The request id for this request.
+ */
+ public function deleteVerifiedEmailAddress($email) {
+ $rest = new SimpleEmailServiceRequest($this, 'DELETE');
+ $rest->setParameter('Action', 'DeleteVerifiedEmailAddress');
+ $rest->setParameter('EmailAddress', $email);
+
+ $rest = $rest->getResponse();
+ if($rest->error === false && $rest->code !== 200) {
+ $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
+ }
+ if($rest->error !== false) {
+ $this->__triggerError('deleteVerifiedEmailAddress', $rest->error);
+ return false;
+ }
+
+ $response['RequestId'] = (string)$rest->body->ResponseMetadata->RequestId;
+ return $response;
+ }
+
+ /**
+ * Retrieves information on the current activity limits for this account.
+ * See http://docs.amazonwebservices.com/ses/latest/APIReference/API_GetSendQuota.html
+ *
+ * @return An array containing information on this account's activity limits.
+ */
+ public function getSendQuota() {
+ $rest = new SimpleEmailServiceRequest($this, 'GET');
+ $rest->setParameter('Action', 'GetSendQuota');
+
+ $rest = $rest->getResponse();
+ if($rest->error === false && $rest->code !== 200) {
+ $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
+ }
+ if($rest->error !== false) {
+ $this->__triggerError('getSendQuota', $rest->error);
+ return false;
+ }
+
+ $response = array();
+ if(!isset($rest->body)) {
+ return $response;
+ }
+
+ $response['Max24HourSend'] = (string)$rest->body->GetSendQuotaResult->Max24HourSend;
+ $response['MaxSendRate'] = (string)$rest->body->GetSendQuotaResult->MaxSendRate;
+ $response['SentLast24Hours'] = (string)$rest->body->GetSendQuotaResult->SentLast24Hours;
+ $response['RequestId'] = (string)$rest->body->ResponseMetadata->RequestId;
+
+ return $response;
+ }
+
+ /**
+ * Retrieves statistics for the last two weeks of activity on this account.
+ * See http://docs.amazonwebservices.com/ses/latest/APIReference/API_GetSendStatistics.html
+ *
+ * @return An array of activity statistics. Each array item covers a 15-minute period.
+ */
+ public function getSendStatistics() {
+ $rest = new SimpleEmailServiceRequest($this, 'GET');
+ $rest->setParameter('Action', 'GetSendStatistics');
+
+ $rest = $rest->getResponse();
+ if($rest->error === false && $rest->code !== 200) {
+ $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
+ }
+ if($rest->error !== false) {
+ $this->__triggerError('getSendStatistics', $rest->error);
+ return false;
+ }
+
+ $response = array();
+ if(!isset($rest->body)) {
+ return $response;
+ }
+
+ $datapoints = array();
+ foreach($rest->body->GetSendStatisticsResult->SendDataPoints->member as $datapoint) {
+ $p = array();
+ $p['Bounces'] = (string)$datapoint->Bounces;
+ $p['Complaints'] = (string)$datapoint->Complaints;
+ $p['DeliveryAttempts'] = (string)$datapoint->DeliveryAttempts;
+ $p['Rejects'] = (string)$datapoint->Rejects;
+ $p['Timestamp'] = (string)$datapoint->Timestamp;
+
+ $datapoints[] = $p;
+ }
+
+ $response['SendDataPoints'] = $datapoints;
+ $response['RequestId'] = (string)$rest->body->ResponseMetadata->RequestId;
+
+ ret