├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── Makefile ├── README.md ├── activator ├── activator-launch-1.2.10.jar ├── app ├── Global.scala ├── controllers │ ├── Admin.java │ ├── Application.java │ ├── Dump.java │ ├── Secured.java │ └── api │ │ ├── CsvExportController.java │ │ ├── DeploymentController.java │ │ ├── FeedCollectionController.java │ │ ├── FeedSourceController.java │ │ ├── FeedVersionController.java │ │ ├── InvalidValueMixIn.java │ │ ├── JsonManager.java │ │ ├── NoteController.java │ │ ├── Rectangle2DDeserializer.java │ │ ├── Rectangle2DMixIn.java │ │ └── UserController.java ├── filters │ └── NoCache.scala ├── jobs │ ├── DeployJob.java │ ├── FetchGtfsJob.java │ ├── FetchProjectFeedsJob.java │ ├── FetchSingleFeedJob.java │ ├── MakePublicJob.java │ ├── ProcessSingleFeedJob.java │ └── RevalidateAllFeedVersionsJob.java ├── models │ ├── AgencyBranding.java │ ├── Deployment.java │ ├── FeedCollection.java │ ├── FeedSource.java │ ├── FeedValidationResultSummary.java │ ├── FeedVersion.java │ ├── JsonViews.java │ ├── Model.java │ ├── Note.java │ ├── OtpBuildConfig.java │ ├── OtpRouterConfig.java │ └── User.java ├── utils │ ├── ClassLoaderSerializer.java │ ├── DataStore.java │ ├── DeploymentManager.java │ ├── FeedStore.java │ ├── HashUtils.java │ └── StringUtils.java └── views │ ├── Public │ └── index.scala.html │ ├── index.scala.html │ └── main.scala.html ├── build.sbt ├── conf ├── application.conf.template ├── messages.en └── routes ├── migrations ├── addCustomBoundsToCollection.js ├── addEditorId.js ├── patchNoteIds.js ├── removeInvalidDeployments.js ├── removePreviousNextIds.js └── splitIsPublic.js ├── project ├── build.properties └── plugins.sbt ├── public ├── build │ ├── build.css │ ├── build.js │ ├── components │ │ └── bootstrap │ │ │ └── 3.3.2 │ │ │ ├── css │ │ │ ├── bootstrap-theme.css.map │ │ │ ├── bootstrap-theme.min.css │ │ │ ├── bootstrap.css.map │ │ │ └── bootstrap.min.css │ │ │ └── fonts │ │ │ ├── glyphicons-halflings-regular.eot │ │ │ ├── glyphicons-halflings-regular.svg │ │ │ ├── glyphicons-halflings-regular.ttf │ │ │ ├── glyphicons-halflings-regular.woff │ │ │ └── glyphicons-halflings-regular.woff2 │ ├── kpwebb │ │ └── select2 │ │ │ └── 3.4.8 │ │ │ ├── select2-spinner.gif │ │ │ ├── select2.png │ │ │ └── select2x2.png │ └── moment │ │ └── moment │ │ └── 2.8.3 │ │ ├── locale │ │ ├── af.js │ │ ├── ar-ma.js │ │ ├── ar-sa.js │ │ ├── ar.js │ │ ├── az.js │ │ ├── be.js │ │ ├── bg.js │ │ ├── bn.js │ │ ├── bo.js │ │ ├── br.js │ │ ├── bs.js │ │ ├── ca.js │ │ ├── cs.js │ │ ├── cv.js │ │ ├── cy.js │ │ ├── da.js │ │ ├── de-at.js │ │ ├── de.js │ │ ├── el.js │ │ ├── en-au.js │ │ ├── en-ca.js │ │ ├── en-gb.js │ │ ├── eo.js │ │ ├── es.js │ │ ├── et.js │ │ ├── eu.js │ │ ├── fa.js │ │ ├── fi.js │ │ ├── fo.js │ │ ├── fr-ca.js │ │ ├── fr.js │ │ ├── gl.js │ │ ├── he.js │ │ ├── hi.js │ │ ├── hr.js │ │ ├── hu.js │ │ ├── hy-am.js │ │ ├── id.js │ │ ├── is.js │ │ ├── it.js │ │ ├── ja.js │ │ ├── ka.js │ │ ├── km.js │ │ ├── ko.js │ │ ├── lb.js │ │ ├── lt.js │ │ ├── lv.js │ │ ├── mk.js │ │ ├── ml.js │ │ ├── mr.js │ │ ├── ms-my.js │ │ ├── my.js │ │ ├── nb.js │ │ ├── ne.js │ │ ├── nl.js │ │ ├── nn.js │ │ ├── pl.js │ │ ├── pt-br.js │ │ ├── pt.js │ │ ├── ro.js │ │ ├── ru.js │ │ ├── sk.js │ │ ├── sl.js │ │ ├── sq.js │ │ ├── sr-cyrl.js │ │ ├── sr.js │ │ ├── sv.js │ │ ├── ta.js │ │ ├── th.js │ │ ├── tl-ph.js │ │ ├── tr.js │ │ ├── tzm-latn.js │ │ ├── tzm.js │ │ ├── uk.js │ │ ├── uz.js │ │ ├── vi.js │ │ ├── zh-cn.js │ │ └── zh-tw.js │ │ └── moment.js ├── client │ ├── admin-helper │ │ ├── admin-helper.js │ │ └── component.json │ ├── admin-route │ │ ├── admin-route.html │ │ ├── admin-route.js │ │ └── component.json │ ├── application │ │ ├── application.css │ │ ├── application.js │ │ └── component.json │ ├── autologin-route │ │ ├── autologin-route.js │ │ └── component.json │ ├── bb │ │ ├── component.json │ │ └── index.js │ ├── breadcrumb-nav │ │ ├── breadcrumb-nav.html │ │ ├── breadcrumb-nav.js │ │ └── component.json │ ├── class-helper │ │ ├── class-helper.js │ │ ├── component.json │ │ ├── getClassForEndDate.js │ │ ├── getClassForStartDate.js │ │ └── highlightZero.js │ ├── composite-view │ │ ├── component.json │ │ └── index.js │ ├── confirm-view │ │ ├── component.json │ │ ├── confirm-view.html │ │ └── confirm-view.js │ ├── date-render-helper │ │ ├── component.json │ │ └── date-render-helper.js │ ├── deployment-collection-route │ │ ├── component.json │ │ └── deployment-collection-route.js │ ├── deployment-collection-view │ │ ├── component.json │ │ ├── deployment-collection-view.html │ │ ├── deployment-collection-view.js │ │ └── deployment-item-view.html │ ├── deployment-collection │ │ ├── component.json │ │ └── deployment-collection.js │ ├── deployment-progress-view │ │ ├── component.json │ │ ├── deployment-progress-view.html │ │ └── deployment-progress-view.js │ ├── deployment-route │ │ ├── component.json │ │ └── deployment-route.js │ ├── deployment-view │ │ ├── component.json │ │ ├── deployment-view.css │ │ ├── deployment-view.html │ │ ├── deployment-view.js │ │ └── feed-version-deployment-view.html │ ├── deployment │ │ ├── component.json │ │ └── deployment.js │ ├── editable-text-widget │ │ ├── component.json │ │ ├── editable-text-widget.css │ │ ├── editable-text-widget.html │ │ └── editable-text-widget.js │ ├── editor-agency-view │ │ ├── component.json │ │ ├── editor-agency-view.html │ │ └── editor-agency-view.js │ ├── feed-branding-view │ │ ├── component.json │ │ ├── feed-branding-view.html │ │ └── feed-branding-view.js │ ├── feed-collection-collection-view │ │ ├── component.json │ │ ├── feed-collection-collection-view.html │ │ └── feed-collection-collection-view.js │ ├── feed-collection-collection │ │ ├── component.json │ │ └── feed-collection-collection.js │ ├── feed-collection-route │ │ ├── component.json │ │ ├── feed-collection-route.html │ │ └── feed-collection-route.js │ ├── feed-collection │ │ ├── component.json │ │ └── feed-collection.js │ ├── feed-source-collection-view │ │ ├── component.json │ │ ├── feed-source-collection-view.html │ │ ├── feed-source-collection-view.js │ │ └── fetch-all-feeds-results.html │ ├── feed-source-collection │ │ ├── component.json │ │ └── feed-source-collection.js │ ├── feed-source-item-view │ │ ├── component.json │ │ ├── feed-source-item-view.css │ │ ├── feed-source-item-view.html │ │ └── feed-source-item-view.js │ ├── feed-source-route │ │ ├── component.json │ │ └── feed-source-route.js │ ├── feed-source-view │ │ ├── component.json │ │ ├── feed-source-view.html │ │ └── feed-source-view.js │ ├── feed-source │ │ ├── component.json │ │ └── feed-source.js │ ├── feed-upload-view │ │ ├── component.json │ │ ├── feed-upload-view.html │ │ ├── feed-upload-view.js │ │ └── views.js │ ├── feed-version-collection-route │ │ ├── component.json │ │ └── feed-version-collection-route.js │ ├── feed-version-collection-view │ │ ├── component.json │ │ ├── feed-version-collection-view.html │ │ ├── feed-version-collection-view.js │ │ └── feed-version-item-view.html │ ├── feed-version-collection │ │ ├── component.json │ │ └── feed-version-collection.js │ ├── feed-version-navigation-view │ │ ├── component.json │ │ ├── feed-version-navigation-view.html │ │ └── feed-version-navigation-view.js │ ├── feed-version-view │ │ ├── component.json │ │ ├── feed-version-view.html │ │ ├── feed-version-view.js │ │ └── invalid-values-list.html │ ├── feed-version │ │ ├── component.json │ │ └── feed-version.js │ ├── item-view │ │ ├── component.json │ │ └── index.js │ ├── layout-view │ │ ├── component.json │ │ └── index.js │ ├── logic-helper │ │ ├── and.js │ │ ├── component.json │ │ ├── eq.js │ │ ├── gt.js │ │ ├── logic-helper.js │ │ ├── neq.js │ │ └── ternary.js │ ├── login-route │ │ ├── component.json │ │ ├── index.js │ │ ├── login-route.html │ │ └── login-route.js │ ├── new-user-route │ │ ├── component.json │ │ └── new-user-route.js │ ├── note-collection-view │ │ ├── component.json │ │ ├── note-collection-view.html │ │ ├── note-collection-view.js │ │ └── note-item-view.html │ ├── note-collection │ │ ├── component.json │ │ └── note-collection.js │ ├── note │ │ ├── component.json │ │ └── note.js │ ├── ok-dialog-view │ │ ├── component.json │ │ ├── ok-dialog-view.html │ │ └── ok-dialog-view.js │ ├── osm-config-route │ │ ├── component.json │ │ └── osm-config-route.js │ ├── osm-config-view │ │ ├── component.json │ │ ├── osm-config-view.html │ │ └── osm-config-view.js │ ├── otp-config-route │ │ ├── component.json │ │ └── index.js │ ├── otp-config-view │ │ ├── component.json │ │ ├── index.js │ │ ├── style.css │ │ └── template.html │ ├── routes │ │ ├── component.json │ │ ├── index.js │ │ └── routes.js │ ├── templater │ │ ├── component.json │ │ ├── index.js │ │ └── input.html │ ├── text-helper │ │ ├── component.json │ │ ├── join.js │ │ └── text-helper.js │ ├── translate-helper │ │ ├── component.json │ │ └── t.js │ ├── user-collection-route │ │ ├── component.json │ │ └── user-collection-route.js │ ├── user-collection-view │ │ ├── component.json │ │ ├── user-collection-view.html │ │ ├── user-collection-view.js │ │ └── user-item-view.html │ ├── user-collection │ │ ├── component.json │ │ └── user-collection.js │ ├── user-route │ │ ├── component.json │ │ └── user-route.js │ ├── user-view │ │ ├── component.json │ │ ├── user-view.html │ │ └── user-view.js │ ├── user │ │ ├── component.json │ │ └── user.js │ └── validation-partial │ │ ├── component.json │ │ ├── validation-partial.html │ │ └── validation-partial.js ├── component.json ├── data │ └── README ├── docs │ └── data_manager_user_guide.pdf ├── images │ ├── favicon.png │ └── login_logo.png ├── index.html └── stylesheets │ └── main.css ├── scripts ├── bulkLoadFeeds.py ├── bulkLoadUrls.py ├── dump.py ├── load.py └── receiveFile.js ├── src └── templates │ └── etc-default └── test ├── ApplicationTest.java └── IntegrationTest.java /.gitignore: -------------------------------------------------------------------------------- 1 | logs 2 | project/project 3 | project/target 4 | target 5 | tmp 6 | .history 7 | dist 8 | /.idea 9 | /*.iml 10 | /out 11 | /.idea_modules 12 | /.classpath 13 | /.project 14 | /RUNNING_PID 15 | /.settings 16 | *~ 17 | \#*\# 18 | public/data/*.zip 19 | .\#* 20 | conf/application.conf 21 | data 22 | 23 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | # [0.3.4] - 2015-12-01 4 | 5 | - Fix NPE when exporting all feeds 6 | 7 | # [0.3.3] - 2015-12-01 8 | 9 | - Add build artifacts to the repository to eliminate one step when deploying 10 | 11 | # [0.3.2] - 2015-11-24 12 | 13 | - Add button to download all feeds -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Conveyal 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # build distributions 2 | # note that the configuration gets wrapped up in the build 3 | 4 | .PHONY: public rpm deb 5 | 6 | public: 7 | (cd public && component build -dc) 8 | 9 | rpm: public 10 | ./activator rpm:packageBin 11 | 12 | deb: public 13 | ./activator debian:packageBin 14 | -------------------------------------------------------------------------------- /activator-launch-1.2.10.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conveyal/gtfs-data-manager/e7269fc1660f1816da269b1c116b43bdf758900b/activator-launch-1.2.10.jar -------------------------------------------------------------------------------- /app/Global.scala: -------------------------------------------------------------------------------- 1 | import filters.NoCache 2 | import play.api.mvc.WithFilters 3 | 4 | object Global extends WithFilters(NoCache) 5 | -------------------------------------------------------------------------------- /app/controllers/Admin.java: -------------------------------------------------------------------------------- 1 | package controllers; 2 | 3 | import models.User; 4 | import play.mvc.Http.Context; 5 | 6 | /** 7 | * Check if a user is both logged in and an admin. 8 | * @author mattwigway 9 | * 10 | */ 11 | public class Admin extends Secured { 12 | @Override 13 | public String getUsername(Context ctx) { 14 | User u = User.getUserByUsername(ctx.session().get("username")); 15 | if (u != null && Boolean.TRUE.equals(u.active) && Boolean.TRUE.equals(u.admin)) { 16 | return u.username; 17 | } 18 | else { 19 | return null; 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /app/controllers/Secured.java: -------------------------------------------------------------------------------- 1 | package controllers; 2 | 3 | import models.User; 4 | import play.mvc.Result; 5 | import play.mvc.Security; 6 | import play.mvc.Http.Context; 7 | 8 | /** 9 | * Check if a user is authenticated, and 401 if not 10 | * @author mattwigway 11 | * 12 | */ 13 | public class Secured extends Security.Authenticator { 14 | @Override 15 | public String getUsername(Context ctx) { 16 | User u = User.getUserByUsername(ctx.session().get("username")); 17 | if (u != null && Boolean.TRUE.equals(u.active)) { 18 | return u.username; 19 | } 20 | else { 21 | return null; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/controllers/api/InvalidValueMixIn.java: -------------------------------------------------------------------------------- 1 | package controllers.api; 2 | 3 | import com.conveyal.gtfs.model.Priority; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | 6 | /** 7 | * Specify the annotations needed to construct an InvalidValue. This is a Jackson mixin so we don't need to 8 | * add a default constructor, etc. 9 | */ 10 | public abstract class InvalidValueMixIn { 11 | InvalidValueMixIn ( 12 | @JsonProperty("affectedEntity") String affectedEntity, 13 | @JsonProperty("affectedField") String affectedField, 14 | @JsonProperty("affectedEntityId") String affectedEntityId, 15 | @JsonProperty("problemType") String problemType, 16 | @JsonProperty("problemDescription") String problemDescription, 17 | @JsonProperty("problemData") Object problemData, 18 | @JsonProperty("priority") Priority priority 19 | ) {}; 20 | } 21 | -------------------------------------------------------------------------------- /app/controllers/api/Rectangle2DDeserializer.java: -------------------------------------------------------------------------------- 1 | package controllers.api; 2 | 3 | import java.awt.geom.Rectangle2D; 4 | import java.io.IOException; 5 | 6 | import com.fasterxml.jackson.core.JsonParseException; 7 | import com.fasterxml.jackson.core.JsonParser; 8 | import com.fasterxml.jackson.core.JsonProcessingException; 9 | import com.fasterxml.jackson.databind.DeserializationContext; 10 | import com.fasterxml.jackson.databind.JsonDeserializer; 11 | 12 | public class Rectangle2DDeserializer extends JsonDeserializer { 13 | 14 | @Override 15 | public Rectangle2D deserialize(JsonParser jp, DeserializationContext arg1) 16 | throws IOException, JsonProcessingException { 17 | 18 | IntermediateBoundingBox bbox = jp.readValueAs(IntermediateBoundingBox.class); 19 | 20 | if (bbox.north == null || bbox.south == null || bbox.east == null || bbox.west == null) 21 | throw new JsonParseException("Unable to deserialize bounding box; need north, south, east, and west.", jp.getCurrentLocation()); 22 | 23 | Rectangle2D.Double ret = new Rectangle2D.Double(bbox.west, bbox.north, 0, 0); 24 | ret.add(bbox.east, bbox.south); 25 | return ret; 26 | } 27 | 28 | /** 29 | * A place to hold information from the JSON stream temporarily. 30 | */ 31 | private static class IntermediateBoundingBox { 32 | public Double north; 33 | public Double south; 34 | public Double east; 35 | public Double west; 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /app/controllers/api/Rectangle2DMixIn.java: -------------------------------------------------------------------------------- 1 | package controllers.api; 2 | 3 | import com.fasterxml.jackson.annotation.JsonFilter; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | 6 | // ignore all by default 7 | @JsonFilter("bbox") 8 | public abstract class Rectangle2DMixIn { 9 | // stored as lon, lat 10 | @JsonProperty("west") public abstract double getMinX(); 11 | @JsonProperty("east") public abstract double getMaxX(); 12 | @JsonProperty("north") public abstract double getMaxY(); 13 | @JsonProperty("south") public abstract double getMinY(); 14 | } 15 | -------------------------------------------------------------------------------- /app/filters/NoCache.scala: -------------------------------------------------------------------------------- 1 | // add a no-cache header to every request so IE won't break 2 | // http://stackoverflow.com/questions/19307850 3 | 4 | package filters 5 | 6 | import play.api.mvc._ 7 | import scala.concurrent.Future 8 | import scala.concurrent.ExecutionContext.Implicits.global 9 | 10 | object NoCache extends Filter { 11 | def apply(f: (RequestHeader) => Future[Result])(rh: RequestHeader): Future[Result] = { 12 | val result = f(rh) 13 | result.map(_.withHeaders("Cache-Control" -> "no-cache")) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /app/jobs/FetchGtfsJob.java: -------------------------------------------------------------------------------- 1 | package jobs; 2 | 3 | import models.FeedSource; 4 | import models.FeedSource.FeedRetrievalMethod; 5 | import play.Logger; 6 | 7 | /** 8 | * Fetch all of the autofetched feeds that need to be fetched. 9 | * @author mattwigway 10 | * 11 | */ 12 | public class FetchGtfsJob implements Runnable { 13 | public void run () { 14 | Logger.info("Fetching GTFS feeds"); 15 | 16 | for (FeedSource source : FeedSource.getAll()) { 17 | if (!FeedRetrievalMethod.FETCHED_AUTOMATICALLY.equals(source.retrievalMethod)) 18 | continue; 19 | 20 | source.fetch(); 21 | } 22 | 23 | Logger.info("Done fetching GTFS feeds"); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /app/jobs/FetchProjectFeedsJob.java: -------------------------------------------------------------------------------- 1 | package jobs; 2 | 3 | import models.FeedCollection; 4 | import models.FeedSource; 5 | import models.FeedVersion; 6 | 7 | import java.util.HashMap; 8 | import java.util.Map; 9 | 10 | /** 11 | * Created by demory on 4/29/15. 12 | */ 13 | public class FetchProjectFeedsJob implements Runnable { 14 | 15 | private FeedCollection feedCollection; 16 | public Map result; 17 | 18 | public FetchProjectFeedsJob (FeedCollection feedCollection) { 19 | this.feedCollection = feedCollection; 20 | } 21 | 22 | @Override 23 | public void run() { 24 | result = new HashMap<>(); 25 | 26 | for(FeedSource feedSource : feedCollection.getFeedSources()) { 27 | if (!FeedSource.FeedRetrievalMethod.FETCHED_AUTOMATICALLY.equals(feedSource.retrievalMethod)) 28 | continue; 29 | 30 | FeedVersion feedVersion = feedSource.fetch(); 31 | result.put(feedSource.id, feedVersion); 32 | } 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /app/jobs/FetchSingleFeedJob.java: -------------------------------------------------------------------------------- 1 | package jobs; 2 | 3 | import models.FeedSource; 4 | import models.FeedVersion; 5 | 6 | public class FetchSingleFeedJob implements Runnable { 7 | 8 | private FeedSource feedSource; 9 | public FeedVersion result; 10 | 11 | public FetchSingleFeedJob (FeedSource feedSource) { 12 | this.feedSource = feedSource; 13 | this.result = null; 14 | } 15 | 16 | @Override 17 | public void run() { 18 | // TODO: fetch automatically vs. manually vs. in-house 19 | result = feedSource.fetch(); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /app/jobs/ProcessSingleFeedJob.java: -------------------------------------------------------------------------------- 1 | package jobs; 2 | 3 | import models.FeedVersion; 4 | 5 | /** 6 | * Process/validate a single GTFS feed 7 | * @author mattwigway 8 | * 9 | */ 10 | public class ProcessSingleFeedJob implements Runnable { 11 | FeedVersion feedVersion; 12 | 13 | /** 14 | * Create a job for the given feed version. 15 | * @param feedVersion 16 | */ 17 | public ProcessSingleFeedJob (FeedVersion feedVersion) { 18 | this.feedVersion = feedVersion; 19 | } 20 | 21 | public void run() { 22 | feedVersion.validate(); 23 | feedVersion.save(); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /app/jobs/RevalidateAllFeedVersionsJob.java: -------------------------------------------------------------------------------- 1 | package jobs; 2 | 3 | import models.FeedVersion; 4 | 5 | /** 6 | * Re-run the validator on every feed version. Useful when something about how the validator has changed. 7 | * Note that this will chew much time and CPU. 8 | * @author mattwigway 9 | * 10 | */ 11 | public class RevalidateAllFeedVersionsJob implements Runnable { 12 | 13 | // TODO: multithread? 14 | public void run() { 15 | for (FeedVersion v : FeedVersion.getAll()) { 16 | v.validate(); 17 | v.save(); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /app/models/AgencyBranding.java: -------------------------------------------------------------------------------- 1 | package models; 2 | 3 | import play.Play; 4 | 5 | import java.io.Serializable; 6 | 7 | /** 8 | * Created by demory on 4/3/15. 9 | */ 10 | 11 | public class AgencyBranding implements Serializable { 12 | private static final long serialVersionUID = 1L; 13 | 14 | public String agencyId; 15 | 16 | public Boolean hasLogo; 17 | 18 | public String urlRoot; 19 | 20 | // TODO: route-level branding 21 | 22 | public AgencyBranding(String agencyId) { 23 | this.agencyId = agencyId; 24 | urlRoot = Play.application().configuration().getString("application.data.branding_public"); 25 | } 26 | 27 | public AgencyBranding() { 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /app/models/JsonViews.java: -------------------------------------------------------------------------------- 1 | package models; 2 | 3 | /** 4 | * Defines all of the JSON views. 5 | * This is basically just a list. 6 | * @author mattwigway 7 | * 8 | */ 9 | public class JsonViews { 10 | /** 11 | * Data that is exposed to the UI via the API. 12 | */ 13 | public static class UserInterface {}; 14 | 15 | /** 16 | * Data that should be included in a database dump. 17 | */ 18 | public static class DataDump {}; 19 | } 20 | -------------------------------------------------------------------------------- /app/models/Note.java: -------------------------------------------------------------------------------- 1 | package models; 2 | 3 | import com.fasterxml.jackson.annotation.JsonInclude; 4 | import com.fasterxml.jackson.annotation.JsonInclude.Include; 5 | import utils.DataStore; 6 | 7 | import java.io.Serializable; 8 | import java.util.Collection; 9 | import java.util.Date; 10 | 11 | /** 12 | * A note about a particular model. 13 | * @author mattwigway 14 | * 15 | */ 16 | @JsonInclude(Include.ALWAYS) 17 | public class Note extends Model implements Serializable { 18 | private static final long serialVersionUID = 1L; 19 | 20 | private static DataStore noteStore = new DataStore("notes"); 21 | 22 | /** The content of the note */ 23 | public String note; 24 | 25 | /** What type of object it is recorded on */ 26 | public NoteType type; 27 | 28 | /** What is the ID of the object it is recorded on */ 29 | public String objectId; 30 | 31 | /** When was this comment made? */ 32 | public Date date; 33 | 34 | public void save () { 35 | save(true); 36 | } 37 | 38 | public void save (boolean commit) { 39 | if (commit) 40 | noteStore.save(id, this); 41 | else 42 | noteStore.saveWithoutCommit(id, this); 43 | } 44 | 45 | public static Note get (String id) { 46 | return noteStore.getById(id); 47 | } 48 | 49 | /** 50 | * The types of object that can have notes recorded on them. 51 | */ 52 | public static enum NoteType { 53 | FEED_VERSION, FEED_SOURCE; 54 | } 55 | 56 | public static Collection getAll() { 57 | return noteStore.getAll(); 58 | } 59 | 60 | public static void commit() { 61 | noteStore.commit(); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /app/models/OtpBuildConfig.java: -------------------------------------------------------------------------------- 1 | package models; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * Created by demory on 3/8/15. 7 | */ 8 | 9 | public class OtpBuildConfig implements Serializable { 10 | private static final long serialVersionUID = 1L; 11 | 12 | public Boolean fetchElevationUS; 13 | 14 | public Boolean stationTransfers; 15 | 16 | public Double subwayAccessTime; 17 | 18 | /** Currently only supports no-configuration fares, e.g. New York or San Francisco */ 19 | public String fares; 20 | } 21 | -------------------------------------------------------------------------------- /app/models/OtpRouterConfig.java: -------------------------------------------------------------------------------- 1 | package models; 2 | 3 | import com.fasterxml.jackson.annotation.JsonInclude; 4 | 5 | import java.io.Serializable; 6 | import java.util.Collection; 7 | 8 | /** 9 | * Created by demory on 3/8/15. 10 | */ 11 | 12 | public class OtpRouterConfig implements Serializable { 13 | 14 | public Integer numItineraries; 15 | 16 | public Double walkSpeed; 17 | 18 | public Double stairsReluctance; 19 | 20 | public Double carDropoffTime; 21 | 22 | public Collection updaters; 23 | 24 | public static class Updater implements Serializable { 25 | 26 | public String type; 27 | 28 | public Integer frequencySec; 29 | 30 | public String sourceType; 31 | 32 | public String url; 33 | 34 | public String defaultAgencyId; 35 | } 36 | 37 | public String brandingUrlRoot; 38 | } 39 | -------------------------------------------------------------------------------- /app/utils/ClassLoaderSerializer.java: -------------------------------------------------------------------------------- 1 | package utils; 2 | 3 | import org.apache.commons.io.input.ClassLoaderObjectInputStream; 4 | import org.mapdb.Serializer; 5 | 6 | import java.io.*; 7 | 8 | /** 9 | * Deserialize using the thread's class loader, not the root class loader. 10 | */ 11 | public class ClassLoaderSerializer implements Serializer, Serializable { 12 | private static final long serialVersionUID = 1L; 13 | 14 | @Override 15 | public void serialize(DataOutput out, Object value) throws IOException { 16 | ObjectOutputStream out2 = new ObjectOutputStream((OutputStream) out); 17 | out2.writeObject(value); 18 | out2.flush(); 19 | } 20 | 21 | @Override 22 | public Object deserialize(DataInput in, int available) throws IOException { 23 | try { 24 | ObjectInputStream in2 = new ClassLoaderObjectInputStream(Thread.currentThread().getContextClassLoader(), (InputStream) in); 25 | return in2.readObject(); 26 | } catch (ClassNotFoundException e) { 27 | throw new IOException(e); 28 | } 29 | } 30 | 31 | @Override 32 | public int fixedSize() { 33 | return -1; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /app/utils/FeedStore.java: -------------------------------------------------------------------------------- 1 | package utils; 2 | 3 | import java.io.File; 4 | import java.util.ArrayList; 5 | import java.util.List; 6 | import java.util.UUID; 7 | 8 | /** 9 | * Store a feed on the file system 10 | * @author mattwigway 11 | * 12 | */ 13 | public class FeedStore { 14 | private File path; 15 | 16 | public FeedStore(File path) { 17 | if (!path.exists() || !path.isDirectory()) { 18 | throw new IllegalArgumentException("Not a directory or not found: " + path.getAbsolutePath()); 19 | } 20 | 21 | this.path = path; 22 | } 23 | 24 | public FeedStore(String path) { 25 | this(new File(path)); 26 | } 27 | 28 | public List getAllFeeds () { 29 | ArrayList ret = new ArrayList(); 30 | for (File file : path.listFiles()) { 31 | ret.add(file.getName()); 32 | } 33 | return ret; 34 | } 35 | 36 | /** 37 | * Get the feed with the given ID. 38 | */ 39 | public File getFeed (String id) { 40 | File feed = new File(path, id); 41 | if (!feed.exists()) return null; 42 | // don't let folks get feeds outside of the directory 43 | if (!feed.getParentFile().equals(path)) return null; 44 | else return feed; 45 | } 46 | 47 | /** 48 | * Create a new feed with the given ID. 49 | */ 50 | public File newFeed (String id) { 51 | return new File(path, id); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /app/utils/HashUtils.java: -------------------------------------------------------------------------------- 1 | package utils; 2 | 3 | import org.apache.commons.codec.binary.Hex; 4 | import org.apache.commons.codec.digest.DigestUtils; 5 | import org.apache.commons.io.FileUtils; 6 | 7 | import java.io.File; 8 | import java.io.FileInputStream; 9 | import java.nio.ByteBuffer; 10 | import java.security.DigestInputStream; 11 | import java.security.MessageDigest; 12 | 13 | public class HashUtils { 14 | 15 | public static String hashString(String input) { 16 | 17 | try { 18 | 19 | byte[] bytesOfMessage = input.getBytes("UTF-8"); 20 | 21 | return DigestUtils.md5Hex(bytesOfMessage); 22 | 23 | } 24 | catch(Exception e) { 25 | 26 | return ""; 27 | } 28 | } 29 | 30 | 31 | public static String hashFile(File file) { 32 | 33 | try { 34 | 35 | return "" + FileUtils.checksumCRC32(file); 36 | 37 | } 38 | catch(Exception e) { 39 | 40 | return ""; 41 | } 42 | } 43 | 44 | } 45 | 46 | -------------------------------------------------------------------------------- /app/utils/StringUtils.java: -------------------------------------------------------------------------------- 1 | package utils; 2 | 3 | public class StringUtils { 4 | /** 5 | * Clean a name to make it filesystem-friendly 6 | * @param name a name with any letters 7 | * @return a new name with weird letters removed/transliterated. 8 | */ 9 | public static String getCleanName (String name) { 10 | return name.replace(' ', '_').replaceAll("[^A-Za-z0-9_-]", ""); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /app/views/Public/index.scala.html: -------------------------------------------------------------------------------- 1 | @(versions: List[FeedVersion], feedVersionFileNames: Map[String, String]) 2 | 3 | 4 | 5 | @Messages("public.title") 6 | 7 | 11 | 12 | 13 |

@Messages("public.title")

14 | 15 | @Messages("public.description") 16 | 17 |
    18 | @for(v <- versions) { 19 | @if(v.getFeedSource().retrievalMethod == models.FeedSource.FeedRetrievalMethod.FETCHED_AUTOMATICALLY) { 20 |
  • @v.getFeedSource().name ( 21 | @if(v.getFeedSource().lastFetched != null) { 22 | @Messages("public.last-checked", v.getFeedSource().lastFetched.format("dd MMM YYYY")), 23 | } 24 | @Messages("public.last-updated", v.updated.format("dd MMM YYYY")) 25 | )
  • 26 | } else { 27 | @* date is only shown on feeds we are hosting *@ 28 |
  • @v.getFeedSource().name (@Messages("public.last-updated", v.updated.format("dd MMM YYYY")))
  • 29 | } 30 | } 31 |
32 | 33 | 34 | -------------------------------------------------------------------------------- /app/views/index.scala.html: -------------------------------------------------------------------------------- 1 | @(message: String) 2 | 3 | @main("Welcome to Play") { 4 | 5 | @play20.welcome(message, style = "Java") 6 | 7 | } 8 | -------------------------------------------------------------------------------- /app/views/main.scala.html: -------------------------------------------------------------------------------- 1 | @(title: String)(content: Html) 2 | 3 | 4 | 5 | 6 | 7 | @title 8 | 9 | 10 | 11 | 12 | 13 | @content 14 | 15 | 16 | -------------------------------------------------------------------------------- /build.sbt: -------------------------------------------------------------------------------- 1 | import com.typesafe.sbt.SbtNativePackager._ 2 | import com.typesafe.sbt.packager.archetypes.ServerLoader 3 | import NativePackagerKeys._ 4 | 5 | name := """gtfs-data-manager""" 6 | 7 | version := "0.3.4" 8 | 9 | serverLoading in Rpm := ServerLoader.SystemV 10 | 11 | serverLoading in Debian := ServerLoader.SystemV 12 | 13 | maintainer in Linux := "Matthew Wigginton Conway " 14 | 15 | packageSummary in Linux := "GTFS Data Manager" 16 | 17 | packageDescription := "GTFS Data Manager" 18 | 19 | rpmRelease := "1" 20 | 21 | rpmVendor := "conveyal.com" 22 | 23 | rpmUrl := Some("http://github.com/conveyal/gtfs-data-manager") 24 | 25 | rpmLicense := Some("MIT") 26 | 27 | lazy val root = (project in file(".")).enablePlugins(PlayJava) 28 | 29 | scalaVersion := "2.11.1" 30 | 31 | libraryDependencies ++= Seq( 32 | javaJdbc, 33 | javaEbean, 34 | cache, 35 | javaWs, 36 | "org.mapdb" % "mapdb" % "1.0.6", 37 | "org.julienrf" %% "play-jsmessages" % "1.6.2", 38 | "com.google.guava" % "guava" % "18.0", 39 | "com.amazonaws" % "aws-java-sdk-s3" % "1.9.3", 40 | "commons-io" % "commons-io" % "2.4", 41 | "net.sourceforge.javacsv" % "javacsv" % "2.0", 42 | "com.conveyal" % "gtfs-validator-json" % "0.0.1-SNAPSHOT" exclude("org.slf4j", "slf4j-simple") 43 | ) 44 | 45 | resolvers += "Local Maven Repository" at "file://"+Path.userHome.absolutePath+"/.m2/repository" 46 | resolvers += "Conveyal Maven Repository" at "http://maven.conveyal.com" 47 | resolvers += "Geotoolkit Maven Repository" at "http://maven.geotoolkit.org" 48 | resolvers += "OSGeo" at "http://download.osgeo.org/webdav/geotools/" 49 | -------------------------------------------------------------------------------- /migrations/addCustomBoundsToCollection.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Default feed collections to not using custom bounds 3 | */ 4 | 5 | var fs = require('fs'); 6 | 7 | var dump = JSON.parse(fs.readFileSync(process.argv[process.argv.length - 2])); 8 | 9 | dump.feedCollections.forEach(function (fc) { 10 | fc.useCustomOsmBounds = false; 11 | }); 12 | 13 | fs.writeFileSync(process.argv[process.argv.length - 1], JSON.stringify(dump)); 14 | -------------------------------------------------------------------------------- /migrations/addEditorId.js: -------------------------------------------------------------------------------- 1 | // Add the GTFS Data Manager ID to a dump, extracting the ID from the existing file 2 | 3 | var fs = require('fs'); 4 | 5 | var dump = JSON.parse(fs.readFileSync(process.argv[process.argv.length - 2])); 6 | 7 | dump.feedSources.forEach(function (source) { 8 | if (source.retrievalMethod == 'PRODUCED_IN_HOUSE' && source.url !== null) { 9 | var id = /agencySelect=([0-9]+)/.exec(source.url)[1]; 10 | id = Number(id); 11 | source.url = null; 12 | source.editorId = id; 13 | } else { 14 | source.editorId = null; 15 | } 16 | }); 17 | 18 | // bounds should not be included in deployments, since they are calculated on the fly 19 | // but there was a bug before this migration was created that caused them to be, and then the files would fail 20 | // reserialization. So we drop the field 21 | dump.deployments.forEach(function (d) { 22 | if (d.bounds !== undefined) 23 | delete d.bounds; 24 | }); 25 | 26 | fs.writeFileSync(process.argv[process.argv.length - 1], JSON.stringify(dump)); 27 | -------------------------------------------------------------------------------- /migrations/patchNoteIds.js: -------------------------------------------------------------------------------- 1 | // Patch up the note IDs 2 | // At one point, the dumper was not saving the reference from feed sources and feed version to notes, although 3 | // the reverse was there. Reconstruct the lost data. 4 | 5 | var fs = require('fs'); 6 | var dump = JSON.parse(fs.readFileSync(process.argv[process.argv.length - 2])); 7 | 8 | // index feedsources and feedversions 9 | var fsIdx = {}; 10 | 11 | dump.feedSources.forEach(function (fs, i) { 12 | fsIdx[fs.id] = i; 13 | }); 14 | 15 | var fvIdx = {}; 16 | 17 | dump.feedVersions.forEach(function (fv, i) { 18 | fvIdx[fv.id] = i; 19 | }); 20 | 21 | dump.notes.forEach(function (note) { 22 | var target; 23 | if (note.type == "FEED_SOURCE") { 24 | target = dump.feedSources[fsIdx[note.objectId]]; 25 | } else if (note.type == "FEED_VERSION") { 26 | target = dump.feedVersions[fvIdx[note.objectId]]; 27 | } 28 | // also types were not getting stored, so reconstruct that as well. 29 | // there is no chance of id collision as format is different. 30 | else if (fsIdx[note.objectId] !== undefined) { 31 | target = dump.feedSources[fsIdx[note.objectId]]; 32 | } else if (fvIdx[note.objectId] !== undefined) { 33 | target = dump.feedVersions[fvIdx[note.objectId]]; 34 | } else { 35 | console.log("Cannot find object to attach note to: ", note); 36 | return; 37 | } 38 | 39 | if (target.noteIds === undefined || target.noteIds === null) 40 | target.noteIds = []; 41 | 42 | target.noteIds.push(note.id); 43 | }); 44 | 45 | fs.writeFileSync(process.argv[process.argv.length - 1], JSON.stringify(dump)); 46 | -------------------------------------------------------------------------------- /migrations/removeInvalidDeployments.js: -------------------------------------------------------------------------------- 1 | /* 2 | * There was a bug where deployments could be created from invalid versions. Delete these deployments. 3 | */ 4 | 5 | var fs = require('fs'); 6 | 7 | var dump = JSON.parse(fs.readFileSync(process.argv[process.argv.length - 2])); 8 | 9 | var before = dump.deployments.length; 10 | 11 | dump.deployments = dump.deployments.filter(function (deployment) { 12 | return deployment.feedVersionIds.indexOf(null) === -1; 13 | }); 14 | 15 | var after = dump.deployments.length; 16 | 17 | console.log("Removed " + (before - after) + " invalid deployments"); 18 | 19 | fs.writeFileSync(process.argv[process.argv.length - 1], JSON.stringify(dump)); 20 | -------------------------------------------------------------------------------- /migrations/removePreviousNextIds.js: -------------------------------------------------------------------------------- 1 | // We used to store feed versions as a linked list, but the updates got messy, so now we use an index on version. 2 | 3 | var fs = require('fs'); 4 | 5 | var dump = JSON.parse(fs.readFileSync(process.argv[process.argv.length - 2])); 6 | 7 | dump.feedVersions.forEach(function (fv) { 8 | fv.previousVersionId = fv.nextVersionId = undefined; 9 | }); 10 | 11 | fs.writeFileSync(process.argv[process.argv.length - 1], JSON.stringify(dump)); 12 | -------------------------------------------------------------------------------- /migrations/splitIsPublic.js: -------------------------------------------------------------------------------- 1 | /** 2 | * make isPublic the deployable tag, and create a new isPublic tag and initialize it to false. 3 | */ 4 | 5 | var fs = require('fs'); 6 | 7 | var dump = JSON.parse(fs.readFileSync(process.argv[process.argv.length - 2])); 8 | 9 | dump.feedSources.forEach(function (feedSource) { 10 | feedSource.deployable = feedSource.isPublic; 11 | // default false 12 | feedSource.isPublic = false; 13 | }); 14 | 15 | fs.writeFileSync(process.argv[process.argv.length - 1], JSON.stringify(dump)); 16 | -------------------------------------------------------------------------------- /project/build.properties: -------------------------------------------------------------------------------- 1 | #Activator-generated Properties 2 | #Fri Oct 10 13:31:38 EDT 2014 3 | template.uuid=a4c33fda-0fa0-458b-a153-0a28c61df830 4 | sbt.version=0.13.8 5 | -------------------------------------------------------------------------------- /project/plugins.sbt: -------------------------------------------------------------------------------- 1 | resolvers += "Typesafe repository" at "http://repo.typesafe.com/typesafe/releases/" 2 | 3 | // The Play plugin 4 | addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.3.8") 5 | 6 | // web plugins 7 | 8 | addSbtPlugin("com.typesafe.sbt" % "sbt-coffeescript" % "1.0.0") 9 | 10 | addSbtPlugin("com.typesafe.sbt" % "sbt-less" % "1.0.0") 11 | 12 | addSbtPlugin("com.typesafe.sbt" % "sbt-jshint" % "1.0.1") 13 | 14 | addSbtPlugin("com.typesafe.sbt" % "sbt-rjs" % "1.0.1") 15 | 16 | addSbtPlugin("com.typesafe.sbt" % "sbt-digest" % "1.0.0") 17 | 18 | addSbtPlugin("com.typesafe.sbt" % "sbt-mocha" % "1.0.0") 19 | -------------------------------------------------------------------------------- /public/build/components/bootstrap/3.3.2/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conveyal/gtfs-data-manager/e7269fc1660f1816da269b1c116b43bdf758900b/public/build/components/bootstrap/3.3.2/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /public/build/components/bootstrap/3.3.2/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conveyal/gtfs-data-manager/e7269fc1660f1816da269b1c116b43bdf758900b/public/build/components/bootstrap/3.3.2/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /public/build/components/bootstrap/3.3.2/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conveyal/gtfs-data-manager/e7269fc1660f1816da269b1c116b43bdf758900b/public/build/components/bootstrap/3.3.2/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /public/build/components/bootstrap/3.3.2/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conveyal/gtfs-data-manager/e7269fc1660f1816da269b1c116b43bdf758900b/public/build/components/bootstrap/3.3.2/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /public/build/kpwebb/select2/3.4.8/select2-spinner.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conveyal/gtfs-data-manager/e7269fc1660f1816da269b1c116b43bdf758900b/public/build/kpwebb/select2/3.4.8/select2-spinner.gif -------------------------------------------------------------------------------- /public/build/kpwebb/select2/3.4.8/select2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conveyal/gtfs-data-manager/e7269fc1660f1816da269b1c116b43bdf758900b/public/build/kpwebb/select2/3.4.8/select2.png -------------------------------------------------------------------------------- /public/build/kpwebb/select2/3.4.8/select2x2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conveyal/gtfs-data-manager/e7269fc1660f1816da269b1c116b43bdf758900b/public/build/kpwebb/select2/3.4.8/select2x2.png -------------------------------------------------------------------------------- /public/build/moment/moment/2.8.3/locale/ar-ma.js: -------------------------------------------------------------------------------- 1 | // moment.js locale configuration 2 | // locale : Moroccan Arabic (ar-ma) 3 | // author : ElFadili Yassine : https://github.com/ElFadiliY 4 | // author : Abdel Said : https://github.com/abdelsaid 5 | 6 | (function (factory) { 7 | if (typeof define === 'function' && define.amd) { 8 | define(['moment'], factory); // AMD 9 | } else if (typeof exports === 'object') { 10 | module.exports = factory(require('../moment')); // Node 11 | } else { 12 | factory(window.moment); // Browser global 13 | } 14 | }(function (moment) { 15 | return moment.defineLocale('ar-ma', { 16 | months : 'يناير_فبراير_مارس_أبريل_ماي_يونيو_يوليوز_غشت_شتنبر_أكتوبر_نونبر_دجنبر'.split('_'), 17 | monthsShort : 'يناير_فبراير_مارس_أبريل_ماي_يونيو_يوليوز_غشت_شتنبر_أكتوبر_نونبر_دجنبر'.split('_'), 18 | weekdays : 'الأحد_الإتنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت'.split('_'), 19 | weekdaysShort : 'احد_اتنين_ثلاثاء_اربعاء_خميس_جمعة_سبت'.split('_'), 20 | weekdaysMin : 'ح_ن_ث_ر_خ_ج_س'.split('_'), 21 | longDateFormat : { 22 | LT : 'HH:mm', 23 | L : 'DD/MM/YYYY', 24 | LL : 'D MMMM YYYY', 25 | LLL : 'D MMMM YYYY LT', 26 | LLLL : 'dddd D MMMM YYYY LT' 27 | }, 28 | calendar : { 29 | sameDay: '[اليوم على الساعة] LT', 30 | nextDay: '[غدا على الساعة] LT', 31 | nextWeek: 'dddd [على الساعة] LT', 32 | lastDay: '[أمس على الساعة] LT', 33 | lastWeek: 'dddd [على الساعة] LT', 34 | sameElse: 'L' 35 | }, 36 | relativeTime : { 37 | future : 'في %s', 38 | past : 'منذ %s', 39 | s : 'ثوان', 40 | m : 'دقيقة', 41 | mm : '%d دقائق', 42 | h : 'ساعة', 43 | hh : '%d ساعات', 44 | d : 'يوم', 45 | dd : '%d أيام', 46 | M : 'شهر', 47 | MM : '%d أشهر', 48 | y : 'سنة', 49 | yy : '%d سنوات' 50 | }, 51 | week : { 52 | dow : 6, // Saturday is the first day of the week. 53 | doy : 12 // The week that contains Jan 1st is the first week of the year. 54 | } 55 | }); 56 | })); 57 | -------------------------------------------------------------------------------- /public/build/moment/moment/2.8.3/locale/cv.js: -------------------------------------------------------------------------------- 1 | // moment.js locale configuration 2 | // locale : chuvash (cv) 3 | // author : Anatoly Mironov : https://github.com/mirontoli 4 | 5 | (function (factory) { 6 | if (typeof define === 'function' && define.amd) { 7 | define(['moment'], factory); // AMD 8 | } else if (typeof exports === 'object') { 9 | module.exports = factory(require('../moment')); // Node 10 | } else { 11 | factory(window.moment); // Browser global 12 | } 13 | }(function (moment) { 14 | return moment.defineLocale('cv', { 15 | months : 'кăрлач_нарăс_пуш_ака_май_çĕртме_утă_çурла_авăн_юпа_чӳк_раштав'.split('_'), 16 | monthsShort : 'кăр_нар_пуш_ака_май_çĕр_утă_çур_ав_юпа_чӳк_раш'.split('_'), 17 | weekdays : 'вырсарникун_тунтикун_ытларикун_юнкун_кĕçнерникун_эрнекун_шăматкун'.split('_'), 18 | weekdaysShort : 'выр_тун_ытл_юн_кĕç_эрн_шăм'.split('_'), 19 | weekdaysMin : 'вр_тн_ыт_юн_кç_эр_шм'.split('_'), 20 | longDateFormat : { 21 | LT : 'HH:mm', 22 | L : 'DD-MM-YYYY', 23 | LL : 'YYYY [çулхи] MMMM [уйăхĕн] D[-мĕшĕ]', 24 | LLL : 'YYYY [çулхи] MMMM [уйăхĕн] D[-мĕшĕ], LT', 25 | LLLL : 'dddd, YYYY [çулхи] MMMM [уйăхĕн] D[-мĕшĕ], LT' 26 | }, 27 | calendar : { 28 | sameDay: '[Паян] LT [сехетре]', 29 | nextDay: '[Ыран] LT [сехетре]', 30 | lastDay: '[Ĕнер] LT [сехетре]', 31 | nextWeek: '[Çитес] dddd LT [сехетре]', 32 | lastWeek: '[Иртнĕ] dddd LT [сехетре]', 33 | sameElse: 'L' 34 | }, 35 | relativeTime : { 36 | future : function (output) { 37 | var affix = /сехет$/i.exec(output) ? 'рен' : /çул$/i.exec(output) ? 'тан' : 'ран'; 38 | return output + affix; 39 | }, 40 | past : '%s каялла', 41 | s : 'пĕр-ик çеккунт', 42 | m : 'пĕр минут', 43 | mm : '%d минут', 44 | h : 'пĕр сехет', 45 | hh : '%d сехет', 46 | d : 'пĕр кун', 47 | dd : '%d кун', 48 | M : 'пĕр уйăх', 49 | MM : '%d уйăх', 50 | y : 'пĕр çул', 51 | yy : '%d çул' 52 | }, 53 | ordinal : '%d-мĕш', 54 | week : { 55 | dow : 1, // Monday is the first day of the week. 56 | doy : 7 // The week that contains Jan 1st is the first week of the year. 57 | } 58 | }); 59 | })); 60 | -------------------------------------------------------------------------------- /public/build/moment/moment/2.8.3/locale/da.js: -------------------------------------------------------------------------------- 1 | // moment.js locale configuration 2 | // locale : danish (da) 3 | // author : Ulrik Nielsen : https://github.com/mrbase 4 | 5 | (function (factory) { 6 | if (typeof define === 'function' && define.amd) { 7 | define(['moment'], factory); // AMD 8 | } else if (typeof exports === 'object') { 9 | module.exports = factory(require('../moment')); // Node 10 | } else { 11 | factory(window.moment); // Browser global 12 | } 13 | }(function (moment) { 14 | return moment.defineLocale('da', { 15 | months : 'januar_februar_marts_april_maj_juni_juli_august_september_oktober_november_december'.split('_'), 16 | monthsShort : 'jan_feb_mar_apr_maj_jun_jul_aug_sep_okt_nov_dec'.split('_'), 17 | weekdays : 'søndag_mandag_tirsdag_onsdag_torsdag_fredag_lørdag'.split('_'), 18 | weekdaysShort : 'søn_man_tir_ons_tor_fre_lør'.split('_'), 19 | weekdaysMin : 'sø_ma_ti_on_to_fr_lø'.split('_'), 20 | longDateFormat : { 21 | LT : 'HH:mm', 22 | L : 'DD/MM/YYYY', 23 | LL : 'D. MMMM YYYY', 24 | LLL : 'D. MMMM YYYY LT', 25 | LLLL : 'dddd [d.] D. MMMM YYYY LT' 26 | }, 27 | calendar : { 28 | sameDay : '[I dag kl.] LT', 29 | nextDay : '[I morgen kl.] LT', 30 | nextWeek : 'dddd [kl.] LT', 31 | lastDay : '[I går kl.] LT', 32 | lastWeek : '[sidste] dddd [kl] LT', 33 | sameElse : 'L' 34 | }, 35 | relativeTime : { 36 | future : 'om %s', 37 | past : '%s siden', 38 | s : 'få sekunder', 39 | m : 'et minut', 40 | mm : '%d minutter', 41 | h : 'en time', 42 | hh : '%d timer', 43 | d : 'en dag', 44 | dd : '%d dage', 45 | M : 'en måned', 46 | MM : '%d måneder', 47 | y : 'et år', 48 | yy : '%d år' 49 | }, 50 | ordinal : '%d.', 51 | week : { 52 | dow : 1, // Monday is the first day of the week. 53 | doy : 4 // The week that contains Jan 4th is the first week of the year. 54 | } 55 | }); 56 | })); 57 | -------------------------------------------------------------------------------- /public/build/moment/moment/2.8.3/locale/en-au.js: -------------------------------------------------------------------------------- 1 | // moment.js locale configuration 2 | // locale : australian english (en-au) 3 | 4 | (function (factory) { 5 | if (typeof define === 'function' && define.amd) { 6 | define(['moment'], factory); // AMD 7 | } else if (typeof exports === 'object') { 8 | module.exports = factory(require('../moment')); // Node 9 | } else { 10 | factory(window.moment); // Browser global 11 | } 12 | }(function (moment) { 13 | return moment.defineLocale('en-au', { 14 | months : 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_'), 15 | monthsShort : 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'), 16 | weekdays : 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_'), 17 | weekdaysShort : 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'), 18 | weekdaysMin : 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'), 19 | longDateFormat : { 20 | LT : 'h:mm A', 21 | L : 'DD/MM/YYYY', 22 | LL : 'D MMMM YYYY', 23 | LLL : 'D MMMM YYYY LT', 24 | LLLL : 'dddd, D MMMM YYYY LT' 25 | }, 26 | calendar : { 27 | sameDay : '[Today at] LT', 28 | nextDay : '[Tomorrow at] LT', 29 | nextWeek : 'dddd [at] LT', 30 | lastDay : '[Yesterday at] LT', 31 | lastWeek : '[Last] dddd [at] LT', 32 | sameElse : 'L' 33 | }, 34 | relativeTime : { 35 | future : 'in %s', 36 | past : '%s ago', 37 | s : 'a few seconds', 38 | m : 'a minute', 39 | mm : '%d minutes', 40 | h : 'an hour', 41 | hh : '%d hours', 42 | d : 'a day', 43 | dd : '%d days', 44 | M : 'a month', 45 | MM : '%d months', 46 | y : 'a year', 47 | yy : '%d years' 48 | }, 49 | ordinal : function (number) { 50 | var b = number % 10, 51 | output = (~~(number % 100 / 10) === 1) ? 'th' : 52 | (b === 1) ? 'st' : 53 | (b === 2) ? 'nd' : 54 | (b === 3) ? 'rd' : 'th'; 55 | return number + output; 56 | }, 57 | week : { 58 | dow : 1, // Monday is the first day of the week. 59 | doy : 4 // The week that contains Jan 4th is the first week of the year. 60 | } 61 | }); 62 | })); 63 | -------------------------------------------------------------------------------- /public/build/moment/moment/2.8.3/locale/en-ca.js: -------------------------------------------------------------------------------- 1 | // moment.js locale configuration 2 | // locale : canadian english (en-ca) 3 | // author : Jonathan Abourbih : https://github.com/jonbca 4 | 5 | (function (factory) { 6 | if (typeof define === 'function' && define.amd) { 7 | define(['moment'], factory); // AMD 8 | } else if (typeof exports === 'object') { 9 | module.exports = factory(require('../moment')); // Node 10 | } else { 11 | factory(window.moment); // Browser global 12 | } 13 | }(function (moment) { 14 | return moment.defineLocale('en-ca', { 15 | months : 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_'), 16 | monthsShort : 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'), 17 | weekdays : 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_'), 18 | weekdaysShort : 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'), 19 | weekdaysMin : 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'), 20 | longDateFormat : { 21 | LT : 'h:mm A', 22 | L : 'YYYY-MM-DD', 23 | LL : 'D MMMM, YYYY', 24 | LLL : 'D MMMM, YYYY LT', 25 | LLLL : 'dddd, D MMMM, YYYY LT' 26 | }, 27 | calendar : { 28 | sameDay : '[Today at] LT', 29 | nextDay : '[Tomorrow at] LT', 30 | nextWeek : 'dddd [at] LT', 31 | lastDay : '[Yesterday at] LT', 32 | lastWeek : '[Last] dddd [at] LT', 33 | sameElse : 'L' 34 | }, 35 | relativeTime : { 36 | future : 'in %s', 37 | past : '%s ago', 38 | s : 'a few seconds', 39 | m : 'a minute', 40 | mm : '%d minutes', 41 | h : 'an hour', 42 | hh : '%d hours', 43 | d : 'a day', 44 | dd : '%d days', 45 | M : 'a month', 46 | MM : '%d months', 47 | y : 'a year', 48 | yy : '%d years' 49 | }, 50 | ordinal : function (number) { 51 | var b = number % 10, 52 | output = (~~(number % 100 / 10) === 1) ? 'th' : 53 | (b === 1) ? 'st' : 54 | (b === 2) ? 'nd' : 55 | (b === 3) ? 'rd' : 'th'; 56 | return number + output; 57 | } 58 | }); 59 | })); 60 | -------------------------------------------------------------------------------- /public/build/moment/moment/2.8.3/locale/en-gb.js: -------------------------------------------------------------------------------- 1 | // moment.js locale configuration 2 | // locale : great britain english (en-gb) 3 | // author : Chris Gedrim : https://github.com/chrisgedrim 4 | 5 | (function (factory) { 6 | if (typeof define === 'function' && define.amd) { 7 | define(['moment'], factory); // AMD 8 | } else if (typeof exports === 'object') { 9 | module.exports = factory(require('../moment')); // Node 10 | } else { 11 | factory(window.moment); // Browser global 12 | } 13 | }(function (moment) { 14 | return moment.defineLocale('en-gb', { 15 | months : 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_'), 16 | monthsShort : 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'), 17 | weekdays : 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_'), 18 | weekdaysShort : 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'), 19 | weekdaysMin : 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'), 20 | longDateFormat : { 21 | LT : 'HH:mm', 22 | L : 'DD/MM/YYYY', 23 | LL : 'D MMMM YYYY', 24 | LLL : 'D MMMM YYYY LT', 25 | LLLL : 'dddd, D MMMM YYYY LT' 26 | }, 27 | calendar : { 28 | sameDay : '[Today at] LT', 29 | nextDay : '[Tomorrow at] LT', 30 | nextWeek : 'dddd [at] LT', 31 | lastDay : '[Yesterday at] LT', 32 | lastWeek : '[Last] dddd [at] LT', 33 | sameElse : 'L' 34 | }, 35 | relativeTime : { 36 | future : 'in %s', 37 | past : '%s ago', 38 | s : 'a few seconds', 39 | m : 'a minute', 40 | mm : '%d minutes', 41 | h : 'an hour', 42 | hh : '%d hours', 43 | d : 'a day', 44 | dd : '%d days', 45 | M : 'a month', 46 | MM : '%d months', 47 | y : 'a year', 48 | yy : '%d years' 49 | }, 50 | ordinal : function (number) { 51 | var b = number % 10, 52 | output = (~~(number % 100 / 10) === 1) ? 'th' : 53 | (b === 1) ? 'st' : 54 | (b === 2) ? 'nd' : 55 | (b === 3) ? 'rd' : 'th'; 56 | return number + output; 57 | }, 58 | week : { 59 | dow : 1, // Monday is the first day of the week. 60 | doy : 4 // The week that contains Jan 4th is the first week of the year. 61 | } 62 | }); 63 | })); 64 | -------------------------------------------------------------------------------- /public/build/moment/moment/2.8.3/locale/eu.js: -------------------------------------------------------------------------------- 1 | // moment.js locale configuration 2 | // locale : euskara (eu) 3 | // author : Eneko Illarramendi : https://github.com/eillarra 4 | 5 | (function (factory) { 6 | if (typeof define === 'function' && define.amd) { 7 | define(['moment'], factory); // AMD 8 | } else if (typeof exports === 'object') { 9 | module.exports = factory(require('../moment')); // Node 10 | } else { 11 | factory(window.moment); // Browser global 12 | } 13 | }(function (moment) { 14 | return moment.defineLocale('eu', { 15 | months : 'urtarrila_otsaila_martxoa_apirila_maiatza_ekaina_uztaila_abuztua_iraila_urria_azaroa_abendua'.split('_'), 16 | monthsShort : 'urt._ots._mar._api._mai._eka._uzt._abu._ira._urr._aza._abe.'.split('_'), 17 | weekdays : 'igandea_astelehena_asteartea_asteazkena_osteguna_ostirala_larunbata'.split('_'), 18 | weekdaysShort : 'ig._al._ar._az._og._ol._lr.'.split('_'), 19 | weekdaysMin : 'ig_al_ar_az_og_ol_lr'.split('_'), 20 | longDateFormat : { 21 | LT : 'HH:mm', 22 | L : 'YYYY-MM-DD', 23 | LL : 'YYYY[ko] MMMM[ren] D[a]', 24 | LLL : 'YYYY[ko] MMMM[ren] D[a] LT', 25 | LLLL : 'dddd, YYYY[ko] MMMM[ren] D[a] LT', 26 | l : 'YYYY-M-D', 27 | ll : 'YYYY[ko] MMM D[a]', 28 | lll : 'YYYY[ko] MMM D[a] LT', 29 | llll : 'ddd, YYYY[ko] MMM D[a] LT' 30 | }, 31 | calendar : { 32 | sameDay : '[gaur] LT[etan]', 33 | nextDay : '[bihar] LT[etan]', 34 | nextWeek : 'dddd LT[etan]', 35 | lastDay : '[atzo] LT[etan]', 36 | lastWeek : '[aurreko] dddd LT[etan]', 37 | sameElse : 'L' 38 | }, 39 | relativeTime : { 40 | future : '%s barru', 41 | past : 'duela %s', 42 | s : 'segundo batzuk', 43 | m : 'minutu bat', 44 | mm : '%d minutu', 45 | h : 'ordu bat', 46 | hh : '%d ordu', 47 | d : 'egun bat', 48 | dd : '%d egun', 49 | M : 'hilabete bat', 50 | MM : '%d hilabete', 51 | y : 'urte bat', 52 | yy : '%d urte' 53 | }, 54 | ordinal : '%d.', 55 | week : { 56 | dow : 1, // Monday is the first day of the week. 57 | doy : 7 // The week that contains Jan 1st is the first week of the year. 58 | } 59 | }); 60 | })); 61 | -------------------------------------------------------------------------------- /public/build/moment/moment/2.8.3/locale/fo.js: -------------------------------------------------------------------------------- 1 | // moment.js locale configuration 2 | // locale : faroese (fo) 3 | // author : Ragnar Johannesen : https://github.com/ragnar123 4 | 5 | (function (factory) { 6 | if (typeof define === 'function' && define.amd) { 7 | define(['moment'], factory); // AMD 8 | } else if (typeof exports === 'object') { 9 | module.exports = factory(require('../moment')); // Node 10 | } else { 11 | factory(window.moment); // Browser global 12 | } 13 | }(function (moment) { 14 | return moment.defineLocale('fo', { 15 | months : 'januar_februar_mars_apríl_mai_juni_juli_august_september_oktober_november_desember'.split('_'), 16 | monthsShort : 'jan_feb_mar_apr_mai_jun_jul_aug_sep_okt_nov_des'.split('_'), 17 | weekdays : 'sunnudagur_mánadagur_týsdagur_mikudagur_hósdagur_fríggjadagur_leygardagur'.split('_'), 18 | weekdaysShort : 'sun_mán_týs_mik_hós_frí_ley'.split('_'), 19 | weekdaysMin : 'su_má_tý_mi_hó_fr_le'.split('_'), 20 | longDateFormat : { 21 | LT : 'HH:mm', 22 | L : 'DD/MM/YYYY', 23 | LL : 'D MMMM YYYY', 24 | LLL : 'D MMMM YYYY LT', 25 | LLLL : 'dddd D. MMMM, YYYY LT' 26 | }, 27 | calendar : { 28 | sameDay : '[Í dag kl.] LT', 29 | nextDay : '[Í morgin kl.] LT', 30 | nextWeek : 'dddd [kl.] LT', 31 | lastDay : '[Í gjár kl.] LT', 32 | lastWeek : '[síðstu] dddd [kl] LT', 33 | sameElse : 'L' 34 | }, 35 | relativeTime : { 36 | future : 'um %s', 37 | past : '%s síðani', 38 | s : 'fá sekund', 39 | m : 'ein minutt', 40 | mm : '%d minuttir', 41 | h : 'ein tími', 42 | hh : '%d tímar', 43 | d : 'ein dagur', 44 | dd : '%d dagar', 45 | M : 'ein mánaði', 46 | MM : '%d mánaðir', 47 | y : 'eitt ár', 48 | yy : '%d ár' 49 | }, 50 | ordinal : '%d.', 51 | week : { 52 | dow : 1, // Monday is the first day of the week. 53 | doy : 4 // The week that contains Jan 4th is the first week of the year. 54 | } 55 | }); 56 | })); 57 | -------------------------------------------------------------------------------- /public/build/moment/moment/2.8.3/locale/fr-ca.js: -------------------------------------------------------------------------------- 1 | // moment.js locale configuration 2 | // locale : canadian french (fr-ca) 3 | // author : Jonathan Abourbih : https://github.com/jonbca 4 | 5 | (function (factory) { 6 | if (typeof define === 'function' && define.amd) { 7 | define(['moment'], factory); // AMD 8 | } else if (typeof exports === 'object') { 9 | module.exports = factory(require('../moment')); // Node 10 | } else { 11 | factory(window.moment); // Browser global 12 | } 13 | }(function (moment) { 14 | return moment.defineLocale('fr-ca', { 15 | months : 'janvier_février_mars_avril_mai_juin_juillet_août_septembre_octobre_novembre_décembre'.split('_'), 16 | monthsShort : 'janv._févr._mars_avr._mai_juin_juil._août_sept._oct._nov._déc.'.split('_'), 17 | weekdays : 'dimanche_lundi_mardi_mercredi_jeudi_vendredi_samedi'.split('_'), 18 | weekdaysShort : 'dim._lun._mar._mer._jeu._ven._sam.'.split('_'), 19 | weekdaysMin : 'Di_Lu_Ma_Me_Je_Ve_Sa'.split('_'), 20 | longDateFormat : { 21 | LT : 'HH:mm', 22 | L : 'YYYY-MM-DD', 23 | LL : 'D MMMM YYYY', 24 | LLL : 'D MMMM YYYY LT', 25 | LLLL : 'dddd D MMMM YYYY LT' 26 | }, 27 | calendar : { 28 | sameDay: '[Aujourd\'hui à] LT', 29 | nextDay: '[Demain à] LT', 30 | nextWeek: 'dddd [à] LT', 31 | lastDay: '[Hier à] LT', 32 | lastWeek: 'dddd [dernier à] LT', 33 | sameElse: 'L' 34 | }, 35 | relativeTime : { 36 | future : 'dans %s', 37 | past : 'il y a %s', 38 | s : 'quelques secondes', 39 | m : 'une minute', 40 | mm : '%d minutes', 41 | h : 'une heure', 42 | hh : '%d heures', 43 | d : 'un jour', 44 | dd : '%d jours', 45 | M : 'un mois', 46 | MM : '%d mois', 47 | y : 'un an', 48 | yy : '%d ans' 49 | }, 50 | ordinal : function (number) { 51 | return number + (number === 1 ? 'er' : ''); 52 | } 53 | }); 54 | })); 55 | -------------------------------------------------------------------------------- /public/build/moment/moment/2.8.3/locale/fr.js: -------------------------------------------------------------------------------- 1 | // moment.js locale configuration 2 | // locale : french (fr) 3 | // author : John Fischer : https://github.com/jfroffice 4 | 5 | (function (factory) { 6 | if (typeof define === 'function' && define.amd) { 7 | define(['moment'], factory); // AMD 8 | } else if (typeof exports === 'object') { 9 | module.exports = factory(require('../moment')); // Node 10 | } else { 11 | factory(window.moment); // Browser global 12 | } 13 | }(function (moment) { 14 | return moment.defineLocale('fr', { 15 | months : 'janvier_février_mars_avril_mai_juin_juillet_août_septembre_octobre_novembre_décembre'.split('_'), 16 | monthsShort : 'janv._févr._mars_avr._mai_juin_juil._août_sept._oct._nov._déc.'.split('_'), 17 | weekdays : 'dimanche_lundi_mardi_mercredi_jeudi_vendredi_samedi'.split('_'), 18 | weekdaysShort : 'dim._lun._mar._mer._jeu._ven._sam.'.split('_'), 19 | weekdaysMin : 'Di_Lu_Ma_Me_Je_Ve_Sa'.split('_'), 20 | longDateFormat : { 21 | LT : 'HH:mm', 22 | L : 'DD/MM/YYYY', 23 | LL : 'D MMMM YYYY', 24 | LLL : 'D MMMM YYYY LT', 25 | LLLL : 'dddd D MMMM YYYY LT' 26 | }, 27 | calendar : { 28 | sameDay: '[Aujourd\'hui à] LT', 29 | nextDay: '[Demain à] LT', 30 | nextWeek: 'dddd [à] LT', 31 | lastDay: '[Hier à] LT', 32 | lastWeek: 'dddd [dernier à] LT', 33 | sameElse: 'L' 34 | }, 35 | relativeTime : { 36 | future : 'dans %s', 37 | past : 'il y a %s', 38 | s : 'quelques secondes', 39 | m : 'une minute', 40 | mm : '%d minutes', 41 | h : 'une heure', 42 | hh : '%d heures', 43 | d : 'un jour', 44 | dd : '%d jours', 45 | M : 'un mois', 46 | MM : '%d mois', 47 | y : 'un an', 48 | yy : '%d ans' 49 | }, 50 | ordinal : function (number) { 51 | return number + (number === 1 ? 'er' : ''); 52 | }, 53 | week : { 54 | dow : 1, // Monday is the first day of the week. 55 | doy : 4 // The week that contains Jan 4th is the first week of the year. 56 | } 57 | }); 58 | })); 59 | -------------------------------------------------------------------------------- /public/build/moment/moment/2.8.3/locale/it.js: -------------------------------------------------------------------------------- 1 | // moment.js locale configuration 2 | // locale : italian (it) 3 | // author : Lorenzo : https://github.com/aliem 4 | // author: Mattia Larentis: https://github.com/nostalgiaz 5 | 6 | (function (factory) { 7 | if (typeof define === 'function' && define.amd) { 8 | define(['moment'], factory); // AMD 9 | } else if (typeof exports === 'object') { 10 | module.exports = factory(require('../moment')); // Node 11 | } else { 12 | factory(window.moment); // Browser global 13 | } 14 | }(function (moment) { 15 | return moment.defineLocale('it', { 16 | months : 'gennaio_febbraio_marzo_aprile_maggio_giugno_luglio_agosto_settembre_ottobre_novembre_dicembre'.split('_'), 17 | monthsShort : 'gen_feb_mar_apr_mag_giu_lug_ago_set_ott_nov_dic'.split('_'), 18 | weekdays : 'Domenica_Lunedì_Martedì_Mercoledì_Giovedì_Venerdì_Sabato'.split('_'), 19 | weekdaysShort : 'Dom_Lun_Mar_Mer_Gio_Ven_Sab'.split('_'), 20 | weekdaysMin : 'D_L_Ma_Me_G_V_S'.split('_'), 21 | longDateFormat : { 22 | LT : 'HH:mm', 23 | L : 'DD/MM/YYYY', 24 | LL : 'D MMMM YYYY', 25 | LLL : 'D MMMM YYYY LT', 26 | LLLL : 'dddd, D MMMM YYYY LT' 27 | }, 28 | calendar : { 29 | sameDay: '[Oggi alle] LT', 30 | nextDay: '[Domani alle] LT', 31 | nextWeek: 'dddd [alle] LT', 32 | lastDay: '[Ieri alle] LT', 33 | lastWeek: '[lo scorso] dddd [alle] LT', 34 | sameElse: 'L' 35 | }, 36 | relativeTime : { 37 | future : function (s) { 38 | return ((/^[0-9].+$/).test(s) ? 'tra' : 'in') + ' ' + s; 39 | }, 40 | past : '%s fa', 41 | s : 'alcuni secondi', 42 | m : 'un minuto', 43 | mm : '%d minuti', 44 | h : 'un\'ora', 45 | hh : '%d ore', 46 | d : 'un giorno', 47 | dd : '%d giorni', 48 | M : 'un mese', 49 | MM : '%d mesi', 50 | y : 'un anno', 51 | yy : '%d anni' 52 | }, 53 | ordinal: '%dº', 54 | week : { 55 | dow : 1, // Monday is the first day of the week. 56 | doy : 4 // The week that contains Jan 4th is the first week of the year. 57 | } 58 | }); 59 | })); 60 | -------------------------------------------------------------------------------- /public/build/moment/moment/2.8.3/locale/ja.js: -------------------------------------------------------------------------------- 1 | // moment.js locale configuration 2 | // locale : japanese (ja) 3 | // author : LI Long : https://github.com/baryon 4 | 5 | (function (factory) { 6 | if (typeof define === 'function' && define.amd) { 7 | define(['moment'], factory); // AMD 8 | } else if (typeof exports === 'object') { 9 | module.exports = factory(require('../moment')); // Node 10 | } else { 11 | factory(window.moment); // Browser global 12 | } 13 | }(function (moment) { 14 | return moment.defineLocale('ja', { 15 | months : '1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月'.split('_'), 16 | monthsShort : '1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月'.split('_'), 17 | weekdays : '日曜日_月曜日_火曜日_水曜日_木曜日_金曜日_土曜日'.split('_'), 18 | weekdaysShort : '日_月_火_水_木_金_土'.split('_'), 19 | weekdaysMin : '日_月_火_水_木_金_土'.split('_'), 20 | longDateFormat : { 21 | LT : 'Ah時m分', 22 | L : 'YYYY/MM/DD', 23 | LL : 'YYYY年M月D日', 24 | LLL : 'YYYY年M月D日LT', 25 | LLLL : 'YYYY年M月D日LT dddd' 26 | }, 27 | meridiem : function (hour, minute, isLower) { 28 | if (hour < 12) { 29 | return '午前'; 30 | } else { 31 | return '午後'; 32 | } 33 | }, 34 | calendar : { 35 | sameDay : '[今日] LT', 36 | nextDay : '[明日] LT', 37 | nextWeek : '[来週]dddd LT', 38 | lastDay : '[昨日] LT', 39 | lastWeek : '[前週]dddd LT', 40 | sameElse : 'L' 41 | }, 42 | relativeTime : { 43 | future : '%s後', 44 | past : '%s前', 45 | s : '数秒', 46 | m : '1分', 47 | mm : '%d分', 48 | h : '1時間', 49 | hh : '%d時間', 50 | d : '1日', 51 | dd : '%d日', 52 | M : '1ヶ月', 53 | MM : '%dヶ月', 54 | y : '1年', 55 | yy : '%d年' 56 | } 57 | }); 58 | })); 59 | -------------------------------------------------------------------------------- /public/build/moment/moment/2.8.3/locale/km.js: -------------------------------------------------------------------------------- 1 | // moment.js locale configuration 2 | // locale : khmer (km) 3 | // author : Kruy Vanna : https://github.com/kruyvanna 4 | 5 | (function (factory) { 6 | if (typeof define === 'function' && define.amd) { 7 | define(['moment'], factory); // AMD 8 | } else if (typeof exports === 'object') { 9 | module.exports = factory(require('../moment')); // Node 10 | } else { 11 | factory(window.moment); // Browser global 12 | } 13 | }(function (moment) { 14 | return moment.defineLocale('km', { 15 | months: 'មករា_កុម្ភៈ_មិនា_មេសា_ឧសភា_មិថុនា_កក្កដា_សីហា_កញ្ញា_តុលា_វិច្ឆិកា_ធ្នូ'.split('_'), 16 | monthsShort: 'មករា_កុម្ភៈ_មិនា_មេសា_ឧសភា_មិថុនា_កក្កដា_សីហា_កញ្ញា_តុលា_វិច្ឆិកា_ធ្នូ'.split('_'), 17 | weekdays: 'អាទិត្យ_ច័ន្ទ_អង្គារ_ពុធ_ព្រហស្បតិ៍_សុក្រ_សៅរ៍'.split('_'), 18 | weekdaysShort: 'អាទិត្យ_ច័ន្ទ_អង្គារ_ពុធ_ព្រហស្បតិ៍_សុក្រ_សៅរ៍'.split('_'), 19 | weekdaysMin: 'អាទិត្យ_ច័ន្ទ_អង្គារ_ពុធ_ព្រហស្បតិ៍_សុក្រ_សៅរ៍'.split('_'), 20 | longDateFormat: { 21 | LT: 'HH:mm', 22 | L: 'DD/MM/YYYY', 23 | LL: 'D MMMM YYYY', 24 | LLL: 'D MMMM YYYY LT', 25 | LLLL: 'dddd, D MMMM YYYY LT' 26 | }, 27 | calendar: { 28 | sameDay: '[ថ្ងៃនៈ ម៉ោង] LT', 29 | nextDay: '[ស្អែក ម៉ោង] LT', 30 | nextWeek: 'dddd [ម៉ោង] LT', 31 | lastDay: '[ម្សិលមិញ ម៉ោង] LT', 32 | lastWeek: 'dddd [សប្តាហ៍មុន] [ម៉ោង] LT', 33 | sameElse: 'L' 34 | }, 35 | relativeTime: { 36 | future: '%sទៀត', 37 | past: '%sមុន', 38 | s: 'ប៉ុន្មានវិនាទី', 39 | m: 'មួយនាទី', 40 | mm: '%d នាទី', 41 | h: 'មួយម៉ោង', 42 | hh: '%d ម៉ោង', 43 | d: 'មួយថ្ងៃ', 44 | dd: '%d ថ្ងៃ', 45 | M: 'មួយខែ', 46 | MM: '%d ខែ', 47 | y: 'មួយឆ្នាំ', 48 | yy: '%d ឆ្នាំ' 49 | }, 50 | week: { 51 | dow: 1, // Monday is the first day of the week. 52 | doy: 4 // The week that contains Jan 4th is the first week of the year. 53 | } 54 | }); 55 | })); 56 | -------------------------------------------------------------------------------- /public/build/moment/moment/2.8.3/locale/ko.js: -------------------------------------------------------------------------------- 1 | // moment.js locale configuration 2 | // locale : korean (ko) 3 | // 4 | // authors 5 | // 6 | // - Kyungwook, Park : https://github.com/kyungw00k 7 | // - Jeeeyul Lee 8 | (function (factory) { 9 | if (typeof define === 'function' && define.amd) { 10 | define(['moment'], factory); // AMD 11 | } else if (typeof exports === 'object') { 12 | module.exports = factory(require('../moment')); // Node 13 | } else { 14 | factory(window.moment); // Browser global 15 | } 16 | }(function (moment) { 17 | return moment.defineLocale('ko', { 18 | months : '1월_2월_3월_4월_5월_6월_7월_8월_9월_10월_11월_12월'.split('_'), 19 | monthsShort : '1월_2월_3월_4월_5월_6월_7월_8월_9월_10월_11월_12월'.split('_'), 20 | weekdays : '일요일_월요일_화요일_수요일_목요일_금요일_토요일'.split('_'), 21 | weekdaysShort : '일_월_화_수_목_금_토'.split('_'), 22 | weekdaysMin : '일_월_화_수_목_금_토'.split('_'), 23 | longDateFormat : { 24 | LT : 'A h시 m분', 25 | L : 'YYYY.MM.DD', 26 | LL : 'YYYY년 MMMM D일', 27 | LLL : 'YYYY년 MMMM D일 LT', 28 | LLLL : 'YYYY년 MMMM D일 dddd LT' 29 | }, 30 | meridiem : function (hour, minute, isUpper) { 31 | return hour < 12 ? '오전' : '오후'; 32 | }, 33 | calendar : { 34 | sameDay : '오늘 LT', 35 | nextDay : '내일 LT', 36 | nextWeek : 'dddd LT', 37 | lastDay : '어제 LT', 38 | lastWeek : '지난주 dddd LT', 39 | sameElse : 'L' 40 | }, 41 | relativeTime : { 42 | future : '%s 후', 43 | past : '%s 전', 44 | s : '몇초', 45 | ss : '%d초', 46 | m : '일분', 47 | mm : '%d분', 48 | h : '한시간', 49 | hh : '%d시간', 50 | d : '하루', 51 | dd : '%d일', 52 | M : '한달', 53 | MM : '%d달', 54 | y : '일년', 55 | yy : '%d년' 56 | }, 57 | ordinal : '%d일', 58 | meridiemParse : /(오전|오후)/, 59 | isPM : function (token) { 60 | return token === '오후'; 61 | } 62 | }); 63 | })); 64 | -------------------------------------------------------------------------------- /public/build/moment/moment/2.8.3/locale/ml.js: -------------------------------------------------------------------------------- 1 | // moment.js locale configuration 2 | // locale : malayalam (ml) 3 | // author : Floyd Pink : https://github.com/floydpink 4 | 5 | (function (factory) { 6 | if (typeof define === 'function' && define.amd) { 7 | define(['moment'], factory); // AMD 8 | } else if (typeof exports === 'object') { 9 | module.exports = factory(require('../moment')); // Node 10 | } else { 11 | factory(window.moment); // Browser global 12 | } 13 | }(function (moment) { 14 | return moment.defineLocale('ml', { 15 | months : 'ജനുവരി_ഫെബ്രുവരി_മാർച്ച്_ഏപ്രിൽ_മേയ്_ജൂൺ_ജൂലൈ_ഓഗസ്റ്റ്_സെപ്റ്റംബർ_ഒക്ടോബർ_നവംബർ_ഡിസംബർ'.split('_'), 16 | monthsShort : 'ജനു._ഫെബ്രു._മാർ._ഏപ്രി._മേയ്_ജൂൺ_ജൂലൈ._ഓഗ._സെപ്റ്റ._ഒക്ടോ._നവം._ഡിസം.'.split('_'), 17 | weekdays : 'ഞായറാഴ്ച_തിങ്കളാഴ്ച_ചൊവ്വാഴ്ച_ബുധനാഴ്ച_വ്യാഴാഴ്ച_വെള്ളിയാഴ്ച_ശനിയാഴ്ച'.split('_'), 18 | weekdaysShort : 'ഞായർ_തിങ്കൾ_ചൊവ്വ_ബുധൻ_വ്യാഴം_വെള്ളി_ശനി'.split('_'), 19 | weekdaysMin : 'ഞാ_തി_ചൊ_ബു_വ്യാ_വെ_ശ'.split('_'), 20 | longDateFormat : { 21 | LT : 'A h:mm -നു', 22 | L : 'DD/MM/YYYY', 23 | LL : 'D MMMM YYYY', 24 | LLL : 'D MMMM YYYY, LT', 25 | LLLL : 'dddd, D MMMM YYYY, LT' 26 | }, 27 | calendar : { 28 | sameDay : '[ഇന്ന്] LT', 29 | nextDay : '[നാളെ] LT', 30 | nextWeek : 'dddd, LT', 31 | lastDay : '[ഇന്നലെ] LT', 32 | lastWeek : '[കഴിഞ്ഞ] dddd, LT', 33 | sameElse : 'L' 34 | }, 35 | relativeTime : { 36 | future : '%s കഴിഞ്ഞ്', 37 | past : '%s മുൻപ്', 38 | s : 'അൽപ നിമിഷങ്ങൾ', 39 | m : 'ഒരു മിനിറ്റ്', 40 | mm : '%d മിനിറ്റ്', 41 | h : 'ഒരു മണിക്കൂർ', 42 | hh : '%d മണിക്കൂർ', 43 | d : 'ഒരു ദിവസം', 44 | dd : '%d ദിവസം', 45 | M : 'ഒരു മാസം', 46 | MM : '%d മാസം', 47 | y : 'ഒരു വർഷം', 48 | yy : '%d വർഷം' 49 | }, 50 | meridiem : function (hour, minute, isLower) { 51 | if (hour < 4) { 52 | return 'രാത്രി'; 53 | } else if (hour < 12) { 54 | return 'രാവിലെ'; 55 | } else if (hour < 17) { 56 | return 'ഉച്ച കഴിഞ്ഞ്'; 57 | } else if (hour < 20) { 58 | return 'വൈകുന്നേരം'; 59 | } else { 60 | return 'രാത്രി'; 61 | } 62 | } 63 | }); 64 | })); 65 | -------------------------------------------------------------------------------- /public/build/moment/moment/2.8.3/locale/nb.js: -------------------------------------------------------------------------------- 1 | // moment.js locale configuration 2 | // locale : norwegian bokmål (nb) 3 | // authors : Espen Hovlandsdal : https://github.com/rexxars 4 | // Sigurd Gartmann : https://github.com/sigurdga 5 | 6 | (function (factory) { 7 | if (typeof define === 'function' && define.amd) { 8 | define(['moment'], factory); // AMD 9 | } else if (typeof exports === 'object') { 10 | module.exports = factory(require('../moment')); // Node 11 | } else { 12 | factory(window.moment); // Browser global 13 | } 14 | }(function (moment) { 15 | return moment.defineLocale('nb', { 16 | months : 'januar_februar_mars_april_mai_juni_juli_august_september_oktober_november_desember'.split('_'), 17 | monthsShort : 'jan_feb_mar_apr_mai_jun_jul_aug_sep_okt_nov_des'.split('_'), 18 | weekdays : 'søndag_mandag_tirsdag_onsdag_torsdag_fredag_lørdag'.split('_'), 19 | weekdaysShort : 'søn_man_tirs_ons_tors_fre_lør'.split('_'), 20 | weekdaysMin : 'sø_ma_ti_on_to_fr_lø'.split('_'), 21 | longDateFormat : { 22 | LT : 'H.mm', 23 | L : 'DD.MM.YYYY', 24 | LL : 'D. MMMM YYYY', 25 | LLL : 'D. MMMM YYYY [kl.] LT', 26 | LLLL : 'dddd D. MMMM YYYY [kl.] LT' 27 | }, 28 | calendar : { 29 | sameDay: '[i dag kl.] LT', 30 | nextDay: '[i morgen kl.] LT', 31 | nextWeek: 'dddd [kl.] LT', 32 | lastDay: '[i går kl.] LT', 33 | lastWeek: '[forrige] dddd [kl.] LT', 34 | sameElse: 'L' 35 | }, 36 | relativeTime : { 37 | future : 'om %s', 38 | past : 'for %s siden', 39 | s : 'noen sekunder', 40 | m : 'ett minutt', 41 | mm : '%d minutter', 42 | h : 'en time', 43 | hh : '%d timer', 44 | d : 'en dag', 45 | dd : '%d dager', 46 | M : 'en måned', 47 | MM : '%d måneder', 48 | y : 'ett år', 49 | yy : '%d år' 50 | }, 51 | ordinal : '%d.', 52 | week : { 53 | dow : 1, // Monday is the first day of the week. 54 | doy : 4 // The week that contains Jan 4th is the first week of the year. 55 | } 56 | }); 57 | })); 58 | -------------------------------------------------------------------------------- /public/build/moment/moment/2.8.3/locale/nn.js: -------------------------------------------------------------------------------- 1 | // moment.js locale configuration 2 | // locale : norwegian nynorsk (nn) 3 | // author : https://github.com/mechuwind 4 | 5 | (function (factory) { 6 | if (typeof define === 'function' && define.amd) { 7 | define(['moment'], factory); // AMD 8 | } else if (typeof exports === 'object') { 9 | module.exports = factory(require('../moment')); // Node 10 | } else { 11 | factory(window.moment); // Browser global 12 | } 13 | }(function (moment) { 14 | return moment.defineLocale('nn', { 15 | months : 'januar_februar_mars_april_mai_juni_juli_august_september_oktober_november_desember'.split('_'), 16 | monthsShort : 'jan_feb_mar_apr_mai_jun_jul_aug_sep_okt_nov_des'.split('_'), 17 | weekdays : 'sundag_måndag_tysdag_onsdag_torsdag_fredag_laurdag'.split('_'), 18 | weekdaysShort : 'sun_mån_tys_ons_tor_fre_lau'.split('_'), 19 | weekdaysMin : 'su_må_ty_on_to_fr_lø'.split('_'), 20 | longDateFormat : { 21 | LT : 'HH:mm', 22 | L : 'DD.MM.YYYY', 23 | LL : 'D MMMM YYYY', 24 | LLL : 'D MMMM YYYY LT', 25 | LLLL : 'dddd D MMMM YYYY LT' 26 | }, 27 | calendar : { 28 | sameDay: '[I dag klokka] LT', 29 | nextDay: '[I morgon klokka] LT', 30 | nextWeek: 'dddd [klokka] LT', 31 | lastDay: '[I går klokka] LT', 32 | lastWeek: '[Føregåande] dddd [klokka] LT', 33 | sameElse: 'L' 34 | }, 35 | relativeTime : { 36 | future : 'om %s', 37 | past : 'for %s sidan', 38 | s : 'nokre sekund', 39 | m : 'eit minutt', 40 | mm : '%d minutt', 41 | h : 'ein time', 42 | hh : '%d timar', 43 | d : 'ein dag', 44 | dd : '%d dagar', 45 | M : 'ein månad', 46 | MM : '%d månader', 47 | y : 'eit år', 48 | yy : '%d år' 49 | }, 50 | ordinal : '%d.', 51 | week : { 52 | dow : 1, // Monday is the first day of the week. 53 | doy : 4 // The week that contains Jan 4th is the first week of the year. 54 | } 55 | }); 56 | })); 57 | -------------------------------------------------------------------------------- /public/build/moment/moment/2.8.3/locale/pt-br.js: -------------------------------------------------------------------------------- 1 | // moment.js locale configuration 2 | // locale : brazilian portuguese (pt-br) 3 | // author : Caio Ribeiro Pereira : https://github.com/caio-ribeiro-pereira 4 | 5 | (function (factory) { 6 | if (typeof define === 'function' && define.amd) { 7 | define(['moment'], factory); // AMD 8 | } else if (typeof exports === 'object') { 9 | module.exports = factory(require('../moment')); // Node 10 | } else { 11 | factory(window.moment); // Browser global 12 | } 13 | }(function (moment) { 14 | return moment.defineLocale('pt-br', { 15 | months : 'janeiro_fevereiro_março_abril_maio_junho_julho_agosto_setembro_outubro_novembro_dezembro'.split('_'), 16 | monthsShort : 'jan_fev_mar_abr_mai_jun_jul_ago_set_out_nov_dez'.split('_'), 17 | weekdays : 'domingo_segunda-feira_terça-feira_quarta-feira_quinta-feira_sexta-feira_sábado'.split('_'), 18 | weekdaysShort : 'dom_seg_ter_qua_qui_sex_sáb'.split('_'), 19 | weekdaysMin : 'dom_2ª_3ª_4ª_5ª_6ª_sáb'.split('_'), 20 | longDateFormat : { 21 | LT : 'HH:mm', 22 | L : 'DD/MM/YYYY', 23 | LL : 'D [de] MMMM [de] YYYY', 24 | LLL : 'D [de] MMMM [de] YYYY [às] LT', 25 | LLLL : 'dddd, D [de] MMMM [de] YYYY [às] LT' 26 | }, 27 | calendar : { 28 | sameDay: '[Hoje às] LT', 29 | nextDay: '[Amanhã às] LT', 30 | nextWeek: 'dddd [às] LT', 31 | lastDay: '[Ontem às] LT', 32 | lastWeek: function () { 33 | return (this.day() === 0 || this.day() === 6) ? 34 | '[Último] dddd [às] LT' : // Saturday + Sunday 35 | '[Última] dddd [às] LT'; // Monday - Friday 36 | }, 37 | sameElse: 'L' 38 | }, 39 | relativeTime : { 40 | future : 'em %s', 41 | past : '%s atrás', 42 | s : 'segundos', 43 | m : 'um minuto', 44 | mm : '%d minutos', 45 | h : 'uma hora', 46 | hh : '%d horas', 47 | d : 'um dia', 48 | dd : '%d dias', 49 | M : 'um mês', 50 | MM : '%d meses', 51 | y : 'um ano', 52 | yy : '%d anos' 53 | }, 54 | ordinal : '%dº' 55 | }); 56 | })); 57 | -------------------------------------------------------------------------------- /public/build/moment/moment/2.8.3/locale/pt.js: -------------------------------------------------------------------------------- 1 | // moment.js locale configuration 2 | // locale : portuguese (pt) 3 | // author : Jefferson : https://github.com/jalex79 4 | 5 | (function (factory) { 6 | if (typeof define === 'function' && define.amd) { 7 | define(['moment'], factory); // AMD 8 | } else if (typeof exports === 'object') { 9 | module.exports = factory(require('../moment')); // Node 10 | } else { 11 | factory(window.moment); // Browser global 12 | } 13 | }(function (moment) { 14 | return moment.defineLocale('pt', { 15 | months : 'janeiro_fevereiro_março_abril_maio_junho_julho_agosto_setembro_outubro_novembro_dezembro'.split('_'), 16 | monthsShort : 'jan_fev_mar_abr_mai_jun_jul_ago_set_out_nov_dez'.split('_'), 17 | weekdays : 'domingo_segunda-feira_terça-feira_quarta-feira_quinta-feira_sexta-feira_sábado'.split('_'), 18 | weekdaysShort : 'dom_seg_ter_qua_qui_sex_sáb'.split('_'), 19 | weekdaysMin : 'dom_2ª_3ª_4ª_5ª_6ª_sáb'.split('_'), 20 | longDateFormat : { 21 | LT : 'HH:mm', 22 | L : 'DD/MM/YYYY', 23 | LL : 'D [de] MMMM [de] YYYY', 24 | LLL : 'D [de] MMMM [de] YYYY LT', 25 | LLLL : 'dddd, D [de] MMMM [de] YYYY LT' 26 | }, 27 | calendar : { 28 | sameDay: '[Hoje às] LT', 29 | nextDay: '[Amanhã às] LT', 30 | nextWeek: 'dddd [às] LT', 31 | lastDay: '[Ontem às] LT', 32 | lastWeek: function () { 33 | return (this.day() === 0 || this.day() === 6) ? 34 | '[Último] dddd [às] LT' : // Saturday + Sunday 35 | '[Última] dddd [às] LT'; // Monday - Friday 36 | }, 37 | sameElse: 'L' 38 | }, 39 | relativeTime : { 40 | future : 'em %s', 41 | past : 'há %s', 42 | s : 'segundos', 43 | m : 'um minuto', 44 | mm : '%d minutos', 45 | h : 'uma hora', 46 | hh : '%d horas', 47 | d : 'um dia', 48 | dd : '%d dias', 49 | M : 'um mês', 50 | MM : '%d meses', 51 | y : 'um ano', 52 | yy : '%d anos' 53 | }, 54 | ordinal : '%dº', 55 | week : { 56 | dow : 1, // Monday is the first day of the week. 57 | doy : 4 // The week that contains Jan 4th is the first week of the year. 58 | } 59 | }); 60 | })); 61 | -------------------------------------------------------------------------------- /public/build/moment/moment/2.8.3/locale/sq.js: -------------------------------------------------------------------------------- 1 | // moment.js locale configuration 2 | // locale : Albanian (sq) 3 | // author : Flakërim Ismani : https://github.com/flakerimi 4 | // author: Menelion Elensúle: https://github.com/Oire (tests) 5 | // author : Oerd Cukalla : https://github.com/oerd (fixes) 6 | 7 | (function (factory) { 8 | if (typeof define === 'function' && define.amd) { 9 | define(['moment'], factory); // AMD 10 | } else if (typeof exports === 'object') { 11 | module.exports = factory(require('../moment')); // Node 12 | } else { 13 | factory(window.moment); // Browser global 14 | } 15 | }(function (moment) { 16 | return moment.defineLocale('sq', { 17 | months : 'Janar_Shkurt_Mars_Prill_Maj_Qershor_Korrik_Gusht_Shtator_Tetor_Nëntor_Dhjetor'.split('_'), 18 | monthsShort : 'Jan_Shk_Mar_Pri_Maj_Qer_Kor_Gus_Sht_Tet_Nën_Dhj'.split('_'), 19 | weekdays : 'E Diel_E Hënë_E Martë_E Mërkurë_E Enjte_E Premte_E Shtunë'.split('_'), 20 | weekdaysShort : 'Die_Hën_Mar_Mër_Enj_Pre_Sht'.split('_'), 21 | weekdaysMin : 'D_H_Ma_Më_E_P_Sh'.split('_'), 22 | meridiem : function (hours, minutes, isLower) { 23 | return hours < 12 ? 'PD' : 'MD'; 24 | }, 25 | longDateFormat : { 26 | LT : 'HH:mm', 27 | L : 'DD/MM/YYYY', 28 | LL : 'D MMMM YYYY', 29 | LLL : 'D MMMM YYYY LT', 30 | LLLL : 'dddd, D MMMM YYYY LT' 31 | }, 32 | calendar : { 33 | sameDay : '[Sot në] LT', 34 | nextDay : '[Nesër në] LT', 35 | nextWeek : 'dddd [në] LT', 36 | lastDay : '[Dje në] LT', 37 | lastWeek : 'dddd [e kaluar në] LT', 38 | sameElse : 'L' 39 | }, 40 | relativeTime : { 41 | future : 'në %s', 42 | past : '%s më parë', 43 | s : 'disa sekonda', 44 | m : 'një minutë', 45 | mm : '%d minuta', 46 | h : 'një orë', 47 | hh : '%d orë', 48 | d : 'një ditë', 49 | dd : '%d ditë', 50 | M : 'një muaj', 51 | MM : '%d muaj', 52 | y : 'një vit', 53 | yy : '%d vite' 54 | }, 55 | ordinal : '%d.', 56 | week : { 57 | dow : 1, // Monday is the first day of the week. 58 | doy : 4 // The week that contains Jan 4th is the first week of the year. 59 | } 60 | }); 61 | })); 62 | -------------------------------------------------------------------------------- /public/build/moment/moment/2.8.3/locale/sv.js: -------------------------------------------------------------------------------- 1 | // moment.js locale configuration 2 | // locale : swedish (sv) 3 | // author : Jens Alm : https://github.com/ulmus 4 | 5 | (function (factory) { 6 | if (typeof define === 'function' && define.amd) { 7 | define(['moment'], factory); // AMD 8 | } else if (typeof exports === 'object') { 9 | module.exports = factory(require('../moment')); // Node 10 | } else { 11 | factory(window.moment); // Browser global 12 | } 13 | }(function (moment) { 14 | return moment.defineLocale('sv', { 15 | months : 'januari_februari_mars_april_maj_juni_juli_augusti_september_oktober_november_december'.split('_'), 16 | monthsShort : 'jan_feb_mar_apr_maj_jun_jul_aug_sep_okt_nov_dec'.split('_'), 17 | weekdays : 'söndag_måndag_tisdag_onsdag_torsdag_fredag_lördag'.split('_'), 18 | weekdaysShort : 'sön_mån_tis_ons_tor_fre_lör'.split('_'), 19 | weekdaysMin : 'sö_må_ti_on_to_fr_lö'.split('_'), 20 | longDateFormat : { 21 | LT : 'HH:mm', 22 | L : 'YYYY-MM-DD', 23 | LL : 'D MMMM YYYY', 24 | LLL : 'D MMMM YYYY LT', 25 | LLLL : 'dddd D MMMM YYYY LT' 26 | }, 27 | calendar : { 28 | sameDay: '[Idag] LT', 29 | nextDay: '[Imorgon] LT', 30 | lastDay: '[Igår] LT', 31 | nextWeek: 'dddd LT', 32 | lastWeek: '[Förra] dddd[en] LT', 33 | sameElse: 'L' 34 | }, 35 | relativeTime : { 36 | future : 'om %s', 37 | past : 'för %s sedan', 38 | s : 'några sekunder', 39 | m : 'en minut', 40 | mm : '%d minuter', 41 | h : 'en timme', 42 | hh : '%d timmar', 43 | d : 'en dag', 44 | dd : '%d dagar', 45 | M : 'en månad', 46 | MM : '%d månader', 47 | y : 'ett år', 48 | yy : '%d år' 49 | }, 50 | ordinal : function (number) { 51 | var b = number % 10, 52 | output = (~~(number % 100 / 10) === 1) ? 'e' : 53 | (b === 1) ? 'a' : 54 | (b === 2) ? 'a' : 55 | (b === 3) ? 'e' : 'e'; 56 | return number + output; 57 | }, 58 | week : { 59 | dow : 1, // Monday is the first day of the week. 60 | doy : 4 // The week that contains Jan 4th is the first week of the year. 61 | } 62 | }); 63 | })); 64 | -------------------------------------------------------------------------------- /public/build/moment/moment/2.8.3/locale/th.js: -------------------------------------------------------------------------------- 1 | // moment.js locale configuration 2 | // locale : thai (th) 3 | // author : Kridsada Thanabulpong : https://github.com/sirn 4 | 5 | (function (factory) { 6 | if (typeof define === 'function' && define.amd) { 7 | define(['moment'], factory); // AMD 8 | } else if (typeof exports === 'object') { 9 | module.exports = factory(require('../moment')); // Node 10 | } else { 11 | factory(window.moment); // Browser global 12 | } 13 | }(function (moment) { 14 | return moment.defineLocale('th', { 15 | months : 'มกราคม_กุมภาพันธ์_มีนาคม_เมษายน_พฤษภาคม_มิถุนายน_กรกฎาคม_สิงหาคม_กันยายน_ตุลาคม_พฤศจิกายน_ธันวาคม'.split('_'), 16 | monthsShort : 'มกรา_กุมภา_มีนา_เมษา_พฤษภา_มิถุนา_กรกฎา_สิงหา_กันยา_ตุลา_พฤศจิกา_ธันวา'.split('_'), 17 | weekdays : 'อาทิตย์_จันทร์_อังคาร_พุธ_พฤหัสบดี_ศุกร์_เสาร์'.split('_'), 18 | weekdaysShort : 'อาทิตย์_จันทร์_อังคาร_พุธ_พฤหัส_ศุกร์_เสาร์'.split('_'), // yes, three characters difference 19 | weekdaysMin : 'อา._จ._อ._พ._พฤ._ศ._ส.'.split('_'), 20 | longDateFormat : { 21 | LT : 'H นาฬิกา m นาที', 22 | L : 'YYYY/MM/DD', 23 | LL : 'D MMMM YYYY', 24 | LLL : 'D MMMM YYYY เวลา LT', 25 | LLLL : 'วันddddที่ D MMMM YYYY เวลา LT' 26 | }, 27 | meridiem : function (hour, minute, isLower) { 28 | if (hour < 12) { 29 | return 'ก่อนเที่ยง'; 30 | } else { 31 | return 'หลังเที่ยง'; 32 | } 33 | }, 34 | calendar : { 35 | sameDay : '[วันนี้ เวลา] LT', 36 | nextDay : '[พรุ่งนี้ เวลา] LT', 37 | nextWeek : 'dddd[หน้า เวลา] LT', 38 | lastDay : '[เมื่อวานนี้ เวลา] LT', 39 | lastWeek : '[วัน]dddd[ที่แล้ว เวลา] LT', 40 | sameElse : 'L' 41 | }, 42 | relativeTime : { 43 | future : 'อีก %s', 44 | past : '%sที่แล้ว', 45 | s : 'ไม่กี่วินาที', 46 | m : '1 นาที', 47 | mm : '%d นาที', 48 | h : '1 ชั่วโมง', 49 | hh : '%d ชั่วโมง', 50 | d : '1 วัน', 51 | dd : '%d วัน', 52 | M : '1 เดือน', 53 | MM : '%d เดือน', 54 | y : '1 ปี', 55 | yy : '%d ปี' 56 | } 57 | }); 58 | })); 59 | -------------------------------------------------------------------------------- /public/build/moment/moment/2.8.3/locale/tl-ph.js: -------------------------------------------------------------------------------- 1 | // moment.js locale configuration 2 | // locale : Tagalog/Filipino (tl-ph) 3 | // author : Dan Hagman 4 | 5 | (function (factory) { 6 | if (typeof define === 'function' && define.amd) { 7 | define(['moment'], factory); // AMD 8 | } else if (typeof exports === 'object') { 9 | module.exports = factory(require('../moment')); // Node 10 | } else { 11 | factory(window.moment); // Browser global 12 | } 13 | }(function (moment) { 14 | return moment.defineLocale('tl-ph', { 15 | months : 'Enero_Pebrero_Marso_Abril_Mayo_Hunyo_Hulyo_Agosto_Setyembre_Oktubre_Nobyembre_Disyembre'.split('_'), 16 | monthsShort : 'Ene_Peb_Mar_Abr_May_Hun_Hul_Ago_Set_Okt_Nob_Dis'.split('_'), 17 | weekdays : 'Linggo_Lunes_Martes_Miyerkules_Huwebes_Biyernes_Sabado'.split('_'), 18 | weekdaysShort : 'Lin_Lun_Mar_Miy_Huw_Biy_Sab'.split('_'), 19 | weekdaysMin : 'Li_Lu_Ma_Mi_Hu_Bi_Sab'.split('_'), 20 | longDateFormat : { 21 | LT : 'HH:mm', 22 | L : 'MM/D/YYYY', 23 | LL : 'MMMM D, YYYY', 24 | LLL : 'MMMM D, YYYY LT', 25 | LLLL : 'dddd, MMMM DD, YYYY LT' 26 | }, 27 | calendar : { 28 | sameDay: '[Ngayon sa] LT', 29 | nextDay: '[Bukas sa] LT', 30 | nextWeek: 'dddd [sa] LT', 31 | lastDay: '[Kahapon sa] LT', 32 | lastWeek: 'dddd [huling linggo] LT', 33 | sameElse: 'L' 34 | }, 35 | relativeTime : { 36 | future : 'sa loob ng %s', 37 | past : '%s ang nakalipas', 38 | s : 'ilang segundo', 39 | m : 'isang minuto', 40 | mm : '%d minuto', 41 | h : 'isang oras', 42 | hh : '%d oras', 43 | d : 'isang araw', 44 | dd : '%d araw', 45 | M : 'isang buwan', 46 | MM : '%d buwan', 47 | y : 'isang taon', 48 | yy : '%d taon' 49 | }, 50 | ordinal : function (number) { 51 | return number; 52 | }, 53 | week : { 54 | dow : 1, // Monday is the first day of the week. 55 | doy : 4 // The week that contains Jan 4th is the first week of the year. 56 | } 57 | }); 58 | })); 59 | -------------------------------------------------------------------------------- /public/build/moment/moment/2.8.3/locale/tzm-latn.js: -------------------------------------------------------------------------------- 1 | // moment.js locale configuration 2 | // locale : Morocco Central Atlas Tamaziɣt in Latin (tzm-latn) 3 | // author : Abdel Said : https://github.com/abdelsaid 4 | 5 | (function (factory) { 6 | if (typeof define === 'function' && define.amd) { 7 | define(['moment'], factory); // AMD 8 | } else if (typeof exports === 'object') { 9 | module.exports = factory(require('../moment')); // Node 10 | } else { 11 | factory(window.moment); // Browser global 12 | } 13 | }(function (moment) { 14 | return moment.defineLocale('tzm-latn', { 15 | months : 'innayr_brˤayrˤ_marˤsˤ_ibrir_mayyw_ywnyw_ywlywz_ɣwšt_šwtanbir_ktˤwbrˤ_nwwanbir_dwjnbir'.split('_'), 16 | monthsShort : 'innayr_brˤayrˤ_marˤsˤ_ibrir_mayyw_ywnyw_ywlywz_ɣwšt_šwtanbir_ktˤwbrˤ_nwwanbir_dwjnbir'.split('_'), 17 | weekdays : 'asamas_aynas_asinas_akras_akwas_asimwas_asiḍyas'.split('_'), 18 | weekdaysShort : 'asamas_aynas_asinas_akras_akwas_asimwas_asiḍyas'.split('_'), 19 | weekdaysMin : 'asamas_aynas_asinas_akras_akwas_asimwas_asiḍyas'.split('_'), 20 | longDateFormat : { 21 | LT : 'HH:mm', 22 | L : 'DD/MM/YYYY', 23 | LL : 'D MMMM YYYY', 24 | LLL : 'D MMMM YYYY LT', 25 | LLLL : 'dddd D MMMM YYYY LT' 26 | }, 27 | calendar : { 28 | sameDay: '[asdkh g] LT', 29 | nextDay: '[aska g] LT', 30 | nextWeek: 'dddd [g] LT', 31 | lastDay: '[assant g] LT', 32 | lastWeek: 'dddd [g] LT', 33 | sameElse: 'L' 34 | }, 35 | relativeTime : { 36 | future : 'dadkh s yan %s', 37 | past : 'yan %s', 38 | s : 'imik', 39 | m : 'minuḍ', 40 | mm : '%d minuḍ', 41 | h : 'saɛa', 42 | hh : '%d tassaɛin', 43 | d : 'ass', 44 | dd : '%d ossan', 45 | M : 'ayowr', 46 | MM : '%d iyyirn', 47 | y : 'asgas', 48 | yy : '%d isgasn' 49 | }, 50 | week : { 51 | dow : 6, // Saturday is the first day of the week. 52 | doy : 12 // The week that contains Jan 1st is the first week of the year. 53 | } 54 | }); 55 | })); 56 | -------------------------------------------------------------------------------- /public/build/moment/moment/2.8.3/locale/tzm.js: -------------------------------------------------------------------------------- 1 | // moment.js locale configuration 2 | // locale : Morocco Central Atlas Tamaziɣt (tzm) 3 | // author : Abdel Said : https://github.com/abdelsaid 4 | 5 | (function (factory) { 6 | if (typeof define === 'function' && define.amd) { 7 | define(['moment'], factory); // AMD 8 | } else if (typeof exports === 'object') { 9 | module.exports = factory(require('../moment')); // Node 10 | } else { 11 | factory(window.moment); // Browser global 12 | } 13 | }(function (moment) { 14 | return moment.defineLocale('tzm', { 15 | months : 'ⵉⵏⵏⴰⵢⵔ_ⴱⵕⴰⵢⵕ_ⵎⴰⵕⵚ_ⵉⴱⵔⵉⵔ_ⵎⴰⵢⵢⵓ_ⵢⵓⵏⵢⵓ_ⵢⵓⵍⵢⵓⵣ_ⵖⵓⵛⵜ_ⵛⵓⵜⴰⵏⴱⵉⵔ_ⴽⵟⵓⴱⵕ_ⵏⵓⵡⴰⵏⴱⵉⵔ_ⴷⵓⵊⵏⴱⵉⵔ'.split('_'), 16 | monthsShort : 'ⵉⵏⵏⴰⵢⵔ_ⴱⵕⴰⵢⵕ_ⵎⴰⵕⵚ_ⵉⴱⵔⵉⵔ_ⵎⴰⵢⵢⵓ_ⵢⵓⵏⵢⵓ_ⵢⵓⵍⵢⵓⵣ_ⵖⵓⵛⵜ_ⵛⵓⵜⴰⵏⴱⵉⵔ_ⴽⵟⵓⴱⵕ_ⵏⵓⵡⴰⵏⴱⵉⵔ_ⴷⵓⵊⵏⴱⵉⵔ'.split('_'), 17 | weekdays : 'ⴰⵙⴰⵎⴰⵙ_ⴰⵢⵏⴰⵙ_ⴰⵙⵉⵏⴰⵙ_ⴰⴽⵔⴰⵙ_ⴰⴽⵡⴰⵙ_ⴰⵙⵉⵎⵡⴰⵙ_ⴰⵙⵉⴹⵢⴰⵙ'.split('_'), 18 | weekdaysShort : 'ⴰⵙⴰⵎⴰⵙ_ⴰⵢⵏⴰⵙ_ⴰⵙⵉⵏⴰⵙ_ⴰⴽⵔⴰⵙ_ⴰⴽⵡⴰⵙ_ⴰⵙⵉⵎⵡⴰⵙ_ⴰⵙⵉⴹⵢⴰⵙ'.split('_'), 19 | weekdaysMin : 'ⴰⵙⴰⵎⴰⵙ_ⴰⵢⵏⴰⵙ_ⴰⵙⵉⵏⴰⵙ_ⴰⴽⵔⴰⵙ_ⴰⴽⵡⴰⵙ_ⴰⵙⵉⵎⵡⴰⵙ_ⴰⵙⵉⴹⵢⴰⵙ'.split('_'), 20 | longDateFormat : { 21 | LT : 'HH:mm', 22 | L : 'DD/MM/YYYY', 23 | LL : 'D MMMM YYYY', 24 | LLL : 'D MMMM YYYY LT', 25 | LLLL : 'dddd D MMMM YYYY LT' 26 | }, 27 | calendar : { 28 | sameDay: '[ⴰⵙⴷⵅ ⴴ] LT', 29 | nextDay: '[ⴰⵙⴽⴰ ⴴ] LT', 30 | nextWeek: 'dddd [ⴴ] LT', 31 | lastDay: '[ⴰⵚⴰⵏⵜ ⴴ] LT', 32 | lastWeek: 'dddd [ⴴ] LT', 33 | sameElse: 'L' 34 | }, 35 | relativeTime : { 36 | future : 'ⴷⴰⴷⵅ ⵙ ⵢⴰⵏ %s', 37 | past : 'ⵢⴰⵏ %s', 38 | s : 'ⵉⵎⵉⴽ', 39 | m : 'ⵎⵉⵏⵓⴺ', 40 | mm : '%d ⵎⵉⵏⵓⴺ', 41 | h : 'ⵙⴰⵄⴰ', 42 | hh : '%d ⵜⴰⵙⵙⴰⵄⵉⵏ', 43 | d : 'ⴰⵙⵙ', 44 | dd : '%d oⵙⵙⴰⵏ', 45 | M : 'ⴰⵢoⵓⵔ', 46 | MM : '%d ⵉⵢⵢⵉⵔⵏ', 47 | y : 'ⴰⵙⴳⴰⵙ', 48 | yy : '%d ⵉⵙⴳⴰⵙⵏ' 49 | }, 50 | week : { 51 | dow : 6, // Saturday is the first day of the week. 52 | doy : 12 // The week that contains Jan 1st is the first week of the year. 53 | } 54 | }); 55 | })); 56 | -------------------------------------------------------------------------------- /public/build/moment/moment/2.8.3/locale/uz.js: -------------------------------------------------------------------------------- 1 | // moment.js locale configuration 2 | // locale : uzbek (uz) 3 | // author : Sardor Muminov : https://github.com/muminoff 4 | 5 | (function (factory) { 6 | if (typeof define === 'function' && define.amd) { 7 | define(['moment'], factory); // AMD 8 | } else if (typeof exports === 'object') { 9 | module.exports = factory(require('../moment')); // Node 10 | } else { 11 | factory(window.moment); // Browser global 12 | } 13 | }(function (moment) { 14 | return moment.defineLocale('uz', { 15 | months : 'январь_февраль_март_апрель_май_июнь_июль_август_сентябрь_октябрь_ноябрь_декабрь'.split('_'), 16 | monthsShort : 'янв_фев_мар_апр_май_июн_июл_авг_сен_окт_ноя_дек'.split('_'), 17 | weekdays : 'Якшанба_Душанба_Сешанба_Чоршанба_Пайшанба_Жума_Шанба'.split('_'), 18 | weekdaysShort : 'Якш_Душ_Сеш_Чор_Пай_Жум_Шан'.split('_'), 19 | weekdaysMin : 'Як_Ду_Се_Чо_Па_Жу_Ша'.split('_'), 20 | longDateFormat : { 21 | LT : 'HH:mm', 22 | L : 'DD/MM/YYYY', 23 | LL : 'D MMMM YYYY', 24 | LLL : 'D MMMM YYYY LT', 25 | LLLL : 'D MMMM YYYY, dddd LT' 26 | }, 27 | calendar : { 28 | sameDay : '[Бугун соат] LT [да]', 29 | nextDay : '[Эртага] LT [да]', 30 | nextWeek : 'dddd [куни соат] LT [да]', 31 | lastDay : '[Кеча соат] LT [да]', 32 | lastWeek : '[Утган] dddd [куни соат] LT [да]', 33 | sameElse : 'L' 34 | }, 35 | relativeTime : { 36 | future : 'Якин %s ичида', 37 | past : 'Бир неча %s олдин', 38 | s : 'фурсат', 39 | m : 'бир дакика', 40 | mm : '%d дакика', 41 | h : 'бир соат', 42 | hh : '%d соат', 43 | d : 'бир кун', 44 | dd : '%d кун', 45 | M : 'бир ой', 46 | MM : '%d ой', 47 | y : 'бир йил', 48 | yy : '%d йил' 49 | }, 50 | week : { 51 | dow : 1, // Monday is the first day of the week. 52 | doy : 7 // The week that contains Jan 4th is the first week of the year. 53 | } 54 | }); 55 | })); 56 | -------------------------------------------------------------------------------- /public/build/moment/moment/2.8.3/locale/vi.js: -------------------------------------------------------------------------------- 1 | // moment.js locale configuration 2 | // locale : vietnamese (vi) 3 | // author : Bang Nguyen : https://github.com/bangnk 4 | 5 | (function (factory) { 6 | if (typeof define === 'function' && define.amd) { 7 | define(['moment'], factory); // AMD 8 | } else if (typeof exports === 'object') { 9 | module.exports = factory(require('../moment')); // Node 10 | } else { 11 | factory(window.moment); // Browser global 12 | } 13 | }(function (moment) { 14 | return moment.defineLocale('vi', { 15 | months : 'tháng 1_tháng 2_tháng 3_tháng 4_tháng 5_tháng 6_tháng 7_tháng 8_tháng 9_tháng 10_tháng 11_tháng 12'.split('_'), 16 | monthsShort : 'Th01_Th02_Th03_Th04_Th05_Th06_Th07_Th08_Th09_Th10_Th11_Th12'.split('_'), 17 | weekdays : 'chủ nhật_thứ hai_thứ ba_thứ tư_thứ năm_thứ sáu_thứ bảy'.split('_'), 18 | weekdaysShort : 'CN_T2_T3_T4_T5_T6_T7'.split('_'), 19 | weekdaysMin : 'CN_T2_T3_T4_T5_T6_T7'.split('_'), 20 | longDateFormat : { 21 | LT : 'HH:mm', 22 | L : 'DD/MM/YYYY', 23 | LL : 'D MMMM [năm] YYYY', 24 | LLL : 'D MMMM [năm] YYYY LT', 25 | LLLL : 'dddd, D MMMM [năm] YYYY LT', 26 | l : 'DD/M/YYYY', 27 | ll : 'D MMM YYYY', 28 | lll : 'D MMM YYYY LT', 29 | llll : 'ddd, D MMM YYYY LT' 30 | }, 31 | calendar : { 32 | sameDay: '[Hôm nay lúc] LT', 33 | nextDay: '[Ngày mai lúc] LT', 34 | nextWeek: 'dddd [tuần tới lúc] LT', 35 | lastDay: '[Hôm qua lúc] LT', 36 | lastWeek: 'dddd [tuần rồi lúc] LT', 37 | sameElse: 'L' 38 | }, 39 | relativeTime : { 40 | future : '%s tới', 41 | past : '%s trước', 42 | s : 'vài giây', 43 | m : 'một phút', 44 | mm : '%d phút', 45 | h : 'một giờ', 46 | hh : '%d giờ', 47 | d : 'một ngày', 48 | dd : '%d ngày', 49 | M : 'một tháng', 50 | MM : '%d tháng', 51 | y : 'một năm', 52 | yy : '%d năm' 53 | }, 54 | ordinal : function (number) { 55 | return number; 56 | }, 57 | week : { 58 | dow : 1, // Monday is the first day of the week. 59 | doy : 4 // The week that contains Jan 4th is the first week of the year. 60 | } 61 | }); 62 | })); 63 | -------------------------------------------------------------------------------- /public/client/admin-helper/admin-helper.js: -------------------------------------------------------------------------------- 1 | // Is the current user an admin 2 | 3 | var Handlebars = require('handlebars'); 4 | 5 | Handlebars.registerHelper( 6 | 'admin', 7 | function() { 8 | // we have to have the require here, because application depends on this file 9 | return require('application').user.admin; 10 | } 11 | ); 12 | -------------------------------------------------------------------------------- /public/client/admin-helper/component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "admin-helper", 3 | "description": "Handlebars helper returning true if admin", 4 | "dependencies": { 5 | "components/handlebars.js": "*" 6 | }, 7 | "local": ["application"], 8 | "main": "admin-helper.js", 9 | "scripts": ["admin-helper.js"] 10 | } 11 | -------------------------------------------------------------------------------- /public/client/admin-route/admin-route.html: -------------------------------------------------------------------------------- 1 |
-------------------------------------------------------------------------------- /public/client/admin-route/admin-route.js: -------------------------------------------------------------------------------- 1 | var app = require('application'); 2 | var FeedCollectionCollectionView = require('feed-collection-collection-view'); 3 | var FeedCollectionCollection = require('feed-collection-collection'); 4 | var LayoutView = require('layout-view'); 5 | 6 | module.exports = function() { 7 | var Admin = LayoutView.extend({ 8 | regions: { 9 | collectionRegion: '#collection' 10 | }, 11 | template: require('./admin-route.html'), 12 | onShow: function() { 13 | var agencies = new FeedCollectionCollection(); 14 | var instance = this; 15 | agencies.fetch().done(function() { 16 | instance.collectionRegion.show(new FeedCollectionCollectionView({ 17 | collection: agencies 18 | })); 19 | }) 20 | 21 | app.nav.setLocation([]); 22 | } 23 | }); 24 | 25 | // show your work 26 | app.appRegion.show(new Admin()); 27 | } 28 | -------------------------------------------------------------------------------- /public/client/admin-route/component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "admin-route", 3 | "description": "Route to show all of the defined feed collections", 4 | "local": ["application", "feed-collection-collection", "feed-collection-collection-view", "layout-view"], 5 | "scripts": ["admin-route.js"], 6 | "templates": ["admin-route.html"] 7 | } 8 | -------------------------------------------------------------------------------- /public/client/application/application.css: -------------------------------------------------------------------------------- 1 | /** general shared styles */ 2 | 3 | .spinner { 4 | animation-name: spinner; 5 | animation-duration: 1s; 6 | animation-timing-function: linear; 7 | animation-iteration-count: infinite; 8 | } 9 | 10 | @keyframes spinner { 11 | from { 12 | transform: rotate(0turn); 13 | } 14 | to { 15 | transform: rotate(1turn); 16 | } 17 | } 18 | 19 | /* after http://codepen.io/tjvantoll/pen/JEKIu */ 20 | .table-fixed-header { 21 | width: 100%; 22 | table-layout: fixed; 23 | border-collapse: collapse; 24 | } 25 | 26 | .table-fixed-header td, .table-fixed-header th { 27 | overflow: hidden; 28 | display: inline-block; 29 | } 30 | 31 | .table-fixed-header thead { 32 | display: block; 33 | } 34 | 35 | .table-fixed-header tbody { 36 | overflow: auto; 37 | display: block; 38 | } 39 | 40 | .navbar { 41 | font-size: 14pt; vertical-align: bottom; 42 | } 43 | 44 | .navbar-text { 45 | margin-top: 12px; 46 | } 47 | -------------------------------------------------------------------------------- /public/client/application/application.js: -------------------------------------------------------------------------------- 1 | var BB = require('bb'); 2 | var Bootstrap = require('bootstrap'); 3 | var Breadcrumb = require('breadcrumb-nav'); 4 | var es5 = require('es5-shim'); 5 | var es6 = require('es6-shim'); 6 | var Handlebars = require('Handlebars'); 7 | 8 | // register Handlebars helpers and partials 9 | require('date-render-helper'); 10 | require('class-helper'); 11 | require('logic-helper'); 12 | require('translate-helper'); 13 | require('text-helper'); 14 | require('admin-helper'); 15 | require('validation-partial'); 16 | 17 | var app = new BB.Marionette.Application(); 18 | 19 | app.user = null; 20 | 21 | app.addRegions({ 22 | appRegion: '#content', 23 | navRegion: '#nav', 24 | modalRegion: '#modal' 25 | }); 26 | 27 | // initialize breadcrumb navigation 28 | app.nav = new Breadcrumb(); 29 | 30 | app.on('before:start', function() { 31 | app.navRegion.show(app.nav); 32 | 33 | // set up the name 34 | $('#appName').text(Messages('app.name')); 35 | 36 | $('#logout').text(Messages('app.logout')) 37 | .click(function(e) { 38 | e.preventDefault(); 39 | $.ajax({ 40 | url: 'logout', 41 | }).done(function(data) { 42 | if (data.status == 'logged_out') { 43 | $('#logout').addClass("hidden"); 44 | $('#logged-in-user').text(''); 45 | $('#manageUsers').addClass('hidden'); 46 | $('#myAccount').addClass('hidden'); 47 | window.location.hash = '#login'; 48 | } 49 | }); 50 | }); 51 | 52 | $('#manageUsers').text(window.Messages("app.user.manage-users")); 53 | $('#myAccount').text(window.Messages("app.user.my-account")); 54 | }); 55 | 56 | module.exports = app; 57 | -------------------------------------------------------------------------------- /public/client/application/component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "application", 3 | "dependencies": { 4 | "components/bootstrap": "3.3.2", 5 | "components/handlebars.js": "*", 6 | "es-shims/es5-shim": "*", 7 | "es-shims/es6-shim": "0.34.2" 8 | }, 9 | "scripts": [ 10 | "application.js" 11 | ], 12 | "local": [ 13 | "bb", 14 | "date-render-helper", 15 | "translate-helper", 16 | "class-helper", 17 | "logic-helper", 18 | "breadcrumb-nav", 19 | "text-helper", 20 | "admin-helper", 21 | "validation-partial" 22 | ], 23 | "styles": [ 24 | "application.css" 25 | ] 26 | } -------------------------------------------------------------------------------- /public/client/autologin-route/autologin-route.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Automatically log in a user with a userId and key, so they can view/upload to a feedsource. 3 | */ 4 | 5 | var app = require('application'); 6 | 7 | module.exports = function() { 8 | var feedSourceId, feedVersionId, userId, key; 9 | 10 | // yes, this is in fact four arguments, not five, but the Bootstrap router throws an extra null on the end 11 | if (arguments.length == 5) { 12 | feedSourceId = arguments[0]; 13 | feedVersionId = arguments[1]; 14 | userId = arguments[2]; 15 | key = arguments[3]; 16 | } else if (arguments.length == 4) { 17 | feedSourceId = arguments[0]; 18 | feedVersionId = null; 19 | userId = arguments[1]; 20 | key = arguments[2]; 21 | } else return; 22 | 23 | $.post('/authenticate', { 24 | userId: userId, 25 | key: key 26 | }) 27 | .then(function(data) { 28 | $('#logged-in-user').text(window.Messages('app.account.logged_in_as', data['username'])); 29 | $('#logout').removeClass('hidden'); 30 | 31 | // note: log out is handled in application.js 32 | 33 | app.user = data; 34 | 35 | window.location.hash = '#feed/' + feedSourceId + 36 | (feedVersionId != null ? '/' + feedVersionId : ''); 37 | }) 38 | .fail(function() { 39 | // TODO: alert is bad, bad error message, not translatable. 40 | alert('Invalid key'); 41 | }); 42 | } 43 | -------------------------------------------------------------------------------- /public/client/autologin-route/component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "autologin-route", 3 | "description": "Automatically log a user in with a key and userId", 4 | "local": ["application"], 5 | "main": "autologin-route.js", 6 | "scripts": ["autologin-route.js"] 7 | } 8 | -------------------------------------------------------------------------------- /public/client/bb/component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bb", 3 | "dependencies": { 4 | "components/jquery": "1.11.2", 5 | "jashkenas/backbone": "*", 6 | "marionettejs/backbone.marionette": "*" 7 | }, 8 | "scripts": [ 9 | "index.js" 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /public/client/bb/index.js: -------------------------------------------------------------------------------- 1 | var Backbone = require('backbone'); 2 | 3 | Backbone.$ = window.jQuery = window.$ = require('jquery'); 4 | Backbone.Marionette = require('backbone.marionette'); 5 | 6 | module.exports = Backbone; 7 | -------------------------------------------------------------------------------- /public/client/breadcrumb-nav/breadcrumb-nav.html: -------------------------------------------------------------------------------- 1 | {{#each location}} 2 |
  • {{name}}
  • 3 | {{/each}} 4 | -------------------------------------------------------------------------------- /public/client/breadcrumb-nav/breadcrumb-nav.js: -------------------------------------------------------------------------------- 1 | // Breadcrumb nav for the site 2 | 3 | var BB = require('bb'); 4 | var _ = require('underscore'); 5 | var Handlebars = require('handlebars'); 6 | 7 | // this is just a backbone view; we don't need the machinery of models here 8 | module.exports = BB.View.extend({ 9 | template: Handlebars.compile(require('./breadcrumb-nav.html')), 10 | tagName: 'ol', 11 | className: 'breadcrumb', 12 | 13 | /** 14 | * call this with a list (representing hierarchy) of hashes with href and name 15 | */ 16 | setLocation: function(location) { 17 | // home is implied 18 | var mod = [{ 19 | name: Messages('app.location.home'), 20 | href: '#' 21 | }]; 22 | 23 | _.each(location, function(val) { 24 | mod.push(val); 25 | }); 26 | 27 | if (mod.length === 2 && mod[1].href === '#login') 28 | this.$el.addClass('hidden'); 29 | else 30 | this.$el.removeClass('hidden'); 31 | 32 | this.$el.empty().append(this.template({ 33 | location: mod 34 | })); 35 | 36 | $('head > title').text(Messages('app.title', mod[mod.length - 1].name)); 37 | } 38 | }); 39 | -------------------------------------------------------------------------------- /public/client/breadcrumb-nav/component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "breadcrumb-nav", 3 | "description": "the breadcrumb nav component. also manages page title", 4 | "dependencies": { 5 | "jashkenas/underscore": "*", 6 | "components/handlebars.js": "*" 7 | }, 8 | "local": [ 9 | "bb" 10 | ], 11 | "main": "breadcrumb-nav.js", 12 | "scripts": ["breadcrumb-nav.js"], 13 | "templates": ["breadcrumb-nav.html"] 14 | } 15 | -------------------------------------------------------------------------------- /public/client/class-helper/class-helper.js: -------------------------------------------------------------------------------- 1 | require('./getClassForStartDate.js'); 2 | require('./getClassForEndDate.js'); 3 | require('./highlightZero.js'); 4 | -------------------------------------------------------------------------------- /public/client/class-helper/component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "class-helper", 3 | "description": "Get classes for different elements of the data manager", 4 | "dependencies": { 5 | "components/handlebars.js": "*" 6 | }, 7 | "main": "class-helper.js", 8 | "scripts": [ 9 | "class-helper.js", 10 | "getClassForStartDate.js", 11 | "getClassForEndDate.js", 12 | "highlightZero.js" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /public/client/class-helper/getClassForEndDate.js: -------------------------------------------------------------------------------- 1 | // highlight in red if past, yellow if within two weeks 2 | 3 | var Handlebars = require('handlebars'); 4 | 5 | Handlebars.registerHelper( 6 | 'getClassForEndDate', 7 | function(date) { 8 | var daysToExpiration = (date - new Date().getTime()) / (60 * 60 * 24 * 1000); 9 | 10 | if (daysToExpiration > 14) { 11 | return ''; 12 | } else if (daysToExpiration >= 0) { 13 | return 'bg-warning'; 14 | } else return 'bg-danger'; 15 | } 16 | ); 17 | -------------------------------------------------------------------------------- /public/client/class-helper/getClassForStartDate.js: -------------------------------------------------------------------------------- 1 | // highlight start dates in the future in red 2 | var Handlebars = require('handlebars'); 3 | 4 | Handlebars.registerHelper( 5 | 'getClassForStartDate', 6 | function(date) { 7 | if (new Date().getTime() > date >= 0) 8 | return ''; 9 | else return 'bg-danger'; 10 | } 11 | ); 12 | -------------------------------------------------------------------------------- /public/client/class-helper/highlightZero.js: -------------------------------------------------------------------------------- 1 | // return a class to highlight something that equals zero 2 | 3 | var Handlebars = require('handlebars'); 4 | 5 | Handlebars.registerHelper( 6 | 'highlightZero', 7 | function(value) { 8 | return value == 0 ? 'bg-danger' : ''; 9 | } 10 | ); 11 | -------------------------------------------------------------------------------- /public/client/composite-view/component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "composite-view", 3 | "local": [ 4 | "bb", 5 | "templater" 6 | ], 7 | "scripts": [ 8 | "index.js" 9 | ] 10 | } -------------------------------------------------------------------------------- /public/client/composite-view/index.js: -------------------------------------------------------------------------------- 1 | var BB = require('bb'); 2 | var Templater = require('templater'); 3 | 4 | module.exports = BB.Marionette.CompositeView.extend({ 5 | onBeforeRender: function() { 6 | if (this.template && typeof this.template === 'string') 7 | this.template = Templater.compile(this.template); 8 | } 9 | }); 10 | -------------------------------------------------------------------------------- /public/client/confirm-view/component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "confirm-view", 3 | "description": "Ask the user if they want to proceed", 4 | "dependencies": { 5 | "jashkenas/underscore": "*" 6 | }, 7 | "local": [ 8 | "bb", 9 | "item-view" 10 | ], 11 | "scripts": ["confirm-view.js"], 12 | "templates": ["confirm-view.html"] 13 | } 14 | -------------------------------------------------------------------------------- /public/client/confirm-view/confirm-view.html: -------------------------------------------------------------------------------- 1 | 21 | -------------------------------------------------------------------------------- /public/client/confirm-view/confirm-view.js: -------------------------------------------------------------------------------- 1 | var BB = require('bb'); 2 | var ItemView = require('item-view'); 3 | var _ = require('underscore'); 4 | 5 | /** 6 | * usage: new ConfirmView({title: text, body: text, [onProceed: function,] [onCancel: function,]}) 7 | */ 8 | module.exports = ItemView.extend({ 9 | template: require('./confirm-view.html'), 10 | 11 | events: { 12 | 'click .cancel-action': 'onCancel', 13 | 'click .proceed-action': 'onProceed' 14 | }, 15 | 16 | initialize: function(attr) { 17 | this.model = new BB.Model({ 18 | title: attr.title, 19 | body: attr.body 20 | }); 21 | 22 | this.onCancel = !_.isUndefined(attr.onCancel) ? attr.onCancel : function() {}; 23 | this.onProceed = !_.isUndefined(attr.onProceed) ? attr.onProceed : function() {}; 24 | }, 25 | 26 | onShow: function() { 27 | this.$el.find('.modal').modal(); 28 | } 29 | }); 30 | -------------------------------------------------------------------------------- /public/client/date-render-helper/component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "date-render-helper", 3 | "description": "Handlebars helpers for rendering a pretty date", 4 | "dependencies": { 5 | "components/handlebars.js": "*", 6 | "moment/moment": "*" 7 | }, 8 | "main": "date-render-helper.js", 9 | "scripts": ["date-render-helper.js"] 10 | } 11 | -------------------------------------------------------------------------------- /public/client/date-render-helper/date-render-helper.js: -------------------------------------------------------------------------------- 1 | // a helper to render a date in milliseconds since epoch as something a normal 2 | // human can understand 3 | 4 | var Handlebars = require('handlebars'); 5 | var moment = require('moment'); 6 | 7 | /** 8 | * Parameters: the date in milliseconds since epoch 9 | * whether to include the time, or just the date (default: include time) 10 | */ 11 | Handlebars.registerHelper( 12 | 'dateRender', 13 | function(date, includeTime) { 14 | if (date === 0 || date === null) 15 | return '-'; 16 | 17 | var m = moment.utc(date); 18 | 19 | return new Handlebars.SafeString( 20 | '' + 21 | Handlebars.escapeExpression(m.format(window.Messages('app.date_format'))) + ' (' + 22 | Handlebars.escapeExpression(m.fromNow()) + 23 | ')'); 24 | } 25 | ); 26 | -------------------------------------------------------------------------------- /public/client/deployment-collection-route/component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "deployment-collection-route", 3 | "dependencies": { 4 | "jashkenas/underscore": "*" 5 | }, 6 | "local": ["feed-collection", "deployment-collection", "deployment-collection-view", "application"], 7 | "main": "deployment-collection-route.js", 8 | "scripts": ["deployment-collection-route.js"] 9 | } 10 | -------------------------------------------------------------------------------- /public/client/deployment-collection-route/deployment-collection-route.js: -------------------------------------------------------------------------------- 1 | var app = require('application'); 2 | var DeploymentCollection = require('deployment-collection'); 3 | var DeploymentCollectionView = require('deployment-collection-view'); 4 | var FeedCollection = require('feed-collection'); 5 | var _ = require('underscore'); 6 | 7 | module.exports = function(feedCollectionId) { 8 | var d = new DeploymentCollection(); 9 | var dDf = d.fetch({ 10 | data: { 11 | feedCollection: feedCollectionId 12 | } 13 | }); 14 | 15 | var fc = new FeedCollection({ 16 | id: feedCollectionId 17 | }); 18 | var fcDf = fc.fetch(); 19 | 20 | $.when(dDf, fcDf).done(function() { 21 | d = d.filter(function(deployment) { 22 | var fsId = deployment.get('feedSourceId'); 23 | return fsId === null || _.isUndefined(fsId); 24 | }); 25 | 26 | d = new DeploymentCollection(d); 27 | 28 | app.appRegion.show(new DeploymentCollectionView({ 29 | collection: d, 30 | model: fc 31 | })); 32 | 33 | // nav 34 | app.nav.setLocation([{ 35 | name: fc.get('name'), 36 | href: '#overview/' + fc.get('id') 37 | }, { 38 | name: window.Messages('app.deployment.deployments'), 39 | href: '#deployments' 40 | }]); 41 | }); 42 | }; 43 | -------------------------------------------------------------------------------- /public/client/deployment-collection-view/component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "deployment-collection-view", 3 | "dependencies": { 4 | "jashkenas/underscore": "*" 5 | }, 6 | "local": ["composite-view", "deployment", "item-view"], 7 | "scripts": ["deployment-collection-view.js"], 8 | "templates": ["deployment-collection-view.html", "deployment-item-view.html"] 9 | } 10 | -------------------------------------------------------------------------------- /public/client/deployment-collection-view/deployment-collection-view.html: -------------------------------------------------------------------------------- 1 |

    2 | 5 |

    6 | 7 |
    8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
    {{ t 'app.deployment.name' }}{{ t 'app.deployment.creation_date' }}{{ t 'app.deployment.number_of_feeds' }}
    16 |
    17 | -------------------------------------------------------------------------------- /public/client/deployment-collection-view/deployment-collection-view.js: -------------------------------------------------------------------------------- 1 | var CompositeView = require('composite-view'); 2 | var Deployment = require('deployment'); 3 | var ItemView = require('item-view'); 4 | var _ = require('underscore'); 5 | 6 | var DeploymentItemView = ItemView.extend({ 7 | tagName: 'tr', 8 | template: require('./deployment-item-view.html') 9 | }); 10 | 11 | module.exports = CompositeView.extend({ 12 | template: require('./deployment-collection-view.html'), 13 | childView: DeploymentItemView, 14 | childViewContainer: 'tbody', 15 | 16 | events: { 17 | 'click .new-deployment': 'deploy' 18 | }, 19 | 20 | initialize: function() { 21 | _.bindAll(this, 'deploy'); 22 | }, 23 | 24 | /** 25 | * Create a new deployment of this feedcollection 26 | */ 27 | deploy: function() { 28 | var now = new Date(); 29 | 30 | var date = String(now.getFullYear()); 31 | date += String(now.getMonth() + 1 < 10 ? '0' + (now.getMonth() + 1) : now.getMonth() + 1); 32 | date += String(now.getDate() < 10 ? '0' + now.getDate() : now.getDate()); 33 | 34 | var d = new Deployment({ 35 | feedCollection: { 36 | id: this.model.id 37 | }, 38 | name: this.model.get('name').toLowerCase().replace(/ /g, '-').replace(/[^a-z0-9-]/g, '') + '-' + date 39 | }); 40 | d.save().done(function() { 41 | window.location.hash = '#deployment/' + d.id; 42 | }); 43 | } 44 | }); 45 | -------------------------------------------------------------------------------- /public/client/deployment-collection-view/deployment-item-view.html: -------------------------------------------------------------------------------- 1 | 2 | {{ name }} 3 | {{#if (neq deployedTo null)}} 4 | {{ deployedTo }} 5 | {{/if}} 6 | 7 | 8 | {{ dateRender dateCreated t }} 9 | 10 | 11 | {{ feedVersions.length }} 12 | 13 | 14 | {{!-- TODO: deployment status --}} 15 | -------------------------------------------------------------------------------- /public/client/deployment-collection/component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "deployment-collection", 3 | "local": ["bb", "deployment"], 4 | "main": "deployment-collection.js", 5 | "scripts": ["deployment-collection.js"] 6 | } 7 | -------------------------------------------------------------------------------- /public/client/deployment-collection/deployment-collection.js: -------------------------------------------------------------------------------- 1 | var BB = require('bb'); 2 | var Deployment = require('deployment'); 3 | 4 | module.exports = BB.Collection.extend({ 5 | model: Deployment, 6 | url: 'api/deployments', 7 | // reverse-sort by date created 8 | comparator: function(d) { 9 | return -d.get('dateCreated'); 10 | } 11 | }); 12 | -------------------------------------------------------------------------------- /public/client/deployment-progress-view/component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "deployment-progress-view", 3 | "description": "show the progress of a deployment", 4 | "dependencies": { 5 | "jashkenas/underscore": "*" 6 | }, 7 | "local": [ 8 | "bb", 9 | "item-view" 10 | ], 11 | "main": "deployment-progress-view.js", 12 | "scripts": ["deployment-progress-view.js"], 13 | "templates": ["deployment-progress-view.html"] 14 | } 15 | -------------------------------------------------------------------------------- /public/client/deployment-progress-view/deployment-progress-view.html: -------------------------------------------------------------------------------- 1 | 25 | -------------------------------------------------------------------------------- /public/client/deployment-route/component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "deployment-route", 3 | "description": "An overview of a deployment: what feeds are defined, &c.", 4 | "dependencies": { 5 | "components/handlebars.js": "*" 6 | }, 7 | "local": ["application", "deployment", "deployment-view", "application"], 8 | "scripts": ["deployment-route.js"] 9 | } 10 | -------------------------------------------------------------------------------- /public/client/deployment-route/deployment-route.js: -------------------------------------------------------------------------------- 1 | var app = require('application'); 2 | var Deployment = require('deployment'); 3 | var DeploymentView = require('deployment-view'); 4 | var Handlebars = require('handlebars.js'); 5 | 6 | module.exports = function(deploymentId) { 7 | var d = new Deployment({ 8 | id: deploymentId 9 | }); 10 | 11 | var targets; 12 | 13 | var tDf = $.ajax({ 14 | url: 'api/deployments/targets', 15 | success: function(data) { 16 | targets = data; 17 | } 18 | }); 19 | 20 | var depDf = d.fetch(); 21 | 22 | $.when(tDf, depDf).then(function() { 23 | app.appRegion.show(new DeploymentView({ 24 | model: d, 25 | targets: targets 26 | })); 27 | 28 | // nav 29 | app.nav.setLocation([{ 30 | name: d.get('feedCollection').name, 31 | href: '#overview/' + d.get('feedCollection').id 32 | }, { 33 | name: window.Messages('app.deployment.deployments'), 34 | href: '#deployments/' + d.get('feedCollection').id 35 | }, { 36 | name: d.get('name'), 37 | href: '#deployment/' + deploymentId 38 | }]); 39 | }); 40 | }; 41 | -------------------------------------------------------------------------------- /public/client/deployment-view/component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "deployment-view", 3 | "description": "show a single deployment", 4 | "dependencies": { 5 | "jashkenas/underscore": "*", 6 | "visionmedia/debug": "*" 7 | }, 8 | "local": ["bb", "composite-view", "feed-collection", "feed-version-collection", "feed-source-collection", "feed-source-collection-view", 9 | "feed-version", "editable-text-widget", "application", "confirm-view", "deployment-progress-view", "item-view" 10 | ], 11 | "main": "deployment-view.js", 12 | "scripts": ["deployment-view.js"], 13 | "templates": ["deployment-view.html", "feed-version-deployment-view.html"], 14 | "styles": ["deployment-view.css"] 15 | } 16 | -------------------------------------------------------------------------------- /public/client/deployment-view/deployment-view.css: -------------------------------------------------------------------------------- 1 | button.iconic { background: transparent; border: 0px } 2 | button[disabled].iconic { color: #ddd } 3 | -------------------------------------------------------------------------------- /public/client/deployment-view/deployment-view.html: -------------------------------------------------------------------------------- 1 | 20 | 21 |

    22 | 23 | {{#if (neq deployedTo null)}} 24 | {{ deployedTo }} 25 | {{/if}} 26 |

    27 | 28 |
    29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 |
    {{ t 'app.feed_source.name' }}{{ t 'app.feed_version.version' }}{{ t 'app.feed_version.date_retrieved' }}{{ t 'app.feed_version.loaded_successfully' }}{{ t 'app.feed_version.error_count' }}{{ t 'app.feed_version.route_count' }}{{ t 'app.feed_version.trip_count' }}{{ t 'app.feed_version.stop_times_count' }}{{ t 'app.feed_version.start_date' }}{{ t 'app.feed_version.end_date' }}
    45 |
    46 | 47 |

    {{ t 'app.deployment.invalid_feed_sources' }}

    48 | 49 |
    50 | -------------------------------------------------------------------------------- /public/client/deployment-view/feed-version-deployment-view.html: -------------------------------------------------------------------------------- 1 | {{ feedSource.name }} 2 | 3 | {{ t 'app.feed_version.version_number' version}} 4 | 5 | {{#if (neq nextVersionId null)}} 6 | 7 | 8 | 9 | {{t 'app.deployment.newer_version' }} 10 | 11 | {{/if}} 12 | 13 | 14 | {{ dateRender updated true }} 15 | 16 | {{#with validationResult}} 17 | {{> validationResult}} 18 | {{/with}} 19 | 20 | 21 | 22 | 27 | 28 | 33 | 34 | 39 | 40 | -------------------------------------------------------------------------------- /public/client/deployment/component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "deployment", 3 | "local": [ 4 | "bb" 5 | ], 6 | "main": "deployment.js", 7 | "scripts": ["deployment.js"] 8 | } 9 | -------------------------------------------------------------------------------- /public/client/deployment/deployment.js: -------------------------------------------------------------------------------- 1 | var BB = require('bb'); 2 | 3 | module.exports = BB.Model.extend({ 4 | defaults: { 5 | feedCollection: null, 6 | feedVersions: null, 7 | osmFileId: null, 8 | otpCommit: null, 9 | deployedTo: null 10 | }, 11 | urlRoot: 'api/deployments/' 12 | }); 13 | -------------------------------------------------------------------------------- /public/client/editable-text-widget/component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "editable-text-widget", 3 | "description": "An editable text widget for a model", 4 | "dependencies": { 5 | "jashkenas/underscore": "*" 6 | }, 7 | "local": [ 8 | "item-view" 9 | ], 10 | "main": "editable-text-widget.js", 11 | "scripts": ["editable-text-widget.js"], 12 | "templates": ["editable-text-widget.html"], 13 | "styles": ["editable-text-widget.css"] 14 | } 15 | -------------------------------------------------------------------------------- /public/client/editable-text-widget/editable-text-widget.css: -------------------------------------------------------------------------------- 1 | button.toggle-edit { background: transparent; border: 0px } 2 | -------------------------------------------------------------------------------- /public/client/editable-text-widget/editable-text-widget.html: -------------------------------------------------------------------------------- 1 | {{!-- TODO: 508 --}} 2 | {{ displayText }} 3 | 4 | 7 | -------------------------------------------------------------------------------- /public/client/editable-text-widget/editable-text-widget.js: -------------------------------------------------------------------------------- 1 | // represents an editable attribute of a model 2 | // each of these gets its own reference to the model, which is fine 3 | // Backbone will handle all the concurrent updates 4 | 5 | var ItemView = require('item-view'); 6 | var _ = require('underscore'); 7 | 8 | module.exports = ItemView.extend({ 9 | template: require('./editable-text-widget.html'), 10 | tagName: 'span', 11 | className: 'EditableText', 12 | events: { 13 | 'click .toggle-edit': 'edit' 14 | }, 15 | 16 | initialize: function(attr) { 17 | this.attribute = attr.attribute || this.attribute; 18 | this.maxWidth = attr.maxWidth; 19 | this.href = attr.href || this.href; 20 | 21 | _.bindAll(this, 'edit'); 22 | // keep track of whether the field is currently being edited or not 23 | this.editing = false; 24 | }, 25 | 26 | // toggle editing of the field 27 | edit: function(e) { 28 | this.$('.input').toggleClass('hidden'); 29 | 30 | this.$('.glyphicon').toggleClass('glyphicon-pencil').toggleClass('glyphicon-ok'); 31 | 32 | if (this.editing) { 33 | // save 34 | var attr = {}; 35 | attr[this.attribute] = this.$('input').val(); 36 | this.model.set(attr); 37 | 38 | var instance = this; 39 | this.model.save().done(function() { 40 | instance.render(); 41 | }); 42 | 43 | this.$('.label').text(Messages('app.save')); 44 | } else { 45 | this.$('.label').text(Messages('app.edit')); 46 | this.$('input').focus(); 47 | } 48 | 49 | this.editing = !this.editing; 50 | }, 51 | 52 | // we override serializeData because we need to get the text of a particular field, and the 53 | // view doesn't know which field that is 54 | serializeData: function() { 55 | var href; 56 | 57 | if (typeof this.href == "function") 58 | href = this.href(); 59 | 60 | else if (_.isUndefined(this.href)) 61 | href = '#'; 62 | 63 | else 64 | href = this.href; 65 | 66 | var text = this.model.get(this.attribute); 67 | 68 | if (!_.isUndefined(this.maxWidth) && !_.isNull(this.maxWidth) && !_.isNull(text) && text.length >= this.maxWidth) { 69 | text = text.slice(0, this.maxWidth - 1); 70 | text += '…'; 71 | } 72 | 73 | var value = this.model.isNew() ? '' : this.model.get(this.attribute); 74 | 75 | return { 76 | displayText: text, 77 | value: value, 78 | placeholder: text, 79 | href: href 80 | }; 81 | } 82 | }); 83 | -------------------------------------------------------------------------------- /public/client/editor-agency-view/component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "editor-agency-view", 3 | "dependencies": { 4 | "jashkenas/underscore": "*" 5 | }, 6 | "local": [ 7 | "item-view" 8 | ], 9 | "main": "editor-agency-view.js", 10 | "scripts": ["editor-agency-view.js"], 11 | "templates": ["editor-agency-view.html"] 12 | } 13 | -------------------------------------------------------------------------------- /public/client/editor-agency-view/editor-agency-view.html: -------------------------------------------------------------------------------- 1 | 2 | 9 | -------------------------------------------------------------------------------- /public/client/editor-agency-view/editor-agency-view.js: -------------------------------------------------------------------------------- 1 | var ItemView = require('item-view'); 2 | var _ = require('underscore'); 3 | 4 | module.exports = ItemView.extend({ 5 | template: require('./editor-agency-view.html'), 6 | 7 | events: { 8 | 'change .agency': 'changeAgency' 9 | }, 10 | 11 | initialize: function() { 12 | this.agencies = []; 13 | this.snapshots = []; 14 | var instance = this; 15 | 16 | if (module.exports.agencies === null) { 17 | module.exports.agencies = $.ajax({ 18 | url: 'api/feedcollections/geteditoragencies' 19 | }); 20 | } 21 | 22 | // even if it is already done, this will still get called 23 | module.exports.agencies.then(function(agencies) { 24 | instance.agencies = agencies; 25 | // this may trigger rendering more than once; oh well. 26 | instance.render(); 27 | }); 28 | 29 | _.bindAll(this, 'changeAgency'); 30 | }, 31 | 32 | onRender: function() { 33 | // select the appropriate agency 34 | this.$('.agency option[value="' + this.model.get('editorId') + '"]').prop('selected', true); 35 | }, 36 | 37 | changeAgency: function() { 38 | var newAgency = this.$('.agency').val(); 39 | this.model.set('editorId', newAgency); 40 | this.model.set('snapshotVersion', null); 41 | this.model.save(); 42 | }, 43 | 44 | serializeData: function() { 45 | return _.extend({ 46 | agencies: this.agencies 47 | }, this.model.toJSON()); 48 | } 49 | }); 50 | 51 | /** Cache the agencies */ 52 | module.exports.agencies = null; 53 | -------------------------------------------------------------------------------- /public/client/feed-branding-view/component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "feed-branding-view", 3 | "description": "The branding UI for a feed", 4 | "dependencies": { 5 | "components/handlebars.js": "*", 6 | "jashkenas/underscore": "*" 7 | }, 8 | "local": [ 9 | "application", 10 | "feed-version", 11 | "item-view" 12 | ], 13 | "scripts": ["feed-branding-view.js"], 14 | "templates": ["feed-branding-view.html"] 15 | } 16 | -------------------------------------------------------------------------------- /public/client/feed-branding-view/feed-branding-view.html: -------------------------------------------------------------------------------- 1 |

    Branding

    2 | 3 |
    4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | {{#each feedSource.latestValidation.agencies}} 12 | 13 | 14 | 21 | 29 | 30 | {{/each}} 31 | 32 |
    AgencyLogo
    {{ this }} 15 | {{#hasAgencyLogo this}} 16 | 17 | {{else}} 18 | (No Branding) 19 | {{/hasAgencyLogo}} 20 | 22 |
    23 | 24 | 25 | 26 |
    27 | 28 |
    33 |
    34 | -------------------------------------------------------------------------------- /public/client/feed-branding-view/feed-branding-view.js: -------------------------------------------------------------------------------- 1 | var ItemView = require('item-view'); 2 | var FeedVersion = require('feed-version'); 3 | var _ = require('underscore'); 4 | 5 | var Handlebars = require('handlebars'); 6 | 7 | module.exports = ItemView.extend({ 8 | template: require('./feed-branding-view.html'), 9 | 10 | events: { 11 | 'click .upload-button': 'upload', 12 | 'submit form': 'onSubmit' 13 | }, 14 | 15 | initialize: function(attr) { 16 | var self = this; 17 | 18 | if (_.isUndefined(this.model)) { 19 | // we create a dummy model simply so we don't have to check in the view if the model exists, only if its properties exist 20 | // and so we can access the feedSource in a uniform way regardless of whether the version exists 21 | this.model = new FeedVersion({ 22 | feedSource: attr.feedSource.toJSON() 23 | }); 24 | } 25 | 26 | 27 | Handlebars.registerHelper( 28 | 'hasAgencyLogo', 29 | function(agencyId, options) { 30 | var branding = self.getAgencyBranding(agencyId); 31 | if(branding !== null && branding.hasLogo) return options.fn(this); 32 | return options.inverse(this);; 33 | } 34 | ); 35 | 36 | Handlebars.registerHelper( 37 | 'getAgencyLogoUrl', 38 | function(agencyId, options) { 39 | var branding = self.getAgencyBranding(agencyId); 40 | if(branding !== null && branding.hasLogo) { 41 | return branding.urlRoot + '/' + encodeURIComponent(agencyId) + '/logo.png?' + Date.now(); 42 | } 43 | } 44 | ); 45 | 46 | }, 47 | 48 | getAgencyBranding: function(agencyId) { 49 | var retval = null; 50 | _.each(this.model.get('feedSource').branding, function(agencyBranding) { 51 | if(agencyBranding.agencyId == agencyId) { 52 | retval = agencyBranding; 53 | } 54 | }); 55 | return retval; 56 | }, 57 | 58 | onSubmit: function(evt) { 59 | var filename = evt.target[0].value; 60 | if(!filename || filename.toLowerCase().indexOf('.png', filename.length - 4) === -1) { 61 | alert('Must be a PNG file'); 62 | evt.preventDefault(); 63 | } 64 | } 65 | 66 | }); -------------------------------------------------------------------------------- /public/client/feed-collection-collection-view/component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "feed-collection-collection-view", 3 | "description": "show all of the feed collections", 4 | "dependencies": { 5 | "jashkenas/underscore": "*" 6 | }, 7 | "local": ["composite-view", "editable-text-widget", "feed-collection"], 8 | "main": "feed-collection-collection-view.js", 9 | "scripts": ["feed-collection-collection-view.js"], 10 | "templates": ["feed-collection-collection-view.html"] 11 | } 12 | -------------------------------------------------------------------------------- /public/client/feed-collection-collection-view/feed-collection-collection-view.html: -------------------------------------------------------------------------------- 1 |

    2 | 5 |

    6 | 7 |
      8 | -------------------------------------------------------------------------------- /public/client/feed-collection-collection-view/feed-collection-collection-view.js: -------------------------------------------------------------------------------- 1 | var CompositeView = require('composite-view'); 2 | var _ = require('underscore'); 3 | var FeedCollection = require('feed-collection'); 4 | var EditableTextWidget = require('editable-text-widget'); 5 | 6 | /** 7 | * An item view of a single FeedCollection 8 | */ 9 | var FeedCollectionItemView = EditableTextWidget.extend({ 10 | tagName: 'li', 11 | attribute: 'name', 12 | className: 'list-group-item', 13 | href: function() { 14 | return '#overview/' + this.model.get('id'); 15 | }, 16 | 17 | onShow: function() { 18 | if (typeof(EditableTextWidget.prototype.onShow) == 'function') 19 | EditableTextWidget.prototype.onShow.call(this); 20 | 21 | if (!this.model.get('id')) 22 | // new feed 23 | this.edit(); 24 | } 25 | }); 26 | 27 | /** 28 | * An editable view of a FeedCollectionCollection 29 | */ 30 | module.exports = CompositeView.extend({ 31 | template: require('./feed-collection-collection-view.html'), 32 | childView: FeedCollectionItemView, 33 | childViewContainer: 'ul', 34 | 35 | // set up event handlers 36 | events: { 37 | 'click .newfeedcoll': 'add' 38 | }, 39 | initialize: function() { 40 | _.bindAll(this, 'add'); 41 | }, 42 | 43 | /** Add an item to the collection */ 44 | add: function() { 45 | // note that this is not persisted to the server here; it won't be, until they change the name 46 | // this is by design 47 | this.collection.add(new FeedCollection({ 48 | name: window.Messages('app.new_feed_collection_name') 49 | })); 50 | } 51 | }); 52 | -------------------------------------------------------------------------------- /public/client/feed-collection-collection/component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "feed-collection-collection", 3 | "local": ["bb", "feed-collection"], 4 | "main": "feed-collection-collection.js", 5 | "scripts": ["feed-collection-collection.js"] 6 | } 7 | -------------------------------------------------------------------------------- /public/client/feed-collection-collection/feed-collection-collection.js: -------------------------------------------------------------------------------- 1 | // brought to you by your local department of redundancy department 2 | var BB = require('bb'); 3 | var FeedCollection = require('feed-collection'); 4 | 5 | module.exports = BB.Collection.extend({ 6 | model: FeedCollection, 7 | url: 'api/feedcollections', 8 | comparator: 'name' 9 | }); 10 | -------------------------------------------------------------------------------- /public/client/feed-collection-route/component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "feed-collection-route", 3 | "description": "An overview of a feed collection: what feeds are defined, &c.", 4 | "dependencies": { 5 | "jashkenas/underscore": "*" 6 | }, 7 | "local": ["application", "feed-collection", "feed-source-collection", "feed-source-collection-view", "layout-view"], 8 | "scripts": ["feed-collection-route.js"], 9 | "templates": ["feed-collection-route.html"] 10 | } 11 | -------------------------------------------------------------------------------- /public/client/feed-collection-route/feed-collection-route.html: -------------------------------------------------------------------------------- 1 | 2 |
      3 | -------------------------------------------------------------------------------- /public/client/feed-collection-route/feed-collection-route.js: -------------------------------------------------------------------------------- 1 | var app = require('application'); 2 | var FeedSourceCollection = require('feed-source-collection'); 3 | var FeedCollection = require('feed-collection'); 4 | var FeedSourceCollectionView = require('feed-source-collection-view'); 5 | var LayoutView = require('layout-view'); 6 | var _ = require('underscore'); 7 | 8 | var Overview = LayoutView.extend({ 9 | regions: { 10 | feedSourceRegion: '#feed-sources' 11 | }, 12 | template: require('./feed-collection-route.html'), 13 | 14 | initialize: function(attr) { 15 | this.feedCollectionId = attr.feedCollectionId; 16 | }, 17 | 18 | onShow: function() { 19 | var feedSources = new FeedSourceCollection(); 20 | var instance = this; 21 | feedSources.fetch({ 22 | data: { 23 | feedcollection: this.feedCollectionId 24 | } 25 | }).done(function() { 26 | instance.feedSourceRegion.show(new FeedSourceCollectionView({ 27 | collection: feedSources, 28 | feedCollectionId: instance.feedCollectionId 29 | })); 30 | }); 31 | 32 | var feedCollection = new FeedCollection({ 33 | id: this.feedCollectionId 34 | }); 35 | feedCollection.fetch().done(function() { 36 | app.nav.setLocation([{ 37 | name: feedCollection.get('name'), 38 | href: '#overview/' + feedCollection.get('id') 39 | }]); 40 | }); 41 | } 42 | }); 43 | 44 | module.exports = function(feedCollectionId) { 45 | app.appRegion.show(new Overview({ 46 | feedCollectionId: feedCollectionId 47 | })); 48 | } 49 | -------------------------------------------------------------------------------- /public/client/feed-collection/component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "feed-collection", 3 | "local": ["bb"], 4 | "main": "feed-collection.js", 5 | "scripts": ["feed-collection.js"] 6 | } 7 | -------------------------------------------------------------------------------- /public/client/feed-collection/feed-collection.js: -------------------------------------------------------------------------------- 1 | var BB = require('bb'); 2 | 3 | module.exports = BB.Model.extend({ 4 | defaults: { 5 | name: null, 6 | id: null, 7 | user: null, 8 | useCustomOsmBounds: null, 9 | osmWest: null, 10 | osmSouth: null, 11 | osmEast: null, 12 | osmNorth: null, 13 | buildConfig: null, 14 | routerConfig: null 15 | }, 16 | urlRoot: 'api/feedcollections/' 17 | }); 18 | -------------------------------------------------------------------------------- /public/client/feed-source-collection-view/component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "feed-source-collection-view", 3 | "dependencies": { 4 | "jashkenas/underscore": "*", 5 | "components/handlebars.js": "*" 6 | }, 7 | "local": [ 8 | "bb", 9 | "composite-view", 10 | "feed-source", 11 | "feed-source-item-view", 12 | "application", 13 | "ok-dialog-view", 14 | "confirm-view" 15 | ], 16 | "main": "feed-source-collection-view.js", 17 | "scripts": ["feed-source-collection-view.js"], 18 | "templates": [ 19 | "feed-source-collection-view.html", 20 | "fetch-all-feeds-results.html" 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /public/client/feed-source-collection-view/fetch-all-feeds-results.html: -------------------------------------------------------------------------------- 1 | {{#each this}} 2 |
      3 | {{@key}}: {{this}} 4 |
      5 | {{/each}} -------------------------------------------------------------------------------- /public/client/feed-source-collection/component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "feed-source-collection", 3 | "dependencies": { 4 | "jashkenas/underscore": "*" 5 | }, 6 | "local": ["bb", "feed-source"], 7 | "main": "feed-source-collection.js", 8 | "scripts": ["feed-source-collection.js"] 9 | } 10 | -------------------------------------------------------------------------------- /public/client/feed-source-collection/feed-source-collection.js: -------------------------------------------------------------------------------- 1 | var BB = require('bb'); 2 | var FeedSource = require('feed-source'); 3 | var _ = require('underscore'); 4 | 5 | module.exports = BB.Collection.extend({ 6 | model: FeedSource, 7 | url: 'api/feedsources', 8 | 9 | /** 10 | * Get a function to compare two feed sources by the specified attribute. 11 | */ 12 | comparator: function(fs1, fs2) { 13 | var attr = this.sortAttribute; 14 | 15 | var order = this.sortBackwards ? -1 : 1; 16 | 17 | var n1, n2; 18 | if (attr.indexOf('latestValidation.') === 0) { 19 | attr = attr.replace('latestValidation.', ''); 20 | 21 | var lv1 = fs1.get('latestValidation'); 22 | var lv2 = fs2.get('latestValidation'); 23 | 24 | n1 = _.isUndefined(lv1) || _.isNull(lv1) ? null : lv1[attr]; 25 | n2 = _.isUndefined(lv2) || _.isNull(lv2) ? null : lv2[attr]; 26 | } else { 27 | 28 | n1 = fs1.get(attr); 29 | n2 = fs2.get(attr); 30 | } 31 | 32 | if (n1 == n2) 33 | return 0; 34 | 35 | if (fs1.id == fs2.id) 36 | return 0; 37 | 38 | // sort the new ones at the top, regardless of sort order 39 | if (_.isUndefined(fs1.id) || _.isNull(fs1.id)) 40 | return -1; 41 | 42 | if (_.isUndefined(fs2.id) || _.isNull(fs2.id)) 43 | return 1; 44 | 45 | if (_.isUndefined(n1) || _.isNull(n1)) 46 | return order * -1; 47 | 48 | if (_.isUndefined(n2) || _.isNull(n2)) 49 | return order * 1; 50 | 51 | if (n1 < n2) 52 | return order * -1; 53 | 54 | else 55 | return order * 1; 56 | }, 57 | 58 | sortAttribute: 'name', 59 | sortBackwards: false 60 | }); 61 | -------------------------------------------------------------------------------- /public/client/feed-source-item-view/component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "feed-source-item-view", 3 | "dependencies": { 4 | "jashkenas/underscore": "*" 5 | }, 6 | "local": ["bb", "editable-text-widget", "confirm-view", "application", "editor-agency-view", "layout-view"], 7 | "main": "feed-source-item-view.js", 8 | "scripts": ["feed-source-item-view.js"], 9 | "templates": ["feed-source-item-view.html"], 10 | "styles": ["feed-source-item-view.css"] 11 | } 12 | -------------------------------------------------------------------------------- /public/client/feed-source-item-view/feed-source-item-view.css: -------------------------------------------------------------------------------- 1 | button.transparent-button { background: transparent; border: 0px } 2 | -------------------------------------------------------------------------------- /public/client/feed-source-item-view/feed-source-item-view.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 10 | 11 | 12 | {{ dateRender lastUpdated true }} 13 | 14 | {{#if (neq latestValidation null)}} 15 | {{#with latestValidation}} 16 | {{> validationResult }} 17 | {{/with}} 18 | {{else}} 19 | ------- 20 | {{/if}} 21 | 22 | 23 | 27 | 28 | -------------------------------------------------------------------------------- /public/client/feed-source-route/component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "feed-source-route", 3 | "description": "The route for showing a feed source.", 4 | "local": ["application", "feed-source", "feed-source-view"], 5 | "main": "feed-source-route.js", 6 | "scripts": ["feed-source-route.js"] 7 | } 8 | -------------------------------------------------------------------------------- /public/client/feed-source-route/feed-source-route.js: -------------------------------------------------------------------------------- 1 | var FeedSource = require('feed-source'); 2 | var FeedSourceView = require('feed-source-view'); 3 | var app = require('application'); 4 | 5 | module.exports = function(feedSourceId, feedVersionId) { 6 | var model = new FeedSource({ 7 | id: feedSourceId 8 | }); 9 | model.fetch().done(function() { 10 | app.appRegion.show(new FeedSourceView({ 11 | model: model, 12 | feedVersionId: feedVersionId 13 | })); 14 | }); 15 | }; 16 | -------------------------------------------------------------------------------- /public/client/feed-source-view/component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "feed-source-view", 3 | "description": "What is the status of a feed source: latest validation results, etc.", 4 | "dependencies": { 5 | "jashkenas/underscore": "*" 6 | }, 7 | "local": [ 8 | "application", 9 | "feed-version", 10 | "feed-version-collection", 11 | "feed-version-collection-view", 12 | "feed-version-view", 13 | "feed-branding-view", 14 | "note-collection-view", 15 | "feed-version-navigation-view", 16 | "layout-view" 17 | ], 18 | "scripts": ["feed-source-view.js"], 19 | "templates": ["feed-source-view.html"] 20 | } 21 | -------------------------------------------------------------------------------- /public/client/feed-source/component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "feed-source", 3 | "local": ["bb"], 4 | "main": "feed-source.js", 5 | "scripts": ["feed-source.js"] 6 | } 7 | -------------------------------------------------------------------------------- /public/client/feed-source/feed-source.js: -------------------------------------------------------------------------------- 1 | var BB = require('bb'); 2 | 3 | module.exports = BB.Model.extend({ 4 | defaults: { 5 | name: null, 6 | isPublic: false, 7 | deployable: false, 8 | retrievalMethod: null, 9 | lastFetched: null, 10 | lastUpdated: null, 11 | url: null, 12 | latest: null, 13 | feedCollection: null 14 | }, 15 | urlRoot: 'api/feedsources/' 16 | }); 17 | -------------------------------------------------------------------------------- /public/client/feed-upload-view/component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "feed-upload-view", 3 | "dependencies": { 4 | "jashkenas/underscore": "*" 5 | }, 6 | "local": ["item-view"], 7 | "main": "feed-upload-view.js", 8 | "scripts": ["feed-upload-view.js"], 9 | "templates": ["feed-upload-view.html"] 10 | } 11 | -------------------------------------------------------------------------------- /public/client/feed-upload-view/feed-upload-view.html: -------------------------------------------------------------------------------- 1 | 25 | -------------------------------------------------------------------------------- /public/client/feed-upload-view/feed-upload-view.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Upload a feed to the manager manually. 3 | */ 4 | 5 | var ItemView = require('item-view'); 6 | 7 | module.exports = ItemView.extend({ 8 | template: require('./feed-upload-view.html'), 9 | onShow: function() { 10 | this.$('.modal').modal(); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /public/client/feed-upload-view/views.js: -------------------------------------------------------------------------------- 1 | var _ = require('underscore'); 2 | 3 | _.extend(module.exports, require('./FeedVersion.js')); 4 | _.extend(module.exports, require('./FeedUpload.js')); 5 | -------------------------------------------------------------------------------- /public/client/feed-version-collection-route/component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "feed-version-collection-route", 3 | "description": "The route for showing all feed versions for a feed source.", 4 | "local": ["application", "feed-version-collection", "feed-version-collection-view"], 5 | "main": "feed-version-collection-route.js", 6 | "scripts": ["feed-version-collection-route.js"] 7 | } 8 | -------------------------------------------------------------------------------- /public/client/feed-version-collection-route/feed-version-collection-route.js: -------------------------------------------------------------------------------- 1 | var FeedVersionCollection = require('feed-version-collection'); 2 | var FeedVersionCollectionView = require('feed-version-collection-view'); 3 | var app = require('application'); 4 | 5 | module.exports = function(feedSourceId) { 6 | // get the data 7 | var versions = new FeedVersionCollection(); 8 | var instance = this; 9 | versions.fetch({ 10 | data: { 11 | feedsource: feedSourceId 12 | } 13 | }).done(function() { 14 | app.appRegion.show(new FeedVersionCollectionView({ 15 | collection: versions 16 | })); 17 | }); 18 | }; 19 | -------------------------------------------------------------------------------- /public/client/feed-version-collection-view/component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "feed-version-collection-view", 3 | "local": ["composite-view", "feed-source", "feed-version", "application", "item-view"], 4 | "main": "feed-version-collection-view.js", 5 | "scripts": ["feed-version-collection-view.js"], 6 | "templates": ["feed-version-collection-view.html", "feed-version-item-view.html"] 7 | } 8 | -------------------------------------------------------------------------------- /public/client/feed-version-collection-view/feed-version-collection-view.html: -------------------------------------------------------------------------------- 1 |

      {{ name }}

      2 | 3 |
      4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
      {{ t 'app.feed_version.version' }}{{ t 'app.feed_version.date_retrieved' }}{{ t 'app.feed_version.loaded_successfully' }}{{ t 'app.feed_version.error_count' }}{{ t 'app.feed_version.route_count' }}{{ t 'app.feed_version.trip_count' }}{{ t 'app.feed_version.stop_times_count' }}{{ t 'app.feed_version.start_date' }}{{ t 'app.feed_version.end_date' }}
      18 |
      19 | -------------------------------------------------------------------------------- /public/client/feed-version-collection-view/feed-version-collection-view.js: -------------------------------------------------------------------------------- 1 | // A list of FeedVersions for a particular FeedSource 2 | 3 | var app = require('application'); 4 | var CompositeView = require('composite-view'); 5 | var FeedSource = require('feed-source'); 6 | var ItemView = require('item-view'); 7 | 8 | var FeedVersionItemView = ItemView.extend({ 9 | template: require('./feed-version-item-view.html'), 10 | tagName: 'tr' 11 | }); 12 | 13 | module.exports = CompositeView.extend({ 14 | childView: FeedVersionItemView, 15 | childViewContainer: 'tbody', 16 | template: require('./feed-version-collection-view.html'), 17 | 18 | initialize: function() { 19 | // extract the feed source 20 | this.model = new FeedSource(this.collection.at(0).get('feedSource')); 21 | }, 22 | 23 | onShow: function() { 24 | app.nav.setLocation([{ 25 | name: this.collection.at(0).get('feedSource').feedCollection.name, 26 | href: '#overview/' + this.collection.at(0).get('feedSource').feedCollection.id 27 | }, { 28 | name: this.collection.at(0).get('feedSource').name, 29 | href: '#feed/' + this.collection.at(0).get('feedSource').id 30 | }, { 31 | name: window.Messages('app.feed_version.versions'), 32 | href: '#versions/' + this.collection.at(0).get('feedSource').id 33 | }]); 34 | } 35 | }); 36 | -------------------------------------------------------------------------------- /public/client/feed-version-collection-view/feed-version-item-view.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | {{ t 'app.feed_version.version_number' version }} 4 | 5 | 6 | {{ dateRender updated true }} 7 | 8 | {{#with validationResult}} 9 | {{> validationResult}} 10 | {{/with}} 11 | -------------------------------------------------------------------------------- /public/client/feed-version-collection/component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "feed-version-collection", 3 | "local": ["bb", "feed-version"], 4 | "main": "feed-version-collection.js", 5 | "scripts": ["feed-version-collection.js"] 6 | } 7 | -------------------------------------------------------------------------------- /public/client/feed-version-collection/feed-version-collection.js: -------------------------------------------------------------------------------- 1 | var BB = require('bb'); 2 | var FeedVersion = require('feed-version'); 3 | 4 | module.exports = BB.Collection.extend({ 5 | model: FeedVersion, 6 | url: 'api/feedversions', 7 | // sort by name, then reverse-sort by version 8 | comparator: function(model0, model1) { 9 | if (model0.get('feedSource').name < model1.get('feedSource').name) 10 | return -1; 11 | else if (model0.get('feedSource').name > model1.get('feedSource').name) 12 | return 1; 13 | 14 | // names are the same, sort by version 15 | return model1.get('version') - model0.get('version'); 16 | } 17 | }); 18 | -------------------------------------------------------------------------------- /public/client/feed-version-navigation-view/component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "feed-version-navigation-view", 3 | "description": "show navigation between feed versions", 4 | "dependencies": { 5 | "jashkenas/underscore": "*" 6 | }, 7 | "local": ["application", "feed-version", "feed-source", "feed-upload-view", "layout-view", "ok-dialog-view"], 8 | "main": "feed-version-navigation-view.js", 9 | "scripts": ["feed-version-navigation-view.js"], 10 | "templates": ["feed-version-navigation-view.html"] 11 | } 12 | -------------------------------------------------------------------------------- /public/client/feed-version-navigation-view/feed-version-navigation-view.html: -------------------------------------------------------------------------------- 1 |

      {{ t 'app.feed_version.version_number' version }} 2 |
      3 | 4 |   {{ t 'app.feed_version.previous_version' }} 5 | 6 | 13 | 14 |   {{ t 'app.feed_version.show_all_versions' }} 15 | 16 | 17 |   {{ t 'app.feed_version.download_gtfs' }} 18 | 19 | {{#if (eq feedSource.retrievalMethod 'MANUALLY_UPLOADED')}} 20 | 23 | {{else}} 24 | 27 | {{/if}} 28 | 29 | {{ t 'app.feed_version.next_version' }}   30 |
      31 |

      32 | -------------------------------------------------------------------------------- /public/client/feed-version-view/component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "feed-version-view", 3 | "description": "show a single feed version", 4 | "dependencies": { 5 | "jashkenas/underscore": "*" 6 | }, 7 | "local": ["application", "bb", "feed-version", "note-collection-view", "feed-upload-view", "feed-source", "item-view", "layout-view"], 8 | "main": "feed-version-view.js", 9 | "scripts": ["feed-version-view.js"], 10 | "templates": ["feed-version-view.html", "invalid-values-list.html"] 11 | } 12 | -------------------------------------------------------------------------------- /public/client/feed-version-view/feed-version-view.html: -------------------------------------------------------------------------------- 1 | {{#if (neq validationResult null)}} 2 |
      3 | 4 | 5 | {{#with validationResult}} 6 | 7 | {{#if (eq loadStatus 'SUCCESS') }} 8 | 9 | 10 | 11 | 12 | 13 | 14 | {{!-- if the stop times count is 0, then there are no service dates, so if we did not suppress them we would see Dec 31 1969 19:00:00 -0500 --}} 15 | {{#if (gt stopTimesCount 0) }} 16 | 21 | 22 | {{else}} 23 | 24 | {{/if}} 25 | 26 | 27 | {{else}} 28 | 29 | {{/if}} 30 | {{/with}} 31 | 32 |
      {{ t 'app.feed_version.load_status' }}{{ loadStatus }}
      {{ t 'app.feed_version.agency_count' }}{{ agencyCount }}
      {{ t 'app.feed_version.route_count' }}{{ routeCount }}
      {{ t 'app.feed_version.trip_count' }}{{ tripCount }}
      {{ t 'app.feed_version.stop_times_count' }}{{ stopTimesCount }}
      Service Range 17 |
      {{ dateRender startDate false }}
      18 | {{ t 'app.feed_version.to' }} 19 |
      {{ dateRender endDate false }}
      20 |
      -
      {{ t 'app.feed_version.reason' }}{{ loadFailureReason }}
      33 |
      34 | {{/if}} 35 | 36 |
      37 |
      38 |
      39 |
      40 |
      41 |
      42 | 43 |

      {{ t 'app.note.version_notes' }}

      44 |

      45 | -------------------------------------------------------------------------------- /public/client/feed-version-view/invalid-values-list.html: -------------------------------------------------------------------------------- 1 |

      {{title}}

      2 | {{#each errors}} 3 |
      4 | 11 |
      12 | 13 | 14 | 15 | 16 | 17 | 18 | {{#if ../showRoute}}{{/if}} 19 | 20 | 21 | {{!-- this is a list, with some extra properties (e.g. name) --}} 22 | {{#each this}} 23 | 24 | 25 | 26 | 27 | 28 | {{#if ../../showRoute}}{{/if}} 29 | 30 | {{/each}} 31 | 32 |
      {{ t 'app.feed_version.problem_type' }}{{ t 'app.feed_version.affected_entity' }}{{ t 'app.feed_version.affected_field' }}{{ t 'app.feed_version.description' }}{{ t 'app.feed_version.route' }}
      {{ problemType }}{{ affectedEntity }}{{ affectedField }}{{ problemDescription }}{{ route_name }}
      33 |
      34 |
      35 | {{/each}} -------------------------------------------------------------------------------- /public/client/feed-version/component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "feed-version", 3 | "dependencies": { 4 | "jashkenas/underscore": "*" 5 | }, 6 | "local": ["bb"], 7 | "main": "feed-version.js", 8 | "scripts": ["feed-version.js"] 9 | } 10 | -------------------------------------------------------------------------------- /public/client/feed-version/feed-version.js: -------------------------------------------------------------------------------- 1 | /* 2 | * A model representing a feed version 3 | */ 4 | 5 | var BB = require('bb'); 6 | var _ = require('underscore'); 7 | 8 | module.exports = BB.Model.extend({ 9 | defaults: { 10 | id: null, 11 | feedSource: null, 12 | user: null, 13 | notes: null, 14 | validationResults: null, 15 | updated: null, 16 | version: null 17 | }, 18 | urlRoot: 'api/feedversions/', 19 | 20 | change: function() { 21 | var vr = this.get('validationResult'); 22 | 23 | if (!_.isUndefined(vr) && _.isUndefined(vr.errorCount)) { 24 | vr.errorCount = 0; 25 | try { 26 | vr.errorCount += vr.routes.invalidValues.length; 27 | } catch (e) {} 28 | try { 29 | vr.errorCount += vr.stops.invalidValues.length; 30 | } catch (e) {} 31 | try { 32 | vr.errorCount += vr.shapes.invalidValues.length; 33 | } catch (e) {} 34 | try { 35 | vr.errorCount += vr.trips.invalidValues.length; 36 | } catch (e) {} 37 | 38 | this.set('validationResult', vr); 39 | } 40 | }, 41 | 42 | initialize: function() { 43 | _.bindAll(this, 'change'); 44 | this.on('add', this.change); 45 | this.change(); 46 | } 47 | }); 48 | -------------------------------------------------------------------------------- /public/client/item-view/component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "item-view", 3 | "local": [ 4 | "bb", 5 | "templater" 6 | ], 7 | "scripts": [ 8 | "index.js" 9 | ] 10 | } -------------------------------------------------------------------------------- /public/client/item-view/index.js: -------------------------------------------------------------------------------- 1 | var BB = require('bb'); 2 | var Templater = require('templater'); 3 | 4 | module.exports = BB.Marionette.ItemView.extend({ 5 | onBeforeRender: function() { 6 | if (this.template && typeof this.template === 'string') 7 | this.template = Templater.compile(this.template); 8 | } 9 | }); 10 | -------------------------------------------------------------------------------- /public/client/layout-view/component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "layout-view", 3 | "local": [ 4 | "bb", 5 | "templater" 6 | ], 7 | "scripts": [ 8 | "index.js" 9 | ] 10 | } -------------------------------------------------------------------------------- /public/client/layout-view/index.js: -------------------------------------------------------------------------------- 1 | var BB = require('bb'); 2 | var Templater = require('templater'); 3 | 4 | module.exports = BB.Marionette.LayoutView.extend({ 5 | onBeforeRender: function() { 6 | if (this.template && typeof this.template === 'string') 7 | this.template = Templater.compile(this.template); 8 | } 9 | }); 10 | -------------------------------------------------------------------------------- /public/client/logic-helper/and.js: -------------------------------------------------------------------------------- 1 | // and for handlebars if statements 2 | 3 | var Handlebars = require('handlebars'); 4 | var _ = require('underscore'); 5 | 6 | Handlebars.registerHelper( 7 | 'and', 8 | function() { 9 | return _.reduce(arguments, function(val, memo) { 10 | return val && memo; 11 | }); 12 | } 13 | ); 14 | -------------------------------------------------------------------------------- /public/client/logic-helper/component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "logic-helper", 3 | "description": "Add logic to handlebars", 4 | "dependencies": { 5 | "jashkenas/underscore": "*", 6 | "components/handlebars.js": "*" 7 | }, 8 | "main": "logic-helper.js", 9 | "scripts": [ 10 | "logic-helper.js", 11 | "ternary.js", 12 | "eq.js", 13 | "neq.js", 14 | "gt.js", 15 | "and.js" 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /public/client/logic-helper/eq.js: -------------------------------------------------------------------------------- 1 | // equality, for use with handlebars if statements 2 | 3 | var Handlebars = require('handlebars'); 4 | 5 | Handlebars.registerHelper( 6 | 'eq', 7 | function(v1, v2) { 8 | return v1 == v2; 9 | } 10 | ); 11 | -------------------------------------------------------------------------------- /public/client/logic-helper/gt.js: -------------------------------------------------------------------------------- 1 | // greater than 2 | 3 | var Handlebars = require('handlebars'); 4 | 5 | Handlebars.registerHelper( 6 | 'gt', 7 | function(v1, v2) { 8 | return v1 > v2; 9 | } 10 | ); 11 | -------------------------------------------------------------------------------- /public/client/logic-helper/logic-helper.js: -------------------------------------------------------------------------------- 1 | require('./ternary.js'); 2 | require('./neq.js'); 3 | require('./eq.js'); 4 | require('./gt.js'); 5 | require('./and.js'); 6 | -------------------------------------------------------------------------------- /public/client/logic-helper/neq.js: -------------------------------------------------------------------------------- 1 | // non-equality for handlebars if statements 2 | 3 | var Handlebars = require('handlebars'); 4 | 5 | Handlebars.registerHelper( 6 | 'neq', 7 | function(v1, v2) { 8 | return v1 != v2; 9 | } 10 | ); 11 | -------------------------------------------------------------------------------- /public/client/logic-helper/ternary.js: -------------------------------------------------------------------------------- 1 | // a ternary operator 2 | // use like ? condition ifTrue ifFalse 3 | 4 | var Handlebars = require('handlebars'); 5 | 6 | Handlebars.registerHelper( 7 | '?', 8 | function(cond, tru, fals) { 9 | return cond ? tru : fals; 10 | } 11 | ); 12 | -------------------------------------------------------------------------------- /public/client/login-route/component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "login-route", 3 | "dependencies": { 4 | "jashkenas/underscore": "*" 5 | }, 6 | "local": [ 7 | "application", 8 | "layout-view" 9 | ], 10 | "scripts": ["login-route.js"], 11 | "templates": ["login-route.html"] 12 | } 13 | -------------------------------------------------------------------------------- /public/client/login-route/index.js: -------------------------------------------------------------------------------- 1 | var template = 2 | -------------------------------------------------------------------------------- /public/client/login-route/login-route.html: -------------------------------------------------------------------------------- 1 |
      2 |
      3 | 4 |
      5 |
      6 | 7 | 8 |
      9 | 10 |
      11 | 12 | 13 |
      14 | 15 | 16 |
      17 |
      18 |
      19 | -------------------------------------------------------------------------------- /public/client/login-route/login-route.js: -------------------------------------------------------------------------------- 1 | var _ = require('underscore'); 2 | var app = require('application'); 3 | var LayoutView = require('layout-view'); 4 | 5 | var Login = LayoutView.extend({ 6 | template: require('./login-route.html'), 7 | events: { 8 | 'click .login': 'doLogin' 9 | }, 10 | 11 | initialize: function(attr) { 12 | this.returnTo = attr.returnTo 13 | // bind it so context is layout not a DOM object 14 | _.bindAll(this, 'doLogin'); 15 | }, 16 | 17 | doLogin: function() { 18 | var instance = this; 19 | $.post('/authenticate', { 20 | username: this.$('input[name="username"]').val(), 21 | password: this.$('input[name="password"]').val() 22 | }) 23 | .then(function(data) { 24 | $('#logged-in-user').text(window.Messages('app.account.logged_in_as', data.username)); 25 | $('#logout').removeClass('hidden'); 26 | $('#myAccount').removeClass('hidden').attr('href', '#user/' + data.id); 27 | 28 | if (data.admin) 29 | $('#manageUsers').removeClass('hidden'); 30 | 31 | // note: log out is handled in application.js 32 | 33 | app.user = data; 34 | 35 | window.location.hash = instance.returnTo ? instance.returnTo : '#admin'; 36 | }) 37 | .fail(function() { 38 | window.alert('Log in failed'); 39 | }); 40 | 41 | return false; 42 | }, 43 | 44 | onShow: function() { 45 | // init nav 46 | app.nav.setLocation([{ 47 | name: Messages('app.location.login'), 48 | href: '#login' 49 | }]); 50 | } 51 | }); 52 | 53 | module.exports = function(returnTo) { 54 | // show your work 55 | app.appRegion.show(new Login({ 56 | returnTo: returnTo 57 | })); 58 | } 59 | -------------------------------------------------------------------------------- /public/client/new-user-route/component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "new-user-route", 3 | "description": "create a new user", 4 | "local": ["user", "application", "user-view"], 5 | "main": "new-user-route.js", 6 | "scripts": ["new-user-route.js"] 7 | } 8 | -------------------------------------------------------------------------------- /public/client/new-user-route/new-user-route.js: -------------------------------------------------------------------------------- 1 | var app = require('application'); 2 | var User = require('user'); 3 | var UserView = require('user-view'); 4 | 5 | module.exports = function() { 6 | // create a blank user, and allow the user to edit it 7 | // but only if the user is an admin 8 | if (!app.user.admin) { 9 | window.location.hash = '#'; 10 | return; 11 | } 12 | 13 | var u = new User(); 14 | var uv = new UserView({ 15 | model: u 16 | }); 17 | app.appRegion.show(uv); 18 | 19 | app.nav.setLocation([{ 20 | name: window.Messages('app.users'), 21 | href: '#users' 22 | }, { 23 | name: window.Messages('app.user.new'), 24 | href: '#users/new' 25 | }]); 26 | }; 27 | -------------------------------------------------------------------------------- /public/client/note-collection-view/component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "note-collection-view", 3 | "dependencies": { 4 | "jashkenas/underscore": "*" 5 | }, 6 | "local": ["composite-view", "item-view", "note", "note-collection"], 7 | "main": "note-collection-view.js", 8 | "scripts": ["note-collection-view.js"], 9 | "templates": ["note-collection-view.html", "note-item-view.html"] 10 | } 11 | -------------------------------------------------------------------------------- /public/client/note-collection-view/note-collection-view.html: -------------------------------------------------------------------------------- 1 |
      2 |
      3 |
      4 | 5 | 6 |
      7 | 8 |
      9 |
      10 | -------------------------------------------------------------------------------- /public/client/note-collection-view/note-collection-view.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Show a bunch of notes, comment-style 3 | */ 4 | 5 | var CompositeView = require('composite-view'); 6 | var _ = require('underscore'); 7 | var ItemView = require('item-view'); 8 | var NoteCollection = require('note-collection'); 9 | var Note = require('note'); 10 | 11 | var NoteItemView = ItemView.extend({ 12 | template: require('./note-item-view.html') 13 | }); 14 | 15 | /** 16 | * Instantiate a new NoteCollectionView like so: 17 | * new NoteCollectionView({objectId: 'u-u-i-d', type: 'FEED_SOURCE'}) 18 | */ 19 | module.exports = CompositeView.extend({ 20 | template: require('./note-collection-view.html'), 21 | childView: NoteItemView, 22 | className: 'row', 23 | events: { 24 | 'submit form': 'newComment' 25 | }, 26 | 27 | initialize: function(attr) { 28 | this.objectId = attr.objectId; 29 | this.type = attr.type; 30 | 31 | this.collection = new NoteCollection(); 32 | this.collection.fetch({ 33 | data: { 34 | objectId: this.objectId, 35 | type: this.type 36 | } 37 | }); 38 | 39 | _.bindAll(this, 'newComment'); 40 | }, 41 | 42 | /** 43 | * Grab the contents of the text field and create a new comment 44 | */ 45 | newComment: function(e) { 46 | // don't submit the form 47 | e.preventDefault(); 48 | 49 | var n = new Note({ 50 | objectId: this.objectId, 51 | type: this.type, 52 | note: this.$('textarea').val() 53 | }); 54 | 55 | this.$('form').addClass('disabled'); 56 | 57 | var instance = this; 58 | n.save().done(function() { 59 | instance.collection.add(n); 60 | instance.$('form').removeClass('disabled'); 61 | instance.$('textarea').val(''); 62 | }) 63 | .fail(function() { 64 | instance.$('form').removeClass('disabled'); 65 | window.alert('Commenting failed'); 66 | }); 67 | }, 68 | 69 | attachHtml: function(collectionView, childView, index) { 70 | // order not important; new things always go at the bottom 71 | collectionView.$('.new-comment').before(childView.$el); 72 | } 73 | }); 74 | -------------------------------------------------------------------------------- /public/client/note-collection-view/note-item-view.html: -------------------------------------------------------------------------------- 1 |
      2 |
      3 |
      4 |

      {{ note }}

      5 |

      {{ t 'app.note.source' user.username }}, {{ dateRender date true }}

      6 |
      7 |
      8 |
      9 | -------------------------------------------------------------------------------- /public/client/note-collection/component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "note-collection", 3 | "local": ["bb", "note"], 4 | "main": "note-collection.js", 5 | "scripts": ["note-collection.js"] 6 | } 7 | -------------------------------------------------------------------------------- /public/client/note-collection/note-collection.js: -------------------------------------------------------------------------------- 1 | /** 2 | * A collection of notes 3 | */ 4 | 5 | var BB = require('bb'); 6 | var Note = require('note'); 7 | 8 | module.exports = BB.Collection.extend({ 9 | model: Note, 10 | url: 'api/notes' 11 | }); 12 | -------------------------------------------------------------------------------- /public/client/note/component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "note", 3 | "local": ["bb"], 4 | "main": "note.js", 5 | "scripts": ["note.js"] 6 | } 7 | -------------------------------------------------------------------------------- /public/client/note/note.js: -------------------------------------------------------------------------------- 1 | var BB = require('bb'); 2 | 3 | module.exports = BB.Model.extend({ 4 | defaults: { 5 | user: null, 6 | note: null 7 | }, 8 | 9 | urlRoot: 'api/notes' 10 | }); 11 | -------------------------------------------------------------------------------- /public/client/ok-dialog-view/component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ok-dialog-view", 3 | "description": "Simple OK dialog box", 4 | "dependencies": { 5 | "jashkenas/underscore": "*" 6 | }, 7 | "local": [ 8 | "bb", 9 | "item-view" 10 | ], 11 | "scripts": ["ok-dialog-view.js"], 12 | "templates": ["ok-dialog-view.html"] 13 | } 14 | -------------------------------------------------------------------------------- /public/client/ok-dialog-view/ok-dialog-view.html: -------------------------------------------------------------------------------- 1 | 20 | -------------------------------------------------------------------------------- /public/client/ok-dialog-view/ok-dialog-view.js: -------------------------------------------------------------------------------- 1 | var BB = require('bb'); 2 | var ItemView = require('item-view'); 3 | var _ = require('underscore'); 4 | 5 | 6 | /** 7 | * usage: new ConfirmView({title: text, body: text, [onProceed: function,] [onCancel: function,]}) 8 | */ 9 | module.exports = ItemView.extend({ 10 | template: require('./ok-dialog-view.html'), 11 | 12 | events: { 13 | 'click .ok-action': 'onOk' 14 | }, 15 | 16 | 17 | initialize: function(attr) { 18 | this.model = new BB.Model({ 19 | title: attr.title, 20 | body: attr.body 21 | }); 22 | 23 | this.onOk = !_.isUndefined(attr.onOk) ? attr.onOk : function() {}; 24 | }, 25 | 26 | onShow: function() { 27 | this.$el.find('.modal').modal(); 28 | } 29 | }); 30 | -------------------------------------------------------------------------------- /public/client/osm-config-route/component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "osm-config-route", 3 | "local": ["feed-collection", "feed-source-collection", "osm-config-view", "application"], 4 | "main": "osm-config-route.js", 5 | "scripts": ["osm-config-route.js"] 6 | } 7 | -------------------------------------------------------------------------------- /public/client/osm-config-route/osm-config-route.js: -------------------------------------------------------------------------------- 1 | var FeedCollection = require('feed-collection'); 2 | var FeedSourceCollection = require('feed-source-collection'); 3 | var OsmConfigView = require('osm-config-view'); 4 | var app = require('application'); 5 | 6 | module.exports = function(feedCollectionId) { 7 | 8 | var fc = new FeedCollection({ 9 | id: feedCollectionId 10 | }); 11 | var fcDf = fc.fetch(); 12 | 13 | var fsc = new FeedSourceCollection(); 14 | var fscDf = fsc.fetch({ 15 | data: { 16 | feedcollection: feedCollectionId 17 | } 18 | }); 19 | 20 | $.when(fcDf, fscDf).done(function() { 21 | 22 | app.appRegion.show(new OsmConfigView({ 23 | model: fc, 24 | feedSources: fsc 25 | })); 26 | 27 | // nav 28 | app.nav.setLocation([{ 29 | name: fc.get('name'), 30 | href: '#overview/' + fc.get('id') 31 | }, { 32 | name: window.Messages('app.osm_config.configure'), 33 | href: '#osmconfig' 34 | }]); 35 | }); 36 | }; 37 | -------------------------------------------------------------------------------- /public/client/osm-config-view/component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "osm-config-view", 3 | "local": ["application", "feed-collection", "item-view"], 4 | "scripts": ["osm-config-view.js"], 5 | "templates": ["osm-config-view.html"] 6 | } 7 | -------------------------------------------------------------------------------- /public/client/osm-config-view/osm-config-view.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | {{ t 'app.osm_config.configure' }} 4 | 5 |
      6 | 7 |
      8 | 9 |
      10 | 11 |
      12 | 13 |
      14 | 15 |
      16 |
      17 |
      18 | 19 | 20 |
      21 | 22 |
      23 | 24 | 25 |
      26 | 27 |
      28 | 29 | 30 |
      31 | 32 |
      33 | 34 | 35 |
      36 |
      37 |
      38 |
      39 | 40 |
      41 | 42 |
      43 | 44 | -------------------------------------------------------------------------------- /public/client/otp-config-route/component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "otp-config-route", 3 | "local": [ 4 | "application", 5 | "feed-collection", 6 | "feed-source-collection", 7 | "otp-config-view" 8 | ], 9 | "scripts": [ 10 | "index.js" 11 | ] 12 | } -------------------------------------------------------------------------------- /public/client/otp-config-route/index.js: -------------------------------------------------------------------------------- 1 | var app = require('application'); 2 | var FeedCollection = require('feed-collection'); 3 | var FeedSourceCollection = require('feed-source-collection'); 4 | var View = require('otp-config-view'); 5 | 6 | module.exports = function(id) { 7 | var fc = new FeedCollection({ 8 | id: id 9 | }); 10 | var fcDf = fc.fetch(); 11 | 12 | var fsc = new FeedSourceCollection(); 13 | var fscDf = fsc.fetch({ 14 | data: { 15 | feedcollection: id 16 | } 17 | }); 18 | 19 | $.when(fcDf, fscDf).done(function() { 20 | app.appRegion.show(new View({ 21 | model: fc, 22 | feedSources: fsc 23 | })); 24 | 25 | // nav 26 | app.nav.setLocation([{ 27 | name: fc.get('name'), 28 | href: '#overview/' + fc.get('id') 29 | }, { 30 | name: window.Messages('app.otp_config.title'), 31 | href: '#otpconfig' 32 | }]); 33 | }); 34 | }; 35 | -------------------------------------------------------------------------------- /public/client/otp-config-view/component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "otp-config-view", 3 | "dependencies": { 4 | "jashkenas/underscore": "*" 5 | }, 6 | "local": [ 7 | "item-view" 8 | ], 9 | "scripts": [ 10 | "index.js" 11 | ], 12 | "styles": [ 13 | "style.css" 14 | ], 15 | "templates": [ 16 | "template.html" 17 | ] 18 | } -------------------------------------------------------------------------------- /public/client/otp-config-view/style.css: -------------------------------------------------------------------------------- 1 | 2 | legend > .btn { 3 | vertical-align: top; 4 | padding: 4px 10px; 5 | } 6 | -------------------------------------------------------------------------------- /public/client/otp-config-view/template.html: -------------------------------------------------------------------------------- 1 | 2 |
      3 | {{ t 'app.otp_config.title' }} {{t 'app.otp_config.docs'}} 4 |
      5 | 6 |
      7 | {{ t 'app.otp_config.build' }} 8 | {{#each build}} 9 | {{> input}} 10 | {{/each}} 11 |
      12 | 13 |
      14 | {{ t 'app.otp_config.router' }} 15 | {{#each router}} 16 | {{> input}} 17 | {{/each}} 18 |
      19 | 20 |
      21 |
      22 |
      23 | {{ t 'app.otp_config.updaters' }} 24 |
      25 | {{#each updaters}} 26 |
      27 | {{ t 'app.otp_config.updater' }} 28 | {{#each this}} 29 | {{> input}} 30 | {{/each}} 31 |
      32 | {{/each}} 33 |
      34 |
      35 | 36 |
      37 | 38 |
      39 | -------------------------------------------------------------------------------- /public/client/routes/component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "routes", 3 | "scripts": ["routes.js"], 4 | "local": [ 5 | "application", 6 | "bb", 7 | "login-route", 8 | "deployment-route", 9 | "admin-route", 10 | "feed-collection-route", 11 | "feed-source-route", 12 | "autologin-route", 13 | "feed-version-collection-route", 14 | "deployment-collection-route", 15 | "user-collection-route", 16 | "user-route", 17 | "new-user-route", 18 | "osm-config-route", 19 | "otp-config-route" 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /public/client/routes/index.js: -------------------------------------------------------------------------------- 1 | // The routes for the gtfs-data-manager webapp 2 | 3 | { 4 | "login": "login" 5 | } 6 | -------------------------------------------------------------------------------- /public/client/templater/component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "templater", 3 | "dependencies": { 4 | "components/handlebars.js": "*", 5 | "ianstormtaylor/to-capital-case": "*" 6 | }, 7 | "scripts": [ 8 | "index.js" 9 | ], 10 | "templates": [ 11 | "input.html" 12 | ] 13 | } -------------------------------------------------------------------------------- /public/client/templater/index.js: -------------------------------------------------------------------------------- 1 | var Handlebars = require('handlebars.js'); 2 | var toCapitalCase = require('to-capital-case'); 3 | 4 | var partials = { 5 | input: require('./input.html') 6 | }; 7 | 8 | var helpers = { 9 | toCapitalCase: toCapitalCase 10 | }; 11 | 12 | var key; 13 | for (key in partials) 14 | Handlebars.registerPartial(key, partials[key]); 15 | 16 | for (key in helpers) 17 | Handlebars.registerHelper(key, helpers[key]); 18 | 19 | module.exports = Handlebars; 20 | -------------------------------------------------------------------------------- /public/client/templater/input.html: -------------------------------------------------------------------------------- 1 |
      2 | 3 | 4 |
      -------------------------------------------------------------------------------- /public/client/text-helper/component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "text-helper", 3 | "description": "Handlebars helpers for text manipulation", 4 | "dependencies": { 5 | "components/handlebars.js": "*" 6 | }, 7 | "main": "text-helper.js", 8 | "scripts": ["text-helper.js", "join.js"] 9 | } 10 | -------------------------------------------------------------------------------- /public/client/text-helper/join.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Join several strings, with the separator being the first argument 3 | */ 4 | 5 | var Handlebars = require('handlebars'); 6 | 7 | Handlebars.registerHelper( 8 | 'join', 9 | function() { 10 | return arguments.slice(1).join(arguments[0]); 11 | } 12 | ); 13 | -------------------------------------------------------------------------------- /public/client/text-helper/text-helper.js: -------------------------------------------------------------------------------- 1 | require('./join.js'); 2 | -------------------------------------------------------------------------------- /public/client/translate-helper/component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "translate-helper", 3 | "description": "Handlebars helper for play jsMessages", 4 | "dependencies": { 5 | "components/handlebars.js": "*" 6 | }, 7 | "scripts": [ 8 | "t.js" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /public/client/translate-helper/t.js: -------------------------------------------------------------------------------- 1 | var Handlebars = require('handlebars'); 2 | Handlebars.registerHelper('t', window.Messages); 3 | -------------------------------------------------------------------------------- /public/client/user-collection-route/component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "user-collection-route", 3 | "description": "The route for showing all users.", 4 | "local": ["application", "user-collection", "user-collection-view"], 5 | "main": "user-collection-route.js", 6 | "scripts": ["user-collection-route.js"] 7 | } 8 | -------------------------------------------------------------------------------- /public/client/user-collection-route/user-collection-route.js: -------------------------------------------------------------------------------- 1 | var app = require('application'); 2 | var UserCollection = require('user-collection'); 3 | var UserCollectionView = require('user-collection-view'); 4 | 5 | module.exports = function() { 6 | if (!app.user.admin) { 7 | window.location.hash = '#'; 8 | return; 9 | } 10 | 11 | new UserCollection().fetch().done(function(d) { 12 | d = new UserCollection(d.filter(function(u) { 13 | return u.autogenerated !== true; 14 | })); 15 | 16 | app.appRegion.show(new UserCollectionView({ 17 | collection: d 18 | })); 19 | app.nav.setLocation([{ 20 | name: window.Messages('app.users'), 21 | href: '#users' 22 | }]); 23 | }); 24 | }; 25 | -------------------------------------------------------------------------------- /public/client/user-collection-view/component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "user-collection-view", 3 | "local": ["composite-view", "item-view", "user", "user-collection"], 4 | "main": "user-collection-view.js", 5 | "scripts": ["user-collection-view.js"], 6 | "templates": ["user-collection-view.html", "user-item-view.html"] 7 | } 8 | -------------------------------------------------------------------------------- /public/client/user-collection-view/user-collection-view.html: -------------------------------------------------------------------------------- 1 |

      2 | 3 | {{ t 'app.user.new' }} 4 | 5 |

      6 | 7 |
      8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
      {{ t 'app.user.username' }}{{ t 'app.user.email' }}{{ t 'app.user.admin' }}{{ t 'app.user.active' }}
      17 |
      18 | -------------------------------------------------------------------------------- /public/client/user-collection-view/user-collection-view.js: -------------------------------------------------------------------------------- 1 | /** 2 | * A view of a number of users. 3 | * 4 | * It's safe to assume the user is an admin as this isn't used in any other contexts. 5 | * Security is implemented on the server anyhow. 6 | */ 7 | 8 | var CompositeView = require('composite-view'); 9 | var ItemView = require('item-view'); 10 | var UserCollection = require('user-collection'); 11 | var User = require('user'); 12 | 13 | var UserItemView = ItemView.extend({ 14 | template: require('./user-item-view.html'), 15 | tagName: 'tr' 16 | }); 17 | 18 | module.exports = CompositeView.extend({ 19 | template: require('./user-collection-view.html'), 20 | childView: UserItemView, 21 | childViewContainer: 'tbody' 22 | }); 23 | -------------------------------------------------------------------------------- /public/client/user-collection-view/user-item-view.html: -------------------------------------------------------------------------------- 1 | {{ username }} 2 | {{ email }} 3 | {{? admin (t 'app.yes') (t 'app.no') }} 4 | {{? active (t 'app.yes') (t 'app.no') }} 5 | -------------------------------------------------------------------------------- /public/client/user-collection/component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "user-collection", 3 | "local": ["bb", "user"], 4 | "main": "user-collection.js", 5 | "scripts": ["user-collection.js"] 6 | } 7 | -------------------------------------------------------------------------------- /public/client/user-collection/user-collection.js: -------------------------------------------------------------------------------- 1 | var BB = require('bb'); 2 | var User = require('user'); 3 | 4 | module.exports = BB.Collection.extend({ 5 | model: User, 6 | url: 'api/users' 7 | }); 8 | -------------------------------------------------------------------------------- /public/client/user-route/component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "user-route", 3 | "descripton": "the route for editing a single user", 4 | "local": ["user", "application", "user-view"], 5 | "main": "user-route.js", 6 | "scripts": ["user-route.js"] 7 | } 8 | -------------------------------------------------------------------------------- /public/client/user-route/user-route.js: -------------------------------------------------------------------------------- 1 | var User = require('user'); 2 | var app = require('application'); 3 | var UserView = require('user-view'); 4 | 5 | module.exports = function(userid) { 6 | var u = new User({ 7 | id: userid 8 | }); 9 | u.fetch().done(function() { 10 | app.appRegion.show(new UserView({ 11 | model: u 12 | })); 13 | app.nav.setLocation([{ 14 | name: window.Messages('app.users'), 15 | href: '#users' 16 | }, { 17 | name: u.get('username'), 18 | href: '#user/' + u.id 19 | }]); 20 | }); 21 | }; 22 | -------------------------------------------------------------------------------- /public/client/user-view/component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "user-view", 3 | "dependencies": { 4 | "jashkenas/underscore": "*", 5 | "components/handlebars.js": "*", 6 | "kpwebb/select2": "*" 7 | }, 8 | "description": "A view used to edit a single user", 9 | "main": "user-view.js", 10 | "local": ["application", "feed-source-collection", "item-view"], 11 | "scripts": ["user-view.js"], 12 | "templates": ["user-view.html"] 13 | } 14 | -------------------------------------------------------------------------------- /public/client/user-view/user-view.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
      4 | {{#if id}} 5 | {{ t 'app.user.edit' username }} 6 | {{else}} 7 |
      8 | 9 | 10 |
      11 | {{/if}} 12 | 13 |
      14 | 15 | 16 |
      17 | 18 |
      19 | 20 | 21 |
      22 | 23 |
      24 | 25 | 26 | 27 |
      28 | 29 | 33 | 34 | {{#if currentUser.admin }} 35 |
      36 | 39 |
      40 | 41 |
      42 | 45 |
      46 | 47 |
      48 |
      51 | {{/if}} 52 | 53 | 54 |
      55 | -------------------------------------------------------------------------------- /public/client/user/component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "user", 3 | "local": ["bb"], 4 | "main": "user.js", 5 | "scripts": ["user.js"] 6 | } 7 | -------------------------------------------------------------------------------- /public/client/user/user.js: -------------------------------------------------------------------------------- 1 | var BB = require('bb'); 2 | 3 | module.exports = BB.Model.extend({ 4 | defaults: { 5 | id: null, 6 | username: null, 7 | email: null, 8 | active: true, 9 | admin: false, 10 | autogenerated: null 11 | }, 12 | 13 | urlRoot: '/api/users' 14 | }); 15 | -------------------------------------------------------------------------------- /public/client/validation-partial/component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "validation-partial", 3 | "description": "Summary of validation results", 4 | "dependencies": { 5 | "components/handlebars.js": "*" 6 | }, 7 | "main": "validation-partial.js", 8 | "scripts": ["validation-partial.js"], 9 | "templates": ["validation-partial.html"] 10 | } 11 | -------------------------------------------------------------------------------- /public/client/validation-partial/validation-partial.html: -------------------------------------------------------------------------------- 1 | {{#if (eq loadStatus 'SUCCESS')}} 2 | {{ t 'app.yes' }} 3 | {{ errorCount }} 4 | {{ routeCount }} 5 | {{ tripCount }} 6 | {{ stopTimesCount }} 7 | {{#if (gt stopTimesCount 0)}} 8 | {{ dateRender startDate false }} 9 | {{ dateRender endDate false }} 10 | {{else}} 11 | -- 12 | {{/if}} 13 | {{else}} 14 | {{ t 'app.no' }} 15 | {{ loadFailureReason }} 16 | {{/if}} 17 | -------------------------------------------------------------------------------- /public/client/validation-partial/validation-partial.js: -------------------------------------------------------------------------------- 1 | var Handlebars = require('handlebars'); 2 | 3 | Handlebars.registerPartial( 4 | 'validationResult', 5 | require('./validation-partial.html') 6 | ); 7 | -------------------------------------------------------------------------------- /public/component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gtfs-data-manager", 3 | "paths": ["client"], 4 | "local": ["routes"], 5 | "development": {} 6 | } 7 | -------------------------------------------------------------------------------- /public/data/README: -------------------------------------------------------------------------------- 1 | This is where the manager stores bundled up deployments for OTP/Docker. This is all derivative data (zipballs of feeds); it's safe to zap when needed. 2 | The only exception is that, if you've created a deployment, dumped it, and then deleted/edited it, there will be no way to get it back. 3 | However, there is only one file here per deployment anyhow, so if you edit a deployment and dump again, the file here will be overwritten anyhow. 4 | -------------------------------------------------------------------------------- /public/docs/data_manager_user_guide.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conveyal/gtfs-data-manager/e7269fc1660f1816da269b1c116b43bdf758900b/public/docs/data_manager_user_guide.pdf -------------------------------------------------------------------------------- /public/images/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conveyal/gtfs-data-manager/e7269fc1660f1816da269b1c116b43bdf758900b/public/images/favicon.png -------------------------------------------------------------------------------- /public/images/login_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conveyal/gtfs-data-manager/e7269fc1660f1816da269b1c116b43bdf758900b/public/images/login_logo.png -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 19 | 20 | 21 | 22 | 45 | 46 |
      47 |
      48 | 49 |
      50 |
      51 |
      52 | 53 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /public/stylesheets/main.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conveyal/gtfs-data-manager/e7269fc1660f1816da269b1c116b43bdf758900b/public/stylesheets/main.css -------------------------------------------------------------------------------- /scripts/bulkLoadUrls.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # load many feeds to the GTFS data manager, from a csv with fields name and url 3 | # usage: bulkLoadFeeds.py file.csv http://server.example.com/ 4 | 5 | import csv 6 | from getpass import getpass 7 | from sys import argv 8 | import json 9 | from cookielib import CookieJar 10 | import urllib2 11 | from urllib import urlencode 12 | 13 | if len(argv) != 3: 14 | print 'usage: %s file.csv http://gtfs-data-manager.example.com' % argv[0] 15 | 16 | server = argv[2] 17 | 18 | with open(argv[1]) as f: 19 | reader = csv.DictReader(f) 20 | 21 | # log in to the server 22 | print 'Please authenticate' 23 | uname = raw_input('username: ') 24 | pw = getpass('password: ') 25 | 26 | # strip trailing slash to normalize url 27 | server = server if not server.endswith('/') else server[:-1] 28 | 29 | # cookie handling 30 | # http://www.techchorus.net/using-cookie-jar-urllib2 31 | cj = CookieJar() 32 | opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj)) 33 | 34 | # authenticate 35 | opener.open(server + '/authenticate', urlencode(dict(username=uname, password=pw))) 36 | 37 | # choose feed collection 38 | colls = json.load(opener.open(server + '/api/feedcollections')) 39 | 40 | print 'choose a feed collection: ' 41 | 42 | for i in xrange(len(colls)): 43 | print '%s. %s' % (i + 1, colls[i]['name']) 44 | 45 | while True: 46 | try: 47 | coll = colls[int(raw_input('> ')) - 1] 48 | except ValueError: 49 | continue 50 | else: 51 | break 52 | 53 | # load each feed 54 | for feed in reader: 55 | data = dict( 56 | name = feed['name'], 57 | url = feed['url'], 58 | isPublic = True, 59 | autofetch = True, 60 | # every day 61 | feedCollection = coll 62 | ) 63 | 64 | # http://stackoverflow.com/questions/3290522 65 | req = urllib2.Request(server + '/api/feedsources/', json.dumps(data), {'Content-Type': 'application/json'}) 66 | opener.open(req) 67 | 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /scripts/dump.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # Dump the database from a server 3 | # usage: dump.py http://localhost:9000 dump.json 4 | 5 | from sys import argv 6 | from shutil import copyfileobj 7 | from getpass import getpass 8 | from cookielib import CookieJar 9 | import urllib2 10 | from urllib import urlencode 11 | 12 | 13 | server = argv[1] 14 | 15 | # log in to the server 16 | print 'Please authenticate' 17 | uname = raw_input('username: ') 18 | pw = getpass('password: ') 19 | 20 | # strip trailing slash to normalize url 21 | server = server if not server.endswith('/') else server[:-1] 22 | 23 | # cookie handling 24 | # http://www.techchorus.net/using-cookie-jar-urllib2 25 | cj = CookieJar() 26 | opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj)) 27 | 28 | # authenticate 29 | opener.open(server + '/authenticate', urlencode(dict(username=uname, password=pw))) 30 | 31 | # get the dump 32 | out = open(argv[2], 'w') 33 | 34 | res = opener.open(server + '/dump') 35 | copyfileobj(res, out) 36 | -------------------------------------------------------------------------------- /scripts/load.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # load the database to a fresh server 3 | # usage: load.py dump.json http://localhost:9000 4 | 5 | from sys import argv 6 | import urllib2 7 | 8 | server = argv[2] 9 | # strip trailing slash to normalize url 10 | server = server if not server.endswith('/') else server[:-1] 11 | 12 | # TODO: don't load everything into RAM when loading 13 | inf = open(argv[1]) 14 | dump = inf.read() 15 | 16 | print dump[0:79] 17 | 18 | req = urllib2.Request(server + '/load', dump, {'Content-Type': 'application/json', 'Content-Length': len(dump)}) 19 | opener = urllib2.build_opener() 20 | 21 | try: 22 | opener.open(req) 23 | except urllib2.URLError, e: 24 | print e.code 25 | print e.read() 26 | -------------------------------------------------------------------------------- /scripts/receiveFile.js: -------------------------------------------------------------------------------- 1 | var http = require('http'); 2 | var fs = require('fs'); 3 | 4 | http.createServer(function (req, res) { 5 | var out = fs.createWriteStream('/tmp/deployment.zip'); 6 | req.pipe(out); 7 | req.on('end', function () { 8 | res.writeHead(200); 9 | res.end('done'); 10 | }); 11 | }).listen(8555, '127.0.0.1'); 12 | -------------------------------------------------------------------------------- /src/templates/etc-default: -------------------------------------------------------------------------------- 1 | -Dpidfile.path=/var/run/gtfs-data-manager/play.pid 2 | # See https://github.com/sbt/sbt-native-packager/issues/361 3 | # Note: this will break on non-Unix systems 4 | -Dconfig.file=/etc/gtfs-data-manager/application.conf 5 | -------------------------------------------------------------------------------- /test/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | import java.util.ArrayList; 2 | import java.util.HashMap; 3 | import java.util.List; 4 | import java.util.Map; 5 | 6 | import com.fasterxml.jackson.databind.JsonNode; 7 | import org.junit.*; 8 | 9 | import play.mvc.*; 10 | import play.test.*; 11 | import play.data.DynamicForm; 12 | import play.data.validation.ValidationError; 13 | import play.data.validation.Constraints.RequiredValidator; 14 | import play.i18n.Lang; 15 | import play.libs.F; 16 | import play.libs.F.*; 17 | import play.twirl.api.Content; 18 | 19 | import static play.test.Helpers.*; 20 | import static org.fest.assertions.Assertions.*; 21 | 22 | 23 | /** 24 | * 25 | * Simple (JUnit) tests that can call all parts of a play app. 26 | * If you are interested in mocking a whole application, see the wiki for more details. 27 | * 28 | */ 29 | public class ApplicationTest { 30 | 31 | @Test 32 | public void simpleCheck() { 33 | int a = 1 + 1; 34 | assertThat(a).isEqualTo(2); 35 | } 36 | 37 | @Test 38 | public void renderTemplate() { 39 | Content html = views.html.index.render("Your new application is ready."); 40 | assertThat(contentType(html)).isEqualTo("text/html"); 41 | assertThat(contentAsString(html)).contains("Your new application is ready."); 42 | } 43 | 44 | 45 | } 46 | -------------------------------------------------------------------------------- /test/IntegrationTest.java: -------------------------------------------------------------------------------- 1 | import org.junit.*; 2 | 3 | import play.mvc.*; 4 | import play.test.*; 5 | import play.libs.F.*; 6 | 7 | import static play.test.Helpers.*; 8 | import static org.fest.assertions.Assertions.*; 9 | 10 | import static org.fluentlenium.core.filter.FilterConstructor.*; 11 | 12 | public class IntegrationTest { 13 | 14 | /** 15 | * add your integration test here 16 | * in this example we just check if the welcome page is being shown 17 | */ 18 | @Test 19 | public void test() { 20 | running(testServer(3333, fakeApplication(inMemoryDatabase())), HTMLUNIT, new Callback() { 21 | public void invoke(TestBrowser browser) { 22 | browser.goTo("http://localhost:3333"); 23 | assertThat(browser.pageSource()).contains("Your new application is ready."); 24 | } 25 | }); 26 | } 27 | 28 | } 29 | --------------------------------------------------------------------------------