├── CNAME ├── .gitignore ├── stylesheets ├── ie.css ├── print.css ├── pygment_trac.css ├── stylesheet.css ├── normalize.css └── styles.css ├── javascripts ├── main.js └── respond.js ├── bus.png ├── findd.png ├── micro.jpg ├── s-bus.jpg ├── tempo.jpg ├── Bus Fare.pdf ├── image001.png ├── images ├── hr.gif ├── bg_hr.png ├── body-bg.jpg ├── bullet.png ├── nav-bg.gif ├── blacktocat.png ├── header-bg.jpg ├── sidebar-bg.jpg ├── highlight-bg.jpg ├── download-button.png ├── github-button.png ├── icon_download.png └── sprite_download.png ├── ktm_bhada.JPG ├── Tempo fare.pdf ├── yatayat office.GIF ├── lib ├── leaflet │ ├── images │ │ ├── findd.png │ │ ├── find_a.png │ │ ├── layers.png │ │ ├── zoom-in.png │ │ ├── zoom-out.png │ │ ├── marker-icon.png │ │ ├── marker-shadow.png │ │ └── popup-close.png │ ├── leaflet.ie.css │ ├── leaflet.spin.js │ ├── spin.min.js │ ├── Leaflet.PolylineDecorator │ │ └── leaflet.polylineDecorator.min.js │ └── leaflet.css ├── kdtree_readme.md ├── autocomplete_styles.css ├── routeinfopanel.js ├── yatayat.css ├── kdTree-min.js ├── jquery.autocomplete.min.js └── bootstrap │ └── js │ └── bootstrap.min.js ├── fonts ├── OpenSans-Bold-webfont.eot ├── OpenSans-Bold-webfont.ttf ├── OpenSans-Bold-webfont.woff ├── OpenSans-Italic-webfont.eot ├── OpenSans-Italic-webfont.ttf ├── OpenSans-Light-webfont.eot ├── OpenSans-Light-webfont.ttf ├── OpenSans-Light-webfont.woff ├── OpenSans-Italic-webfont.woff ├── OpenSans-Regular-webfont.eot ├── OpenSans-Regular-webfont.ttf ├── OpenSans-Regular-webfont.woff ├── OpenSans-Semibold-webfont.eot ├── OpenSans-Semibold-webfont.ttf ├── OpenSans-Semibold-webfont.woff ├── OpenSans-BoldItalic-webfont.eot ├── OpenSans-BoldItalic-webfont.ttf ├── OpenSans-BoldItalic-webfont.woff ├── OpenSans-LightItalic-webfont.eot ├── OpenSans-LightItalic-webfont.ttf ├── OpenSans-LightItalic-webfont.woff ├── OpenSans-SemiboldItalic-webfont.eot ├── OpenSans-SemiboldItalic-webfont.ttf └── OpenSans-SemiboldItalic-webfont.woff ├── .gitmodules ├── spec └── jasmine │ ├── jasmine_favicon.png │ ├── MIT.LICENSE │ ├── jasmine.css │ └── jasmine-html.js ├── config.local.js ├── todo.rst ├── bhadadar.html ├── config.stable.json ├── config.experimental.json ├── config.overpass.json ├── config.js ├── dump_gtfs.js ├── sample └── test.js ├── cli_dataquality.js ├── osmroutenames.html ├── README ├── tests.html ├── params.json ├── README.md ├── api.node.js ├── datasync.py ├── GTFO.js ├── data_quality.html └── dataquality.js /CNAME: -------------------------------------------------------------------------------- 1 | yatayat.monsooncollective.org 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .*.swp 2 | *.*~ 3 | .DS_STORE 4 | -------------------------------------------------------------------------------- /stylesheets/ie.css: -------------------------------------------------------------------------------- 1 | nav { 2 | display: none; 3 | } 4 | -------------------------------------------------------------------------------- /javascripts/main.js: -------------------------------------------------------------------------------- 1 | console.log('This would be the main JS file.'); 2 | -------------------------------------------------------------------------------- /bus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monsooncollective/yatayat/HEAD/bus.png -------------------------------------------------------------------------------- /findd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monsooncollective/yatayat/HEAD/findd.png -------------------------------------------------------------------------------- /micro.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monsooncollective/yatayat/HEAD/micro.jpg -------------------------------------------------------------------------------- /s-bus.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monsooncollective/yatayat/HEAD/s-bus.jpg -------------------------------------------------------------------------------- /tempo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monsooncollective/yatayat/HEAD/tempo.jpg -------------------------------------------------------------------------------- /Bus Fare.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monsooncollective/yatayat/HEAD/Bus Fare.pdf -------------------------------------------------------------------------------- /image001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monsooncollective/yatayat/HEAD/image001.png -------------------------------------------------------------------------------- /images/hr.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monsooncollective/yatayat/HEAD/images/hr.gif -------------------------------------------------------------------------------- /ktm_bhada.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monsooncollective/yatayat/HEAD/ktm_bhada.JPG -------------------------------------------------------------------------------- /Tempo fare.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monsooncollective/yatayat/HEAD/Tempo fare.pdf -------------------------------------------------------------------------------- /images/bg_hr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monsooncollective/yatayat/HEAD/images/bg_hr.png -------------------------------------------------------------------------------- /images/body-bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monsooncollective/yatayat/HEAD/images/body-bg.jpg -------------------------------------------------------------------------------- /images/bullet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monsooncollective/yatayat/HEAD/images/bullet.png -------------------------------------------------------------------------------- /images/nav-bg.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monsooncollective/yatayat/HEAD/images/nav-bg.gif -------------------------------------------------------------------------------- /yatayat office.GIF: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monsooncollective/yatayat/HEAD/yatayat office.GIF -------------------------------------------------------------------------------- /images/blacktocat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monsooncollective/yatayat/HEAD/images/blacktocat.png -------------------------------------------------------------------------------- /images/header-bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monsooncollective/yatayat/HEAD/images/header-bg.jpg -------------------------------------------------------------------------------- /images/sidebar-bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monsooncollective/yatayat/HEAD/images/sidebar-bg.jpg -------------------------------------------------------------------------------- /images/highlight-bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monsooncollective/yatayat/HEAD/images/highlight-bg.jpg -------------------------------------------------------------------------------- /images/download-button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monsooncollective/yatayat/HEAD/images/download-button.png -------------------------------------------------------------------------------- /images/github-button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monsooncollective/yatayat/HEAD/images/github-button.png -------------------------------------------------------------------------------- /images/icon_download.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monsooncollective/yatayat/HEAD/images/icon_download.png -------------------------------------------------------------------------------- /images/sprite_download.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monsooncollective/yatayat/HEAD/images/sprite_download.png -------------------------------------------------------------------------------- /lib/leaflet/images/findd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monsooncollective/yatayat/HEAD/lib/leaflet/images/findd.png -------------------------------------------------------------------------------- /fonts/OpenSans-Bold-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monsooncollective/yatayat/HEAD/fonts/OpenSans-Bold-webfont.eot -------------------------------------------------------------------------------- /fonts/OpenSans-Bold-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monsooncollective/yatayat/HEAD/fonts/OpenSans-Bold-webfont.ttf -------------------------------------------------------------------------------- /lib/leaflet/images/find_a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monsooncollective/yatayat/HEAD/lib/leaflet/images/find_a.png -------------------------------------------------------------------------------- /lib/leaflet/images/layers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monsooncollective/yatayat/HEAD/lib/leaflet/images/layers.png -------------------------------------------------------------------------------- /lib/leaflet/images/zoom-in.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monsooncollective/yatayat/HEAD/lib/leaflet/images/zoom-in.png -------------------------------------------------------------------------------- /lib/leaflet/images/zoom-out.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monsooncollective/yatayat/HEAD/lib/leaflet/images/zoom-out.png -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "docopt.coffee"] 2 | path = docopt.coffee 3 | url = https://github.com/scarnie/docopt.coffee.git 4 | -------------------------------------------------------------------------------- /fonts/OpenSans-Bold-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monsooncollective/yatayat/HEAD/fonts/OpenSans-Bold-webfont.woff -------------------------------------------------------------------------------- /fonts/OpenSans-Italic-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monsooncollective/yatayat/HEAD/fonts/OpenSans-Italic-webfont.eot -------------------------------------------------------------------------------- /fonts/OpenSans-Italic-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monsooncollective/yatayat/HEAD/fonts/OpenSans-Italic-webfont.ttf -------------------------------------------------------------------------------- /fonts/OpenSans-Light-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monsooncollective/yatayat/HEAD/fonts/OpenSans-Light-webfont.eot -------------------------------------------------------------------------------- /fonts/OpenSans-Light-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monsooncollective/yatayat/HEAD/fonts/OpenSans-Light-webfont.ttf -------------------------------------------------------------------------------- /fonts/OpenSans-Light-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monsooncollective/yatayat/HEAD/fonts/OpenSans-Light-webfont.woff -------------------------------------------------------------------------------- /spec/jasmine/jasmine_favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monsooncollective/yatayat/HEAD/spec/jasmine/jasmine_favicon.png -------------------------------------------------------------------------------- /fonts/OpenSans-Italic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monsooncollective/yatayat/HEAD/fonts/OpenSans-Italic-webfont.woff -------------------------------------------------------------------------------- /fonts/OpenSans-Regular-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monsooncollective/yatayat/HEAD/fonts/OpenSans-Regular-webfont.eot -------------------------------------------------------------------------------- /fonts/OpenSans-Regular-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monsooncollective/yatayat/HEAD/fonts/OpenSans-Regular-webfont.ttf -------------------------------------------------------------------------------- /fonts/OpenSans-Regular-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monsooncollective/yatayat/HEAD/fonts/OpenSans-Regular-webfont.woff -------------------------------------------------------------------------------- /fonts/OpenSans-Semibold-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monsooncollective/yatayat/HEAD/fonts/OpenSans-Semibold-webfont.eot -------------------------------------------------------------------------------- /fonts/OpenSans-Semibold-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monsooncollective/yatayat/HEAD/fonts/OpenSans-Semibold-webfont.ttf -------------------------------------------------------------------------------- /fonts/OpenSans-Semibold-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monsooncollective/yatayat/HEAD/fonts/OpenSans-Semibold-webfont.woff -------------------------------------------------------------------------------- /lib/leaflet/images/marker-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monsooncollective/yatayat/HEAD/lib/leaflet/images/marker-icon.png -------------------------------------------------------------------------------- /lib/leaflet/images/marker-shadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monsooncollective/yatayat/HEAD/lib/leaflet/images/marker-shadow.png -------------------------------------------------------------------------------- /lib/leaflet/images/popup-close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monsooncollective/yatayat/HEAD/lib/leaflet/images/popup-close.png -------------------------------------------------------------------------------- /fonts/OpenSans-BoldItalic-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monsooncollective/yatayat/HEAD/fonts/OpenSans-BoldItalic-webfont.eot -------------------------------------------------------------------------------- /fonts/OpenSans-BoldItalic-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monsooncollective/yatayat/HEAD/fonts/OpenSans-BoldItalic-webfont.ttf -------------------------------------------------------------------------------- /fonts/OpenSans-BoldItalic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monsooncollective/yatayat/HEAD/fonts/OpenSans-BoldItalic-webfont.woff -------------------------------------------------------------------------------- /fonts/OpenSans-LightItalic-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monsooncollective/yatayat/HEAD/fonts/OpenSans-LightItalic-webfont.eot -------------------------------------------------------------------------------- /fonts/OpenSans-LightItalic-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monsooncollective/yatayat/HEAD/fonts/OpenSans-LightItalic-webfont.ttf -------------------------------------------------------------------------------- /fonts/OpenSans-LightItalic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monsooncollective/yatayat/HEAD/fonts/OpenSans-LightItalic-webfont.woff -------------------------------------------------------------------------------- /fonts/OpenSans-SemiboldItalic-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monsooncollective/yatayat/HEAD/fonts/OpenSans-SemiboldItalic-webfont.eot -------------------------------------------------------------------------------- /fonts/OpenSans-SemiboldItalic-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monsooncollective/yatayat/HEAD/fonts/OpenSans-SemiboldItalic-webfont.ttf -------------------------------------------------------------------------------- /fonts/OpenSans-SemiboldItalic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monsooncollective/yatayat/HEAD/fonts/OpenSans-SemiboldItalic-webfont.woff -------------------------------------------------------------------------------- /lib/kdtree_readme.md: -------------------------------------------------------------------------------- 1 | Was having errors using submodule. kdtree-min.js comes from: 2 | https://github.com/ubilabs/kd-tree-javascript/raw/d17f3291d77562d485858a147dabf78270a94c2e/kdTree-min.js 3 | 4 | -------------------------------------------------------------------------------- /config.local.js: -------------------------------------------------------------------------------- 1 | var YY = YY || {}; 2 | 3 | YY.API_URL = 'sample/26_june_2013.xml'; 4 | YY.GET_OR_POST = 'GET'; 5 | 6 | YY.LNG = 85.3; 7 | YY.LAT = 27.7; 8 | 9 | // export as a node module 10 | var module = module || {} 11 | module.exports = YY; 12 | -------------------------------------------------------------------------------- /todo.rst: -------------------------------------------------------------------------------- 1 | * emails, documentation, etc. get help from osm-nepal to get to dq-0. [pp, deadline: April 21] 2 | * Make videos, upload to youtube, add to OSM wiki [pp] 3 | * Once we hit DQ-0, re-convene [rmo, pp] 4 | * Progress report onto yatayat-dev list 5 | * Normalize transit types to one of (bus|microbus|tempo) [] 6 | * Show the fucking routes [pp, deadline: April 31st] 7 | -------------------------------------------------------------------------------- /bhadadar.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Bhadadar 5 | 6 | 7 | 8 | 9 |
10 |

Source : Department of Transport Management

11 |

Downloads:

12 | Tempo Fare
13 | Bus Fare

14 | Back to Home Page 15 | 16 | -------------------------------------------------------------------------------- /config.stable.json: -------------------------------------------------------------------------------- 1 | { 2 | "API_URL": "transit.stable.xml", 3 | "GET_OR_POST": "GET", 4 | "WAX": false, 5 | "TILE_SOURCE": "http://otile1.mqcdn.com/tiles/1.0.0/map/{z}/{x}/{y}.jpg", 6 | "ATTRIBUTION": "Tiles Courtesy of MapQuest ", 7 | "LNG": 85.35, 8 | "LAT": 27.7 9 | } -------------------------------------------------------------------------------- /config.experimental.json: -------------------------------------------------------------------------------- 1 | { 2 | "API_URL": "transit.experimental.xml", 3 | "GET_OR_POST": "GET", 4 | "WAX": true, 5 | "TILE_SOURCE": "http://a.tiles.mapbox.com/v3/amritkarma.map-6c5zckhu.jsonp", 6 | "ATTRIBUTION": "Tiles Courtesy of MapQuest ", 7 | "LNG": 85.3, 8 | "LAT": 27.7 9 | } -------------------------------------------------------------------------------- /config.overpass.json: -------------------------------------------------------------------------------- 1 | { 2 | "API_URL": "http://www.overpass-api.de/api/interpreter", 3 | "QUERY_STRING": " ", 4 | "GET_OR_POST": "POST", 5 | "WAX": true, 6 | "TILE_SOURCE": "http://a.tiles.mapbox.com/v3/modilabs.map-p543gvbh.jsonp", 7 | "ATTRIBUTION": "Tiles Courtesy of MapQuest ", 8 | "LNG": 85.3, 9 | "LAT": 27.7 10 | } -------------------------------------------------------------------------------- /lib/autocomplete_styles.css: -------------------------------------------------------------------------------- 1 | body { font-family: sans-serif; font-size: 14px; line-height: 1.6em; margin: 0; padding: 0; } 2 | .container { width: 800px; margin: 0 auto; } 3 | 4 | .autocomplete-suggestions { border: 1px solid #999; background: #FFF; cursor: default; overflow: auto; -webkit-box-shadow: 1px 4px 3px rgba(50, 50, 50, 0.64); -moz-box-shadow: 1px 4px 3px rgba(50, 50, 50, 0.64); box-shadow: 1px 4px 3px rgba(50, 50, 50, 0.64); } 5 | .autocomplete-suggestion { padding: 2px 5px; white-space: nowrap; overflow: hidden; } 6 | .autocomplete-selected { background: #F0F0F0; } 7 | .autocomplete-suggestions strong { font-weight: normal; color: #3399FF; } 8 | 9 | input { font-size: 28px; padding: 10px; border: 1px solid #CCC; display: block; margin: 20px 0; } 10 | -------------------------------------------------------------------------------- /config.js: -------------------------------------------------------------------------------- 1 | var YY = YY || {}; 2 | 3 | YY.API_URL = 'http://www.overpass-api.de/api/interpreter'; 4 | YY.QUERY_STRING = ' '; 5 | YY.GET_OR_POST = 'POST'; 6 | 7 | // Alternative layerings: 8 | // http://{s}.tile.cloudmade.com/[API-key]/997/256/ 9 | // http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png 10 | YY.WAX = true; 11 | YY.TILE_SOURCE = 'http://a.tiles.mapbox.com/v3/modilabs.map-p543gvbh.jsonp'; // 'http://otile1.mqcdn.com/tiles/1.0.0/osm/{z}/{x}/{y}.png'; 12 | YY.ATTRIBUTION = 'Tiles Courtesy of MapQuest '; 13 | 14 | YY.LNG = 85.3; 15 | YY.LAT = 27.7; 16 | 17 | // export as a node module 18 | var module = module || {} 19 | module.exports = YY; 20 | -------------------------------------------------------------------------------- /dump_gtfs.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env nodejs 2 | 3 | var YY = require('./yatayat.js'); 4 | var GTFO = require('./GTFO.js'); 5 | 6 | var fs = require("fs"); 7 | 8 | var USAGE = "./dump_gtfs.js OVERPASS.xml" 9 | 10 | var AGENCIES = [ 11 | {name: "Microbus", filter: "bus", url: "http://yatayat.monsooncollective.org/#agency:micro"}, 12 | {name: "Tempo", filter: "tempo", url: "http://yatayat.monsooncollective.org/#agency:tempo"} 13 | ]; 14 | 15 | // Get "system" -- assumes that overpass XML is stored locally 16 | if(process.argv.length < 3) { 17 | console.log(USAGE); 18 | throw "dump_gtfs requires path to XML data"; 19 | } 20 | 21 | // Load system as YY.System 22 | var system = YY.fromOSM(fs.readFileSync(process.argv[2], "utf-8")); 23 | 24 | AGENCIES.forEach(function(agency) { 25 | var gtfo = new GTFO(system, agency); 26 | var csvs = gtfo.generate_csvs(); 27 | 28 | for(var key in csvs) { 29 | fs.writeFileSync(agency.name + "-" + key + ".txt", csvs[key]); 30 | } 31 | }); 32 | -------------------------------------------------------------------------------- /sample/test.js: -------------------------------------------------------------------------------- 1 | var tlat = 27.7; 2 | var tlng = 85.3; 3 | 4 | var routes = []; 5 | for(var i=0; i<5; i++) { 6 | var segments = []; 7 | var stops = []; 8 | 9 | var lastlat = tlat + 0.1*Math.random() - 0.05; 10 | var lastlng = tlng + 0.1*Math.random() - 0.05; 11 | 12 | var nsegs = 5 + Math.floor(15*Math.random()) 13 | for(var j=0; j [show_correct_routes] [--include-warnings]\n"; 9 | 10 | var opts = docopt.docopt(docstring); 11 | 12 | // Load system as YY.System 13 | var system = YY.fromOSM(fs.readFileSync(opts[''], "utf-8")); 14 | 15 | // Run tests: this will be silent if there are no errors 16 | if(opts['show_correct_routes']) { 17 | console.log("CORRECT ROUTES"); 18 | console.log(DQ.findCorrectRoutes(system).map(function(route) { 19 | return route.name + " (" + route.id + ")"; 20 | })); 21 | } else { 22 | var errors = DQ.errorString(system); 23 | if(errors.length > 0) 24 | console.log("\n\n~~~~~~~~~~~ERRORS:~~~~~~~~~~~~~~\n\n" + errors); 25 | if (opts['--include-warnings']) { 26 | var warnings = DQ.errorString(system, 'WARNING'); 27 | if(warnings.length > 0) 28 | console.log("\n\n~~~~~~~~~~~WARNINGS:~~~~~~~~~~~~~~\n\n" + warnings); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /lib/leaflet/leaflet.ie.css: -------------------------------------------------------------------------------- 1 | .leaflet-vml-shape { 2 | width: 1px; 3 | height: 1px; 4 | } 5 | .lvml { 6 | behavior: url(#default#VML); 7 | display: inline-block; 8 | position: absolute; 9 | } 10 | 11 | .leaflet-control { 12 | display: inline; 13 | } 14 | 15 | .leaflet-popup-tip { 16 | width: 21px; 17 | _width: 27px; 18 | margin: 0 auto; 19 | _margin-top: -3px; 20 | 21 | filter: progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678); 22 | -ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)"; 23 | } 24 | .leaflet-popup-tip-container { 25 | margin-top: -1px; 26 | } 27 | .leaflet-popup-content-wrapper, .leaflet-popup-tip { 28 | border: 1px solid #bbb; 29 | } 30 | 31 | .leaflet-control-zoom { 32 | filter: progid:DXImageTransform.Microsoft.gradient(startColorStr='#3F000000',EndColorStr='#3F000000'); 33 | } 34 | .leaflet-control-zoom a { 35 | background-color: #eee; 36 | } 37 | .leaflet-control-zoom a:hover { 38 | background-color: #fff; 39 | } 40 | .leaflet-control-layers-toggle { 41 | } 42 | .leaflet-control-attribution, .leaflet-control-layers { 43 | background: white; 44 | } -------------------------------------------------------------------------------- /osmroutenames.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Kathmandu Public Transport 4 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | == HACKING / DEPLOYING 2 | 3 | ==== submodules 4 | yatayat uses a kdtree implementation from @ubilabs on github; to 5 | use it you will need to run 6 | 7 | % git submodule init 8 | % git submodule update 9 | 10 | inside your cloned repository 11 | 12 | ==== config 13 | config.js pulls from a overpass-api directly; to develop locally, 14 | you can symlink config.local.js to config.js, but please be 15 | careful not to commit your symlinked file 16 | 17 | % ln -s config.local.js config.js 18 | 19 | 20 | == Data Model 21 | OSM Data is transformed into Routes, Stops, and Segments: 22 | 23 | Route: 24 | - id 25 | - name 26 | - ref // route number 27 | - transport // type of transport; pulled from tag.type 28 | - stops: [] // are ordered 29 | - stopDict: {} // indexed by id 30 | - segments: [] 31 | - tag: {} 32 | 33 | Stop: 34 | - id 35 | - name 36 | - lat 37 | - lng 38 | - tag: {} 39 | 40 | Segment: // mostly useful to rendering and internal fns. 41 | - listOfLatLng: [(lat,lng), ...] 42 | - tag: {} 43 | 44 | == API 45 | 46 | We define a node.js-based API for external applications to make 47 | high-level queries of public transit data. 48 | 49 | % node api.node.js 50 | 51 | + http://localhost:8020/route 52 | 53 | Returns all routes and stops as a JSON object. 54 | 55 | The API requires that jquery and underscore be installed for node: 56 | 57 | % npm install underscore 58 | % npm install jquery 59 | -------------------------------------------------------------------------------- /lib/leaflet/leaflet.spin.js: -------------------------------------------------------------------------------- 1 | L.SpinMapMixin = { 2 | spin: function (state) { 3 | var state = !!state; 4 | if (state) { 5 | // start spinning ! 6 | if (!this._spinner) { 7 | this._spinner = new Spinner().spin(this._container); 8 | this._spinning = 0; 9 | } 10 | this._spinning++; 11 | } 12 | else { 13 | this._spinning--; 14 | if (this._spinning <= 0) { 15 | // end spinning ! 16 | if (this._spinner) { 17 | this._spinner.stop(); 18 | this._spinner = null; 19 | } 20 | } 21 | } 22 | } 23 | }; 24 | 25 | L.Map.include(L.SpinMapMixin); 26 | 27 | L.Map.addInitHook(function () { 28 | this.on('layeradd', function (e) { 29 | // If added layer is currently loading, spin ! 30 | if (e.layer.loading) this.spin(true); 31 | if (typeof e.layer.on != 'function') return; 32 | e.layer.on('data:loading', function () { this.spin(true) }, this); 33 | e.layer.on('data:loaded', function () { this.spin(false) }, this); 34 | }, this); 35 | this.on('layerremove', function (e) { 36 | // Clean-up 37 | if (e.layer.loading) this.spin(false); 38 | if (typeof e.layer.on != 'function') return; 39 | e.layer.off('data:loaded'); 40 | e.layer.off('data:loading'); 41 | }, this); 42 | }); 43 | -------------------------------------------------------------------------------- /lib/routeinfopanel.js: -------------------------------------------------------------------------------- 1 | // route information sidebar 2 | 3 | function routeinfopanel(routes) { 4 | var panel = document.getElementById("routename"); 5 | var rdiv = document.createElement('div'); 6 | rdiv.setAttribute("class", "btn-group"); 7 | rdiv.setAttribute("data-toggle", "buttons"); 8 | panel.appendChild(rdiv); 9 | c = 0; 10 | //sorting the routes 11 | var route_names_dict = {}; 12 | 13 | var route_names = []; 14 | 15 | _(routes).each(function(r) { 16 | route_names_dict[r.name] = r.id; 17 | route_names.push(r.name); 18 | }); 19 | 20 | var sorted_obj = {}; 21 | 22 | route_names.sort(); 23 | // debugger; 24 | _(route_names).each(function(rn) { 25 | // sorted_obj[rn] = route_names_dict[rn]; 26 | routeid = route_names_dict[rn]; 27 | r = routes[routeid]; 28 | // console.log("%s,%s",r.name,r.id); 29 | var button = document.createElement('input'); 30 | button.type = 'radio'; 31 | button.name = 'options'; 32 | button.id = routeid; 33 | // button.id = c++; //make this the routes' id 34 | button.setAttribute("onclick", "YY.single_route_render(system,system.routeDict[this.id])"); 35 | // button.setAttribute("data-toggle","button"); 36 | var label = document.createElement('label'); 37 | label.setAttribute("class", "btn btn-default"); 38 | label.innerHTML = r.name; 39 | label.appendChild(button); 40 | rdiv.appendChild(label); 41 | }) 42 | } -------------------------------------------------------------------------------- /tests.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | Jasmine Spec Runner 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /lib/yatayat.css: -------------------------------------------------------------------------------- 1 | 81 | 82 | -------------------------------------------------------------------------------- /params.json: -------------------------------------------------------------------------------- 1 | {"name":"Yatayat","tagline":"Kathmandu Public Transport App","body":"### Welcome to GitHub Pages.\r\nThis automatic page generator is the easiest way to create beautiful pages for all of your projects. Author your page content here using GitHub Flavored Markdown, select a template crafted by a designer, and publish. After your page is generated, you can check out the new branch:\r\n\r\n```\r\n$ cd your_repo_root/repo_name\r\n$ git fetch origin\r\n$ git checkout gh-pages\r\n```\r\n\r\nIf you're using the GitHub for Mac, simply sync your repository and you'll see the new branch.\r\n\r\n### Designer Templates\r\nWe've crafted some handsome templates for you to use. Go ahead and continue to layouts to browse through them. You can easily go back to edit your page before publishing. After publishing your page, you can revisit the page generator and switch to another theme. Your Page content will be preserved if it remained markdown format.\r\n\r\n### Rather Drive Stick?\r\nIf you prefer to not use the automatic generator, push a branch named `gh-pages` to your repository to create a page manually. In addition to supporting regular HTML content, GitHub Pages support Jekyll, a simple, blog aware static site generator written by our own Tom Preston-Werner. Jekyll makes it easy to create site-wide headers and footers without having to copy them across every page. It also offers intelligent blog support and other advanced templating features.\r\n\r\n### Authors and Contributors\r\nYou can @mention a GitHub username to generate a link to their profile. The resulting `` element will link to the contributor's GitHub Profile. For example: In 2007, Chris Wanstrath (@defunkt), PJ Hyett (@pjhyett), and Tom Preston-Werner (@mojombo) founded GitHub.\r\n\r\n### Support or Contact\r\nHaving trouble with Pages? Check out the documentation at http://help.github.com/pages or contact support@github.com and we’ll help you sort it out.\r\n","google":"","note":"Don't delete this file! It's used internally to help with page regeneration."} -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Yatayat 2 | -- 3 | Kathmandu Public Transport 4 | 5 | Openstreetmap-based point-to-point routing, developed for Kathmandu. 6 | 7 | ## HACKING / DEPLOYING 8 | 9 | ### submodules 10 | yatayat uses a kdtree implementation from @ubilabs on github; to 11 | use it you will need to run 12 | 13 | ```sh 14 | % git submodule init 15 | % git submodule update 16 | ``` 17 | 18 | inside your cloned repository 19 | 20 | ### config 21 | config.js pulls from a overpass-api directly; to develop locally, 22 | you can symlink config.local.js to config.js, but please be 23 | careful not to commit your symlinked file 24 | 25 | ```sh 26 | % ln -s config.local.js config.js 27 | ``` 28 | 29 | ## Data Model 30 | OSM Data is transformed into Routes, Stops, and Segments: 31 | 32 | ### Route: 33 | - id 34 | - name 35 | - ref // route number 36 | - transport // type of transport; pulled from tag.type 37 | - stops: [] // are ordered 38 | - stopDict: {} // indexed by id 39 | - segments: [] 40 | - tag: {} 41 | 42 | ### Stop: 43 | - id 44 | - name 45 | - lat 46 | - lng 47 | - tag: {} 48 | 49 | ### Segment: 50 | - listOfLatLng: [(lat,lng), ...] 51 | - tag: {} 52 | 53 | ## CLI 54 | 55 | ### data quality. 56 | 57 | These make use of nodejs. On Debian-based systems, 58 | all external dependencies can be installed via APT: 59 | 60 | ```sh 61 | % apt-get install nodejs node-jquery node-underscore 62 | ``` 63 | 64 | Elsewhere, you can try your luck with NPM: 65 | 66 | ```sh 67 | % npm install jquery underscore docopt 68 | ``` 69 | 70 | Then, you can run: 71 | 72 | ```sh 73 | % nodejs cli_dataquality.js transit.experimental.xml 74 | ``` 75 | 76 | Additionally, the "datasync.py" python wrapper downloads the latest 77 | route information from OSM through overpass, checks for quality 78 | issues, and depending on the results of cli_dataquality, can e-mail 79 | relevant parties or else commit the new info into git. 80 | 81 | ### GTFS 82 | 83 | ```sh 84 | % nodejs dump_gtfs.js transit.experimental.xml 85 | ```# osm-nepal.github.io 86 | -------------------------------------------------------------------------------- /spec/jasmine/jasmine.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: "Helvetica Neue Light", "Lucida Grande", "Calibri", "Arial", sans-serif; 3 | } 4 | 5 | 6 | .jasmine_reporter a:visited, .jasmine_reporter a { 7 | color: #303; 8 | } 9 | 10 | .jasmine_reporter a:hover, .jasmine_reporter a:active { 11 | color: blue; 12 | } 13 | 14 | .run_spec { 15 | float:right; 16 | padding-right: 5px; 17 | font-size: .8em; 18 | text-decoration: none; 19 | } 20 | 21 | .jasmine_reporter { 22 | margin: 0 5px; 23 | } 24 | 25 | .banner { 26 | color: #303; 27 | background-color: #fef; 28 | padding: 5px; 29 | } 30 | 31 | .logo { 32 | float: left; 33 | font-size: 1.1em; 34 | padding-left: 5px; 35 | } 36 | 37 | .logo .version { 38 | font-size: .6em; 39 | padding-left: 1em; 40 | } 41 | 42 | .runner.running { 43 | background-color: yellow; 44 | } 45 | 46 | 47 | .options { 48 | text-align: right; 49 | font-size: .8em; 50 | } 51 | 52 | 53 | 54 | 55 | .suite { 56 | border: 1px outset gray; 57 | margin: 5px 0; 58 | padding-left: 1em; 59 | } 60 | 61 | .suite .suite { 62 | margin: 5px; 63 | } 64 | 65 | .suite.passed { 66 | background-color: #dfd; 67 | } 68 | 69 | .suite.failed { 70 | background-color: #fdd; 71 | } 72 | 73 | .spec { 74 | margin: 5px; 75 | padding-left: 1em; 76 | clear: both; 77 | } 78 | 79 | .spec.failed, .spec.passed, .spec.skipped { 80 | padding-bottom: 5px; 81 | border: 1px solid gray; 82 | } 83 | 84 | .spec.failed { 85 | background-color: #fbb; 86 | border-color: red; 87 | } 88 | 89 | .spec.passed { 90 | background-color: #bfb; 91 | border-color: green; 92 | } 93 | 94 | .spec.skipped { 95 | background-color: #bbb; 96 | } 97 | 98 | .messages { 99 | border-left: 1px dashed gray; 100 | padding-left: 1em; 101 | padding-right: 1em; 102 | } 103 | 104 | .passed { 105 | background-color: #cfc; 106 | display: none; 107 | } 108 | 109 | .failed { 110 | background-color: #fbb; 111 | } 112 | 113 | .skipped { 114 | color: #777; 115 | background-color: #eee; 116 | display: none; 117 | } 118 | 119 | 120 | /*.resultMessage {*/ 121 | /*white-space: pre;*/ 122 | /*}*/ 123 | 124 | .resultMessage span.result { 125 | display: block; 126 | line-height: 2em; 127 | color: black; 128 | } 129 | 130 | .resultMessage .mismatch { 131 | color: black; 132 | } 133 | 134 | .stackTrace { 135 | white-space: pre; 136 | font-size: .8em; 137 | margin-left: 10px; 138 | max-height: 5em; 139 | overflow: auto; 140 | border: 1px inset red; 141 | padding: 1em; 142 | background: #eef; 143 | } 144 | 145 | .finished-at { 146 | padding-left: 1em; 147 | font-size: .6em; 148 | } 149 | 150 | .show-passed .passed, 151 | .show-skipped .skipped { 152 | display: block; 153 | } 154 | 155 | 156 | #jasmine_content { 157 | position:fixed; 158 | right: 100%; 159 | } 160 | 161 | .runner { 162 | border: 1px solid gray; 163 | display: block; 164 | margin: 5px 0; 165 | padding: 2px 0 2px 10px; 166 | } 167 | -------------------------------------------------------------------------------- /api.node.js: -------------------------------------------------------------------------------- 1 | var http = require('http'); 2 | var url = require('url'); 3 | var yy = require('./yatayat.js') 4 | var conf = require('./config.js') 5 | var _ = require('underscore'); 6 | 7 | // fetch overpass API data 8 | var system = {}; 9 | 10 | // split API url into host and path 11 | var options = url.parse(conf.API_URL); 12 | options.method='POST'; 13 | 14 | var req = http.request(options, function(res) { 15 | res.content = ''; 16 | res.setEncoding('utf8'); 17 | res.on('data', function(chunk) { 18 | //console.log('CHUNK', chunk); 19 | res.content += chunk; 20 | }); 21 | res.on('end', function() { 22 | system = yy(res.content); 23 | console.log('got', system.routes.length, 'routes from overpass'); 24 | }); 25 | }); 26 | 27 | req.write(conf.QUERY_STRING); 28 | req.end(); 29 | 30 | function serializeStop(stop) { 31 | return {id: stop.id, 32 | lat: stop.lat, 33 | lng: stop.lng, 34 | name: stop.name}; 35 | } 36 | 37 | function serializeRoute(route, isPartialRoute) { 38 | // returns a JSON object for a route 39 | var fullRouteBool = !isPartialRoute; // ie. isPartialRoute is falsy 40 | return {id: route.id, 41 | name: route.name, 42 | ref: route.ref, 43 | transport: route.transport, 44 | fullroute: fullRouteBool, 45 | stops: route.stops.map(function(s) { return serializeStop(s); })}; 46 | } 47 | 48 | function serializeSystem(system) { 49 | return {routes: system.routes.map(function(r) { return serializeRoute(r); })}; 50 | } 51 | 52 | http.createServer(function (req, res) { 53 | console.log('REQUEST',req.url) 54 | 55 | // ALWAYS A JSON RESPONSE 56 | res.writeHead(200, {'Content-Type': 'application/json'}); 57 | 58 | var reqObj = url.parse(req.url, true); 59 | var path = reqObj.path; 60 | if(! _.keys(system).length) { 61 | res.end("Nothing loaded yet"); 62 | } else if (path.indexOf('routes') === 1) { 63 | res.end(JSON.stringify(serializeSystem(system), null, 4)); 64 | } else if (path.indexOf('nearestStops') === 1) { 65 | var ll = [reqObj.query.lat, reqObj.query.lng]; 66 | var stopArray = system.nearestStops(ll, 2); 67 | res.end(JSON.stringify(stopArray.map(serializeStop), 68 | null, 4)); 69 | } else if (path.indexOf('takeMeThere') === 1) { 70 | var routeArray = system.takeMeThere(reqObj.query.startStopID, 71 | reqObj.query.goalStopID); 72 | if (!routeArray.map) { res.end("No route found"); return; } 73 | var ret = routeArray.map(function(r) { return serializeRoute(r,true); }); 74 | res.end(JSON.stringify(ret, null, 4)); 75 | } else if (path.indexOf('getAllStops') === 1) { 76 | res.end(JSON.stringify(_.map(system.allStops(), serializeStop), null, 4)); 77 | } else { 78 | var jsonmessage = {"Access points" : [ 79 | { path: "/routes", description: "returns all routes"}, 80 | { path: "/nearestStops", params: ["lat", "lng"], 81 | description: "nearest stops to lat/lng position"}, 82 | { path: "/takeMeThere", params: ["startStopID", "goalStopID"], 83 | description: "return a list of partial routes to take when going from start to goal"}, 84 | { path: "/getAllStops", description: "returns all stops"}]}; 85 | res.end(JSON.stringify(jsonmessage, null, 4)); 86 | } 87 | }).listen(8020, "127.0.0.1"); 88 | console.log('yatayat api running at http://127.0.0.1:8020/'); 89 | -------------------------------------------------------------------------------- /lib/leaflet/spin.min.js: -------------------------------------------------------------------------------- 1 | (function(t,e){if(typeof exports=="object")module.exports=e();else if(typeof define=="function"&&define.amd)define(e);else t.Spinner=e()})(this,function(){"use strict";var t=["webkit","Moz","ms","O"],e={},i;function o(t,e){var i=document.createElement(t||"div"),o;for(o in e)i[o]=e[o];return i}function n(t){for(var e=1,i=arguments.length;e>1):parseInt(n.left,10)+s)+"px",top:(n.top=="auto"?l.y-a.y+(t.offsetHeight>>1):parseInt(n.top,10)+s)+"px"})}r.setAttribute("role","progressbar");e.lines(r,e.opts);if(!i){var u=0,p=(n.lines-1)*(1-n.direction)/2,c,h=n.fps,m=h/n.speed,y=(1-n.opacity)/(m*n.trail/100),g=m/n.lines;(function v(){u++;for(var t=0;t>1)+"px"})}for(;r',e)}r.addRule(".spin-vml","behavior:url(#default#VML)");p.prototype.lines=function(e,i){var o=i.length+i.width,r=2*o;function s(){return f(t("group",{coordsize:r+" "+r,coordorigin:-o+" "+-o}),{width:r,height:r})}var a=-(i.width+i.length)*2+"px",l=f(s(),{position:"absolute",top:a,left:a}),d;function u(e,r,a){n(l,n(f(s(),{rotation:360/i.lines*e+"deg",left:~~r}),n(f(t("roundrect",{arcsize:i.corners}),{width:o,height:i.width,left:i.radius,top:-i.width>>1,filter:a}),t("fill",{color:i.color,opacity:i.opacity}),t("stroke",{opacity:0}))))}if(i.shadow)for(d=1;d<=i.lines;d++)u(d,-2,"progid:DXImageTransform.Microsoft.Blur(pixelradius=2,makeshadow=1,shadowopacity=.3)");for(d=1;d<=i.lines;d++)u(d);return n(e,l)};p.prototype.opacity=function(t,e,i,o){var n=t.firstChild;o=o.shadow&&o.lines||0;if(n&&e+o, 2012 7 | * @author Martin Kleppe , 2012 8 | * @author Ubilabs http://ubilabs.net, 2012 9 | * @license MIT License 10 | */(function(e,t){if(typeof define==="function"&&define.amd){define(["exports"],t)}else if(typeof exports==="object"){t(exports)}else{t(e.commonJsStrict={})}})(this,function(e){function t(e,t,n){this.obj=e;this.left=null;this.right=null;this.parent=n;this.dimension=t}function n(e,n,i){function o(e,n,r){var s=n%i.length,u,a;if(e.length===0){return null}if(e.length===1){return new t(e[0],s,r)}e.sort(function(e,t){return e[i[s]]-t[i[s]]});u=Math.floor(e.length/2);a=new t(e[u],s,r);a.left=o(e.slice(0,u),n+1,a);a.right=o(e.slice(u+1),n+1,a);return a}function u(e){function t(e){if(e.left){e.left.parent=e;t(e.left)}if(e.right){e.right.parent=e;t(e.right)}}s.root=e;t(s.root)}var s=this;if(!Array.isArray(e))u(e,n,i);else this.root=o(e,0,null);this.toJSON=function(e){if(!e)e=this.root;var n=new t(e.obj,e.dimension,null);if(e.left)n.left=s.toJSON(e.left);if(e.right)n.right=s.toJSON(e.right);return n};this.insert=function(e){function n(t,r){if(t===null){return r}var s=i[t.dimension];if(e[s]r){a=s}if(o!==null&&o.obj[n]>a.obj[n]){a=o}return a}function a(e,t){var n,r,s,o,u;if(e===null){return null}n=i[t];if(e.dimension===t){if(e.left!==null){return a(e.left,t)}return e}r=e.obj[n];s=a(e.left,t);o=a(e.right,t);u=e;if(s!==null&&s.obj[n]t){f.pop()}}var s,o=i[r.dimension],u=n(e,r.obj),a={},c,h,p;for(p=0;p0){this.content[0]=t;this.sinkDown(0)}return e},peek:function(){return this.content[0]},remove:function(e){var t=this.content.length;for(var n=0;n0){var n=Math.floor((e+1)/2)-1,r=this.content[n];if(this.scoreFunction(t) 18 | Subject: %s 19 | 20 | %s 21 | """ % (address, subject, errors) 22 | p = subprocess.Popen(["/usr/lib/sendmail", '--', address], 23 | stdin=subprocess.PIPE) 24 | p.stdin.write(msg) 25 | p.stdin.close() 26 | p.wait() 27 | 28 | def pull(): 29 | subprocess.call(["git", "stash"]) 30 | subprocess.call(["git", "pull"]) 31 | 32 | def push(files): 33 | ret = subprocess.call(["git", "commit", "-m", "datasync: overpass files updated"] + files) 34 | if ret == 0: 35 | subprocess.call(["git", "push"]) 36 | 37 | def parse_args(): 38 | parser = argparse.ArgumentParser(description="synchronize osm data through the overpass API") 39 | parser.add_argument("--address", 40 | default="yatayat@numm.org", 41 | help="address to email with errors") 42 | parser.add_argument("--config", 43 | default="config.overpass.json", 44 | type=argparse.FileType('r'), 45 | help="JSON config file") 46 | parser.add_argument("--experimental", 47 | default="transit.experimental.xml", 48 | help="Where to download latest overpass data") 49 | parser.add_argument("--stable", 50 | default="transit.stable.xml", 51 | help="Where to put overpass data, if stable") 52 | parser.add_argument("--no-overpass", 53 | default=False, 54 | action="store_true", 55 | help="Don't download from overpass") 56 | parser.add_argument("--force", 57 | default=False, 58 | action="store_true", 59 | help="overwrite 'stable' even if tests fail") 60 | parser.add_argument("--silent", 61 | default=False, 62 | action="store_true", 63 | help="suppresses git or e-mail outputs") 64 | parser.add_argument("--no-pull", 65 | default=False, 66 | action="store_true", 67 | help="don't pull code from remote before running rest of script") 68 | return parser.parse_args() 69 | 70 | def run(): 71 | # Change CWD to location of this script 72 | os.chdir(os.path.abspath(os.path.dirname(__file__))) 73 | 74 | opts = parse_args() 75 | 76 | conf = json.load(opts.config) 77 | 78 | # update code & data 79 | if not opts.no_pull: 80 | pull() 81 | 82 | # Download latest data from overpass 83 | if not opts.no_overpass: 84 | open(opts.experimental, 'w').write( 85 | urllib2.urlopen(conf["API_URL"], data=conf["QUERY_STRING"]).read()) 86 | 87 | NODE = 'nodejs' # debian 88 | if sys.platform == 'darwin': # osx 89 | NODE = 'node' 90 | 91 | # Check data for quality errors 92 | ep = subprocess.Popen([NODE, "cli_dataquality.js", opts.experimental], 93 | stdout=subprocess.PIPE, stderr=subprocess.PIPE) 94 | e_out = ep.stdout.read() 95 | e_err = ep.stderr.read() 96 | wp = subprocess.Popen([NODE, "cli_dataquality.js", opts.experimental, '--include-warnings'], 97 | stdout=subprocess.PIPE, stderr=subprocess.PIPE) 98 | w_out = wp.stdout.read() 99 | w_err = wp.stderr.read() 100 | ## EMAIL 101 | if (len(e_err.strip()) > 0 or len(w_err.strip()) > 0) and not opts.force: 102 | # code-wise errors (!) 103 | if not opts.silent: 104 | email(opts.address, e_err + w_err, subject="URGENT JS ERRORS IN YATAYAT") 105 | if len(w_out.strip()) > 0 and not opts.silent: 106 | # warnings present -- email 107 | subject = "(warnings in yatayat overpass data)" if len(e_out.strip()) == 0 else "ERRORS detected in yatayat overpass data" 108 | email(opts.address, w_out, subject=subject) 109 | ## DATA 110 | if len(e_out.strip()) > 0 and not opts.force: 111 | # There were errors 112 | if not opts.silent: 113 | # only push experimental 114 | push([opts.experimental]) 115 | else: 116 | # Copy "experimental" to "stable" 117 | shutil.copy(opts.experimental, opts.stable) 118 | if not opts.silent: 119 | push([opts.experimental, opts.stable]) 120 | 121 | if __name__=='__main__': 122 | run() 123 | -------------------------------------------------------------------------------- /GTFO.js: -------------------------------------------------------------------------------- 1 | // Rudimentary serialization of YY System based on the 2 | // General Transit Feed Specification Reference. 3 | 4 | // For the benefit of node 5 | var YY = YY || require('./yatayat.js'); 6 | 7 | var GTFO = function(system, agency) { 8 | // Filter by agency; agency is an object {name:, filter:, url:} 9 | var routes = system.routes.filter(function(r) { 10 | return r.transport.toLowerCase().indexOf(agency.filter) >= 0; 11 | }); 12 | 13 | this.system = new YY.System(routes); 14 | this._agency = agency; 15 | }; 16 | 17 | GTFO.prototype.agency = function() { 18 | return [{ 19 | agency_name: this._agency.name, 20 | agency_url: this._agency.url, 21 | agency_timezone: "Asia/Kathmandu" 22 | }]; 23 | }; 24 | 25 | GTFO.prototype.stops = function() { 26 | return this.system.allStops().map(function(stop) { 27 | return { 28 | stop_id: stop.id, 29 | stop_name: stop.name, 30 | stop_lat: stop.lat, 31 | stop_lon: stop.lng 32 | }; 33 | }); 34 | }; 35 | 36 | GTFO.prototype.routes = function() { 37 | return this.system.routes.map(function(route) { 38 | return { 39 | route_id: route.id, 40 | route_short_name: route.ref || "", 41 | route_long_name: route.name, 42 | route_type: 3 // 3 == bus 43 | }; 44 | }); 45 | }; 46 | 47 | GTFO.prototype.trips = function() { 48 | /* 49 | route_id - route.id 50 | service_id - calendar.txt 51 | trip_id - autoincrement 52 | (opt) 53 | shape_id 54 | */ 55 | 56 | // We'll make one trip per route, one shape per trip 57 | // ergo: one shape per route, one trip per trip. 58 | return this.system.routes.map(function(route, route_idx) { 59 | return { 60 | route_id: route.id, 61 | service_id: "calendar-0", 62 | trip_id: "trip-" + route_idx, 63 | shape_id: "shape-" + route_idx 64 | }; 65 | }); 66 | }; 67 | 68 | GTFO.prototype.stop_times = function() { 69 | /* 70 | trip_id - 71 | arrival_time - "" when nothing; must exist for 1st & last stop of trip 72 | departure_time - can be identical to ^ if difference not specified 73 | stop_id - stop.id 74 | stop_sequence - monotonically increasing integers 75 | 76 | (opt:) 77 | pickup_type - 0 = reg / 3 = "must coordinate with driver to arrange pickup" 78 | drop_off_type - same as ^ 79 | shape_dist_traveled - in same unit as shapes.txt, dist from start 80 | */ 81 | 82 | // arrival_time & departure_time will be ignored -- we'll do 83 | // frequencies instead 84 | 85 | var out = []; 86 | 87 | this.system.routes.forEach(function(route, route_idx) { 88 | var trip_id = "trip-" + route_idx; 89 | route.stops.forEach(function(stop, stop_idx) { 90 | out.push({ 91 | trip_id: trip_id, 92 | arrival_time: "", 93 | departure_time: "", 94 | stop_id: stop.id, 95 | stop_sequence: stop_idx // XXX: are stops ordered? 96 | }); 97 | }); 98 | }); 99 | 100 | return out; 101 | }; 102 | 103 | GTFO.prototype.calendar = function() { 104 | /* 105 | service_id - dataset-unique, ref'ed by trips 106 | monday - 1 == all mondays, 0 == none 107 | [tues-sun] - "" "" 108 | start_date - YYYYMMDD 109 | end_date = YYYYMMDD 110 | */ 111 | 112 | // XXX: Is this true? 113 | // TODO: incorporate wildcat strikes into calendar_dates 114 | 115 | return [{ 116 | service_id: "calendar-0", 117 | monday: 1, 118 | tuesday: 1, 119 | wednesday: 1, 120 | thursday: 1, 121 | friday: 1, 122 | saturday: 1, 123 | sunday: 1, 124 | start_date: 20120701, 125 | end_date: 20140701 126 | }]; 127 | }; 128 | 129 | GTFO.prototype.shapes = function() { 130 | /* 131 | shape_id - 132 | shape_pt_lat - 133 | shape_pt_lon - 134 | shape_pt_sequence - int ordering 135 | (opt) 136 | shape_dist_traveled - see stop_times.txt 137 | */ 138 | 139 | var out = []; 140 | this.system.routes.forEach(function(route, route_idx) { 141 | var shape_id = "shape-" + route_idx; 142 | var shape_pt_sequence = 0; 143 | route.segments.forEach(function(seg) { 144 | seg.listOfLatLng.forEach(function(ll) { 145 | out.push({ 146 | shape_id: shape_id, 147 | shape_pt_lat: ll[0], 148 | shape_pt_lon: ll[1], 149 | shape_pt_sequence: shape_pt_sequence 150 | // XXX: shape_dist_traveled 151 | }); 152 | shape_pt_sequence += 1; 153 | }); 154 | }); 155 | }); 156 | return out; 157 | }; 158 | 159 | GTFO.prototype.frequencies = function() { 160 | /* 161 | trip_id 162 | start_time 163 | end_time 164 | headway_secs - time between launches 165 | */ 166 | 167 | // XXX: These are a complete fabrication. 168 | 169 | return this.system.routes.map(function(route, route_idx) { 170 | return { 171 | trip_id: "trip-" + route_idx, 172 | start_time: "06:00:00", 173 | end_time: "21:00:00", 174 | headway_secs: 60*15 175 | }; 176 | }); 177 | }; 178 | 179 | GTFO.prototype.FILES = ["agency", "stops", "routes", "trips", "stop_times", "calendar", "shapes", "frequencies"]; 180 | 181 | GTFO.prototype.generate_csvs = function() { 182 | var that = this; 183 | var out = {}; 184 | 185 | this.FILES.forEach(function(name) { 186 | console.log("fn", name); 187 | out[name] = jsonToCsv(that[name]()); 188 | }); 189 | 190 | return out; 191 | }; 192 | 193 | function jsonToCsv(data) { 194 | // data is a list of shallow objects. 195 | var out = ""; 196 | 197 | var fields = []; 198 | for(var key in data[0]) { 199 | fields.push(key); 200 | } 201 | 202 | function _cn(idx,list){ 203 | // Whether to add a trailing comma or a newline 204 | return idx === list.length-1 ? "\n" : ","; 205 | } 206 | function _q(str) { 207 | // XXX: quoting/escaping? 208 | // see: https://developers.google.com/transit/gtfs/reference#FileRequirements 209 | return str === undefined ? "" : str; 210 | } 211 | 212 | // Header 213 | fields.forEach(function(name, idx) { 214 | out += _q(name) + _cn(idx, fields); 215 | }); 216 | 217 | // Payload 218 | data.forEach(function(row) { 219 | fields.forEach(function(name, idx) { 220 | out += _q(row[name]) + _cn(idx, fields); 221 | }); 222 | }); 223 | return out; 224 | }; 225 | 226 | // selectively export as a node module 227 | var module = module || {}; 228 | module.exports = GTFO; -------------------------------------------------------------------------------- /lib/leaflet/Leaflet.PolylineDecorator/leaflet.polylineDecorator.min.js: -------------------------------------------------------------------------------- 1 | L.LineUtil.PolylineDecorator={computeAngle:function(a,b){return 180*Math.atan2(b.y-a.y,b.x-a.x)/Math.PI+90},getPointPathPixelLength:function(a){var b=a.length;if(2>b)return 0;for(var c=0,d=a[0],e=1;ed)return 0;for(var e=0,f=b.latLngToLayerPoint(c[0]),g=1;gc)return null;if(0>=b)return{pt:a[0],predecessor:0,heading:this.computeAngle(a[0],a[1])};if(1<=b)return{pt:a[c-1],predecessor:c-1,heading:this.computeAngle(a[c-2],a[c-1])};if(2==c)return{pt:this.interpolateBetweenPoints(a[0],a[1],b),predecessor:0,heading:this.computeAngle(a[0],a[1])};for(var d=this.getPointPathPixelLength(a),e=a[0],f=e,g=0,h=0,k=0,j=1;j=b.pixelSize)return new L.Polyline([a.latLng,a.latLng],b.pathOptions);var d=c.project(a.latLng);a=-(a.heading-90)*L.LatLng.DEG_TO_RAD;a=new L.Point(d.x+b.pixelSize*Math.cos(a+Math.PI)/2,d.y+b.pixelSize*Math.sin(a)/2);d=d.add(d.subtract(a));return new L.Polyline([c.unproject(a),c.unproject(d)], 7 | b.pathOptions)}});L.Symbol.dash=function(a){return new L.Symbol.Dash(a)}; 8 | L.Symbol.ArrowHead=L.Class.extend({isZoomDependant:!0,options:{polygon:!0,pixelSize:10,headAngle:60,pathOptions:{stroke:!1,weight:2}},initialize:function(a){L.Util.setOptions(this,a);this.options.pathOptions.clickable=!1},buildSymbol:function(a,b,c){b=this.options;return b.polygon?new L.Polygon(this._buildArrowPath(a,c),b.pathOptions):new L.Polyline(this._buildArrowPath(a,c),b.pathOptions)},_buildArrowPath:function(a,b){var c=b.project(a.latLng),d=-(a.heading-90)*L.LatLng.DEG_TO_RAD,e=this.options.headAngle/ 9 | 2*L.LatLng.DEG_TO_RAD,f=d+e,d=d-e,f=new L.Point(c.x-this.options.pixelSize*Math.cos(f),c.y+this.options.pixelSize*Math.sin(f)),c=new L.Point(c.x-this.options.pixelSize*Math.cos(d),c.y+this.options.pixelSize*Math.sin(d));return[b.unproject(f),a.latLng,b.unproject(c)]}});L.Symbol.arrowHead=function(a){return new L.Symbol.ArrowHead(a)}; 10 | L.Symbol.Marker=L.Class.extend({isZoomDependant:!1,options:{markerOptions:{},rotate:!1},initialize:function(a){L.Util.setOptions(this,a);this.options.markerOptions.clickable=!1;this.options.markerOptions.draggable=!1;this.isZoomDependant=L.Browser.ie&&this.options.rotate},buildSymbol:function(a){return this.options.rotate?(this.options.markerOptions.angle=a.heading,new L.RotatedMarker(a.latLng,this.options.markerOptions)):new L.Marker(a.latLng,this.options.markerOptions)}});L.Symbol.marker=function(a){return new L.Symbol.Marker(a)};L.PolylineDecorator=L.LayerGroup.extend({options:{patterns:[]},initialize:function(a,b){L.LayerGroup.prototype.initialize.call(this);L.Util.setOptions(this,b);this._map=null;this._initPaths(a);this._initPatterns()},_initPaths:function(a){this._paths=[];var b=!1;if(a instanceof L.MultiPolyline||(b=a instanceof L.MultiPolygon)){a=a.getLatLngs();for(var c=0;c 0) ? "runner failed" : "runner passed"; 93 | this.runnerDiv.setAttribute("class", className); 94 | //do it twice for IE 95 | this.runnerDiv.setAttribute("className", className); 96 | var specs = runner.specs(); 97 | var specCount = 0; 98 | for (var i = 0; i < specs.length; i++) { 99 | if (this.specFilter(specs[i])) { 100 | specCount++; 101 | } 102 | } 103 | var message = "" + specCount + " spec" + (specCount == 1 ? "" : "s" ) + ", " + results.failedCount + " failure" + ((results.failedCount == 1) ? "" : "s"); 104 | message += " in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s"; 105 | this.runnerMessageSpan.replaceChild(this.createDom('a', { className: 'description', href: '?'}, message), this.runnerMessageSpan.firstChild); 106 | 107 | this.finishedAtSpan.appendChild(document.createTextNode("Finished at " + new Date().toString())); 108 | }; 109 | 110 | jasmine.TrivialReporter.prototype.reportSuiteResults = function(suite) { 111 | var results = suite.results(); 112 | var status = results.passed() ? 'passed' : 'failed'; 113 | if (results.totalCount === 0) { // todo: change this to check results.skipped 114 | status = 'skipped'; 115 | } 116 | this.suiteDivs[suite.id].className += " " + status; 117 | }; 118 | 119 | jasmine.TrivialReporter.prototype.reportSpecStarting = function(spec) { 120 | if (this.logRunningSpecs) { 121 | this.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...'); 122 | } 123 | }; 124 | 125 | jasmine.TrivialReporter.prototype.reportSpecResults = function(spec) { 126 | var results = spec.results(); 127 | var status = results.passed() ? 'passed' : 'failed'; 128 | if (results.skipped) { 129 | status = 'skipped'; 130 | } 131 | var specDiv = this.createDom('div', { className: 'spec ' + status }, 132 | this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(spec.getFullName()) }, "run"), 133 | this.createDom('a', { 134 | className: 'description', 135 | href: '?spec=' + encodeURIComponent(spec.getFullName()), 136 | title: spec.getFullName() 137 | }, spec.description)); 138 | 139 | 140 | var resultItems = results.getItems(); 141 | var messagesDiv = this.createDom('div', { className: 'messages' }); 142 | for (var i = 0; i < resultItems.length; i++) { 143 | var result = resultItems[i]; 144 | 145 | if (result.type == 'log') { 146 | messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString())); 147 | } else if (result.type == 'expect' && result.passed && !result.passed()) { 148 | messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message)); 149 | 150 | if (result.trace.stack) { 151 | messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack)); 152 | } 153 | } 154 | } 155 | 156 | if (messagesDiv.childNodes.length > 0) { 157 | specDiv.appendChild(messagesDiv); 158 | } 159 | 160 | this.suiteDivs[spec.suite.id].appendChild(specDiv); 161 | }; 162 | 163 | jasmine.TrivialReporter.prototype.log = function() { 164 | var console = jasmine.getGlobal().console; 165 | if (console && console.log) { 166 | if (console.log.apply) { 167 | console.log.apply(console, arguments); 168 | } else { 169 | console.log(arguments); // ie fix: console.log.apply doesn't exist on ie 170 | } 171 | } 172 | }; 173 | 174 | jasmine.TrivialReporter.prototype.getLocation = function() { 175 | return this.document.location; 176 | }; 177 | 178 | jasmine.TrivialReporter.prototype.specFilter = function(spec) { 179 | var paramMap = {}; 180 | var params = this.getLocation().search.substring(1).split('&'); 181 | for (var i = 0; i < params.length; i++) { 182 | var p = params[i].split('='); 183 | paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]); 184 | } 185 | 186 | if (!paramMap.spec) { 187 | return true; 188 | } 189 | return spec.getFullName().indexOf(paramMap.spec) === 0; 190 | }; 191 | -------------------------------------------------------------------------------- /stylesheets/stylesheet.css: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | Slate Theme for GitHub Pages 3 | by Jason Costello, @jsncostello 4 | *******************************************************************************/ 5 | 6 | @import url(pygment_trac.css); 7 | 8 | /******************************************************************************* 9 | MeyerWeb Reset 10 | *******************************************************************************/ 11 | 12 | html, body, div, span, applet, object, iframe, 13 | h1, h2, h3, h4, h5, h6, p, blockquote, pre, 14 | a, abbr, acronym, address, big, cite, code, 15 | del, dfn, em, img, ins, kbd, q, s, samp, 16 | small, strike, strong, sub, sup, tt, var, 17 | b, u, i, center, 18 | dl, dt, dd, ol, ul, li, 19 | fieldset, form, label, legend, 20 | table, caption, tbody, tfoot, thead, tr, th, td, 21 | article, aside, canvas, details, embed, 22 | figure, figcaption, footer, header, hgroup, 23 | menu, nav, output, ruby, section, summary, 24 | time, mark, audio, video { 25 | margin: 0; 26 | padding: 0; 27 | border: 0; 28 | font: inherit; 29 | vertical-align: baseline; 30 | } 31 | 32 | /* HTML5 display-role reset for older browsers */ 33 | article, aside, details, figcaption, figure, 34 | footer, header, hgroup, menu, nav, section { 35 | display: block; 36 | } 37 | 38 | ol, ul { 39 | list-style: none; 40 | } 41 | 42 | table { 43 | border-collapse: collapse; 44 | border-spacing: 0; 45 | } 46 | 47 | /******************************************************************************* 48 | Theme Styles 49 | *******************************************************************************/ 50 | 51 | body { 52 | box-sizing: border-box; 53 | color:#373737; 54 | background: #212121; 55 | font-size: 16px; 56 | font-family: 'Myriad Pro', Calibri, Helvetica, Arial, sans-serif; 57 | line-height: 1.5; 58 | -webkit-font-smoothing: antialiased; 59 | } 60 | 61 | h1, h2, h3, h4, h5, h6 { 62 | margin: 10px 0; 63 | font-weight: 700; 64 | color:#222222; 65 | font-family: 'Lucida Grande', 'Calibri', Helvetica, Arial, sans-serif; 66 | letter-spacing: -1px; 67 | } 68 | 69 | h1 { 70 | font-size: 36px; 71 | font-weight: 700; 72 | } 73 | 74 | h2 { 75 | padding-bottom: 10px; 76 | font-size: 32px; 77 | background: url('../images/bg_hr.png') repeat-x bottom; 78 | } 79 | 80 | h3 { 81 | font-size: 24px; 82 | } 83 | 84 | h4 { 85 | font-size: 21px; 86 | } 87 | 88 | h5 { 89 | font-size: 18px; 90 | } 91 | 92 | h6 { 93 | font-size: 16px; 94 | } 95 | 96 | p { 97 | margin: 10px 0 15px 0; 98 | } 99 | 100 | footer p { 101 | color: #f2f2f2; 102 | } 103 | 104 | a { 105 | text-decoration: none; 106 | color: #007edf; 107 | text-shadow: none; 108 | 109 | transition: color 0.5s ease; 110 | transition: text-shadow 0.5s ease; 111 | -webkit-transition: color 0.5s ease; 112 | -webkit-transition: text-shadow 0.5s ease; 113 | -moz-transition: color 0.5s ease; 114 | -moz-transition: text-shadow 0.5s ease; 115 | -o-transition: color 0.5s ease; 116 | -o-transition: text-shadow 0.5s ease; 117 | -ms-transition: color 0.5s ease; 118 | -ms-transition: text-shadow 0.5s ease; 119 | } 120 | 121 | a:hover, a:focus {text-decoration: underline;} 122 | 123 | footer a { 124 | color: #F2F2F2; 125 | text-decoration: underline; 126 | } 127 | 128 | em { 129 | font-style: italic; 130 | } 131 | 132 | strong { 133 | font-weight: bold; 134 | } 135 | 136 | img { 137 | position: relative; 138 | margin: 0 auto; 139 | max-width: 739px; 140 | padding: 5px; 141 | margin: 10px 0 10px 0; 142 | border: 1px solid #ebebeb; 143 | 144 | box-shadow: 0 0 5px #ebebeb; 145 | -webkit-box-shadow: 0 0 5px #ebebeb; 146 | -moz-box-shadow: 0 0 5px #ebebeb; 147 | -o-box-shadow: 0 0 5px #ebebeb; 148 | -ms-box-shadow: 0 0 5px #ebebeb; 149 | } 150 | 151 | p img { 152 | display: inline; 153 | margin: 0; 154 | padding: 0; 155 | vertical-align: middle; 156 | text-align: center; 157 | border: none; 158 | } 159 | 160 | pre, code { 161 | width: 100%; 162 | color: #222; 163 | background-color: #fff; 164 | 165 | font-family: Monaco, "Bitstream Vera Sans Mono", "Lucida Console", Terminal, monospace; 166 | font-size: 14px; 167 | 168 | border-radius: 2px; 169 | -moz-border-radius: 2px; 170 | -webkit-border-radius: 2px; 171 | } 172 | 173 | pre { 174 | width: 100%; 175 | padding: 10px; 176 | box-shadow: 0 0 10px rgba(0,0,0,.1); 177 | overflow: auto; 178 | } 179 | 180 | code { 181 | padding: 3px; 182 | margin: 0 3px; 183 | box-shadow: 0 0 10px rgba(0,0,0,.1); 184 | } 185 | 186 | pre code { 187 | display: block; 188 | box-shadow: none; 189 | } 190 | 191 | blockquote { 192 | color: #666; 193 | margin-bottom: 20px; 194 | padding: 0 0 0 20px; 195 | border-left: 3px solid #bbb; 196 | } 197 | 198 | 199 | ul, ol, dl { 200 | margin-bottom: 15px 201 | } 202 | 203 | ul { 204 | list-style: inside; 205 | padding-left: 20px; 206 | } 207 | 208 | ol { 209 | list-style: decimal inside; 210 | padding-left: 20px; 211 | } 212 | 213 | dl dt { 214 | font-weight: bold; 215 | } 216 | 217 | dl dd { 218 | padding-left: 20px; 219 | font-style: italic; 220 | } 221 | 222 | dl p { 223 | padding-left: 20px; 224 | font-style: italic; 225 | } 226 | 227 | hr { 228 | height: 1px; 229 | margin-bottom: 5px; 230 | border: none; 231 | background: url('../images/bg_hr.png') repeat-x center; 232 | } 233 | 234 | table { 235 | border: 1px solid #373737; 236 | margin-bottom: 20px; 237 | text-align: left; 238 | } 239 | 240 | th { 241 | font-family: 'Lucida Grande', 'Helvetica Neue', Helvetica, Arial, sans-serif; 242 | padding: 10px; 243 | background: #373737; 244 | color: #fff; 245 | } 246 | 247 | td { 248 | padding: 10px; 249 | border: 1px solid #373737; 250 | } 251 | 252 | form { 253 | background: #f2f2f2; 254 | padding: 20px; 255 | } 256 | 257 | /******************************************************************************* 258 | Full-Width Styles 259 | *******************************************************************************/ 260 | 261 | .outer { 262 | width: 100%; 263 | } 264 | 265 | .inner { 266 | position: relative; 267 | max-width: 640px; 268 | padding: 20px 10px; 269 | margin: 0 auto; 270 | } 271 | 272 | #forkme_banner { 273 | display: block; 274 | position: absolute; 275 | top:0; 276 | right: 10px; 277 | z-index: 10; 278 | padding: 10px 50px 10px 10px; 279 | color: #fff; 280 | background: url('../images/blacktocat.png') #0090ff no-repeat 95% 50%; 281 | font-weight: 700; 282 | box-shadow: 0 0 10px rgba(0,0,0,.5); 283 | border-bottom-left-radius: 2px; 284 | border-bottom-right-radius: 2px; 285 | } 286 | 287 | #header_wrap { 288 | background: #212121; 289 | background: -moz-linear-gradient(top, #373737, #212121); 290 | background: -webkit-linear-gradient(top, #373737, #212121); 291 | background: -ms-linear-gradient(top, #373737, #212121); 292 | background: -o-linear-gradient(top, #373737, #212121); 293 | background: linear-gradient(top, #373737, #212121); 294 | } 295 | 296 | #header_wrap .inner { 297 | padding: 50px 10px 30px 10px; 298 | } 299 | 300 | #project_title { 301 | margin: 0; 302 | color: #fff; 303 | font-size: 42px; 304 | font-weight: 700; 305 | text-shadow: #111 0px 0px 10px; 306 | } 307 | 308 | #project_tagline { 309 | color: #fff; 310 | font-size: 24px; 311 | font-weight: 300; 312 | background: none; 313 | text-shadow: #111 0px 0px 10px; 314 | } 315 | 316 | #downloads { 317 | position: absolute; 318 | width: 210px; 319 | z-index: 10; 320 | bottom: -40px; 321 | right: 0; 322 | height: 70px; 323 | background: url('../images/icon_download.png') no-repeat 0% 90%; 324 | } 325 | 326 | .zip_download_link { 327 | display: block; 328 | float: right; 329 | width: 90px; 330 | height:70px; 331 | text-indent: -5000px; 332 | overflow: hidden; 333 | background: url(../images/sprite_download.png) no-repeat bottom left; 334 | } 335 | 336 | .tar_download_link { 337 | display: block; 338 | float: right; 339 | width: 90px; 340 | height:70px; 341 | text-indent: -5000px; 342 | overflow: hidden; 343 | background: url(../images/sprite_download.png) no-repeat bottom right; 344 | margin-left: 10px; 345 | } 346 | 347 | .zip_download_link:hover { 348 | background: url(../images/sprite_download.png) no-repeat top left; 349 | } 350 | 351 | .tar_download_link:hover { 352 | background: url(../images/sprite_download.png) no-repeat top right; 353 | } 354 | 355 | #main_content_wrap { 356 | background: #f2f2f2; 357 | border-top: 1px solid #111; 358 | border-bottom: 1px solid #111; 359 | } 360 | 361 | #main_content { 362 | padding-top: 40px; 363 | } 364 | 365 | #footer_wrap { 366 | background: #212121; 367 | } 368 | 369 | 370 | 371 | /******************************************************************************* 372 | Small Device Styles 373 | *******************************************************************************/ 374 | 375 | @media screen and (max-width: 480px) { 376 | body { 377 | font-size:14px; 378 | } 379 | 380 | #downloads { 381 | display: none; 382 | } 383 | 384 | .inner { 385 | min-width: 320px; 386 | max-width: 480px; 387 | } 388 | 389 | #project_title { 390 | font-size: 32px; 391 | } 392 | 393 | h1 { 394 | font-size: 28px; 395 | } 396 | 397 | h2 { 398 | font-size: 24px; 399 | } 400 | 401 | h3 { 402 | font-size: 21px; 403 | } 404 | 405 | h4 { 406 | font-size: 18px; 407 | } 408 | 409 | h5 { 410 | font-size: 14px; 411 | } 412 | 413 | h6 { 414 | font-size: 12px; 415 | } 416 | 417 | code, pre { 418 | min-width: 320px; 419 | max-width: 480px; 420 | font-size: 11px; 421 | } 422 | 423 | } 424 | -------------------------------------------------------------------------------- /lib/leaflet/leaflet.css: -------------------------------------------------------------------------------- 1 | /* required styles */ 2 | 3 | .leaflet-map-pane, 4 | .leaflet-tile, 5 | .leaflet-marker-icon, 6 | .leaflet-marker-shadow, 7 | .leaflet-tile-pane, 8 | .leaflet-overlay-pane, 9 | .leaflet-shadow-pane, 10 | .leaflet-marker-pane, 11 | .leaflet-popup-pane, 12 | .leaflet-overlay-pane svg, 13 | .leaflet-zoom-box, 14 | .leaflet-image-layer { /* TODO optimize classes */ 15 | position: absolute; 16 | } 17 | .leaflet-container { 18 | overflow: hidden; 19 | } 20 | .leaflet-tile, 21 | .leaflet-marker-icon, 22 | .leaflet-marker-shadow { 23 | -moz-user-select: none; 24 | -webkit-user-select: none; 25 | user-select: none; 26 | } 27 | .leaflet-marker-icon, 28 | .leaflet-marker-shadow { 29 | display: block; 30 | } 31 | .leaflet-clickable { 32 | cursor: pointer; 33 | } 34 | .leaflet-dragging, .leaflet-dragging .leaflet-clickable { 35 | cursor: move; 36 | } 37 | .leaflet-container img { 38 | /* map is broken in FF if you have max-width: 100% on tiles */ 39 | max-width: none !important; 40 | } 41 | .leaflet-container img.leaflet-image-layer { 42 | /* stupid Android 2 doesn't understand "max-width: none" properly */ 43 | max-width: 15000px !important; 44 | } 45 | 46 | .leaflet-tile-pane { z-index: 2; } 47 | .leaflet-objects-pane { z-index: 3; } 48 | .leaflet-overlay-pane { z-index: 4; } 49 | .leaflet-shadow-pane { z-index: 5; } 50 | .leaflet-marker-pane { z-index: 6; } 51 | .leaflet-popup-pane { z-index: 7; } 52 | 53 | .leaflet-tile { 54 | filter: inherit; 55 | visibility: hidden; 56 | } 57 | .leaflet-tile-loaded { 58 | visibility: inherit; 59 | } 60 | 61 | .leaflet-zoom-box { 62 | width: 0; 63 | height: 0; 64 | } 65 | 66 | /* Leaflet controls */ 67 | 68 | .leaflet-control { 69 | position: relative; 70 | z-index: 7; 71 | } 72 | .leaflet-top, 73 | .leaflet-bottom { 74 | position: absolute; 75 | } 76 | .leaflet-top { 77 | top: 0; 78 | } 79 | .leaflet-right { 80 | right: 0; 81 | } 82 | .leaflet-bottom { 83 | bottom: 0; 84 | } 85 | .leaflet-left { 86 | left: 0; 87 | } 88 | .leaflet-control { 89 | float: left; 90 | clear: both; 91 | } 92 | .leaflet-right .leaflet-control { 93 | float: right; 94 | } 95 | .leaflet-top .leaflet-control { 96 | margin-top: 10px; 97 | } 98 | .leaflet-bottom .leaflet-control { 99 | margin-bottom: 10px; 100 | } 101 | .leaflet-left .leaflet-control { 102 | margin-left: 10px; 103 | } 104 | .leaflet-right .leaflet-control { 105 | margin-right: 10px; 106 | } 107 | 108 | .leaflet-control-zoom { 109 | -moz-border-radius: 7px; 110 | -webkit-border-radius: 7px; 111 | border-radius: 7px; 112 | } 113 | .leaflet-control-zoom { 114 | padding: 5px; 115 | background: rgba(0, 0, 0, 0.25); 116 | } 117 | .leaflet-control-zoom a { 118 | background-color: rgba(255, 255, 255, 0.75); 119 | } 120 | .leaflet-control-zoom a, .leaflet-control-layers a { 121 | background-position: 50% 50%; 122 | background-repeat: no-repeat; 123 | display: block; 124 | } 125 | .leaflet-control-zoom a { 126 | -moz-border-radius: 4px; 127 | -webkit-border-radius: 4px; 128 | border-radius: 4px; 129 | width: 19px; 130 | height: 19px; 131 | } 132 | .leaflet-control-zoom a:hover { 133 | background-color: #fff; 134 | } 135 | .leaflet-touch .leaflet-control-zoom a { 136 | width: 27px; 137 | height: 27px; 138 | } 139 | .leaflet-control-zoom-in { 140 | background-image: url(images/zoom-in.png); 141 | margin-bottom: 5px; 142 | } 143 | .leaflet-control-zoom-out { 144 | background-image: url(images/zoom-out.png); 145 | } 146 | 147 | .leaflet-control-layers { 148 | box-shadow: 0 1px 7px #999; 149 | background: #f8f8f9; 150 | -moz-border-radius: 8px; 151 | -webkit-border-radius: 8px; 152 | border-radius: 8px; 153 | } 154 | .leaflet-control-layers a { 155 | background-image: url(images/layers.png); 156 | width: 36px; 157 | height: 36px; 158 | } 159 | .leaflet-touch .leaflet-control-layers a { 160 | width: 44px; 161 | height: 44px; 162 | } 163 | .leaflet-control-layers .leaflet-control-layers-list, 164 | .leaflet-control-layers-expanded .leaflet-control-layers-toggle { 165 | display: none; 166 | } 167 | .leaflet-control-layers-expanded .leaflet-control-layers-list { 168 | display: block; 169 | position: relative; 170 | } 171 | .leaflet-control-layers-expanded { 172 | padding: 6px 10px 6px 6px; 173 | font: 12px/1.5 "Helvetica Neue", Arial, Helvetica, sans-serif; 174 | color: #333; 175 | background: #fff; 176 | } 177 | .leaflet-control-layers input { 178 | margin-top: 2px; 179 | position: relative; 180 | top: 1px; 181 | } 182 | .leaflet-control-layers label { 183 | display: block; 184 | } 185 | .leaflet-control-layers-separator { 186 | height: 0; 187 | border-top: 1px solid #ddd; 188 | margin: 5px -10px 5px -6px; 189 | } 190 | 191 | .leaflet-container .leaflet-control-attribution { 192 | background-color: rgba(255, 255, 255, 0.7); 193 | box-shadow: 0 0 5px #bbb; 194 | margin: 0; 195 | } 196 | 197 | .leaflet-control-attribution, 198 | .leaflet-control-scale-line { 199 | padding: 0 5px; 200 | color: #333; 201 | } 202 | 203 | .leaflet-container .leaflet-control-attribution, 204 | .leaflet-container .leaflet-control-scale { 205 | font: 11px/1.5 "Helvetica Neue", Arial, Helvetica, sans-serif; 206 | } 207 | 208 | .leaflet-left .leaflet-control-scale { 209 | margin-left: 5px; 210 | } 211 | .leaflet-bottom .leaflet-control-scale { 212 | margin-bottom: 5px; 213 | } 214 | 215 | .leaflet-control-scale-line { 216 | border: 2px solid #777; 217 | border-top: none; 218 | color: black; 219 | line-height: 1; 220 | font-size: 10px; 221 | padding-bottom: 2px; 222 | text-shadow: 1px 1px 1px #fff; 223 | background-color: rgba(255, 255, 255, 0.5); 224 | } 225 | .leaflet-control-scale-line:nth-child(2) { 226 | border-top: 2px solid #777; 227 | padding-top: 1px; 228 | border-bottom: none; 229 | margin-top: -2px; 230 | } 231 | 232 | .leaflet-touch .leaflet-control-attribution, .leaflet-touch .leaflet-control-layers { 233 | box-shadow: none; 234 | } 235 | .leaflet-touch .leaflet-control-layers { 236 | border: 5px solid #bbb; 237 | } 238 | 239 | 240 | /* Zoom and fade animations */ 241 | 242 | .leaflet-fade-anim .leaflet-tile, .leaflet-fade-anim .leaflet-popup { 243 | opacity: 0; 244 | 245 | -webkit-transition: opacity 0.2s linear; 246 | -moz-transition: opacity 0.2s linear; 247 | -o-transition: opacity 0.2s linear; 248 | transition: opacity 0.2s linear; 249 | } 250 | .leaflet-fade-anim .leaflet-tile-loaded, .leaflet-fade-anim .leaflet-map-pane .leaflet-popup { 251 | opacity: 1; 252 | } 253 | 254 | .leaflet-zoom-anim .leaflet-zoom-animated { 255 | -webkit-transition: -webkit-transform 0.25s cubic-bezier(0.25,0.1,0.25,0.75); 256 | -moz-transition: -moz-transform 0.25s cubic-bezier(0.25,0.1,0.25,0.75); 257 | -o-transition: -o-transform 0.25s cubic-bezier(0.25,0.1,0.25,0.75); 258 | transition: transform 0.25s cubic-bezier(0.25,0.1,0.25,0.75); 259 | } 260 | 261 | .leaflet-zoom-anim .leaflet-tile, 262 | .leaflet-pan-anim .leaflet-tile, 263 | .leaflet-touching .leaflet-zoom-animated { 264 | -webkit-transition: none; 265 | -moz-transition: none; 266 | -o-transition: none; 267 | transition: none; 268 | } 269 | 270 | .leaflet-zoom-anim .leaflet-zoom-hide { 271 | visibility: hidden; 272 | } 273 | 274 | 275 | /* Popup layout */ 276 | 277 | .leaflet-popup { 278 | position: absolute; 279 | text-align: center; 280 | } 281 | .leaflet-popup-content-wrapper { 282 | padding: 1px; 283 | text-align: left; 284 | } 285 | .leaflet-popup-content { 286 | margin: 14px 20px; 287 | } 288 | .leaflet-popup-tip-container { 289 | margin: 0 auto; 290 | width: 40px; 291 | height: 16px; 292 | position: relative; 293 | overflow: hidden; 294 | } 295 | .leaflet-popup-tip { 296 | width: 15px; 297 | height: 15px; 298 | padding: 1px; 299 | 300 | margin: -8px auto 0; 301 | 302 | -moz-transform: rotate(45deg); 303 | -webkit-transform: rotate(45deg); 304 | -ms-transform: rotate(45deg); 305 | -o-transform: rotate(45deg); 306 | transform: rotate(45deg); 307 | } 308 | .leaflet-popup-close-button { 309 | position: absolute; 310 | top: 8px; 311 | right: 8px; 312 | 313 | width: 10px; 314 | height: 10px; 315 | 316 | overflow: hidden; 317 | } 318 | .leaflet-popup-content p { 319 | margin: 18px 0; 320 | } 321 | .leaflet-popup-scrolled { 322 | overflow: auto; 323 | border-bottom: 1px solid #ddd; 324 | border-top: 1px solid #ddd; 325 | } 326 | 327 | 328 | /* Visual appearance */ 329 | 330 | .leaflet-container { 331 | background: #ddd; 332 | } 333 | .leaflet-container a { 334 | color: #0078A8; 335 | } 336 | .leaflet-container a.leaflet-active { 337 | outline: 2px solid orange; 338 | } 339 | .leaflet-zoom-box { 340 | border: 2px dotted #05f; 341 | background: white; 342 | opacity: 0.5; 343 | } 344 | .leaflet-div-icon { 345 | background: #fff; 346 | border: 1px solid #666; 347 | } 348 | .leaflet-editing-icon { 349 | border-radius: 2px; 350 | } 351 | .leaflet-popup-content-wrapper, .leaflet-popup-tip { 352 | background: white; 353 | 354 | box-shadow: 0 3px 10px #888; 355 | -moz-box-shadow: 0 3px 10px #888; 356 | -webkit-box-shadow: 0 3px 14px #999; 357 | } 358 | .leaflet-popup-content-wrapper { 359 | -moz-border-radius: 20px; 360 | -webkit-border-radius: 20px; 361 | border-radius: 20px; 362 | } 363 | .leaflet-popup-content { 364 | font: 12px/1.4 "Helvetica Neue", Arial, Helvetica, sans-serif; 365 | } 366 | .leaflet-popup-close-button { 367 | background: white url(images/popup-close.png); 368 | } 369 | -------------------------------------------------------------------------------- /data_quality.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Kathmandu Public Transport 4 | 5 | 8 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 |
Loading ...
43 |

 44 | 
WARNINGS
45 | 46 | 267 | 268 | 269 | -------------------------------------------------------------------------------- /lib/jquery.autocomplete.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Ajax Autocomplete for jQuery, version 1.2.9 3 | * (c) 2013 Tomas Kirda 4 | * 5 | * Ajax Autocomplete for jQuery is freely distributable under the terms of an MIT-style license. 6 | * For details, see the web site: https://github.com/devbridge/jQuery-Autocomplete 7 | * 8 | */ 9 | (function(d){"function"===typeof define&&define.amd?define(["jquery"],d):d(jQuery)})(function(d){function g(a,b){var c=function(){},c={autoSelectFirst:!1,appendTo:"body",serviceUrl:null,lookup:null,onSelect:null,width:"auto",minChars:1,maxHeight:300,deferRequestBy:0,params:{},formatResult:g.formatResult,delimiter:null,zIndex:9999,type:"GET",noCache:!1,onSearchStart:c,onSearchComplete:c,onSearchError:c,containerClass:"autocomplete-suggestions",tabDisabled:!1,dataType:"text",currentRequest:null,triggerSelectOnValidInput:!0, 10 | lookupFilter:function(a,b,c){return-1!==a.value.toLowerCase().indexOf(c)},paramName:"query",transformResult:function(a){return"string"===typeof a?d.parseJSON(a):a}};this.element=a;this.el=d(a);this.suggestions=[];this.badQueries=[];this.selectedIndex=-1;this.currentValue=this.element.value;this.intervalId=0;this.cachedResponse={};this.onChange=this.onChangeInterval=null;this.isLocal=!1;this.suggestionsContainer=null;this.options=d.extend({},c,b);this.classes={selected:"autocomplete-selected",suggestion:"autocomplete-suggestion"}; 11 | this.hint=null;this.hintValue="";this.selection=null;this.initialize();this.setOptions(b)}var k=function(){return{escapeRegExChars:function(a){return a.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")},createNode:function(a){var b=document.createElement("div");b.className=a;b.style.position="absolute";b.style.display="none";return b}}}();g.utils=k;d.Autocomplete=g;g.formatResult=function(a,b){var c="("+k.escapeRegExChars(b)+")";return a.value.replace(RegExp(c,"gi"),"$1")};g.prototype= 12 | {killerFn:null,initialize:function(){var a=this,b="."+a.classes.suggestion,c=a.classes.selected,e=a.options,f;a.element.setAttribute("autocomplete","off");a.killerFn=function(b){0===d(b.target).closest("."+a.options.containerClass).length&&(a.killSuggestions(),a.disableKillerFn())};a.suggestionsContainer=g.utils.createNode(e.containerClass);f=d(a.suggestionsContainer);f.appendTo(e.appendTo);"auto"!==e.width&&f.width(e.width);f.on("mouseover.autocomplete",b,function(){a.activate(d(this).data("index"))}); 13 | f.on("mouseout.autocomplete",function(){a.selectedIndex=-1;f.children("."+c).removeClass(c)});f.on("click.autocomplete",b,function(){a.select(d(this).data("index"))});a.fixPosition();a.fixPositionCapture=function(){a.visible&&a.fixPosition()};d(window).on("resize.autocomplete",a.fixPositionCapture);a.el.on("keydown.autocomplete",function(b){a.onKeyPress(b)});a.el.on("keyup.autocomplete",function(b){a.onKeyUp(b)});a.el.on("blur.autocomplete",function(){a.onBlur()});a.el.on("focus.autocomplete",function(){a.onFocus()}); 14 | a.el.on("change.autocomplete",function(b){a.onKeyUp(b)})},onFocus:function(){this.fixPosition();if(this.options.minChars<=this.el.val().length)this.onValueChange()},onBlur:function(){this.enableKillerFn()},setOptions:function(a){var b=this.options;d.extend(b,a);if(this.isLocal=d.isArray(b.lookup))b.lookup=this.verifySuggestionsFormat(b.lookup);d(this.suggestionsContainer).css({"max-height":b.maxHeight+"px",width:b.width+"px","z-index":b.zIndex})},clearCache:function(){this.cachedResponse={};this.badQueries= 15 | []},clear:function(){this.clearCache();this.currentValue="";this.suggestions=[]},disable:function(){this.disabled=!0;this.currentRequest&&this.currentRequest.abort()},enable:function(){this.disabled=!1},fixPosition:function(){var a;"body"===this.options.appendTo&&(a=this.el.offset(),a={top:a.top+this.el.outerHeight()+"px",left:a.left+"px"},"auto"===this.options.width&&(a.width=this.el.outerWidth()-2+"px"),d(this.suggestionsContainer).css(a))},enableKillerFn:function(){d(document).on("click.autocomplete", 16 | this.killerFn)},disableKillerFn:function(){d(document).off("click.autocomplete",this.killerFn)},killSuggestions:function(){var a=this;a.stopKillSuggestions();a.intervalId=window.setInterval(function(){a.hide();a.stopKillSuggestions()},50)},stopKillSuggestions:function(){window.clearInterval(this.intervalId)},isCursorAtEnd:function(){var a=this.el.val().length,b=this.element.selectionStart;return"number"===typeof b?b===a:document.selection?(b=document.selection.createRange(),b.moveStart("character", 17 | -a),a===b.text.length):!0},onKeyPress:function(a){if(!this.disabled&&!this.visible&&40===a.which&&this.currentValue)this.suggest();else if(!this.disabled&&this.visible){switch(a.which){case 27:this.el.val(this.currentValue);this.hide();break;case 39:if(this.hint&&this.options.onHint&&this.isCursorAtEnd()){this.selectHint();break}return;case 9:if(this.hint&&this.options.onHint){this.selectHint();return}case 13:if(-1===this.selectedIndex){this.hide();return}this.select(this.selectedIndex);if(9===a.which&& 18 | !1===this.options.tabDisabled)return;break;case 38:this.moveUp();break;case 40:this.moveDown();break;default:return}a.stopImmediatePropagation();a.preventDefault()}},onKeyUp:function(a){var b=this;if(!b.disabled){switch(a.which){case 38:case 40:return}clearInterval(b.onChangeInterval);if(b.currentValue!==b.el.val())if(b.findBestHint(),0f&&(b.suggestions=b.suggestions.slice(0,f));return b},getSuggestions:function(a){var b,c=this,e=c.options,f=e.serviceUrl,l,g;e.params[e.paramName]=a;l=e.ignoreParams?null:e.params; 21 | c.isLocal?b=c.getSuggestionsLocal(a):(d.isFunction(f)&&(f=f.call(c.element,a)),g=f+"?"+d.param(l||{}),b=c.cachedResponse[g]);b&&d.isArray(b.suggestions)?(c.suggestions=b.suggestions,c.suggest()):c.isBadQuery(a)||!1===e.onSearchStart.call(c.element,e.params)||(c.currentRequest&&c.currentRequest.abort(),c.currentRequest=d.ajax({url:f,data:l,type:e.type,dataType:e.dataType}).done(function(b){c.currentRequest=null;c.processResponse(b,a,g);e.onSearchComplete.call(c.element,a)}).fail(function(b,d,f){e.onSearchError.call(c.element, 22 | a,b,d,f)}))},isBadQuery:function(a){for(var b=this.badQueries,c=b.length;c--;)if(0===a.indexOf(b[c]))return!0;return!1},hide:function(){this.visible=!1;this.selectedIndex=-1;d(this.suggestionsContainer).hide();this.signalHint(null)},suggest:function(){if(0===this.suggestions.length)this.hide();else{var a=this.options,b=a.formatResult,c=this.getQuery(this.currentValue),e=this.classes.suggestion,f=this.classes.selected,g=d(this.suggestionsContainer),k=a.beforeRender,m="",h;if(a.triggerSelectOnValidInput&& 23 | (h=this.findSuggestionIndex(c),-1!==h)){this.select(h);return}d.each(this.suggestions,function(a,d){m+='
'+b(d,c)+"
"});"auto"===a.width&&(h=this.el.outerWidth()-2,g.width(0this.selectedIndex?(a=e.get(this.selectedIndex),d(a).addClass(b),a):null},selectHint:function(){var a=d.inArray(this.hint,this.suggestions); 26 | this.select(a)},select:function(a){this.hide();this.onSelect(a)},moveUp:function(){-1!==this.selectedIndex&&(0===this.selectedIndex?(d(this.suggestionsContainer).children().first().removeClass(this.classes.selected),this.selectedIndex=-1,this.el.val(this.currentValue),this.findBestHint()):this.adjustScroll(this.selectedIndex-1))},moveDown:function(){this.selectedIndex!==this.suggestions.length-1&&this.adjustScroll(this.selectedIndex+1)},adjustScroll:function(a){var b=this.activate(a),c,e;b&&(b=b.offsetTop, 27 | c=d(this.suggestionsContainer).scrollTop(),e=c+this.options.maxHeight-25,be&&d(this.suggestionsContainer).scrollTop(b-this.options.maxHeight+25),this.el.val(this.getValue(this.suggestions[a].value)),this.signalHint(null))},onSelect:function(a){var b=this.options.onSelect;a=this.suggestions[a];this.currentValue=this.getValue(a.value);this.el.val(this.currentValue);this.signalHint(null);this.suggestions=[];this.selection=a;d.isFunction(b)&&b.call(this.element, 28 | a)},getValue:function(a){var b=this.options.delimiter,c;if(!b)return a;c=this.currentValue;b=c.split(b);return 1===b.length?a:c.substr(0,c.length-b[b.length-1].length)+a},dispose:function(){this.el.off(".autocomplete").removeData("autocomplete");this.disableKillerFn();d(window).off("resize.autocomplete",this.fixPositionCapture);d(this.suggestionsContainer).remove()}};d.fn.autocomplete=function(a,b){return 0===arguments.length?this.first().data("autocomplete"):this.each(function(){var c=d(this),e= 29 | c.data("autocomplete");if("string"===typeof a){if(e&&"function"===typeof e[a])e[a](b)}else e&&e.dispose&&e.dispose(),e=new g(this,a),c.data("autocomplete",e)})}}); -------------------------------------------------------------------------------- /stylesheets/normalize.css: -------------------------------------------------------------------------------- 1 | /* normalize.css 2012-02-07T12:37 UTC - http://github.com/necolas/normalize.css */ 2 | /* ============================================================================= 3 | HTML5 display definitions 4 | ========================================================================== */ 5 | /* 6 | * Corrects block display not defined in IE6/7/8/9 & FF3 7 | */ 8 | article, 9 | aside, 10 | details, 11 | figcaption, 12 | figure, 13 | footer, 14 | header, 15 | hgroup, 16 | nav, 17 | section, 18 | summary { 19 | display: block; 20 | } 21 | 22 | /* 23 | * Corrects inline-block display not defined in IE6/7/8/9 & FF3 24 | */ 25 | audio, 26 | canvas, 27 | video { 28 | display: inline-block; 29 | *display: inline; 30 | *zoom: 1; 31 | } 32 | 33 | /* 34 | * Prevents modern browsers from displaying 'audio' without controls 35 | */ 36 | audio:not([controls]) { 37 | display: none; 38 | } 39 | 40 | /* 41 | * Addresses styling for 'hidden' attribute not present in IE7/8/9, FF3, S4 42 | * Known issue: no IE6 support 43 | */ 44 | [hidden] { 45 | display: none; 46 | } 47 | 48 | /* ============================================================================= 49 | Base 50 | ========================================================================== */ 51 | /* 52 | * 1. Corrects text resizing oddly in IE6/7 when body font-size is set using em units 53 | * http://clagnut.com/blog/348/#c790 54 | * 2. Prevents iOS text size adjust after orientation change, without disabling user zoom 55 | * www.456bereastreet.com/archive/201012/controlling_text_size_in_safari_for_ios_without_disabling_user_zoom/ 56 | */ 57 | html { 58 | font-size: 100%; 59 | /* 1 */ 60 | -webkit-text-size-adjust: 100%; 61 | /* 2 */ 62 | -ms-text-size-adjust: 100%; 63 | /* 2 */ 64 | } 65 | 66 | /* 67 | * Addresses font-family inconsistency between 'textarea' and other form elements. 68 | */ 69 | html, 70 | button, 71 | input, 72 | select, 73 | textarea { 74 | font-family: sans-serif; 75 | } 76 | 77 | /* 78 | * Addresses margins handled incorrectly in IE6/7 79 | */ 80 | body { 81 | margin: 0; 82 | } 83 | 84 | /* ============================================================================= 85 | Links 86 | ========================================================================== */ 87 | /* 88 | * Addresses outline displayed oddly in Chrome 89 | */ 90 | a:focus { 91 | outline: thin dotted; 92 | } 93 | 94 | /* 95 | * Improves readability when focused and also mouse hovered in all browsers 96 | * people.opera.com/patrickl/experiments/keyboard/test 97 | */ 98 | a:hover, 99 | a:active { 100 | outline: 0; 101 | } 102 | 103 | /* ============================================================================= 104 | Typography 105 | ========================================================================== */ 106 | /* 107 | * Addresses font sizes and margins set differently in IE6/7 108 | * Addresses font sizes within 'section' and 'article' in FF4+, Chrome, S5 109 | */ 110 | h1 { 111 | font-size: 2em; 112 | margin: 0.67em 0; 113 | } 114 | 115 | h2 { 116 | font-size: 1.5em; 117 | margin: 0.83em 0; 118 | } 119 | 120 | h3 { 121 | font-size: 1.17em; 122 | margin: 1em 0; 123 | } 124 | 125 | h4 { 126 | font-size: 1em; 127 | margin: 1.33em 0; 128 | } 129 | 130 | h5 { 131 | font-size: 0.83em; 132 | margin: 1.67em 0; 133 | } 134 | 135 | h6 { 136 | font-size: 0.75em; 137 | margin: 2.33em 0; 138 | } 139 | 140 | /* 141 | * Addresses styling not present in IE7/8/9, S5, Chrome 142 | */ 143 | abbr[title] { 144 | border-bottom: 1px dotted; 145 | } 146 | 147 | /* 148 | * Addresses style set to 'bolder' in FF3+, S4/5, Chrome 149 | */ 150 | b, 151 | strong { 152 | font-weight: bold; 153 | } 154 | 155 | blockquote { 156 | margin: 1em 40px; 157 | } 158 | 159 | /* 160 | * Addresses styling not present in S5, Chrome 161 | */ 162 | dfn { 163 | font-style: italic; 164 | } 165 | 166 | /* 167 | * Addresses styling not present in IE6/7/8/9 168 | */ 169 | mark { 170 | background: #ff0; 171 | color: #000; 172 | } 173 | 174 | /* 175 | * Addresses margins set differently in IE6/7 176 | */ 177 | p, 178 | pre { 179 | margin: 1em 0; 180 | } 181 | 182 | /* 183 | * Corrects font family set oddly in IE6, S4/5, Chrome 184 | * en.wikipedia.org/wiki/User:Davidgothberg/Test59 185 | */ 186 | pre, 187 | code, 188 | kbd, 189 | samp { 190 | font-family: monospace, serif; 191 | _font-family: 'courier new', monospace; 192 | font-size: 1em; 193 | } 194 | 195 | /* 196 | * 1. Addresses CSS quotes not supported in IE6/7 197 | * 2. Addresses quote property not supported in S4 198 | */ 199 | /* 1 */ 200 | q { 201 | quotes: none; 202 | } 203 | 204 | /* 2 */ 205 | q:before, 206 | q:after { 207 | content: ''; 208 | content: none; 209 | } 210 | 211 | small { 212 | font-size: 75%; 213 | } 214 | 215 | /* 216 | * Prevents sub and sup affecting line-height in all browsers 217 | * gist.github.com/413930 218 | */ 219 | sub, 220 | sup { 221 | font-size: 75%; 222 | line-height: 0; 223 | position: relative; 224 | vertical-align: baseline; 225 | } 226 | 227 | sup { 228 | top: -0.5em; 229 | } 230 | 231 | sub { 232 | bottom: -0.25em; 233 | } 234 | 235 | /* ============================================================================= 236 | Lists 237 | ========================================================================== */ 238 | /* 239 | * Addresses margins set differently in IE6/7 240 | */ 241 | dl, 242 | menu, 243 | ol, 244 | ul { 245 | margin: 1em 0; 246 | } 247 | 248 | dd { 249 | margin: 0 0 0 40px; 250 | } 251 | 252 | /* 253 | * Addresses paddings set differently in IE6/7 254 | */ 255 | menu, 256 | ol, 257 | ul { 258 | padding: 0 0 0 40px; 259 | } 260 | 261 | /* 262 | * Corrects list images handled incorrectly in IE7 263 | */ 264 | nav ul, 265 | nav ol { 266 | list-style: none; 267 | list-style-image: none; 268 | } 269 | 270 | /* ============================================================================= 271 | Embedded content 272 | ========================================================================== */ 273 | /* 274 | * 1. Removes border when inside 'a' element in IE6/7/8/9, FF3 275 | * 2. Improves image quality when scaled in IE7 276 | * code.flickr.com/blog/2008/11/12/on-ui-quality-the-little-things-client-side-image-resizing/ 277 | */ 278 | img { 279 | border: 0; 280 | /* 1 */ 281 | -ms-interpolation-mode: bicubic; 282 | /* 2 */ 283 | } 284 | 285 | /* 286 | * Corrects overflow displayed oddly in IE9 287 | */ 288 | svg:not(:root) { 289 | overflow: hidden; 290 | } 291 | 292 | /* ============================================================================= 293 | Figures 294 | ========================================================================== */ 295 | /* 296 | * Addresses margin not present in IE6/7/8/9, S5, O11 297 | */ 298 | figure { 299 | margin: 0; 300 | } 301 | 302 | /* ============================================================================= 303 | Forms 304 | ========================================================================== */ 305 | /* 306 | * Corrects margin displayed oddly in IE6/7 307 | */ 308 | form { 309 | margin: 0; 310 | } 311 | 312 | /* 313 | * Define consistent border, margin, and padding 314 | */ 315 | fieldset { 316 | border: 1px solid #c0c0c0; 317 | margin: 0 2px; 318 | padding: 0.35em 0.625em 0.75em; 319 | } 320 | 321 | /* 322 | * 1. Corrects color not being inherited in IE6/7/8/9 323 | * 2. Corrects text not wrapping in FF3 324 | * 3. Corrects alignment displayed oddly in IE6/7 325 | */ 326 | legend { 327 | border: 0; 328 | /* 1 */ 329 | padding: 0; 330 | white-space: normal; 331 | /* 2 */ 332 | *margin-left: -7px; 333 | /* 3 */ 334 | } 335 | 336 | /* 337 | * 1. Corrects font size not being inherited in all browsers 338 | * 2. Addresses margins set differently in IE6/7, FF3+, S5, Chrome 339 | * 3. Improves appearance and consistency in all browsers 340 | */ 341 | button, 342 | input, 343 | select, 344 | textarea { 345 | font-size: 100%; 346 | /* 1 */ 347 | margin: 0; 348 | /* 2 */ 349 | vertical-align: baseline; 350 | /* 3 */ 351 | *vertical-align: middle; 352 | /* 3 */ 353 | } 354 | 355 | /* 356 | * Addresses FF3/4 setting line-height on 'input' using !important in the UA stylesheet 357 | */ 358 | button, 359 | input { 360 | line-height: normal; 361 | /* 1 */ 362 | } 363 | 364 | /* 365 | * 1. Improves usability and consistency of cursor style between image-type 'input' and others 366 | * 2. Corrects inability to style clickable 'input' types in iOS 367 | * 3. Removes inner spacing in IE7 without affecting normal text inputs 368 | * Known issue: inner spacing remains in IE6 369 | */ 370 | button, 371 | input[type="button"], 372 | input[type="reset"], 373 | input[type="submit"] { 374 | cursor: pointer; 375 | /* 1 */ 376 | -webkit-appearance: button; 377 | /* 2 */ 378 | *overflow: visible; 379 | /* 3 */ 380 | } 381 | 382 | /* 383 | * Re-set default cursor for disabled elements 384 | */ 385 | button[disabled], 386 | input[disabled] { 387 | cursor: default; 388 | } 389 | 390 | /* 391 | * 1. Addresses box sizing set to content-box in IE8/9 392 | * 2. Removes excess padding in IE8/9 393 | * 3. Removes excess padding in IE7 394 | Known issue: excess padding remains in IE6 395 | */ 396 | input[type="checkbox"], 397 | input[type="radio"] { 398 | box-sizing: border-box; 399 | /* 1 */ 400 | padding: 0; 401 | /* 2 */ 402 | *height: 13px; 403 | /* 3 */ 404 | *width: 13px; 405 | /* 3 */ 406 | } 407 | 408 | /* 409 | * 1. Addresses appearance set to searchfield in S5, Chrome 410 | * 2. Addresses box-sizing set to border-box in S5, Chrome (include -moz to future-proof) 411 | */ 412 | input[type="search"] { 413 | -webkit-appearance: textfield; 414 | /* 1 */ 415 | -moz-box-sizing: content-box; 416 | -webkit-box-sizing: content-box; 417 | /* 2 */ 418 | box-sizing: content-box; 419 | } 420 | 421 | /* 422 | * Removes inner padding and search cancel button in S5, Chrome on OS X 423 | */ 424 | input[type="search"]::-webkit-search-decoration, 425 | input[type="search"]::-webkit-search-cancel-button { 426 | -webkit-appearance: none; 427 | } 428 | 429 | /* 430 | * Removes inner padding and border in FF3+ 431 | * www.sitepen.com/blog/2008/05/14/the-devils-in-the-details-fixing-dojos-toolbar-buttons/ 432 | */ 433 | button::-moz-focus-inner, 434 | input::-moz-focus-inner { 435 | border: 0; 436 | padding: 0; 437 | } 438 | 439 | /* 440 | * 1. Removes default vertical scrollbar in IE6/7/8/9 441 | * 2. Improves readability and alignment in all browsers 442 | */ 443 | textarea { 444 | overflow: auto; 445 | /* 1 */ 446 | vertical-align: top; 447 | /* 2 */ 448 | } 449 | 450 | /* ============================================================================= 451 | Tables 452 | ========================================================================== */ 453 | /* 454 | * Remove most spacing between table cells 455 | */ 456 | table { 457 | border-collapse: collapse; 458 | border-spacing: 0; 459 | } 460 | -------------------------------------------------------------------------------- /dataquality.js: -------------------------------------------------------------------------------- 1 | // Data Quality: headless sanity checks for Yatayat System data. 2 | 3 | var DQ = DQ || {}; 4 | var _ = _ || require("underscore"); 5 | 6 | // nearestStops returns squared-distance; 7 | // regardless, this is a magic number. 8 | var SAME_STOP_DIST = Math.pow(0.0005,2); 9 | 10 | DQ.sanityChecks = { 11 | // name of test -> { 12 | // run: function(route, [system]), 13 | // print: function(run_output, route, system) 14 | // } 15 | 16 | 17 | "nearby different stops": { 18 | run: function(route, system) { 19 | // Returns: stop1.id -> stop2, when stop1 and stop2 are nearby 20 | // and different 21 | stopClosest = {}; 22 | 23 | route.stops.forEach(function(stop) { 24 | var stops = system.nearestStops([stop.lat, stop.lng], 2, SAME_STOP_DIST) 25 | .filter(function(s) { return s.id !== stop.id; }); 26 | if(stops.length > 0 && stop.name && stops[0].name && stops[0].name !== stop.name) { 27 | stopClosest[stop.id] = stops[0]; 28 | } 29 | }); 30 | 31 | return stopClosest; 32 | }, 33 | print: function(run_output, route, system) { 34 | var pairs = []; 35 | for(var stopid in run_output) { 36 | pairs.push([route.stopDict[stopid], run_output[stopid]]); 37 | } 38 | if(pairs.length > 0) { 39 | var out = "" + pairs.length + " nearby different stops:\n"; 40 | pairs.forEach(function(pair) { 41 | out += " " + pair[0].name + "(" + pair[0].id + ") - " + pair[1].name + "(" + pair[1].id + ")\n"; 42 | }); 43 | out += "\n"; 44 | return out; 45 | } 46 | }, 47 | kind: 'WARNING' 48 | }, 49 | 50 | "first segment doesn't end at a stop": { 51 | run: function(route) { 52 | if(route.stops.length === 0 || route.segments.length === 0) { 53 | return true; 54 | } 55 | var firstStop = route.stops[0]; 56 | var firstSegmentEnd = route.segments[0].listOfLatLng[0]; 57 | if (!firstStop) return true; 58 | return firstStop.lat == firstSegmentEnd[0] && firstStop.lng == firstSegmentEnd[1]; 59 | }, 60 | print: function(run_output, route) { 61 | debugger; 62 | if (run_output) { 63 | if(route.stops.length === 0 || route.segments.length === 0) { 64 | return "Without stops or segments, it's silly to talk about whether the first segment will end at a stop.\n\n"; 65 | } 66 | return "First segment of route (id:" + route.segments[0].id + 67 | ") doesn't start at a properly key-ed stop.\n"; 68 | } 69 | }, 70 | kind: 'WARNING' 71 | }, 72 | 73 | "unnamed stops": { 74 | run: function(route) { 75 | // Returns: stop.id -> true, when stop is unnamed 76 | unnamedStops = {}; 77 | 78 | route.stops.forEach(function(stop) { 79 | if(!stop.name) { 80 | unnamedStops[stop.id] = true; 81 | } 82 | }); 83 | 84 | return unnamedStops; 85 | }, 86 | print: function(run_output, route, system) { 87 | var stops = []; 88 | for(var stopid in run_output) { 89 | stops.push(route.stopDict[stopid]); 90 | } 91 | if(stops.length > 0) { 92 | var out = "" + stops.length + " unnamed stops:\n"; 93 | stops.forEach(function(stop) { 94 | out += " " + stop.id + "\n"; 95 | }); 96 | out += "\n"; 97 | return out; 98 | } 99 | }, 100 | kind: 'WARNING' 101 | }, 102 | 103 | "no terminus": { 104 | run: function(route) { 105 | // Returns true if route has no terminus, false otherwise 106 | return false || route._noTerminus; 107 | }, 108 | print: function(run_output, route, system) { 109 | if(run_output) { 110 | return "No terminus\n\n"; 111 | } 112 | }, 113 | kind: 'ERROR' 114 | }, 115 | 116 | "unconnected segments": { 117 | run: function(route) { 118 | // Returns seg.id -> true, when Segment is unconnected 119 | unconnected = {}; 120 | route._unconnectedSegments.forEach(function(seg) { 121 | unconnected[seg.id] = true; 122 | }); 123 | return unconnected; 124 | }, 125 | print: function(run_output, route, system) { 126 | var segs = []; 127 | for(var segid in run_output) { 128 | segs.push(segid); 129 | } 130 | if(segs.length > 0) { 131 | var out = "" + segs.length + " unconnected segments:\n"; 132 | segs.forEach(function(segid) { 133 | out += " " + segid + "\n"; 134 | }); 135 | out += "\n"; 136 | return out; 137 | } 138 | }, 139 | kind: 'ERROR' 140 | }, 141 | 142 | "similar names": { 143 | run: function(route, system) { 144 | // Returns stop1.id -> stop2, when stop1 and stop2 have 145 | // similar names. 146 | 147 | // thanks! http://thinkphp.ro/apps/js-hacks/String.levenshtein/String.levenshtein.html 148 | var levenshtein = function(stringa, stringb) { 149 | var cost = new Array(), 150 | str1 = stringa, 151 | str2 = stringb, 152 | n = str1.length, 153 | m = str2.length, 154 | i, j; 155 | var minimum = function(a,b,c) { 156 | var min = a; 157 | if(b < min) { 158 | min = b; 159 | } 160 | if(c < min) { 161 | min = c; 162 | } 163 | return min; 164 | } 165 | 166 | if(n == 0 || m == 0) { 167 | return; 168 | } 169 | 170 | for(var i=0;i<=n;i++) { 171 | cost[i] = new Array(); 172 | } 173 | 174 | for(i=0;i<=n;i++) { 175 | cost[i][0] = i; 176 | } 177 | 178 | for(j=0;j<=m;j++) { 179 | cost[0][j] = j; 180 | } 181 | 182 | for(i=1;i<=n;i++) { 183 | var x = str1.charAt(i-1); 184 | for(j=1;j<=m;j++) { 185 | var y = str2.charAt(j-1); 186 | if(x == y) { 187 | cost[i][j] = cost[i-1][j-1]; 188 | } else { 189 | cost[i][j] = 1 + minimum(cost[i-1][j-1], cost[i][j-1], cost[i-1][j]); 190 | } 191 | } 192 | } 193 | return cost[n][m]; 194 | }; 195 | 196 | var preprocess = function(str) { 197 | return str.toLowerCase().replace(' ', ''); 198 | }; 199 | 200 | similarNames = {}; 201 | 202 | // n^2 algorithm that compares string-distance between every two pairs of stop 203 | route.stops.forEach(function(stop) { 204 | 205 | system.routes.forEach(function(route2) { 206 | route.stops.forEach(function(stop2) { 207 | 208 | if(stop.name && stop2.name && levenshtein(stop.name, stop2.name) < 3) { 209 | var physicalDistance = Math.pow(stop.lat-stop2.lat,2) + Math.pow(stop.lng-stop2.lng,2); 210 | if(physicalDistance > SAME_STOP_DIST) { 211 | // console.log(stop.name, stop2.name, physicalDistance); 212 | similarNames[stop.id] = stop2; 213 | } 214 | else if(stop.id != stop2.id) { 215 | //console.log(stop.name, stop2.name, 'nearby'); 216 | } 217 | } 218 | 219 | }); 220 | }); 221 | }); 222 | return similarNames; 223 | }, 224 | print: function(run_output, route, system) { 225 | // XXX: *very* similar code to nearby different stops 226 | var pairs = []; 227 | for(var stopid in run_output) { 228 | pairs.push([route.stopDict[stopid], run_output[stopid]]); 229 | } 230 | if(pairs.length > 0) { 231 | var out = "" + pairs.length + " stops with similar names:\n"; 232 | pairs.forEach(function(pair) { 233 | out += " " + pair[0].name + "(" + pair[0].id + ") - " + pair[1].name + "(" + pair[1].id + ")\n"; 234 | }); 235 | out += "\n"; 236 | return out; 237 | } 238 | }, 239 | kind: 'WARNING' 240 | } 241 | }; 242 | 243 | // For easier integration with data_quality.html, make aliases 244 | DQ.nearbyDifferentStops = DQ.sanityChecks["nearby different stops"].run; 245 | DQ.unnamedStops = DQ.sanityChecks["unnamed stops"].run; 246 | DQ.similarNames = DQ.sanityChecks["similar names"].run; 247 | DQ.noTerminus = DQ.sanityChecks["no terminus"].run; 248 | DQ.unconnectedSegments = DQ.sanityChecks["unconnected segments"].run; 249 | 250 | DQ.errorString = function(system, which) { 251 | var which = which || 'ERROR'; // possible options: 'ERROR', 'WARNING' 252 | var errForRoute = function(route) { 253 | var errs = DQ.findErrorsAndWarnings(route, system)[which]; 254 | var prequel = "\n### Route: " + route.name + " (" + route.id + ")\n\n" + 255 | "http://yatayat.monsooncollective.org/data_quality.html#" + route.id + "\n\n"; 256 | return errs ? prequel + errs : ""; 257 | }; 258 | return _.chain(system.routes) 259 | .map(errForRoute) 260 | .reduce(function(a, b) { return a+b; }, "") 261 | .value(); 262 | }; 263 | 264 | DQ.findErrorsAndWarnings = function(route, system) { 265 | var retval = {}; 266 | //TODO: If route is undefined 267 | _(DQ.sanityChecks).each(function(v, testname) { 268 | var test = DQ.sanityChecks[testname]; 269 | var res = test.run(route, system); 270 | var errout = test.print(res, route, system); 271 | if(errout) { 272 | if(!(test.kind in retval)) // warning or error not added yet 273 | retval[test.kind] = [errout]; 274 | else 275 | retval[test.kind].push(errout); 276 | } 277 | }); 278 | return retval; 279 | }; 280 | DQ.findAllErrorsAndWarnings = function(system) { 281 | return system.routes.map(function(r) { return DQ.findErrorsAndWarnings(r, system); }); 282 | }; 283 | DQ.findCorrectRoutes = function(system) { 284 | return system.routes.filter(function(route) { 285 | for(var testname in DQ.sanityChecks) { 286 | var res = DQ.sanityChecks[testname].run(route, system); 287 | var errout = DQ.sanityChecks[testname].print(res, route, system); 288 | if(errout) { 289 | return false; 290 | } 291 | } 292 | return true; 293 | }); 294 | }; 295 | 296 | 297 | // export as a node module 298 | var module = module || {}; 299 | module.exports = DQ; 300 | -------------------------------------------------------------------------------- /javascripts/respond.js: -------------------------------------------------------------------------------- 1 | if(typeof Object.create!=="function"){ 2 | Object.create=function(o){ 3 | function F(){ 4 | }; 5 | F.prototype=o; 6 | return new F(); 7 | }; 8 | } 9 | var ua={toString:function(){ 10 | return navigator.userAgent; 11 | },test:function(s){ 12 | return this.toString().toLowerCase().indexOf(s.toLowerCase())>-1; 13 | }}; 14 | ua.version=(ua.toString().toLowerCase().match(/[\s\S]+(?:rv|it|ra|ie)[\/: ]([\d.]+)/)||[])[1]; 15 | ua.webkit=ua.test("webkit"); 16 | ua.gecko=ua.test("gecko")&&!ua.webkit; 17 | ua.opera=ua.test("opera"); 18 | ua.ie=ua.test("msie")&&!ua.opera; 19 | ua.ie6=ua.ie&&document.compatMode&&typeof document.documentElement.style.maxHeight==="undefined"; 20 | ua.ie7=ua.ie&&document.documentElement&&typeof document.documentElement.style.maxHeight!=="undefined"&&typeof XDomainRequest==="undefined"; 21 | ua.ie8=ua.ie&&typeof XDomainRequest!=="undefined"; 22 | var domReady=function(){ 23 | var _1=[]; 24 | var _2=function(){ 25 | if(!arguments.callee.done){ 26 | arguments.callee.done=true; 27 | for(var i=0;i<_1.length;i++){ 28 | _1[i](); 29 | } 30 | } 31 | }; 32 | if(document.addEventListener){ 33 | document.addEventListener("DOMContentLoaded",_2,false); 34 | } 35 | if(ua.ie){ 36 | (function(){ 37 | try{ 38 | document.documentElement.doScroll("left"); 39 | } 40 | catch(e){ 41 | setTimeout(arguments.callee,50); 42 | return; 43 | } 44 | _2(); 45 | })(); 46 | document.onreadystatechange=function(){ 47 | if(document.readyState==="complete"){ 48 | document.onreadystatechange=null; 49 | _2(); 50 | } 51 | }; 52 | } 53 | if(ua.webkit&&document.readyState){ 54 | (function(){ 55 | if(document.readyState!=="loading"){ 56 | _2(); 57 | }else{ 58 | setTimeout(arguments.callee,10); 59 | } 60 | })(); 61 | } 62 | window.onload=_2; 63 | return function(fn){ 64 | if(typeof fn==="function"){ 65 | _1[_1.length]=fn; 66 | } 67 | return fn; 68 | }; 69 | }(); 70 | var cssHelper=function(){ 71 | var _3={BLOCKS:/[^\s{][^{]*\{(?:[^{}]*\{[^{}]*\}[^{}]*|[^{}]*)*\}/g,BLOCKS_INSIDE:/[^\s{][^{]*\{[^{}]*\}/g,DECLARATIONS:/[a-zA-Z\-]+[^;]*:[^;]+;/g,RELATIVE_URLS:/url\(['"]?([^\/\)'"][^:\)'"]+)['"]?\)/g,REDUNDANT_COMPONENTS:/(?:\/\*([^*\\\\]|\*(?!\/))+\*\/|@import[^;]+;)/g,REDUNDANT_WHITESPACE:/\s*(,|:|;|\{|\})\s*/g,MORE_WHITESPACE:/\s{2,}/g,FINAL_SEMICOLONS:/;\}/g,NOT_WHITESPACE:/\S+/g}; 72 | var _4,_5=false; 73 | var _6=[]; 74 | var _7=function(fn){ 75 | if(typeof fn==="function"){ 76 | _6[_6.length]=fn; 77 | } 78 | }; 79 | var _8=function(){ 80 | for(var i=0;i<_6.length;i++){ 81 | _6[i](_4); 82 | } 83 | }; 84 | var _9={}; 85 | var _a=function(n,v){ 86 | if(_9[n]){ 87 | var _b=_9[n].listeners; 88 | if(_b){ 89 | for(var i=0;i<_b.length;i++){ 90 | _b[i](v); 91 | } 92 | } 93 | } 94 | }; 95 | var _c=function(_d,_e,_f){ 96 | if(ua.ie&&!window.XMLHttpRequest){ 97 | window.XMLHttpRequest=function(){ 98 | return new ActiveXObject("Microsoft.XMLHTTP"); 99 | }; 100 | } 101 | if(!XMLHttpRequest){ 102 | return ""; 103 | } 104 | var r=new XMLHttpRequest(); 105 | try{ 106 | r.open("get",_d,true); 107 | r.setRequestHeader("X_REQUESTED_WITH","XMLHttpRequest"); 108 | } 109 | catch(e){ 110 | _f(); 111 | return; 112 | } 113 | var _10=false; 114 | setTimeout(function(){ 115 | _10=true; 116 | },5000); 117 | document.documentElement.style.cursor="progress"; 118 | r.onreadystatechange=function(){ 119 | if(r.readyState===4&&!_10){ 120 | if(!r.status&&location.protocol==="file:"||(r.status>=200&&r.status<300)||r.status===304||navigator.userAgent.indexOf("Safari")>-1&&typeof r.status==="undefined"){ 121 | _e(r.responseText); 122 | }else{ 123 | _f(); 124 | } 125 | document.documentElement.style.cursor=""; 126 | r=null; 127 | } 128 | }; 129 | r.send(""); 130 | }; 131 | var _11=function(_12){ 132 | _12=_12.replace(_3.REDUNDANT_COMPONENTS,""); 133 | _12=_12.replace(_3.REDUNDANT_WHITESPACE,"$1"); 134 | _12=_12.replace(_3.MORE_WHITESPACE," "); 135 | _12=_12.replace(_3.FINAL_SEMICOLONS,"}"); 136 | return _12; 137 | }; 138 | var _13={mediaQueryList:function(s){ 139 | var o={}; 140 | var idx=s.indexOf("{"); 141 | var lt=s.substring(0,idx); 142 | s=s.substring(idx+1,s.length-1); 143 | var mqs=[],rs=[]; 144 | var qts=lt.toLowerCase().substring(7).split(","); 145 | for(var i=0;i-1&&_23.href&&_23.href.length!==0&&!_23.disabled){ 315 | _1f[_1f.length]=_23; 316 | } 317 | } 318 | if(_1f.length>0){ 319 | var c=0; 320 | var _24=function(){ 321 | c++; 322 | if(c===_1f.length){ 323 | _20(); 324 | } 325 | }; 326 | var _25=function(_26){ 327 | var _27=_26.href; 328 | _c(_27,function(_28){ 329 | _28=_11(_28).replace(_3.RELATIVE_URLS,"url("+_27.substring(0,_27.lastIndexOf("/"))+"/$1)"); 330 | _26.cssHelperText=_28; 331 | _24(); 332 | },_24); 333 | }; 334 | for(i=0;i<_1f.length;i++){ 335 | _25(_1f[i]); 336 | } 337 | }else{ 338 | _20(); 339 | } 340 | }; 341 | var _29={mediaQueryLists:"array",rules:"array",selectors:"object",declarations:"array",properties:"object"}; 342 | var _2a={mediaQueryLists:null,rules:null,selectors:null,declarations:null,properties:null}; 343 | var _2b=function(_2c,v){ 344 | if(_2a[_2c]!==null){ 345 | if(_29[_2c]==="array"){ 346 | return (_2a[_2c]=_2a[_2c].concat(v)); 347 | }else{ 348 | var c=_2a[_2c]; 349 | for(var n in v){ 350 | if(v.hasOwnProperty(n)){ 351 | if(!c[n]){ 352 | c[n]=v[n]; 353 | }else{ 354 | c[n]=c[n].concat(v[n]); 355 | } 356 | } 357 | } 358 | return c; 359 | } 360 | } 361 | }; 362 | var _2d=function(_2e){ 363 | _2a[_2e]=(_29[_2e]==="array")?[]:{}; 364 | for(var i=0;i<_4.length;i++){ 365 | _2b(_2e,_4[i].cssHelperParsed[_2e]); 366 | } 367 | return _2a[_2e]; 368 | }; 369 | domReady(function(){ 370 | var els=document.body.getElementsByTagName("*"); 371 | for(var i=0;i=_44)||(max&&_46<_44)||(!min&&!max&&_46===_44)); 554 | }else{ 555 | return false; 556 | } 557 | }else{ 558 | return _46>0; 559 | } 560 | }else{ 561 | if("device-height"===_41.substring(l-13,l)){ 562 | _47=screen.height; 563 | if(_42!==null){ 564 | if(_43==="length"){ 565 | return ((min&&_47>=_44)||(max&&_47<_44)||(!min&&!max&&_47===_44)); 566 | }else{ 567 | return false; 568 | } 569 | }else{ 570 | return _47>0; 571 | } 572 | }else{ 573 | if("width"===_41.substring(l-5,l)){ 574 | _46=document.documentElement.clientWidth||document.body.clientWidth; 575 | if(_42!==null){ 576 | if(_43==="length"){ 577 | return ((min&&_46>=_44)||(max&&_46<_44)||(!min&&!max&&_46===_44)); 578 | }else{ 579 | return false; 580 | } 581 | }else{ 582 | return _46>0; 583 | } 584 | }else{ 585 | if("height"===_41.substring(l-6,l)){ 586 | _47=document.documentElement.clientHeight||document.body.clientHeight; 587 | if(_42!==null){ 588 | if(_43==="length"){ 589 | return ((min&&_47>=_44)||(max&&_47<_44)||(!min&&!max&&_47===_44)); 590 | }else{ 591 | return false; 592 | } 593 | }else{ 594 | return _47>0; 595 | } 596 | }else{ 597 | if("device-aspect-ratio"===_41.substring(l-19,l)){ 598 | return _43==="aspect-ratio"&&screen.width*_44[1]===screen.height*_44[0]; 599 | }else{ 600 | if("color-index"===_41.substring(l-11,l)){ 601 | var _48=Math.pow(2,screen.colorDepth); 602 | if(_42!==null){ 603 | if(_43==="absolute"){ 604 | return ((min&&_48>=_44)||(max&&_48<_44)||(!min&&!max&&_48===_44)); 605 | }else{ 606 | return false; 607 | } 608 | }else{ 609 | return _48>0; 610 | } 611 | }else{ 612 | if("color"===_41.substring(l-5,l)){ 613 | var _49=screen.colorDepth; 614 | if(_42!==null){ 615 | if(_43==="absolute"){ 616 | return ((min&&_49>=_44)||(max&&_49<_44)||(!min&&!max&&_49===_44)); 617 | }else{ 618 | return false; 619 | } 620 | }else{ 621 | return _49>0; 622 | } 623 | }else{ 624 | if("resolution"===_41.substring(l-10,l)){ 625 | var res; 626 | if(_45==="dpcm"){ 627 | res=_3d("1cm"); 628 | }else{ 629 | res=_3d("1in"); 630 | } 631 | if(_42!==null){ 632 | if(_43==="resolution"){ 633 | return ((min&&res>=_44)||(max&&res<_44)||(!min&&!max&&res===_44)); 634 | }else{ 635 | return false; 636 | } 637 | }else{ 638 | return res>0; 639 | } 640 | }else{ 641 | return false; 642 | } 643 | } 644 | } 645 | } 646 | } 647 | } 648 | } 649 | } 650 | }; 651 | var _4a=function(mq){ 652 | var _4b=mq.getValid(); 653 | var _4c=mq.getExpressions(); 654 | var l=_4c.length; 655 | if(l>0){ 656 | for(var i=0;i0){ 675 | s[c++]=","; 676 | } 677 | s[c++]=n; 678 | } 679 | } 680 | if(s.length>0){ 681 | _39[_39.length]=cssHelper.addStyle("@media "+s.join("")+"{"+mql.getCssText()+"}",false); 682 | } 683 | }; 684 | var _4e=function(_4f){ 685 | for(var i=0;i<_4f.length;i++){ 686 | _4d(_4f[i]); 687 | } 688 | if(ua.ie){ 689 | document.documentElement.style.display="block"; 690 | setTimeout(function(){ 691 | document.documentElement.style.display=""; 692 | },0); 693 | setTimeout(function(){ 694 | cssHelper.broadcast("cssMediaQueriesTested"); 695 | },100); 696 | }else{ 697 | cssHelper.broadcast("cssMediaQueriesTested"); 698 | } 699 | }; 700 | var _50=function(){ 701 | for(var i=0;i<_39.length;i++){ 702 | cssHelper.removeStyle(_39[i]); 703 | } 704 | _39=[]; 705 | cssHelper.mediaQueryLists(_4e); 706 | }; 707 | var _51=0; 708 | var _52=function(){ 709 | var _53=cssHelper.getViewportWidth(); 710 | var _54=cssHelper.getViewportHeight(); 711 | if(ua.ie){ 712 | var el=document.createElement("div"); 713 | el.style.position="absolute"; 714 | el.style.top="-9999em"; 715 | el.style.overflow="scroll"; 716 | document.body.appendChild(el); 717 | _51=el.offsetWidth-el.clientWidth; 718 | document.body.removeChild(el); 719 | } 720 | var _55; 721 | var _56=function(){ 722 | var vpw=cssHelper.getViewportWidth(); 723 | var vph=cssHelper.getViewportHeight(); 724 | if(Math.abs(vpw-_53)>_51||Math.abs(vph-_54)>_51){ 725 | _53=vpw; 726 | _54=vph; 727 | clearTimeout(_55); 728 | _55=setTimeout(function(){ 729 | if(!_3a()){ 730 | _50(); 731 | }else{ 732 | cssHelper.broadcast("cssMediaQueriesTested"); 733 | } 734 | },500); 735 | } 736 | }; 737 | window.onresize=function(){ 738 | var x=window.onresize||function(){ 739 | }; 740 | return function(){ 741 | x(); 742 | _56(); 743 | }; 744 | }(); 745 | }; 746 | var _57=document.documentElement; 747 | _57.style.marginLeft="-32767px"; 748 | setTimeout(function(){ 749 | _57.style.marginTop=""; 750 | },20000); 751 | return function(){ 752 | if(!_3a()){ 753 | cssHelper.addListener("newStyleParsed",function(el){ 754 | _4e(el.cssHelperParsed.mediaQueryLists); 755 | }); 756 | cssHelper.addListener("cssMediaQueriesTested",function(){ 757 | if(ua.ie){ 758 | _57.style.width="1px"; 759 | } 760 | setTimeout(function(){ 761 | _57.style.width=""; 762 | _57.style.marginLeft=""; 763 | },0); 764 | cssHelper.removeListener("cssMediaQueriesTested",arguments.callee); 765 | }); 766 | _3c(); 767 | _50(); 768 | }else{ 769 | _57.style.marginLeft=""; 770 | } 771 | _52(); 772 | }; 773 | }()); 774 | try{ 775 | document.execCommand("BackgroundImageCache",false,true); 776 | } 777 | catch(e){ 778 | } 779 | 780 | -------------------------------------------------------------------------------- /lib/bootstrap/js/bootstrap.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap.js by @fat & @mdo 3 | * Copyright 2012 Twitter, Inc. 4 | * http://www.apache.org/licenses/LICENSE-2.0.txt 5 | */ 6 | !function(a){a(function(){"use strict",a.support.transition=function(){var a=function(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd",msTransition:"MSTransitionEnd",transition:"transitionend"},c;for(c in b)if(a.style[c]!==undefined)return b[c]}();return a&&{end:a}}()})}(window.jQuery),!function(a){"use strict";var b='[data-dismiss="alert"]',c=function(c){a(c).on("click",b,this.close)};c.prototype.close=function(b){function f(){e.trigger("closed").remove()}var c=a(this),d=c.attr("data-target"),e;d||(d=c.attr("href"),d=d&&d.replace(/.*(?=#[^\s]*$)/,"")),e=a(d),b&&b.preventDefault(),e.length||(e=c.hasClass("alert")?c:c.parent()),e.trigger(b=a.Event("close"));if(b.isDefaultPrevented())return;e.removeClass("in"),a.support.transition&&e.hasClass("fade")?e.on(a.support.transition.end,f):f()},a.fn.alert=function(b){return this.each(function(){var d=a(this),e=d.data("alert");e||d.data("alert",e=new c(this)),typeof b=="string"&&e[b].call(d)})},a.fn.alert.Constructor=c,a(function(){a("body").on("click.alert.data-api",b,c.prototype.close)})}(window.jQuery),!function(a){"use strict";var b=function(b,c){this.$element=a(b),this.options=a.extend({},a.fn.button.defaults,c)};b.prototype.setState=function(a){var b="disabled",c=this.$element,d=c.data(),e=c.is("input")?"val":"html";a+="Text",d.resetText||c.data("resetText",c[e]()),c[e](d[a]||this.options[a]),setTimeout(function(){a=="loadingText"?c.addClass(b).attr(b,b):c.removeClass(b).removeAttr(b)},0)},b.prototype.toggle=function(){var a=this.$element.parent('[data-toggle="buttons-radio"]');a&&a.find(".active").removeClass("active"),this.$element.toggleClass("active")},a.fn.button=function(c){return this.each(function(){var d=a(this),e=d.data("button"),f=typeof c=="object"&&c;e||d.data("button",e=new b(this,f)),c=="toggle"?e.toggle():c&&e.setState(c)})},a.fn.button.defaults={loadingText:"loading..."},a.fn.button.Constructor=b,a(function(){a("body").on("click.button.data-api","[data-toggle^=button]",function(b){var c=a(b.target);c.hasClass("btn")||(c=c.closest(".btn")),c.button("toggle")})})}(window.jQuery),!function(a){"use strict";var b=function(b,c){this.$element=a(b),this.options=c,this.options.slide&&this.slide(this.options.slide),this.options.pause=="hover"&&this.$element.on("mouseenter",a.proxy(this.pause,this)).on("mouseleave",a.proxy(this.cycle,this))};b.prototype={cycle:function(b){return b||(this.paused=!1),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},to:function(b){var c=this.$element.find(".active"),d=c.parent().children(),e=d.index(c),f=this;if(b>d.length-1||b<0)return;return this.sliding?this.$element.one("slid",function(){f.to(b)}):e==b?this.pause().cycle():this.slide(b>e?"next":"prev",a(d[b]))},pause:function(a){return a||(this.paused=!0),clearInterval(this.interval),this.interval=null,this},next:function(){if(this.sliding)return;return this.slide("next")},prev:function(){if(this.sliding)return;return this.slide("prev")},slide:function(b,c){var d=this.$element.find(".active"),e=c||d[b](),f=this.interval,g=b=="next"?"left":"right",h=b=="next"?"first":"last",i=this,j=a.Event("slide");this.sliding=!0,f&&this.pause(),e=e.length?e:this.$element.find(".item")[h]();if(e.hasClass("active"))return;if(a.support.transition&&this.$element.hasClass("slide")){this.$element.trigger(j);if(j.isDefaultPrevented())return;e.addClass(b),e[0].offsetWidth,d.addClass(g),e.addClass(g),this.$element.one(a.support.transition.end,function(){e.removeClass([b,g].join(" ")).addClass("active"),d.removeClass(["active",g].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger("slid")},0)})}else{this.$element.trigger(j);if(j.isDefaultPrevented())return;d.removeClass("active"),e.addClass("active"),this.sliding=!1,this.$element.trigger("slid")}return f&&this.cycle(),this}},a.fn.carousel=function(c){return this.each(function(){var d=a(this),e=d.data("carousel"),f=a.extend({},a.fn.carousel.defaults,typeof c=="object"&&c);e||d.data("carousel",e=new b(this,f)),typeof c=="number"?e.to(c):typeof c=="string"||(c=f.slide)?e[c]():f.interval&&e.cycle()})},a.fn.carousel.defaults={interval:5e3,pause:"hover"},a.fn.carousel.Constructor=b,a(function(){a("body").on("click.carousel.data-api","[data-slide]",function(b){var c=a(this),d,e=a(c.attr("data-target")||(d=c.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,"")),f=!e.data("modal")&&a.extend({},e.data(),c.data());e.carousel(f),b.preventDefault()})})}(window.jQuery),!function(a){"use strict";var b=function(b,c){this.$element=a(b),this.options=a.extend({},a.fn.collapse.defaults,c),this.options.parent&&(this.$parent=a(this.options.parent)),this.options.toggle&&this.toggle()};b.prototype={constructor:b,dimension:function(){var a=this.$element.hasClass("width");return a?"width":"height"},show:function(){var b,c,d,e;if(this.transitioning)return;b=this.dimension(),c=a.camelCase(["scroll",b].join("-")),d=this.$parent&&this.$parent.find("> .accordion-group > .in");if(d&&d.length){e=d.data("collapse");if(e&&e.transitioning)return;d.collapse("hide"),e||d.data("collapse",null)}this.$element[b](0),this.transition("addClass",a.Event("show"),"shown"),this.$element[b](this.$element[0][c])},hide:function(){var b;if(this.transitioning)return;b=this.dimension(),this.reset(this.$element[b]()),this.transition("removeClass",a.Event("hide"),"hidden"),this.$element[b](0)},reset:function(a){var b=this.dimension();return this.$element.removeClass("collapse")[b](a||"auto")[0].offsetWidth,this.$element[a!==null?"addClass":"removeClass"]("collapse"),this},transition:function(b,c,d){var e=this,f=function(){c.type=="show"&&e.reset(),e.transitioning=0,e.$element.trigger(d)};this.$element.trigger(c);if(c.isDefaultPrevented())return;this.transitioning=1,this.$element[b]("in"),a.support.transition&&this.$element.hasClass("collapse")?this.$element.one(a.support.transition.end,f):f()},toggle:function(){this[this.$element.hasClass("in")?"hide":"show"]()}},a.fn.collapse=function(c){return this.each(function(){var d=a(this),e=d.data("collapse"),f=typeof c=="object"&&c;e||d.data("collapse",e=new b(this,f)),typeof c=="string"&&e[c]()})},a.fn.collapse.defaults={toggle:!0},a.fn.collapse.Constructor=b,a(function(){a("body").on("click.collapse.data-api","[data-toggle=collapse]",function(b){var c=a(this),d,e=c.attr("data-target")||b.preventDefault()||(d=c.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""),f=a(e).data("collapse")?"toggle":c.data();a(e).collapse(f)})})}(window.jQuery),!function(a){function d(){a(b).parent().removeClass("open")}"use strict";var b='[data-toggle="dropdown"]',c=function(b){var c=a(b).on("click.dropdown.data-api",this.toggle);a("html").on("click.dropdown.data-api",function(){c.parent().removeClass("open")})};c.prototype={constructor:c,toggle:function(b){var c=a(this),e,f,g;if(c.is(".disabled, :disabled"))return;return f=c.attr("data-target"),f||(f=c.attr("href"),f=f&&f.replace(/.*(?=#[^\s]*$)/,"")),e=a(f),e.length||(e=c.parent()),g=e.hasClass("open"),d(),g||e.toggleClass("open"),!1}},a.fn.dropdown=function(b){return this.each(function(){var d=a(this),e=d.data("dropdown");e||d.data("dropdown",e=new c(this)),typeof b=="string"&&e[b].call(d)})},a.fn.dropdown.Constructor=c,a(function(){a("html").on("click.dropdown.data-api",d),a("body").on("click.dropdown",".dropdown form",function(a){a.stopPropagation()}).on("click.dropdown.data-api",b,c.prototype.toggle)})}(window.jQuery),!function(a){function c(){var b=this,c=setTimeout(function(){b.$element.off(a.support.transition.end),d.call(b)},500);this.$element.one(a.support.transition.end,function(){clearTimeout(c),d.call(b)})}function d(a){this.$element.hide().trigger("hidden"),e.call(this)}function e(b){var c=this,d=this.$element.hasClass("fade")?"fade":"";if(this.isShown&&this.options.backdrop){var e=a.support.transition&&d;this.$backdrop=a('