├── .gitignore ├── SCREENSHOT.png ├── static ├── img │ └── map-loading.gif ├── fonts │ ├── glyphicons-halflings-regular.eot │ ├── glyphicons-halflings-regular.ttf │ ├── glyphicons-halflings-regular.woff │ └── glyphicons-halflings-regular.woff2 ├── js │ ├── spin-2.3.1.min.js │ ├── jquery.validate-1.13.1.min.js │ ├── moment-2.10.3.min.js │ ├── bootstrap-datetimepicker-4.14.30.min.js │ ├── bootstrap-3.3.4.min.js │ └── main.js └── css │ ├── main.css │ └── bootstrap-datetimepicker-4.14.30.min.css ├── setup.py ├── flaskapp.cfg ├── methodology.txt ├── .travis.yml ├── LICENSE ├── README.md ├── app.py ├── flaskapp.py ├── templates └── index.html └── gtfsviewer.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | -------------------------------------------------------------------------------- /SCREENSHOT.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jonkostyniuk/gtfs-viewer/HEAD/SCREENSHOT.png -------------------------------------------------------------------------------- /static/img/map-loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jonkostyniuk/gtfs-viewer/HEAD/static/img/map-loading.gif -------------------------------------------------------------------------------- /static/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jonkostyniuk/gtfs-viewer/HEAD/static/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /static/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jonkostyniuk/gtfs-viewer/HEAD/static/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /static/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jonkostyniuk/gtfs-viewer/HEAD/static/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /static/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jonkostyniuk/gtfs-viewer/HEAD/static/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | 3 | setup(name='GTFS Viewer', 4 | version='0.1a', 5 | description='A GTFS viewer to display transit route data in a web browser.', 6 | author='Jon Kostyniuk', 7 | author_email='jon.kostyniuk@gmail.com', 8 | url='http://gtfsviewer-jonkostyniuk.rhcloud.com/', 9 | install_requires=['Flask>=0.10.1','numpy>=1.9.2','pandas>=0.16.1'], 10 | ) 11 | -------------------------------------------------------------------------------- /flaskapp.cfg: -------------------------------------------------------------------------------- 1 | import os 2 | DEBUG = True 3 | PROPAGATE_EXCEPTIONS = True 4 | SECRET_KEY = os.environ.get('SECRET_KEY','\xfb\x13\xdf\xa1@i\xd6>V\xc0\xbf\x8fp\x16#Z\x0b\x81\xeb\x16') 5 | HOST_NAME = os.environ.get('OPENSHIFT_APP_DNS','localhost') 6 | APP_NAME = os.environ.get('OPENSHIFT_APP_NAME','flask') 7 | IP = os.environ.get('OPENSHIFT_PYTHON_IP','127.0.0.1') 8 | PORT = int(os.environ.get('OPENSHIFT_PYTHON_PORT',8080)) 9 | -------------------------------------------------------------------------------- /methodology.txt: -------------------------------------------------------------------------------- 1 | X convert times to seconds 2 | X determine routeid from routes data 3 | X lookup date from calendar data, need to add exception for calendar dates later 4 | X get serviceid from calendar data 5 | X in trips data, use service id and route id to get plural trip ids 6 | X in stop times data find trip id with 'stop sequence 1' that is greater than or equal to desired time, get trip id 7 | - using specified trip id in trip data, get shape id -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | python: 3 | - "2.6" 4 | - "2.7" 5 | - "3.3" 6 | install: 7 | # install dependencies from setup.py 8 | - pip install . 9 | # install dependencies from requirements.txt 10 | # - pip install -r requirements.txt 11 | # run nose tests 12 | script: nosetests 13 | # more information on configuring openshift deployments 14 | # http://docs.travis-ci.com/user/deployment/openshift/ 15 | deploy: 16 | provider: openshift 17 | # Configure these values on your TravisCI 'Repository Settings' page: 18 | # http://docs.travis-ci.com/user/environment-variables/#Using-Settings 19 | user: $OPENSHIFT_USERNAME 20 | password: $OPENSHIFT_PASSWORD 21 | app: $OPENSHIFT_APP_NAME 22 | domain: $OPENSHIFT_APP_NAMESPACE 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Jon Kostyniuk 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GTFS Transit Route Viewer # 2 | *This application is a viewer to display general transit feed specification (GTFS) data in a web browser. Its intent is to act as an auditing tool for GTFS data or to be modified for implementation with a transit agency trip planning system.* 3 | 4 | [![GTFS Viewer Screenshot](https://github.com/jonkostyniuk/gtfs-viewer/blob/master/SCREENSHOT.png?raw=true)](https://github.com/jonkostyniuk/gtfs-viewer/blob/master/SCREENSHOT.png?raw=true) 5 | 6 | ## Versions ## 7 | V0.1a, Build XX, Released 2015-08-XX (COMING SOON) 8 | 9 | ## Implementation ## 10 | Start a local web server by running the following from the command line: 11 | 12 | python app.py 13 | 14 | Load the following web page to interact with the program: 15 | 16 | http://localhost:8080/ 17 | 18 | ## Testing ## 19 | This software is currently considered in ALPHA status, meaning that testing is still ongoing and all functionality has yet to be implemented. **Use at your own risk.** 20 | 21 | The current version has primarily been released as proof-of-concept and is not ready for production purposes at this time. 22 | 23 | Development and testing to date has primarily been in the *Google Chrome* browser. Unexpected functionality may occur with other browsers at this time. 24 | 25 | Open-source GTFS transit data was used in the testing of this application from the following transit agencies: 26 | * [Calgary Transit](http://www.calgarytransit.com) 27 | * [Halifax Transit](http://www.halifax.ca/transit/) 28 | * [Kingston Transit](http://www.kingstontransit.ca) 29 | * [Saskatoon Transit](https://transit.saskatoon.ca/) 30 | * [Winnipeg Transit](http://www.winnipegtransit.com) 31 | * [York Region Transit](http://www.yrt.ca) 32 | 33 | ## Dependencies ## 34 | The GTFS Viewer is built upon several third-party, open-source dependency packages to provide functionality. 35 | 36 | ### Python ### 37 | * Flask >=0.10.1 38 | * pandas >=0.16.1 39 | * requests >=2.2.1 40 | 41 | ### HTML/CSS/JavaScript ### 42 | * JQuery >=1.11.2 43 | * Bootstrap >=3.3.4 44 | * Moment >=2.10.3 45 | * Bootstrap-DateTimePicker >=4.14.30 46 | * Spin >=2.3.1 47 | * Google Maps API >=3.21 48 | 49 | ## Current Features ## 50 | The GTFS Viewer presently features the following functionality: 51 | * Select GTFS files from preloaded, unzipped dropdown. Folder structure uses './[UUID]/[Timestamp]/' structure to contain unzipped GTFS files. 52 | * Select from routes loaded on-the-fly from GTFS files. 53 | * Specify date/time of trip desired. 54 | * API based on agency, route, and date/time request will fetch route polylines and dynamically display on map using Google Maps API. 55 | * Zoom in to see stop level detail and stop locations. 56 | 57 | ## Future Development ## 58 | Ongoing development of this repository may include the following potential features: 59 | * Pull GTFS data directly from www.gtfs-data-exchange.com 60 | * Upload functionality for zipped GTFS files. 61 | * Inter-relation with other stops and routes. 62 | 63 | ## Project Inspiration ## 64 | Why did I create this project? Honestly, similar applications have been created for transit agencies, so this really is nothing new. 65 | 66 | This project was created so that I could further develop my skills in the following areas: 67 | * Using the Flask Python framework for API backend development. 68 | * Working with the GTFS protocol for transit planning and routing. 69 | * Gain more experience using the Pandas Python package for data analysis. 70 | 71 | ## Contact ## 72 | For questions or information about this repository, please contact: 73 | 74 | jon.kostyniuk@gmail.com 75 | 76 | ## License ## 77 | This code is released under the MIT License 78 | 79 | https://github.com/jonkostyniuk/gtfs-viewer/blob/master/LICENSE 80 | 81 | Copyright (c) 2015 Jon Kostyniuk 82 | -------------------------------------------------------------------------------- /static/js/spin-2.3.1.min.js: -------------------------------------------------------------------------------- 1 | // http://spin.js.org/#v2.3.1 2 | !function(a,b){"object"==typeof exports?module.exports=b():"function"==typeof define&&define.amd?define(b):a.Spinner=b()}(this,function(){"use strict";function a(a,b){var c,d=document.createElement(a||"div");for(c in b)d[c]=b[c];return d}function b(a){for(var b=1,c=arguments.length;c>b;b++)a.appendChild(arguments[b]);return a}function c(a,b,c,d){var e=["opacity",b,~~(100*a),c,d].join("-"),f=.01+c/d*100,g=Math.max(1-(1-a)/b*(100-f),a),h=j.substring(0,j.indexOf("Animation")).toLowerCase(),i=h&&"-"+h+"-"||"";return m[e]||(k.insertRule("@"+i+"keyframes "+e+"{0%{opacity:"+g+"}"+f+"%{opacity:"+a+"}"+(f+.01)+"%{opacity:1}"+(f+b)%100+"%{opacity:"+a+"}100%{opacity:"+g+"}}",k.cssRules.length),m[e]=1),e}function d(a,b){var c,d,e=a.style;if(b=b.charAt(0).toUpperCase()+b.slice(1),void 0!==e[b])return b;for(d=0;d',c)}k.addRule(".spin-vml","behavior:url(#default#VML)"),h.prototype.lines=function(a,d){function f(){return e(c("group",{coordsize:k+" "+k,coordorigin:-j+" "+-j}),{width:k,height:k})}function h(a,h,i){b(m,b(e(f(),{rotation:360/d.lines*a+"deg",left:~~h}),b(e(c("roundrect",{arcsize:d.corners}),{width:j,height:d.scale*d.width,left:d.scale*d.radius,top:-d.scale*d.width>>1,filter:i}),c("fill",{color:g(d.color,a),opacity:d.opacity}),c("stroke",{opacity:0}))))}var i,j=d.scale*(d.length+d.width),k=2*d.scale*j,l=-(d.width+d.length)*d.scale*2+"px",m=e(f(),{position:"absolute",top:l,left:l});if(d.shadow)for(i=1;i<=d.lines;i++)h(i,-2,"progid:DXImageTransform.Microsoft.Blur(pixelradius=2,makeshadow=1,shadowopacity=.3)");for(i=1;i<=d.lines;i++)h(i);return b(a,m)},h.prototype.opacity=function(a,b,c,d){var e=a.firstChild;d=d.shadow&&d.lines||0,e&&b+d>1)+"px"})}for(var i,k=0,l=(f.lines-1)*(1-f.direction)/2;k or empty div as the final element following the last floated div (within the #container) if the #footer is removed or taken out of the #container */ 168 | clear:both; 169 | height:0; 170 | font-size: 1px; 171 | line-height: 0px; 172 | } 173 | 174 | /* GOOGLE MAP WINDOW STYLING */ 175 | .gmapinfo { 176 | color: #000000; 177 | } 178 | .gmaploading { 179 | display: block; 180 | margin-left: auto; 181 | margin-right: auto; 182 | } -------------------------------------------------------------------------------- /app.py: -------------------------------------------------------------------------------- 1 | # ########################################################################################################## 2 | # FLASK APPLICATION 3 | # Created by Jon Kostyniuk on 07JUN2015 4 | # Last modified by Jon Kostyniuk on 07JUN2015 5 | # Property of JK Enterprises 6 | # v0.01a 7 | # ########################################################################################################## 8 | # 9 | # Version History: 10 | # ---------------- 11 | # 07JUN2015 v0.01a - JK 12 | # - Initial Version. 13 | # 14 | # Usage: 15 | # ------ 16 | # This file originates from the source found on 'https://github.com/openshift-quickstart/flask-base' 17 | # repository for use on the OpenShift platform. It has been adapted for use with Python Flask as a generic 18 | # start file with OpenShift. The 'flaskapp.py' file referenced below is modified for application-specific 19 | # functionality. 20 | # 21 | # This file may be used instead of Apache mod_wsgi to run your python web application in a different 22 | # framework. A few examples are provided (cherrypi, gevent), but this file may be altered to run whatever 23 | # framework is desired - or a completely customized service. 24 | # 25 | # Instructions: 26 | # ------------- 27 | # From the command line, run 'python app.py' within this directory for development purposes. For live use, 28 | # load and run from the OpenShift platform. 29 | # 30 | 31 | # ########################################################################################################## 32 | # MODULES AND DEFINITIONS 33 | # ########################################################################################################## 34 | 35 | #!/usr/bin/env python 36 | 37 | import imp 38 | import os 39 | import sys 40 | 41 | 42 | # ########################################################################################################## 43 | # MAIN PROGRAM 44 | # ########################################################################################################## 45 | 46 | # Environment Initialization 47 | try: 48 | virtenv = os.path.join(os.environ.get('OPENSHIFT_PYTHON_DIR','.'), 'virtenv') 49 | python_version = "python" + str(sys.version_info[0]) + "." + str(sys.version_info[1]) 50 | os.environ['PYTHON_EGG_CACHE'] = os.path.join(virtenv, 'lib', python_version, 'site-packages') 51 | virtualenv = os.path.join(virtenv, 'bin','activate_this.py') 52 | if(sys.version_info[0] < 3): 53 | execfile(virtualenv, dict(__file__=virtualenv)) 54 | else: 55 | exec(open(virtualenv).read(), dict(__file__=virtualenv)) 56 | except IOError: 57 | pass 58 | 59 | # 60 | # IMPORTANT: Put any additional includes below this line. If placed above this 61 | # line, it's possible required libraries won't be in your searchable path 62 | # 63 | 64 | # Main Program 65 | if __name__ == '__main__': 66 | # Connection Information 67 | application = imp.load_source('app', 'flaskapp.py') 68 | port = application.app.config['PORT'] 69 | ip = application.app.config['IP'] 70 | app_name = application.app.config['APP_NAME'] 71 | host_name = application.app.config['HOST_NAME'] 72 | 73 | # Determine Server Type 74 | fwtype = "wsgiref" 75 | for fw in ("gevent", "cherrypy", "flask"): 76 | try: 77 | imp.find_module(fw) 78 | fwtype = fw 79 | except ImportError: 80 | pass 81 | 82 | # Start WSGI Server and Run Forever 83 | print 'Starting WSGIServer type %s on %s:%d ... ' % (fwtype, ip, port) 84 | if fwtype == "gevent": 85 | from gevent.pywsgi import WSGIServer 86 | WSGIServer((ip, port), application.app).serve_forever() 87 | elif fwtype == "cherrypy": 88 | from cherrypy import wsgiserver 89 | server = wsgiserver.CherryPyWSGIServer( 90 | (ip, port), application.app, server_name=host_name) 91 | server.start() 92 | elif fwtype == "flask": 93 | from flask import Flask 94 | server = Flask(__name__) 95 | server.wsgi_app = application.app 96 | server.run(host=ip, port=port) 97 | else: 98 | from wsgiref.simple_server import make_server 99 | make_server(ip, port, application.app).serve_forever() 100 | 101 | 102 | # ########################################################################################################## 103 | # END OF SCRIPT 104 | # ########################################################################################################## -------------------------------------------------------------------------------- /flaskapp.py: -------------------------------------------------------------------------------- 1 | # ########################################################################################################## 2 | # GTFS FLASK API APPLICATION 3 | # Created by Jon Kostyniuk on 07JUN2015 4 | # Last modified by Jon Kostyniuk on 07JUN2015 5 | # Property of JK Enterprises 6 | # v0.01a 7 | # ########################################################################################################## 8 | # 9 | # Version History: 10 | # ---------------- 11 | # 07JUN2015 v0.01a - JK 12 | # - Initial Version. 13 | # 14 | # Usage: 15 | # ------ 16 | # This script is used to direct website traffic and calls from reference URLs to required resource files. 17 | # 18 | # Instructions: 19 | # ------------- 20 | # None. This script is referenced by 'app.py' when the application is initialized. 21 | # 22 | 23 | # ########################################################################################################## 24 | # MODULES AND DEFINITIONS 25 | # ########################################################################################################## 26 | 27 | # STANDARD MODULES 28 | # ---------------- 29 | import flask as fl 30 | #import os #USED?? 31 | #from datetime import datetime #USED?? 32 | #from flask import Flask, request, flash, url_for, redirect, render_template, abort, send_from_directory 33 | 34 | # CUSTOM MODULES 35 | # -------------- 36 | 37 | import gtfsviewer as gv 38 | 39 | # GLOBAL CONSTANT VARIABLES 40 | # ------------------------- 41 | 42 | # Initialize 43 | # n/a 44 | 45 | # Define 46 | # n/a 47 | 48 | # DEFINITIONS 49 | # ----------- 50 | 51 | # Flask Initialize Variables 52 | app = fl.Flask(__name__) # Define Application Object 53 | app.config.from_pyfile("flaskapp.cfg") # Configure Application Object 54 | 55 | # Reference Path Variables 56 | #appPath = '/gtfs-viewer/api/v0.1/' # Define Application Path 57 | 58 | 59 | # ########################################################################################################## 60 | # DEFINED CLASSES AND FUNCTIONS 61 | # ########################################################################################################## 62 | 63 | # API CALL FUNCTIONS 64 | # ------------------ 65 | 66 | # Function to Get GTFS Exchange Feed 67 | @app.route("/api/agencies", methods=["POST"]) 68 | def apiAgencies(): 69 | return gv.getAgencies(fl.request.json["uuid"]) 70 | #return gv.getAgencies(fl.request.args.get("uuid")) ## WORKS FOR 'GET' 71 | 72 | # Function to Get Trip Map 73 | @app.route("/api/createmap", methods=["POST"]) 74 | def apiCreateMap(): 75 | return gv.createTripMap(fl.request.json["uuid"], fl.request.json["agency_id"], fl.request.json["route_id"], fl.request.json["datetime"]) 76 | 77 | # Function to Get GTFS Exchange Feed 78 | @app.route("/api/gtfs", methods=["GET"]) 79 | def apiGTFS(): 80 | return gv.getGTFS() 81 | 82 | # Function to Get Agency Route Data 83 | @app.route("/api/routes", methods=["POST"]) 84 | def apiRoutes(): 85 | return gv.getRoutes(fl.request.json["uuid"], fl.request.json["agency_id"]) 86 | #return gv.getAgencies(fl.request.args.get("uuid")) ## WORKS FOR 'GET' 87 | 88 | # Function to Get Bus Stop Points 89 | @app.route("/api/stops", methods=["POST"]) 90 | def apiGetStopPoints(): 91 | return gv.getStopPoints(fl.request.json["uuid"], fl.request.json["agency_id"], fl.request.json["bounds"]) 92 | 93 | # Function to Create Unique User ID 94 | @app.route("/api/uuid", methods=["GET"]) 95 | def apiCreateUUID(): 96 | return gv.createUUID() 97 | 98 | # URL REFERENCE FUNCTIONS 99 | # ----------------------- 100 | 101 | # Function to Route Index Page 102 | @app.route("/") 103 | def index(): 104 | return fl.render_template("index.html") 105 | 106 | # Function to Route Static Resources 107 | @app.route("/") 108 | def serveStaticResource(resource): 109 | return fl.send_from_directory("static/", resource) 110 | 111 | 112 | # ########################################################################################################## 113 | # MAIN PROGRAM 114 | # ########################################################################################################## 115 | 116 | # Run Application 117 | if __name__ == "__main__": 118 | app.run() 119 | 120 | 121 | # ########################################################################################################## 122 | # END OF SCRIPT 123 | # ########################################################################################################## -------------------------------------------------------------------------------- /static/css/bootstrap-datetimepicker-4.14.30.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Datetimepicker for Bootstrap 3 3 | * version : 4.14.30 4 | * https://github.com/Eonasdan/bootstrap-datetimepicker/ 5 | */.bootstrap-datetimepicker-widget{list-style:none}.bootstrap-datetimepicker-widget.dropdown-menu{margin:2px 0;padding:4px;width:19em}@media (min-width:768px){.bootstrap-datetimepicker-widget.dropdown-menu.timepicker-sbs{width:38em}}@media (min-width:992px){.bootstrap-datetimepicker-widget.dropdown-menu.timepicker-sbs{width:38em}}@media (min-width:1200px){.bootstrap-datetimepicker-widget.dropdown-menu.timepicker-sbs{width:38em}}.bootstrap-datetimepicker-widget.dropdown-menu:before,.bootstrap-datetimepicker-widget.dropdown-menu:after{content:'';display:inline-block;position:absolute}.bootstrap-datetimepicker-widget.dropdown-menu.bottom:before{border-left:7px solid transparent;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-bottom-color:rgba(0,0,0,0.2);top:-7px;left:7px}.bootstrap-datetimepicker-widget.dropdown-menu.bottom:after{border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid white;top:-6px;left:8px}.bootstrap-datetimepicker-widget.dropdown-menu.top:before{border-left:7px solid transparent;border-right:7px solid transparent;border-top:7px solid #ccc;border-top-color:rgba(0,0,0,0.2);bottom:-7px;left:6px}.bootstrap-datetimepicker-widget.dropdown-menu.top:after{border-left:6px solid transparent;border-right:6px solid transparent;border-top:6px solid white;bottom:-6px;left:7px}.bootstrap-datetimepicker-widget.dropdown-menu.pull-right:before{left:auto;right:6px}.bootstrap-datetimepicker-widget.dropdown-menu.pull-right:after{left:auto;right:7px}.bootstrap-datetimepicker-widget .list-unstyled{margin:0}.bootstrap-datetimepicker-widget a[data-action]{padding:6px 0}.bootstrap-datetimepicker-widget a[data-action]:active{box-shadow:none}.bootstrap-datetimepicker-widget .timepicker-hour,.bootstrap-datetimepicker-widget .timepicker-minute,.bootstrap-datetimepicker-widget .timepicker-second{width:54px;font-weight:bold;font-size:1.2em;margin:0}.bootstrap-datetimepicker-widget button[data-action]{padding:6px}.bootstrap-datetimepicker-widget .btn[data-action="incrementHours"]::after{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);border:0;content:"Increment Hours"}.bootstrap-datetimepicker-widget .btn[data-action="incrementMinutes"]::after{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);border:0;content:"Increment Minutes"}.bootstrap-datetimepicker-widget .btn[data-action="decrementHours"]::after{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);border:0;content:"Decrement Hours"}.bootstrap-datetimepicker-widget .btn[data-action="decrementMinutes"]::after{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);border:0;content:"Decrement Minutes"}.bootstrap-datetimepicker-widget .btn[data-action="showHours"]::after{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);border:0;content:"Show Hours"}.bootstrap-datetimepicker-widget .btn[data-action="showMinutes"]::after{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);border:0;content:"Show Minutes"}.bootstrap-datetimepicker-widget .btn[data-action="togglePeriod"]::after{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);border:0;content:"Toggle AM/PM"}.bootstrap-datetimepicker-widget .btn[data-action="clear"]::after{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);border:0;content:"Clear the picker"}.bootstrap-datetimepicker-widget .btn[data-action="today"]::after{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);border:0;content:"Set the date to today"}.bootstrap-datetimepicker-widget .picker-switch{text-align:center}.bootstrap-datetimepicker-widget .picker-switch::after{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);border:0;content:"Toggle Date and Time Screens"}.bootstrap-datetimepicker-widget .picker-switch td{padding:0;margin:0;height:auto;width:auto;line-height:inherit}.bootstrap-datetimepicker-widget .picker-switch td span{line-height:2.5;height:2.5em;width:100%}.bootstrap-datetimepicker-widget table{width:100%;margin:0}.bootstrap-datetimepicker-widget table td,.bootstrap-datetimepicker-widget table th{text-align:center;border-radius:4px}.bootstrap-datetimepicker-widget table th{height:20px;line-height:20px;width:20px}.bootstrap-datetimepicker-widget table th.picker-switch{width:145px}.bootstrap-datetimepicker-widget table th.disabled,.bootstrap-datetimepicker-widget table th.disabled:hover{background:none;color:#777;cursor:not-allowed}.bootstrap-datetimepicker-widget table th.prev::after{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);border:0;content:"Previous Month"}.bootstrap-datetimepicker-widget table th.next::after{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);border:0;content:"Next Month"}.bootstrap-datetimepicker-widget table thead tr:first-child th{cursor:pointer}.bootstrap-datetimepicker-widget table thead tr:first-child th:hover{background:#eee}.bootstrap-datetimepicker-widget table td{height:54px;line-height:54px;width:54px}.bootstrap-datetimepicker-widget table td.cw{font-size:.8em;height:20px;line-height:20px;color:#777}.bootstrap-datetimepicker-widget table td.day{height:20px;line-height:20px;width:20px}.bootstrap-datetimepicker-widget table td.day:hover,.bootstrap-datetimepicker-widget table td.hour:hover,.bootstrap-datetimepicker-widget table td.minute:hover,.bootstrap-datetimepicker-widget table td.second:hover{background:#eee;cursor:pointer}.bootstrap-datetimepicker-widget table td.old,.bootstrap-datetimepicker-widget table td.new{color:#777}.bootstrap-datetimepicker-widget table td.today{position:relative}.bootstrap-datetimepicker-widget table td.today:before{content:'';display:inline-block;border:0 0 7px 7px solid transparent;border-bottom-color:#337ab7;border-top-color:rgba(0,0,0,0.2);position:absolute;bottom:4px;right:4px}.bootstrap-datetimepicker-widget table td.active,.bootstrap-datetimepicker-widget table td.active:hover{background-color:#337ab7;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25)}.bootstrap-datetimepicker-widget table td.active.today:before{border-bottom-color:#fff}.bootstrap-datetimepicker-widget table td.disabled,.bootstrap-datetimepicker-widget table td.disabled:hover{background:none;color:#777;cursor:not-allowed}.bootstrap-datetimepicker-widget table td span{display:inline-block;width:54px;height:54px;line-height:54px;margin:2px 1.5px;cursor:pointer;border-radius:4px}.bootstrap-datetimepicker-widget table td span:hover{background:#eee}.bootstrap-datetimepicker-widget table td span.active{background-color:#337ab7;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25)}.bootstrap-datetimepicker-widget table td span.old{color:#777}.bootstrap-datetimepicker-widget table td span.disabled,.bootstrap-datetimepicker-widget table td span.disabled:hover{background:none;color:#777;cursor:not-allowed}.bootstrap-datetimepicker-widget.usetwentyfour td.hour{height:27px;line-height:27px}.bootstrap-datetimepicker-widget.wider{width:21em}.bootstrap-datetimepicker-widget .datepicker-decades .decade{line-height:1.8em !important}.input-group.date .input-group-addon{cursor:pointer}.sr-only{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);border:0} -------------------------------------------------------------------------------- /templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | GTFS Transit Route Viewer 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 26 |
27 | 61 |
62 | 63 | 65 |
66 |
67 |

Agency Information:

68 |

--

69 |

Calendar Information:

70 |

--

71 |

Route Information:

72 |

--

73 |
74 |
75 |
76 | 79 | 80 | 81 | 82 | 112 | 113 | 114 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 165 | 166 | -------------------------------------------------------------------------------- /gtfsviewer.py: -------------------------------------------------------------------------------- 1 | # ########################################################################################################## 2 | # GTFS DATA EXTRACTOR 3 | # Created by Jon Kostyniuk on 25AUG2015 4 | # Last modified by Jon Kostyniuk on 25AUG2015 5 | # Property of JK Enterprises 6 | # v0.1a 7 | # ########################################################################################################## 8 | # 9 | # Version History: 10 | # ---------------- 11 | # 25AUG2015 v0.1a - JK 12 | # - Initial Version 13 | # 14 | # Usage: 15 | # ------ 16 | # Called by 'flaskapp.py' to handle API requests. 17 | # 18 | # Instructions: 19 | # ------------- 20 | # None - Called Automatically 21 | # 22 | 23 | # ########################################################################################################## 24 | # MODULES AND DEFINITIONS 25 | # ########################################################################################################## 26 | 27 | #!/usr/bin/python 28 | 29 | # STANDARD MODULES 30 | # ---------------- 31 | 32 | #import csv 33 | import datetime as dt 34 | import json 35 | import os 36 | import pandas as pd 37 | import StringIO 38 | import requests 39 | import uuid 40 | import zipfile 41 | 42 | # CUSTOM MODULES 43 | # -------------- 44 | 45 | # n/a 46 | 47 | # GLOBAL CONSTANT VARIABLES 48 | # ------------------------- 49 | 50 | # Initialize 51 | global DATA_FOLDER # GTFS Server Side Data Folder 52 | 53 | # Define 54 | DATA_FOLDER = "./data/" 55 | 56 | # DEFINITIONS 57 | # ----------- 58 | 59 | # GTFS Feed Variables 60 | gtfsFeeds = [ # GTFS Feed Sources, URLs, and API Keys 61 | { 62 | "name": "TransitFeeds", 63 | "url": "http://api.transitfeeds.com/v1/", 64 | "api-key": "0d8f7e0c-2f6d-4180-b824-242a44658b03" 65 | } 66 | ] 67 | 68 | 69 | # SQLite Database Variables 70 | #dbConn = None 71 | 72 | testdata = { 73 | "success": "true", 74 | "uuid": "4f7698c38c734c249ecf9aa5a3c6e0ca", 75 | "data": [ 76 | { 77 | "timestamp": 1434328453, 78 | "agency_name": "York Region Transit" 79 | } 80 | ] 81 | } 82 | 83 | # General Transit Feed Specification (GTFS) Variables 84 | #gtfsSource = "http://gtfs.winnipegtransit.com/google_transit.zip" # GTFS Source File 85 | gtfsSource = "google_transit.zip" # GTFS Source File 86 | 87 | # External API Links 88 | GTFS_API = "http://www.gtfs-data-exchange.com/api/agencies" # GTFS Exchange API Data 89 | 90 | 91 | # ########################################################################################################## 92 | # DEFINED CLASSES AND FUNCTIONS 93 | # ########################################################################################################## 94 | 95 | # MODULE CLASSES 96 | # -------------- 97 | 98 | # n/a 99 | 100 | # MODULE FUNCTIONS 101 | # ---------------- 102 | 103 | # Function to Create Trip Map 104 | def createTripMap(uuid, AgencyID, RouteID, datetime): 105 | # Define UUID and Preset Agency Folder Path 106 | datapath = DATA_FOLDER + str(uuid) + "/" + str(AgencyID) + "/" 107 | jsondata = {} 108 | jsondata["uuid"] = str(uuid) 109 | jsondata["agency_id"] = int(AgencyID) 110 | jsondata["agency_name"] = readAgencyName(datapath) 111 | jsondata["route_id"] = RouteID 112 | 113 | # Split Date and Time Data 114 | trDate = datetime.split(", ")[0] 115 | trTime = datetime.split(", ")[1] + ":00" 116 | 117 | # Get Valid Service ID List for Date/Time 118 | try: 119 | lServiceID = getServiceID(datapath, trDate) 120 | jsondata["service_id"] = lServiceID # Audit Trail 121 | #print lServiceID 122 | success = True 123 | except: 124 | jsondata["service_id"] = [] # Audit Trail 125 | print "ERROR: Service ID failed to resolve!!" 126 | success = False 127 | 128 | # Get Valid Trip ID List from Route and Service IDs 129 | try: 130 | lTripID = getTripID(datapath, RouteID, lServiceID) 131 | jsondata["trip_id"] = lTripID # Audit Trail 132 | #print lTripID 133 | success = True 134 | except: 135 | jsondata["trip_id"] = [] # Audit Trail 136 | print "ERROR: Initial Trip ID failed to resolve!!" 137 | success = False 138 | 139 | # Get Trip ID Sequence Based on Arrival Time of First Stop, Return Sequence 140 | try: 141 | lStopSeq = getStopSeq(datapath, lTripID, trTime) 142 | jsondata["trip_id"] = lStopSeq[0]["trip_id"] # Audit Trail 143 | jsondata["stop_sequence"] = lStopSeq 144 | #print lStopSeq[0]["trip_id"] 145 | #print lStopSeq 146 | success = True 147 | except: 148 | jsondata["trip_id"] = -1 # Audit Trail 149 | jsondata["stop_sequence"] = [] 150 | print "ERROR: Final Trip ID and Stop Sequence failed to resolve!!" 151 | success = False 152 | 153 | # Get Shape ID from Trip ID 154 | try: 155 | [ShpID, ServID] = getShapeID(datapath, jsondata["trip_id"]) 156 | jsondata["shape_id"] = ShpID # Audit Trail 157 | jsondata["service_id"] = ServID # Get Final Service ID 158 | #print ShpID 159 | #print ServID 160 | success = True 161 | except: 162 | jsondata["shape_id"] = -1 # Audit Trail 163 | jsondata["service_id"] = -1 164 | print "ERROR: Polyline Shape ID and Service ID failed to resolve!!" 165 | success = False 166 | 167 | # Get Route Polyline Sequence 168 | try: 169 | lShpSeq = getRtPolySeq(datapath, jsondata["shape_id"]) 170 | jsondata["shape_sequence"] = lShpSeq 171 | #print lShpSeq 172 | success = True 173 | except: 174 | jsondata["shape_sequence"] = [] # Audit Trail 175 | print "ERROR: Shape Sequence failed to resolve!!" 176 | success = False 177 | 178 | # Output Final Parsed Date and Time 179 | jsondata["datetime"] = trDate + ", " + trTime 180 | 181 | # Confirm whether calculations succeeded, as tried above 182 | if success: 183 | jsondata["success"] = "true" 184 | else: 185 | jsondata["success"] = "false" 186 | 187 | return json.dumps(jsondata) 188 | 189 | # Function to Create Unique User ID 190 | def createUUID(): 191 | return str(uuid.uuid4().hex) 192 | 193 | # Function to Get Preloaded Agencies 194 | def getAgencies(uuid): 195 | # Define UUID Folder Path Variables 196 | uuidpath = DATA_FOLDER + str(uuid) 197 | jsondata = {} 198 | jsondata["uuid"] = str(uuid) 199 | jsondata["data"] = [] 200 | # Check if server-side UUID directory exists 201 | dataCount = 0 202 | if os.path.isdir(uuidpath): 203 | # Get preset folders for UUID 204 | listPreset = os.listdir(uuidpath) 205 | # Populate preset data list 206 | for listitem in listPreset: 207 | try: # Enables only timestamp directories to be fetched, others skipped 208 | itemdata = {} 209 | itemdata["timestamp"] = int(listitem) 210 | itemdata["agency_name"] = readAgencyName(uuidpath + "/" + listitem + "/") 211 | jsondata["data"].append(itemdata) 212 | dataCount += 1 213 | except: 214 | pass 215 | # Create directory for UUID 216 | else: 217 | os.makedirs(uuidpath) 218 | # Indicate JSON Data Success 219 | jsondata["data_count"] = dataCount 220 | jsondata["success"] = "true" 221 | 222 | return json.dumps(jsondata) 223 | 224 | # Function to Get GTFS Exchange API Data 225 | def getGTFS(): 226 | return requests.get(GTFS_API).text 227 | 228 | # Function to Get Routes List 229 | def getRoutes(uuid, AgencyID): 230 | # Define UUID and Preset Agency Folder Path 231 | datapath = DATA_FOLDER + str(uuid) + "/" + str(AgencyID) + "/" 232 | jsondata = {} 233 | jsondata["uuid"] = str(uuid) 234 | jsondata["agency_id"] = int(AgencyID) 235 | # Get Full Agency Information to Display 236 | jsondata["agency_info"] = readAgency(datapath) 237 | # Get Start and End Calendar Dates 238 | jsondata["calendar_dates"] = readCalendarExt(datapath) 239 | # Get Required Route Fields to Display 240 | jsondata["data"] = readRoutes(datapath) 241 | # Indicate JSON Data Success 242 | jsondata["data_count"] = len(jsondata["data"]) 243 | jsondata["success"] = "true" 244 | 245 | return json.dumps(jsondata) 246 | 247 | # Function to Get Bus Stop Points 248 | def getStopPoints(uuid, AgencyID, bounds): 249 | # Define UUID and Preset Agency Folder Path 250 | datapath = DATA_FOLDER + str(uuid) + "/" + str(AgencyID) + "/" 251 | jsondata = {} 252 | jsondata["uuid"] = str(uuid) 253 | jsondata["agency_id"] = int(AgencyID) 254 | jsondata["bounds"] = bounds 255 | 256 | # Lookup Stops within given bounds 257 | pdStops = pd.read_csv(datapath + "stops.txt", encoding="utf-8-sig") 258 | pdStops = pdStops[["stop_id", "stop_name", "stop_lat", "stop_lon"]] # Limit to required fields, per GTFS Documentation 259 | pdStops = pdStops[(pdStops.stop_lat >= bounds["loLat"]) & (pdStops.stop_lat <= bounds["upLat"]) & (pdStops.stop_lon >= bounds["ltLng"]) & (pdStops.stop_lon <= bounds["rtLng"])] 260 | pdStops = pdStops.reset_index(drop=True) 261 | 262 | # Transform Data Object into List 263 | dStops = pdStops.transpose().to_dict() # Transform to transposed dictionary object 264 | # Transfrom from dictionary to list object 265 | lStops = [] 266 | for seqk, seqv in dStops.iteritems(): 267 | lStops.append(seqv) # Save sequence value, not key 268 | jsondata["stops"] = lStops 269 | 270 | return json.dumps(jsondata) 271 | 272 | 273 | # HELPER (MONKEY) FUNCTIONS 274 | # ------------------------- 275 | 276 | # Function to Convert Date Format 277 | def convDateFormat(longdate): 278 | return int(dt.datetime.strptime(longdate, "%a %b %d %Y").strftime("%Y%m%d")) 279 | 280 | # Function to Convert Day of Week to Long 281 | def convLongDoW(longdate): 282 | return dt.datetime.strptime(longdate, "%a %b %d %Y").strftime("%A").lower() 283 | 284 | # Function to Convert Time to Seconds 285 | def convTimeSecs(hhmmss): 286 | # Split Hours/Minutes/Seconds 287 | hhmmss = hhmmss.strip().split(":") 288 | # Set and Cumulate Time Seconds 289 | timesecs = 0 290 | # Add Hour Seconds 291 | timesecs += int(hhmmss[0]) * 60 * 60 292 | # Add Minute Seconds 293 | timesecs += int(hhmmss[1]) * 60 294 | # Add Remaining Seconds 295 | timesecs += int(hhmmss[2]) 296 | 297 | return timesecs 298 | 299 | # Function to Get Route Polyline Sequence 300 | def getRtPolySeq(filepath, shpid): 301 | pdShapes = pd.read_csv(filepath + "shapes.txt", encoding="utf-8-sig") 302 | pdShpSeq = pdShapes[(pdShapes["shape_id"].astype(str) == str(shpid))].reset_index(drop=True) 303 | pdShpSeq = pdShpSeq.sort_index(by=["shape_pt_sequence"]) 304 | pdShpSeq = pdShpSeq[["shape_pt_lat", "shape_pt_lon", "shape_pt_sequence"]] 305 | #print pdShpSeq.info() 306 | dShpSeq = pdShpSeq.transpose().to_dict() # Transform to transposed dictionary object 307 | # Transfrom from dictionary to list object 308 | lShpSeq = [] 309 | for seqk, seqv in dShpSeq.iteritems(): 310 | lShpSeq.append(seqv) # Save sequence value, not key 311 | 312 | return lShpSeq 313 | 314 | # Function to Get Shape ID 315 | def getShapeID(filepath, tripid): 316 | pdTrips = pd.read_csv(filepath + "trips.txt", encoding="utf-8-sig") 317 | tripsel = pdTrips[(pdTrips["trip_id"] == tripid)].reset_index(drop=True) 318 | if len(tripsel) == 1: 319 | shpid = tripsel["shape_id"][0] 320 | servid = tripsel["service_id"][0] 321 | return [shpid, servid] 322 | else: 323 | return [-1, -1] 324 | 325 | # Function to Get Service IDs 326 | def getServiceID(filepath, trdate): 327 | # Convert Format of Variables 328 | dow = convLongDoW(trdate) # Convert to Long Day of Week 329 | numdate = convDateFormat(trdate) # Convert to Numeric Date Value 330 | # Lookup Calendar Day of Week and Get Service ID 331 | pdCalendar = pd.read_csv(filepath + "calendar.txt", encoding="utf-8-sig") 332 | calsel = pdCalendar[(pdCalendar[dow] == 1) & (pdCalendar["start_date"] <= numdate) & (pdCalendar["end_date"] >= numdate)].transpose().to_dict() 333 | # Lookup Calendar Dates Exceptions for Current Date 334 | pdCalDates = pd.read_csv(filepath + "calendar_dates.txt", encoding="utf-8-sig") 335 | excsel = pdCalDates[(pdCalDates["date"] == numdate)].transpose().to_dict() 336 | # Create Valid Service ID List for Application 337 | lServiceID = [] # List to Hold Valid Service IDs 338 | for i in calsel.keys(): 339 | lServiceID.append(calsel[i]["service_id"]) # Append Current Service ID Value 340 | # Add/Remove Exception Service IDs 341 | for i in excsel.keys(): 342 | if excsel[i]["exception_type"] == 1: # Add Exception Service ID 343 | lServiceID.append(excsel[i]["service_id"]) # Append Current Service ID Value 344 | elif excsel[i]["exception_type"] == 2: # Remove Exception Service ID 345 | for j in range(len(lServiceID)): 346 | if excsel[i]["service_id"] == lServiceID[j]: 347 | lServiceID[j] = -1 # Set Exception Removal Flag 348 | # Drop Removal Flags 349 | lServiceID = filter(lambda a: a != -1, lServiceID) 350 | 351 | return lServiceID 352 | 353 | # Function to Get Stop Sequence 354 | def getStopSeq(filepath, trid, trtime): 355 | # Lookup Trip ID and Stop Times Sequence 356 | pdStopTimes = pd.read_csv(filepath + "stop_times.txt", encoding="utf-8-sig") 357 | # Lookup Valid Stop Sequence and Convert Arrival Time to Seconds 358 | selstseq = pdStopTimes[(pdStopTimes["trip_id"].isin(trid)) & (pdStopTimes["stop_sequence"] == 1)] 359 | dfTimeCol = selstseq["arrival_time"] # Temp Variable to Hold Time Data 360 | dfTimeCol = dfTimeCol.str.strip() # Strip Whitespace 361 | dfTimeCol = dfTimeCol.str.split(":") # Split Time Values between ':' 362 | selstseq.loc[:, "arrival_time"] = (dfTimeCol.str[0].astype("int") * 3600) + (dfTimeCol.str[1].astype("int") * 60) + dfTimeCol.str[2].astype("int") # Convert to Seconds 363 | selstseq = selstseq[(selstseq["arrival_time"] >= convTimeSecs(trtime))] 364 | try: # Attempt to find stop times for route at requested interval 365 | selstseq = selstseq.loc[selstseq["arrival_time"].idxmin(),:] 366 | pdStopSeq = pdStopTimes[(pdStopTimes["trip_id"] == selstseq["trip_id"])] 367 | pdStopSeq = pdStopSeq[["trip_id", "arrival_time", "departure_time", "stop_id", "stop_sequence"]] 368 | pdStopSeq = pdStopSeq.reset_index(drop=True) 369 | #print pdStopSeq.info() 370 | # Transform Data Object into List 371 | dStopSeq = pdStopSeq.transpose().to_dict() # Transform to transposed dictionary object 372 | # Transfrom from dictionary to list object 373 | lStopSeq = [] 374 | for seqk, seqv in dStopSeq.iteritems(): 375 | lStopSeq.append(seqv) # Save sequence value, not key 376 | return lStopSeq 377 | 378 | except: # Return empty data 379 | return [] 380 | 381 | # Function to Get Trip IDs 382 | def getTripID(filepath, rtid, srvid): 383 | # Lookup Calendar Day of Week and Get Service ID 384 | pdTrips = pd.read_csv(filepath + "trips.txt", encoding="utf-8-sig") 385 | pdTrips["route_id"] = pdTrips["route_id"].astype(str) # Ensure Route ID Always String Type 386 | # Lookup Valid Trip IDs 387 | tripsel = pdTrips[(pdTrips["service_id"].isin(srvid)) & (pdTrips["route_id"] == rtid)] 388 | lTripID = tripsel["trip_id"].tolist() 389 | 390 | return lTripID 391 | 392 | # Function to Read Agency Info 393 | def readAgency(filepath): 394 | pdAgency = pd.read_csv(filepath + "agency.txt", encoding="utf-8-sig") 395 | pdAgency = pdAgency.fillna("") 396 | 397 | return {"name": pdAgency["agency_name"][0], "url": pdAgency["agency_url"][0], "timezone": pdAgency["agency_timezone"][0],} 398 | 399 | # Function to Read Agency Name 400 | def readAgencyName(filepath): 401 | pdAgency = pd.read_csv(filepath + "agency.txt", encoding="utf-8-sig") 402 | 403 | return pdAgency["agency_name"][0] 404 | 405 | # Function to Read Calendar Extent Dates 406 | def readCalendarExt(filepath): 407 | # Read Regular Calendar Data 408 | pdCalendar = pd.read_csv(filepath + "calendar.txt", encoding="utf-8-sig") 409 | sDate = pdCalendar.min()["start_date"] 410 | eDate = pdCalendar.max()["end_date"] 411 | 412 | return {"start": sDate, "end": eDate} 413 | 414 | # Function to Read Routes File 415 | def readRoutes(filepath): 416 | # Prepare Route Data 417 | pdRoutes = pd.read_csv(filepath + "routes.txt", encoding="utf-8-sig") 418 | pdRoutes = pdRoutes.fillna("") 419 | pdRoutes = pdRoutes.sort(columns=["route_short_name"]) 420 | #pdRoutes = pdRoutes.sort_index(by = "route_short_name") 421 | numRt = len(pdRoutes) 422 | pdRoutes = pdRoutes.to_dict() 423 | # Load Route Data 424 | listRoutes = [] 425 | for i in range(numRt): 426 | itemdata = {} 427 | itemdata["route_id"] = str(pdRoutes["route_id"][i]) 428 | itemdata["route_short_name"] = pdRoutes["route_short_name"][i] 429 | if pdRoutes["route_long_name"][i] != "": 430 | itemdata["route_long_name"] = pdRoutes["route_long_name"][i] 431 | else: 432 | itemdata["route_long_name"] = "[ UNNAMED ROUTE ]" 433 | itemdata["route_type"] = pdRoutes["route_type"][i] 434 | listRoutes.append(itemdata) 435 | 436 | return listRoutes 437 | 438 | # Function to Extract GTFS ZIP to Temporary Folder [UNFINISHED] 439 | def unzipGTFS(fileloc): 440 | # Open ZIP Archive Location 441 | zf = zipfile.ZipFile(gtfsSource) 442 | 443 | # Loop through ZIP File Names 444 | #for filename in zf.namelist(): 445 | 446 | 447 | # ########################################################################################################## 448 | # END OF SCRIPT 449 | # ########################################################################################################## 450 | 451 | 452 | 453 | 454 | 455 | """ 456 | def main(): 457 | # Open ZIP Archive Location 458 | zf = zipfile.ZipFile(gtfsSource) 459 | 460 | # Loop through ZIP File Names 461 | for filename in zf.namelist(): 462 | # Find Transit Route Shape File 463 | if filename == "shapes.txt": 464 | # Read Data Model into Pandas 465 | shapes = pd.read_csv(zf.open(filename)) 466 | 467 | 468 | 469 | # Test Outputs 470 | #print shapes.head() 471 | #print shapes[["shape_pt_sequence","shape_pt_lat","shape_pt_lon"]] 472 | 473 | # Grab by ID and sort by PT Sequence 474 | curShape = shapes[shapes['shape_id'] == 36099].sort_index(by = 'shape_pt_sequence')[["shape_pt_lat","shape_pt_lon"]] 475 | """ 476 | 477 | """ 478 | try: 479 | data = zf.read(filename) 480 | except KeyError: 481 | print "ERROR: Did not find %s in zip file" % filename 482 | else: 483 | #print filename 484 | """ 485 | 486 | 487 | """ 488 | TRY USING PANDAS HERE 489 | http://bokeh.pydata.org/en/latest/ 490 | https://github.com/datalit/pythonworkshop 491 | 492 | train[(train['Age'] == 34) & (train['Sex']== 'female')] 493 | train[(train['Name'].str.contains('Lily'))] 494 | train[(train['Name'].str.startswith('Futrelle'))] 495 | sorting available... train.sort_index(by = 'Age') 496 | train.sort_index(by = ['Age', 'Pclass'], ascending = [False, True]).head() 497 | add fields to data frame... train['FareToAge'] = train['Fare'] / train['Age'] 498 | pivot tables... pd.pivot_table(train, values = 'Age', index = ['Sex'], columns = ['Pclass'], aggfunc = 'mean') 499 | save... train.to_csv('./data/train-new.csv') 500 | """ 501 | 502 | 503 | """ 504 | JSON-- 505 | 506 | { 507 | "shape_id": 36099, 508 | "shape_pt_number": 91, 509 | "shape_pt_sequence": [ 510 | { 511 | "id": 1, 512 | "lat": 43.809785, 513 | "lon": -79.454099, 514 | "dist": 0.0 515 | }, 516 | { 517 | "id": 2, 518 | "lat": 43.8098, 519 | "lon": -79.453994, 520 | "dist": 0.0082 521 | }, 522 | { 523 | "id": 3, 524 | "lat": 43.809784, 525 | "lon": -79.45389, 526 | "dist": 0.0175 527 | } 528 | ] 529 | } 530 | """ -------------------------------------------------------------------------------- /static/js/jquery.validate-1.13.1.min.js: -------------------------------------------------------------------------------- 1 | /*! jQuery Validation Plugin - v1.13.1 - 10/14/2014 2 | * http://jqueryvalidation.org/ 3 | * Copyright (c) 2014 Jörn Zaefferer; Licensed MIT */ 4 | !function(a){"function"==typeof define&&define.amd?define(["jquery"],a):a(jQuery)}(function(a){a.extend(a.fn,{validate:function(b){if(!this.length)return void(b&&b.debug&&window.console&&console.warn("Nothing selected, can't validate, returning nothing."));var c=a.data(this[0],"validator");return c?c:(this.attr("novalidate","novalidate"),c=new a.validator(b,this[0]),a.data(this[0],"validator",c),c.settings.onsubmit&&(this.validateDelegate(":submit","click",function(b){c.settings.submitHandler&&(c.submitButton=b.target),a(b.target).hasClass("cancel")&&(c.cancelSubmit=!0),void 0!==a(b.target).attr("formnovalidate")&&(c.cancelSubmit=!0)}),this.submit(function(b){function d(){var d,e;return c.settings.submitHandler?(c.submitButton&&(d=a("").attr("name",c.submitButton.name).val(a(c.submitButton).val()).appendTo(c.currentForm)),e=c.settings.submitHandler.call(c,c.currentForm,b),c.submitButton&&d.remove(),void 0!==e?e:!1):!0}return c.settings.debug&&b.preventDefault(),c.cancelSubmit?(c.cancelSubmit=!1,d()):c.form()?c.pendingRequest?(c.formSubmitted=!0,!1):d():(c.focusInvalid(),!1)})),c)},valid:function(){var b,c;return a(this[0]).is("form")?b=this.validate().form():(b=!0,c=a(this[0].form).validate(),this.each(function(){b=c.element(this)&&b})),b},removeAttrs:function(b){var c={},d=this;return a.each(b.split(/\s/),function(a,b){c[b]=d.attr(b),d.removeAttr(b)}),c},rules:function(b,c){var d,e,f,g,h,i,j=this[0];if(b)switch(d=a.data(j.form,"validator").settings,e=d.rules,f=a.validator.staticRules(j),b){case"add":a.extend(f,a.validator.normalizeRule(c)),delete f.messages,e[j.name]=f,c.messages&&(d.messages[j.name]=a.extend(d.messages[j.name],c.messages));break;case"remove":return c?(i={},a.each(c.split(/\s/),function(b,c){i[c]=f[c],delete f[c],"required"===c&&a(j).removeAttr("aria-required")}),i):(delete e[j.name],f)}return g=a.validator.normalizeRules(a.extend({},a.validator.classRules(j),a.validator.attributeRules(j),a.validator.dataRules(j),a.validator.staticRules(j)),j),g.required&&(h=g.required,delete g.required,g=a.extend({required:h},g),a(j).attr("aria-required","true")),g.remote&&(h=g.remote,delete g.remote,g=a.extend(g,{remote:h})),g}}),a.extend(a.expr[":"],{blank:function(b){return!a.trim(""+a(b).val())},filled:function(b){return!!a.trim(""+a(b).val())},unchecked:function(b){return!a(b).prop("checked")}}),a.validator=function(b,c){this.settings=a.extend(!0,{},a.validator.defaults,b),this.currentForm=c,this.init()},a.validator.format=function(b,c){return 1===arguments.length?function(){var c=a.makeArray(arguments);return c.unshift(b),a.validator.format.apply(this,c)}:(arguments.length>2&&c.constructor!==Array&&(c=a.makeArray(arguments).slice(1)),c.constructor!==Array&&(c=[c]),a.each(c,function(a,c){b=b.replace(new RegExp("\\{"+a+"\\}","g"),function(){return c})}),b)},a.extend(a.validator,{defaults:{messages:{},groups:{},rules:{},errorClass:"error",validClass:"valid",errorElement:"label",focusCleanup:!1,focusInvalid:!0,errorContainer:a([]),errorLabelContainer:a([]),onsubmit:!0,ignore:":hidden",ignoreTitle:!1,onfocusin:function(a){this.lastActive=a,this.settings.focusCleanup&&(this.settings.unhighlight&&this.settings.unhighlight.call(this,a,this.settings.errorClass,this.settings.validClass),this.hideThese(this.errorsFor(a)))},onfocusout:function(a){this.checkable(a)||!(a.name in this.submitted)&&this.optional(a)||this.element(a)},onkeyup:function(a,b){(9!==b.which||""!==this.elementValue(a))&&(a.name in this.submitted||a===this.lastElement)&&this.element(a)},onclick:function(a){a.name in this.submitted?this.element(a):a.parentNode.name in this.submitted&&this.element(a.parentNode)},highlight:function(b,c,d){"radio"===b.type?this.findByName(b.name).addClass(c).removeClass(d):a(b).addClass(c).removeClass(d)},unhighlight:function(b,c,d){"radio"===b.type?this.findByName(b.name).removeClass(c).addClass(d):a(b).removeClass(c).addClass(d)}},setDefaults:function(b){a.extend(a.validator.defaults,b)},messages:{required:"This field is required.",remote:"Please fix this field.",email:"Please enter a valid email address.",url:"Please enter a valid URL.",date:"Please enter a valid date.",dateISO:"Please enter a valid date ( ISO ).",number:"Please enter a valid number.",digits:"Please enter only digits.",creditcard:"Please enter a valid credit card number.",equalTo:"Please enter the same value again.",maxlength:a.validator.format("Please enter no more than {0} characters."),minlength:a.validator.format("Please enter at least {0} characters."),rangelength:a.validator.format("Please enter a value between {0} and {1} characters long."),range:a.validator.format("Please enter a value between {0} and {1}."),max:a.validator.format("Please enter a value less than or equal to {0}."),min:a.validator.format("Please enter a value greater than or equal to {0}.")},autoCreateRanges:!1,prototype:{init:function(){function b(b){var c=a.data(this[0].form,"validator"),d="on"+b.type.replace(/^validate/,""),e=c.settings;e[d]&&!this.is(e.ignore)&&e[d].call(c,this[0],b)}this.labelContainer=a(this.settings.errorLabelContainer),this.errorContext=this.labelContainer.length&&this.labelContainer||a(this.currentForm),this.containers=a(this.settings.errorContainer).add(this.settings.errorLabelContainer),this.submitted={},this.valueCache={},this.pendingRequest=0,this.pending={},this.invalid={},this.reset();var c,d=this.groups={};a.each(this.settings.groups,function(b,c){"string"==typeof c&&(c=c.split(/\s/)),a.each(c,function(a,c){d[c]=b})}),c=this.settings.rules,a.each(c,function(b,d){c[b]=a.validator.normalizeRule(d)}),a(this.currentForm).validateDelegate(":text, [type='password'], [type='file'], select, textarea, [type='number'], [type='search'] ,[type='tel'], [type='url'], [type='email'], [type='datetime'], [type='date'], [type='month'], [type='week'], [type='time'], [type='datetime-local'], [type='range'], [type='color'], [type='radio'], [type='checkbox']","focusin focusout keyup",b).validateDelegate("select, option, [type='radio'], [type='checkbox']","click",b),this.settings.invalidHandler&&a(this.currentForm).bind("invalid-form.validate",this.settings.invalidHandler),a(this.currentForm).find("[required], [data-rule-required], .required").attr("aria-required","true")},form:function(){return this.checkForm(),a.extend(this.submitted,this.errorMap),this.invalid=a.extend({},this.errorMap),this.valid()||a(this.currentForm).triggerHandler("invalid-form",[this]),this.showErrors(),this.valid()},checkForm:function(){this.prepareForm();for(var a=0,b=this.currentElements=this.elements();b[a];a++)this.check(b[a]);return this.valid()},element:function(b){var c=this.clean(b),d=this.validationTargetFor(c),e=!0;return this.lastElement=d,void 0===d?delete this.invalid[c.name]:(this.prepareElement(d),this.currentElements=a(d),e=this.check(d)!==!1,e?delete this.invalid[d.name]:this.invalid[d.name]=!0),a(b).attr("aria-invalid",!e),this.numberOfInvalids()||(this.toHide=this.toHide.add(this.containers)),this.showErrors(),e},showErrors:function(b){if(b){a.extend(this.errorMap,b),this.errorList=[];for(var c in b)this.errorList.push({message:b[c],element:this.findByName(c)[0]});this.successList=a.grep(this.successList,function(a){return!(a.name in b)})}this.settings.showErrors?this.settings.showErrors.call(this,this.errorMap,this.errorList):this.defaultShowErrors()},resetForm:function(){a.fn.resetForm&&a(this.currentForm).resetForm(),this.submitted={},this.lastElement=null,this.prepareForm(),this.hideErrors(),this.elements().removeClass(this.settings.errorClass).removeData("previousValue").removeAttr("aria-invalid")},numberOfInvalids:function(){return this.objectLength(this.invalid)},objectLength:function(a){var b,c=0;for(b in a)c++;return c},hideErrors:function(){this.hideThese(this.toHide)},hideThese:function(a){a.not(this.containers).text(""),this.addWrapper(a).hide()},valid:function(){return 0===this.size()},size:function(){return this.errorList.length},focusInvalid:function(){if(this.settings.focusInvalid)try{a(this.findLastActive()||this.errorList.length&&this.errorList[0].element||[]).filter(":visible").focus().trigger("focusin")}catch(b){}},findLastActive:function(){var b=this.lastActive;return b&&1===a.grep(this.errorList,function(a){return a.element.name===b.name}).length&&b},elements:function(){var b=this,c={};return a(this.currentForm).find("input, select, textarea").not(":submit, :reset, :image, [disabled], [readonly]").not(this.settings.ignore).filter(function(){return!this.name&&b.settings.debug&&window.console&&console.error("%o has no name assigned",this),this.name in c||!b.objectLength(a(this).rules())?!1:(c[this.name]=!0,!0)})},clean:function(b){return a(b)[0]},errors:function(){var b=this.settings.errorClass.split(" ").join(".");return a(this.settings.errorElement+"."+b,this.errorContext)},reset:function(){this.successList=[],this.errorList=[],this.errorMap={},this.toShow=a([]),this.toHide=a([]),this.currentElements=a([])},prepareForm:function(){this.reset(),this.toHide=this.errors().add(this.containers)},prepareElement:function(a){this.reset(),this.toHide=this.errorsFor(a)},elementValue:function(b){var c,d=a(b),e=b.type;return"radio"===e||"checkbox"===e?a("input[name='"+b.name+"']:checked").val():"number"===e&&"undefined"!=typeof b.validity?b.validity.badInput?!1:d.val():(c=d.val(),"string"==typeof c?c.replace(/\r/g,""):c)},check:function(b){b=this.validationTargetFor(this.clean(b));var c,d,e,f=a(b).rules(),g=a.map(f,function(a,b){return b}).length,h=!1,i=this.elementValue(b);for(d in f){e={method:d,parameters:f[d]};try{if(c=a.validator.methods[d].call(this,i,b,e.parameters),"dependency-mismatch"===c&&1===g){h=!0;continue}if(h=!1,"pending"===c)return void(this.toHide=this.toHide.not(this.errorsFor(b)));if(!c)return this.formatAndAdd(b,e),!1}catch(j){throw this.settings.debug&&window.console&&console.log("Exception occurred when checking element "+b.id+", check the '"+e.method+"' method.",j),j}}if(!h)return this.objectLength(f)&&this.successList.push(b),!0},customDataMessage:function(b,c){return a(b).data("msg"+c.charAt(0).toUpperCase()+c.substring(1).toLowerCase())||a(b).data("msg")},customMessage:function(a,b){var c=this.settings.messages[a];return c&&(c.constructor===String?c:c[b])},findDefined:function(){for(var a=0;aWarning: No message defined for "+b.name+"")},formatAndAdd:function(b,c){var d=this.defaultMessage(b,c.method),e=/\$?\{(\d+)\}/g;"function"==typeof d?d=d.call(this,c.parameters,b):e.test(d)&&(d=a.validator.format(d.replace(e,"{$1}"),c.parameters)),this.errorList.push({message:d,element:b,method:c.method}),this.errorMap[b.name]=d,this.submitted[b.name]=d},addWrapper:function(a){return this.settings.wrapper&&(a=a.add(a.parent(this.settings.wrapper))),a},defaultShowErrors:function(){var a,b,c;for(a=0;this.errorList[a];a++)c=this.errorList[a],this.settings.highlight&&this.settings.highlight.call(this,c.element,this.settings.errorClass,this.settings.validClass),this.showLabel(c.element,c.message);if(this.errorList.length&&(this.toShow=this.toShow.add(this.containers)),this.settings.success)for(a=0;this.successList[a];a++)this.showLabel(this.successList[a]);if(this.settings.unhighlight)for(a=0,b=this.validElements();b[a];a++)this.settings.unhighlight.call(this,b[a],this.settings.errorClass,this.settings.validClass);this.toHide=this.toHide.not(this.toShow),this.hideErrors(),this.addWrapper(this.toShow).show()},validElements:function(){return this.currentElements.not(this.invalidElements())},invalidElements:function(){return a(this.errorList).map(function(){return this.element})},showLabel:function(b,c){var d,e,f,g=this.errorsFor(b),h=this.idOrName(b),i=a(b).attr("aria-describedby");g.length?(g.removeClass(this.settings.validClass).addClass(this.settings.errorClass),g.html(c)):(g=a("<"+this.settings.errorElement+">").attr("id",h+"-error").addClass(this.settings.errorClass).html(c||""),d=g,this.settings.wrapper&&(d=g.hide().show().wrap("<"+this.settings.wrapper+"/>").parent()),this.labelContainer.length?this.labelContainer.append(d):this.settings.errorPlacement?this.settings.errorPlacement(d,a(b)):d.insertAfter(b),g.is("label")?g.attr("for",h):0===g.parents("label[for='"+h+"']").length&&(f=g.attr("id").replace(/(:|\.|\[|\])/g,"\\$1"),i?i.match(new RegExp("\\b"+f+"\\b"))||(i+=" "+f):i=f,a(b).attr("aria-describedby",i),e=this.groups[b.name],e&&a.each(this.groups,function(b,c){c===e&&a("[name='"+b+"']",this.currentForm).attr("aria-describedby",g.attr("id"))}))),!c&&this.settings.success&&(g.text(""),"string"==typeof this.settings.success?g.addClass(this.settings.success):this.settings.success(g,b)),this.toShow=this.toShow.add(g)},errorsFor:function(b){var c=this.idOrName(b),d=a(b).attr("aria-describedby"),e="label[for='"+c+"'], label[for='"+c+"'] *";return d&&(e=e+", #"+d.replace(/\s+/g,", #")),this.errors().filter(e)},idOrName:function(a){return this.groups[a.name]||(this.checkable(a)?a.name:a.id||a.name)},validationTargetFor:function(b){return this.checkable(b)&&(b=this.findByName(b.name)),a(b).not(this.settings.ignore)[0]},checkable:function(a){return/radio|checkbox/i.test(a.type)},findByName:function(b){return a(this.currentForm).find("[name='"+b+"']")},getLength:function(b,c){switch(c.nodeName.toLowerCase()){case"select":return a("option:selected",c).length;case"input":if(this.checkable(c))return this.findByName(c.name).filter(":checked").length}return b.length},depend:function(a,b){return this.dependTypes[typeof a]?this.dependTypes[typeof a](a,b):!0},dependTypes:{"boolean":function(a){return a},string:function(b,c){return!!a(b,c.form).length},"function":function(a,b){return a(b)}},optional:function(b){var c=this.elementValue(b);return!a.validator.methods.required.call(this,c,b)&&"dependency-mismatch"},startRequest:function(a){this.pending[a.name]||(this.pendingRequest++,this.pending[a.name]=!0)},stopRequest:function(b,c){this.pendingRequest--,this.pendingRequest<0&&(this.pendingRequest=0),delete this.pending[b.name],c&&0===this.pendingRequest&&this.formSubmitted&&this.form()?(a(this.currentForm).submit(),this.formSubmitted=!1):!c&&0===this.pendingRequest&&this.formSubmitted&&(a(this.currentForm).triggerHandler("invalid-form",[this]),this.formSubmitted=!1)},previousValue:function(b){return a.data(b,"previousValue")||a.data(b,"previousValue",{old:null,valid:!0,message:this.defaultMessage(b,"remote")})}},classRuleSettings:{required:{required:!0},email:{email:!0},url:{url:!0},date:{date:!0},dateISO:{dateISO:!0},number:{number:!0},digits:{digits:!0},creditcard:{creditcard:!0}},addClassRules:function(b,c){b.constructor===String?this.classRuleSettings[b]=c:a.extend(this.classRuleSettings,b)},classRules:function(b){var c={},d=a(b).attr("class");return d&&a.each(d.split(" "),function(){this in a.validator.classRuleSettings&&a.extend(c,a.validator.classRuleSettings[this])}),c},attributeRules:function(b){var c,d,e={},f=a(b),g=b.getAttribute("type");for(c in a.validator.methods)"required"===c?(d=b.getAttribute(c),""===d&&(d=!0),d=!!d):d=f.attr(c),/min|max/.test(c)&&(null===g||/number|range|text/.test(g))&&(d=Number(d)),d||0===d?e[c]=d:g===c&&"range"!==g&&(e[c]=!0);return e.maxlength&&/-1|2147483647|524288/.test(e.maxlength)&&delete e.maxlength,e},dataRules:function(b){var c,d,e={},f=a(b);for(c in a.validator.methods)d=f.data("rule"+c.charAt(0).toUpperCase()+c.substring(1).toLowerCase()),void 0!==d&&(e[c]=d);return e},staticRules:function(b){var c={},d=a.data(b.form,"validator");return d.settings.rules&&(c=a.validator.normalizeRule(d.settings.rules[b.name])||{}),c},normalizeRules:function(b,c){return a.each(b,function(d,e){if(e===!1)return void delete b[d];if(e.param||e.depends){var f=!0;switch(typeof e.depends){case"string":f=!!a(e.depends,c.form).length;break;case"function":f=e.depends.call(c,c)}f?b[d]=void 0!==e.param?e.param:!0:delete b[d]}}),a.each(b,function(d,e){b[d]=a.isFunction(e)?e(c):e}),a.each(["minlength","maxlength"],function(){b[this]&&(b[this]=Number(b[this]))}),a.each(["rangelength","range"],function(){var c;b[this]&&(a.isArray(b[this])?b[this]=[Number(b[this][0]),Number(b[this][1])]:"string"==typeof b[this]&&(c=b[this].replace(/[\[\]]/g,"").split(/[\s,]+/),b[this]=[Number(c[0]),Number(c[1])]))}),a.validator.autoCreateRanges&&(null!=b.min&&null!=b.max&&(b.range=[b.min,b.max],delete b.min,delete b.max),null!=b.minlength&&null!=b.maxlength&&(b.rangelength=[b.minlength,b.maxlength],delete b.minlength,delete b.maxlength)),b},normalizeRule:function(b){if("string"==typeof b){var c={};a.each(b.split(/\s/),function(){c[this]=!0}),b=c}return b},addMethod:function(b,c,d){a.validator.methods[b]=c,a.validator.messages[b]=void 0!==d?d:a.validator.messages[b],c.length<3&&a.validator.addClassRules(b,a.validator.normalizeRule(b))},methods:{required:function(b,c,d){if(!this.depend(d,c))return"dependency-mismatch";if("select"===c.nodeName.toLowerCase()){var e=a(c).val();return e&&e.length>0}return this.checkable(c)?this.getLength(b,c)>0:a.trim(b).length>0},email:function(a,b){return this.optional(b)||/^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/.test(a)},url:function(a,b){return this.optional(b)||/^(https?|s?ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i.test(a)},date:function(a,b){return this.optional(b)||!/Invalid|NaN/.test(new Date(a).toString())},dateISO:function(a,b){return this.optional(b)||/^\d{4}[\/\-](0?[1-9]|1[012])[\/\-](0?[1-9]|[12][0-9]|3[01])$/.test(a)},number:function(a,b){return this.optional(b)||/^-?(?:\d+|\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/.test(a)},digits:function(a,b){return this.optional(b)||/^\d+$/.test(a)},creditcard:function(a,b){if(this.optional(b))return"dependency-mismatch";if(/[^0-9 \-]+/.test(a))return!1;var c,d,e=0,f=0,g=!1;if(a=a.replace(/\D/g,""),a.length<13||a.length>19)return!1;for(c=a.length-1;c>=0;c--)d=a.charAt(c),f=parseInt(d,10),g&&(f*=2)>9&&(f-=9),e+=f,g=!g;return e%10===0},minlength:function(b,c,d){var e=a.isArray(b)?b.length:this.getLength(b,c);return this.optional(c)||e>=d},maxlength:function(b,c,d){var e=a.isArray(b)?b.length:this.getLength(b,c);return this.optional(c)||d>=e},rangelength:function(b,c,d){var e=a.isArray(b)?b.length:this.getLength(b,c);return this.optional(c)||e>=d[0]&&e<=d[1]},min:function(a,b,c){return this.optional(b)||a>=c},max:function(a,b,c){return this.optional(b)||c>=a},range:function(a,b,c){return this.optional(b)||a>=c[0]&&a<=c[1]},equalTo:function(b,c,d){var e=a(d);return this.settings.onfocusout&&e.unbind(".validate-equalTo").bind("blur.validate-equalTo",function(){a(c).valid()}),b===e.val()},remote:function(b,c,d){if(this.optional(c))return"dependency-mismatch";var e,f,g=this.previousValue(c);return this.settings.messages[c.name]||(this.settings.messages[c.name]={}),g.originalMessage=this.settings.messages[c.name].remote,this.settings.messages[c.name].remote=g.message,d="string"==typeof d&&{url:d}||d,g.old===b?g.valid:(g.old=b,e=this,this.startRequest(c),f={},f[c.name]=b,a.ajax(a.extend(!0,{url:d,mode:"abort",port:"validate"+c.name,dataType:"json",data:f,context:e.currentForm,success:function(d){var f,h,i,j=d===!0||"true"===d;e.settings.messages[c.name].remote=g.originalMessage,j?(i=e.formSubmitted,e.prepareElement(c),e.formSubmitted=i,e.successList.push(c),delete e.invalid[c.name],e.showErrors()):(f={},h=d||e.defaultMessage(c,"remote"),f[c.name]=g.message=a.isFunction(h)?h(b):h,e.invalid[c.name]=!0,e.showErrors(f)),g.valid=j,e.stopRequest(c,j)}},d)),"pending")}}}),a.format=function(){throw"$.format has been deprecated. Please use $.validator.format instead."};var b,c={};a.ajaxPrefilter?a.ajaxPrefilter(function(a,b,d){var e=a.port;"abort"===a.mode&&(c[e]&&c[e].abort(),c[e]=d)}):(b=a.ajax,a.ajax=function(d){var e=("mode"in d?d:a.ajaxSettings).mode,f=("port"in d?d:a.ajaxSettings).port;return"abort"===e?(c[f]&&c[f].abort(),c[f]=b.apply(this,arguments),c[f]):b.apply(this,arguments)}),a.extend(a.fn,{validateDelegate:function(b,c,d){return this.bind(c,function(c){var e=a(c.target);return e.is(b)?d.apply(e,arguments):void 0})}})}); -------------------------------------------------------------------------------- /static/js/moment-2.10.3.min.js: -------------------------------------------------------------------------------- 1 | //! moment.js 2 | //! version : 2.10.3 3 | //! authors : Tim Wood, Iskren Chernev, Moment.js contributors 4 | //! license : MIT 5 | //! momentjs.com 6 | !function(a,b){"object"==typeof exports&&"undefined"!=typeof module?module.exports=b():"function"==typeof define&&define.amd?define(b):a.moment=b()}(this,function(){"use strict";function a(){return Dc.apply(null,arguments)}function b(a){Dc=a}function c(a){return"[object Array]"===Object.prototype.toString.call(a)}function d(a){return a instanceof Date||"[object Date]"===Object.prototype.toString.call(a)}function e(a,b){var c,d=[];for(c=0;c0)for(c in Fc)d=Fc[c],e=b[d],"undefined"!=typeof e&&(a[d]=e);return a}function n(b){m(this,b),this._d=new Date(+b._d),Gc===!1&&(Gc=!0,a.updateOffset(this),Gc=!1)}function o(a){return a instanceof n||null!=a&&null!=a._isAMomentObject}function p(a){var b=+a,c=0;return 0!==b&&isFinite(b)&&(c=b>=0?Math.floor(b):Math.ceil(b)),c}function q(a,b,c){var d,e=Math.min(a.length,b.length),f=Math.abs(a.length-b.length),g=0;for(d=0;e>d;d++)(c&&a[d]!==b[d]||!c&&p(a[d])!==p(b[d]))&&g++;return g+f}function r(){}function s(a){return a?a.toLowerCase().replace("_","-"):a}function t(a){for(var b,c,d,e,f=0;f0;){if(d=u(e.slice(0,b).join("-")))return d;if(c&&c.length>=b&&q(e,c,!0)>=b-1)break;b--}f++}return null}function u(a){var b=null;if(!Hc[a]&&"undefined"!=typeof module&&module&&module.exports)try{b=Ec._abbr,require("./locale/"+a),v(b)}catch(c){}return Hc[a]}function v(a,b){var c;return a&&(c="undefined"==typeof b?x(a):w(a,b),c&&(Ec=c)),Ec._abbr}function w(a,b){return null!==b?(b.abbr=a,Hc[a]||(Hc[a]=new r),Hc[a].set(b),v(a),Hc[a]):(delete Hc[a],null)}function x(a){var b;if(a&&a._locale&&a._locale._abbr&&(a=a._locale._abbr),!a)return Ec;if(!c(a)){if(b=u(a))return b;a=[a]}return t(a)}function y(a,b){var c=a.toLowerCase();Ic[c]=Ic[c+"s"]=Ic[b]=a}function z(a){return"string"==typeof a?Ic[a]||Ic[a.toLowerCase()]:void 0}function A(a){var b,c,d={};for(c in a)f(a,c)&&(b=z(c),b&&(d[b]=a[c]));return d}function B(b,c){return function(d){return null!=d?(D(this,b,d),a.updateOffset(this,c),this):C(this,b)}}function C(a,b){return a._d["get"+(a._isUTC?"UTC":"")+b]()}function D(a,b,c){return a._d["set"+(a._isUTC?"UTC":"")+b](c)}function E(a,b){var c;if("object"==typeof a)for(c in a)this.set(c,a[c]);else if(a=z(a),"function"==typeof this[a])return this[a](b);return this}function F(a,b,c){for(var d=""+Math.abs(a),e=a>=0;d.lengthb;b++)Mc[d[b]]?d[b]=Mc[d[b]]:d[b]=H(d[b]);return function(e){var f="";for(b=0;c>b;b++)f+=d[b]instanceof Function?d[b].call(e,a):d[b];return f}}function J(a,b){return a.isValid()?(b=K(b,a.localeData()),Lc[b]||(Lc[b]=I(b)),Lc[b](a)):a.localeData().invalidDate()}function K(a,b){function c(a){return b.longDateFormat(a)||a}var d=5;for(Kc.lastIndex=0;d>=0&&Kc.test(a);)a=a.replace(Kc,c),Kc.lastIndex=0,d-=1;return a}function L(a,b,c){_c[a]="function"==typeof b?b:function(a){return a&&c?c:b}}function M(a,b){return f(_c,a)?_c[a](b._strict,b._locale):new RegExp(N(a))}function N(a){return a.replace("\\","").replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g,function(a,b,c,d,e){return b||c||d||e}).replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}function O(a,b){var c,d=b;for("string"==typeof a&&(a=[a]),"number"==typeof b&&(d=function(a,c){c[b]=p(a)}),c=0;cd;d++){if(e=h([2e3,d]),c&&!this._longMonthsParse[d]&&(this._longMonthsParse[d]=new RegExp("^"+this.months(e,"").replace(".","")+"$","i"),this._shortMonthsParse[d]=new RegExp("^"+this.monthsShort(e,"").replace(".","")+"$","i")),c||this._monthsParse[d]||(f="^"+this.months(e,"")+"|^"+this.monthsShort(e,""),this._monthsParse[d]=new RegExp(f.replace(".",""),"i")),c&&"MMMM"===b&&this._longMonthsParse[d].test(a))return d;if(c&&"MMM"===b&&this._shortMonthsParse[d].test(a))return d;if(!c&&this._monthsParse[d].test(a))return d}}function V(a,b){var c;return"string"==typeof b&&(b=a.localeData().monthsParse(b),"number"!=typeof b)?a:(c=Math.min(a.date(),R(a.year(),b)),a._d["set"+(a._isUTC?"UTC":"")+"Month"](b,c),a)}function W(b){return null!=b?(V(this,b),a.updateOffset(this,!0),this):C(this,"Month")}function X(){return R(this.year(),this.month())}function Y(a){var b,c=a._a;return c&&-2===j(a).overflow&&(b=c[cd]<0||c[cd]>11?cd:c[dd]<1||c[dd]>R(c[bd],c[cd])?dd:c[ed]<0||c[ed]>24||24===c[ed]&&(0!==c[fd]||0!==c[gd]||0!==c[hd])?ed:c[fd]<0||c[fd]>59?fd:c[gd]<0||c[gd]>59?gd:c[hd]<0||c[hd]>999?hd:-1,j(a)._overflowDayOfYear&&(bd>b||b>dd)&&(b=dd),j(a).overflow=b),a}function Z(b){a.suppressDeprecationWarnings===!1&&"undefined"!=typeof console&&console.warn&&console.warn("Deprecation warning: "+b)}function $(a,b){var c=!0,d=a+"\n"+(new Error).stack;return g(function(){return c&&(Z(d),c=!1),b.apply(this,arguments)},b)}function _(a,b){kd[a]||(Z(b),kd[a]=!0)}function aa(a){var b,c,d=a._i,e=ld.exec(d);if(e){for(j(a).iso=!0,b=0,c=md.length;c>b;b++)if(md[b][1].exec(d)){a._f=md[b][0]+(e[6]||" ");break}for(b=0,c=nd.length;c>b;b++)if(nd[b][1].exec(d)){a._f+=nd[b][0];break}d.match(Yc)&&(a._f+="Z"),ta(a)}else a._isValid=!1}function ba(b){var c=od.exec(b._i);return null!==c?void(b._d=new Date(+c[1])):(aa(b),void(b._isValid===!1&&(delete b._isValid,a.createFromInputFallback(b))))}function ca(a,b,c,d,e,f,g){var h=new Date(a,b,c,d,e,f,g);return 1970>a&&h.setFullYear(a),h}function da(a){var b=new Date(Date.UTC.apply(null,arguments));return 1970>a&&b.setUTCFullYear(a),b}function ea(a){return fa(a)?366:365}function fa(a){return a%4===0&&a%100!==0||a%400===0}function ga(){return fa(this.year())}function ha(a,b,c){var d,e=c-b,f=c-a.day();return f>e&&(f-=7),e-7>f&&(f+=7),d=Aa(a).add(f,"d"),{week:Math.ceil(d.dayOfYear()/7),year:d.year()}}function ia(a){return ha(a,this._week.dow,this._week.doy).week}function ja(){return this._week.dow}function ka(){return this._week.doy}function la(a){var b=this.localeData().week(this);return null==a?b:this.add(7*(a-b),"d")}function ma(a){var b=ha(this,1,4).week;return null==a?b:this.add(7*(a-b),"d")}function na(a,b,c,d,e){var f,g,h=da(a,0,1).getUTCDay();return h=0===h?7:h,c=null!=c?c:e,f=e-h+(h>d?7:0)-(e>h?7:0),g=7*(b-1)+(c-e)+f+1,{year:g>0?a:a-1,dayOfYear:g>0?g:ea(a-1)+g}}function oa(a){var b=Math.round((this.clone().startOf("day")-this.clone().startOf("year"))/864e5)+1;return null==a?b:this.add(a-b,"d")}function pa(a,b,c){return null!=a?a:null!=b?b:c}function qa(a){var b=new Date;return a._useUTC?[b.getUTCFullYear(),b.getUTCMonth(),b.getUTCDate()]:[b.getFullYear(),b.getMonth(),b.getDate()]}function ra(a){var b,c,d,e,f=[];if(!a._d){for(d=qa(a),a._w&&null==a._a[dd]&&null==a._a[cd]&&sa(a),a._dayOfYear&&(e=pa(a._a[bd],d[bd]),a._dayOfYear>ea(e)&&(j(a)._overflowDayOfYear=!0),c=da(e,0,a._dayOfYear),a._a[cd]=c.getUTCMonth(),a._a[dd]=c.getUTCDate()),b=0;3>b&&null==a._a[b];++b)a._a[b]=f[b]=d[b];for(;7>b;b++)a._a[b]=f[b]=null==a._a[b]?2===b?1:0:a._a[b];24===a._a[ed]&&0===a._a[fd]&&0===a._a[gd]&&0===a._a[hd]&&(a._nextDay=!0,a._a[ed]=0),a._d=(a._useUTC?da:ca).apply(null,f),null!=a._tzm&&a._d.setUTCMinutes(a._d.getUTCMinutes()-a._tzm),a._nextDay&&(a._a[ed]=24)}}function sa(a){var b,c,d,e,f,g,h;b=a._w,null!=b.GG||null!=b.W||null!=b.E?(f=1,g=4,c=pa(b.GG,a._a[bd],ha(Aa(),1,4).year),d=pa(b.W,1),e=pa(b.E,1)):(f=a._locale._week.dow,g=a._locale._week.doy,c=pa(b.gg,a._a[bd],ha(Aa(),f,g).year),d=pa(b.w,1),null!=b.d?(e=b.d,f>e&&++d):e=null!=b.e?b.e+f:f),h=na(c,d,e,g,f),a._a[bd]=h.year,a._dayOfYear=h.dayOfYear}function ta(b){if(b._f===a.ISO_8601)return void aa(b);b._a=[],j(b).empty=!0;var c,d,e,f,g,h=""+b._i,i=h.length,k=0;for(e=K(b._f,b._locale).match(Jc)||[],c=0;c0&&j(b).unusedInput.push(g),h=h.slice(h.indexOf(d)+d.length),k+=d.length),Mc[f]?(d?j(b).empty=!1:j(b).unusedTokens.push(f),Q(f,d,b)):b._strict&&!d&&j(b).unusedTokens.push(f);j(b).charsLeftOver=i-k,h.length>0&&j(b).unusedInput.push(h),j(b).bigHour===!0&&b._a[ed]<=12&&b._a[ed]>0&&(j(b).bigHour=void 0),b._a[ed]=ua(b._locale,b._a[ed],b._meridiem),ra(b),Y(b)}function ua(a,b,c){var d;return null==c?b:null!=a.meridiemHour?a.meridiemHour(b,c):null!=a.isPM?(d=a.isPM(c),d&&12>b&&(b+=12),d||12!==b||(b=0),b):b}function va(a){var b,c,d,e,f;if(0===a._f.length)return j(a).invalidFormat=!0,void(a._d=new Date(0/0));for(e=0;ef)&&(d=f,c=b));g(a,c||b)}function wa(a){if(!a._d){var b=A(a._i);a._a=[b.year,b.month,b.day||b.date,b.hour,b.minute,b.second,b.millisecond],ra(a)}}function xa(a){var b,e=a._i,f=a._f;return a._locale=a._locale||x(a._l),null===e||void 0===f&&""===e?l({nullInput:!0}):("string"==typeof e&&(a._i=e=a._locale.preparse(e)),o(e)?new n(Y(e)):(c(f)?va(a):f?ta(a):d(e)?a._d=e:ya(a),b=new n(Y(a)),b._nextDay&&(b.add(1,"d"),b._nextDay=void 0),b))}function ya(b){var f=b._i;void 0===f?b._d=new Date:d(f)?b._d=new Date(+f):"string"==typeof f?ba(b):c(f)?(b._a=e(f.slice(0),function(a){return parseInt(a,10)}),ra(b)):"object"==typeof f?wa(b):"number"==typeof f?b._d=new Date(f):a.createFromInputFallback(b)}function za(a,b,c,d,e){var f={};return"boolean"==typeof c&&(d=c,c=void 0),f._isAMomentObject=!0,f._useUTC=f._isUTC=e,f._l=c,f._i=a,f._f=b,f._strict=d,xa(f)}function Aa(a,b,c,d){return za(a,b,c,d,!1)}function Ba(a,b){var d,e;if(1===b.length&&c(b[0])&&(b=b[0]),!b.length)return Aa();for(d=b[0],e=1;ea&&(a=-a,c="-"),c+F(~~(a/60),2)+b+F(~~a%60,2)})}function Ha(a){var b=(a||"").match(Yc)||[],c=b[b.length-1]||[],d=(c+"").match(td)||["-",0,0],e=+(60*d[1])+p(d[2]);return"+"===d[0]?e:-e}function Ia(b,c){var e,f;return c._isUTC?(e=c.clone(),f=(o(b)||d(b)?+b:+Aa(b))-+e,e._d.setTime(+e._d+f),a.updateOffset(e,!1),e):Aa(b).local();return c._isUTC?Aa(b).zone(c._offset||0):Aa(b).local()}function Ja(a){return 15*-Math.round(a._d.getTimezoneOffset()/15)}function Ka(b,c){var d,e=this._offset||0;return null!=b?("string"==typeof b&&(b=Ha(b)),Math.abs(b)<16&&(b=60*b),!this._isUTC&&c&&(d=Ja(this)),this._offset=b,this._isUTC=!0,null!=d&&this.add(d,"m"),e!==b&&(!c||this._changeInProgress?$a(this,Va(b-e,"m"),1,!1):this._changeInProgress||(this._changeInProgress=!0,a.updateOffset(this,!0),this._changeInProgress=null)),this):this._isUTC?e:Ja(this)}function La(a,b){return null!=a?("string"!=typeof a&&(a=-a),this.utcOffset(a,b),this):-this.utcOffset()}function Ma(a){return this.utcOffset(0,a)}function Na(a){return this._isUTC&&(this.utcOffset(0,a),this._isUTC=!1,a&&this.subtract(Ja(this),"m")),this}function Oa(){return this._tzm?this.utcOffset(this._tzm):"string"==typeof this._i&&this.utcOffset(Ha(this._i)),this}function Pa(a){return a=a?Aa(a).utcOffset():0,(this.utcOffset()-a)%60===0}function Qa(){return this.utcOffset()>this.clone().month(0).utcOffset()||this.utcOffset()>this.clone().month(5).utcOffset()}function Ra(){if(this._a){var a=this._isUTC?h(this._a):Aa(this._a);return this.isValid()&&q(this._a,a.toArray())>0}return!1}function Sa(){return!this._isUTC}function Ta(){return this._isUTC}function Ua(){return this._isUTC&&0===this._offset}function Va(a,b){var c,d,e,g=a,h=null;return Fa(a)?g={ms:a._milliseconds,d:a._days,M:a._months}:"number"==typeof a?(g={},b?g[b]=a:g.milliseconds=a):(h=ud.exec(a))?(c="-"===h[1]?-1:1,g={y:0,d:p(h[dd])*c,h:p(h[ed])*c,m:p(h[fd])*c,s:p(h[gd])*c,ms:p(h[hd])*c}):(h=vd.exec(a))?(c="-"===h[1]?-1:1,g={y:Wa(h[2],c),M:Wa(h[3],c),d:Wa(h[4],c),h:Wa(h[5],c),m:Wa(h[6],c),s:Wa(h[7],c),w:Wa(h[8],c)}):null==g?g={}:"object"==typeof g&&("from"in g||"to"in g)&&(e=Ya(Aa(g.from),Aa(g.to)),g={},g.ms=e.milliseconds,g.M=e.months),d=new Ea(g),Fa(a)&&f(a,"_locale")&&(d._locale=a._locale),d}function Wa(a,b){var c=a&&parseFloat(a.replace(",","."));return(isNaN(c)?0:c)*b}function Xa(a,b){var c={milliseconds:0,months:0};return c.months=b.month()-a.month()+12*(b.year()-a.year()),a.clone().add(c.months,"M").isAfter(b)&&--c.months,c.milliseconds=+b-+a.clone().add(c.months,"M"),c}function Ya(a,b){var c;return b=Ia(b,a),a.isBefore(b)?c=Xa(a,b):(c=Xa(b,a),c.milliseconds=-c.milliseconds,c.months=-c.months),c}function Za(a,b){return function(c,d){var e,f;return null===d||isNaN(+d)||(_(b,"moment()."+b+"(period, number) is deprecated. Please use moment()."+b+"(number, period)."),f=c,c=d,d=f),c="string"==typeof c?+c:c,e=Va(c,d),$a(this,e,a),this}}function $a(b,c,d,e){var f=c._milliseconds,g=c._days,h=c._months;e=null==e?!0:e,f&&b._d.setTime(+b._d+f*d),g&&D(b,"Date",C(b,"Date")+g*d),h&&V(b,C(b,"Month")+h*d),e&&a.updateOffset(b,g||h)}function _a(a){var b=a||Aa(),c=Ia(b,this).startOf("day"),d=this.diff(c,"days",!0),e=-6>d?"sameElse":-1>d?"lastWeek":0>d?"lastDay":1>d?"sameDay":2>d?"nextDay":7>d?"nextWeek":"sameElse";return this.format(this.localeData().calendar(e,this,Aa(b)))}function ab(){return new n(this)}function bb(a,b){var c;return b=z("undefined"!=typeof b?b:"millisecond"),"millisecond"===b?(a=o(a)?a:Aa(a),+this>+a):(c=o(a)?+a:+Aa(a),c<+this.clone().startOf(b))}function cb(a,b){var c;return b=z("undefined"!=typeof b?b:"millisecond"),"millisecond"===b?(a=o(a)?a:Aa(a),+a>+this):(c=o(a)?+a:+Aa(a),+this.clone().endOf(b)a?Math.ceil(a):Math.floor(a)}function gb(a,b,c){var d,e,f=Ia(a,this),g=6e4*(f.utcOffset()-this.utcOffset());return b=z(b),"year"===b||"month"===b||"quarter"===b?(e=hb(this,f),"quarter"===b?e/=3:"year"===b&&(e/=12)):(d=this-f,e="second"===b?d/1e3:"minute"===b?d/6e4:"hour"===b?d/36e5:"day"===b?(d-g)/864e5:"week"===b?(d-g)/6048e5:d),c?e:fb(e)}function hb(a,b){var c,d,e=12*(b.year()-a.year())+(b.month()-a.month()),f=a.clone().add(e,"months");return 0>b-f?(c=a.clone().add(e-1,"months"),d=(b-f)/(f-c)):(c=a.clone().add(e+1,"months"),d=(b-f)/(c-f)),-(e+d)}function ib(){return this.clone().locale("en").format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ")}function jb(){var a=this.clone().utc();return 0b;b++)if(this._weekdaysParse[b]||(c=Aa([2e3,1]).day(b),d="^"+this.weekdays(c,"")+"|^"+this.weekdaysShort(c,"")+"|^"+this.weekdaysMin(c,""),this._weekdaysParse[b]=new RegExp(d.replace(".",""),"i")),this._weekdaysParse[b].test(a))return b}function Mb(a){var b=this._isUTC?this._d.getUTCDay():this._d.getDay();return null!=a?(a=Hb(a,this.localeData()),this.add(a-b,"d")):b}function Nb(a){var b=(this.day()+7-this.localeData()._week.dow)%7;return null==a?b:this.add(a-b,"d")}function Ob(a){return null==a?this.day()||7:this.day(this.day()%7?a:a-7)}function Pb(a,b){G(a,0,0,function(){return this.localeData().meridiem(this.hours(),this.minutes(),b)})}function Qb(a,b){return b._meridiemParse}function Rb(a){return"p"===(a+"").toLowerCase().charAt(0)}function Sb(a,b,c){return a>11?c?"pm":"PM":c?"am":"AM"}function Tb(a){G(0,[a,3],0,"millisecond")}function Ub(){return this._isUTC?"UTC":""}function Vb(){return this._isUTC?"Coordinated Universal Time":""}function Wb(a){return Aa(1e3*a)}function Xb(){return Aa.apply(null,arguments).parseZone()}function Yb(a,b,c){var d=this._calendar[a];return"function"==typeof d?d.call(b,c):d}function Zb(a){var b=this._longDateFormat[a];return!b&&this._longDateFormat[a.toUpperCase()]&&(b=this._longDateFormat[a.toUpperCase()].replace(/MMMM|MM|DD|dddd/g,function(a){return a.slice(1)}),this._longDateFormat[a]=b),b}function $b(){return this._invalidDate}function _b(a){return this._ordinal.replace("%d",a)}function ac(a){return a}function bc(a,b,c,d){var e=this._relativeTime[c];return"function"==typeof e?e(a,b,c,d):e.replace(/%d/i,a)}function cc(a,b){var c=this._relativeTime[a>0?"future":"past"];return"function"==typeof c?c(b):c.replace(/%s/i,b)}function dc(a){var b,c;for(c in a)b=a[c],"function"==typeof b?this[c]=b:this["_"+c]=b;this._ordinalParseLenient=new RegExp(this._ordinalParse.source+"|"+/\d{1,2}/.source)}function ec(a,b,c,d){var e=x(),f=h().set(d,b);return e[c](f,a)}function fc(a,b,c,d,e){if("number"==typeof a&&(b=a,a=void 0),a=a||"",null!=b)return ec(a,b,c,e);var f,g=[];for(f=0;d>f;f++)g[f]=ec(a,f,c,e);return g}function gc(a,b){return fc(a,b,"months",12,"month")}function hc(a,b){return fc(a,b,"monthsShort",12,"month")}function ic(a,b){return fc(a,b,"weekdays",7,"day")}function jc(a,b){return fc(a,b,"weekdaysShort",7,"day")}function kc(a,b){return fc(a,b,"weekdaysMin",7,"day")}function lc(){var a=this._data;return this._milliseconds=Rd(this._milliseconds),this._days=Rd(this._days),this._months=Rd(this._months),a.milliseconds=Rd(a.milliseconds),a.seconds=Rd(a.seconds),a.minutes=Rd(a.minutes),a.hours=Rd(a.hours),a.months=Rd(a.months),a.years=Rd(a.years),this}function mc(a,b,c,d){var e=Va(b,c);return a._milliseconds+=d*e._milliseconds,a._days+=d*e._days,a._months+=d*e._months,a._bubble()}function nc(a,b){return mc(this,a,b,1)}function oc(a,b){return mc(this,a,b,-1)}function pc(){var a,b,c,d=this._milliseconds,e=this._days,f=this._months,g=this._data,h=0;return g.milliseconds=d%1e3,a=fb(d/1e3),g.seconds=a%60,b=fb(a/60),g.minutes=b%60,c=fb(b/60),g.hours=c%24,e+=fb(c/24),h=fb(qc(e)),e-=fb(rc(h)),f+=fb(e/30),e%=30,h+=fb(f/12),f%=12,g.days=e,g.months=f,g.years=h,this}function qc(a){return 400*a/146097}function rc(a){return 146097*a/400}function sc(a){var b,c,d=this._milliseconds;if(a=z(a),"month"===a||"year"===a)return b=this._days+d/864e5,c=this._months+12*qc(b),"month"===a?c:c/12;switch(b=this._days+Math.round(rc(this._months/12)),a){case"week":return b/7+d/6048e5;case"day":return b+d/864e5;case"hour":return 24*b+d/36e5;case"minute":return 1440*b+d/6e4;case"second":return 86400*b+d/1e3;case"millisecond":return Math.floor(864e5*b)+d;default:throw new Error("Unknown unit "+a)}}function tc(){return this._milliseconds+864e5*this._days+this._months%12*2592e6+31536e6*p(this._months/12)}function uc(a){return function(){return this.as(a)}}function vc(a){return a=z(a),this[a+"s"]()}function wc(a){return function(){return this._data[a]}}function xc(){return fb(this.days()/7)}function yc(a,b,c,d,e){return e.relativeTime(b||1,!!c,a,d)}function zc(a,b,c){var d=Va(a).abs(),e=fe(d.as("s")),f=fe(d.as("m")),g=fe(d.as("h")),h=fe(d.as("d")),i=fe(d.as("M")),j=fe(d.as("y")),k=e0,k[4]=c,yc.apply(null,k)}function Ac(a,b){return void 0===ge[a]?!1:void 0===b?ge[a]:(ge[a]=b,!0)}function Bc(a){var b=this.localeData(),c=zc(this,!a,b);return a&&(c=b.pastFuture(+this,c)),b.postformat(c)}function Cc(){var a=he(this.years()),b=he(this.months()),c=he(this.days()),d=he(this.hours()),e=he(this.minutes()),f=he(this.seconds()+this.milliseconds()/1e3),g=this.asSeconds();return g?(0>g?"-":"")+"P"+(a?a+"Y":"")+(b?b+"M":"")+(c?c+"D":"")+(d||e||f?"T":"")+(d?d+"H":"")+(e?e+"M":"")+(f?f+"S":""):"P0D"}var Dc,Ec,Fc=a.momentProperties=[],Gc=!1,Hc={},Ic={},Jc=/(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Q|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|mm?|ss?|S{1,4}|x|X|zz?|ZZ?|.)/g,Kc=/(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g,Lc={},Mc={},Nc=/\d/,Oc=/\d\d/,Pc=/\d{3}/,Qc=/\d{4}/,Rc=/[+-]?\d{6}/,Sc=/\d\d?/,Tc=/\d{1,3}/,Uc=/\d{1,4}/,Vc=/[+-]?\d{1,6}/,Wc=/\d+/,Xc=/[+-]?\d+/,Yc=/Z|[+-]\d\d:?\d\d/gi,Zc=/[+-]?\d+(\.\d{1,3})?/,$c=/[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i,_c={},ad={},bd=0,cd=1,dd=2,ed=3,fd=4,gd=5,hd=6;G("M",["MM",2],"Mo",function(){return this.month()+1}),G("MMM",0,0,function(a){return this.localeData().monthsShort(this,a)}),G("MMMM",0,0,function(a){return this.localeData().months(this,a)}),y("month","M"),L("M",Sc),L("MM",Sc,Oc),L("MMM",$c),L("MMMM",$c),O(["M","MM"],function(a,b){b[cd]=p(a)-1}),O(["MMM","MMMM"],function(a,b,c,d){var e=c._locale.monthsParse(a,d,c._strict);null!=e?b[cd]=e:j(c).invalidMonth=a});var id="January_February_March_April_May_June_July_August_September_October_November_December".split("_"),jd="Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),kd={};a.suppressDeprecationWarnings=!1;var ld=/^\s*(?:[+-]\d{6}|\d{4})-(?:(\d\d-\d\d)|(W\d\d$)|(W\d\d-\d)|(\d\d\d))((T| )(\d\d(:\d\d(:\d\d(\.\d+)?)?)?)?([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/,md=[["YYYYYY-MM-DD",/[+-]\d{6}-\d{2}-\d{2}/],["YYYY-MM-DD",/\d{4}-\d{2}-\d{2}/],["GGGG-[W]WW-E",/\d{4}-W\d{2}-\d/],["GGGG-[W]WW",/\d{4}-W\d{2}/],["YYYY-DDD",/\d{4}-\d{3}/]],nd=[["HH:mm:ss.SSSS",/(T| )\d\d:\d\d:\d\d\.\d+/],["HH:mm:ss",/(T| )\d\d:\d\d:\d\d/],["HH:mm",/(T| )\d\d:\d\d/],["HH",/(T| )\d\d/]],od=/^\/?Date\((\-?\d+)/i;a.createFromInputFallback=$("moment construction falls back to js Date. This is discouraged and will be removed in upcoming major release. Please refer to https://github.com/moment/moment/issues/1407 for more info.",function(a){a._d=new Date(a._i+(a._useUTC?" UTC":""))}),G(0,["YY",2],0,function(){return this.year()%100}),G(0,["YYYY",4],0,"year"),G(0,["YYYYY",5],0,"year"),G(0,["YYYYYY",6,!0],0,"year"),y("year","y"),L("Y",Xc),L("YY",Sc,Oc),L("YYYY",Uc,Qc),L("YYYYY",Vc,Rc),L("YYYYYY",Vc,Rc),O(["YYYY","YYYYY","YYYYYY"],bd),O("YY",function(b,c){c[bd]=a.parseTwoDigitYear(b)}),a.parseTwoDigitYear=function(a){return p(a)+(p(a)>68?1900:2e3)};var pd=B("FullYear",!1);G("w",["ww",2],"wo","week"),G("W",["WW",2],"Wo","isoWeek"),y("week","w"),y("isoWeek","W"),L("w",Sc),L("ww",Sc,Oc),L("W",Sc),L("WW",Sc,Oc),P(["w","ww","W","WW"],function(a,b,c,d){b[d.substr(0,1)]=p(a)});var qd={dow:0,doy:6};G("DDD",["DDDD",3],"DDDo","dayOfYear"),y("dayOfYear","DDD"),L("DDD",Tc),L("DDDD",Pc),O(["DDD","DDDD"],function(a,b,c){c._dayOfYear=p(a)}),a.ISO_8601=function(){};var rd=$("moment().min is deprecated, use moment.min instead. https://github.com/moment/moment/issues/1548",function(){var a=Aa.apply(null,arguments);return this>a?this:a}),sd=$("moment().max is deprecated, use moment.max instead. https://github.com/moment/moment/issues/1548",function(){var a=Aa.apply(null,arguments);return a>this?this:a});Ga("Z",":"),Ga("ZZ",""),L("Z",Yc),L("ZZ",Yc),O(["Z","ZZ"],function(a,b,c){c._useUTC=!0,c._tzm=Ha(a)});var td=/([\+\-]|\d\d)/gi;a.updateOffset=function(){};var ud=/(\-)?(?:(\d*)\.)?(\d+)\:(\d+)(?:\:(\d+)\.?(\d{3})?)?/,vd=/^(-)?P(?:(?:([0-9,.]*)Y)?(?:([0-9,.]*)M)?(?:([0-9,.]*)D)?(?:T(?:([0-9,.]*)H)?(?:([0-9,.]*)M)?(?:([0-9,.]*)S)?)?|([0-9,.]*)W)$/;Va.fn=Ea.prototype;var wd=Za(1,"add"),xd=Za(-1,"subtract");a.defaultFormat="YYYY-MM-DDTHH:mm:ssZ";var yd=$("moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.",function(a){return void 0===a?this.localeData():this.locale(a)});G(0,["gg",2],0,function(){return this.weekYear()%100}),G(0,["GG",2],0,function(){return this.isoWeekYear()%100}),Ab("gggg","weekYear"),Ab("ggggg","weekYear"),Ab("GGGG","isoWeekYear"),Ab("GGGGG","isoWeekYear"),y("weekYear","gg"),y("isoWeekYear","GG"),L("G",Xc),L("g",Xc),L("GG",Sc,Oc),L("gg",Sc,Oc),L("GGGG",Uc,Qc),L("gggg",Uc,Qc),L("GGGGG",Vc,Rc),L("ggggg",Vc,Rc),P(["gggg","ggggg","GGGG","GGGGG"],function(a,b,c,d){b[d.substr(0,2)]=p(a)}),P(["gg","GG"],function(b,c,d,e){c[e]=a.parseTwoDigitYear(b)}),G("Q",0,0,"quarter"),y("quarter","Q"),L("Q",Nc),O("Q",function(a,b){b[cd]=3*(p(a)-1)}),G("D",["DD",2],"Do","date"),y("date","D"),L("D",Sc),L("DD",Sc,Oc),L("Do",function(a,b){return a?b._ordinalParse:b._ordinalParseLenient}),O(["D","DD"],dd),O("Do",function(a,b){b[dd]=p(a.match(Sc)[0],10)});var zd=B("Date",!0);G("d",0,"do","day"),G("dd",0,0,function(a){return this.localeData().weekdaysMin(this,a)}),G("ddd",0,0,function(a){return this.localeData().weekdaysShort(this,a)}),G("dddd",0,0,function(a){return this.localeData().weekdays(this,a)}),G("e",0,0,"weekday"),G("E",0,0,"isoWeekday"),y("day","d"),y("weekday","e"),y("isoWeekday","E"),L("d",Sc),L("e",Sc),L("E",Sc),L("dd",$c),L("ddd",$c),L("dddd",$c),P(["dd","ddd","dddd"],function(a,b,c){var d=c._locale.weekdaysParse(a);null!=d?b.d=d:j(c).invalidWeekday=a}),P(["d","e","E"],function(a,b,c,d){b[d]=p(a)});var Ad="Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),Bd="Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),Cd="Su_Mo_Tu_We_Th_Fr_Sa".split("_");G("H",["HH",2],0,"hour"),G("h",["hh",2],0,function(){return this.hours()%12||12}),Pb("a",!0),Pb("A",!1),y("hour","h"),L("a",Qb),L("A",Qb),L("H",Sc),L("h",Sc),L("HH",Sc,Oc),L("hh",Sc,Oc),O(["H","HH"],ed),O(["a","A"],function(a,b,c){c._isPm=c._locale.isPM(a),c._meridiem=a}),O(["h","hh"],function(a,b,c){b[ed]=p(a),j(c).bigHour=!0});var Dd=/[ap]\.?m?\.?/i,Ed=B("Hours",!0);G("m",["mm",2],0,"minute"),y("minute","m"),L("m",Sc),L("mm",Sc,Oc),O(["m","mm"],fd);var Fd=B("Minutes",!1);G("s",["ss",2],0,"second"),y("second","s"),L("s",Sc),L("ss",Sc,Oc),O(["s","ss"],gd);var Gd=B("Seconds",!1);G("S",0,0,function(){return~~(this.millisecond()/100)}),G(0,["SS",2],0,function(){return~~(this.millisecond()/10)}),Tb("SSS"),Tb("SSSS"),y("millisecond","ms"),L("S",Tc,Nc),L("SS",Tc,Oc),L("SSS",Tc,Pc),L("SSSS",Wc),O(["S","SS","SSS","SSSS"],function(a,b){b[hd]=p(1e3*("0."+a))});var Hd=B("Milliseconds",!1);G("z",0,0,"zoneAbbr"),G("zz",0,0,"zoneName");var Id=n.prototype;Id.add=wd,Id.calendar=_a,Id.clone=ab,Id.diff=gb,Id.endOf=sb,Id.format=kb,Id.from=lb,Id.fromNow=mb,Id.to=nb,Id.toNow=ob,Id.get=E,Id.invalidAt=zb,Id.isAfter=bb,Id.isBefore=cb,Id.isBetween=db,Id.isSame=eb,Id.isValid=xb,Id.lang=yd,Id.locale=pb,Id.localeData=qb,Id.max=sd,Id.min=rd,Id.parsingFlags=yb,Id.set=E,Id.startOf=rb,Id.subtract=xd,Id.toArray=wb,Id.toDate=vb,Id.toISOString=jb,Id.toJSON=jb,Id.toString=ib,Id.unix=ub,Id.valueOf=tb,Id.year=pd,Id.isLeapYear=ga,Id.weekYear=Cb,Id.isoWeekYear=Db,Id.quarter=Id.quarters=Gb,Id.month=W,Id.daysInMonth=X,Id.week=Id.weeks=la,Id.isoWeek=Id.isoWeeks=ma,Id.weeksInYear=Fb,Id.isoWeeksInYear=Eb,Id.date=zd,Id.day=Id.days=Mb,Id.weekday=Nb,Id.isoWeekday=Ob,Id.dayOfYear=oa,Id.hour=Id.hours=Ed,Id.minute=Id.minutes=Fd,Id.second=Id.seconds=Gd,Id.millisecond=Id.milliseconds=Hd,Id.utcOffset=Ka,Id.utc=Ma,Id.local=Na,Id.parseZone=Oa,Id.hasAlignedHourOffset=Pa,Id.isDST=Qa,Id.isDSTShifted=Ra,Id.isLocal=Sa,Id.isUtcOffset=Ta,Id.isUtc=Ua,Id.isUTC=Ua,Id.zoneAbbr=Ub,Id.zoneName=Vb,Id.dates=$("dates accessor is deprecated. Use date instead.",zd),Id.months=$("months accessor is deprecated. Use month instead",W),Id.years=$("years accessor is deprecated. Use year instead",pd),Id.zone=$("moment().zone is deprecated, use moment().utcOffset instead. https://github.com/moment/moment/issues/1779",La);var Jd=Id,Kd={sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},Ld={LTS:"h:mm:ss A",LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY LT",LLLL:"dddd, MMMM D, YYYY LT"},Md="Invalid date",Nd="%d",Od=/\d{1,2}/,Pd={future:"in %s",past:"%s ago",s:"a few seconds",m:"a minute",mm:"%d minutes",h:"an hour", 7 | hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},Qd=r.prototype;Qd._calendar=Kd,Qd.calendar=Yb,Qd._longDateFormat=Ld,Qd.longDateFormat=Zb,Qd._invalidDate=Md,Qd.invalidDate=$b,Qd._ordinal=Nd,Qd.ordinal=_b,Qd._ordinalParse=Od,Qd.preparse=ac,Qd.postformat=ac,Qd._relativeTime=Pd,Qd.relativeTime=bc,Qd.pastFuture=cc,Qd.set=dc,Qd.months=S,Qd._months=id,Qd.monthsShort=T,Qd._monthsShort=jd,Qd.monthsParse=U,Qd.week=ia,Qd._week=qd,Qd.firstDayOfYear=ka,Qd.firstDayOfWeek=ja,Qd.weekdays=Ib,Qd._weekdays=Ad,Qd.weekdaysMin=Kb,Qd._weekdaysMin=Cd,Qd.weekdaysShort=Jb,Qd._weekdaysShort=Bd,Qd.weekdaysParse=Lb,Qd.isPM=Rb,Qd._meridiemParse=Dd,Qd.meridiem=Sb,v("en",{ordinalParse:/\d{1,2}(th|st|nd|rd)/,ordinal:function(a){var b=a%10,c=1===p(a%100/10)?"th":1===b?"st":2===b?"nd":3===b?"rd":"th";return a+c}}),a.lang=$("moment.lang is deprecated. Use moment.locale instead.",v),a.langData=$("moment.langData is deprecated. Use moment.localeData instead.",x);var Rd=Math.abs,Sd=uc("ms"),Td=uc("s"),Ud=uc("m"),Vd=uc("h"),Wd=uc("d"),Xd=uc("w"),Yd=uc("M"),Zd=uc("y"),$d=wc("milliseconds"),_d=wc("seconds"),ae=wc("minutes"),be=wc("hours"),ce=wc("days"),de=wc("months"),ee=wc("years"),fe=Math.round,ge={s:45,m:45,h:22,d:26,M:11},he=Math.abs,ie=Ea.prototype;ie.abs=lc,ie.add=nc,ie.subtract=oc,ie.as=sc,ie.asMilliseconds=Sd,ie.asSeconds=Td,ie.asMinutes=Ud,ie.asHours=Vd,ie.asDays=Wd,ie.asWeeks=Xd,ie.asMonths=Yd,ie.asYears=Zd,ie.valueOf=tc,ie._bubble=pc,ie.get=vc,ie.milliseconds=$d,ie.seconds=_d,ie.minutes=ae,ie.hours=be,ie.days=ce,ie.weeks=xc,ie.months=de,ie.years=ee,ie.humanize=Bc,ie.toISOString=Cc,ie.toString=Cc,ie.toJSON=Cc,ie.locale=pb,ie.localeData=qb,ie.toIsoString=$("toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)",Cc),ie.lang=yd,G("X",0,0,"unix"),G("x",0,0,"valueOf"),L("x",Xc),L("X",Zc),O("X",function(a,b,c){c._d=new Date(1e3*parseFloat(a,10))}),O("x",function(a,b,c){c._d=new Date(p(a))}),a.version="2.10.3",b(Aa),a.fn=Jd,a.min=Ca,a.max=Da,a.utc=h,a.unix=Wb,a.months=gc,a.isDate=d,a.locale=v,a.invalid=l,a.duration=Va,a.isMoment=o,a.weekdays=ic,a.parseZone=Xb,a.localeData=x,a.isDuration=Fa,a.monthsShort=hc,a.weekdaysMin=kc,a.defineLocale=w,a.weekdaysShort=jc,a.normalizeUnits=z,a.relativeTimeThreshold=Ac;var je=a;return je}); -------------------------------------------------------------------------------- /static/js/bootstrap-datetimepicker-4.14.30.min.js: -------------------------------------------------------------------------------- 1 | /*! version : 4.14.30 2 | ========================================================= 3 | bootstrap-datetimejs 4 | https://github.com/Eonasdan/bootstrap-datetimepicker 5 | Copyright (c) 2015 Jonathan Peterson 6 | ========================================================= 7 | */ 8 | !function(a){"use strict";if("function"==typeof define&&define.amd)define(["jquery","moment"],a);else if("object"==typeof exports)a(require("jquery"),require("moment"));else{if("undefined"==typeof jQuery)throw"bootstrap-datetimepicker requires jQuery to be loaded first";if("undefined"==typeof moment)throw"bootstrap-datetimepicker requires Moment.js to be loaded first";a(jQuery,moment)}}(function(a,b){"use strict";if(!b)throw new Error("bootstrap-datetimepicker requires Moment.js to be loaded first");var c=function(c,d){var e,f,g,h,i,j={},k=b().startOf("d"),l=k.clone(),m=!0,n=!1,o=!1,p=0,q=[{clsName:"days",navFnc:"M",navStep:1},{clsName:"months",navFnc:"y",navStep:1},{clsName:"years",navFnc:"y",navStep:10},{clsName:"decades",navFnc:"y",navStep:100}],r=["days","months","years","decades"],s=["top","bottom","auto"],t=["left","right","auto"],u=["default","top","bottom"],v={up:38,38:"up",down:40,40:"down",left:37,37:"left",right:39,39:"right",tab:9,9:"tab",escape:27,27:"escape",enter:13,13:"enter",pageUp:33,33:"pageUp",pageDown:34,34:"pageDown",shift:16,16:"shift",control:17,17:"control",space:32,32:"space",t:84,84:"t","delete":46,46:"delete"},w={},x=function(a){if("string"!=typeof a||a.length>1)throw new TypeError("isEnabled expects a single character string parameter");switch(a){case"y":return-1!==g.indexOf("Y");case"M":return-1!==g.indexOf("M");case"d":return-1!==g.toLowerCase().indexOf("d");case"h":case"H":return-1!==g.toLowerCase().indexOf("h");case"m":return-1!==g.indexOf("m");case"s":return-1!==g.indexOf("s");default:return!1}},y=function(){return x("h")||x("m")||x("s")},z=function(){return x("y")||x("M")||x("d")},A=function(){var b=a("").append(a("").append(a("").addClass("prev").attr("data-action","previous").append(a("").addClass(d.icons.previous))).append(a("").addClass("picker-switch").attr("data-action","pickerSwitch").attr("colspan",d.calendarWeeks?"6":"5")).append(a("").addClass("next").attr("data-action","next").append(a("").addClass(d.icons.next)))),c=a("").append(a("").append(a("").attr("colspan",d.calendarWeeks?"8":"7")));return[a("
").addClass("datepicker-days").append(a("").addClass("table-condensed").append(b).append(a(""))),a("
").addClass("datepicker-months").append(a("
").addClass("table-condensed").append(b.clone()).append(c.clone())),a("
").addClass("datepicker-years").append(a("
").addClass("table-condensed").append(b.clone()).append(c.clone())),a("
").addClass("datepicker-decades").append(a("
").addClass("table-condensed").append(b.clone()).append(c.clone()))]},B=function(){var b=a(""),c=a(""),e=a("");return x("h")&&(b.append(a("
").append(a("").attr({href:"#",tabindex:"-1",title:"Increment Hour"}).addClass("btn").attr("data-action","incrementHours").append(a("").addClass(d.icons.up)))),c.append(a("").append(a("").addClass("timepicker-hour").attr({"data-time-component":"hours",title:"Pick Hour"}).attr("data-action","showHours"))),e.append(a("").append(a("").attr({href:"#",tabindex:"-1",title:"Decrement Hour"}).addClass("btn").attr("data-action","decrementHours").append(a("").addClass(d.icons.down))))),x("m")&&(x("h")&&(b.append(a("").addClass("separator")),c.append(a("").addClass("separator").html(":")),e.append(a("").addClass("separator"))),b.append(a("").append(a("").attr({href:"#",tabindex:"-1",title:"Increment Minute"}).addClass("btn").attr("data-action","incrementMinutes").append(a("").addClass(d.icons.up)))),c.append(a("").append(a("").addClass("timepicker-minute").attr({"data-time-component":"minutes",title:"Pick Minute"}).attr("data-action","showMinutes"))),e.append(a("").append(a("").attr({href:"#",tabindex:"-1",title:"Decrement Minute"}).addClass("btn").attr("data-action","decrementMinutes").append(a("").addClass(d.icons.down))))),x("s")&&(x("m")&&(b.append(a("").addClass("separator")),c.append(a("").addClass("separator").html(":")),e.append(a("").addClass("separator"))),b.append(a("").append(a("").attr({href:"#",tabindex:"-1",title:"Increment Second"}).addClass("btn").attr("data-action","incrementSeconds").append(a("").addClass(d.icons.up)))),c.append(a("").append(a("").addClass("timepicker-second").attr({"data-time-component":"seconds",title:"Pick Second"}).attr("data-action","showSeconds"))),e.append(a("").append(a("").attr({href:"#",tabindex:"-1",title:"Decrement Second"}).addClass("btn").attr("data-action","decrementSeconds").append(a("").addClass(d.icons.down))))),f||(b.append(a("").addClass("separator")),c.append(a("").append(a("").addClass("separator"))),a("
").addClass("timepicker-picker").append(a("").addClass("table-condensed").append([b,c,e]))},C=function(){var b=a("
").addClass("timepicker-hours").append(a("
").addClass("table-condensed")),c=a("
").addClass("timepicker-minutes").append(a("
").addClass("table-condensed")),d=a("
").addClass("timepicker-seconds").append(a("
").addClass("table-condensed")),e=[B()];return x("h")&&e.push(b),x("m")&&e.push(c),x("s")&&e.push(d),e},D=function(){var b=[];return d.showTodayButton&&b.push(a("
").append(a("").attr({"data-action":"today",title:"Go to today"}).append(a("").addClass(d.icons.today)))),!d.sideBySide&&z()&&y()&&b.push(a("").append(a("").attr({"data-action":"togglePicker",title:"Select Time"}).append(a("").addClass(d.icons.time)))),d.showClear&&b.push(a("").append(a("").attr({"data-action":"clear",title:"Clear selection"}).append(a("").addClass(d.icons.clear)))),d.showClose&&b.push(a("").append(a("").attr({"data-action":"close",title:"Close the picker"}).append(a("").addClass(d.icons.close)))),a("").addClass("table-condensed").append(a("").append(a("").append(b)))},E=function(){var b=a("
").addClass("bootstrap-datetimepicker-widget dropdown-menu"),c=a("
").addClass("datepicker").append(A()),e=a("
").addClass("timepicker").append(C()),g=a("
    ").addClass("list-unstyled"),h=a("
  • ").addClass("picker-switch"+(d.collapse?" accordion-toggle":"")).append(D());return d.inline&&b.removeClass("dropdown-menu"),f&&b.addClass("usetwentyfour"),x("s")&&!f&&b.addClass("wider"),d.sideBySide&&z()&&y()?(b.addClass("timepicker-sbs"),b.append(a("
    ").addClass("row").append(c.addClass("col-sm-6")).append(e.addClass("col-sm-6"))),b.append(h),b):("top"===d.toolbarPlacement&&g.append(h),z()&&g.append(a("
  • ").addClass(d.collapse&&y()?"collapse in":"").append(c)),"default"===d.toolbarPlacement&&g.append(h),y()&&g.append(a("
  • ").addClass(d.collapse&&z()?"collapse":"").append(e)),"bottom"===d.toolbarPlacement&&g.append(h),b.append(g))},F=function(){var b,e={};return b=c.is("input")||d.inline?c.data():c.find("input").data(),b.dateOptions&&b.dateOptions instanceof Object&&(e=a.extend(!0,e,b.dateOptions)),a.each(d,function(a){var c="date"+a.charAt(0).toUpperCase()+a.slice(1);void 0!==b[c]&&(e[a]=b[c])}),e},G=function(){var b,e=(n||c).position(),f=(n||c).offset(),g=d.widgetPositioning.vertical,h=d.widgetPositioning.horizontal;if(d.widgetParent)b=d.widgetParent.append(o);else if(c.is("input"))b=c.after(o).parent();else{if(d.inline)return void(b=c.append(o));b=c,c.children().first().after(o)}if("auto"===g&&(g=f.top+1.5*o.height()>=a(window).height()+a(window).scrollTop()&&o.height()+c.outerHeight()a(window).width()?"right":"left"),"top"===g?o.addClass("top").removeClass("bottom"):o.addClass("bottom").removeClass("top"),"right"===h?o.addClass("pull-right"):o.removeClass("pull-right"),"relative"!==b.css("position")&&(b=b.parents().filter(function(){return"relative"===a(this).css("position")}).first()),0===b.length)throw new Error("datetimepicker component should be placed within a relative positioned container");o.css({top:"top"===g?"auto":e.top+c.outerHeight(),bottom:"top"===g?e.top+c.outerHeight():"auto",left:"left"===h?b===c?0:e.left:"auto",right:"left"===h?"auto":b.outerWidth()-c.outerWidth()-(b===c?0:e.left)})},H=function(a){"dp.change"===a.type&&(a.date&&a.date.isSame(a.oldDate)||!a.date&&!a.oldDate)||c.trigger(a)},I=function(a){"y"===a&&(a="YYYY"),H({type:"dp.update",change:a,viewDate:l.clone()})},J=function(a){o&&(a&&(i=Math.max(p,Math.min(3,i+a))),o.find(".datepicker > div").hide().filter(".datepicker-"+q[i].clsName).show())},K=function(){var b=a("
"),c=l.clone().startOf("w").startOf("d");for(d.calendarWeeks===!0&&b.append(a(""),d.calendarWeeks&&e.append('"),j.push(e)),f="",c.isBefore(l,"M")&&(f+=" old"),c.isAfter(l,"M")&&(f+=" new"),c.isSame(k,"d")&&!m&&(f+=" active"),P(c,"d")||(f+=" disabled"),c.isSame(b(),"d")&&(f+=" today"),(0===c.day()||6===c.day())&&(f+=" weekend"),e.append('"),c.add(1,"d");h.find("tbody").empty().append(j),R(),S(),T()}},V=function(){var b=o.find(".timepicker-hours table"),c=l.clone().startOf("d"),d=[],e=a("");for(l.hour()>11&&!f&&c.hour(12);c.isSame(l,"d")&&(f||l.hour()<12&&c.hour()<12||l.hour()>11);)c.hour()%4===0&&(e=a(""),d.push(e)),e.append('"),c.add(1,"h");b.empty().append(d)},W=function(){for(var b=o.find(".timepicker-minutes table"),c=l.clone().startOf("h"),e=[],f=a(""),g=1===d.stepping?5:d.stepping;l.isSame(c,"h");)c.minute()%(4*g)===0&&(f=a(""),e.push(f)),f.append('"),c.add(g,"m");b.empty().append(e)},X=function(){for(var b=o.find(".timepicker-seconds table"),c=l.clone().startOf("m"),d=[],e=a("");l.isSame(c,"m");)c.second()%20===0&&(e=a(""),d.push(e)),e.append('"),c.add(5,"s");b.empty().append(d)},Y=function(){var a,b,c=o.find(".timepicker span[data-time-component]");f||(a=o.find(".timepicker [data-action=togglePeriod]"),b=k.clone().add(k.hours()>=12?-12:12,"h"),a.text(k.format("A")),P(b,"h")?a.removeClass("disabled"):a.addClass("disabled")),c.filter("[data-time-component=hours]").text(k.format(f?"HH":"hh")),c.filter("[data-time-component=minutes]").text(k.format("mm")),c.filter("[data-time-component=seconds]").text(k.format("ss")),V(),W(),X()},Z=function(){o&&(U(),Y())},$=function(a){var b=m?null:k;return a?(a=a.clone().locale(d.locale),1!==d.stepping&&a.minutes(Math.round(a.minutes()/d.stepping)*d.stepping%60).seconds(0),void(P(a)?(k=a,l=k.clone(),e.val(k.format(g)),c.data("date",k.format(g)),m=!1,Z(),H({type:"dp.change",date:k.clone(),oldDate:b})):(d.keepInvalid||e.val(m?"":k.format(g)),H({type:"dp.error",date:a})))):(m=!0,e.val(""),c.data("date",""),H({type:"dp.change",date:!1,oldDate:b}),void Z())},_=function(){var b=!1;return o?(o.find(".collapse").each(function(){var c=a(this).data("collapse");return c&&c.transitioning?(b=!0,!1):!0}),b?j:(n&&n.hasClass("btn")&&n.toggleClass("active"),o.hide(),a(window).off("resize",G),o.off("click","[data-action]"),o.off("mousedown",!1),o.remove(),o=!1,H({type:"dp.hide",date:k.clone()}),j)):j},aa=function(){$(null)},ba={next:function(){var a=q[i].navFnc;l.add(q[i].navStep,a),U(),I(a)},previous:function(){var a=q[i].navFnc;l.subtract(q[i].navStep,a),U(),I(a)},pickerSwitch:function(){J(1)},selectMonth:function(b){var c=a(b.target).closest("tbody").find("span").index(a(b.target));l.month(c),i===p?($(k.clone().year(l.year()).month(l.month())),d.inline||_()):(J(-1),U()),I("M")},selectYear:function(b){var c=parseInt(a(b.target).text(),10)||0;l.year(c),i===p?($(k.clone().year(l.year())),d.inline||_()):(J(-1),U()),I("YYYY")},selectDecade:function(b){var c=parseInt(a(b.target).data("selection"),10)||0;l.year(c),i===p?($(k.clone().year(l.year())),d.inline||_()):(J(-1),U()),I("YYYY")},selectDay:function(b){var c=l.clone();a(b.target).is(".old")&&c.subtract(1,"M"),a(b.target).is(".new")&&c.add(1,"M"),$(c.date(parseInt(a(b.target).text(),10))),y()||d.keepOpen||d.inline||_()},incrementHours:function(){var a=k.clone().add(1,"h");P(a,"h")&&$(a)},incrementMinutes:function(){var a=k.clone().add(d.stepping,"m");P(a,"m")&&$(a)},incrementSeconds:function(){var a=k.clone().add(1,"s");P(a,"s")&&$(a)},decrementHours:function(){var a=k.clone().subtract(1,"h");P(a,"h")&&$(a)},decrementMinutes:function(){var a=k.clone().subtract(d.stepping,"m");P(a,"m")&&$(a)},decrementSeconds:function(){var a=k.clone().subtract(1,"s");P(a,"s")&&$(a)},togglePeriod:function(){$(k.clone().add(k.hours()>=12?-12:12,"h"))},togglePicker:function(b){var c,e=a(b.target),f=e.closest("ul"),g=f.find(".in"),h=f.find(".collapse:not(.in)");if(g&&g.length){if(c=g.data("collapse"),c&&c.transitioning)return;g.collapse?(g.collapse("hide"),h.collapse("show")):(g.removeClass("in"),h.addClass("in")),e.is("span")?e.toggleClass(d.icons.time+" "+d.icons.date):e.find("span").toggleClass(d.icons.time+" "+d.icons.date)}},showPicker:function(){o.find(".timepicker > div:not(.timepicker-picker)").hide(),o.find(".timepicker .timepicker-picker").show()},showHours:function(){o.find(".timepicker .timepicker-picker").hide(),o.find(".timepicker .timepicker-hours").show()},showMinutes:function(){o.find(".timepicker .timepicker-picker").hide(),o.find(".timepicker .timepicker-minutes").show()},showSeconds:function(){o.find(".timepicker .timepicker-picker").hide(),o.find(".timepicker .timepicker-seconds").show()},selectHour:function(b){var c=parseInt(a(b.target).text(),10);f||(k.hours()>=12?12!==c&&(c+=12):12===c&&(c=0)),$(k.clone().hours(c)),ba.showPicker.call(j)},selectMinute:function(b){$(k.clone().minutes(parseInt(a(b.target).text(),10))),ba.showPicker.call(j)},selectSecond:function(b){$(k.clone().seconds(parseInt(a(b.target).text(),10))),ba.showPicker.call(j)},clear:aa,today:function(){P(b(),"d")&&$(b())},close:_},ca=function(b){return a(b.currentTarget).is(".disabled")?!1:(ba[a(b.currentTarget).data("action")].apply(j,arguments),!1)},da=function(){var c,f={year:function(a){return a.month(0).date(1).hours(0).seconds(0).minutes(0)},month:function(a){return a.date(1).hours(0).seconds(0).minutes(0)},day:function(a){return a.hours(0).seconds(0).minutes(0)},hour:function(a){return a.seconds(0).minutes(0)},minute:function(a){return a.seconds(0)}};return e.prop("disabled")||!d.ignoreReadonly&&e.prop("readonly")||o?j:(void 0!==e.val()&&0!==e.val().trim().length?$(fa(e.val().trim())):d.useCurrent&&m&&(e.is("input")&&0===e.val().trim().length||d.inline)&&(c=b(),"string"==typeof d.useCurrent&&(c=f[d.useCurrent](c)),$(c)),o=E(),K(),Q(),o.find(".timepicker-hours").hide(),o.find(".timepicker-minutes").hide(),o.find(".timepicker-seconds").hide(),Z(),J(),a(window).on("resize",G),o.on("click","[data-action]",ca),o.on("mousedown",!1),n&&n.hasClass("btn")&&n.toggleClass("active"),o.show(),G(),d.focusOnShow&&!e.is(":focus")&&e.focus(),H({type:"dp.show"}),j)},ea=function(){return o?_():da()},fa=function(a){return a=b.isMoment(a)||a instanceof Date?b(a):b(a,h,d.useStrict),a.locale(d.locale),a},ga=function(a){var b,c,e,f,g=null,h=[],i={},k=a.which,l="p";w[k]=l;for(b in w)w.hasOwnProperty(b)&&w[b]===l&&(h.push(b),parseInt(b,10)!==k&&(i[b]=!0));for(b in d.keyBinds)if(d.keyBinds.hasOwnProperty(b)&&"function"==typeof d.keyBinds[b]&&(e=b.split(" "),e.length===h.length&&v[k]===e[e.length-1])){for(f=!0,c=e.length-2;c>=0;c--)if(!(v[e[c]]in i)){f=!1;break}if(f){g=d.keyBinds[b];break}}g&&(g.call(j,o),a.stopPropagation(),a.preventDefault())},ha=function(a){w[a.which]="r",a.stopPropagation(),a.preventDefault()},ia=function(b){var c=a(b.target).val().trim(),d=c?fa(c):null;return $(d),b.stopImmediatePropagation(),!1},ja=function(){e.on({change:ia,blur:d.debug?"":_,keydown:ga,keyup:ha,focus:d.allowInputToggle?da:""}),c.is("input")?e.on({focus:da}):n&&(n.on("click",ea),n.on("mousedown",!1))},ka=function(){e.off({change:ia,blur:_,keydown:ga,keyup:ha,focus:d.allowInputToggle?_:""}),c.is("input")?e.off({focus:da}):n&&(n.off("click",ea),n.off("mousedown",!1))},la=function(b){var c={};return a.each(b,function(){var a=fa(this);a.isValid()&&(c[a.format("YYYY-MM-DD")]=!0)}),Object.keys(c).length?c:!1},ma=function(b){var c={};return a.each(b,function(){c[this]=!0}),Object.keys(c).length?c:!1},na=function(){var a=d.format||"L LT";g=a.replace(/(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g,function(a){var b=k.localeData().longDateFormat(a)||a;return b.replace(/(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g,function(a){return k.localeData().longDateFormat(a)||a})}),h=d.extraFormats?d.extraFormats.slice():[],h.indexOf(a)<0&&h.indexOf(g)<0&&h.push(g),f=g.toLowerCase().indexOf("a")<1&&g.replace(/\[.*?\]/g,"").indexOf("h")<1,x("y")&&(p=2),x("M")&&(p=1),x("d")&&(p=0),i=Math.max(p,i),m||$(k)};if(j.destroy=function(){_(),ka(),c.removeData("DateTimePicker"),c.removeData("date")},j.toggle=ea,j.show=da,j.hide=_,j.disable=function(){return _(),n&&n.hasClass("btn")&&n.addClass("disabled"),e.prop("disabled",!0),j},j.enable=function(){return n&&n.hasClass("btn")&&n.removeClass("disabled"),e.prop("disabled",!1),j},j.ignoreReadonly=function(a){if(0===arguments.length)return d.ignoreReadonly;if("boolean"!=typeof a)throw new TypeError("ignoreReadonly () expects a boolean parameter");return d.ignoreReadonly=a,j},j.options=function(b){if(0===arguments.length)return a.extend(!0,{},d);if(!(b instanceof Object))throw new TypeError("options() options parameter should be an object");return a.extend(!0,d,b),a.each(d,function(a,b){if(void 0===j[a])throw new TypeError("option "+a+" is not recognized!");j[a](b)}),j},j.date=function(a){if(0===arguments.length)return m?null:k.clone();if(!(null===a||"string"==typeof a||b.isMoment(a)||a instanceof Date))throw new TypeError("date() parameter must be one of [null, string, moment or Date]");return $(null===a?null:fa(a)),j},j.format=function(a){if(0===arguments.length)return d.format;if("string"!=typeof a&&("boolean"!=typeof a||a!==!1))throw new TypeError("format() expects a sting or boolean:false parameter "+a);return d.format=a,g&&na(),j},j.dayViewHeaderFormat=function(a){if(0===arguments.length)return d.dayViewHeaderFormat;if("string"!=typeof a)throw new TypeError("dayViewHeaderFormat() expects a string parameter");return d.dayViewHeaderFormat=a,j},j.extraFormats=function(a){if(0===arguments.length)return d.extraFormats;if(a!==!1&&!(a instanceof Array))throw new TypeError("extraFormats() expects an array or false parameter");return d.extraFormats=a,h&&na(),j},j.disabledDates=function(b){if(0===arguments.length)return d.disabledDates?a.extend({},d.disabledDates):d.disabledDates;if(!b)return d.disabledDates=!1,Z(),j;if(!(b instanceof Array))throw new TypeError("disabledDates() expects an array parameter");return d.disabledDates=la(b),d.enabledDates=!1,Z(),j},j.enabledDates=function(b){if(0===arguments.length)return d.enabledDates?a.extend({},d.enabledDates):d.enabledDates;if(!b)return d.enabledDates=!1,Z(),j;if(!(b instanceof Array))throw new TypeError("enabledDates() expects an array parameter");return d.enabledDates=la(b),d.disabledDates=!1,Z(),j},j.daysOfWeekDisabled=function(a){if(0===arguments.length)return d.daysOfWeekDisabled.splice(0);if("boolean"==typeof a&&!a)return d.daysOfWeekDisabled=!1,Z(),j;if(!(a instanceof Array))throw new TypeError("daysOfWeekDisabled() expects an array parameter");if(d.daysOfWeekDisabled=a.reduce(function(a,b){return b=parseInt(b,10),b>6||0>b||isNaN(b)?a:(-1===a.indexOf(b)&&a.push(b),a)},[]).sort(),d.useCurrent&&!d.keepInvalid){for(var b=0;!P(k,"d");){if(k.add(1,"d"),7===b)throw"Tried 7 times to find a valid date";b++}$(k)}return Z(),j},j.maxDate=function(a){if(0===arguments.length)return d.maxDate?d.maxDate.clone():d.maxDate;if("boolean"==typeof a&&a===!1)return d.maxDate=!1,Z(),j;"string"==typeof a&&("now"===a||"moment"===a)&&(a=b());var c=fa(a);if(!c.isValid())throw new TypeError("maxDate() Could not parse date parameter: "+a);if(d.minDate&&c.isBefore(d.minDate))throw new TypeError("maxDate() date parameter is before options.minDate: "+c.format(g));return d.maxDate=c,d.useCurrent&&!d.keepInvalid&&k.isAfter(a)&&$(d.maxDate),l.isAfter(c)&&(l=c.clone()),Z(),j},j.minDate=function(a){if(0===arguments.length)return d.minDate?d.minDate.clone():d.minDate;if("boolean"==typeof a&&a===!1)return d.minDate=!1,Z(),j;"string"==typeof a&&("now"===a||"moment"===a)&&(a=b());var c=fa(a);if(!c.isValid())throw new TypeError("minDate() Could not parse date parameter: "+a);if(d.maxDate&&c.isAfter(d.maxDate))throw new TypeError("minDate() date parameter is after options.maxDate: "+c.format(g));return d.minDate=c,d.useCurrent&&!d.keepInvalid&&k.isBefore(a)&&$(d.minDate),l.isBefore(c)&&(l=c.clone()),Z(),j},j.defaultDate=function(a){if(0===arguments.length)return d.defaultDate?d.defaultDate.clone():d.defaultDate;if(!a)return d.defaultDate=!1,j;"string"==typeof a&&("now"===a||"moment"===a)&&(a=b());var c=fa(a);if(!c.isValid())throw new TypeError("defaultDate() Could not parse date parameter: "+a);if(!P(c))throw new TypeError("defaultDate() date passed is invalid according to component setup validations");return d.defaultDate=c,(d.defaultDate&&d.inline||""===e.val().trim()&&void 0===e.attr("placeholder"))&&$(d.defaultDate),j},j.locale=function(a){if(0===arguments.length)return d.locale;if(!b.localeData(a))throw new TypeError("locale() locale "+a+" is not loaded from moment locales!");return d.locale=a,k.locale(d.locale),l.locale(d.locale),g&&na(),o&&(_(),da()),j},j.stepping=function(a){return 0===arguments.length?d.stepping:(a=parseInt(a,10),(isNaN(a)||1>a)&&(a=1),d.stepping=a,j)},j.useCurrent=function(a){var b=["year","month","day","hour","minute"];if(0===arguments.length)return d.useCurrent;if("boolean"!=typeof a&&"string"!=typeof a)throw new TypeError("useCurrent() expects a boolean or string parameter");if("string"==typeof a&&-1===b.indexOf(a.toLowerCase()))throw new TypeError("useCurrent() expects a string parameter of "+b.join(", "));return d.useCurrent=a,j},j.collapse=function(a){if(0===arguments.length)return d.collapse;if("boolean"!=typeof a)throw new TypeError("collapse() expects a boolean parameter");return d.collapse===a?j:(d.collapse=a,o&&(_(),da()),j)},j.icons=function(b){if(0===arguments.length)return a.extend({},d.icons);if(!(b instanceof Object))throw new TypeError("icons() expects parameter to be an Object");return a.extend(d.icons,b),o&&(_(),da()),j},j.useStrict=function(a){if(0===arguments.length)return d.useStrict;if("boolean"!=typeof a)throw new TypeError("useStrict() expects a boolean parameter");return d.useStrict=a,j},j.sideBySide=function(a){if(0===arguments.length)return d.sideBySide;if("boolean"!=typeof a)throw new TypeError("sideBySide() expects a boolean parameter");return d.sideBySide=a,o&&(_(),da()),j},j.viewMode=function(a){if(0===arguments.length)return d.viewMode;if("string"!=typeof a)throw new TypeError("viewMode() expects a string parameter");if(-1===r.indexOf(a))throw new TypeError("viewMode() parameter must be one of ("+r.join(", ")+") value");return d.viewMode=a,i=Math.max(r.indexOf(a),p),J(),j},j.toolbarPlacement=function(a){if(0===arguments.length)return d.toolbarPlacement;if("string"!=typeof a)throw new TypeError("toolbarPlacement() expects a string parameter");if(-1===u.indexOf(a))throw new TypeError("toolbarPlacement() parameter must be one of ("+u.join(", ")+") value");return d.toolbarPlacement=a,o&&(_(),da()),j},j.widgetPositioning=function(b){if(0===arguments.length)return a.extend({},d.widgetPositioning);if("[object Object]"!=={}.toString.call(b))throw new TypeError("widgetPositioning() expects an object variable");if(b.horizontal){if("string"!=typeof b.horizontal)throw new TypeError("widgetPositioning() horizontal variable must be a string");if(b.horizontal=b.horizontal.toLowerCase(),-1===t.indexOf(b.horizontal))throw new TypeError("widgetPositioning() expects horizontal parameter to be one of ("+t.join(", ")+")");d.widgetPositioning.horizontal=b.horizontal}if(b.vertical){if("string"!=typeof b.vertical)throw new TypeError("widgetPositioning() vertical variable must be a string");if(b.vertical=b.vertical.toLowerCase(),-1===s.indexOf(b.vertical))throw new TypeError("widgetPositioning() expects vertical parameter to be one of ("+s.join(", ")+")");d.widgetPositioning.vertical=b.vertical}return Z(),j},j.calendarWeeks=function(a){if(0===arguments.length)return d.calendarWeeks;if("boolean"!=typeof a)throw new TypeError("calendarWeeks() expects parameter to be a boolean value");return d.calendarWeeks=a,Z(),j},j.showTodayButton=function(a){if(0===arguments.length)return d.showTodayButton;if("boolean"!=typeof a)throw new TypeError("showTodayButton() expects a boolean parameter");return d.showTodayButton=a,o&&(_(),da()),j},j.showClear=function(a){if(0===arguments.length)return d.showClear;if("boolean"!=typeof a)throw new TypeError("showClear() expects a boolean parameter");return d.showClear=a,o&&(_(),da()),j},j.widgetParent=function(b){if(0===arguments.length)return d.widgetParent;if("string"==typeof b&&(b=a(b)),null!==b&&"string"!=typeof b&&!(b instanceof a))throw new TypeError("widgetParent() expects a string or a jQuery object parameter");return d.widgetParent=b,o&&(_(),da()),j},j.keepOpen=function(a){if(0===arguments.length)return d.keepOpen;if("boolean"!=typeof a)throw new TypeError("keepOpen() expects a boolean parameter");return d.keepOpen=a,j},j.focusOnShow=function(a){if(0===arguments.length)return d.focusOnShow;if("boolean"!=typeof a)throw new TypeError("focusOnShow() expects a boolean parameter");return d.focusOnShow=a,j},j.inline=function(a){if(0===arguments.length)return d.inline;if("boolean"!=typeof a)throw new TypeError("inline() expects a boolean parameter");return d.inline=a,j},j.clear=function(){return aa(),j},j.keyBinds=function(a){return d.keyBinds=a,j},j.debug=function(a){if("boolean"!=typeof a)throw new TypeError("debug() expects a boolean parameter");return d.debug=a,j},j.allowInputToggle=function(a){if(0===arguments.length)return d.allowInputToggle;if("boolean"!=typeof a)throw new TypeError("allowInputToggle() expects a boolean parameter");return d.allowInputToggle=a,j},j.showClose=function(a){if(0===arguments.length)return d.showClose;if("boolean"!=typeof a)throw new TypeError("showClose() expects a boolean parameter");return d.showClose=a,j},j.keepInvalid=function(a){if(0===arguments.length)return d.keepInvalid;if("boolean"!=typeof a)throw new TypeError("keepInvalid() expects a boolean parameter");return d.keepInvalid=a,j},j.datepickerInput=function(a){if(0===arguments.length)return d.datepickerInput;if("string"!=typeof a)throw new TypeError("datepickerInput() expects a string parameter");return d.datepickerInput=a,j},j.disabledTimeIntervals=function(b){if(0===arguments.length)return d.disabledTimeIntervals?a.extend({},d.disabledTimeIntervals):d.disabledTimeIntervals;if(!b)return d.disabledTimeIntervals=!1,Z(),j;if(!(b instanceof Array))throw new TypeError("disabledTimeIntervals() expects an array parameter");return d.disabledTimeIntervals=b,Z(),j},j.disabledHours=function(b){if(0===arguments.length)return d.disabledHours?a.extend({},d.disabledHours):d.disabledHours;if(!b)return d.disabledHours=!1,Z(),j;if(!(b instanceof Array))throw new TypeError("disabledHours() expects an array parameter");if(d.disabledHours=ma(b),d.enabledHours=!1,d.useCurrent&&!d.keepInvalid){for(var c=0;!P(k,"h");){if(k.add(1,"h"),24===c)throw"Tried 24 times to find a valid date";c++}$(k)}return Z(),j},j.enabledHours=function(b){if(0===arguments.length)return d.enabledHours?a.extend({},d.enabledHours):d.enabledHours;if(!b)return d.enabledHours=!1,Z(),j;if(!(b instanceof Array))throw new TypeError("enabledHours() expects an array parameter");if(d.enabledHours=ma(b),d.disabledHours=!1,d.useCurrent&&!d.keepInvalid){for(var c=0;!P(k,"h");){if(k.add(1,"h"),24===c)throw"Tried 24 times to find a valid date";c++}$(k); 9 | }return Z(),j},j.viewDate=function(a){if(0===arguments.length)return l.clone();if(!a)return l=k.clone(),j;if(!("string"==typeof a||b.isMoment(a)||a instanceof Date))throw new TypeError("viewDate() parameter must be one of [string, moment or Date]");return l=fa(a),I(),j},c.is("input"))e=c;else if(e=c.find(d.datepickerInput),0===e.size())e=c.find("input");else if(!e.is("input"))throw new Error('CSS class "'+d.datepickerInput+'" cannot be applied to non input element');if(c.hasClass("input-group")&&(n=0===c.find(".datepickerbutton").size()?c.find('[class^="input-group-"]'):c.find(".datepickerbutton")),!d.inline&&!e.is("input"))throw new Error("Could not initialize DateTimePicker without an input element");return a.extend(!0,d,F()),j.options(d),na(),ja(),e.prop("disabled")&&j.disable(),e.is("input")&&0!==e.val().trim().length?$(fa(e.val().trim())):d.defaultDate&&void 0===e.attr("placeholder")&&$(d.defaultDate),d.inline&&da(),j};a.fn.datetimepicker=function(b){return this.each(function(){var d=a(this);d.data("DateTimePicker")||(b=a.extend(!0,{},a.fn.datetimepicker.defaults,b),d.data("DateTimePicker",c(d,b)))})},a.fn.datetimepicker.defaults={format:!1,dayViewHeaderFormat:"MMMM YYYY",extraFormats:!1,stepping:1,minDate:!1,maxDate:!1,useCurrent:!0,collapse:!0,locale:b.locale(),defaultDate:!1,disabledDates:!1,enabledDates:!1,icons:{time:"glyphicon glyphicon-time",date:"glyphicon glyphicon-calendar",up:"glyphicon glyphicon-chevron-up",down:"glyphicon glyphicon-chevron-down",previous:"glyphicon glyphicon-chevron-left",next:"glyphicon glyphicon-chevron-right",today:"glyphicon glyphicon-screenshot",clear:"glyphicon glyphicon-trash",close:"glyphicon glyphicon-remove"},useStrict:!1,sideBySide:!1,daysOfWeekDisabled:!1,calendarWeeks:!1,viewMode:"days",toolbarPlacement:"default",showTodayButton:!1,showClear:!1,showClose:!1,widgetPositioning:{horizontal:"auto",vertical:"auto"},widgetParent:null,ignoreReadonly:!1,keepOpen:!1,focusOnShow:!0,inline:!1,keepInvalid:!1,datepickerInput:".datepickerinput",keyBinds:{up:function(a){if(a){var c=this.date()||b();a.find(".datepicker").is(":visible")?this.date(c.clone().subtract(7,"d")):this.date(c.clone().add(1,"m"))}},down:function(a){if(!a)return void this.show();var c=this.date()||b();a.find(".datepicker").is(":visible")?this.date(c.clone().add(7,"d")):this.date(c.clone().subtract(1,"m"))},"control up":function(a){if(a){var c=this.date()||b();a.find(".datepicker").is(":visible")?this.date(c.clone().subtract(1,"y")):this.date(c.clone().add(1,"h"))}},"control down":function(a){if(a){var c=this.date()||b();a.find(".datepicker").is(":visible")?this.date(c.clone().add(1,"y")):this.date(c.clone().subtract(1,"h"))}},left:function(a){if(a){var c=this.date()||b();a.find(".datepicker").is(":visible")&&this.date(c.clone().subtract(1,"d"))}},right:function(a){if(a){var c=this.date()||b();a.find(".datepicker").is(":visible")&&this.date(c.clone().add(1,"d"))}},pageUp:function(a){if(a){var c=this.date()||b();a.find(".datepicker").is(":visible")&&this.date(c.clone().subtract(1,"M"))}},pageDown:function(a){if(a){var c=this.date()||b();a.find(".datepicker").is(":visible")&&this.date(c.clone().add(1,"M"))}},enter:function(){this.hide()},escape:function(){this.hide()},"control space":function(a){a.find(".timepicker").is(":visible")&&a.find('.btn[data-action="togglePeriod"]').click()},t:function(){this.date(b())},"delete":function(){this.clear()}},debug:!1,allowInputToggle:!1,disabledTimeIntervals:!1,disabledHours:!1,enabledHours:!1,viewDate:!1}}); -------------------------------------------------------------------------------- /static/js/bootstrap-3.3.4.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v3.3.4 (http://getbootstrap.com) 3 | * Copyright 2011-2015 Twitter, Inc. 4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 5 | */ 6 | if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(a){"use strict";var b=a.fn.jquery.split(" ")[0].split(".");if(b[0]<2&&b[1]<9||1==b[0]&&9==b[1]&&b[2]<1)throw new Error("Bootstrap's JavaScript requires jQuery version 1.9.1 or higher")}(jQuery),+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]};return!1}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one("bsTransitionEnd",function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b(),a.support.transition&&(a.event.special.bsTransitionEnd={bindType:a.support.transition.end,delegateType:a.support.transition.end,handle:function(b){return a(b.target).is(this)?b.handleObj.handler.apply(this,arguments):void 0}})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var c=a(this),e=c.data("bs.alert");e||c.data("bs.alert",e=new d(this)),"string"==typeof b&&e[b].call(c)})}var c='[data-dismiss="alert"]',d=function(b){a(b).on("click",c,this.close)};d.VERSION="3.3.4",d.TRANSITION_DURATION=150,d.prototype.close=function(b){function c(){g.detach().trigger("closed.bs.alert").remove()}var e=a(this),f=e.attr("data-target");f||(f=e.attr("href"),f=f&&f.replace(/.*(?=#[^\s]*$)/,""));var g=a(f);b&&b.preventDefault(),g.length||(g=e.closest(".alert")),g.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(g.removeClass("in"),a.support.transition&&g.hasClass("fade")?g.one("bsTransitionEnd",c).emulateTransitionEnd(d.TRANSITION_DURATION):c())};var e=a.fn.alert;a.fn.alert=b,a.fn.alert.Constructor=d,a.fn.alert.noConflict=function(){return a.fn.alert=e,this},a(document).on("click.bs.alert.data-api",c,d.prototype.close)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof b&&b;e||d.data("bs.button",e=new c(this,f)),"toggle"==b?e.toggle():b&&e.setState(b)})}var c=function(b,d){this.$element=a(b),this.options=a.extend({},c.DEFAULTS,d),this.isLoading=!1};c.VERSION="3.3.4",c.DEFAULTS={loadingText:"loading..."},c.prototype.setState=function(b){var c="disabled",d=this.$element,e=d.is("input")?"val":"html",f=d.data();b+="Text",null==f.resetText&&d.data("resetText",d[e]()),setTimeout(a.proxy(function(){d[e](null==f[b]?this.options[b]:f[b]),"loadingText"==b?(this.isLoading=!0,d.addClass(c).attr(c,c)):this.isLoading&&(this.isLoading=!1,d.removeClass(c).removeAttr(c))},this),0)},c.prototype.toggle=function(){var a=!0,b=this.$element.closest('[data-toggle="buttons"]');if(b.length){var c=this.$element.find("input");"radio"==c.prop("type")&&(c.prop("checked")&&this.$element.hasClass("active")?a=!1:b.find(".active").removeClass("active")),a&&c.prop("checked",!this.$element.hasClass("active")).trigger("change")}else this.$element.attr("aria-pressed",!this.$element.hasClass("active"));a&&this.$element.toggleClass("active")};var d=a.fn.button;a.fn.button=b,a.fn.button.Constructor=c,a.fn.button.noConflict=function(){return a.fn.button=d,this},a(document).on("click.bs.button.data-api",'[data-toggle^="button"]',function(c){var d=a(c.target);d.hasClass("btn")||(d=d.closest(".btn")),b.call(d,"toggle"),c.preventDefault()}).on("focus.bs.button.data-api blur.bs.button.data-api",'[data-toggle^="button"]',function(b){a(b.target).closest(".btn").toggleClass("focus",/^focus(in)?$/.test(b.type))})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},c.DEFAULTS,d.data(),"object"==typeof b&&b),g="string"==typeof b?b:f.slide;e||d.data("bs.carousel",e=new c(this,f)),"number"==typeof b?e.to(b):g?e[g]():f.interval&&e.pause().cycle()})}var c=function(b,c){this.$element=a(b),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=null,this.sliding=null,this.interval=null,this.$active=null,this.$items=null,this.options.keyboard&&this.$element.on("keydown.bs.carousel",a.proxy(this.keydown,this)),"hover"==this.options.pause&&!("ontouchstart"in document.documentElement)&&this.$element.on("mouseenter.bs.carousel",a.proxy(this.pause,this)).on("mouseleave.bs.carousel",a.proxy(this.cycle,this))};c.VERSION="3.3.4",c.TRANSITION_DURATION=600,c.DEFAULTS={interval:5e3,pause:"hover",wrap:!0,keyboard:!0},c.prototype.keydown=function(a){if(!/input|textarea/i.test(a.target.tagName)){switch(a.which){case 37:this.prev();break;case 39:this.next();break;default:return}a.preventDefault()}},c.prototype.cycle=function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},c.prototype.getItemIndex=function(a){return this.$items=a.parent().children(".item"),this.$items.index(a||this.$active)},c.prototype.getItemForDirection=function(a,b){var c=this.getItemIndex(b),d="prev"==a&&0===c||"next"==a&&c==this.$items.length-1;if(d&&!this.options.wrap)return b;var e="prev"==a?-1:1,f=(c+e)%this.$items.length;return this.$items.eq(f)},c.prototype.to=function(a){var b=this,c=this.getItemIndex(this.$active=this.$element.find(".item.active"));return a>this.$items.length-1||0>a?void 0:this.sliding?this.$element.one("slid.bs.carousel",function(){b.to(a)}):c==a?this.pause().cycle():this.slide(a>c?"next":"prev",this.$items.eq(a))},c.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},c.prototype.next=function(){return this.sliding?void 0:this.slide("next")},c.prototype.prev=function(){return this.sliding?void 0:this.slide("prev")},c.prototype.slide=function(b,d){var e=this.$element.find(".item.active"),f=d||this.getItemForDirection(b,e),g=this.interval,h="next"==b?"left":"right",i=this;if(f.hasClass("active"))return this.sliding=!1;var j=f[0],k=a.Event("slide.bs.carousel",{relatedTarget:j,direction:h});if(this.$element.trigger(k),!k.isDefaultPrevented()){if(this.sliding=!0,g&&this.pause(),this.$indicators.length){this.$indicators.find(".active").removeClass("active");var l=a(this.$indicators.children()[this.getItemIndex(f)]);l&&l.addClass("active")}var m=a.Event("slid.bs.carousel",{relatedTarget:j,direction:h});return a.support.transition&&this.$element.hasClass("slide")?(f.addClass(b),f[0].offsetWidth,e.addClass(h),f.addClass(h),e.one("bsTransitionEnd",function(){f.removeClass([b,h].join(" ")).addClass("active"),e.removeClass(["active",h].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger(m)},0)}).emulateTransitionEnd(c.TRANSITION_DURATION)):(e.removeClass("active"),f.addClass("active"),this.sliding=!1,this.$element.trigger(m)),g&&this.cycle(),this}};var d=a.fn.carousel;a.fn.carousel=b,a.fn.carousel.Constructor=c,a.fn.carousel.noConflict=function(){return a.fn.carousel=d,this};var e=function(c){var d,e=a(this),f=a(e.attr("data-target")||(d=e.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""));if(f.hasClass("carousel")){var g=a.extend({},f.data(),e.data()),h=e.attr("data-slide-to");h&&(g.interval=!1),b.call(f,g),h&&f.data("bs.carousel").to(h),c.preventDefault()}};a(document).on("click.bs.carousel.data-api","[data-slide]",e).on("click.bs.carousel.data-api","[data-slide-to]",e),a(window).on("load",function(){a('[data-ride="carousel"]').each(function(){var c=a(this);b.call(c,c.data())})})}(jQuery),+function(a){"use strict";function b(b){var c,d=b.attr("data-target")||(c=b.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,"");return a(d)}function c(b){return this.each(function(){var c=a(this),e=c.data("bs.collapse"),f=a.extend({},d.DEFAULTS,c.data(),"object"==typeof b&&b);!e&&f.toggle&&/show|hide/.test(b)&&(f.toggle=!1),e||c.data("bs.collapse",e=new d(this,f)),"string"==typeof b&&e[b]()})}var d=function(b,c){this.$element=a(b),this.options=a.extend({},d.DEFAULTS,c),this.$trigger=a('[data-toggle="collapse"][href="#'+b.id+'"],[data-toggle="collapse"][data-target="#'+b.id+'"]'),this.transitioning=null,this.options.parent?this.$parent=this.getParent():this.addAriaAndCollapsedClass(this.$element,this.$trigger),this.options.toggle&&this.toggle()};d.VERSION="3.3.4",d.TRANSITION_DURATION=350,d.DEFAULTS={toggle:!0},d.prototype.dimension=function(){var a=this.$element.hasClass("width");return a?"width":"height"},d.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var b,e=this.$parent&&this.$parent.children(".panel").children(".in, .collapsing");if(!(e&&e.length&&(b=e.data("bs.collapse"),b&&b.transitioning))){var f=a.Event("show.bs.collapse");if(this.$element.trigger(f),!f.isDefaultPrevented()){e&&e.length&&(c.call(e,"hide"),b||e.data("bs.collapse",null));var g=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[g](0).attr("aria-expanded",!0),this.$trigger.removeClass("collapsed").attr("aria-expanded",!0),this.transitioning=1;var h=function(){this.$element.removeClass("collapsing").addClass("collapse in")[g](""),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return h.call(this);var i=a.camelCase(["scroll",g].join("-"));this.$element.one("bsTransitionEnd",a.proxy(h,this)).emulateTransitionEnd(d.TRANSITION_DURATION)[g](this.$element[0][i])}}}},d.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var b=a.Event("hide.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.dimension();this.$element[c](this.$element[c]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse in").attr("aria-expanded",!1),this.$trigger.addClass("collapsed").attr("aria-expanded",!1),this.transitioning=1;var e=function(){this.transitioning=0,this.$element.removeClass("collapsing").addClass("collapse").trigger("hidden.bs.collapse")};return a.support.transition?void this.$element[c](0).one("bsTransitionEnd",a.proxy(e,this)).emulateTransitionEnd(d.TRANSITION_DURATION):e.call(this)}}},d.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()},d.prototype.getParent=function(){return a(this.options.parent).find('[data-toggle="collapse"][data-parent="'+this.options.parent+'"]').each(a.proxy(function(c,d){var e=a(d);this.addAriaAndCollapsedClass(b(e),e)},this)).end()},d.prototype.addAriaAndCollapsedClass=function(a,b){var c=a.hasClass("in");a.attr("aria-expanded",c),b.toggleClass("collapsed",!c).attr("aria-expanded",c)};var e=a.fn.collapse;a.fn.collapse=c,a.fn.collapse.Constructor=d,a.fn.collapse.noConflict=function(){return a.fn.collapse=e,this},a(document).on("click.bs.collapse.data-api",'[data-toggle="collapse"]',function(d){var e=a(this);e.attr("data-target")||d.preventDefault();var f=b(e),g=f.data("bs.collapse"),h=g?"toggle":e.data();c.call(f,h)})}(jQuery),+function(a){"use strict";function b(b){b&&3===b.which||(a(e).remove(),a(f).each(function(){var d=a(this),e=c(d),f={relatedTarget:this};e.hasClass("open")&&(e.trigger(b=a.Event("hide.bs.dropdown",f)),b.isDefaultPrevented()||(d.attr("aria-expanded","false"),e.removeClass("open").trigger("hidden.bs.dropdown",f)))}))}function c(b){var c=b.attr("data-target");c||(c=b.attr("href"),c=c&&/#[A-Za-z]/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,""));var d=c&&a(c);return d&&d.length?d:b.parent()}function d(b){return this.each(function(){var c=a(this),d=c.data("bs.dropdown");d||c.data("bs.dropdown",d=new g(this)),"string"==typeof b&&d[b].call(c)})}var e=".dropdown-backdrop",f='[data-toggle="dropdown"]',g=function(b){a(b).on("click.bs.dropdown",this.toggle)};g.VERSION="3.3.4",g.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=c(e),g=f.hasClass("open");if(b(),!g){"ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length&&a('',trigger:"hover focus",title:"",delay:0,html:!1,container:!1,viewport:{selector:"body",padding:0}},c.prototype.init=function(b,c,d){if(this.enabled=!0,this.type=b,this.$element=a(c),this.options=this.getOptions(d),this.$viewport=this.options.viewport&&a(this.options.viewport.selector||this.options.viewport),this.$element[0]instanceof document.constructor&&!this.options.selector)throw new Error("`selector` option must be specified when initializing "+this.type+" on the window.document object!");for(var e=this.options.trigger.split(" "),f=e.length;f--;){var g=e[f];if("click"==g)this.$element.on("click."+this.type,this.options.selector,a.proxy(this.toggle,this));else if("manual"!=g){var h="hover"==g?"mouseenter":"focusin",i="hover"==g?"mouseleave":"focusout";this.$element.on(h+"."+this.type,this.options.selector,a.proxy(this.enter,this)),this.$element.on(i+"."+this.type,this.options.selector,a.proxy(this.leave,this))}}this.options.selector?this._options=a.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.getOptions=function(b){return b=a.extend({},this.getDefaults(),this.$element.data(),b),b.delay&&"number"==typeof b.delay&&(b.delay={show:b.delay,hide:b.delay}),b},c.prototype.getDelegateOptions=function(){var b={},c=this.getDefaults();return this._options&&a.each(this._options,function(a,d){c[a]!=d&&(b[a]=d)}),b},c.prototype.enter=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c&&c.$tip&&c.$tip.is(":visible")?void(c.hoverState="in"):(c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),clearTimeout(c.timeout),c.hoverState="in",c.options.delay&&c.options.delay.show?void(c.timeout=setTimeout(function(){"in"==c.hoverState&&c.show()},c.options.delay.show)):c.show())},c.prototype.leave=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),clearTimeout(c.timeout),c.hoverState="out",c.options.delay&&c.options.delay.hide?void(c.timeout=setTimeout(function(){"out"==c.hoverState&&c.hide()},c.options.delay.hide)):c.hide()},c.prototype.show=function(){var b=a.Event("show.bs."+this.type);if(this.hasContent()&&this.enabled){this.$element.trigger(b);var d=a.contains(this.$element[0].ownerDocument.documentElement,this.$element[0]);if(b.isDefaultPrevented()||!d)return;var e=this,f=this.tip(),g=this.getUID(this.type);this.setContent(),f.attr("id",g),this.$element.attr("aria-describedby",g),this.options.animation&&f.addClass("fade");var h="function"==typeof this.options.placement?this.options.placement.call(this,f[0],this.$element[0]):this.options.placement,i=/\s?auto?\s?/i,j=i.test(h);j&&(h=h.replace(i,"")||"top"),f.detach().css({top:0,left:0,display:"block"}).addClass(h).data("bs."+this.type,this),this.options.container?f.appendTo(this.options.container):f.insertAfter(this.$element);var k=this.getPosition(),l=f[0].offsetWidth,m=f[0].offsetHeight;if(j){var n=h,o=this.options.container?a(this.options.container):this.$element.parent(),p=this.getPosition(o);h="bottom"==h&&k.bottom+m>p.bottom?"top":"top"==h&&k.top-mp.width?"left":"left"==h&&k.left-lg.top+g.height&&(e.top=g.top+g.height-i)}else{var j=b.left-f,k=b.left+f+c;jg.width&&(e.left=g.left+g.width-k)}return e},c.prototype.getTitle=function(){var a,b=this.$element,c=this.options;return a=b.attr("data-original-title")||("function"==typeof c.title?c.title.call(b[0]):c.title)},c.prototype.getUID=function(a){do a+=~~(1e6*Math.random());while(document.getElementById(a));return a},c.prototype.tip=function(){return this.$tip=this.$tip||a(this.options.template)},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},c.prototype.enable=function(){this.enabled=!0},c.prototype.disable=function(){this.enabled=!1},c.prototype.toggleEnabled=function(){this.enabled=!this.enabled},c.prototype.toggle=function(b){var c=this;b&&(c=a(b.currentTarget).data("bs."+this.type),c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c))),c.tip().hasClass("in")?c.leave(c):c.enter(c)},c.prototype.destroy=function(){var a=this;clearTimeout(this.timeout),this.hide(function(){a.$element.off("."+a.type).removeData("bs."+a.type)})};var d=a.fn.tooltip;a.fn.tooltip=b,a.fn.tooltip.Constructor=c,a.fn.tooltip.noConflict=function(){return a.fn.tooltip=d,this}}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.popover"),f="object"==typeof b&&b;(e||!/destroy|hide/.test(b))&&(e||d.data("bs.popover",e=new c(this,f)),"string"==typeof b&&e[b]())})}var c=function(a,b){this.init("popover",a,b)};if(!a.fn.tooltip)throw new Error("Popover requires tooltip.js");c.VERSION="3.3.4",c.DEFAULTS=a.extend({},a.fn.tooltip.Constructor.DEFAULTS,{placement:"right",trigger:"click",content:"",template:''}),c.prototype=a.extend({},a.fn.tooltip.Constructor.prototype),c.prototype.constructor=c,c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.setContent=function(){var a=this.tip(),b=this.getTitle(),c=this.getContent();a.find(".popover-title")[this.options.html?"html":"text"](b),a.find(".popover-content").children().detach().end()[this.options.html?"string"==typeof c?"html":"append":"text"](c),a.removeClass("fade top bottom left right in"),a.find(".popover-title").html()||a.find(".popover-title").hide()},c.prototype.hasContent=function(){return this.getTitle()||this.getContent()},c.prototype.getContent=function(){var a=this.$element,b=this.options;return a.attr("data-content")||("function"==typeof b.content?b.content.call(a[0]):b.content)},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".arrow")};var d=a.fn.popover;a.fn.popover=b,a.fn.popover.Constructor=c,a.fn.popover.noConflict=function(){return a.fn.popover=d,this}}(jQuery),+function(a){"use strict";function b(c,d){this.$body=a(document.body),this.$scrollElement=a(a(c).is(document.body)?window:c),this.options=a.extend({},b.DEFAULTS,d),this.selector=(this.options.target||"")+" .nav li > a",this.offsets=[],this.targets=[],this.activeTarget=null,this.scrollHeight=0,this.$scrollElement.on("scroll.bs.scrollspy",a.proxy(this.process,this)),this.refresh(),this.process()}function c(c){return this.each(function(){var d=a(this),e=d.data("bs.scrollspy"),f="object"==typeof c&&c;e||d.data("bs.scrollspy",e=new b(this,f)),"string"==typeof c&&e[c]()})}b.VERSION="3.3.4",b.DEFAULTS={offset:10},b.prototype.getScrollHeight=function(){return this.$scrollElement[0].scrollHeight||Math.max(this.$body[0].scrollHeight,document.documentElement.scrollHeight)},b.prototype.refresh=function(){var b=this,c="offset",d=0;this.offsets=[],this.targets=[],this.scrollHeight=this.getScrollHeight(),a.isWindow(this.$scrollElement[0])||(c="position",d=this.$scrollElement.scrollTop()),this.$body.find(this.selector).map(function(){var b=a(this),e=b.data("target")||b.attr("href"),f=/^#./.test(e)&&a(e);return f&&f.length&&f.is(":visible")&&[[f[c]().top+d,e]]||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){b.offsets.push(this[0]),b.targets.push(this[1])})},b.prototype.process=function(){var a,b=this.$scrollElement.scrollTop()+this.options.offset,c=this.getScrollHeight(),d=this.options.offset+c-this.$scrollElement.height(),e=this.offsets,f=this.targets,g=this.activeTarget;if(this.scrollHeight!=c&&this.refresh(),b>=d)return g!=(a=f[f.length-1])&&this.activate(a);if(g&&b=e[a]&&(void 0===e[a+1]||b .dropdown-menu > .active").removeClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!1),b.addClass("active").find('[data-toggle="tab"]').attr("aria-expanded",!0),h?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu").length&&b.closest("li.dropdown").addClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!0),e&&e()}var g=d.find("> .active"),h=e&&a.support.transition&&(g.length&&g.hasClass("fade")||!!d.find("> .fade").length);g.length&&h?g.one("bsTransitionEnd",f).emulateTransitionEnd(c.TRANSITION_DURATION):f(),g.removeClass("in")};var d=a.fn.tab;a.fn.tab=b,a.fn.tab.Constructor=c,a.fn.tab.noConflict=function(){return a.fn.tab=d,this};var e=function(c){c.preventDefault(),b.call(a(this),"show")};a(document).on("click.bs.tab.data-api",'[data-toggle="tab"]',e).on("click.bs.tab.data-api",'[data-toggle="pill"]',e)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.affix"),f="object"==typeof b&&b;e||d.data("bs.affix",e=new c(this,f)),"string"==typeof b&&e[b]()})}var c=function(b,d){this.options=a.extend({},c.DEFAULTS,d),this.$target=a(this.options.target).on("scroll.bs.affix.data-api",a.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",a.proxy(this.checkPositionWithEventLoop,this)),this.$element=a(b),this.affixed=null,this.unpin=null,this.pinnedOffset=null,this.checkPosition()};c.VERSION="3.3.4",c.RESET="affix affix-top affix-bottom",c.DEFAULTS={offset:0,target:window},c.prototype.getState=function(a,b,c,d){var e=this.$target.scrollTop(),f=this.$element.offset(),g=this.$target.height();if(null!=c&&"top"==this.affixed)return c>e?"top":!1;if("bottom"==this.affixed)return null!=c?e+this.unpin<=f.top?!1:"bottom":a-d>=e+g?!1:"bottom";var h=null==this.affixed,i=h?e:f.top,j=h?g:b;return null!=c&&c>=e?"top":null!=d&&i+j>=a-d?"bottom":!1},c.prototype.getPinnedOffset=function(){if(this.pinnedOffset)return this.pinnedOffset;this.$element.removeClass(c.RESET).addClass("affix");var a=this.$target.scrollTop(),b=this.$element.offset();return this.pinnedOffset=b.top-a},c.prototype.checkPositionWithEventLoop=function(){setTimeout(a.proxy(this.checkPosition,this),1)},c.prototype.checkPosition=function(){if(this.$element.is(":visible")){var b=this.$element.height(),d=this.options.offset,e=d.top,f=d.bottom,g=a(document.body).height();"object"!=typeof d&&(f=e=d),"function"==typeof e&&(e=d.top(this.$element)),"function"==typeof f&&(f=d.bottom(this.$element));var h=this.getState(g,b,e,f);if(this.affixed!=h){null!=this.unpin&&this.$element.css("top","");var i="affix"+(h?"-"+h:""),j=a.Event(i+".bs.affix");if(this.$element.trigger(j),j.isDefaultPrevented())return;this.affixed=h,this.unpin="bottom"==h?this.getPinnedOffset():null,this.$element.removeClass(c.RESET).addClass(i).trigger(i.replace("affix","affixed")+".bs.affix")}"bottom"==h&&this.$element.offset({top:g-b-f})}};var d=a.fn.affix;a.fn.affix=b,a.fn.affix.Constructor=c,a.fn.affix.noConflict=function(){return a.fn.affix=d,this},a(window).on("load",function(){a('[data-spy="affix"]').each(function(){var c=a(this),d=c.data();d.offset=d.offset||{},null!=d.offsetBottom&&(d.offset.bottom=d.offsetBottom),null!=d.offsetTop&&(d.offset.top=d.offsetTop),b.call(c,d)})})}(jQuery); -------------------------------------------------------------------------------- /static/js/main.js: -------------------------------------------------------------------------------- 1 | // ########################################################################################################## 2 | // GTFS CLIENT-SIDE APPLICATION 3 | // Created by Jon Kostyniuk on 25AUG2015 4 | // Last modified by Jon Kostyniuk on 25AUG2015 5 | // Property of JK Enterprises 6 | // v0.01a 7 | // ########################################################################################################## 8 | // 9 | // Version History: 10 | // ---------------- 11 | // 25AUG2015 v0.01a - JK 12 | // - Initial Version. 13 | // 14 | // Usage: 15 | // ------ 16 | // Describe usage. 17 | // 18 | // Instructions: 19 | // ------------- 20 | // None currently. 21 | // 22 | 23 | // ########################################################################################################## 24 | // DEFINITIONS 25 | // ########################################################################################################## 26 | 27 | // Map Object Variables 28 | var $map = null; // Google Map Variable 29 | var $mapStyles = [ 30 | { 31 | "featureType": "administrative.land_parcel", 32 | "elementType": "all", 33 | "stylers": [ 34 | {"visibility": "off"} 35 | ] 36 | },{ 37 | "featureType": "landscape.man_made", 38 | "elementType": "all", 39 | "stylers": [ 40 | {"visibility": "off"} 41 | ] 42 | },{ 43 | "featureType": "poi", 44 | "elementType": "labels", 45 | "stylers": [ 46 | {"visibility": "off"} 47 | ] 48 | },{ 49 | "featureType": "road", 50 | "elementType": "labels", 51 | "stylers": [ 52 | {"visibility": "simplified"}, 53 | {"lightness": 20} 54 | ] 55 | },{ 56 | "featureType": "road.highway", 57 | "elementType": "geometry", 58 | "stylers": [ 59 | {"hue": "#f49935"} 60 | ] 61 | },{ 62 | "featureType": "road.highway", 63 | "elementType": "labels", 64 | "stylers": [ 65 | {"visibility": "simplified"} 66 | ] 67 | },{ 68 | "featureType": "road.arterial", 69 | "elementType": "geometry", 70 | "stylers": [ 71 | {"hue": "#fad959"} 72 | ] 73 | },{ 74 | "featureType": "road.arterial", 75 | "elementType": "labels", 76 | "stylers": [ 77 | {"visibility": "off"} 78 | ] 79 | },{ 80 | "featureType": "road.local", 81 | "elementType": "geometry", 82 | "stylers": [ 83 | {"visibility": "simplified"} 84 | ] 85 | },{ 86 | "featureType": "road.local", 87 | "elementType": "labels", 88 | "stylers": [ 89 | {"visibility": "simplified"} 90 | ] 91 | },{ 92 | "featureType": "transit", 93 | "elementType": "all", 94 | "stylers": [ 95 | {"visibility": "off"} 96 | ] 97 | },{ 98 | "featureType": "water", 99 | "elementType": "all", 100 | "stylers": [ 101 | {"hue":"#a1cdfc"}, 102 | {"saturation":30}, 103 | {"lightness":49} 104 | ] 105 | } 106 | ]; 107 | var $mapOptions = { // Map Options Variables 108 | zoom: 5, 109 | center: new google.maps.LatLng(49.895529, -97.138449), 110 | styles: $mapStyles, 111 | mapTypeControl: false, 112 | }; 113 | var $MapBounds = { // Map Bounds Coordinates 114 | upLat: null, 115 | loLat: null, 116 | ltLng: null, 117 | rtLng: null 118 | }; 119 | var $ehMapIdle = null; // Google Map Idle Event Handler Object 120 | var $bsZoom = 17; // Threshold zoom level to show bus stop locations 121 | var $BusStops = null; // JSON Object for Bus Stops Data 122 | google.setOnLoadCallback(initMap); // Asynchronous Call Back to Initialize Map 123 | 124 | // GTFS Data Variables 125 | var $AgencyData = null; // JSON Object for Agency Feed Data 126 | var $SelAgency = null; // Selected Transit Agency ID 127 | var $GTFS_API = "http://www.gtfs-data-exchange.com/api/agencies"; // GTFS Exchange API Data 128 | var $GTFS_ZIP = new RegExp(/\.(zip$)/); // GTFS ZIP File Regular Expression 129 | var $ZipType = null; // ZIP Radio - URL or File 130 | 131 | // Loaded Agency Variables 132 | var $AgencyPreset = null; // JSON Object for User Agency Preset Data 133 | var $RoutesData = null; // JSON Object for Agency Route Data 134 | var $TripData = null; // JSON Object for Route Trip Data 135 | 136 | // GUI Variables 137 | var $diaName = null; // Name of Dialogue Window Open 138 | var $UUID = null; // Client Side Unique User ID 139 | var $TimeOffset = new Date().getTimezoneOffset(); // Timezone Offset in Minutes 140 | 141 | // Google Maps Polyline Options 142 | var $polyline = null; // Polyline Object Initialization 143 | var $polypts = []; // Array to hold polyline points 144 | var $polyopts = { // Options for polyline styling 145 | geodesic: true, 146 | strokeColor: "#0000ff", 147 | strokeOpacity: 1.0, 148 | strokeWeight: 3 149 | }; 150 | var $bounds = null; // Map Bounds Object Initialization 151 | 152 | // Google Maps Marker References 153 | var $sMarker = null; // Start Marker Object Initialization 154 | var $eMarker = null; // End Marker Object Initialization 155 | var $gmMarkers = { // Google Map Marker References 156 | green: "http://maps.google.com/mapfiles/ms/icons/green-dot.png", 157 | red: "http://maps.google.com/mapfiles/ms/icons/red-dot.png", 158 | blue: "http://maps.google.com/mapfiles/ms/icons/blue-dot.png", 159 | yellow: "http://maps.google.com/mapfiles/ms/icons/yellow-dot.png" 160 | }; 161 | var $bsMarkers = []; // Bus Stop Markers Object Initialization 162 | var $bsInfoWindow= new google.maps.InfoWindow({ // Bus Stop Marker Info Window Initialization 163 | content: "Loading..." 164 | }); 165 | 166 | // AJAX Loading 'spin.js' Variables 167 | var $SpinOpts = { // Set Spin Options 168 | lines: 13, // The number of lines to draw 169 | length: 7, // The length of each line 170 | width: 5, // The line thickness 171 | radius: 12, // The radius of the inner circle 172 | rotate: 0, // The rotation offset 173 | color: "#efefef", // #rgb or #rrggbb 174 | speed: 0.75, // Rounds per second 175 | trail: 50, // Afterglow percentage 176 | shadow: true, // Whether to render a shadow 177 | hwaccel: false, // Whether to use hardware acceleration 178 | className: "spinner", // The CSS class to assign to the spinner 179 | zIndex: 2000000000, // The z-index (defaults to 2000000000) 180 | top: "auto", // Top position relative to parent in px 181 | left: "auto" // Left position relative to parent in px 182 | }; 183 | var $spinner = new Spinner($SpinOpts); // Spinner Object Initialize 184 | var $ajax_cnt = 0; // Support for parallel AJAX requests 185 | 186 | 187 | // ########################################################################################################## 188 | // DEFINED FUNCTIONS 189 | // ########################################################################################################## 190 | 191 | // MODULE FUNCTIONS 192 | // ---------------- 193 | 194 | // Function to Clear Agency 195 | function clearAgency() { 196 | $SelAgency = null; // Clear Selected Agency 197 | $(".list-item").css("color", "#000000"); // Clear selected styles 198 | $(".list-item").css("background", "#ffffff"); // Clear selected styles 199 | $('#load-agency').prop('disabled', true); // Disable submit button 200 | $('#mAgency').modal('hide'); // Hide dialogue 201 | $diaName = null; // Clear active dialogue name 202 | 203 | return; 204 | } 205 | 206 | // Function to Clear Upload 207 | function clearUpload() { 208 | $('#upload-ZIP').prop('disabled', true); // Disable submit button 209 | $('#mUploadZIP').modal('hide'); // Hide dialogue 210 | $diaName = null; // Clear active dialogue name 211 | 212 | return; 213 | } 214 | 215 | // Function to Create Trip Map from Route Data 216 | function createTripMap() { 217 | if($("#route").val() != "NULL") { 218 | var $reqData = { 219 | "uuid": $UUID, 220 | "agency_id": $('#agency').val().split("aID_")[1], 221 | "route_id": $("#route").val().split("rtID_")[1], 222 | "datetime": $("#rtdatetime").val() 223 | } 224 | // AJAX Call and JSON Response 225 | $.ajax({ 226 | url: "./api/createmap", 227 | method: "POST", 228 | contentType: "application/json", 229 | data: JSON.stringify($reqData), 230 | dataType: "json", 231 | success: function($data) { 232 | // Save Global JSON Data 233 | $TripData = $data; 234 | 235 | // Validate Returned JSON Data 236 | var $tdMsg = valTripData($TripData); 237 | if($tdMsg == "success") { 238 | // Clear existing polyline 239 | if($polyline) { 240 | $polyline.setMap(null); // Remove polyline 241 | $sMarker.setMap(null); // Remove start marker 242 | $eMarker.setMap(null); // Remove end marker 243 | } 244 | $polypts = []; 245 | // Set Bounds Object 246 | $bounds = new google.maps.LatLngBounds(); 247 | // Define Polyline Shape Sequence 248 | for(var $i =0; $i < $TripData["shape_sequence"].length; $i++) { 249 | // Create Lat/Lon Point Object 250 | var $polypt = new google.maps.LatLng( 251 | $TripData["shape_sequence"][$i]["shape_pt_lat"], 252 | $TripData["shape_sequence"][$i]["shape_pt_lon"] 253 | ); 254 | $polypts.push($polypt); // Add new point to polyline 255 | $bounds.extend($polypt); // Extend polyline boundary fit 256 | } 257 | // Set new polyline on map 258 | $polyline = new google.maps.Polyline({ 259 | path: $polypts, 260 | map: $map, 261 | strokeColor: $polyopts["strokeColor"], 262 | geodesic: $polyopts["geodesic"], 263 | strokeOpacity: $polyopts["strokeOpacity"], 264 | strokeWeight: $polyopts["strokeWeight"] 265 | }); 266 | $polyline.setMap($map); 267 | $map.fitBounds($bounds); 268 | 269 | // Set new start and end markers 270 | $sPoint = $polypts[0]; // Set Start Point of Polyline 271 | $sMarker = new google.maps.Marker({ 272 | position: $sPoint, 273 | map: $map, 274 | icon: $gmMarkers["green"] 275 | }); 276 | $ePoint = $polypts[$polypts.length - 1]; // Set End Point of Polyline 277 | $eMarker = new google.maps.Marker({ 278 | position: $ePoint, 279 | map: $map, 280 | icon: $gmMarkers["red"] 281 | }); 282 | 283 | // Set Route Information for Trip 284 | $rtOutput = ""; 285 | $rtOutput += "Route ID: " + $TripData["route_id"] + "
"; 286 | $rtOutput += "Service ID: " + $TripData["service_id"] + "
"; 287 | $rtOutput += "Trip ID: " + $TripData["trip_id"] + "
"; 288 | $rtOutput += "Shape ID: " + $TripData["shape_id"] + "
"; 289 | $rtOutput += "Start Time: " + $TripData["stop_sequence"][0]["departure_time"] + "
"; 290 | $rtOutput += "End Time: " + $TripData["stop_sequence"][$TripData["stop_sequence"].length - 1]["arrival_time"] + "
"; 291 | $("#route-out").html($rtOutput); 292 | } 293 | else { 294 | alert($tdMsg); // Development - Handle through Bootstrap in production 295 | } 296 | 297 | 298 | }, 299 | error: function ($jqXHR, $textStatus, $errorThrown) { 300 | if ($jqXHR.status == 500) { 301 | alert("Internal error: " + $jqXHR.responseText); 302 | } else { 303 | alert("Unexpected error!!"); 304 | } 305 | } 306 | }); 307 | } 308 | else alert("ERROR: Please select transit route!!"); 309 | 310 | return; 311 | } 312 | 313 | // Function to Create and/or Verify Unique User ID 314 | function createUUID() { 315 | if(localStorage.getItem("uuid") == "null") { 316 | $.ajax({ 317 | url: "./api/uuid", 318 | method: "GET", 319 | dataType: "text", 320 | success: function($data) { 321 | localStorage.setItem("uuid", $data); 322 | $UUID = $data; 323 | preloadGTFS(); 324 | }, 325 | error: function ($jqXHR, $textStatus, $errorThrown) { 326 | if ($jqXHR.status == 500) { 327 | alert("Internal error: " + $jqXHR.responseText); 328 | } else { 329 | alert("Unexpected error!!"); 330 | } 331 | } 332 | }); 333 | } 334 | else { 335 | $UUID = localStorage.getItem("uuid"); 336 | preloadGTFS(); 337 | } 338 | 339 | return; 340 | } 341 | 342 | // Function to Control Map Click Event Handler 343 | function ehMapClick() { 344 | // Check that map meets zoom threshold 345 | if($map.getZoom() >= $bsZoom) { 346 | // Get Current Map Bounds 347 | var $curBounds = $map.getBounds(); 348 | // Save Map Bound Coordinates 349 | scMapBndCoord("set", $curBounds); 350 | var $reqData = { 351 | "uuid": $UUID, 352 | "agency_id": $('#agency').val().split("aID_")[1], 353 | "bounds": $MapBounds 354 | } 355 | // AJAX Call and JSON Response 356 | $.ajax({ 357 | url: "./api/stops", 358 | method: "POST", 359 | contentType: "application/json", 360 | data: JSON.stringify($reqData), 361 | dataType: "json", 362 | success: function($data) { 363 | // Save Global JSON Data 364 | var $prevBusStops = $BusStops; 365 | $BusStops = $data; 366 | getBusStopInfo(); // Function call to supplement data - '$BusStops' global variable modified 367 | $modstops = sortBusStops($prevBusStops, $BusStops); 368 | $addBusStops = $modstops[0]; 369 | $remBusStops = $modstops[1]; 370 | console.log($addBusStops); 371 | console.log($remBusStops); 372 | 373 | // If Remove Stops Present 374 | if($remBusStops.length > 0) { 375 | for (var $i in $bsMarkers) { 376 | for (var $j in $remBusStops) { 377 | if($remBusStops[$j]["stop_id"] == $bsMarkers[$i]["id"]) 378 | $bsMarkers[$i]["marker"].setMap(null); 379 | } 380 | } 381 | } 382 | 383 | // If Add Stops Present 384 | if($addBusStops.length > 0) { 385 | // Loop through and plot stop points 386 | for(var $i = 0; $i < $addBusStops.length; $i++) { 387 | // Check if on current trip route 388 | if($addBusStops[$i]["on_trip"]) $mcolor = "blue"; // Blue for route stops 389 | else $mcolor = "yellow"; // Yellow for other stops 390 | // Map Current Bus Stop Lat/Lng Object 391 | var $bspt = new google.maps.LatLng( 392 | $addBusStops[$i]["stop_lat"], 393 | $addBusStops[$i]["stop_lon"] 394 | ); 395 | var $bsmarker = new google.maps.Marker({ 396 | position: $bspt, 397 | map: $map, 398 | icon: $gmMarkers[$mcolor], 399 | html: makeBusStopHTML($addBusStops[$i]) 400 | }); 401 | // Add event listener for marker click 402 | google.maps.event.addListener($bsmarker, "click", function() { 403 | if($bsInfoWindow) $bsInfoWindow.close(); // Close any open info windows BUG HERE 404 | $bsInfoWindow.setContent(this.html); 405 | $bsInfoWindow.open($map, this); 406 | }); 407 | $bsMarkers.push({"id": $addBusStops[$i]["stop_id"], "marker": $bsmarker}); 408 | } 409 | } 410 | }, 411 | error: function ($jqXHR, $textStatus, $errorThrown) { 412 | if ($jqXHR.status == 500) { 413 | alert("Internal error: " + $jqXHR.responseText); 414 | } else { 415 | alert("Unexpected error!!"); 416 | } 417 | } 418 | }); 419 | } 420 | else { 421 | // Clear existing bus stop points 422 | $BusStops = null; 423 | for (var $i in $bsMarkers) { 424 | $bsMarkers[$i]["marker"].setMap(null); 425 | } 426 | $bsMarkers = []; 427 | } 428 | 429 | return; 430 | } 431 | 432 | // Function to Initialize Google Map 433 | function initMap() { 434 | // Create New Google Maps Object 435 | $map = new google.maps.Map($('#gmap')[0], $mapOptions); 436 | 437 | google.maps.event.addListener($map, "idle", ehMapClick); 438 | 439 | return; 440 | } 441 | 442 | // Function to Load Agency 443 | function loadAgency() { 444 | $(".list-item").css("color", "#000000"); // Clear selected styles 445 | $(".list-item").css("background", "#ffffff"); // Clear selected styles 446 | $('#load-agency').prop('disabled', true); 447 | $('#mAgency').modal('hide'); 448 | $diaName = null; 449 | 450 | 451 | alert($SelAgency); //TEMP, DO SOMETHING HERE 452 | 453 | return; 454 | } 455 | 456 | // Function to Load Agency 457 | function loadRoutes() { 458 | // If a Valid Agency is selected 459 | if($('#agency').val() != "null") { 460 | // Clear Dropdown List and Add Null Option 461 | $("#route").empty(); 462 | $("#route").append(new Option("[ Select Route ]","NULL")); 463 | // Prepare AJAX Send Data 464 | var $reqData = { 465 | "uuid": $UUID, 466 | "agency_id": $('#agency').val().split("aID_")[1] 467 | } 468 | // AJAX Call and JSON Response 469 | $.ajax({ 470 | url: "./api/routes", 471 | method: "POST", 472 | contentType: "application/json", 473 | data: JSON.stringify($reqData), 474 | dataType: "json", 475 | success: function($data) { 476 | // Save Routes Data and Enable Routes Fields 477 | $RoutesData = $data; 478 | $("#route").prop("disabled", false); 479 | $("#datetime").children().prop("disabled", false); 480 | $("#create-map").prop("disabled", false); 481 | 482 | // Clear Date/Time Selector Data 483 | $("#datetime").data("DateTimePicker").defaultDate(false); 484 | $("#datetime").data("DateTimePicker").minDate(false); 485 | $("#datetime").data("DateTimePicker").maxDate(false); 486 | 487 | // Load Agency Dropdown Data 488 | var RouteOpt = {} 489 | for(var $i = 0; $i < $RoutesData["data_count"]; $i++) { 490 | RouteOpt["rtID_" + $RoutesData["data"][$i]["route_id"]] = $RoutesData["data"][$i]["route_short_name"] + " " + $RoutesData["data"][$i]["route_long_name"]; 491 | } 492 | $.each(RouteOpt, function(val, text) { 493 | $("#route").append(new Option(text,val)); 494 | }); 495 | 496 | // Load Agency Info Output 497 | $AgencyInfo = $RoutesData["agency_info"]["name"] + "
"; 498 | $AgencyInfo += ""; 499 | $AgencyInfo += $RoutesData["agency_info"]["url"] + ""; 500 | $("#agency-out").html($AgencyInfo); 501 | 502 | // Load Calendar Info Output 503 | $CalendarInfo = ISOtoLongDate($RoutesData["calendar_dates"]["start"].toString()) + "
"; 504 | $CalendarInfo += "to
"; 505 | $CalendarInfo += ISOtoLongDate($RoutesData["calendar_dates"]["end"].toString()) + "
"; 506 | $("#calendar-out").html($CalendarInfo); 507 | 508 | // Set Date/Time Selector Min/Max/Default Values 509 | $("#datetime").data("DateTimePicker").defaultDate(new Date(ISOtoLongDate($RoutesData["calendar_dates"]["start"].toString()) + " 00:00")); 510 | $("#datetime").data("DateTimePicker").minDate(new Date(ISOtoLongDate($RoutesData["calendar_dates"]["start"].toString()) + " 00:00")); 511 | $("#datetime").data("DateTimePicker").maxDate(new Date(ISOtoLongDate($RoutesData["calendar_dates"]["end"].toString()) + " 23:59")); 512 | }, 513 | error: function ($jqXHR, $textStatus, $errorThrown) { 514 | if ($jqXHR.status == 500) { 515 | alert("Preload Agency Data: Internal error: " + $jqXHR.responseText); 516 | } else { 517 | alert("Preload Agency Data: Unexpected error!!"); 518 | } 519 | } 520 | }); 521 | } 522 | else { // If no valid agency is selected 523 | // Disable Routes Dropdown on NULL 524 | $("#route").prop("disabled", true); 525 | $("#datetime").children().prop("disabled", true); 526 | $("#create-map").prop("disabled", true); 527 | 528 | // Clear Dropdown List and Add Null Option 529 | $("#route").empty(); 530 | $("#route").append(new Option("[ Select Route ]","NULL")); 531 | 532 | // Clear Date/Time Selector Data 533 | $("#datetime").data("DateTimePicker").defaultDate(false); 534 | $("#datetime").data("DateTimePicker").minDate(false); 535 | $("#datetime").data("DateTimePicker").maxDate(false); 536 | $("#rtdatetime").val(""); 537 | 538 | // Clear Output Data 539 | $("#agency-out").html("--"); 540 | $("#calendar-out").html("--"); 541 | } 542 | 543 | return; 544 | } 545 | 546 | // Function to Handle List Clicks 547 | function listClick($listID) { 548 | // Determine which dialogue to handle 549 | switch($diaName) { 550 | case "Agency": // Agency Select Dialogue Window 551 | $SelAgency = $listID 552 | $('#load-agency').prop('disabled', false); 553 | break; 554 | // Add more cases as needed 555 | } 556 | 557 | // Clear selected styles 558 | $(".list-item").css("color", "#000000"); 559 | $(".list-item").css("background", "#ffffff"); 560 | 561 | // Add selected item style 562 | $("#" + $listID).css("color", "#ffffff"); 563 | $("#" + $listID).css("background", "#0000ff"); 564 | 565 | // Load Preview Data 566 | for(var $i = 0; $i < $AgencyData["data"].length; $i++) { 567 | if($AgencyData["data"][$i]["dataexchange_id"] == $listID) { 568 | var $curData = $AgencyData["data"][$i]; 569 | } 570 | } 571 | 572 | // Construct Location Data 573 | var $locInfo = ""; 574 | if($curData["state"] != "") $locInfo += $curData["state"] + ", "; 575 | if($curData["country"] != "") $locInfo += $curData["country"]; 576 | 577 | // Construct Date and Time 578 | var $datetime = new Date($curData["date_last_updated"] * 1000); 579 | //$dtStr = $datetime.format("dd.mm.yyyy hh:MM:ss"); 580 | 581 | // Construct Official Feed or Not 582 | var $aOfficial = "Unofficial"; 583 | if($curData["is_official"] == true) $aOfficial = "Official"; 584 | 585 | // Change Agency Dialogue Preview Values 586 | $("#aName").html($curData["name"]); 587 | $("#aLocation").html($locInfo); 588 | $("#aURL").html("" + $curData["url"] + ""); 589 | $("#aFeed").html("" + $curData["feed_baseurl"] + ""); 590 | $("#aOfficial").html($aOfficial); 591 | $("#aFeedLastUpdated").html($datetime); 592 | 593 | return; 594 | } 595 | 596 | // Function to Preload GTFS Agency Data from Server 597 | function preloadGTFS() { 598 | if($UUID != "null") { 599 | $.ajax({ 600 | url: "./api/agencies", 601 | method: "POST", 602 | contentType: 'application/json', 603 | data: JSON.stringify({"uuid": $UUID}), 604 | dataType: "json", 605 | success: function($data) { 606 | // Save Agency Preset JSON Data 607 | $AgencyPreset = $data; 608 | $("#testout").html($AgencyPreset["uuid"]);//TEMP OUTPUT 609 | 610 | // Load Agency Dropdown Data 611 | var AgencyOpt = {} 612 | for(var $i = 0; $i < $AgencyPreset["data_count"]; $i++) { 613 | AgencyOpt["aID_" + $AgencyPreset["data"][$i]["timestamp"]] = $AgencyPreset["data"][$i]["agency_name"]; 614 | } 615 | $.each(AgencyOpt, function(val, text) { 616 | $("#agency").append(new Option(text,val)); 617 | }); 618 | }, 619 | error: function ($jqXHR, $textStatus, $errorThrown) { 620 | if ($jqXHR.status == 500) { 621 | alert("Preload Agency Data: Internal error: " + $jqXHR.responseText); 622 | } else { 623 | alert("Preload Agency Data: Unexpected error!!"); 624 | } 625 | } 626 | }); 627 | } 628 | else { 629 | alert("ERROR: User preloaded agencies unavailable!! Please try again later.") 630 | } 631 | 632 | return; 633 | } 634 | 635 | // Function to Select GTFS Exchange Feed 636 | function selectFeed() { 637 | $("#mAgency").modal('show'); // Load dialogue window 638 | $diaName = "Agency"; // Set active dialogue name 639 | 640 | $.ajax({ 641 | url: $GTFS_API, 642 | method: "GET", 643 | dataType: "jsonp", 644 | success: function($data) { 645 | parseGTFS($data); 646 | } 647 | }); 648 | 649 | return; 650 | } 651 | 652 | // Function to Select GTFS ZIP File 653 | function selectZIP() { 654 | $("#mUploadZIP").modal("show"); // Load dialogue window 655 | $diaName = "Upload"; // Set active dialogue name 656 | $('#zipurl').prop('disabled', true); // Disable field until radio checked 657 | $('#zipfile').prop('disabled', true); // Disable field until radio checked 658 | 659 | return; 660 | } 661 | 662 | // Function to Validate and Upload ZIP File 663 | function uploadZIP() { 664 | 665 | 666 | // ADD VALIDATION HANDLING HERE 667 | if($ZipType == "url") alert($('#zipurl').val()); 668 | else alert($('#zipfile').val()); 669 | 670 | 671 | 672 | // Clear and close dialogue after validation 673 | $("#upload-ZIP").prop("disabled", true); 674 | $("#mUploadZIP").modal("hide"); 675 | $("input[name='ziptype']").prop("checked", false); // Clear radio boxes 676 | $diaName = null; // Clear active dilogue 677 | $ZipType = null; // Clear Radio Box Type 678 | $('#zipfile').val(""); // Clear field value 679 | $('#zipurl').val(""); // Clear field value 680 | 681 | return; 682 | } 683 | 684 | 685 | // HELPER (MONKEY) FUNCTIONS 686 | // ------------------------- 687 | 688 | // Function to Check if Agency Official 689 | function aIsOfficial($isOfficial) { 690 | if($isOfficial == true) { 691 | return ""; 692 | } 693 | else { 694 | return ""; 695 | } 696 | } 697 | 698 | // Function to Supplement Bus Stop Data 699 | function getBusStopInfo() { 700 | // For each bus stop 701 | for (var $i in $BusStops["stops"]) { 702 | $found = false; 703 | for (var $j in $TripData["stop_sequence"]) { 704 | if(!$found) { 705 | // If bus stop on current route, supplement data from trip data 706 | if($BusStops["stops"][$i]["stop_id"] == $TripData["stop_sequence"][$j]["stop_id"]) { 707 | $found = true; 708 | $BusStops["stops"][$i]["on_trip"] = true; 709 | $BusStops["stops"][$i]["arrival_time"] = $TripData["stop_sequence"][$j]["arrival_time"]; 710 | $BusStops["stops"][$i]["departure_time"] = $TripData["stop_sequence"][$j]["departure_time"]; 711 | } 712 | else { // When bus stop not within trip route 713 | $BusStops["stops"][$i]["on_trip"] = false; 714 | $BusStops["stops"][$i]["arrival_time"] = ""; 715 | $BusStops["stops"][$i]["departure_time"] = ""; 716 | } 717 | } 718 | } 719 | } 720 | return; 721 | } 722 | 723 | // Function to Convert ISO Date String to Long Date Format 724 | function ISOtoLongDate($isostr) { 725 | // Check for ISO String Format 726 | if($isostr.length == 8 || $isostr.length == 10) { 727 | if($isostr.length == 8) { 728 | $isostr = insertStr(insertStr($isostr, 6, "-"), 4, "-"); 729 | } 730 | // Convert to Long Date Format 731 | $longdate = new Date($isostr + " 00:00"); 732 | return $longdate.toDateString(); 733 | } 734 | else { 735 | return "!ERROR"; 736 | } 737 | } 738 | 739 | // Function to Make Bus Stop HTML for Marker Info Windows 740 | function makeBusStopHTML($bsdata) { 741 | if($bsdata["on_trip"]) { 742 | var $bsHTML = "
" + 743 | "" + $bsdata["stop_name"] + "
" + 744 | "Stop ID: " + $bsdata["stop_id"] + "
" + 745 | "Arrival: " + $bsdata["arrival_time"] + "
" + 746 | "Departure: " + $bsdata["departure_time"] + "
" + 747 | "
"; 748 | } 749 | else { 750 | var $bsHTML = "
" + 751 | "" + $bsdata["stop_name"] + "
" + 752 | "Stop ID: " + $bsdata["stop_id"] + "
" + 753 | "
"; 754 | } 755 | return $bsHTML; 756 | } 757 | 758 | // Function to Parse GTFS Data 759 | function parseGTFS($gtfsjson) { 760 | $AgencyData = $gtfsjson; // Save Active GTFS Global Object 761 | var $gtfsline = ""; 762 | var $aCount = 0; 763 | for(var $i = 0; $i < $gtfsjson["data"].length; $i++) { 764 | // Verify Feed Link Present 765 | if($GTFS_ZIP.test($gtfsjson["data"][$i]["feed_baseurl"])) { // Test whether feed contains '.zip' extension 766 | // Check if official feed 767 | $isOfficial = aIsOfficial($gtfsjson["data"][$i]["is_official"]) 768 | // Construct GTFS List 769 | $gtfsline += "
" + $isOfficial + " " + $gtfsjson["data"][$i]["name"]; 771 | $gtfsline += "
"; 772 | $aCount++; 773 | } 774 | } 775 | // Output Results 776 | $("#agency-data").html($gtfsline); 777 | $("#aTotal").html("Total Agencies: " + $aCount); 778 | return; 779 | } 780 | 781 | // Function to Set or Clear Map Bound Coordinates 782 | function scMapBndCoord($scsave, $mbounds) { 783 | var $NE = $mbounds.getNorthEast(); 784 | var $SW = $mbounds.getSouthWest(); 785 | if($scsave == "set") { 786 | $MapBounds["upLat"] = $NE.lat(); 787 | $MapBounds["loLat"] = $SW.lat(); 788 | $MapBounds["ltLng"] = $SW.lng(); 789 | $MapBounds["rtLng"] = $NE.lng(); 790 | } 791 | else { 792 | $MapBounds["upLat"] = null; 793 | $MapBounds["loLat"] = null; 794 | $MapBounds["ltLng"] = null; 795 | $MapBounds["rtLng"] = null; 796 | } 797 | 798 | return; 799 | } 800 | 801 | // Function to Sort Previous and Current Bus Stops 802 | function sortBusStops($prevbs, $currbs) { 803 | // Initialize add and remove lists 804 | var $addbs = []; 805 | var $rembs = []; 806 | // Check for first condition 807 | if($prevbs != null) { 808 | // Look for added bus stop location data 809 | for(var $i in $currbs["stops"]) { 810 | var $found = false; 811 | for(var $j in $prevbs["stops"]) { 812 | if($currbs["stops"][$i]["stop_id"] == $prevbs["stops"][$j]["stop_id"]) $found = true; 813 | } 814 | if(!$found) $addbs.push($currbs["stops"][$i]); 815 | } 816 | // Look for removed bus stop location data 817 | for(var $i in $prevbs["stops"]) { 818 | var $found = false; 819 | for(var $j in $currbs["stops"]) { 820 | if($prevbs["stops"][$i]["stop_id"] == $currbs["stops"][$j]["stop_id"]) $found = true; 821 | } 822 | if(!$found) $rembs.push($prevbs["stops"][$i]); 823 | } 824 | } 825 | else $addbs = $currbs["stops"]; // On first condition 826 | return [$addbs, $rembs]; 827 | } 828 | 829 | // Functions to Validate Trip Data 830 | function valTripData($tdata) { 831 | if($tdata["service_id"] == []) { 832 | return "ERROR: Service ID failed to resolve for selected date and time!!"; 833 | } 834 | if($tdata["trip_id"] == []) { 835 | return "ERROR: Initial Trip ID failed to resolve for selected date and time!!"; 836 | } 837 | if($tdata["trip_id"] == -1 || $tdata["stop_sequence"] == []) { 838 | return "ERROR: Final Trip ID and/or Stop Sequence failed to resolve for selected date and time!!"; 839 | } 840 | if($tdata["shape_id"] == -1 || $tdata["service_id"] == -1) { 841 | return "ERROR: Shape ID and/or Service ID failed to resolve for selected date and time!!"; 842 | } 843 | if($tdata["shape_sequence"] == []) { 844 | return "ERROR: Shape Sequence failed to resolve for selected date and time!!"; 845 | } 846 | 847 | return "success"; 848 | } 849 | 850 | // TEMP FOR TESTING 851 | function removeUUID() { 852 | $UUID = null; 853 | localStorage.setItem("uuid", $UUID) 854 | alert("UUID is " + localStorage.getItem("uuid")); 855 | 856 | return; 857 | } 858 | 859 | // Function to Insert Into String 860 | function insertStr(str, index, value) { 861 | return str.substr(0, index) + value + str.substr(index); 862 | } 863 | 864 | 865 | // ########################################################################################################## 866 | // MAIN PROGRAM 867 | // ########################################################################################################## 868 | 869 | // When HTML Document Loaded, Add Event Listeners Here 870 | $(document).ready(function() { 871 | // Procedures to call with AJAX Start 872 | $(document).ajaxStart(function() { 873 | // Start Spinner Object 874 | $("
 
").appendTo("body"); 875 | $spinner.spin($("#spinner_center")[0]); 876 | $ajax_cnt++; 877 | }); 878 | 879 | // Procedures to call with AJAX Stop 880 | $(document).ajaxStop(function() { 881 | // Stop Spinner Object 882 | $ajax_cnt--; 883 | if ($ajax_cnt <= 0) { 884 | $spinner.stop(); 885 | $("#spinner_center").remove(); 886 | $ajax_cnt = 0; 887 | } 888 | }); 889 | 890 | 891 | /* INITIALIZE ON DOCUMENT READY */ 892 | 893 | // Initialize Route Date/Time Picker 894 | $("#datetime").datetimepicker({ 895 | format: "ddd MMM DD YYYY, HH:mm" 896 | //defaultDate: new Date("2015-07-01"), 897 | //minDate: new Date("2015-07-01 00:00"), 898 | //maxDate: new Date("2015-07-31 23:59") 899 | }); 900 | $("#datetime").children().prop("disabled", true); 901 | 902 | // Event Handler to Load Transit Routes on Transit Agency Change 903 | $("#agency").change(function() { 904 | loadRoutes(); 905 | }); 906 | 907 | 908 | /* EVENT HANDLERS */ 909 | 910 | // Event Handler to Create Map from Route Data 911 | $("#create-map").on("click", function() { 912 | createTripMap(); 913 | }); 914 | // Event Handler to Manage Clicks and Double Clicks on Google Map 915 | /*$("#gmap").on("click", function() { 916 | ehMapClick(); 917 | }); 918 | $("#gmap").on("dblclick", function() { 919 | ehMapClick(); 920 | }); */ 921 | // Event Handler to Load Selected Agency ZIP on Click 922 | $("#load-agency").on("click", function() { 923 | loadAgency(); 924 | }); 925 | // Event Handler to Select Feed Agency on Click 926 | $("#select-feed").on("click", function() { 927 | selectFeed(); 928 | }); 929 | // Event Handler to Select Upload Method on Click 930 | $("#select-zip").on("click", function() { 931 | selectZIP(); 932 | }); 933 | // Event Handler to Upload ZIP from URL or File 934 | $("#upload-ZIP").on("click", function() { 935 | uploadZIP(); 936 | }); 937 | 938 | 939 | 940 | // TEMP FOR TESTING 941 | $("#remuuid").on("click", function() { 942 | removeUUID(); 943 | }); 944 | 945 | // Event Handler for All Popovers 946 | $("[data-toggle='popover']").popover(); 947 | 948 | // ZIP File Form Validator 949 | /* 950 | jQuery.validator.setDefaults({ 951 | debug: true, 952 | success: "valid" 953 | }); 954 | $("#zipform").validate({ 955 | rules: { 956 | zipurl: { 957 | //regex: /(http(s?):)|([/|.|\w|\s])*\.(?:zip)/, 958 | regex: /(http(s?):)|([/|.|\w|\s])*\.(zip)/, 959 | required: "#zipfile:blank" 960 | }, 961 | zipfile: { 962 | //minlength: 2, 963 | //accept: "application/octet-stream,application/zip,application/x-zip,application/x-zip-compressed", 964 | required: "#zipurl:blank", 965 | extension: "zip" 966 | //accept: "application/zip,application/octet-stream,application/x-zip,application/x-zip-compressed" 967 | } 968 | }, 969 | highlight: function (e) { 970 | $(e).closest('.control-group').removeClass('success').addClass('error'); 971 | }, 972 | success: function (e) { 973 | e.text('OK!').addClass('valid') 974 | .closest('.control-group').removeClass('error').addClass('success'); 975 | } 976 | });*/ 977 | }); 978 | 979 | // Determine ZIP Radio Button Value and Call Function //// CONSIDER MOVING INTO DOC READY 980 | $(document).on("change", "input[name='ziptype']:radio", function() { 981 | $ZipType = $(this).val(); 982 | $('#upload-ZIP').prop('disabled', false); 983 | if($(this).val() == "url") { 984 | $('#zipurl').prop('disabled', false); 985 | $('#zipfile').prop('disabled', true); 986 | $('#zipfile').val(""); // Clear disabled field value 987 | } 988 | else { 989 | $('#zipurl').prop('disabled', true); 990 | $('#zipfile').prop('disabled', false); 991 | $('#zipurl').val(""); // Clear disabled field value 992 | } 993 | }); 994 | 995 | // Create and/or Verify Unique User ID on Client Side 996 | createUUID(); //// TEMP - CONSIDER MOVING INTO DOCUMENT READY FOR PRODUCTION 997 | 998 | 999 | // ########################################################################################################## 1000 | // END OF SCRIPT 1001 | // ########################################################################################################## --------------------------------------------------------------------------------
").addClass("cw").text("#"));c.isBefore(l.clone().endOf("w"));)b.append(a("").addClass("dow").text(c.format("dd"))),c.add(1,"d");o.find(".datepicker-days thead").append(b)},L=function(a){return d.disabledDates[a.format("YYYY-MM-DD")]===!0},M=function(a){return d.enabledDates[a.format("YYYY-MM-DD")]===!0},N=function(a){return d.disabledHours[a.format("H")]===!0},O=function(a){return d.enabledHours[a.format("H")]===!0},P=function(b,c){if(!b.isValid())return!1;if(d.disabledDates&&"d"===c&&L(b))return!1;if(d.enabledDates&&"d"===c&&!M(b))return!1;if(d.minDate&&b.isBefore(d.minDate,c))return!1;if(d.maxDate&&b.isAfter(d.maxDate,c))return!1;if(d.daysOfWeekDisabled&&"d"===c&&-1!==d.daysOfWeekDisabled.indexOf(b.day()))return!1;if(d.disabledHours&&("h"===c||"m"===c||"s"===c)&&N(b))return!1;if(d.enabledHours&&("h"===c||"m"===c||"s"===c)&&!O(b))return!1;if(d.disabledTimeIntervals&&("h"===c||"m"===c||"s"===c)){var e=!1;if(a.each(d.disabledTimeIntervals,function(){return b.isBetween(this[0],this[1])?(e=!0,!1):void 0}),e)return!1}return!0},Q=function(){for(var b=[],c=l.clone().startOf("y").startOf("d");c.isSame(l,"y");)b.push(a("").attr("data-action","selectMonth").addClass("month").text(c.format("MMM"))),c.add(1,"M");o.find(".datepicker-months td").empty().append(b)},R=function(){var b=o.find(".datepicker-months"),c=b.find("th"),d=b.find("tbody").find("span");c.eq(0).find("span").attr("title","Previous Year"),c.eq(1).attr("title","Select Year"),c.eq(2).find("span").attr("title","Next Year"),b.find(".disabled").removeClass("disabled"),P(l.clone().subtract(1,"y"),"y")||c.eq(0).addClass("disabled"),c.eq(1).text(l.year()),P(l.clone().add(1,"y"),"y")||c.eq(2).addClass("disabled"),d.removeClass("active"),k.isSame(l,"y")&&!m&&d.eq(k.month()).addClass("active"),d.each(function(b){P(l.clone().month(b),"M")||a(this).addClass("disabled")})},S=function(){var a=o.find(".datepicker-years"),b=a.find("th"),c=l.clone().subtract(5,"y"),e=l.clone().add(6,"y"),f="";for(b.eq(0).find("span").attr("title","Previous Decade"),b.eq(1).attr("title","Select Decade"),b.eq(2).find("span").attr("title","Next Decade"),a.find(".disabled").removeClass("disabled"),d.minDate&&d.minDate.isAfter(c,"y")&&b.eq(0).addClass("disabled"),b.eq(1).text(c.year()+"-"+e.year()),d.maxDate&&d.maxDate.isBefore(e,"y")&&b.eq(2).addClass("disabled");!c.isAfter(e,"y");)f+=''+c.year()+"",c.add(1,"y");a.find("td").html(f)},T=function(){var a=o.find(".datepicker-decades"),c=a.find("th"),e=b(l.isBefore(b({y:1999}))?{y:1899}:{y:1999}),f=e.clone().add(100,"y"),g="";for(c.eq(0).find("span").attr("title","Previous Century"),c.eq(2).find("span").attr("title","Next Century"),a.find(".disabled").removeClass("disabled"),(e.isSame(b({y:1900}))||d.minDate&&d.minDate.isAfter(e,"y"))&&c.eq(0).addClass("disabled"),c.eq(1).text(e.year()+"-"+f.year()),(e.isSame(b({y:2e3}))||d.maxDate&&d.maxDate.isBefore(f,"y"))&&c.eq(2).addClass("disabled");!e.isAfter(f,"y");)g+=''+(e.year()+1)+" - "+(e.year()+12)+"",e.add(12,"y");g+="",a.find("td").html(g)},U=function(){var c,e,f,g,h=o.find(".datepicker-days"),i=h.find("th"),j=[];if(z()){for(i.eq(0).find("span").attr("title","Previous Month"),i.eq(1).attr("title","Select Month"),i.eq(2).find("span").attr("title","Next Month"),h.find(".disabled").removeClass("disabled"),i.eq(1).text(l.format(d.dayViewHeaderFormat)),P(l.clone().subtract(1,"M"),"M")||i.eq(0).addClass("disabled"),P(l.clone().add(1,"M"),"M")||i.eq(2).addClass("disabled"),c=l.clone().startOf("M").startOf("w").startOf("d"),g=0;42>g;g++)0===c.weekday()&&(e=a("
'+c.week()+"'+c.date()+"
'+c.format(f?"HH":"hh")+"
'+c.format("mm")+"
'+c.format("ss")+"