<commit_before>/* app/js/controllers.js -- application controllers
 * Copyright 2014 Sergei Ianovich
 *
 * Licensed under AGPL-3.0 or later, see LICENSE
 * Process Control Service Web Interface
 */

'use strict';

function loadDeviceState($scope, deviceId) {
  if ($scope.stateStream) $scope.stateStream.close();
  $scope.stateStream = new EventSource('/devices/' + deviceId
      + '/states?stream=1&interval=10');
  $scope.state = { outputs: {} };
  $scope.stateStream.addEventListener('message', function (e) {
    $scope.$apply(function () {
      $scope.state = angular.fromJson(e.data);
    });
  }, false);
  var off = $scope.$on('$locationChangeStart', function (e, next, current) {
    if ($scope.stateStream) $scope.stateStream.close();
    off();
  });
}

function setDeviceUpdater($scope) {
  $scope.updateDevice = function () {
    $scope.device = {};
    $scope.system.device = null;
    var devices = Device.query({ name: $scope.n.deviceName }, function () {
      if (devices.length !== 2) {
        return;
      }
      $scope.device = devices[0];
      $scope.system.device = devices[0]._id;
      loadDeviceState($scope, $scope.system.device);
    });
  }
}

angular.module('pcs.controllers', [])
  .controller('NavCtrl', ['$scope', '$location', function($scope, $location) {
    $scope.isActive = function (viewLocation) {
      return viewLocation === '#' + $location.path();
    }
  }])
  .controller('PageCtrl', ['$scope', '$location', function($scope, $location) {
    $scope.pager = {
      first: 0,
      last: 0,
      count: 0,
      page: 1,
      show: false
    }
    $scope.moment = moment;
    $scope.operator = {}
    $scope.setNewURL = function (url) {
      $scope.newURL = url;
    }
    $scope.page = function (page, perPage, count) {
      $scope.pager.count = count;
      if (count) {
        $scope.pager.show = true;
      } else {
        $scope.pager.show = false;
      }
      $scope.pager.page = page;
      $scope.pager.first = (page - 1) * perPage + 1;
      $scope.pager.last = page * perPage;
      if (page > 1) {
        $scope.pager.prev = '#' + $location.path() + '?page=' + (page - 1);
      } else {
        $scope.pager.prev = '';
      }
      if ($scope.pager.last >= $scope.pager.count) {
        $scope.pager.last = $scope.pager.count;
        $scope.pager.next = '';
      } else {
        $scope.pager.next = '#' + $location.path() + '?page=' + (page + 1);
      }
    }
  }])
  .controller('NewDeviceCtrl', ['$scope', '$location', 'Device',
      function($scope, $location, Device) {
        $scope.page(1, 1, 0);
        $scope.setNewURL(null);
        $scope.device = new Device();
        $scope.save = function () {
          console.log('Saving ' + $scope.device.name);
          $scope.device.$save({}, function () {
            $scope.deviceForm.$setPristine();
            console.log($scope.device);
            $location.path('/devices/' + $scope.device._id).replace();
          }, function (res) {
            console.log(res);
          });
        }
  }])
  .controller('DeviceCtrl', ['$scope', '$routeParams', 'Device', 'State',
      'Setpoints',
      function($scope, $routeParams, Device, State, Setpoints) {
        $scope.page(1, 1, 0);
        $scope.setNewURL('#/devices/new');
        $scope.device = Device.get({ deviceId: $routeParams.deviceId }, function () {
        });
        $scope.setpoints = Setpoints.get({ deviceId: $routeParams.deviceId }, function () {
        });
        loadDeviceState($scope, $routeParams.deviceId);
        $scope.save = function () {
          console.log('Saving ' + $scope.device._id);
          $scope.device.$save({}, function () {
            $scope.deviceForm.$setPristine();
            console.log($scope.device);
          }, function (res) {
            console.log(res);
          });
        }
  }])
  .controller('DevicesCtrl', ['$scope', '$location', 'Device',
      function($scope, $location, Device) {
        var page = Number($location.search().page) || 1;
        $scope.setNewURL('#/devices/new');
        $scope.devices = Device.query({page: page}, function () {
          var len = $scope.devices.length - 1;
          var count = $scope.devices.splice(len)[0].count;
          $scope.page(page, 25, count);
        });
  }])
  .controller('NewSiteCtrl', ['$scope', '$location', 'Site',
      function($scope, $location, Site) {
        $scope.page(1, 1, 0);
        $scope.setNewURL(null);
        $scope.site = new Site();
        $scope.save = function () {
          console.log('Saving ' + $scope.site.name);
          $scope.site.$save({}, function () {
            $scope.siteForm.$setPristine();
            console.log($scope.site);
            $location.path('/sites/' + $scope.site._id).replace();
          }, function (res) {
            console.log(res);
          });
        }
  }])
  .controller('SiteCtrl', ['$scope', '$routeParams', 'Site', 'System',
      function($scope, $routeParams, Site, System) {
        var page = Number($routeParams.page) || 1;
        $scope.setNewURL('#/sites/' + $routeParams.siteId + '/systems/new');
        $scope.site = Site.get({ siteId: $routeParams.siteId }, function () {
        });
        $scope.systems = System.query({siteId: $routeParams.siteId,
          page: page}, function () {
            var len = $scope.systems.length - 1;
            var count = $scope.systems.splice(len)[0].count;
            $scope.page(page, 25, count);
        });
        $scope.save = function () {
          $scope.site.$save({}, function () {
            $scope.siteForm.$setPristine();
          }, function (res) {
            console.log(res);
          });
        }
  }])
  .controller('SitesCtrl', ['$scope', '$location', 'Site',
      function($scope, $location, Site) {
        var page = Number($location.search().page) || 1;
        $scope.setNewURL('#/sites/new');
        $scope.sites = Site.query({page: page}, function () {
          var len = $scope.sites.length - 1;
          var count = $scope.sites.splice(len)[0].count;
          $scope.page(page, 25, count);
        });
  }])
  .controller('NewSystemCtrl', ['$scope', '$routeParams', '$location',
		  'Site', 'System',
      function($scope, $routeParams, $location, Site, System) {
        $scope.page(1, 1, 0);
        $scope.setNewURL(null);
        $scope.system = new System();
        $scope.system.site = $routeParams.siteId;
        $scope.site = Site.get({ siteId: $routeParams.siteId });
        $scope.save = function () {
          console.log('Saving ' + $scope.system.name);
          $scope.system.$save({}, function () {
            $scope.systemForm.$setPristine();
            console.log($scope.system);
            $location.path('/sites/' + $scope.site._id + '/systems/'
		    + $scope.system._id).replace();
          }, function (res) {
            console.log(res);
          });
        }
        setDeviceUpdater($scope);
  }])
  .controller('SystemCtrl', ['$scope', '$routeParams', 'Site', 'System',
      'Device', 'State',
      function($scope, $routeParams, Site, System, Device, State
        ) {
        $scope.device = {};
        $scope.state = { outputs: {} };
        $scope.n = {};
        $scope.page(1, 1, 0);
        $scope.setNewURL(null);
        $scope.system = System.get({ siteId: $routeParams.siteId,
          systemId: $routeParams.systemId }, function () {
            $scope.device = Device.get({ deviceId: $scope.system.device }, function () {
              $scope.n.deviceName = $scope.device.name;
            });
            if (!$scope.system.outputs)
              $scope.system.outputs = [];
            if (!$scope.system.setpoints)
              $scope.system.setpoints = {};
            loadDeviceState($scope, $scope.system.device);
          });
        $scope.site = Site.get({ siteId: $routeParams.siteId });
        $scope.addOutput = function () {
          $scope.system.outputs.push($scope.n.out);
          $scope.n.out = null;
        }
        $scope.dropOutput = function (i) {
          $scope.system.outputs.splice(i);
        }
        $scope.addSetpoint = function () {
          $scope.system.setpoints[$scope.n.set] = $scope.n.setValue;
          $scope.n.set = null;
        }
        $scope.dropSetpoint = function (key) {
          delete $scope.system.setpoints[key];
          $scope.systemForm.$setDirty();
        }
        $scope.save = function () {
          $scope.system.$save({}, function () {
            $scope.systemForm.$setPristine();
          }, function (res) {
            console.log(res);
          });
        }
  }])
  .controller('NewUserCtrl', ['$scope', '$location', 'User',
      function($scope, $location, User) {
        $scope.page(1, 1, 0);
        $scope.setNewURL(null);
        $scope.user = new User();
        $scope.save = function () {
          console.log('Saving ' + $scope.user.name);
          $scope.user.$save({}, function () {
            $scope.userForm.$setPristine();
            console.log($scope.user);
            $location.path('/users/' + $scope.user._id).replace();
          }, function (res) {
            console.log(res);
          });
        }
  }])
  .controller('UserCtrl', ['$scope', '$routeParams', 'User',
      function($scope, $routeParams, User) {
        $scope.page(1, 1, 0);
        $scope.setNewURL('#/users/new');
        $scope.user = User.get({ userId: $routeParams.userId }, function () {
          console.log($scope.user);
        });
        $scope.save = function () {
          console.log('Saving ' + $scope.user._id);
          $scope.user.$save({}, function () {
            $scope.userForm.$setPristine();
            console.log($scope.user);
          }, function (res) {
            console.log(res);
          });
        }
  }])
  .controller('UsersCtrl', ['$scope', '$location', 'User',
      function($scope, $location, User) {
        var page = Number($location.search().page) || 1;
        $scope.setNewURL('#/users/new');
        $scope.users = User.query({page: page}, function () {
          var len = $scope.users.length - 1;
          var count = $scope.users.splice(len)[0].count;
          $scope.page(page, 25, count);
        });
  }]);

// vim:ts=2 sts=2 sw=2 et:
<commit_msg>system page: mark form dirty on state removal<commit_after>/* app/js/controllers.js -- application controllers
 * Copyright 2014 Sergei Ianovich
 *
 * Licensed under AGPL-3.0 or later, see LICENSE
 * Process Control Service Web Interface
 */

'use strict';

function loadDeviceState($scope, deviceId) {
  if ($scope.stateStream) $scope.stateStream.close();
  $scope.stateStream = new EventSource('/devices/' + deviceId
      + '/states?stream=1&interval=10');
  $scope.state = { outputs: {} };
  $scope.stateStream.addEventListener('message', function (e) {
    $scope.$apply(function () {
      $scope.state = angular.fromJson(e.data);
    });
  }, false);
  var off = $scope.$on('$locationChangeStart', function (e, next, current) {
    if ($scope.stateStream) $scope.stateStream.close();
    off();
  });
}

function setDeviceUpdater($scope) {
  $scope.updateDevice = function () {
    $scope.device = {};
    $scope.system.device = null;
    var devices = Device.query({ name: $scope.n.deviceName }, function () {
      if (devices.length !== 2) {
        return;
      }
      $scope.device = devices[0];
      $scope.system.device = devices[0]._id;
      loadDeviceState($scope, $scope.system.device);
    });
  }
}

angular.module('pcs.controllers', [])
  .controller('NavCtrl', ['$scope', '$location', function($scope, $location) {
    $scope.isActive = function (viewLocation) {
      return viewLocation === '#' + $location.path();
    }
  }])
  .controller('PageCtrl', ['$scope', '$location', function($scope, $location) {
    $scope.pager = {
      first: 0,
      last: 0,
      count: 0,
      page: 1,
      show: false
    }
    $scope.moment = moment;
    $scope.operator = {}
    $scope.setNewURL = function (url) {
      $scope.newURL = url;
    }
    $scope.page = function (page, perPage, count) {
      $scope.pager.count = count;
      if (count) {
        $scope.pager.show = true;
      } else {
        $scope.pager.show = false;
      }
      $scope.pager.page = page;
      $scope.pager.first = (page - 1) * perPage + 1;
      $scope.pager.last = page * perPage;
      if (page > 1) {
        $scope.pager.prev = '#' + $location.path() + '?page=' + (page - 1);
      } else {
        $scope.pager.prev = '';
      }
      if ($scope.pager.last >= $scope.pager.count) {
        $scope.pager.last = $scope.pager.count;
        $scope.pager.next = '';
      } else {
        $scope.pager.next = '#' + $location.path() + '?page=' + (page + 1);
      }
    }
  }])
  .controller('NewDeviceCtrl', ['$scope', '$location', 'Device',
      function($scope, $location, Device) {
        $scope.page(1, 1, 0);
        $scope.setNewURL(null);
        $scope.device = new Device();
        $scope.save = function () {
          console.log('Saving ' + $scope.device.name);
          $scope.device.$save({}, function () {
            $scope.deviceForm.$setPristine();
            console.log($scope.device);
            $location.path('/devices/' + $scope.device._id).replace();
          }, function (res) {
            console.log(res);
          });
        }
  }])
  .controller('DeviceCtrl', ['$scope', '$routeParams', 'Device', 'State',
      'Setpoints',
      function($scope, $routeParams, Device, State, Setpoints) {
        $scope.page(1, 1, 0);
        $scope.setNewURL('#/devices/new');
        $scope.device = Device.get({ deviceId: $routeParams.deviceId }, function () {
        });
        $scope.setpoints = Setpoints.get({ deviceId: $routeParams.deviceId }, function () {
        });
        loadDeviceState($scope, $routeParams.deviceId);
        $scope.save = function () {
          console.log('Saving ' + $scope.device._id);
          $scope.device.$save({}, function () {
            $scope.deviceForm.$setPristine();
            console.log($scope.device);
          }, function (res) {
            console.log(res);
          });
        }
  }])
  .controller('DevicesCtrl', ['$scope', '$location', 'Device',
      function($scope, $location, Device) {
        var page = Number($location.search().page) || 1;
        $scope.setNewURL('#/devices/new');
        $scope.devices = Device.query({page: page}, function () {
          var len = $scope.devices.length - 1;
          var count = $scope.devices.splice(len)[0].count;
          $scope.page(page, 25, count);
        });
  }])
  .controller('NewSiteCtrl', ['$scope', '$location', 'Site',
      function($scope, $location, Site) {
        $scope.page(1, 1, 0);
        $scope.setNewURL(null);
        $scope.site = new Site();
        $scope.save = function () {
          console.log('Saving ' + $scope.site.name);
          $scope.site.$save({}, function () {
            $scope.siteForm.$setPristine();
            console.log($scope.site);
            $location.path('/sites/' + $scope.site._id).replace();
          }, function (res) {
            console.log(res);
          });
        }
  }])
  .controller('SiteCtrl', ['$scope', '$routeParams', 'Site', 'System',
      function($scope, $routeParams, Site, System) {
        var page = Number($routeParams.page) || 1;
        $scope.setNewURL('#/sites/' + $routeParams.siteId + '/systems/new');
        $scope.site = Site.get({ siteId: $routeParams.siteId }, function () {
        });
        $scope.systems = System.query({siteId: $routeParams.siteId,
          page: page}, function () {
            var len = $scope.systems.length - 1;
            var count = $scope.systems.splice(len)[0].count;
            $scope.page(page, 25, count);
        });
        $scope.save = function () {
          $scope.site.$save({}, function () {
            $scope.siteForm.$setPristine();
          }, function (res) {
            console.log(res);
          });
        }
  }])
  .controller('SitesCtrl', ['$scope', '$location', 'Site',
      function($scope, $location, Site) {
        var page = Number($location.search().page) || 1;
        $scope.setNewURL('#/sites/new');
        $scope.sites = Site.query({page: page}, function () {
          var len = $scope.sites.length - 1;
          var count = $scope.sites.splice(len)[0].count;
          $scope.page(page, 25, count);
        });
  }])
  .controller('NewSystemCtrl', ['$scope', '$routeParams', '$location',
		  'Site', 'System',
      function($scope, $routeParams, $location, Site, System) {
        $scope.page(1, 1, 0);
        $scope.setNewURL(null);
        $scope.system = new System();
        $scope.system.site = $routeParams.siteId;
        $scope.site = Site.get({ siteId: $routeParams.siteId });
        $scope.save = function () {
          console.log('Saving ' + $scope.system.name);
          $scope.system.$save({}, function () {
            $scope.systemForm.$setPristine();
            console.log($scope.system);
            $location.path('/sites/' + $scope.site._id + '/systems/'
		    + $scope.system._id).replace();
          }, function (res) {
            console.log(res);
          });
        }
        setDeviceUpdater($scope);
  }])
  .controller('SystemCtrl', ['$scope', '$routeParams', 'Site', 'System',
      'Device', 'State',
      function($scope, $routeParams, Site, System, Device, State
        ) {
        $scope.device = {};
        $scope.state = { outputs: {} };
        $scope.n = {};
        $scope.page(1, 1, 0);
        $scope.setNewURL(null);
        $scope.system = System.get({ siteId: $routeParams.siteId,
          systemId: $routeParams.systemId }, function () {
            $scope.device = Device.get({ deviceId: $scope.system.device }, function () {
              $scope.n.deviceName = $scope.device.name;
            });
            if (!$scope.system.outputs)
              $scope.system.outputs = [];
            if (!$scope.system.setpoints)
              $scope.system.setpoints = {};
            loadDeviceState($scope, $scope.system.device);
          });
        $scope.site = Site.get({ siteId: $routeParams.siteId });
        $scope.addOutput = function () {
          $scope.system.outputs.push($scope.n.out);
          $scope.n.out = null;
        }
        $scope.dropOutput = function (i) {
          $scope.system.outputs.splice(i);
          $scope.systemForm.$setDirty();
        }
        $scope.addSetpoint = function () {
          $scope.system.setpoints[$scope.n.set] = $scope.n.setValue;
          $scope.n.set = null;
        }
        $scope.dropSetpoint = function (key) {
          delete $scope.system.setpoints[key];
          $scope.systemForm.$setDirty();
        }
        $scope.save = function () {
          $scope.system.$save({}, function (e) {
            $scope.systemForm.$setPristine();
          }, function (res) {
            console.log(res);
          });
        }
  }])
  .controller('NewUserCtrl', ['$scope', '$location', 'User',
      function($scope, $location, User) {
        $scope.page(1, 1, 0);
        $scope.setNewURL(null);
        $scope.user = new User();
        $scope.save = function () {
          console.log('Saving ' + $scope.user.name);
          $scope.user.$save({}, function () {
            $scope.userForm.$setPristine();
            console.log($scope.user);
            $location.path('/users/' + $scope.user._id).replace();
          }, function (res) {
            console.log(res);
          });
        }
  }])
  .controller('UserCtrl', ['$scope', '$routeParams', 'User',
      function($scope, $routeParams, User) {
        $scope.page(1, 1, 0);
        $scope.setNewURL('#/users/new');
        $scope.user = User.get({ userId: $routeParams.userId }, function () {
          console.log($scope.user);
        });
        $scope.save = function () {
          console.log('Saving ' + $scope.user._id);
          $scope.user.$save({}, function () {
            $scope.userForm.$setPristine();
            console.log($scope.user);
          }, function (res) {
            console.log(res);
          });
        }
  }])
  .controller('UsersCtrl', ['$scope', '$location', 'User',
      function($scope, $location, User) {
        var page = Number($location.search().page) || 1;
        $scope.setNewURL('#/users/new');
        $scope.users = User.query({page: page}, function () {
          var len = $scope.users.length - 1;
          var count = $scope.users.splice(len)[0].count;
          $scope.page(page, 25, count);
        });
  }]);

// vim:ts=2 sts=2 sw=2 et:
<|endoftext|>


<commit_before>
define([
  'jquery',
  'underscore',
  'backbone',
  'helpers/conf',
  'text!templates/modal.html',
  'text!templates/welcome.html'
], function($, _, Backbone, ConfHelper, ModalTemplate, WelcomeTemplate) {
  return {

    version: '',
    isExtension: true,
    urlPrefix: 'https://eksisozluk.com/',

    initialize: function(version) {
      this.version = version;

      if (document.domain.match(/(github\.io|eksi\.ninja)$/)) {
        this.isExtension = false;
        this.urlPrefix   = 'http://proxy.eksi.ninja/';
      }
    },

    modal: function(title, message) {

      $('#generic-modal').remove();
      $('body').append(_.template(ModalTemplate, { title: title,
                                                   message: message }));
      $('#generic-modal').modal('show');

    },

    welcome: function () {

      var welcome_page_version = [];
      var current_version = this.version.match(/(\d+)\.(\d+)\.(\d+)/);
      if (ConfHelper.options.welcome_page &&
          (welcome_page_version =
               ConfHelper.options.welcome_page.match(/(\d+)\.(\d+)\.(\d+)/)) &&
          current_version[1] <= welcome_page_version[1] &&
          current_version[2] <= welcome_page_version[2]) {
        return;
      }

      $('#welcome-modal').remove();
      $('body').append(_.template(WelcomeTemplate,
            { version: {
                          version_str: this.version,
                          current_version: current_version,
                          old_version: welcome_page_version
                        },
              isExtension: this.isExtension }));
      $('#welcome-modal').modal('show');

      // save version info in welcome_page option
      // we can show what's new in next version
      ConfHelper.options.welcome_page = this.version;
      ConfHelper.saveConf();

    }

  };

});
<commit_msg>Set correct proxy url<commit_after>
define([
  'jquery',
  'underscore',
  'backbone',
  'helpers/conf',
  'text!templates/modal.html',
  'text!templates/welcome.html'
], function($, _, Backbone, ConfHelper, ModalTemplate, WelcomeTemplate) {
  return {

    version: '',
    isExtension: true,
    urlPrefix: 'https://eksisozluk.com/',

    initialize: function(version) {
      this.version = version;

      if (document.domain.match(/(github\.io|eksi\.ninja)$/)) {
        this.isExtension = false;
        this.urlPrefix   = '/proxy/';
      }
    },

    modal: function(title, message) {

      $('#generic-modal').remove();
      $('body').append(_.template(ModalTemplate, { title: title,
                                                   message: message }));
      $('#generic-modal').modal('show');

    },

    welcome: function () {

      var welcome_page_version = [];
      var current_version = this.version.match(/(\d+)\.(\d+)\.(\d+)/);
      if (ConfHelper.options.welcome_page &&
          (welcome_page_version =
               ConfHelper.options.welcome_page.match(/(\d+)\.(\d+)\.(\d+)/)) &&
          current_version[1] <= welcome_page_version[1] &&
          current_version[2] <= welcome_page_version[2]) {
        return;
      }

      $('#welcome-modal').remove();
      $('body').append(_.template(WelcomeTemplate,
            { version: {
                          version_str: this.version,
                          current_version: current_version,
                          old_version: welcome_page_version
                        },
              isExtension: this.isExtension }));
      $('#welcome-modal').modal('show');

      // save version info in welcome_page option
      // we can show what's new in next version
      ConfHelper.options.welcome_page = this.version;
      ConfHelper.saveConf();

    }

  };

});
<|endoftext|>


<commit_before>var async = require('async'),
	fs = require('fs'),
	config = require('../../config/config'),
	exec = require('child_process').exec;

module.exports = function(){
	var errors = 0;
    async.series([
		function(cb){
			fs.exists(config.mediaDir,function(exists){
				if(!exists){
                    fs.mkdir(config.mediaDir,0777,function (err) {
                        if (err) {
                            console.log('*****************************************************');
                            console.log('*     Unable to create media directory, exiting     *');
                            console.log('*****************************************************\n');
                            process.exit(1);
                        } else {
                            cb()
                        }
                    })
				} else
				    cb();
			})
		},
		function(cb){
			fs.exists(config.thumbnailDir,function(exists){
				if(!exists){
                    fs.mkdir(config.thumbnailDir,0777,function (err) {
                        if (err) {
                            console.log('********************************************************************');
                            console.log('* media/_thumbnails directory absent, thumbnails cannot be created *');
                            console.log('********************************************************************\n');
                            errors++;
                        }
                        cb()
                    })
                } else
				    cb();
			})
		},
		function(cb){
			exec('which ffprobe',function(err,stdout,stderr){
				if(err){
					console.log('****************************************************************');
					console.log('*  Please install ffmpeg, videos cannot be uploaded otherwise  *');
					console.log('****************************************************************\n');
                    errors++;
                }
				cb();
			})
		},
		function(cb){
			exec('which convert',function(err,stdout,stderr){
				if(err){
					console.log('*********************************************************************');
					console.log('* Please install imagemagik, otherwise thumbnails cannot be created *');
					console.log('*********************************************************************\n');
                    errors++;
                }
				cb();
			})
		}
	],function(err){
		console.log('********************************************');
		if (errors)
            console.log('*  system check complete with '+errors+' errors     *');
        else
            console.log('*        system check passed               *');
        console.log('********************************************');
	})
}<commit_msg>making check OS agnostic<commit_after>var async = require('async'),
	fs = require('fs'),
	config = require('../../config/config'),
	exec = require('child_process').exec;

module.exports = function(){
	var errors = 0;
    async.series([
		function(cb){
			fs.exists(config.mediaDir,function(exists){
				if(!exists){
                    fs.mkdir(config.mediaDir,0777,function (err) {
                        if (err) {
                            console.log('*****************************************************');
                            console.log('*     Unable to create media directory, exiting     *');
                            console.log('*****************************************************\n');
                            process.exit(1);
                        } else {
                            cb()
                        }
                    })
				} else
				    cb();
			})
		},
		function(cb){
			fs.exists(config.thumbnailDir,function(exists){
				if(!exists){
                    fs.mkdir(config.thumbnailDir,0777,function (err) {
                        if (err) {
                            console.log('********************************************************************');
                            console.log('* media/_thumbnails directory absent, thumbnails cannot be created *');
                            console.log('********************************************************************\n');
                            errors++;
                        }
                        cb()
                    })
                } else
				    cb();
			})
		},
		function(cb){
			exec('ffprobe -version',function(err,stdout,stderr){
				if(err){
					console.log('****************************************************************');
					console.log('*  Please install ffmpeg, videos cannot be uploaded otherwise  *');
					console.log('****************************************************************\n');
                    console.log(err)
                    errors++;
                }
				cb();
			})
		},
		function(cb){
			exec('convert -version',function(err,stdout,stderr){
                if(err){
					console.log('*********************************************************************');
					console.log('* Please install imagemagik, otherwise thumbnails cannot be created *');
					console.log('*********************************************************************\n');
                    console.log(err)
                    errors++;
                }
				cb();
			})
		}
	],function(err){
		console.log('********************************************');
		if (errors)
            console.log('*  system check complete with '+errors+' errors     *');
        else
            console.log('*        system check passed               *');
        console.log('********************************************');
	})
}<|endoftext|>


<commit_before>'use strict';

const Ractive = require('lib/ractive');
const emitter = require('lib/emitter');
const CS = require('lib/wallet');
const showTooltip = require('widgets/modals/tooltip');
const showQr = require('widgets/modals/qr');
const geo = require('lib/geo');
const { showError } = require('widgets/modals/flash');
const showSetDetails = require('widgets/modals/set-details');
const qrcode = require('lib/qrcode');
const initEosSetup = require('widgets/eos/setup');
const details = require('lib/wallet/details');
const { translate } = require('lib/i18n');

module.exports = function(el) {
  const ractive = new Ractive({
    el,
    template: require('./index.ract'),
    data: {
      address: '',
      qrVisible: false,
      btn_message: 'Turn Mecto on',
      connecting: false,
      broadcasting: false,
      isPhonegap: process.env.BUILD_TYPE === 'phonegap',
      addressTypes: [],
      addressType: '',
      addressTooltip: false,
      getAddressTypeLabel(type) {
        if (type === 'p2pkh') return '(P2PKH)';
        if (type === 'p2sh') return '(P2SH)';
        if (type === 'p2wpkh') return '(Bech32)';
        return '-';
      },
      getAddressTypeOption(type) {
        if (type === 'p2pkh') return translate('P2PKH - Legacy');
        if (type === 'p2sh') return translate('P2SH - SegWit compatible');
        if (type === 'p2wpkh') return translate('Bech32 - SegWit native');
        return '-';
      },
    },
  });

  initEosSetup(ractive.find('#eos-setup'));

  emitter.on('wallet-ready', () => {
    const wallet = CS.getWallet();
    ractive.set('needToSetupEos', wallet.networkName === 'eos' && !wallet.isActive);

    const addressTypes = (wallet.network && wallet.network.addressTypes) || [];
    ractive.set('addressTypes', addressTypes);
    ractive.set('addressType', wallet.addressType);
    ractive.set('addressTooltip', [
      'bitcoin',
      'bitcoincash',
      'bitcoinsv',
      'litecoin',
      'dogecoin',
      'dash',
    ].indexOf(wallet.networkName) !== -1);
    showAddress();
  });
  emitter.on('tx-sent', showAddress);
  emitter.on('change-address-type', showAddress);

  ractive.on('change-address-type', () => {
    const wallet = CS.getWallet();
    const addressType = ractive.get('addressType');
    details.set(wallet.networkName + '.addressType', addressType)
      .then(() => {
        wallet.addressType = addressType;
        emitter.emit('change-address-type');
      })
      .catch(console.error);
  });

  ractive.on('toggle-broadcast', () => {
    if (ractive.get('connecting')) return;

    if (ractive.get('broadcasting')) {
      mectoOff();
    } else {
      showSetDetails(() => {
        mectoOn();
      });
    }
  });

  function showQRcode(address) {
    if (ractive.get('isPhonegap')) {
      const canvas = document.getElementById('qr_canvas');
      while (canvas.hasChildNodes()) {
        canvas.removeChild(canvas.firstChild);
      }
      const qr = qrcode.encode(CS.getWallet().networkName + ':' + address);
      canvas.appendChild(qr);
    }
  }

  function mectoOff() {
    ractive.set('broadcasting', false);
    ractive.set('btn_message', 'Turn Mecto on');
    geo.remove();
  }

  async function mectoOn() {
    ractive.set('connecting', true);
    ractive.set('btn_message', 'Checking your location');
    try {
      await geo.save();
      ractive.set('connecting', false);
      ractive.set('broadcasting', true);
      ractive.set('btn_message', 'Turn Mecto off');
    } catch (err) {
      return handleMectoError(err);
    }
  }

  ractive.on('show-qr', () => {
    if (ractive.get('isPhonegap')) {
      window.plugins.socialsharing.shareWithOptions({
        message: ractive.get('address'),
      });
    } else {
      showQr({
        address: ractive.get('address'),
        name: CS.getWallet().networkName,
      });
    }
  });

  ractive.on('help-address', () => {
    // eslint-disable-next-line max-len
    let message = translate('Address will be changed after receiving funds. All previously used addresses remain valid and still can be used to receive funds multiple times. Please use fresh address for each receiving transaction to enhance your privacy.');
    if (ractive.get('addressTypes').length > 1) {
      message += '

';
      message += translate(
        // eslint-disable-next-line max-len
        'Not all address types are fully compatible on all platforms, so it is important to use a compatible address (:url).',
        // eslint-disable-next-line max-len
        { url: "" + translate('more info') + "" }
      );
    }
    showTooltip({
      message,
      isHTML: true,
      isTranslated: true,
    });
  });

  ractive.on('help-mecto', () => {
    showTooltip({
      // eslint-disable-next-line max-len
      message: 'Mecto lets you broadcast your wallet address to other nearby Coin users by comparing GPS data. This data is deleted once you turn Mecto off.',
    });
  });

  function showAddress() {
    const address = CS.getWallet().getNextAddress();
    ractive.set('address', address);
    showQRcode(address);
  }

  function handleMectoError(err) {
    showError({
      message: err.message,
    });
    ractive.set('connecting', false);
    ractive.set('broadcasting', false);
    ractive.set('btn_message', 'Turn Mecto on');
  }

  return ractive;
};
<commit_msg>fix(android): black qr<commit_after>'use strict';

const Ractive = require('lib/ractive');
const emitter = require('lib/emitter');
const CS = require('lib/wallet');
const showTooltip = require('widgets/modals/tooltip');
const showQr = require('widgets/modals/qr');
const geo = require('lib/geo');
const { showError } = require('widgets/modals/flash');
const showSetDetails = require('widgets/modals/set-details');
const qrcode = require('lib/qrcode');
const initEosSetup = require('widgets/eos/setup');
const details = require('lib/wallet/details');
const { translate } = require('lib/i18n');

module.exports = function(el) {
  const ractive = new Ractive({
    el,
    template: require('./index.ract'),
    data: {
      address: '',
      qrVisible: false,
      btn_message: 'Turn Mecto on',
      connecting: false,
      broadcasting: false,
      isPhonegap: process.env.BUILD_TYPE === 'phonegap',
      addressTypes: [],
      addressType: '',
      addressTooltip: false,
      getAddressTypeLabel(type) {
        if (type === 'p2pkh') return '(P2PKH)';
        if (type === 'p2sh') return '(P2SH)';
        if (type === 'p2wpkh') return '(Bech32)';
        return '-';
      },
      getAddressTypeOption(type) {
        if (type === 'p2pkh') return translate('P2PKH - Legacy');
        if (type === 'p2sh') return translate('P2SH - SegWit compatible');
        if (type === 'p2wpkh') return translate('Bech32 - SegWit native');
        return '-';
      },
    },
  });

  initEosSetup(ractive.find('#eos-setup'));

  ractive.on('before-show', () => {
    showAddress();
  });

  emitter.on('wallet-ready', () => {
    const wallet = CS.getWallet();
    ractive.set('needToSetupEos', wallet.networkName === 'eos' && !wallet.isActive);

    const addressTypes = (wallet.network && wallet.network.addressTypes) || [];
    ractive.set('addressTypes', addressTypes);
    ractive.set('addressType', wallet.addressType);
    ractive.set('addressTooltip', [
      'bitcoin',
      'bitcoincash',
      'bitcoinsv',
      'litecoin',
      'dogecoin',
      'dash',
    ].indexOf(wallet.networkName) !== -1);
  });
  emitter.on('change-address-type', showAddress);

  ractive.on('change-address-type', () => {
    const wallet = CS.getWallet();
    const addressType = ractive.get('addressType');
    details.set(wallet.networkName + '.addressType', addressType)
      .then(() => {
        wallet.addressType = addressType;
        emitter.emit('change-address-type');
      })
      .catch(console.error);
  });

  ractive.on('toggle-broadcast', () => {
    if (ractive.get('connecting')) return;

    if (ractive.get('broadcasting')) {
      mectoOff();
    } else {
      showSetDetails(() => {
        mectoOn();
      });
    }
  });

  function showQRcode(address) {
    if (ractive.get('isPhonegap')) {
      const canvas = document.getElementById('qr_canvas');
      while (canvas.hasChildNodes()) {
        canvas.removeChild(canvas.firstChild);
      }
      const qr = qrcode.encode(CS.getWallet().networkName + ':' + address);
      canvas.appendChild(qr);
    }
  }

  function mectoOff() {
    ractive.set('broadcasting', false);
    ractive.set('btn_message', 'Turn Mecto on');
    geo.remove();
  }

  async function mectoOn() {
    ractive.set('connecting', true);
    ractive.set('btn_message', 'Checking your location');
    try {
      await geo.save();
      ractive.set('connecting', false);
      ractive.set('broadcasting', true);
      ractive.set('btn_message', 'Turn Mecto off');
    } catch (err) {
      return handleMectoError(err);
    }
  }

  ractive.on('show-qr', () => {
    if (ractive.get('isPhonegap')) {
      window.plugins.socialsharing.shareWithOptions({
        message: ractive.get('address'),
      });
    } else {
      showQr({
        address: ractive.get('address'),
        name: CS.getWallet().networkName,
      });
    }
  });

  ractive.on('help-address', () => {
    // eslint-disable-next-line max-len
    let message = translate('Address will be changed after receiving funds. All previously used addresses remain valid and still can be used to receive funds multiple times. Please use fresh address for each receiving transaction to enhance your privacy.');
    if (ractive.get('addressTypes').length > 1) {
      message += '

';
      message += translate(
        // eslint-disable-next-line max-len
        'Not all address types are fully compatible on all platforms, so it is important to use a compatible address (:url).',
        // eslint-disable-next-line max-len
        { url: "" + translate('more info') + "" }
      );
    }
    showTooltip({
      message,
      isHTML: true,
      isTranslated: true,
    });
  });

  ractive.on('help-mecto', () => {
    showTooltip({
      // eslint-disable-next-line max-len
      message: 'Mecto lets you broadcast your wallet address to other nearby Coin users by comparing GPS data. This data is deleted once you turn Mecto off.',
    });
  });

  function showAddress() {
    const address = CS.getWallet().getNextAddress();
    ractive.set('address', address);
    showQRcode(address);
  }

  function handleMectoError(err) {
    showError({
      message: err.message,
    });
    ractive.set('connecting', false);
    ractive.set('broadcasting', false);
    ractive.set('btn_message', 'Turn Mecto on');
  }

  return ractive;
};
<|endoftext|>


<commit_before>/*
SMTPAPI Library for AppC
*/

function smtpapi(header) {
  header = header || {};
  this.header = {};
  this.header.to = header.to || [];
  this.header.sub = header.sub || {};
  this.header.unique_args = header.unique_args || {};
  this.header.category = header.category || [];
  this.header.section = header.section || {};
  this.header.filters = header.filters || {};
}

smtpapi.prototype.addTo = function(to) {
  if (to instanceof Array) {
    this.header.to = this.header.to.concat(to);
  } else {
    this.header.to.push(to);
  }
};

smtpapi.prototype.setTos = function(to) {
  if (to instanceof Array) {
    this.header.to = to;
  } else {
    this.header.to = [to];
  }
};

smtpapi.prototype.addSubstitution = function(key, val) {
  if (this.header.sub[key] === undefined) this.header.sub[key] = [];
  if (val instanceof Array) {
    this.header.sub = this.header.sub[key].concat(val);
  } else {
    this.header.sub[key].push(val);
  }
};

smtpapi.prototype.setSubstitutions = function(subs) {
  this.header.sub = subs;
};

smtpapi.prototype.addUniqueArg = function(key, val) {
  this.header.unique_args[key] = val;
};

smtpapi.prototype.setUniqueArgs = function(val) {
  this.header.unique_args = val;
};

smtpapi.prototype.addCategory = function(cat) {
  if (cat instanceof Array) {
    this.header.category.concat(cat);
  } else {
    this.header.category.push(cat);
  }
};

smtpapi.prototype.setCategories = function(cats) {
  if (cats instanceof Array) {
    this.header.category = cats;
  } else {
    this.header.category = [cats];
  }
};

smtpapi.prototype.addSection = function(sec, val) {
  this.header.section[sec] = val;
};

smtpapi.prototype.setSections = function(sec) {
  this.header.section = sec;
};

smtpapi.prototype.addFilter = function(filter, setting, val) {
  if (this.header.filters[filter] === undefined) {
    this.header.filters[filter] = {'settings': {}};
  }
  this.header.filters[filter].settings[setting] = val;
};

smtpapi.prototype.setFilters = function(filters) {
  this.header.filters = filters;
};

smtpapi.prototype.jsonString = function() {
  var header = {};
  for (var key in this.header) {
    if (this.header.hasOwnProperty(key) && Object.keys(this.header[key]).length) {
      header[key] = this.header[key];
    }
  }
  return JSON.stringify(header);
};

/*
SendGrid.Email implementation for AppC
*/

function Email(mail) {
  if (!(this instanceof Email)) {
    return new Email(mail);
  }

  mail = mail || {};
  smtpapi.call(this, mail['x-smtpapi']);
  this.body = {};
  this.toCounter = 0;
  this.bccCounter = 0;
  this.tonameCounter = 0;
  this.addTo(mail.to || mail['to[]']);
  this.addToName(mail.toname || mail['toname[]']);
  this.addBcc(mail.bcc || mail['bcc[]']);
  this.body.from = mail.from || '';
  this.body.fromname = mail.fromname || '';
  this.body.subject = mail.subject || '';
  this.body.text = mail.text || '';
  this.body.html = mail.html || '';
  this.body.replyto = mail.replyto || '';
  this.body.dates = mail.date || new Date().toUTCString();
  this.body.headers = mail.headers || '';
  if (mail.files && mail.files instanceof Array) {
    for (var i = 0, len = mail.files.length; i < len; i++) {
      this.addFile(mail.files[i].file, mail.files[i].name);
    }
  }
}

Email.prototype = Object.create(smtpapi.prototype);
Email.prototype.constructor = Email;

Email.prototype.addTo = function(email) {
  if (email instanceof Array) {
    for(var i = 0, len = email.length; i < len; i++) {
      this.body['to[' + this.toCounter++ +']'] = email[i];
    }
  } else {
    this.body['to['+ this.toCounter++ +']'] = email;
  }
};

Email.prototype.addToName = function(name) {
  if (name instanceof Array) {
    for(var i = 0, len = name.length; i < len; i++) {
      this.body['toname[' + this.tonameCounter++ +']'] = name[i];
    }
  } else {
    this.body['toname['+ this.tonameCounter++ +']'] = name;
  }
};

Email.prototype.setFrom = function(email) {
  this.body.from = email;
};

Email.prototype.setFromName = function(name) {
  this.body.fromname = name;
};

Email.prototype.setSubject = function(subject) {
  this.body.subject = subject;
};

Email.prototype.setText = function(text) {
  this.body.text = text;
};

Email.prototype.setHTML = function(html) {
  this.body.html = html;
};

Email.prototype.addBcc = function(bcc) {
  if (bcc instanceof Array) {
    for(var i = 0, len = bcc.length; i < len; i++) {
      this.body['bcc[' + this.bccCounter++ + ']'] = bcc[i];
    }
  } else {
    this.body['bcc['+ this.bccCounter++ +']'] = bcc;
  }
};

Email.prototype.setReplyTo = function(replyto) {
  this.body.replyto = replyto;
};

Email.prototype.setDate = function(date) {
  this.body.date = date;
};

Email.prototype.addFile = function(file, name) {
  if (typeof file === 'string') {
    file = Titanium.Filesystem.getFile(file);
  }
  name = name || file.name;
  this.body['files[' + name + ']'] = file;
};

Email.prototype.setHeaders = function(header) {
  this.body.header = header;
};

Email.prototype.setAPIHeader = function(header) {
  this.body['x-smtpapi'] = header || this.jsonString();
};

Email.prototype.getEmail = function() {
  this.setAPIHeader();
  var body = {};
  for (var key in this.body) {
    if (this.body.hasOwnProperty(key) && this.body[key]) {
      if (this.body[key] instanceof Array && this.body[key].length === 0) {
        continue;
      }
      body[key] = this.body[key];
    }
  }
  return body;
};

function SendGrid(api_user, api_key) {
  if (!(this instanceof SendGrid)) {
    return new SendGrid(api_user, api_key);
  }

  //Private
  var _buildBody = function(mail) {
    if (mail.constructor.name === 'Email') {
      mail = mail.getEmail();
    } else {
      mail = (new Email(mail)).getEmail();
    }
    mail.api_user = credentials.api_user;
    mail.api_key = credentials.api_key;
    return mail;
  };

  var options = {
    method  : 'POST',
    uri     : 'https://api.sendgrid.com/api/mail.send.json'
  };

  var credentials = {
    api_user: api_user,
    api_key: api_key
  };

  //Priviledged
  this.send = function (email, cb) {
    var client = Ti.Network.createHTTPClient({
      onload: function(e) {
        cb(null);
      },
      onerror: function(e) {
        cb(JSON.parse(this.responseText));
      },
      timeout: 5000
    });

    email = _buildBody(email);
    client.open(options.method, options.uri);
    client.send(email);
  };

  this.Email = Email;
  this.smtpapi = smtpapi;

}

module.exports = SendGrid;
<commit_msg>Pesky things that aren't needed.<commit_after><|endoftext|>


<commit_before>define(['backbone', 'underscore'], function (Backbone, _) {

    return Backbone.Collection.extend({
        /**
         * Paginated Collection
         * make sure you override this empty config with necessary information
         * paginationConfig {
         *      pageSize : '', - results per page
         *      skipPages : '', - number of results to skip
         *      url : '', - endpoint
         *      pageLink : '',- paginated page numbers link, example : '#users/page/'. this automatically concats with its page number in the fetch success method to create -> '#users/page/3'
         *      showLink : '', - attached on the end of pageLink for the limit attribute in the request
         *      pageLimits : { - used in creating a show # dropdown
         *      start : '',
         *      stop : '',
         *      step : ''
         * }
         */

        paginationConfig : {
            pageSize : '',
            skipPages : '',
            url : '',
            pageLink : '',
            showLink : '',
            pageLimits : {
                start : '',
                stop : '',
                step : ''
            }
        },
        fetch : fetch,
        createPages : createPages,
        createPageSizeDropdownOptions : createPageSizeDropdownOptions,
        calculatePrevOrNextButton : calculatePrevOrNextButton,
        initialize : function () {
            this._paginator = {};
        },
        put : function (prop, value) {
            this._paginator[prop] = value;
        },
        grab : function (prop) {
            return this._paginator[prop];
        }

    });

    function fetch (options) {
        var args = Array.prototype.slice.call(arguments, 0);
        var fetchOptions = {};

        fetchOptions.data = {
            limit : this.paginationConfig.pageSize,
            skip : this.paginationConfig.skipPages
        };

        fetchOptions.success = function (collection, response, options) {

            collection.put('totalResults', response.total);
            collection.put('totalPages', Math.ceil(response.total / collection.paginationConfig.pageSize));
            collection.put('currentPage', (options.data.skip / options.data.limit) + 1);
            collection.put('pages', collection.createPages(options));
            collection.put('dropDownOptions', collection.createPageSizeDropdownOptions());
            collection.put('nextPage', collection.calculatePrevOrNextButton('next'));
            collection.put('prevPage', collection.calculatePrevOrNextButton('prev'));
        };

        if (options) {
            _.extend(fetchOptions.data, options.data, {
                skip : (options.data.page - 1) * this.paginationConfig.pageSize,
                limit : options.data.limit
            });
            _.extend(fetchOptions.headers, options.headers);
            _.extend(fetchOptions.success, options.success);
        }
        args[0] = fetchOptions;
        return Backbone.Collection.prototype.fetch.apply(this, args);
    }

    function createPages (options) {
        var pages = _.range(1, this.grab('totalPages') + 1),
            self = this;

        return _.map(pages, function (page) {
            return {
                page : page,
                current : (page == (options.data.skip / options.data.limit) + 1),
                link : self.paginationConfig.pageLink + page + self.paginationConfig.showLink + options.data.limit
            };
        });
    }

    function createPageSizeDropdownOptions () {
        var self = this,
            options = _.range(
                this.paginationConfig.pageLimits.start,
                this.paginationConfig.pageLimits.stop,
                this.paginationConfig.pageLimits.step
            );

        return _.map(options, function (option) {
            return {
                option : option,
                selected : self.paginationConfig.pageSize == option ? true : false
            };
        });
    }

    function calculatePrevOrNextButton (button) {
        var returnObj = {
            disabled : true,
            link : '',
            onClick : 'return false;'
        };

        if ('prev' == button) {
            if (this.grab('currentPage') > 1) {
                returnObj = {
                    disabled : false,
                    link : this.paginationConfig.pageLink + (this.grab('currentPage') - 1) + this.paginationConfig.showLink + this.paginationConfig.pageSize,
                    onClick : ''
                };
            }
        } else {
            if (this.grab('currentPage') < this.grab('totalPages')) {
                returnObj = {
                    disabled : false,
                    link : this.paginationConfig.pageLink + (this.grab('currentPage') + 1) + this.paginationConfig.showLink + this.paginationConfig.pageSize,
                    onClick : ''
                };
            }
        }

        return returnObj;
    }

});
<commit_msg>added headers and data properties to fetchOptions<commit_after>define(['backbone', 'underscore'], function (Backbone, _) {

    return Backbone.Collection.extend({
        /**
         * Paginated Collection
         * make sure you override this empty config with necessary information
         * paginationConfig {
         *      pageSize : '', - results per page
         *      skipPages : '', - number of results to skip
         *      url : '', - endpoint
         *      pageLink : '',- paginated page numbers link, example : '#users/page/'. this automatically concats with its page number in the fetch success method to create -> '#users/page/3'
         *      showLink : '', - attached on the end of pageLink for the limit attribute in the request
         *      pageLimits : { - used in creating a show # dropdown
         *      start : '',
         *      stop : '',
         *      step : ''
         * }
         */

        paginationConfig : {
            pageSize : '',
            skipPages : '',
            url : '',
            pageLink : '',
            showLink : '',
            pageLimits : {
                start : '',
                stop : '',
                step : ''
            }
        },
        fetch : fetch,
        createPages : createPages,
        createPageSizeDropdownOptions : createPageSizeDropdownOptions,
        calculatePrevOrNextButton : calculatePrevOrNextButton,
        initialize : function () {
            this._paginator = {};
        },
        put : function (prop, value) {
            this._paginator[prop] = value;
        },
        grab : function (prop) {
            return this._paginator[prop];
        }

    });

    function fetch (options) {
        var args = Array.prototype.slice.call(arguments, 0);
        var fetchOptions = {
            data: {},
            headers: {}
        };

        fetchOptions.data = {
            limit : this.paginationConfig.pageSize,
            skip : this.paginationConfig.skipPages
        };

        fetchOptions.success = function (collection, response, options) {

            collection.put('totalResults', response.total);
            collection.put('totalPages', Math.ceil(response.total / collection.paginationConfig.pageSize));
            collection.put('currentPage', (options.data.skip / options.data.limit) + 1);
            collection.put('pages', collection.createPages(options));
            collection.put('dropDownOptions', collection.createPageSizeDropdownOptions());
            collection.put('nextPage', collection.calculatePrevOrNextButton('next'));
            collection.put('prevPage', collection.calculatePrevOrNextButton('prev'));
        };

        if (options) {
            _.extend(fetchOptions.data, options.data, {
                skip : (options.data.page - 1) * this.paginationConfig.pageSize,
                limit : options.data.limit
            });
            _.extend(fetchOptions.headers, options.headers);
            _.extend(fetchOptions.success, options.success);
        }
        args[0] = fetchOptions;
        return Backbone.Collection.prototype.fetch.apply(this, args);
    }

    function createPages (options) {
        var pages = _.range(1, this.grab('totalPages') + 1),
            self = this;

        return _.map(pages, function (page) {
            return {
                page : page,
                current : (page == (options.data.skip / options.data.limit) + 1),
                link : self.paginationConfig.pageLink + page + self.paginationConfig.showLink + options.data.limit
            };
        });
    }

    function createPageSizeDropdownOptions () {
        var self = this,
            options = _.range(
                this.paginationConfig.pageLimits.start,
                this.paginationConfig.pageLimits.stop,
                this.paginationConfig.pageLimits.step
            );

        return _.map(options, function (option) {
            return {
                option : option,
                selected : self.paginationConfig.pageSize == option ? true : false
            };
        });
    }

    function calculatePrevOrNextButton (button) {
        var returnObj = {
            disabled : true,
            link : '',
            onClick : 'return false;'
        };

        if ('prev' == button) {
            if (this.grab('currentPage') > 1) {
                returnObj = {
                    disabled : false,
                    link : this.paginationConfig.pageLink + (this.grab('currentPage') - 1) + this.paginationConfig.showLink + this.paginationConfig.pageSize,
                    onClick : ''
                };
            }
        } else {
            if (this.grab('currentPage') < this.grab('totalPages')) {
                returnObj = {
                    disabled : false,
                    link : this.paginationConfig.pageLink + (this.grab('currentPage') + 1) + this.paginationConfig.showLink + this.paginationConfig.pageSize,
                    onClick : ''
                };
            }
        }

        return returnObj;
    }

});
<|endoftext|>


<commit_before>'use strict';

// Variables
let queueCache = [];

// Send back the function
module.exports = function(task) {
  return new Promise((resolve, reject) => {

    // Exit without a task
    if ( ! task || typeof task !== 'function' ) {
      return reject('Missing or invalid task argument');
    }

    // Resolve for now
    return resolve();
  });
};
<commit_msg>Update queue addition<commit_after>'use strict';

// Load requirements
const assign = require('deep-assign');

// Variables
let queueCache = [];

// Send back the function
module.exports = function(task) {
  return new Promise((resolve, reject) => {

    // Variables
    let added = [],
        promises = [],
        options = {};

    // Exit without a task
    if ( ! task || typeof task !== 'object' ) {
      return reject('Missing or invalid task argument');
    }

    // Loop through and assign the available jobs to the queue
    task.jobs.forEach((job) => {

      // Skip if already in queue
      if ( queueCache.includes(job.file) ) {
        return false;
      }

      // Add to cache to stop additional runs
      queueCache.push(job.file);
      this.total = queueCache.length;

      // Track files being added with this task
      added.push(job.basename);

      // Merge options for this task
      job.options = assign(options, job.options);

      // Add to the queue
      promises.push(this.items.add(() => {

        // Update current task position
        this.current++;

        // Update overall counter
        task.overall = {total: this.total, current: this.current};

        // DEBUG
        console.log('[{cyan:Queue}] Starting task %s of %s', this.current, this.total);

        // Send to conversion for processing
        return require('../conversion').run(job);
      }));

    });

    // DEBUG
    console.log('Added:\n  ' + added.join('  \n').trim());

    // Unpause the queue
    this.items.maxPendingPromises = 1;
    this.items._dequeue();

    // Wait for this task to complete to resolve
    Promise.all(promises).then((result) => {
      return resolve(result);
    }).catch((err) => {
      console.log(err);
      return reject(err);
    });
  });
};
<|endoftext|>


<commit_before>!function () {

    function NugetStore(base) {
        this.base = base;
    }

    NugetStore.prototype.get = function get() {
        this.getVersion.apply(this, arguments);
    };

    NugetStore.prototype.set = function set (name, hash, type, version, cb) {
        var newVersion = {
            component: name,
            version: version,
            hash: hash,
            type: type,
            timestamp: Date.now()
        };

        this.base
            .open(this.base.databases.versions)
            .save(newVersion, cb);
    };

    NugetStore.prototype.getVersion = function getVersion (name, cb) {
        this.base
            .open(this.base.databases.versions).view('versions/all', { key: name }, function (err, res) {
                if (err) { cb(err) return; }

                cb(null, res.sort(function (a, b) {
                    return a.value.timestamp < b.value.timestamp;
                })[0]);
            });
    };

    module.exports = NugetStore;
}();
<commit_msg>:syringe:<commit_after>!function () {

    function NugetStore(base) {
        this.base = base;
    }

    NugetStore.prototype.get = function get() {
        this.getVersion.apply(this, arguments);
    };

    NugetStore.prototype.set = function set (name, hash, type, version, cb) {
        var newVersion = {
            component: name,
            version: version,
            hash: hash,
            type: type,
            timestamp: Date.now()
        };

        this.base
            .open(this.base.databases.versions)
            .save(newVersion, cb);
    };

    NugetStore.prototype.getVersion = function getVersion (name, cb) {
        this.base
            .open(this.base.databases.versions).view('versions/all', { key: name }, function (err, res) {
                if (err) { cb(err); return; }

                cb(null, res.sort(function (a, b) {
                    return a.value.timestamp < b.value.timestamp;
                })[0]);
            });
    };

    module.exports = NugetStore;
}();
<|endoftext|>


<commit_before>export default class AgeRenderer {
  constructor(elem, date, accuracy = 9) {
    this.elem = elem;
    this.date = date;
    this.accuracy = accuracy;
  }

  getMs() {
    return (new Date() - this.date);
  }

  getSeconds() {
    return this.getMs() / 1000;
  }

  getMinutes() {
    return this.getSeconds() / 60;
  }

  getHours() {
    return this.getMinutes() / 60;
  }

  getDays() {
    return this.getHours() / 24;
  }

  getYears() {
    return this.getDays() / 365;
  }

  render() {
    this.elem.innerText = this.getYears().toFixed(this.accuracy);
  }

  loop() {
    setInterval(() => this.render(), 30);
  }
}
<commit_msg>Fully document AgeRenderer<commit_after>/** Displays an age in years in an HTML element */
export default class AgeRenderer {
  /**
   * @param {HTMLElement} elem - the element in which the age should be written
   * @param {Date} date - the date from which the age should be measured
   * @param {number} accuracy - the number of decimal places to include
   */
  constructor(elem, date, accuracy = 9) {
    this.elem = elem;
    this.date = date;
    this.accuracy = accuracy;
  }

  /**
   * Milliseconds since the date
   * @return {number} - the number of milliseconds that have passed since the specified date.
   */
  getMs() {
    return (new Date() - this.date);
  }

  /**
   * Seconds since the date
   * @return {number} - the decimal number of seconds that have passed since the specified date.
   */
  getSeconds() {
    return this.getMs() / 1000;
  }

  /**
   * Minutes since the date
   * @return {number} - the decimal number of minutes that have passed since the specified date.
   */
  getMinutes() {
    return this.getSeconds() / 60;
  }

  /**
   * Hours since the date
   * @return {number} - the decimal number of hours that have passed since the specified date.
   */
  getHours() {
    return this.getMinutes() / 60;
  }

  /**
   * Days since the date
   * @return {number} - the decimal number of days that have passed since the specified date.
   */
  getDays() {
    return this.getHours() / 24;
  }

  /**
   * Years since the date
   * @return {number} - the decimal number of years that have passed since the specified date.
   */
  getYears() {
    return this.getDays() / 365;
  }

  /** Write the number of years (to `accuracy` decimal places) in `this.elem`*/
  render() {
    this.elem.innerText = this.getYears().toFixed(this.accuracy);
  }

  /** Start a loop updating the element every 30ms */
  loop() {
    setInterval(() => this.render(), 30);
  }
}
<|endoftext|>


<commit_before>'use strict';

const mongoose = require('mongoose');

/**
 * Schema.
 */
const messageSchema = new mongoose.Schema({
  conversation: {
    type: mongoose.Schema.Types.ObjectId,
    ref: 'Conversation',
  },
  userId: String,
  date: { type: Date, default: Date.now },
  direction: {
    type: String,
    enum: ['inbound', 'outbound-reply', 'outbound-api-send', 'outbound-api-import'],
  },
  campaignId: Number,
  template: String,
  text: String,
  topic: String,
});

module.exports = mongoose.model('messages', messageSchema);
<commit_msg>added createdAt and updatedAt columns to the Message schema<commit_after>'use strict';

const mongoose = require('mongoose');

/**
 * Schema.
 */
const messageSchema = new mongoose.Schema({
  conversation: {
    type: mongoose.Schema.Types.ObjectId,
    ref: 'Conversation',
  },
  userId: String,
  direction: {
    type: String,
    enum: ['inbound', 'outbound-reply', 'outbound-api-send', 'outbound-api-import'],
  },
  campaignId: Number,
  template: String,
  text: String,
  topic: String,
  attachments: Array,
}, { timestamps: true });

module.exports = mongoose.model('messages', messageSchema);
<|endoftext|>


<commit_before>import DS from 'ember-data';

export default DS.Model.extend({
  username: DS.attr('string'),
  apiKey: DS.attr('string'),
});
<commit_msg>Call it "accountName" for consistency.<commit_after>import DS from 'ember-data';

export default DS.Model.extend({
  accountName: DS.attr('string'),
  apiKey: DS.attr('string'),
});
<|endoftext|>


<commit_before>import * as Promise from 'bluebird'
import * as Immutable from 'immutable'

import uuid from 'helpers/uuid'
import randomChar from 'helpers/randomChar'
import countCredits from 'helpers/countCredits'

import Schedule from 'models/schedule'
import Study from 'models/study'

import * as demoStudent from '../../mockups/demo_student.json'

let currentVersionString = '3.0.0alpha8'

let StudentRecord = Immutable.Record({
	id: uuid(),
	name: 'Student ' + randomChar(),
	active: false,
	version: currentVersionString,

	creditsNeeded: 35,

	matriculation: 1894,
	graduation: 1898,

	studies: Immutable.Map(),
	schedules: Immutable.Map(),
	overrides: Immutable.Map(),
	fabrications: Immutable.Map(),
})

class Student extends StudentRecord {
	constructor(encodedStudent={}) {
		let filtered = Immutable.fromJS(encodedStudent)
			.filter((val, key) => ['studies', 'schedules', 'overrides', 'fabrications'].indexOf(key) === -1)

		super(filtered.toJS())
		// console.log(encodedStudent, filtered.toJS())

		if (encodedStudent) {
			return this.withMutations((student) => {
				Immutable.Seq(encodedStudent.studies || [])
					.forEach((study) => {
						student = student.addArea(study)
					})

				Immutable.Seq(encodedStudent.schedules || [])
					.forEach((schedule) => {
						student = student.addSchedule(schedule)
					})

				Immutable.Seq(encodedStudent.overrides || [])
					.forEach((override) => {
						student = student.addOverride(override)
					})

				Immutable.Seq(encodedStudent.fabrications || [])
					.forEach((fabrication) => {
						student = student.addFabrication(fabrication)
					})

				return student
			})
		}
	}

	rename(newName) {
		return this.set('name', newName)
	}

	changeActive(isActive) {
		return this.set('active', isActive)
	}

	changeCreditsNeeded(newCreditsNeeded) {
		return this.set('creditsNeeded', newCreditsNeeded)
	}

	changeMatriculation(newMatriculation) {
		return this.set('matriculation', newMatriculation)
	}

	changeGraduation(newGraduation) {
		return this.set('graduation', newGraduation)
	}

	// schedule methods

	get schedulesByYear() {
		return this.schedules.groupBy(sched => sched.year)
	}

	get activeSchedules() {
		return this.schedules.filter(sched => sched.active).sortBy(sched => sched.semester)
	}

	addSchedule(newSchedule) {
		let sched = new Schedule(newSchedule)
		return this.setIn(['schedules', sched.id], sched)
	}

	destroySchedule(scheduleId) {
		console.log(`removing schedule ${scheduleId}`)

		let deadSched = this.getIn(['schedules', scheduleId])
		let scheduleIsNoMore = this.set('schedules', this.schedules.delete(scheduleId))

		if (deadSched && deadSched.active) {
			let otherSchedKey = this.schedules.findKey((sched) => sched.year === deadSched.year && sched.semester === deadSched.semester)
			if (otherSchedKey) {
				return scheduleIsNoMore.setIn(['schedules', otherSchedKey, 'active'], true)
			}
		}
		return scheduleIsNoMore
	}

	destroyMultipleSchedules(ids) {
		return this.withMutations((student) => {
			Immutable.Seq(ids).forEach((id) => {
				console.log('destroyMultipleSchedules', id)
				student = student.destroySchedule(id)
			})
			return student
		})
	}

	// area-of-study methods

	get areasByType() {
		return this.studies.groupBy((study) => study.type)
	}

	addArea(areaOfStudy) {
		let study = new Study(areaOfStudy)
		return this.setIn(['studies', study.id], study)
	}

	removeArea(id) {
		let removedIndex = this.studies.findIndex((study) => study.id === id)
		return this.set('studies', this.studies.delete(removedIndex))
	}

	removeMultipleAreas(ids) {
		Seq(ids).forEach(this.removeArea, this)
	}

	// misc

	addOverride(override) {
		return this
	}

	addFabrication(fabrication) {
		return this
	}

	// getters

	get courses() {
		let courses = this.activeSchedules.map((schedule) => schedule.courses)
		let scheduleCoursePromises = Promise.all(courses)
		return scheduleCoursePromises.then((courses) => courses.flatten(true))
	}

	get creditCount() {
		return this.courses.then(countCredits)
	}

	// helpers

	encode() {
		return encodeURIComponent(this)
	}

	toString() {
		return JSON.stringify(this.toJS())
	}

	toJSON() {
		return JSON.stringify(this.toJS())
	}

	save() {
		console.log('saving student', this.name, '(' + this.id + ')')
		localStorage.setItem(this.id, this.toJSON())

		if (this.active)
			localStorage.setItem('activeStudentId', this.id)
	}
}

export default Student
<commit_msg>Put a thing back on a newline<commit_after>import * as Promise from 'bluebird'
import * as Immutable from 'immutable'

import uuid from 'helpers/uuid'
import randomChar from 'helpers/randomChar'
import countCredits from 'helpers/countCredits'

import Schedule from 'models/schedule'
import Study from 'models/study'

import * as demoStudent from '../../mockups/demo_student.json'

let currentVersionString = '3.0.0alpha8'

let StudentRecord = Immutable.Record({
	id: uuid(),
	name: 'Student ' + randomChar(),
	active: false,
	version: currentVersionString,

	creditsNeeded: 35,

	matriculation: 1894,
	graduation: 1898,

	studies: Immutable.Map(),
	schedules: Immutable.Map(),
	overrides: Immutable.Map(),
	fabrications: Immutable.Map(),
})

class Student extends StudentRecord {
	constructor(encodedStudent={}) {
		let filtered = Immutable.fromJS(encodedStudent)
			.filter((val, key) => ['studies', 'schedules', 'overrides', 'fabrications'].indexOf(key) === -1)

		super(filtered.toJS())
		// console.log(encodedStudent, filtered.toJS())

		if (encodedStudent) {
			return this.withMutations((student) => {
				Immutable.Seq(encodedStudent.studies || [])
					.forEach((study) => {
						student = student.addArea(study)
					})

				Immutable.Seq(encodedStudent.schedules || [])
					.forEach((schedule) => {
						student = student.addSchedule(schedule)
					})

				Immutable.Seq(encodedStudent.overrides || [])
					.forEach((override) => {
						student = student.addOverride(override)
					})

				Immutable.Seq(encodedStudent.fabrications || [])
					.forEach((fabrication) => {
						student = student.addFabrication(fabrication)
					})

				return student
			})
		}
	}

	rename(newName) {
		return this.set('name', newName)
	}

	changeActive(isActive) {
		return this.set('active', isActive)
	}

	changeCreditsNeeded(newCreditsNeeded) {
		return this.set('creditsNeeded', newCreditsNeeded)
	}

	changeMatriculation(newMatriculation) {
		return this.set('matriculation', newMatriculation)
	}

	changeGraduation(newGraduation) {
		return this.set('graduation', newGraduation)
	}

	// schedule methods

	get schedulesByYear() {
		return this.schedules.groupBy(sched => sched.year)
	}

	get activeSchedules() {
		return this.schedules.filter(sched => sched.active).sortBy(sched => sched.semester)
	}

	addSchedule(newSchedule) {
		let sched = new Schedule(newSchedule)
		return this.setIn(['schedules', sched.id], sched)
	}

	destroySchedule(scheduleId) {
		console.log(`removing schedule ${scheduleId}`)

		let deadSched = this.getIn(['schedules', scheduleId])
		let scheduleIsNoMore = this.set('schedules', this.schedules.delete(scheduleId))

		if (deadSched && deadSched.active) {
			let otherSchedKey = this.schedules.findKey((sched) =>
				sched.year === deadSched.year && sched.semester === deadSched.semester)

			if (otherSchedKey) {
				return scheduleIsNoMore.setIn(['schedules', otherSchedKey, 'active'], true)
			}
		}
		return scheduleIsNoMore
	}

	destroyMultipleSchedules(ids) {
		return this.withMutations((student) => {
			Immutable.Seq(ids).forEach((id) => {
				console.log('destroyMultipleSchedules', id)
				student = student.destroySchedule(id)
			})
			return student
		})
	}

	// area-of-study methods

	get areasByType() {
		return this.studies.groupBy((study) => study.type)
	}

	addArea(areaOfStudy) {
		let study = new Study(areaOfStudy)
		return this.setIn(['studies', study.id], study)
	}

	removeArea(id) {
		let removedIndex = this.studies.findIndex((study) => study.id === id)
		return this.set('studies', this.studies.delete(removedIndex))
	}

	removeMultipleAreas(ids) {
		Seq(ids).forEach(this.removeArea, this)
	}

	// misc

	addOverride(override) {
		return this
	}

	addFabrication(fabrication) {
		return this
	}

	// getters

	get courses() {
		let courses = this.activeSchedules.map((schedule) => schedule.courses)
		let scheduleCoursePromises = Promise.all(courses)
		return scheduleCoursePromises.then((courses) => courses.flatten(true))
	}

	get creditCount() {
		return this.courses.then(countCredits)
	}

	// helpers

	encode() {
		return encodeURIComponent(this)
	}

	toString() {
		return JSON.stringify(this.toJS())
	}

	toJSON() {
		return JSON.stringify(this.toJS())
	}

	save() {
		console.log('saving student', this.name, '(' + this.id + ')')
		localStorage.setItem(this.id, this.toJSON())

		if (this.active)
			localStorage.setItem('activeStudentId', this.id)
	}
}

export default Student
<|endoftext|>


<commit_before>/*!
 * Lectric v0.2.3
 * http://github.com/mckinney/lectric
 *
 * Copyright 2010, McKinney
 * Licensed under the MIT license.
 * http://github.com/mckinney/lectric/blob/master/LICENSE
 *
 * Author: Brett C. Buddin
 */

(function(window) {
  var ua = navigator.userAgent.toLowerCase();
  isWebkit = !!ua.match(/applewebkit/i);
  var supportsTouch = false;
  try {
    document.createEvent("TouchEvent");
    supportsTouch = true;
  } catch (e) {}

  var cssWithoutUnit = function(element, attribute) {
    var measure = element.css(attribute);
    return (measure !== undefined) ? parseInt(measure.replace('px', ''), 10) : 0;
  };

  var Position = function(x, y) {
    if (x && x.hasOwnProperty('x') && x.hasOwnProperty('y')) {
      x = x.x;
      y = x.y;
    }
    this.x = x;
    this.y = y;
  };
  Position.prototype = {
    difference: function(p) {
      return new Position(p.x - this.x, p.y - this.y);
    }
  };

  var Slider = function() {
    if (supportsTouch && isWebkit) {
      return new TouchSlider();
    } else {
      return new BaseSlider();
    }
  };

  var BaseSlider = function() {};

  // Initialize the BaseSlider.
  //
  // text - The String CSS selector of the slider container.
  // opts - The Map of extra parameters.
  //
  // Returns nothing.
  BaseSlider.prototype.init = function(target, opts) {
    this.opts = jQuery.extend({
      next: undefined,
      previous: undefined,
      itemWrapperClassName: 'items',
      itemClassName: 'item',
      limitLeft: false,
      limitRight: false,
      animateDuration: 400,
      hooks: {}
    }, opts);

    this.position = new Position(0, 0);
    this.startPosition = new Position(this.position);
    this.lastPosition = new Position(this.position);

    // Set up the styling of the slider
    var element = $('<div/>', {
      className: this.opts.itemWrapperClassName
    });
    element.css('width', '1000000px');

    var itemSelector = '.' + this.opts.itemClassName;
    var itemWrapperSelector = '.' + this.opts.itemWrapperClassName;

    $(target).css('overflow', 'hidden');
    $(target).find(itemSelector).css('float', 'left').wrapAll(element);
    this.element = $(target).find(itemWrapperSelector);
    this.element.itemSelector = itemSelector;
    this.element.itemWrapperSelector = itemWrapperSelector;

    var self = this;

    var type = supportsTouch ? 'touchstart' : 'click';
    $(this.opts.next).bind(type, function(e) {
      e.preventDefault();
      var page = self.page();
      self.to(page + 1);
    });

    $(this.opts.previous).bind(type, function(e) {
      e.preventDefault();
      var page = self.page();
      self.to(page - 1);
    });

    // Keep clicks from doing what they do if
    // we support touch on this device
    if (supportsTouch) {
      $(this.opts.next).click(function(e) {
        e.preventDefault();
      });

      $(this.opts.previous).click(function(e) {
        e.preventDefault();
      });
    }

    // Bind callbacks passed in at initialization
    $.each(this.opts.hooks, function(name, fn) {
      if ($.isArray(fn)) {
        $.each(fn, function(fn2) {
          self.subscribe(name, fn2);
        });
      } else {
        self.subscribe(name, fn);
      }
    });

    this.element.trigger('init.lectric');
  };

  // Update the current position of the slider.
  //
  // opts - The Map of extra parameters:
  //        animate - Boolean of whether or not to animate between two states.
  //        triggerMove - Boolean of whether or not to trigger the move hook.
  //
  // Returns nothing.
  BaseSlider.prototype.update = function(opts) {
    var options = jQuery.extend({animate: true, triggerMove: true}, opts);

    var self = this;
    var after = function() {
      self.element.trigger('animationEnd.lectric');
      $(this).dequeue();
    };

    if (options.animate) {
      this.element.animate({'margin-left': this.position.x + 'px'}, this.opts.animateDuration).queue(after);
    } else {
      this.element.css({'margin-left': this.position.x + 'px'}).queue(after);
    }

    if (options.triggerMove) { this.element.trigger('move.lectric'); }
  };

  // Subscribe a callback function to a hook.
  //
  // name - The String name of the hook.
  // fn - The Function callback to execute when the hook is triggered.
  //
  // Returns the Function callback that was bound to the hook.
  BaseSlider.prototype.subscribe = function(name, fn) {
    var self = this;
    var callback = function(e) {
      if (e.target == self.target[0]) {
        fn(self, e);
      }
    }
    $(this).bind(name + '.lectric', callback);
    return callback;
  };

  // Unsubscribe a callback function from a hook or unsubscribe all callbacks from a hook.
  //
  // name - The String name of the hook.
  // fn - The Function callback to execute when the hook is triggered.
  //
  // Returns nothing.
  BaseSlider.prototype.unsubscribe = function(name, fn) {
    if (typeof fn !== undefined && $.isFunction(fn)) {
      $(this).unbind(name + '.lectric', fn);
    } else {
      $(this).unbind(name + '.lectric');
    }
  };

  // Retrieve the current page of the slider.
  //
  // Returns the Integer page number of the slider.
  BaseSlider.prototype.page = function() {
    return Math.abs(Math.round(this.position.x / this._itemWidth()));
  };

  // Move to a specific page number.
  //
  // page - The Integer page number to move to.
  //
  // Returns nothing.
  BaseSlider.prototype.to = function(page) {
    var previous = this.position.x;
    this.position.x = this._limitXBounds(this._xForPage(page));
    if (this.position.x !== previous) {
      this.update();
    }
  };

  // Retrieve the current X position.
  //
  // page - The Integer page number.
  //
  // Returns the Integer X position of the slider.
  BaseSlider.prototype._xForPage = function(page) {
    var flip = (this.opts.reverse) ? 1 : -1;
    return flip * page * this._itemWidth();
  };

  // Retrieve the width of a single item (including margin-right and padding).
  //
  // Returns the Integer width of a single item.
  BaseSlider.prototype._itemWidth = function() {
    var first = this.element.find(this.element.itemSelector).eq(0);
    var padding = cssWithoutUnit(first, 'paddingRight') + cssWithoutUnit(first, 'paddingLeft');
    return cssWithoutUnit(first, 'marginRight') + padding + first.width();
  };

  // Retrieve number of items in the slider.
  //
  // Returns the Integer number of items.
  BaseSlider.prototype._itemCount = function() {
    return this.element.find(this.element.itemSelector).size();
  };

  // Constrain the X position to within the slider beginning and end.
  //
  // x - The Integer X position
  //
  // Returns the Integer X position after being constrained.
  BaseSlider.prototype._limitXBounds = function(x) {
    var itemWidth = this._itemWidth();
    var itemCount = this._itemCount();
    var totalWidth = itemWidth * itemCount;

    if (this.opts.reverse) {
      x = (x > totalWidth - itemWidth) ?  totalWidth - itemWidth : x;
      x = (x < 0) ? 0 : x;
    } else {
      x = (x < -totalWidth + itemWidth) ?  -totalWidth + itemWidth : x;
      x = (x > 0) ? 0 : x;
    }

    if ((this.position.x - x > 0 && this.opts.limitRight) ||
        (this.position.x - x < 0 && this.opts.limitRight)) {
      x = this.position.x;
    }

    return x;
  };

  var TouchSlider = function() {};
  TouchSlider.prototype = new BaseSlider();
  TouchSlider.superobject = BaseSlider.prototype;

  // Initialize the TouchSlider.
  //
  // text - The String CSS selector of the slider container.
  // opts - The Map of extra parameters.
  //
  // Returns nothing.
  TouchSlider.prototype.init = function(target, opts) {
    TouchSlider.superobject.init.call(this, target, opts);
    this.opts = $.extend({
      tossFunction: function(x, dx, dt) {
        return x + dx * 100 / dt;
      }
    }, this.opts);
    this.element.parent().addClass('lectric-slider-touch');

    this.gesturing = false;
    $(target)[0].addEventListener('touchstart', this, false);
    $(target)[0].addEventListener('webkitTransitionEnd', this, false);
  };

  // Proxy the events triggered on the element to another function.
  //
  // event - The Event triggered on the element
  //
  // Returns nothing.
  TouchSlider.prototype.handleEvent = function(event) {
    TouchEvents[event.type].call(this, event);
  };

  // Update the current position of the slider.
  //
  // opts - The Map of extra parameters:
  //        animate - Boolean of whether or not to animate between two states.
  //        triggerMove - Boolean of whether or not to trigger the move hook.
  //
  // Returns nothing.
  TouchSlider.prototype.update = function(opts) {
    var options = jQuery.extend({animate: true, triggerMove: true}, opts);
    if (options.animate) { this._decayOn(); }
    this.element.css({'-webkit-transform': 'translate3d(' + this.position.x + 'px, 0, 0)'});

    if (options.triggerMove) { this.element.trigger('move.lectric'); }
  };

  // Turn off CSS3 animation decay.
  //
  // Returns nothing.
  TouchSlider.prototype._decayOff = function() {
    this.element.css({'-webkit-transition-duration': '0s'});
    this.element.css({'-webkit-transition-property': 'none'});
  };

  // Turn on CSS3 animation decay.
  //
  // Returns nothing.
  TouchSlider.prototype._decayOn = function() {
    var duration = this.opts.animateDuration / 1000;
    this.element.css({'-webkit-transition-duration': duration + 's'});
    this.element.css({'-webkit-transition-property': '-webkit-transform'});
  };

  var TouchEvents = {
    click: function(e) {
      if (this.moved) { e.preventDefault(); }
      this.element[0].removeEventListener('click', this, false);
      return false;
    },

    touchstart: function(e) {
      this.currentTarget = e.currentTarget;
      this.startPosition.x = e.touches[0].pageX - this.position.x;
      this.startPosition.y = e.touches[0].pageY - this.position.y;
      this.moved = false;

      window.addEventListener('gesturestart', this, false);
      window.addEventListener('gestureend', this, false);
      window.addEventListener('touchmove', this, false);
      window.addEventListener('touchend', this, false);
      this.element[0].addEventListener('click', this, false);

      this._decayOff();

      this.element.trigger('start.lectric');
    },

    touchmove: function(e) {
      if (this.gesturing) { return false; }

      if (!this.moved) {
        var deltaY = e.touches[0].pageY - this.startPosition.y;
        var deltaX = e.touches[0].pageX - this.startPosition.x;
        if (Math.abs(deltaY) < 15) {
          e.preventDefault();
        }

        this.element.trigger('firstMove.lectric');
      }

      this.moved = true;
      this.lastPosition.x = this.position.x;
      this.lastPosition.y = this.position.y;
      this.lastMoveTime = new Date();

      this.position.x = this._limitXBounds(e.touches[0].pageX - this.startPosition.x);

      this.update({animate: false});
    },

    touchend: function(e) {
      window.removeEventListener('gesturestart', this, false);
      window.removeEventListener('gestureend', this, false);
      window.removeEventListener('touchmove', this, false);
      window.removeEventListener('touchend', this, false);

      if (this.moved) {
        var dx = this.position.x - this.lastPosition.x;
        var dt = (new Date()) - this.lastMoveTime + 1;

        var tossedX = this._limitXBounds(this.opts.tossFunction(this.position.x, dx, dt));
        var width = this._itemWidth();

        // Find the nearest page
        this.position.x = Math.round(this.position.x / width) * width;

        this.update();
        this.element.trigger('end.lectric');
      } else {
        this.element.trigger('endNoMove.lectric');
      }

      this.currentTarget = undefined;
    },

    gesturestart: function(e) {
      this.gesturing = true;
    },

    gestureend: function(e) {
      this.gesturing = false;
    },

    webkitTransitionEnd: function(e) {
      this.element.trigger('animationEnd.lectric');
    }
  };

  var Lectric = {};
  Lectric.Slider = Slider;
  Lectric.BaseSlider = BaseSlider;
  Lectric.TouchSlider = TouchSlider;
  window.Lectric = Lectric;
})(window);
<commit_msg>whitespace<commit_after>/*!
 * Lectric v0.2.3
 * http://github.com/mckinney/lectric
 *
 * Copyright 2010, McKinney
 * Licensed under the MIT license.
 * http://github.com/mckinney/lectric/blob/master/LICENSE
 *
 * Author: Brett C. Buddin
 */

(function(window) {
  var ua = navigator.userAgent.toLowerCase();
  isWebkit = !!ua.match(/applewebkit/i);
  var supportsTouch = false;
  try {
    document.createEvent("TouchEvent");
    supportsTouch = true;
  } catch (e) {}

  var cssWithoutUnit = function(element, attribute) {
    var measure = element.css(attribute);
    return (measure !== undefined) ? parseInt(measure.replace('px', ''), 10) : 0;
  };

  var Position = function(x, y) {
    if (x && x.hasOwnProperty('x') && x.hasOwnProperty('y')) {
      x = x.x;
      y = x.y;
    }
    this.x = x;
    this.y = y;
  };
  Position.prototype = {
    difference: function(p) {
      return new Position(p.x - this.x, p.y - this.y);
    }
  };

  var Slider = function() {
    if (supportsTouch && isWebkit) {
      return new TouchSlider();
    } else {
      return new BaseSlider();
    }
  };

  var BaseSlider = function() {};

  // Initialize the BaseSlider.
  //
  // text - The String CSS selector of the slider container.
  // opts - The Map of extra parameters.
  //
  // Returns nothing.
  BaseSlider.prototype.init = function(target, opts) {
    this.opts = jQuery.extend({
      next: undefined,
      previous: undefined,
      itemWrapperClassName: 'items',
      itemClassName: 'item',
      limitLeft: false,
      limitRight: false,
      animateDuration: 400,
      hooks: {}
    }, opts);

    this.position = new Position(0, 0);
    this.startPosition = new Position(this.position);
    this.lastPosition = new Position(this.position);

    // Set up the styling of the slider
    var element = $('<div/>', {
      className: this.opts.itemWrapperClassName
    });
    element.css('width', '1000000px');

    var itemSelector = '.' + this.opts.itemClassName;
    var itemWrapperSelector = '.' + this.opts.itemWrapperClassName;

    $(target).css('overflow', 'hidden');
    $(target).find(itemSelector).css('float', 'left').wrapAll(element);
    this.element = $(target).find(itemWrapperSelector);
    this.element.itemSelector = itemSelector;
    this.element.itemWrapperSelector = itemWrapperSelector;

    var self = this;

    var type = supportsTouch ? 'touchstart' : 'click';
    $(this.opts.next).bind(type, function(e) {
      e.preventDefault();
      var page = self.page();
      self.to(page + 1);
    });

    $(this.opts.previous).bind(type, function(e) {
      e.preventDefault();
      var page = self.page();
      self.to(page - 1);
    });

    // Keep clicks from doing what they do if
    // we support touch on this device
    if (supportsTouch) {
      $(this.opts.next).click(function(e) {
        e.preventDefault();
      });

      $(this.opts.previous).click(function(e) {
        e.preventDefault();
      });
    }

    // Bind callbacks passed in at initialization
    $.each(this.opts.hooks, function(name, fn) {
      if ($.isArray(fn)) {
        $.each(fn, function(fn2) {
          self.subscribe(name, fn2);
        });
      } else {
        self.subscribe(name, fn);
      }
    });

    this.element.trigger('init.lectric');
  };

  // Update the current position of the slider.
  //
  // opts - The Map of extra parameters:
  //        animate - Boolean of whether or not to animate between two states.
  //        triggerMove - Boolean of whether or not to trigger the move hook.
  //
  // Returns nothing.
  BaseSlider.prototype.update = function(opts) {
    var options = jQuery.extend({animate: true, triggerMove: true}, opts);

    var self = this;
    var after = function() {
      self.element.trigger('animationEnd.lectric');
      $(this).dequeue();
    };

    if (options.animate) {
      this.element.animate({'margin-left': this.position.x + 'px'}, this.opts.animateDuration).queue(after);
    } else {
      this.element.css({'margin-left': this.position.x + 'px'}).queue(after);
    }

    if (options.triggerMove) { this.element.trigger('move.lectric'); }
  };

  // Subscribe a callback function to a hook.
  //
  // name - The String name of the hook.
  // fn - The Function callback to execute when the hook is triggered.
  //
  // Returns the Function callback that was bound to the hook.
  BaseSlider.prototype.subscribe = function(name, fn) {
    var self = this;
    var callback = function(e) {
      if (e.target == self.target[0]) {
        fn(self, e);
      }
    }
    $(this).bind(name + '.lectric', callback);
    return callback;
  };

  // Unsubscribe a callback function from a hook or unsubscribe all callbacks from a hook.
  //
  // name - The String name of the hook.
  // fn - The Function callback to execute when the hook is triggered.
  //
  // Returns nothing.
  BaseSlider.prototype.unsubscribe = function(name, fn) {
    if (typeof fn !== undefined && $.isFunction(fn)) {
      $(this).unbind(name + '.lectric', fn);
    } else {
      $(this).unbind(name + '.lectric');
    }
  };

  // Retrieve the current page of the slider.
  //
  // Returns the Integer page number of the slider.
  BaseSlider.prototype.page = function() {
    return Math.abs(Math.round(this.position.x / this._itemWidth()));
  };

  // Move to a specific page number.
  //
  // page - The Integer page number to move to.
  //
  // Returns nothing.
  BaseSlider.prototype.to = function(page) {
    var previous = this.position.x;
    this.position.x = this._limitXBounds(this._xForPage(page));
    if (this.position.x !== previous) {
      this.update();
    }
  };

  // Retrieve the current X position.
  //
  // page - The Integer page number.
  //
  // Returns the Integer X position of the slider.
  BaseSlider.prototype._xForPage = function(page) {
    var flip = (this.opts.reverse) ? 1 : -1;
    return flip * page * this._itemWidth();
  };

  // Retrieve the width of a single item (including margin-right and padding).
  //
  // Returns the Integer width of a single item.
  BaseSlider.prototype._itemWidth = function() {
    var first = this.element.find(this.element.itemSelector).eq(0);
    var padding = cssWithoutUnit(first, 'paddingRight') + cssWithoutUnit(first, 'paddingLeft');
    return cssWithoutUnit(first, 'marginRight') + padding + first.width();
  };

  // Retrieve number of items in the slider.
  //
  // Returns the Integer number of items.
  BaseSlider.prototype._itemCount = function() {
    return this.element.find(this.element.itemSelector).size();
  };

  // Constrain the X position to within the slider beginning and end.
  //
  // x - The Integer X position
  //
  // Returns the Integer X position after being constrained.
  BaseSlider.prototype._limitXBounds = function(x) {
    var itemWidth = this._itemWidth();
    var itemCount = this._itemCount();
    var totalWidth = itemWidth * itemCount;

    if (this.opts.reverse) {
      x = (x > totalWidth - itemWidth) ?  totalWidth - itemWidth : x;
      x = (x < 0) ? 0 : x;
    } else {
      x = (x < -totalWidth + itemWidth) ?  -totalWidth + itemWidth : x;
      x = (x > 0) ? 0 : x;
    }

    if ((this.position.x - x > 0 && this.opts.limitRight) ||
        (this.position.x - x < 0 && this.opts.limitRight)) {
      x = this.position.x;
    }

    return x;
  };

  var TouchSlider = function() {};
  TouchSlider.prototype = new BaseSlider();
  TouchSlider.superobject = BaseSlider.prototype;

  // Initialize the TouchSlider.
  //
  // text - The String CSS selector of the slider container.
  // opts - The Map of extra parameters.
  //
  // Returns nothing.
  TouchSlider.prototype.init = function(target, opts) {
    TouchSlider.superobject.init.call(this, target, opts);
    this.opts = $.extend({
      tossFunction: function(x, dx, dt) {
        return x + dx * 100 / dt;
      }
    }, this.opts);
    this.element.parent().addClass('lectric-slider-touch');

    this.gesturing = false;
    $(target)[0].addEventListener('touchstart', this, false);
    $(target)[0].addEventListener('webkitTransitionEnd', this, false);
  };

  // Proxy the events triggered on the element to another function.
  //
  // event - The Event triggered on the element
  //
  // Returns nothing.
  TouchSlider.prototype.handleEvent = function(event) {
    TouchEvents[event.type].call(this, event);
  };

  // Update the current position of the slider.
  //
  // opts - The Map of extra parameters:
  //        animate - Boolean of whether or not to animate between two states.
  //        triggerMove - Boolean of whether or not to trigger the move hook.
  //
  // Returns nothing.
  TouchSlider.prototype.update = function(opts) {
    var options = jQuery.extend({animate: true, triggerMove: true}, opts);
    if (options.animate) { this._decayOn(); }
    this.element.css({'-webkit-transform': 'translate3d(' + this.position.x + 'px, 0, 0)'});

    if (options.triggerMove) { this.element.trigger('move.lectric'); }
  };

  // Turn off CSS3 animation decay.
  //
  // Returns nothing.
  TouchSlider.prototype._decayOff = function() {
    this.element.css({'-webkit-transition-duration': '0s'});
    this.element.css({'-webkit-transition-property': 'none'});
  };

  // Turn on CSS3 animation decay.
  //
  // Returns nothing.
  TouchSlider.prototype._decayOn = function() {
    var duration = this.opts.animateDuration / 1000;
    this.element.css({'-webkit-transition-duration': duration + 's'});
    this.element.css({'-webkit-transition-property': '-webkit-transform'});
  };

  var TouchEvents = {
    click: function(e) {
      if (this.moved) { e.preventDefault(); }
      this.element[0].removeEventListener('click', this, false);
      return false;
    },

    touchstart: function(e) {
      this.currentTarget = e.currentTarget;
      this.startPosition.x = e.touches[0].pageX - this.position.x;
      this.startPosition.y = e.touches[0].pageY - this.position.y;
      this.moved = false;

      window.addEventListener('gesturestart', this, false);
      window.addEventListener('gestureend', this, false);
      window.addEventListener('touchmove', this, false);
      window.addEventListener('touchend', this, false);
      this.element[0].addEventListener('click', this, false);

      this._decayOff();

      this.element.trigger('start.lectric');
    },

    touchmove: function(e) {
      if (this.gesturing) { return false; }

      if (!this.moved) {
        var deltaY = e.touches[0].pageY - this.startPosition.y;
        var deltaX = e.touches[0].pageX - this.startPosition.x;
        if (Math.abs(deltaY) < 15) {
          e.preventDefault();
        }

        this.element.trigger('firstMove.lectric');
      }

      this.moved = true;
      this.lastPosition.x = this.position.x;
      this.lastPosition.y = this.position.y;
      this.lastMoveTime = new Date();

      this.position.x = this._limitXBounds(e.touches[0].pageX - this.startPosition.x);

      this.update({animate: false});
    },

    touchend: function(e) {
      window.removeEventListener('gesturestart', this, false);
      window.removeEventListener('gestureend', this, false);
      window.removeEventListener('touchmove', this, false);
      window.removeEventListener('touchend', this, false);

      if (this.moved) {
        var dx = this.position.x - this.lastPosition.x;
        var dt = (new Date()) - this.lastMoveTime + 1;

        var tossedX = this._limitXBounds(this.opts.tossFunction(this.position.x, dx, dt));
        var width = this._itemWidth();

        // Find the nearest page
        this.position.x = Math.round(this.position.x / width) * width;

        this.update();
        this.element.trigger('end.lectric');
      } else {
        this.element.trigger('endNoMove.lectric');
      }

      this.currentTarget = undefined;
    },

    gesturestart: function(e) {
      this.gesturing = true;
    },

    gestureend: function(e) {
      this.gesturing = false;
    },

    webkitTransitionEnd: function(e) {
      this.element.trigger('animationEnd.lectric');
    }
  };

  var Lectric = {};
  Lectric.Slider = Slider;
  Lectric.BaseSlider = BaseSlider;
  Lectric.TouchSlider = TouchSlider;
  window.Lectric = Lectric;
})(window);
<|endoftext|>