<commit_before>module.config([
	'$locationProvider', '$routeProvider', function ($locationProvider, $routeProvider) {
		$locationProvider.html5Mode(true);

		//

		var appResolve = function (config) {
			if (!config.resolve)
				config.resolve = {};

			angular.extend(config.resolve, {
				authPromise: [
					'authService', function (auth) {
						return auth.$promise;
					}
				],
				constantPromise: [
					'constantService', function (constants) {
						return constants.$promise;
					}
				]
			});

			return config;
		};

		//

		$routeProvider.when('/', appResolve({
			controller: 'WelcomeView',
			templateUrl: 'welcomeView.html',
			reloadOnSearch: false
		}));

		//

		$routeProvider.when('/login', appResolve({
			controller: 'LoginView',
			templateUrl: 'loginView.html',
			reloadOnSearch: false
		}));

		//

		$routeProvider.when('/register', appResolve({
			controller: 'RegisterView',
			templateUrl: 'registerView.html',
			reloadOnSearch: false
		}));

		//

		$routeProvider.when('/password', appResolve({
			controller: 'ResetView',
			templateUrl: 'resetView.html',
			reloadOnSearch: false
		}));

		//

		$routeProvider.when('/search', appResolve({
			controller: 'SearchView',
			templateUrl: 'searchView.html',
			resolve: {
				volumes: [
					'$route', 'Volume', '$q', function ($route, Volume, $q) {
						var deferred = $q.defer();

						Volume.query({}, function (data) {
							deferred.resolve(data);
						}, function (data) {
							deferred.reject();
						});

						return deferred.promise;
					}
				]
			},
			reloadOnSearch: false
		}));

		//

		var partyView = appResolve({
			controller: 'PartyView',
			templateUrl: 'partyView.html',
			resolve: {
				party: [
					'$route',
					'Party',
					'$q',
					'$window',
					'typeService',
					'authService',
					function ($route, Party, $q, $window, type, auth) {
						var deferred = $q.defer();

						var req = {
							comments: '',
							access: '',
							parents: '',
							children: ''
						};

						if ($route.current.params.id)
							req.id = $route.current.params.id;
						else if (auth.isLoggedIn())
							req.id = auth.user.id;
						else if (type.isParty($window.$play.object))
							req.id = $window.$play.object.id;

						if ($route.current.params.id)
							Party.get(req, function (data) {
								deferred.resolve(data);
							}, function (error) {
								deferred.reject();
							});
						else
							Party.profile(req, function (data) {
								deferred.resolve(data);
							}, function (error) {
								deferred.reject();
							});

						return deferred.promise;
					}
				],
				volumes: [
					'$route',
					'Volume',
					'$q',
					'authService',
					'typeService',
					'$window',
					function ($route, Volume, $q, auth, type, $window) {
						var deferred = $q.defer();

						var req = {
							id: null
						};

						if ($route.current.params.id)
							req.party = $route.current.params.id;
						else if (auth.isLoggedIn())
							req.party = auth.user.id;
						else if (type.isParty($window.$play.object))
							req.party = $window.$play.object.id;

						Volume.query(req, function (data) {
							deferred.resolve(data);
						}, function (data) {
							deferred.reject();
						});

						return deferred.promise;
					}
				]
			},
			reloadOnSearch: false
		});

		$routeProvider.when('/party/:id', partyView);
		$routeProvider.when('/profile', partyView);

		//

		$routeProvider.when('/volume/:id', appResolve({
			controller: 'VolumeView',
			templateUrl: 'volumeView.html',
			resolve: {
				volume: [
					'$route', 'Volume', '$q', function ($route, Volume, $q) {
						var deferred = $q.defer();

						Volume.get({
							access: '',
							citations: '',
							providers: '',
							consumers: '',
							top: '',
							tags: '',
							excerpts: '',
							comments: '',
							records: '',
							summary: '',
							sessions: '',
							categories: '',
							funding: ''
						}, function (res) {
							deferred.resolve(res);
						}, function (res) {
							deferred.reject();
						});

						return deferred.promise;
					}
				]
			},
			reloadOnSearch: false
		}));

		//

		$routeProvider.otherwise({
			redirectTo: '/search'
		});
	}
]);

module.run([
	'$rootScope',
	'routerService',
	'constantService',
	'authService',
	'$location',
	function ($rootScope, router, constants, auth, $location) {
		$rootScope.$on('$routeChangeStart', function (event, next, current) {
			if (auth.isLoggedIn()) {
				if (auth.isUnauthorized()) {
					if (!next.$$route || next.$$route.controller != 'RegisterView')
						$location.url(router.register());
					return;
				} else if (next.$$route && [
					'ResetView',
					'WelcomeView',
					'LoginView',
					'RegisterView'
				].indexOf(next.$$route.controller) != -1) {
					$location.url(router.search());
				} else if (auth.next) {
					$location.url(auth.next).replace();
					auth.next = undefined;
				}
			} else {
				if (auth.isPasswordPending() && next.$$route && next.$$route.controller != 'RegisterView') {
					$location.url(router.register());
				} else if (next.$$route && [
					'ResetView',
					'WelcomeView',
					'LoginView',
					'RegisterView'
				].indexOf(next.$$route.controller) == -1) {
					auth.next = $location.url();
					$location.url(router.index());
				}
			}
		});
	}
]);

<commit_msg>minor twist to fix loop<commit_after>module.config([
	'$locationProvider', '$routeProvider', function ($locationProvider, $routeProvider) {
		$locationProvider.html5Mode(true);

		//

		var appResolve = function (config) {
			if (!config.resolve)
				config.resolve = {};

			angular.extend(config.resolve, {
				authPromise: [
					'authService', function (auth) {
						return auth.$promise;
					}
				],
				constantPromise: [
					'constantService', function (constants) {
						return constants.$promise;
					}
				]
			});

			return config;
		};

		//

		$routeProvider.when('/', appResolve({
			controller: 'WelcomeView',
			templateUrl: 'welcomeView.html',
			reloadOnSearch: false
		}));

		//

		$routeProvider.when('/login', appResolve({
			controller: 'LoginView',
			templateUrl: 'loginView.html',
			reloadOnSearch: false
		}));

		//

		$routeProvider.when('/register', appResolve({
			controller: 'RegisterView',
			templateUrl: 'registerView.html',
			reloadOnSearch: false
		}));

		//

		$routeProvider.when('/password', appResolve({
			controller: 'ResetView',
			templateUrl: 'resetView.html',
			reloadOnSearch: false
		}));

		//

		$routeProvider.when('/search', appResolve({
			controller: 'SearchView',
			templateUrl: 'searchView.html',
			resolve: {
				volumes: [
					'$route', 'Volume', '$q', function ($route, Volume, $q) {
						var deferred = $q.defer();

						Volume.query({}, function (data) {
							deferred.resolve(data);
						}, function (data) {
							deferred.reject();
						});

						return deferred.promise;
					}
				]
			},
			reloadOnSearch: false
		}));

		//

		var partyView = appResolve({
			controller: 'PartyView',
			templateUrl: 'partyView.html',
			resolve: {
				party: [
					'$route',
					'Party',
					'$q',
					'$window',
					'typeService',
					'authService',
					function ($route, Party, $q, $window, type, auth) {
						var deferred = $q.defer();

						var req = {
							comments: '',
							access: '',
							parents: '',
							children: ''
						};

						if ($route.current.params.id)
							req.id = $route.current.params.id;
						else if (auth.isLoggedIn())
							req.id = auth.user.id;
						else if (type.isParty($window.$play.object))
							req.id = $window.$play.object.id;

						if ($route.current.params.id)
							Party.get(req, function (data) {
								deferred.resolve(data);
							}, function (error) {
								deferred.reject();
							});
						else
							Party.profile(req, function (data) {
								deferred.resolve(data);
							}, function (error) {
								deferred.reject();
							});

						return deferred.promise;
					}
				],
				volumes: [
					'$route',
					'Volume',
					'$q',
					'authService',
					'typeService',
					'$window',
					function ($route, Volume, $q, auth, type, $window) {
						var deferred = $q.defer();

						var req = {
							id: null
						};

						if ($route.current.params.id)
							req.party = $route.current.params.id;
						else if (auth.isLoggedIn())
							req.party = auth.user.id;
						else if (type.isParty($window.$play.object))
							req.party = $window.$play.object.id;

						Volume.query(req, function (data) {
							deferred.resolve(data);
						}, function (data) {
							deferred.reject();
						});

						return deferred.promise;
					}
				]
			},
			reloadOnSearch: false
		});

		$routeProvider.when('/party/:id', partyView);
		$routeProvider.when('/profile', partyView);

		//

		$routeProvider.when('/volume/:id', appResolve({
			controller: 'VolumeView',
			templateUrl: 'volumeView.html',
			resolve: {
				volume: [
					'$route', 'Volume', '$q', function ($route, Volume, $q) {
						var deferred = $q.defer();

						Volume.get({
							access: '',
							citations: '',
							providers: '',
							consumers: '',
							top: '',
							tags: '',
							excerpts: '',
							comments: '',
							records: '',
							summary: '',
							sessions: '',
							categories: '',
							funding: ''
						}, function (res) {
							deferred.resolve(res);
						}, function (res) {
							deferred.reject();
						});

						return deferred.promise;
					}
				]
			},
			reloadOnSearch: false
		}));

		//

		$routeProvider.otherwise({
			redirectTo: '/search'
		});
	}
]);

module.run([
	'$rootScope',
	'routerService',
	'constantService',
	'authService',
	'$location',
	function ($rootScope, router, constants, auth, $location) {
		$rootScope.$on('$routeChangeStart', function (event, next, current) {
			if (auth.isLoggedIn()) {
				if (auth.isUnauthorized()) {
					if (!next.$$route || next.$$route.controller != 'RegisterView')
						$location.url(router.register());
					return;
				} else if (next.$$route && [
					'ResetView',
					'WelcomeView',
					'LoginView',
					'RegisterView'
				].indexOf(next.$$route.controller) != -1) {
					$location.url(router.search());
				} else if (auth.next) {
					$location.url(auth.next).replace();
					auth.next = undefined;
				}
			} else {
				if (auth.isPasswordPending() && next.$$route && next.$$route.controller != 'RegisterView') {
					$location.url(router.register());
				} else if (next.$$route && [
					'ResetView',
					'WelcomeView',
					'LoginView',
					'RegisterView'
				].indexOf(next.$$route.controller) == -1) {
					$location.url(router.index());
				}
			}
		});
	}
]);

<|endoftext|>


<commit_before>var idleTime = 0;
var alerted = true;
$(document).ready(function () {
  if(alerted === true) {
    var idleInterval = setInterval(timerIncrement, 20000); // 1 minute
  }
});

function timerIncrement() {
  idleTime++;
  if (idleTime > 1 && alerted === true) { // 50 minutes
    alerted = false
    alert("Your page has timed out.  Please save/copy your information elsewhere before you are redirected to our login server.")
  }
}
<commit_msg>Changed format of JS code<commit_after>$(document).ready(function () {
  var idleTime = 0;
  var alerted = true;

  if(alerted === true) {
    var idleInterval = setInterval(timerIncrement, 20000); // 1 minute
  }

  function timerIncrement() {
    idleTime++;
    if (idleTime > 1 && alerted === true) { // 50 minutes
      alerted = false
      alert("Your page has timed out.  Please save/copy your information elsewhere before you are redirected to our login server.")
    }
  }
});
<|endoftext|>


<commit_before>$(function () {
    $("#task_version").autocomplete({
        source:function (req, resp) {
            var applicationId = $("#task_application_id").val();
            if (applicationId) {
                $.ajax({
                    url:"/applications/" + applicationId + "/tags?term=" + req.term,
                    dataType:"json",
                    success:resp
                });
            }
        }
    });
});<commit_msg>Remove unused autocompletion script.<commit_after><|endoftext|>


<commit_before>// Copyright 2016 Circonus, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

module.exports = {
    root: true,
    extends: [
        '@maier/base',
        '@maier/node',
        '@maier/node-cmd'
    ],
    rules: {
        // ...additional project specific rules
        'max-len': [
            'error',
            {
                code                   : 120,
                tabWidth               : 4,
                ignoreComments         : true,
                ignoreTrailingComments : true,
                ignoreUrls             : true,
                ignoreStrings          : true,
                ignoreTemplateLiterals : true,
                ignoreRegExpLiterals   : true
            }
        ],
        'max-lines': [
            'error',
            {
                max: 1000
            }
        ],
        // destructuring not supported on all omnios nodejs builds yet
        'prefer-destructuring': 'off',
        // most api objects use an underscore prefix to
        // annotate attributes which may not be modified.
        'no-underscore-dangle': 'off',
        'no-restricted-properties' : [
            'error',
            {
                message  : 'DEPRECATED (v6.0.0): use third-party module for logging',
                object   : 'util',
                property : 'log'
            },
            {
                message  : 'DEPRECATED (v0.11.3): use third-party module for logging',
                object   : 'util',
                property : 'print'
            },
            {
                message  : 'DEPRECATED (v0.11.3): use third-party module for logging',
                object   : 'util',
                property : 'puts'
            },
            {
                message  : 'DEPRECATED (v0.11.3): use console.error()',
                object   : 'util',
                property : 'debug'
            },
            {
                message  : 'DEPRECATED (v0.11.3): use console.error()',
                object   : 'util',
                property : 'error'
            },
            {
                message  : 'DEPRECATED (v4.0.0): use Array.isArray()',
                object   : 'util',
                property : 'isArray'
            },
            {
                message  : 'DEPRECATED (v4.0.0): use typeof x === "boolean"',
                object   : 'util',
                property : 'isBoolean'
            },
            {
                message  : 'DEPRECATED (v4.0.0): use Buffer.isBuffer()',
                object   : 'util',
                property : 'isBuffer'
            },
            {
                message  : 'DEPRECATED (v4.0.0)',
                object   : 'util',
                property : 'isDate'
            },
            {
                message  : 'DEPRECATED (v4.0.0)',
                object   : 'util',
                property : 'isError'
            },
            {
                message  : 'DEPRECATED (v4.0.0): use typeof x === "function"',
                object   : 'util',
                property : 'isFunction'
            },
            {
                message  : 'DEPRECATED (v4.0.0): use x === null',
                object   : 'util',
                property : 'isNull'
            },
            {
                message  : 'DEPRECATED (v4.0.0)',
                object   : 'util',
                property : 'isNullOrUndefined'
            },
            {
                message  : 'DEPRECATED (v4.0.0): typeof x === "number"',
                object   : 'util',
                property : 'isNumber'
            },
            {
                message  : 'DEPRECATED (v4.0.0): use typeof x === "object"',
                object   : 'util',
                property : 'isObject'
            },
            {
                message  : 'DEPRECATED (v4.0.0)',
                object   : 'util',
                property : 'isPrimitive'
            },
            {
                message  : 'DEPRECATED (v4.0.0)',
                object   : 'util',
                property : 'isRegExp'
            },
            {
                message  : 'DEPRECATED (v4.0.0): use typeof x === "string"',
                object   : 'util',
                property : 'isString'
            },
            {
                message  : 'DEPRECATED (v4.0.0)',
                object   : 'util',
                property : 'isSymbol'
            },
            {
                message  : 'DEPRECATED (v4.0.0): use typeof x === "undefined"',
                object   : 'util',
                property : 'isUndefined'
            }
        ]
    }
};
<commit_msg>upd pkg names for eslint configs<commit_after>// Copyright 2016 Circonus, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

module.exports = {
    root: true,
    extends: [
        '@maier/eslint-config-base',
        '@maier/eslint-config-node',
        '@maier/eslint-config-node-cmd'
    ],
    rules: {
        // ...additional project specific rules
        'max-len': [
            'error',
            {
                code                   : 120,
                tabWidth               : 4,
                ignoreComments         : true,
                ignoreTrailingComments : true,
                ignoreUrls             : true,
                ignoreStrings          : true,
                ignoreTemplateLiterals : true,
                ignoreRegExpLiterals   : true
            }
        ],
        'max-lines': [
            'error',
            {
                max: 1000
            }
        ],
        // destructuring not supported on all omnios nodejs builds yet
        'prefer-destructuring': 'off',
        // most api objects use an underscore prefix to
        // annotate attributes which may not be modified.
        'no-underscore-dangle': 'off',
        'no-restricted-properties' : [
            'error',
            {
                message  : 'DEPRECATED (v6.0.0): use third-party module for logging',
                object   : 'util',
                property : 'log'
            },
            {
                message  : 'DEPRECATED (v0.11.3): use third-party module for logging',
                object   : 'util',
                property : 'print'
            },
            {
                message  : 'DEPRECATED (v0.11.3): use third-party module for logging',
                object   : 'util',
                property : 'puts'
            },
            {
                message  : 'DEPRECATED (v0.11.3): use console.error()',
                object   : 'util',
                property : 'debug'
            },
            {
                message  : 'DEPRECATED (v0.11.3): use console.error()',
                object   : 'util',
                property : 'error'
            },
            {
                message  : 'DEPRECATED (v4.0.0): use Array.isArray()',
                object   : 'util',
                property : 'isArray'
            },
            {
                message  : 'DEPRECATED (v4.0.0): use typeof x === "boolean"',
                object   : 'util',
                property : 'isBoolean'
            },
            {
                message  : 'DEPRECATED (v4.0.0): use Buffer.isBuffer()',
                object   : 'util',
                property : 'isBuffer'
            },
            {
                message  : 'DEPRECATED (v4.0.0)',
                object   : 'util',
                property : 'isDate'
            },
            {
                message  : 'DEPRECATED (v4.0.0)',
                object   : 'util',
                property : 'isError'
            },
            {
                message  : 'DEPRECATED (v4.0.0): use typeof x === "function"',
                object   : 'util',
                property : 'isFunction'
            },
            {
                message  : 'DEPRECATED (v4.0.0): use x === null',
                object   : 'util',
                property : 'isNull'
            },
            {
                message  : 'DEPRECATED (v4.0.0)',
                object   : 'util',
                property : 'isNullOrUndefined'
            },
            {
                message  : 'DEPRECATED (v4.0.0): typeof x === "number"',
                object   : 'util',
                property : 'isNumber'
            },
            {
                message  : 'DEPRECATED (v4.0.0): use typeof x === "object"',
                object   : 'util',
                property : 'isObject'
            },
            {
                message  : 'DEPRECATED (v4.0.0)',
                object   : 'util',
                property : 'isPrimitive'
            },
            {
                message  : 'DEPRECATED (v4.0.0)',
                object   : 'util',
                property : 'isRegExp'
            },
            {
                message  : 'DEPRECATED (v4.0.0): use typeof x === "string"',
                object   : 'util',
                property : 'isString'
            },
            {
                message  : 'DEPRECATED (v4.0.0)',
                object   : 'util',
                property : 'isSymbol'
            },
            {
                message  : 'DEPRECATED (v4.0.0): use typeof x === "undefined"',
                object   : 'util',
                property : 'isUndefined'
            }
        ]
    }
};
<|endoftext|>


<commit_before>zound.ui.NodeEditor = Backbone.View.extend({
  options: {
    w: 700,
    h: 380
  },
  initialize: function () {
    this.init();
    this.listenTo(this.model, "change", this.render);
    this.listenTo(this.model.modules, "change", this.render);
    this.listenTo(this.model.modules, "add", function (module) {
      this.listenModule(module);
      this.render();
    });
    this.listenTo(this.model.modules, "remove", this.onModuleRemove);
    this.model.modules.each(this.listenModule, this);
    this.render();
  },

  listenModule: function (module) {
    this.listenTo(module, "change", this.render);
    this.listenTo(module.outputs, "add", this.render);
    this.listenTo(module.outputs, "remove", this.render);
  },

  init: function () {
    this.svg = d3.select("#node-editor").append("svg")
      .attr("width", this.options.w)
      .attr("height", this.options.h);
  },

  onModuleRemove: function (module) {
    if (module.$box) {
      module.$box.remove();
      this.render();
    }
  },

  selectModule: function (module) {
    if (module === this.selectedModule) return;
    if (this.selectedModule) {
      this.selectedModule.set('isSelected', false);
      this.trigger("unselectModule", this.selectedModule);
      this.selectedModule = null;
    }
    if (module) {
      this.selectedModule = module;
      module.set('isSelected', true);
      this.trigger("selectModule", module);
    }
  },

  render: function(){
    var editor = this,
        g = this.draw(this.model.modules.models);
    this.addBehaviours(g);
    return g;
  },

  addBehaviours: function(g) {
    var editor = this;

    g.on('click', function(d){
      editor.selectModule(d);
    });

    var move = d3.behavior.drag()
      .on('dragstart', function(m) {
        editor.selectModule(m);
      })
      .on("drag", function (module){
        var x = module.get('x'),
            y = module.get('y');
        module
          .set('x', d3.event.dx + x)
          .set('y', d3.event.dy + y);
      });

    // TODO: activate connect when user is holding Command
    var svg = this.svg,
      connect = d3.behavior.drag()
       .on('dragstart', function(module) {
          editor.selectModule(module);
          var x = module.get('x'),
              y = module.get('y');
          svg
            .insert('svg:line', ":first-child")
            .attr('id', 'connectLine')
            .attr("stroke-dasharray", "5, 5")
            .attr("stroke-width", 2)
            .attr("stroke", "#bfcbdb")
            .attr("x1", x)
            .attr("y1", y)
            .attr("x2", x)
            .attr("y2", y);
        })
       .on("drag", function (module){
          svg.select('#connectLine')
            .attr("x2", d3.event.x)
            .attr("y2", d3.event.y);
       })
       .on("dragend", function (module){
          svg.select('#connectLine').remove();

          var pos = d3.mouse(svg.node()),
              px = pos[0],
              py = pos[1];

          var out = editor.model.modules.find(function (m) {
            var x = m.get("x"),
                y = m.get("y"),
                r = m.get("w") / 2;

            return x - r < px &&
                px < x + r &&
                y - r < py &&
                py < y + r &&
                m.canHaveInputs();
          });

          if (out && module !== out) {
            if (module.outputs.contains(out))
              module.disconnect(out);
            else
              module.connect(out);
          }

       });

     g.call(move);
     return g;
  },

  draw: function (data) {
    var editor = this,
        svg = this.svg,
        options = {
          margin: 15
        };

    var get = function(k){
      return function(m){ return m.get(k); };
    };

    var e = svg
      .selectAll("g")
      .data(data, get('id'));
    e.exit().remove();

    // connections
    var cs = _.flatten(
      _.map(data, function(m){
        return _.map(m.outputs.models, function(o){
          return [m, o];
        });
      }), true);
    var lines = svg.selectAll('line').data(cs);
    lines.enter().insert("svg:line", 'g');
    lines.attr("stroke-width", 2)
      .attr("stroke", "#bfcbdb")
      .attr("x1", function(m) { return m[0].get('x'); })
      .attr("y1", function(m) { return m[0].get('y'); })
      .attr("x2", function(m) { return m[1].get('x'); })
      .attr("y2", function(m) { return m[1].get('y'); });
    lines.exit().remove();

    // groups
    var g = e.enter()
      .append("svg:g")
      .attr('id', get('id'))
      .attr("cursor", "pointer");

    // outer circle
    g.append('svg:circle')
      .attr('class', 'outer')
      .attr("fill", "#f3f9ff")
      .attr("stroke-width", 10);
    e.select('.outer')
      .attr("cx", get('x'))
      .attr("cy", get('y'))
      .attr("r", function(d){ return d.get('w') / 2 + options.margin; })
      .attr("stroke", function(m) { return m.get('isSelected') ? '#79838e' : '#bfcbdb'; });

    // center circle
    g.append('svg:circle')
      .attr('class', 'inner')
      .attr("fill", "#314355")
      .attr("stroke-width", 0);
    e.select('.inner')
      .attr("cx", get('x'))
      .attr("cy", get('y'))
      .attr("r", function(d){ return d.get('w') / 2; });

    // title
    g.append("svg:text")
      .attr('class', 'title')
      .attr("fill", '#fff')
      .attr("font-family", "monospace")
      .attr("font-size", "10px")
      .attr("text-anchor", "middle");
    e.select('.title')
      .attr("x", get('x'))
      .attr("y", get('y'))
      .text(get('title'));

    // id
    g.append("svg:text")
      .attr('class', 'id')
      .attr("fill", "#fff")
      .attr("text-anchor", "middle")
      .attr("font-family", "monospace")
      .attr("font-size", "8px");
    e.select('.id')
      .attr("x", get('x'))
      .attr("y", function(d){ return d.get('y') + 10; })
      .text(get('id'));

    return g;
  }

});
<commit_msg>connect using Command key<commit_after>zound.ui.NodeEditor = Backbone.View.extend({
  options: {
    w: 700,
    h: 380
  },
  initialize: function () {
    this.init();
    this.listenTo(this.model, "change", this.render);
    this.listenTo(this.model.modules, "change", this.render);
    this.listenTo(this.model.modules, "add", function (module) {
      this.listenModule(module);
      this.render();
    });
    this.listenTo(this.model.modules, "remove", this.onModuleRemove);
    this.model.modules.each(this.listenModule, this);
    this.render();
  },

  listenModule: function (module) {
    this.listenTo(module, "change", this.render);
    this.listenTo(module.outputs, "add", this.render);
    this.listenTo(module.outputs, "remove", this.render);
  },

  init: function () {
    this.svg = d3.select("#node-editor").append("svg")
      .attr("width", this.options.w)
      .attr("height", this.options.h);
  },

  onModuleRemove: function (module) {
    if (module.$box) {
      module.$box.remove();
      this.render();
    }
  },

  selectModule: function (module) {
    if (module === this.selectedModule) return;
    if (this.selectedModule) {
      this.selectedModule.set('isSelected', false);
      this.trigger("unselectModule", this.selectedModule);
      this.selectedModule = null;
    }
    if (module) {
      this.selectedModule = module;
      module.set('isSelected', true);
      this.trigger("selectModule", module);
    }
  },

  render: function(){
    var editor = this,
        g = this.draw(this.model.modules.models);
    this.addBehaviours(g);
    return g;
  },

  addBehaviours: function(g) {
    var editor = this;

    g.on('click', function(d){
      editor.selectModule(d);
    });

    var move = d3.behavior.drag()
      .on('dragstart', function(m) {
        editor.selectModule(m);
      })
      .on("drag", function (module){
        var x = module.get('x'),
            y = module.get('y');
        module
          .set('x', d3.event.dx + x)
          .set('y', d3.event.dy + y);
      });

    // TODO: activate connect when user is holding Command
    var svg = this.svg,
      connect = d3.behavior.drag()
       .on('dragstart', function(module) {
          editor.selectModule(module);
          var x = module.get('x'),
              y = module.get('y');
          svg
            .insert('svg:line', ":first-child")
            .attr('id', 'connectLine')
            .attr("stroke-dasharray", "5, 5")
            .attr("stroke-width", 2)
            .attr("stroke", "#bfcbdb")
            .attr("x1", x)
            .attr("y1", y)
            .attr("x2", x)
            .attr("y2", y);
        })
       .on("drag", function (module){
          svg.select('#connectLine')
            .attr("x2", d3.event.x)
            .attr("y2", d3.event.y);
       })
       .on("dragend", function (module){
          svg.select('#connectLine').remove();

          var pos = d3.mouse(svg.node()),
              px = pos[0],
              py = pos[1];

          var out = editor.model.modules.find(function (m) {
            var x = m.get("x"),
                y = m.get("y"),
                r = m.get("w") / 2;

            return x - r < px &&
                px < x + r &&
                y - r < py &&
                py < y + r &&
                m.canHaveInputs();
          });

          if (out && module !== out) {
            if (module.outputs.contains(out))
              module.disconnect(out);
            else
              module.connect(out);
          }

       });

     g.call(move);

     d3.select("body")
      .on("keydown", function() {
        if(d3.event.metaKey)
          g.call(connect);
      })
      .on('keyup', function() {
        if(!d3.event.metaKey)
          g.call(move);
      });

     return g;
  },

  draw: function (data) {
    var editor = this,
        svg = this.svg,
        options = {
          margin: 15
        };

    var get = function(k){
      return function(m){ return m.get(k); };
    };

    var e = svg
      .selectAll("g")
      .data(data, get('id'));

    e.exit().remove();

    // connections
    var cs = _.flatten(
      _.map(data, function(m){
        return _.map(m.outputs.models, function(o){
          return [m, o];
        });
      }), true);
    var lines = svg.selectAll('line').data(cs);
    lines.enter().insert("svg:line", 'g');
    lines.attr("stroke-width", 2)
      .attr("stroke", "#bfcbdb")
      .attr("x1", function(m) { return m[0].get('x'); })
      .attr("y1", function(m) { return m[0].get('y'); })
      .attr("x2", function(m) { return m[1].get('x'); })
      .attr("y2", function(m) { return m[1].get('y'); });
    lines.exit().remove();

    // groups
    var g = e.enter()
      .append("svg:g")
      .attr('id', get('id'))
      .attr("cursor", "pointer");

    // outer circle
    g.append('svg:circle')
      .attr('class', 'outer')
      .attr("fill", "#f3f9ff")
      .attr("stroke-width", 10);
    e.select('.outer')
      .attr("cx", get('x'))
      .attr("cy", get('y'))
      .attr("r", function(d){ return d.get('w') / 2 + options.margin; })
      .attr("stroke", function(m) { return m.get('isSelected') ? '#79838e' : '#bfcbdb'; });

    // center circle
    g.append('svg:circle')
      .attr('class', 'inner')
      .attr("fill", "#314355")
      .attr("stroke-width", 0);
    e.select('.inner')
      .attr("cx", get('x'))
      .attr("cy", get('y'))
      .attr("r", function(d){ return d.get('w') / 2; });

    // title
    g.append("svg:text")
      .attr('class', 'title')
      .attr("fill", '#fff')
      .attr("font-family", "monospace")
      .attr("font-size", "10px")
      .attr("text-anchor", "middle");
    e.select('.title')
      .attr("x", get('x'))
      .attr("y", get('y'))
      .text(get('title'));

    // id
    g.append("svg:text")
      .attr('class', 'id')
      .attr("fill", "#fff")
      .attr("text-anchor", "middle")
      .attr("font-family", "monospace")
      .attr("font-size", "8px");
    e.select('.id')
      .attr("x", get('x'))
      .attr("y", function(d){ return d.get('y') + 10; })
      .text(get('id'));

    return e;
  }

});
<|endoftext|>


<commit_before>/*
 * Paper.js
 *
 * This file is part of Paper.js, a JavaScript Vector Graphics Library,
 * based on Scriptographer.org and designed to be largely API compatible.
 * http://paperjs.org/
 * http://scriptographer.org/
 *
 * Distributed under the MIT license. See LICENSE file for details.
 *
 * Copyright (c) 2011, Juerg Lehni & Jonathan Puckey
 * http://lehni.org/ & http://jonathanpuckey.com/
 *
 * All rights reserved.
 */

/*
 * BlendMode code ported from Context Blender JavaScript Library
 *
 * Copyright © 2010 Gavin Kistner
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

var BlendMode = {
	process: function(blendMode, sourceContext, destContext, opacity, offset) {
		var sourceCanvas = sourceContext.canvas,
			dstData = destContext.getImageData(offset.x, offset.y,
					sourceCanvas.width, sourceCanvas.height),
			dst  = dstData.data,
			src  = sourceContext.getImageData(0, 0,
					sourceCanvas.width, sourceCanvas.height).data,
			min = Math.min,
			max = Math.max,
			sA, dA, rA, sM, dM, rM, sRA, sGA, sBA, dRA, dGA, dBA;

		// TODO: Some blend modes seem broken at the moment, e.g. dodge, burn
		var modes = {
			multiply: function(i) {
				var sA1 = 1 - sA, dA1 = 1 - dA;
				dst[i]     = (sRA * dRA + sRA * dA1 + dRA * sA1) * rM;
				dst[i + 1] = (sGA * dGA + sGA * dA1 + dGA * sA1) * rM;
				dst[i + 2] = (sBA * dBA + sBA * dA1 + dBA * sA1) * rM;
			},

			screen: function(i) {
				dst[i]     = (sRA + dRA - sRA * dRA) * rM;
				dst[i + 1] = (sGA + dGA - sGA * dGA) * rM;
				dst[i + 2] = (sBA + dBA - sBA * dBA) * rM;
			},

			overlay: function(i) {
				// = Reverse of hard-light
				// Correct for 100% opacity case; colors get clipped as opacity falls
				dst[i]     = dRA <= 0.5 ? (2 * src[i]     * dRA / dA) : 255 - (2 - 2 * dRA / dA) * (255 - src[i]);
				dst[i + 1] = dGA <= 0.5 ? (2 * src[i + 1] * dGA / dA) : 255 - (2 - 2 * dGA / dA) * (255 - src[i + 1]);
				dst[i + 2] = dBA <= 0.5 ? (2 * src[i + 2] * dBA / dA) : 255 - (2 - 2 * dBA / dA) * (255 - src[i + 2]);
			},

			// TODO: Missing: soft-light

			'hard-light': function(i) {
				dst[i]     = sRA <= 0.5 ? (2 * dst[i]     * sRA / dA) : 255 - (2 - 2 * sRA / sA) * (255 - dst[i]);
				dst[i + 1] = sGA <= 0.5 ? (2 * dst[i + 1] * sGA / dA) : 255 - (2 - 2 * sGA / sA) * (255 - dst[i + 1]);
				dst[i + 2] = sBA <= 0.5 ? (2 * dst[i + 2] * sBA / dA) : 255 - (2 - 2 * sBA / sA) * (255 - dst[i + 2]);
			},

			'color-dodge': function(i) {
				dst[i]     = src[i]     == 255 && dRA == 0 ? 255 : min(255, dst[i]     / (255 - src[i]    )) * rM;
				dst[i + 1] = src[i + 1] == 255 && dGA == 0 ? 255 : min(255, dst[i + 1] / (255 - src[i + 1])) * rM;
				dst[i + 2] = src[i + 2] == 255 && dBA == 0 ? 255 : min(255, dst[i + 2] / (255 - src[i + 2])) * rM;
			},

			'color-burn': function(i) {
				dst[i]     = src[i]     == 0 && dRA == 0 ? 0 : (1 - min(1, (1 - dRA) / sRA)) * rM;
				dst[i + 1] = src[i + 1] == 0 && dGA == 0 ? 0 : (1 - min(1, (1 - dGA) / sGA)) * rM;
				dst[i + 2] = src[i + 2] == 0 && dBA == 0 ? 0 : (1 - min(1, (1 - dBA) / sBA)) * rM;
			},

			darken: function(i) {
				dst[i]     = min(sRA, dRA) * rM;
				dst[i + 1] = min(sGA, dGA) * rM;
				dst[i + 2] = min(sBA, dBA) * rM;
			},

			lighten: function(i) {
				dst[i]     = max(sRA, dRA) * rM;
				dst[i + 1] = max(sGA, dGA) * rM;
				dst[i + 2] = max(sBA, dBA) * rM;
			},

			difference: function(i) {
				dst[i]     = (sRA + dRA - 2 * min(sRA * dA, dRA * sA)) * rM;
				dst[i + 1] = (sGA + dGA - 2 * min(sGA * dA, dGA * sA)) * rM;
				dst[i + 2] = (sBA + dBA - 2 * min(sBA * dA, dBA * sA)) * rM;
			},

			exclusion: function(i) {
				dst[i]     = (dRA + sRA - 2 * dRA * sRA) * rM;
				dst[i + 1] = (dGA + sGA - 2 * dGA * sGA) * rM;
				dst[i + 2] = (dBA + sBA - 2 * dBA * sBA) * rM;
			},

			// TODO: Missing: hue, saturation, color, luminosity

			// Not in Illustrator:

			'src-in': function(i) {
				// Only differs from Photoshop in low - opacity areas
				rA = sA * dA;
				rM = 255 / rA;
				dst[i]     = sRA * dA * rM;
				dst[i + 1] = sGA * dA * rM;
				dst[i + 2] = sBA * dA * rM;
			},

			add: function(i) {
				// Photoshop doesn't simply add the alpha channels,
				// this might be correct wrt SVG 1.2
				rA = min(1, sA + dA);
				rM = 255 / rA;
				dst[i]     = min(sRA + dRA, 1) * rM;
				dst[i + 1] = min(sGA + dGA, 1) * rM;
				dst[i + 2] = min(sBA + dBA, 1) * rM;
			}
		};

		var process = modes[blendMode];
		if (!process)
			return;
		opacity /= 255;
		for (var i = 0, l = dst.length; i < l; i += 4) {
			sA  = src[i + 3] * opacity;
			dA  = dst[i + 3] / 255;
			rA = sA + dA - sA * dA;
			sM = sA / 255;
			dM = dA / 255;
			sRA = src[i] * sM;
			dRA = dst[i] * dM;
			sGA = src[i + 1] * sM;
			dGA = dst[i + 1] * dM;
			sBA = src[i + 2] * sM;
			dBA = dst[i + 2] * dM;
			rM = 255 / rA;
			process(i);
			dst[i + 3] = rA * 255;
		}
		destContext.putImageData(dstData, offset.x, offset.y);
	}
};
<commit_msg>Fix blend modes to work correctly with alpha channels.<commit_after>/*
 * Paper.js
 *
 * This file is part of Paper.js, a JavaScript Vector Graphics Library,
 * based on Scriptographer.org and designed to be largely API compatible.
 * http://paperjs.org/
 * http://scriptographer.org/
 *
 * Distributed under the MIT license. See LICENSE file for details.
 *
 * Copyright (c) 2011, Juerg Lehni & Jonathan Puckey
 * http://lehni.org/ & http://jonathanpuckey.com/
 *
 * All rights reserved.
 */

/*
 * BlendMode code ported from Context Blender JavaScript Library
 *
 * Copyright © 2010 Gavin Kistner
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

var BlendMode = {
	process: function(blendMode, sourceContext, destContext, opacity, offset) {
		var sourceCanvas = sourceContext.canvas,
			dstData = destContext.getImageData(offset.x, offset.y,
					sourceCanvas.width, sourceCanvas.height),
			dst  = dstData.data,
			src  = sourceContext.getImageData(0, 0,
					sourceCanvas.width, sourceCanvas.height).data,
			min = Math.min,
			max = Math.max,
			abs = Math.abs,
			sr, sb, sg, sa, // source
			br, bb, bg, ba, // backdrop
			dr, dg, db;     // destination

		var modes = {
			multiply: function() {
				dr = br * sr / 255;
				dg = bg * sg / 255;
				db = bb * sb / 255;
			},

			screen: function() {
				dr = 255 - (255 - br) * (255 - sr) / 255;
				dg = 255 - (255 - bg) * (255 - sg) / 255;
				db = 255 - (255 - bb) * (255 - sb) / 255;
			},

			overlay: function() {
				// = Reverse of hard-light
				dr = br < 128 ? 2 * br * sr / 255 : 255 - 2 * (255 - br) * (255 - sr) / 255;
				dg = bg < 128 ? 2 * bg * sg / 255 : 255 - 2 * (255 - bg) * (255 - sg) / 255;
				db = bb < 128 ? 2 * bb * sb / 255 : 255 - 2 * (255 - bb) * (255 - sb) / 255;
			},

			'soft-light': function() {
				var d = sr * br / 255;
				dr = d + br * (255 - (255 - br) * (255 - sr) / 255 - d) / 255;
				d = sg * bg / 255;
				dg = d + bg * (255 - (255 - bg) * (255 - sg) / 255 - d) / 255;
				d = sb * bb / 255;
				db = d + bb * (255 - (255 - bb) * (255 - sb) / 255 - d) / 255;
			},

			'hard-light': function() {
				dr = sr < 128 ? 2 * sr * br / 255 : 255 - 2 * (255 - sr) * (255 - br) / 255;
				dg = sg < 128 ? 2 * sg * bg / 255 : 255 - 2 * (255 - sg) * (255 - bg) / 255;
				db = sb < 128 ? 2 * sb * bb / 255 : 255 - 2 * (255 - sb) * (255 - bb) / 255;
			},

			'color-dodge': function() {
				dr = sr == 255 ? sr : min(255, br * 255 / (255 - sr));
				dg = sg == 255 ? sg : min(255, bg * 255 / (255 - sg));
				db = sb == 255 ? sb : min(255, bb * 255 / (255 - sb));
			},

			'color-burn': function() {
				dr = sr == 0 ? 0 : max(255 - ((255 - br) * 255) / sr, 0);
				dg = sg == 0 ? 0 : max(255 - ((255 - bg) * 255) / sg, 0);
				db = sb == 0 ? 0 : max(255 - ((255 - bb) * 255) / sb, 0);
			},

			darken: function() {
				dr = br < sr ? br : sr;
				dg = bg < sg ? bg : sg;
				db = bb < sb ? bb : sb;
			},

			lighten: function() {
				dr = br > sr ? br : sr;
				dg = bg > sg ? bg : sg;
				db = bb > sb ? bb : sb;
			},

			difference: function() {
				dr = br - sr;
				if (dr < 0)
					dr = -dr;
				dg = bg - sg;
				if (dg < 0)
					dg = -dg;
				db = bb - sb;
				if (db < 0)
					db = -db;
			},

			exclusion: function() {
				dr = br + sr * (255 - br - br) / 255;
				dg = bg + sg * (255 - bg - bg) / 255;
				db = bb + sb * (255 - bb - bb) / 255;
			},

			// TODO: Missing: hue, saturation, color, luminosity

			// TODO: Not in Illustrator:
			add: function() {
				dr = min(br + sr, 255);
				dg = min(bg + sg, 255);
				db = min(bb + sb, 255);
			},

			subtract: function() {
				dr = max(br - sr, 0);
				dg = max(bg - sg, 0);
				db = max(bb - sb, 0);
			},

			average: function() {
				dr = (br + sr) / 2;
				dg = (bg + sg) / 2;
				db = (bb + sb) / 2;
			},

			'pin-light': function() {
				var op = sr < 128 ? min : max;
				dr = op(sr, br);
				dg = op(sg, bg);
				db = op(sb, bb);
			},

			negation: function() {
				dr = 255 - abs(255 - sr - br);
				dg = 255 - abs(255 - sg - bg);
				db = 255 - abs(255 - sb - bb);
			}
		};

		var process = modes[blendMode];
		if (!process)
			return;

		for (var i = 0, l = dst.length; i < l; i += 4) {
			sr = src[i];
			br = dst[i];
			sg = src[i + 1];
			bg = dst[i + 1];
			sb = src[i + 2];
			bb = dst[i + 2];
			sa = src[i + 3];
			ba = dst[i + 3];
			process();
			var a1 = sa * opacity / 255,
				a2 = 1 - a1;
			dst[i] = a1 * dr + a2 * br;
			dst[i + 1] = a1 * dg + a2 * bg;
			dst[i + 2] = a1 * db + a2 * bb;
			dst[i + 3] = sa * opacity + a2 * ba;
		}
		destContext.putImageData(dstData, offset.x, offset.y);
	}
};
<|endoftext|>


<commit_before>import _ from 'lodash'

function isExportMethod(name, value) {
  return name[0] !== '_' && name !== 'constructor' && typeof value === 'function'
}

function getOwnPropertyNames(obj) {
  return obj ? Object.getOwnPropertyNames(obj) : null
}

function extractExportMethods(obj, methods = {}) {
  _.each(getOwnPropertyNames(obj), name => {
    const value = obj[name]
    if (isExportMethod(name, value) && !methods[name]) {
      methods[name] = value
    }
  })
  return methods
}
function getClassMethodsDeep(Class, methods = {}) {
  // eslint-disable-next-line
  while (Class && !Class.isPrototypeOf(Object)) {
    extractExportMethods(Class.prototype, methods)
    Class = Object.getPrototypeOf(Class)
  }
  return methods
}
function getObjectMethodsDeep(obj, methods = {}) {
  extractExportMethods(obj, methods)
  getClassMethodsDeep(Object.getPrototypeOf(obj), methods)
  return methods
}
function convertObjectToMixin(mixin) {
  return Base => {
    // convert object to mixin
    const props = {}
    const Class = class extends Base {
      constructor(...args) {
        super(...args)
        Object.assign(this, props)
      }
    }
    if (_.isPlainObject(mixin)) {
      _.each(mixin, (v, k) => {
        if (typeof v === 'function') {
          Class.prototype[k] = v
        } else {
          props[k] = v
        }
      })
    } else {
      _.assign(Class.prototype, getObjectMethodsDeep(mixin))
    }
    return Class
  }
}

export function isClass(Class) {
  if (typeof Class !== 'function') return false

  const SuperClass = Object.getPrototypeOf(Class)
  // eslint-disable-next-line
  if (!SuperClass.isPrototypeOf(Object)) return true

  const methods = _.without(getOwnPropertyNames(Class.prototype), 'constructor')
  return methods.length > 0
}

// Mixin = A function "with a superclass as input and a subclass extending that superclass as output"
// https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Classes
export function composeClass(...array) {
  const mixins = _.compact(_.flattenDeep(array))

  if (mixins.length === 0) return class {}
  if (mixins.length === 1) return mixins[0]

  const Accumulator = mixins[0]
  if (isClass(Accumulator)) {
    return Accumulator
  }

  // NOTE mixin = "with a superclass as input and a subclass extending that superclass as output"

  // Array.reduce will take first item as accumulator
  if (typeof Accumulator === 'object') {
    mixins[0] = convertObjectToMixin(Accumulator)
  }

  return mixins.reduce((accumulator, mixin) => {
    if (typeof mixin === 'object') {
      mixin = convertObjectToMixin(mixin)
    } else if (isClass(mixin)) {
      // ignore Base and directly return mixin because it is class
      return () => accumulator(mixin)
    }

    // return new mixin = current accumulator + current mixin
    return Base => accumulator(mixin(Base))
  })()
  // finally run all accumulated function with Base argument as undefined / Object
}

export function getSetters(...ids) {
  const obj = {}
  _.each(ids, id => {
    obj[_.camelCase(`get-${id}`)] = function fieldGetter(option) {
      return this.get(id, option)
    }
    obj[_.camelCase(`set-${id}`)] = function fieldSetter(value) {
      return this.set(id, value)
    }
  })
  return obj
}
<commit_msg>less recursive code<commit_after>import _ from 'lodash'

function getOwnPropertyNames(obj) {
  return obj ? Object.getOwnPropertyNames(obj) : null
}

// NOTE less recursive code
// function isExportMethod(name, value) {
//   return name[0] !== '_' && name !== 'constructor' && typeof value === 'function'
// }
// function extractExportMethods(obj, methods = {}) {
//   _.each(getOwnPropertyNames(obj), name => {
//     const value = obj[name]
//     if (isExportMethod(name, value) && !methods[name]) {
//       methods[name] = value
//     }
//   })
//   return methods
// }
// function getClassMethodsDeep(Class, methods = {}) {
//   // eslint-disable-next-line
//   while (Class && !Class.isPrototypeOf(Object)) {
//     extractExportMethods(Class.prototype, methods)
//     Class = Object.getPrototypeOf(Class)
//   }
//   return methods
// }
// function getObjectMethodsDeep(obj, methods = {}) {
//   extractExportMethods(obj, methods)
//   getClassMethodsDeep(Object.getPrototypeOf(obj), methods)
//   return methods
// }
function convertObjectToMixin(mixin) {
  return Base => {
    // convert object to mixin
    const props = {}
    const Class = class extends Base {
      constructor(...args) {
        super(...args)
        Object.assign(this, props)
      }
    }
    // if (_.isPlainObject(mixin)) {
    //   _.each(...)
    // } else {
    //   _.assign(Class.prototype, getObjectMethodsDeep(mixin))
    // }
    _.each(mixin, (v, k) => {
      if (typeof v === 'function') {
        Class.prototype[k] = v
      } else {
        props[k] = v
      }
    })
    return Class
  }
}

export function isClass(Class) {
  if (typeof Class !== 'function') return false

  const SuperClass = Object.getPrototypeOf(Class)
  // eslint-disable-next-line
  if (!SuperClass.isPrototypeOf(Object)) return true

  const methods = _.without(getOwnPropertyNames(Class.prototype), 'constructor')
  return methods.length > 0
}

// Mixin = A function "with a superclass as input and a subclass extending that superclass as output"
// https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Classes
export function composeClass(...array) {
  const mixins = _.compact(_.flattenDeep(array))

  if (mixins.length === 0) return class {}
  if (mixins.length === 1) return mixins[0]

  const Accumulator = mixins[0]
  if (isClass(Accumulator)) {
    return Accumulator
  }

  // NOTE mixin = "with a superclass as input and a subclass extending that superclass as output"

  // Array.reduce will take first item as accumulator
  if (typeof Accumulator === 'object') {
    mixins[0] = convertObjectToMixin(Accumulator)
  }

  return mixins.reduce((accumulator, mixin) => {
    if (typeof mixin === 'object') {
      mixin = convertObjectToMixin(mixin)
    } else if (isClass(mixin)) {
      // ignore Base and directly return mixin because it is class
      return () => accumulator(mixin)
    }

    // return new mixin = current accumulator + current mixin
    return Base => accumulator(mixin(Base))
  })()
  // finally run all accumulated function with Base argument as undefined / Object
}

export function getSetters(...ids) {
  const obj = {}
  _.each(ids, id => {
    obj[_.camelCase(`get-${id}`)] = function fieldGetter(option) {
      return this.get(id, option)
    }
    obj[_.camelCase(`set-${id}`)] = function fieldSetter(value) {
      return this.set(id, value)
    }
  })
  return obj
}
<|endoftext|>


<commit_before>import React from 'react';
import { Observable } from 'rxjs';
import { ActionsObservable } from 'redux-observable';
import Hapi from 'hapi';
import Cookie from 'tough-cookie';
import TestUtils from 'react-addons-test-utils';
import RouterContext from 'react-router/lib/RouterContext';
import match from 'react-router/lib/match';
import { IntlProvider } from 'react-intl';
import { Provider } from 'react-redux';
import {
	MOCK_MEANINGLESS_ACTION,
	MOCK_APP_STATE
} from './mocks/app';

export const findComponentsWithType = (tree, typeString) =>
	TestUtils.findAllInRenderedTree(
		tree,
		(component) => component && component.constructor.name === typeString
	);

export const createFakeStore = fakeData => ({
	getState() {
		return fakeData;
	},
	dispatch() {},
	subscribe() {},
});

export const middlewareDispatcher = middleware => (storeData, action) => {
	let dispatched = null;
	const dispatch = middleware(createFakeStore(storeData))(actionAttempt => dispatched = actionAttempt);
	dispatch(action);
	return dispatched;
};

export const parseCookieHeader = cookieHeader => {
	const cookies = (cookieHeader instanceof Array) ?
		cookieHeader.map(Cookie.parse) :
		[Cookie.parse(cookieHeader)];

	return cookies.reduce(
		(acc, cookie) => ({ ...acc, [cookie.key]: cookie.value }),
		{}
	);

};

export const getServer = connection => {
	const server = new Hapi.Server();
	server.connection(connection);

	// mock the anonAuthPlugin
	server.decorate(
		'request',
		'authorize',
		request => () => Observable.of(request),
		{ apply: true }
	);
	return server;
};

export const epicIgnoreAction = (epic, action=MOCK_MEANINGLESS_ACTION, store=createFakeStore(MOCK_APP_STATE)) => () => {
	const spyable = {
		notCalled: () => {}
	};
	spyOn(spyable, 'notCalled');
	const action$ = ActionsObservable.of(action);
	return epic(action$, store)
		.do(spyable.notCalled, null, expect(spyable.notCalled).not.toHaveBeenCalled())
		.toPromise();
};

/**
 * Curry a function that takes a set of React Router routes and a location to
 * render, and return a Promise that resolves with the rendered React app
 *
 * @example
 * ```
 * const renderLocation = routeRenderer(routes);
 * renderLocation('/').then(app => ...);
 * renderLocation('/foo').then(app => ...);
 * ```
 */
export const routeRenderer = routes => {
	return (location, state=MOCK_APP_STATE) => {
		const FAKE_STORE = createFakeStore(state);
		return new Promise((resolve, reject) => {
			match({ location, routes }, (err, redirectLocation, renderProps) => {
				const app = TestUtils.renderIntoDocument(
					<IntlProvider locale='en'>
						<Provider store={FAKE_STORE}>
							<RouterContext {...renderProps} />
						</Provider>
					</IntlProvider>
				);
				resolve(app);
			});
		});
	};
};

<commit_msg>tighten<commit_after>import React from 'react';
import { Observable } from 'rxjs';
import { ActionsObservable } from 'redux-observable';
import Hapi from 'hapi';
import Cookie from 'tough-cookie';
import TestUtils from 'react-addons-test-utils';
import RouterContext from 'react-router/lib/RouterContext';
import match from 'react-router/lib/match';
import { IntlProvider } from 'react-intl';
import { Provider } from 'react-redux';
import {
	MOCK_MEANINGLESS_ACTION,
	MOCK_APP_STATE
} from './mocks/app';

export const findComponentsWithType = (tree, typeString) =>
	TestUtils.findAllInRenderedTree(
		tree,
		(component) => component && component.constructor.name === typeString
	);

export const createFakeStore = fakeData => ({
	getState() {
		return fakeData;
	},
	dispatch() {},
	subscribe() {},
});

export const middlewareDispatcher = middleware => (storeData, action) => {
	let dispatched = null;
	const dispatch = middleware(createFakeStore(storeData))(actionAttempt => dispatched = actionAttempt);
	dispatch(action);
	return dispatched;
};

export const parseCookieHeader = cookieHeader => {
	const cookies = (cookieHeader instanceof Array) ?
		cookieHeader.map(Cookie.parse) :
		[Cookie.parse(cookieHeader)];

	return cookies.reduce(
		(acc, cookie) => ({ ...acc, [cookie.key]: cookie.value }),
		{}
	);

};

export const getServer = connection => {
	const server = new Hapi.Server();
	server.connection(connection);

	// mock the anonAuthPlugin
	server.decorate(
		'request',
		'authorize',
		request => () => Observable.of(request),
		{ apply: true }
	);
	return server;
};

export const epicIgnoreAction = (epic, action=MOCK_MEANINGLESS_ACTION, store=createFakeStore(MOCK_APP_STATE)) => () => {
	const spyable = {
		notCalled: () => {}
	};
	spyOn(spyable, 'notCalled');
	const action$ = ActionsObservable.of(action);
	return epic(action$, store)
		.do(spyable.notCalled, null, expect(spyable.notCalled).not.toHaveBeenCalled())
		.toPromise();
};

/**
 * Curry a function that takes a set of React Router routes and a location to
 * render, and return a Promise that resolves with the rendered React app
 *
 * @example
 * ```
 * const renderLocation = routeRenderer(routes);
 * renderLocation('/').then(app => ...);
 * renderLocation('/foo').then(app => ...);
 * ```
 */
export const routeRenderer = routes => (location, state=MOCK_APP_STATE) =>
	new Promise((resolve, reject) =>
		match({ location, routes }, (err, redirectLocation, renderProps) => {
			const FAKE_STORE = createFakeStore(state);
			const app = TestUtils.renderIntoDocument(
				<IntlProvider locale='en'>
					<Provider store={FAKE_STORE}>
						<RouterContext {...renderProps} />
					</Provider>
				</IntlProvider>
			);
			resolve(app);
		})
	);

<|endoftext|>


<commit_before>/*
 * Copyright (c) 2017-2019 Onegini B.V.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

'use strict';

const fs = require('fs');
const path = require('path');
const spawn = require('child_process').spawn;

const supportedPlatforms = ['android', 'ios'];
const envVariables = {
  enableAutoconfigure: 'ONEGINI_AUTOCONFIGURE',
  configuratorName: 'ONEGINI_SDK_CONFIGURATOR_PATH',
  configFiles: {
    android: 'ONEGINI_CONFIG_ANDROID_PATH',
    ios: 'ONEGINI_CONFIG_IOS_PATH'
  }
};
const extractedConfigPlugin = 'cordova-plugin-onegini-extracted-config';

module.exports = function (context) {
  if (process.env.ONEGINI_AUTOCONFIGURE === "false") {
    console.log('ONEGINI_AUTOCONFIGURE is set to false. Skipping Onegini SDK Configuration');
    return;
  }

  const projectRoot = context.opts.projectRoot;
  const hasExtractedConfig = hasExtractedConfigFiles(context);
  const deferral = context.requireCordovaModule('q').defer();
  const args = ['--cordova', '--app-dir', projectRoot];
  console.log('Configuring the Onegini SDK');
  console.log('===========================\n\n');

  // deduce the platforms based on whatever in the whitelist is currently installed
  const platforms = supportedPlatforms.filter(platform => fs.existsSync(path.join(projectRoot, "platforms", platform)));

  platforms
    .map(platform => platform.split('@')[0])
    .forEach(platform => {
      console.log(`Configuring the ${platform} platform`);
      console.log('--------------------------' + new Array(platform.length).join('-') + '\n');

      let platformArgs = args.slice();
      platformArgs.unshift(platform);
      const configFile = getConfigFileForPlatform(projectRoot, platform, hasExtractedConfig);
      platformArgs.push('--config', configFile);

      execConfigurator(projectRoot, platform, hasExtractedConfig, platformArgs, deferral);
    });

  return deferral.promise;
};

function executeCommand(command, args) {
  return new Promise(function (resolve, reject) {
    console.log('\nRunning command:');
    console.log(`${command} ${args.join(' ')}\n`);

    const configurator = spawn(command, args);

    configurator.stdout.on('data', (data) => {
      process.stdout.write(data);
    });

    configurator.stderr.on('data', (data) => {
      process.stdout.write(data);
    });

    configurator.on('close', (code) => {
      if (code === 0) {
        resolve("finished");
      }
      else {
        reject("failed");
      }
    });
  });
}

function execConfigurator(projectRoot, platform, hasExtractedConfig, args, deferral) {
  const configuratorName = getConfiguratorName(projectRoot, platform, hasExtractedConfig);
  executeCommand(configuratorName, args)
    .then(copyArtifactoryCredentials(projectRoot, platform, hasExtractedConfig))
    .then(function () {
      deferral.resolve();
    }, function () {
      deferral.reject('Could not configure the Onegini SDK with your configuration');
    });
}

function getConfigFileForPlatform(projectRoot, platform, hasExtractedConfig) {
  const environmentVar = envVariables.configFiles[platform];
  const environmentLocation = process.env[environmentVar];
  const extractedConfigPluginLocation = `${projectRoot}/plugins/${extractedConfigPlugin}/onegini-config-${platform}.zip`;
  const defaultLocation = `${projectRoot}/onegini-config-${platform}.zip`;

  if (environmentLocation) {
    console.log(`Using Token Server config zip: '${environmentLocation}' set in '${environmentVar}'`);
    return environmentLocation;
  }

  if (hasExtractedConfig) {
    console.log(`Using Token Server config zip from '${extractedConfigPluginLocation}'`);
    return extractedConfigPluginLocation;
  }

  console.log(`Using default Token Server config zip: '${defaultLocation}'`);
  return defaultLocation;
}

function getConfiguratorName(projectRoot, platform, hasExtractedConfig) {
  const environmentVar = envVariables.configuratorName;
  const environmentName = process.env[environmentVar];
  const extractedName = `${projectRoot}/plugins/${extractedConfigPlugin}/onegini-sdk-configurator-${platform}`;
  const defaultName = 'onegini-sdk-configurator';

  if (environmentName) {
    console.log(`Using SDK Configurator executable in '${environmentName}' set in '${environmentVar}'`);
    return environmentName;
  }

  if (hasExtractedConfig) {
    console.log(`Using SDK Configurator executable in '${extractedName}'`);
    return extractedName;
  }

  console.log('Using SDK Configurator from $PATH');
  return defaultName;
}

function copyArtifactoryCredentials(projectRoot, platform, hasExtractedConfig) {
  return new Promise(function (resolve, reject) {
    if (platform === 'android' && hasExtractedConfig) {
      const filePath = `${projectRoot}/plugins/${extractedConfigPlugin}/artifactory.properties`;
      const destinationFilePath = path.join(projectRoot, 'platforms/android/artifactory.properties');
      const destDir = path.dirname(destinationFilePath);

      if (fs.existsSync(filePath) && fs.existsSync(destDir)) {
        console.log(`Copying '${filePath}' into '${destDir}'`);
        const stream = fs.createReadStream(filePath).pipe(fs.createWriteStream(destinationFilePath));
        stream.on('end', () => resolve("finished"));
        stream.on('error', (error) => reject("failed"));
        return;
      }
    }
    resolve("Skipping artifactory config");
  });
}

function hasExtractedConfigFiles(context) {
  return context.opts.cordova.plugins.indexOf(extractedConfigPlugin) > -1;
}
<commit_msg>CORDOPLUG-380 wait for all platforms to be configured<commit_after>/*
 * Copyright (c) 2017-2019 Onegini B.V.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

'use strict';

const fs = require('fs');
const path = require('path');
const spawn = require('child_process').spawn;

const supportedPlatforms = ['android', 'ios'];
const envVariables = {
  enableAutoconfigure: 'ONEGINI_AUTOCONFIGURE',
  configuratorName: 'ONEGINI_SDK_CONFIGURATOR_PATH',
  configFiles: {
    android: 'ONEGINI_CONFIG_ANDROID_PATH',
    ios: 'ONEGINI_CONFIG_IOS_PATH'
  }
};
const extractedConfigPlugin = 'cordova-plugin-onegini-extracted-config';

module.exports = function (context) {
  if (process.env.ONEGINI_AUTOCONFIGURE === "false") {
    console.log('ONEGINI_AUTOCONFIGURE is set to false. Skipping Onegini SDK Configuration');
    return;
  }

  const projectRoot = context.opts.projectRoot;
  const hasExtractedConfig = hasExtractedConfigFiles(context);
  const deferral = context.requireCordovaModule('q').defer();
  const args = ['--cordova', '--app-dir', projectRoot];
  console.log('Configuring the Onegini SDK');
  console.log('===========================\n\n');

  // deduce the platforms based on whatever in the whitelist is currently installed
  const platforms = supportedPlatforms.filter(platform => fs.existsSync(path.join(projectRoot, "platforms", platform)));

  platforms
    .map(platform => platform.split('@')[0])
    .forEach(platform => {
      console.log(`Configuring the ${platform} platform`);
      console.log('--------------------------' + new Array(platform.length).join('-') + '\n');

      let platformArgs = args.slice();
      platformArgs.unshift(platform);
      const configFile = getConfigFileForPlatform(projectRoot, platform, hasExtractedConfig);
      platformArgs.push('--config', configFile);

      execConfigurator(projectRoot, platform, hasExtractedConfig, platformArgs, deferral);
    });

  return deferral.promise;
};

function executeCommand(command, args) {
  return new Promise(function (resolve, reject) {
    console.log('\nRunning command:');
    console.log(`${command} ${args.join(' ')}\n`);

    const configurator = spawn(command, args);

    configurator.stdout.on('data', (data) => {
      process.stdout.write(data);
    });

    configurator.stderr.on('data', (data) => {
      process.stdout.write(data);
    });

    configurator.on('close', (code) => {
      if (code === 0) {
        resolve("finished");
      }
      else {
        reject("failed");
      }
    });
  });
}

function execConfigurator(projectRoot, platform, hasExtractedConfig, args, deferral, index, length) {
  const configuratorName = getConfiguratorName(projectRoot, platform, hasExtractedConfig);
  executeCommand(configuratorName, args)
    .then(copyArtifactoryCredentials(projectRoot, platform, hasExtractedConfig))
    .then(function () {
      if (index + 1 === length) {
        deferral.resolve();
      }
    }, function () {
      deferral.reject('Could not configure the Onegini SDK with your configuration');
    });
}

function getConfigFileForPlatform(projectRoot, platform, hasExtractedConfig) {
  const environmentVar = envVariables.configFiles[platform];
  const environmentLocation = process.env[environmentVar];
  const extractedConfigPluginLocation = `${projectRoot}/plugins/${extractedConfigPlugin}/onegini-config-${platform}.zip`;
  const defaultLocation = `${projectRoot}/onegini-config-${platform}.zip`;

  if (environmentLocation) {
    console.log(`Using Token Server config zip: '${environmentLocation}' set in '${environmentVar}'`);
    return environmentLocation;
  }

  if (hasExtractedConfig) {
    console.log(`Using Token Server config zip from '${extractedConfigPluginLocation}'`);
    return extractedConfigPluginLocation;
  }

  console.log(`Using default Token Server config zip: '${defaultLocation}'`);
  return defaultLocation;
}

function getConfiguratorName(projectRoot, platform, hasExtractedConfig) {
  const environmentVar = envVariables.configuratorName;
  const environmentName = process.env[environmentVar];
  const extractedName = `${projectRoot}/plugins/${extractedConfigPlugin}/onegini-sdk-configurator-${platform}`;
  const defaultName = 'onegini-sdk-configurator';

  if (environmentName) {
    console.log(`Using SDK Configurator executable in '${environmentName}' set in '${environmentVar}'`);
    return environmentName;
  }

  if (hasExtractedConfig) {
    console.log(`Using SDK Configurator executable in '${extractedName}'`);
    return extractedName;
  }

  console.log('Using SDK Configurator from $PATH');
  return defaultName;
}

function copyArtifactoryCredentials(projectRoot, platform, hasExtractedConfig) {
  return new Promise(function (resolve, reject) {
    if (platform === 'android' && hasExtractedConfig) {
      const filePath = `${projectRoot}/plugins/${extractedConfigPlugin}/artifactory.properties`;
      const destinationFilePath = path.join(projectRoot, 'platforms/android/artifactory.properties');
      const destDir = path.dirname(destinationFilePath);

      if (fs.existsSync(filePath) && fs.existsSync(destDir)) {
        console.log(`Copying '${filePath}' into '${destDir}'`);
        const stream = fs.createReadStream(filePath).pipe(fs.createWriteStream(destinationFilePath));
        stream.on('end', () => resolve("finished"));
        stream.on('error', (error) => reject("failed"));
        return;
      }
    }
    resolve("Skipping artifactory config");
  });
}

function hasExtractedConfigFiles(context) {
  return context.opts.cordova.plugins.indexOf(extractedConfigPlugin) > -1;
}
<|endoftext|>


<commit_before>import React from 'react'
import { connect } from 'react-redux'

import FloatingActionButton from 'material-ui/FloatingActionButton'
import FileFileDownload from 'material-ui/svg-icons/file/file-download'

const mapStateToProps = ({ }) => ({ })

const DownloadButton = ({fileName, list, style, disabled }) => (
  <FloatingActionButton
    style={style}
    disabled={disabled}
    onClick={() => {
      var content = list.map(line => line.join(',')).join("\n")

      var blob = new Blob([content], {type: 'text/csv'});
      var url = window.URL || window.webkitURL;
      var blobURL = url.createObjectURL(blob);

      if(window.navigator.msSaveBlob){
        window.navigator.msSaveBlob(blob, fileName)
      }
      else{
        var a = document.createElement('a');
         a.download = fileName;
         a.href = blobURL;
         a.click();
       }
     }
    }
    ><FileFileDownload /></FloatingActionButton>
)

export default connect(mapStateToProps)(DownloadButton) <commit_msg>add bom<commit_after>import React from 'react'
import { connect } from 'react-redux'

import FloatingActionButton from 'material-ui/FloatingActionButton'
import FileFileDownload from 'material-ui/svg-icons/file/file-download'

const mapStateToProps = ({ }) => ({ })

const DownloadButton = ({fileName, list, style, disabled }) => (
  <FloatingActionButton
    style={style}
    disabled={disabled}
    onClick={() => {
      var content = list.map(line => line.join(',')).join("\n")
      var bom = new Uint8Array([0xEF, 0xBB, 0xBF]);
      var blob = new Blob([bom,content], {type: 'text/csv'});
      var url = window.URL || window.webkitURL;
      var blobURL = url.createObjectURL(blob);

      if(window.navigator.msSaveBlob){
        window.navigator.msSaveBlob(blob, fileName)
      }
      else{
        var a = document.createElement('a');
         a.download = fileName;
         a.href = blobURL;
         a.click();
       }
     }
    }
    ><FileFileDownload /></FloatingActionButton>
)

export default connect(mapStateToProps)(DownloadButton)
<|endoftext|>


<commit_before>export default []
<commit_msg>Delete even more dead code<commit_after><|endoftext|>


<commit_before>'use strict';

/**
 * Right Track Date Time
 * ---------------------
 * This class handles the various representations of dates and
 * times used by the GTFS Spec and the Right Track Library and
 * the various transformations between them.
 *
 * Time Formats
 * - _string_ hh:mm aa (1:30 PM) | **Human Readable Time**
 * - _string_ HH:mm:ss (13:30:00) | **GTFS Time**
 * - _string_ HH:mm (13:30)
 * - _string_ HHmm (1330)
 * - _int_ seconds since midnight (7:00 am = 25200) | **Time Seconds**
 *
 * Date Formats
 * - _int_ yyyymmdd (20170930) | **Date Integer**
 *
 * **package:** core.utils.DateTime
 *
 * @class
 */
class DateTime {

    /**
     * Right Track Date Time Constructor
     * @constructor
     * @param {(string|int)} time String or Integer representation of the time.  Can be in one
     * of the following formats: 1) HH:mm:ss 2) HH:mm 3) HHmm 4) hh:mm aa or 5) an integer of the
     * number of seconds since midnight (ex 7:00 am = 25200)
     * @param {int=} date The date of the DateTime in the format yyyymmdd
     */
    constructor(time, date=19700101) {

        /**
         * INTERNAL REPRESENTATION
         * time = {int} number of seconds since midnight
         * date = {int} date in the format of yyyymmdd
         */

        // ==== PARSE THE TIME ==== //

        // Time Format: integer with seconds in day
        if ( Number.isInteger(time) ) {

            // Check to make sure time int is within reasonable range
            if ( time >= 0 && time <= 115200 ) {
                this.time = time;
            }

            // Time int is not within reasonable range of 0 --> 32 hours
            else {
                throw new Error("DATETIME ERROR: Time Integer is out of bounds!");
            }
        }
        else {

            // Time format: hh:mm aa
            let matches = time.match("((1[0-2]|0?[1-9]):([0-5][0-9])\\s?([AaPp][Mm]))");
            if ( null !== matches && matches.length > 0 ) {
                let h = parseInt(time.split(":")[0]);
                let m = parseInt(time.split(":")[1].substr(0, 2));
                let aa = time.slice(-2).toLowerCase();

                // Reset h to 0 for 12 AM
                if ( aa === "am" && h === 12 ) {
                    h = 0;
                }

                // Add 12 to h for pm
                else if ( aa === "pm" && h !== 12 ) {
                    h = h + 12;
                }

                this.time = h*3600 + m*60;
            }

            // Time Format: HH:mm:ss OR HH:mm
            else if ( time.indexOf(":") > -1 ) {
                let parts = time.split(":");

                // When there is either 1 or 2 colons
                if ( parts.length === 3 || parts.length === 2 ) {
                    let h = parseInt(parts[0]);
                    let m = parseInt(parts[1]);
                    let s = parts.length === 3 ? parseInt(parts[2]) : 0;

                    // Check to make sure time parts are within a reasonable range
                    if (Number.isInteger(h) && h >= 0 && h <= 32 &&
                        Number.isInteger(m) && m >= 0 && m <= 59 &&
                        Number.isInteger(s) && s >= 0 && s <= 59) {
                        this.time = h*3600 + m*60 + s;
                    }
                    else {
                        throw new Error("DATETIME ERROR: Could not parse the time. h=" + h + ", m=" + m + ", s=" + s);
                    }

                }

                // Time format: incorrect with colon
                else {
                    throw new Error("DATETIME ERROR: Could not parse the time: " + time);
                }

            }

            // Time Format: HHmm
            else if ( time.length === 4 ) {

                // Parse hours and minutes from time
                let h = parseInt(time.substring(0, 2));
                let m = parseInt(time.substring(2, 4));

                // Check to make sure time parse are numbers within a reasonable range
                if ( Number.isInteger(h) && h >= 0 && h <= 32 &&
                     Number.isInteger(m) && m >= 0 && m <= 59 ) {
                    this.time = h*3600 + m*60;
                }
                else {
                    throw new Error("DATETIME ERROR: Could not parse the time. h=" + h + ", m=" + m);
                }

            }

            // Time Format: incorrect
            else {
                throw new Error("DATETIME ERROR: Could not parse the time: " + time);
            }

        }

        // ==== PARSE THE DATE ==== //

        // Make sure the date is within a reasonable range
        if ( date >= 19700101 && date <= 21001231 ) {
            this.date = date;
        }
        else {
            throw new Error("DATETIME ERROR: Date is not within the expected range. date=" + date);
        }

    }

    // ==== TIME GETTERS ==== //

    /**
     * Get the GTFS Spec time representation (HH:mm:ss)
     * @returns {string} GTFS Time (HH:mm:ss)
     */
    getTimeGTFS() {
        let h = Math.floor(this.time/3600);
        let m = Math.floor((this.time%3600)/60);
        let s = Math.floor((this.time%3600)%60);

        // Pad with leading 0s
        if ( h < 10 ) {
            h = "0" + h;
        }
        if ( m < 10 ) {
            m = "0" + m;
        }
        if ( s < 10 ) {
            s = "0" + s;
        }

        return h + ":" + m + ":" + s;
    }

    /**
     * Get the time in seconds since midnight
     * @returns {int} time integer in seconds
     */
    getTimeSeconds() {
        return this.time;
    }

    // ==== DATE GETTERS ==== //

    /**
     * Check if the date is set
     * @returns {boolean} true if the date is set
     */
    isDateSet() {
        return this.date !== 19700101;
    }

    /**
     * Get the integer representation of the date (yyyymmdd)
     * @returns {int} date integer (yyyymmdd)
     */
    getDateInt() {
        return this.date;
    }

    /**
     * Get the full name of the weekday of the date (monday, tuesday, etc)
     * @returns {string} day of week
     */
    getDateDOW() {
        let dow = new Array(7);
        dow[0] = "sunday";
        dow[1] = "monday";
        dow[2] = "tuesday";
        dow[3] = "wednesday";
        dow[4] = "thursday";
        dow[5] = "friday";
        dow[6] = "saturday";

        let s = this.date.toString();
        let y = s.substr(0, 4);
        let m = s.substr(4, 2);
        let d = s.substr(6, 2);
        let jd = new Date(y, m-1, d);

        return dow[jd.getDay()];
    }

    /**
     * Get the date integer (yyyymmdd) of the day following
     * this date
     * @returns {int} the next date (yyyymmdd)
     */
    getNextDateInt() {
        let s = this.date.toString();
        let y = s.substr(0, 4);
        let m = s.substr(4, 2);
        let d = s.substr(6, 2);
        let jd = new Date(y, m-1, d);

        jd.setDate(jd.getDate() + 1);

        y = jd.getFullYear();
        m = jd.getMonth()+1;
        d = jd.getDate();

        if ( m < 10 ) {
            m = "0" + m;
        }
        if ( d < 10 ) {
            d = "0" + d;
        }

        return parseInt("" + y + m + d);
    }

    /**
     * Get the date integer (yyyymmdd) of the day
     * preceding this date
     * @returns {int} the previous date (yyyymmdd)
     */
    getPreviousDateInt() {
        let s = this.date.toString();
        let y = s.substr(0, 4);
        let m = s.substr(4, 2);
        let d = s.substr(6, 2);
        let jd = new Date(y, m-1, d);

        jd.setDate(jd.getDate() - 1);

        y = jd.getFullYear();
        m = jd.getMonth()+1;
        d = jd.getDate();

        if ( m < 10 ) {
            m = "0" + m;
        }
        if ( d < 10 ) {
            d = "0" + d;
        }

        return parseInt("" + y + m + d);
    }

    /**
     * Get a String representation of the DateTIme
     * @returns {string} string of DateTime
     */
    toString() {
        let str = "";
        if ( this.date !== 19700101 ) {
            let s = this.date.toString();
            let y = s.substr(0, 4);
            let m = s.substr(4, 2);
            let d = s.substr(6, 2);

            str = str + y + "-" + m + "-" + d + " ";
        }
        str = str + "@ " + this.getTimeGTFS();
        return str;
    }

}

/**
 * DateTime Factory
 * @param {string} time Time
 * @param {int} date Date
 * @returns {DateTime} DateTime
 */
DateTime.create = function(time, date) {
    return new DateTime(time, date);
};

/**
 * DateTime Factory
 * @param {string} time Time
 * @returns {DateTime} DateTime
 */
DateTime.createFromTime = function(time) {
    return new DateTime(time);
};

/**
 * DateTime Factory
 * @param {int} date Date
 * @returns {DateTime} DateTime
 */
DateTime.createFromDate = function(date) {
    return new DateTime("00:00:00", date);
};

module.exports = DateTime;
<commit_msg>DatTime: get readable time<commit_after>'use strict';

/**
 * Right Track Date Time
 * ---------------------
 * This class handles the various representations of dates and
 * times used by the GTFS Spec and the Right Track Library and
 * the various transformations between them.
 *
 * Time Formats
 * - _string_ hh:mm aa (1:30 PM) | **Human Readable Time**
 * - _string_ HH:mm:ss (13:30:00) | **GTFS Time**
 * - _string_ HH:mm (13:30)
 * - _string_ HHmm (1330)
 * - _int_ seconds since midnight (7:00 am = 25200) | **Time Seconds**
 *
 * Date Formats
 * - _int_ yyyymmdd (20170930) | **Date Integer**
 *
 * **package:** core.utils.DateTime
 *
 * @class
 */
class DateTime {

    /**
     * Right Track Date Time Constructor
     * @constructor
     * @param {(string|int)} time String or Integer representation of the time.  Can be in one
     * of the following formats: 1) HH:mm:ss 2) HH:mm 3) HHmm 4) hh:mm aa or 5) an integer of the
     * number of seconds since midnight (ex 7:00 am = 25200)
     * @param {int=} date The date of the DateTime in the format yyyymmdd
     */
    constructor(time, date=19700101) {

        /**
         * INTERNAL REPRESENTATION
         * time = {int} number of seconds since midnight
         * date = {int} date in the format of yyyymmdd
         */

        // ==== PARSE THE TIME ==== //

        // Time Format: integer with seconds in day
        if ( Number.isInteger(time) ) {

            // Check to make sure time int is within reasonable range
            if ( time >= 0 && time <= 115200 ) {
                this.time = time;
            }

            // Time int is not within reasonable range of 0 --> 32 hours
            else {
                throw new Error("DATETIME ERROR: Time Integer is out of bounds!");
            }
        }
        else {

            // Time format: hh:mm aa
            let matches = time.match("((1[0-2]|0?[1-9]):([0-5][0-9])\\s?([AaPp][Mm]))");
            if ( null !== matches && matches.length > 0 ) {
                let h = parseInt(time.split(":")[0]);
                let m = parseInt(time.split(":")[1].substr(0, 2));
                let aa = time.slice(-2).toLowerCase();

                // Reset h to 0 for 12 AM
                if ( aa === "am" && h === 12 ) {
                    h = 0;
                }

                // Add 12 to h for pm
                else if ( aa === "pm" && h !== 12 ) {
                    h = h + 12;
                }

                this.time = h*3600 + m*60;
            }

            // Time Format: HH:mm:ss OR HH:mm
            else if ( time.indexOf(":") > -1 ) {
                let parts = time.split(":");

                // When there is either 1 or 2 colons
                if ( parts.length === 3 || parts.length === 2 ) {
                    let h = parseInt(parts[0]);
                    let m = parseInt(parts[1]);
                    let s = parts.length === 3 ? parseInt(parts[2]) : 0;

                    // Check to make sure time parts are within a reasonable range
                    if (Number.isInteger(h) && h >= 0 && h <= 32 &&
                        Number.isInteger(m) && m >= 0 && m <= 59 &&
                        Number.isInteger(s) && s >= 0 && s <= 59) {
                        this.time = h*3600 + m*60 + s;
                    }
                    else {
                        throw new Error("DATETIME ERROR: Could not parse the time. h=" + h + ", m=" + m + ", s=" + s);
                    }

                }

                // Time format: incorrect with colon
                else {
                    throw new Error("DATETIME ERROR: Could not parse the time: " + time);
                }

            }

            // Time Format: HHmm
            else if ( time.length === 4 ) {

                // Parse hours and minutes from time
                let h = parseInt(time.substring(0, 2));
                let m = parseInt(time.substring(2, 4));

                // Check to make sure time parse are numbers within a reasonable range
                if ( Number.isInteger(h) && h >= 0 && h <= 32 &&
                     Number.isInteger(m) && m >= 0 && m <= 59 ) {
                    this.time = h*3600 + m*60;
                }
                else {
                    throw new Error("DATETIME ERROR: Could not parse the time. h=" + h + ", m=" + m);
                }

            }

            // Time Format: incorrect
            else {
                throw new Error("DATETIME ERROR: Could not parse the time: " + time);
            }

        }

        // ==== PARSE THE DATE ==== //

        // Make sure the date is within a reasonable range
        if ( date >= 19700101 && date <= 21001231 ) {
            this.date = date;
        }
        else {
            throw new Error("DATETIME ERROR: Date is not within the expected range. date=" + date);
        }

    }

    // ==== TIME GETTERS ==== //

    /**
     * Get the GTFS Spec time representation (HH:mm:ss)
     * @returns {string} GTFS Time (HH:mm:ss)
     */
    getTimeGTFS() {
        let h = Math.floor(this.time/3600);
        let m = Math.floor((this.time%3600)/60);
        let s = Math.floor((this.time%3600)%60);

        // Pad with leading 0s
        if ( h < 10 ) {
            h = "0" + h;
        }
        if ( m < 10 ) {
            m = "0" + m;
        }
        if ( s < 10 ) {
            s = "0" + s;
        }

        return h + ":" + m + ":" + s;
    }

    /**
     * Get the time in seconds since midnight
     * @returns {int} time integer in seconds
     */
    getTimeSeconds() {
        return this.time;
    }

    /**
     * Get the human readable time (12 hr with AM/PM)
     * @returns {string} human readable time
     */
    getTimeReadable() {
        let h = Math.floor(this.time/3600);
        let m = Math.floor((this.time%3600)/60);
        let s = Math.floor((this.time%3600)%60);

        // Pad Minutes with 0s
        if ( m < 10 ) {
            m = "0" + m;
        }

        // 12 AM
        if ( h === 0 ) {
            return "12:" + m + " AM";
        }

        // AM
        else if ( h < 12 ) {
            return h + ":" + m + " AM";
        }

        // 12 PM
        else if ( h === 12 ) {
            return h + ":" + m + " PM";
        }

        // PM
        else if ( h < 24 ) {
            h = h - 12;
            return h + ":" + m + " PM";
        }

        // Next day
        else if ( h === 24 ) {
            h = 12;
            return h + ":" + m + " AM";
        }

        // Next Dat
        else if ( h > 24 ) {
            h = h - 24;
            return h + ":" + m + " AM";
        }

        // Shouldn't reach here
        else {
            return this.getTimeGTFS();
        }

    }

    // ==== DATE GETTERS ==== //

    /**
     * Check if the date is set
     * @returns {boolean} true if the date is set
     */
    isDateSet() {
        return this.date !== 19700101;
    }

    /**
     * Get the integer representation of the date (yyyymmdd)
     * @returns {int} date integer (yyyymmdd)
     */
    getDateInt() {
        return this.date;
    }

    /**
     * Get the full name of the weekday of the date (monday, tuesday, etc)
     * @returns {string} day of week
     */
    getDateDOW() {
        let dow = new Array(7);
        dow[0] = "sunday";
        dow[1] = "monday";
        dow[2] = "tuesday";
        dow[3] = "wednesday";
        dow[4] = "thursday";
        dow[5] = "friday";
        dow[6] = "saturday";

        let s = this.date.toString();
        let y = s.substr(0, 4);
        let m = s.substr(4, 2);
        let d = s.substr(6, 2);
        let jd = new Date(y, m-1, d);

        return dow[jd.getDay()];
    }

    /**
     * Get the date integer (yyyymmdd) of the day following
     * this date
     * @returns {int} the next date (yyyymmdd)
     */
    getNextDateInt() {
        let s = this.date.toString();
        let y = s.substr(0, 4);
        let m = s.substr(4, 2);
        let d = s.substr(6, 2);
        let jd = new Date(y, m-1, d);

        jd.setDate(jd.getDate() + 1);

        y = jd.getFullYear();
        m = jd.getMonth()+1;
        d = jd.getDate();

        if ( m < 10 ) {
            m = "0" + m;
        }
        if ( d < 10 ) {
            d = "0" + d;
        }

        return parseInt("" + y + m + d);
    }

    /**
     * Get the date integer (yyyymmdd) of the day
     * preceding this date
     * @returns {int} the previous date (yyyymmdd)
     */
    getPreviousDateInt() {
        let s = this.date.toString();
        let y = s.substr(0, 4);
        let m = s.substr(4, 2);
        let d = s.substr(6, 2);
        let jd = new Date(y, m-1, d);

        jd.setDate(jd.getDate() - 1);

        y = jd.getFullYear();
        m = jd.getMonth()+1;
        d = jd.getDate();

        if ( m < 10 ) {
            m = "0" + m;
        }
        if ( d < 10 ) {
            d = "0" + d;
        }

        return parseInt("" + y + m + d);
    }

    /**
     * Get a String representation of the DateTIme
     * @returns {string} string of DateTime
     */
    toString() {
        let str = "";
        if ( this.date !== 19700101 ) {
            let s = this.date.toString();
            let y = s.substr(0, 4);
            let m = s.substr(4, 2);
            let d = s.substr(6, 2);

            str = str + y + "-" + m + "-" + d + " ";
        }
        str = str + "@ " + this.getTimeGTFS();
        return str;
    }

}

/**
 * DateTime Factory
 * @param {string} time Time
 * @param {int} date Date
 * @returns {DateTime} DateTime
 */
DateTime.create = function(time, date) {
    return new DateTime(time, date);
};

/**
 * DateTime Factory
 * @param {string} time Time
 * @returns {DateTime} DateTime
 */
DateTime.createFromTime = function(time) {
    return new DateTime(time);
};

/**
 * DateTime Factory
 * @param {int} date Date
 * @returns {DateTime} DateTime
 */
DateTime.createFromDate = function(date) {
    return new DateTime("00:00:00", date);
};

module.exports = DateTime;
<|endoftext|>