<commit_before>var io = require('socket.io').listen(8080);

var gamelobby = io.of('/gamelobby');

var playerInRoomState = new Object();
var onLeaveTimeOut = new Object();

io.set('log level', 1);

var roomList = new Object();
// roomList[1] =  {shape:"BarShape", player:2, occupied: 2, playerList:{"1":1,"2":1}, readyPlayerList:{}, roomId: 1, state:'waiting'};
// roomList[2] =  {shape:"BarShape", player:2, occupied: 2, playerList:{"4":1,"5":1}, readyPlayerList:{}, roomId: 2, state:'waiting'};
// roomList[3] =  {shape:"BarShape", player:2, occupied: 1, playerList:{"6":1}, readyPlayerList:{}, roomId: 3, state:'waiting'};
// roomList[4] =  {shape:"BarShape", player:4, occupied: 2, playerList:{"14":1,"16":1}, readyPlayerList:{}, roomId: 4, state:'waiting'};
// roomList[5] =  {shape:"BarShape", player:4, occupied: 3, playerList:{"12":1,"31":1,"45":1}, readyPlayerList:{}, roomId: 5, state:'waiting'};
// roomList[6] =  {shape:"RoundShape", player:4, occupied: 3, playerList:{"2":1,"9":1,"41":1}, readyPlayerList:{}, roomId: 6, state:'waiting'};
// roomList[7] =  {shape:"RoundShape", player:2, occupied: 2, playerList:{"71":1,"73":1}, readyPlayerList:{}, roomId: 7, state:'waiting'};
// roomList[8] =  {shape:"RoundShape", player:2, occupied: 2, playerList:{"74":1,"75":1}, readyPlayerList:{}, roomId: 8, state:'waiting'};
// roomList[9] =  {shape:"RoundShape", player:2, occupied: 1, playerList:{"76":1}, readyPlayerList:{}, roomId: 9, state:'waiting'};
// roomList[10] =  {shape:"RoundShape", player:4, occupied: 2, playerList:{"714":1,"716":1}, readyPlayerList:{}, roomId: 10, state:'waiting'};
// roomList[11] =  {shape:"RoundShape", player:4, occupied: 3, playerList:{"712":1,"731":1,"745":1}, readyPlayerList:{}, roomId: 11, state:'waiting'};
// roomList[12] =  {shape:"RoundShape", player:4, occupied: 3, playerList:{"102":1,"49":1,"741":1}, readyPlayerList:{}, roomId: 12, state:'waiting'};

gamelobby.on('connection', function (socket) {
  console.log("connected");

  socket.on('playerid register', function (playerid, inroom){
  	console.log("playerid reg: "+playerid+" inroom: "+inroom);
  	socket.playerid = playerid;
  	playerInRoomState[playerid] = inroom;

  	if (socket.playerid in onLeaveTimeOut){
      console.log('this is reached');
  		clearTimeout(onLeaveTimeOut[socket.playerid]);
  		delete onLeaveTimeOut[socket.playerid];
  	}

  	socket.emit('playerid register ok');

  });

  socket.on('update room list', function (requestMode) {
    var relpyList = new Array();
    for (var roomId in roomList){
      if (roomList[roomId].shape == requestMode.shape
        && roomList[roomId].player == requestMode.player)

        relpyList.push(roomList[roomId]);

    }
    socket.emit(requestMode.shape + " " + requestMode.player+'PlayerMode', relpyList);

  });

  socket.on('new room', function (requestMode) {
  	console.log('new room request received from player '+ socket.playerid);
  	if (socket.playerid in playerInRoomState && playerInRoomState[socket.playerid]==true){
  		socket.emit('new room fail');
  	}
	else{
	  	var room = new Object();
	  	var roomId;
	  	while (true){
	  		roomId = Math.round(Math.random() * 10000);
	  		roomId = roomId.toString();
	  		if (roomId in roomList)
	  			continue;
	  		break;
	  	}
	  	room.roomId = roomId;
	  	room.shape = requestMode.shape;
	  	room.player = requestMode.player;
	  	room.occupied = 1;
	  	room.playerList = new Object();
	  	room.readyPlayerList = new Object();
	  	room.playerList[socket.playerid] = 1;
	  	playerInRoomState[socket.playerid] = true;
	  	room.state = 'waiting';
	  	roomList[roomId] = room;
	  	socket.emit("new room success", roomId);
	  	replyAll();
	  }
  });

  socket.on('auto join', function (requestMode){
  	console.log("auto join request by player "+ socket.playerid);
  	if (socket.playerid in playerInRoomState && playerInRoomState[socket.playerid]==true){
  		socket.emit('auto join fail');
  	}
	else{
	  	var found = new Array();
	  	for (var roomId in roomList)
	      if (roomList[roomId].shape == requestMode.shape
	        && roomList[roomId].player == requestMode.player
	        && roomList[roomId].state == 'waiting'
	        && roomList[roomId].occupied < roomList[roomId].player)

	      	found.push(roomId);

	    if (found.length == 0)
			socket.emit('auto join fail');
		else{
			roomId = found[Math.floor((Math.random()*found.length))];
	      	roomList[roomId].occupied++;
	      	roomList[roomId].playerList[socket.playerid] = 1;
	      	playerInRoomState[socket.playerid] = true;
	      	socket.emit('auto join success', roomId);
	      	replyAll();
		}
	}

  });

  socket.on('game ready', function(){

  	for (var roomId in roomList)
  		if ((socket.playerid in roomList[roomId].playerList)
  			&& !(socket.playerid in roomList[roomId].readyPlayerList)){
  			roomList[roomId].readyPlayerList[socket.playerid] = 1;
  			console.log('Player ' + socket.playerid + 'says he is ready.');
        break;
  		}

  })

  // socket.on('cancel ready', function(){
  // 	for (var roomId in roomList)
  // 		if ((socket.playerid in roomList[roomId].playerList)
  // 			&& (socket.playerid in roomList[roomId].readyPlayerList)){
  // 			delete roomList[roomId].readyPlayerList[socket.playerid];
  // 			break;
  // 		}
  // });

  socket.on('disconnect', function () {
  		console.log("disconnecting");
  	  	for (var roomId in roomList){
  			if (socket.playerid in (roomList[roomId].playerList)) {
  				console.log('now player '+ socket.playerid +' is in room '+roomId);

  				onLeaveTimeOut[socket.playerid] =  setTimeout(function(){
  					var rid = roomId;
  					var sid = socket.playerid;
  					return function(){

  						console.log("player "+sid+" is now offline from room "+rid);

		  				delete roomList[rid].playerList[sid];
		  				if (socket.playerid in roomList[rid].readyPlayerList)
		  					delete roomList[rid].readyPlayerList[sid];
			  		}

  				}(), 10000);
  			}
  		}
  });

});

function replyAll(){
	replyList({shape:'BarShape', player:2});
	replyList({shape:'BarShape', player:4});
	replyList({shape:'RoundShape', player:2});
	replyList({shape:'RoundShape', player:4});
}

function replyList(requestMode) {
    var relpyList = new Array();
    for (var roomId in roomList){
      if (roomList[roomId].shape == requestMode.shape
        && roomList[roomId].player == requestMode.player)

        relpyList.push(roomList[roomId]);

    }
    gamelobby.emit(requestMode.shape + " " + requestMode.player+'PlayerMode', relpyList);

}

<commit_msg>modify msg exchange method between game.php and airhockey.php<commit_after>var io = require('socket.io').listen(8080);
io.set('log level', 1);
var gamelobby = io.of('/gamelobby');

var playerInRoomState = new Object();
var roomList = new Object();

// roomList[1] =  {shape:"BarShape", player:2, occupied: 2, playerList:{"1":1,"2":1}, readyPlayerList:{}, roomId: 1, state:'waiting'};
// roomList[12] =  {shape:"RoundShape", player:4, occupied: 3, playerList:{"102":1,"49":1,"741":1}, readyPlayerList:{}, roomId: 12, state:'waiting'};

gamelobby.on('connection', function (socket) {
  console.log("connected");

  socket.on('playerid register', function (playerid, inroom){
  	console.log("playerid reg: "+playerid+" inroom: "+inroom);
  	socket.playerid = playerid;
  	playerInRoomState[playerid] = inroom;
  	if (inroom!=false){
  		var roomId = inroom;
      	roomList[roomId].occupied++;
      	roomList[roomId].playerList[socket.playerid] = 1;
      	playerInRoomState[socket.playerid] = true;
      	replyAll();

  	}
  	socket.emit('playerid register ok');

  });

  socket.on('update room list', function (requestMode) {
    var relpyList = new Array();
    for (var roomId in roomList){
      if (roomList[roomId].shape == requestMode.shape
        && roomList[roomId].player == requestMode.player)

        relpyList.push(roomList[roomId]);

    }
    socket.emit(requestMode.shape + " " + requestMode.player+'PlayerMode', relpyList);

  });

  socket.on('new room', function (requestMode) {
  	console.log('new room request received from player '+ socket.playerid);
  	if (socket.playerid in playerInRoomState && playerInRoomState[socket.playerid]==true){
  		socket.emit('new room fail');
  	}
	else{
	  	var room = new Object();
	  	var roomId;
	  	while (true){
	  		roomId = Math.round(Math.random() * 10000);
	  		roomId = roomId.toString();
	  		if (roomId in roomList)
	  			continue;
	  		break;
	  	}
	  	room.roomId = roomId;
	  	room.shape = requestMode.shape;
	  	room.player = requestMode.player;
	  	room.occupied = 0;
	  	room.playerList = new Object();
	  	room.readyPlayerList = new Object();
	  	// room.playerList[socket.playerid] = 1;
	  	// playerInRoomState[socket.playerid] = true;
	  	room.state = 'waiting';
	  	roomList[roomId] = room;
	  	socket.emit("new room success", roomId);
	  	replyAll();
	  }
  });

  socket.on('auto join', function (requestMode){
  	console.log("auto join request by player "+ socket.playerid);
  	if (socket.playerid in playerInRoomState && playerInRoomState[socket.playerid]==true){
  		socket.emit('auto join fail');
  	}
	else{
	  	var found = new Array();
	  	for (var roomId in roomList)
	      if (roomList[roomId].shape == requestMode.shape
	        && roomList[roomId].player == requestMode.player
	        && roomList[roomId].state == 'waiting'
	        && roomList[roomId].occupied < roomList[roomId].player)

	      	found.push(roomId);

	    if (found.length == 0)
			socket.emit('auto join fail');
		else{
			roomId = found[Math.floor((Math.random()*found.length))];
	      	// roomList[roomId].occupied++;
	      	// roomList[roomId].playerList[socket.playerid] = 1;
	      	// playerInRoomState[socket.playerid] = true;
	      	socket.emit('auto join success', roomId);
	      	replyAll();
		}
	}

  });

  socket.on('game ready', function(){

  	for (var roomId in roomList)
  		if ((socket.playerid in roomList[roomId].playerList)
  			&& !(socket.playerid in roomList[roomId].readyPlayerList)){
  			roomList[roomId].readyPlayerList[socket.playerid] = 1;
  			console.log('Player ' + socket.playerid + ' is ready.');
        break;
  		}

  })

  // socket.on('cancel ready', function(){
  // 	for (var roomId in roomList)
  // 		if ((socket.playerid in roomList[roomId].playerList)
  // 			&& (socket.playerid in roomList[roomId].readyPlayerList)){
  // 			delete roomList[roomId].readyPlayerList[socket.playerid];
  // 			break;
  // 		}
  // });

  socket.on('disconnect', function () {
  		console.log("disconnecting");
  	  	for (var roomId in roomList){
  			if (socket.playerid in (roomList[roomId].playerList)) {
  				console.log('now player '+ socket.playerid +' is in room '+roomId);

					console.log("player "+ sid +" is now offline from room "+rid);

	  				delete roomList[rid].playerList[sid];
	  				if (socket.playerid in roomList[rid].readyPlayerList)
	  					delete roomList[rid].readyPlayerList[sid];

  			}
  		}
  });

});

function replyAll(){
	replyList({shape:'BarShape', player:2});
	replyList({shape:'BarShape', player:4});
	replyList({shape:'RoundShape', player:2});
	replyList({shape:'RoundShape', player:4});
}

function replyList(requestMode) {
    var relpyList = new Array();
    for (var roomId in roomList){
      if (roomList[roomId].shape == requestMode.shape
        && roomList[roomId].player == requestMode.player)

        relpyList.push(roomList[roomId]);

    }
    gamelobby.emit(requestMode.shape + " " + requestMode.player+'PlayerMode', relpyList);

}

<|endoftext|>


<commit_before>const funds = {
  generalFund: 969200000, // TOTAL FUNDS AVAILABLE
  generalFund2016: 911000000,
  lastYearServicesSum: 867226871,
  sumOfServiceSpending: null,
  generalFundsRemaining: null,
}

export default funds;
<commit_msg>Update sum of services from last year #, closes #143<commit_after>const funds = {
  generalFund: 969200000, // TOTAL FUNDS AVAILABLE
  generalFund2016: 911000000,
  lastYearServicesSum: 939221442, // need to doublecheck and update this number in line with the sum we use for departments
  sumOfServiceSpending: null,
  generalFundsRemaining: null,
}

export default funds;
<|endoftext|>


<commit_before>/*
 * SASS: Compile Sass to CSS
 */
module.exports = {
    /*
     * TARGET:  Build Bolts css file
     */
    boltCss: {
        options: {
            outputStyle: 'compressed',
            includePaths: [
                '<%= path.src.bower %>/bootstrap-sass/assets/stylesheets/',
                '<%= path.src.bower %>/font-awesome/scss/'
            ],
            lineNumbers: false,
            unixNewlines: true,
            banner: '<%= banner.boltCss %>',
            precision: 5,
            sourceMap: '<%= sourcemap.css %>',
            sourceMapContents: true
        },
        files: [
            {
                src:  '<%= path.src.sass %>/app-old-ie.scss',
                dest: '<%= path.dest.css %>/bolt-old-ie.css'
            }, {
                src:  '<%= path.src.sass %>/app.scss',
                dest: '<%= path.dest.css %>/bolt.css'
            }, {
                src:  '<%= path.src.sass %>/liveeditor.scss',
                dest: '<%= path.dest.css %>/liveeditor.css'
            }
        ]
    }
};
<commit_msg>Write sass output uncompressed, csswring wil do that later<commit_after>/*
 * SASS: Compile Sass to CSS
 */
module.exports = {
    /*
     * TARGET:  Build Bolts css file
     */
    boltCss: {
        options: {
            includePaths: [
                '<%= path.src.bower %>/bootstrap-sass/assets/stylesheets/',
                '<%= path.src.bower %>/font-awesome/scss/'
            ],
            lineNumbers: false,
            unixNewlines: true,
            banner: '<%= banner.boltCss %>',
            precision: 5,
            sourceMap: '<%= sourcemap.css %>',
            sourceMapContents: true
        },
        files: [
            {
                src:  '<%= path.src.sass %>/app-old-ie.scss',
                dest: '<%= path.dest.css %>/bolt-old-ie.css'
            }, {
                src:  '<%= path.src.sass %>/app.scss',
                dest: '<%= path.dest.css %>/bolt.css'
            }, {
                src:  '<%= path.src.sass %>/liveeditor.scss',
                dest: '<%= path.dest.css %>/liveeditor.css'
            }
        ]
    }
};
<|endoftext|>


<commit_before>var CANVAS_WIDTH = 828;
var CANVAS_HEIGHT = 495;

var BOUNDARY_RECT_TOP_LEFT_X = 237;
var BOUNDARY_RECT_TOP_LEFT_Y = 88;
var BOUNDARY_RECT_BOTTOM_LEFT_X = 700;
var BOUNDARY_RECT_BOTTOM_LEFT_Y = 391;
var BOUNDARY_RECT_REAL_WIDTH = 2095;
var BOUNDARY_RECT_REAL_HEIGHT = 740;
var BOUNDARY_RECT_FILL_SELECTED = 'rgba(0,188,140,0.2)';
var BOUNDARY_RECT_FILL_DISABLED = 'rgba(178,74,24,0.2)';

var POINT_RADIUS = 5;
var POINT_FILL_COLOR = 'red';
var POINT_LABEL_FONT = 'sans-serif';
var POINT_LABEL_FONT_SIZE = 14;
var POINT_LABEL_FONT_WEIGHT = 'bold';

var CAMERA_DEFAULT_HEIGHT = 40;

angular.module('CameraApp', []).config(function ($interpolateProvider) {
  $interpolateProvider.startSymbol('[[').endSymbol(']]');
});

function CameraController ($scope, $http) {
  var images = {
    cmu: {
      image: 'cmu.jpg',
      plan: 'cmu-plan.jpg'
    },
    stanford: {
      image: 'stanford.jpg',
      plan: 'stanford-plan.jpg'
    }
  }
  var type = window.location.hash.substring(1);
  if (!type) {
    type = 'cmu';
  }
  $scope.selectedImage = images[type];

  // Plan view slicing
  planViewCanvas = new fabric.Canvas('map-container', {
    width: CANVAS_WIDTH,
    height: CANVAS_HEIGHT
  });

  $scope.topLeft = {x: BOUNDARY_RECT_TOP_LEFT_X, y: BOUNDARY_RECT_TOP_LEFT_Y};
  $scope.bottomRight = {x: BOUNDARY_RECT_BOTTOM_LEFT_X, y: BOUNDARY_RECT_BOTTOM_LEFT_Y};
  $scope.boundaryWidth = BOUNDARY_RECT_REAL_WIDTH;
  $scope.boundaryHeight = BOUNDARY_RECT_REAL_HEIGHT;
  $scope.boundaryRectEditable = false;

  var boundaryRect = new fabric.Rect({
    lockRotation: true
  });

  function getBoundaryRectProps () {
    return {
      scale: 1,
      scaleX: 1,
      scaleY: 1,
      width: $scope.bottomRight.x - $scope.topLeft.x,
      height: $scope.bottomRight.y - $scope.topLeft.y,
      left: $scope.topLeft.x,
      top: $scope.topLeft.y
    }
  }

  planViewCanvas.on('object:modified', function (object) {
    if (object.target === boundaryRect) {
      updateBoundaryRect(object.target);
    }
  });

  function updateBoundaryRect (rect) {
    $scope.topLeft.x = Math.round(rect.left);
    $scope.topLeft.y = Math.round(rect.top);
    $scope.bottomRight.x = Math.round(rect.left + rect.currentWidth);
    $scope.bottomRight.y = Math.round(rect.top + rect.currentHeight);
    $scope.$apply();
  }

  function toggleBoundaryRectEditing (state) {
    $scope.boundaryRectEditable = typeof state !== 'undefined' ? state : !$scope.boundaryRectEditable;
    boundaryRect.set({
      selectable: $scope.boundaryRectEditable,
      fill: $scope.boundaryRectEditable ? BOUNDARY_RECT_FILL_SELECTED : BOUNDARY_RECT_FILL_DISABLED,
      hasControls: $scope.boundaryRectEditable,
      hasBorders: $scope.boundaryRectEditable
    });
    planViewCanvas.renderAll();
  };

  $scope.renderBoundaryRect = function () {
    boundaryRect.set(getBoundaryRectProps());
    planViewCanvas.renderAll();
  };

  $scope.pathPoints = [];

  planViewCanvas.on('mouse:down', function(options) {
    if ($scope.boundaryRectEditable) {
      // Prevent point from being added when editing boundary rect
      return;
    }

    var point = options.e;

    var circle = new fabric.Circle({
      radius: POINT_RADIUS,
      fill: POINT_FILL_COLOR,
      left: point.offsetX - POINT_RADIUS,
      top: point.offsetY - POINT_RADIUS,
      selectable: false
    });
    circle.z = CAMERA_DEFAULT_HEIGHT; // Set default z-value for video;

    var label = new fabric.Text(($scope.pathPoints.length + 1).toString(), {
      fontWeight: POINT_LABEL_FONT_WEIGHT,
      fontSize: POINT_LABEL_FONT_SIZE,
      fontFamily: POINT_LABEL_FONT,
      left: point.offsetX - POINT_RADIUS/2,
      top: point.offsetY + POINT_RADIUS,
    });
    $scope.pathPoints.push({
      point: circle,
      label: label
    })
    planViewCanvas.add(circle);
    planViewCanvas.add(label);
    $scope.$apply();
  });

  $scope.deletePoint = function (index) {
    var pt = $scope.pathPoints[index];
    planViewCanvas.remove(pt.point);
    planViewCanvas.remove(pt.label);
    $scope.pathPoints.splice(index, 1);
    for (var i = 0; i < $scope.pathPoints.length; i++) {
      $scope.pathPoints[i].label.setText((i+1).toString());
    }
    planViewCanvas.renderAll();
  }

  $scope.normalizePathPoint = function (point) {
    var x = point.left - $scope.topLeft.x;
    var y = point.top - $scope.topLeft.y;
    var boundaryBoxX = x;
    var boundaryBoxY = y;
    return {
      x: Math.round(((-boundaryBoxY/boundaryRect.currentHeight) + 0.5) * $scope.boundaryHeight, 2),
      y: Math.round(-boundaryBoxX/boundaryRect.currentWidth * $scope.boundaryWidth, 2),
      z: point.z
    };
  }

  function normalizePathPoints (pathPoints) {
    return pathPoints.map(function (point) {
      // Map to boundary box coordinates
      return $scope.normalizePathPoint(point);
    });
  }

  $scope.renderingVideo = false;

  $scope.renderVideoWithPath = function () {
    var pathPoints = $scope.pathPoints.map(function (pt) {
      return pt.point;
    });
    var cameraPathPoints = normalizePathPoints(pathPoints);

    $scope.renderingVideo = true;
    $http.post('/generate_video', {
      camera_path: cameraPathPoints,
      file_name: new Date().getTime(),
      world: $scope.world,
      planeRect: {
        x: parseInt($scope.planeTopLeft.x/scale),
        y: parseInt($scope.planeTopLeft.y/scale),
        width: parseInt(($scope.planeBottomRight.x - $scope.planeTopLeft.x)/scale),
        height: parseInt(($scope.planeBottomRight.y - $scope.planeTopLeft.y)/scale)
      },
      vanishingPoint: {
        x: parseInt($scope.vanishingPoint.left/scale),
        y: parseInt($scope.vanishingPoint.top/scale),
      },
      image: $scope.selectedImage.image
    }).success(function (res, status, headers, config) {
      if (res.status === 'success') {
        $scope.renderingVideo = false;
        var video = res.video;
        var $videoPlayer = $('.video-player');
        $videoPlayer.width(video.width);
        $videoPlayer.height(video.height);
        $videoPlayer.attr('src', video.src);
        $('#video-modal').modal();
      }
    }).error(function (res, status, headers, config) {
      alert('Rendering failed');
      $scope.renderingVideo = false;
    });
  }

  $scope.getRenderVideoButtonState = function () {
    var pathObject = planViewCanvas.getActiveObject();
    return pathObject && pathObject !== boundaryRect && pathObject.path;
  };

  toggleBoundaryRectEditing($scope.boundaryRectEditable);
  boundaryRect.set(getBoundaryRectProps());

  $scope.toggleBoundaryRectEditing = toggleBoundaryRectEditing;

  fabric.Image.fromURL('/static/img/' + $scope.selectedImage.plan, function (img) {
    img.set('selectable', false);
    planViewCanvas.add(img);
    planViewCanvas.add(boundaryRect);
  });

  // Plane slicing section
  imageCanvas = null;

  $scope.planeTopLeft = {x: 198, y: 225};
  $scope.planeBottomRight = {x: 198+378, y: 225+226};

  var planeBoundaryRect = new fabric.Rect({
    lockRotation: true,
    top: 225,
    left: 198,
    width: 378,
    height: 226,
    fill: 'rgba(178,74,24,0.5)'
  });

  var img = new Image();
  var scale;
  img.src = '/static/img/' + $scope.selectedImage.image;
  img.onload = function () {
    var imgWidth = this.width;
    var imgHeight = this.height;
    fabric.Image.fromURL('/static/img/' + $scope.selectedImage.image, function (img) {
      img.set('selectable', false);
      img.set('width', CANVAS_WIDTH);
      scale = CANVAS_WIDTH/imgWidth;
      var canvasHeight = scale * imgHeight;
      img.set('height', canvasHeight);

      imageCanvas = new fabric.Canvas('image-container', {
        width: CANVAS_WIDTH,
        height: canvasHeight
      });
      imageCanvas.add(img);
      imageCanvas.add(planeBoundaryRect);

      $scope.vanishingPoint = new fabric.Circle({
        radius: 5,
        fill: POINT_FILL_COLOR,
        left: 335,
        top: 415.5,
        lockScalingX: true,
        lockScalingY: true
      });

      $scope.vanishingPoint.setControlsVisibility({
        bl: false,
        br: false,
        mb: false,
        ml: false,
        mr: false,
        mt: false,
        tl: false,
        tr: false,
        mtr: false
      })
      imageCanvas.add($scope.vanishingPoint);

      imageCanvas.on('object:modified', function (object) {
        if (object.target === planeBoundaryRect) {
          updatePlaneBoundaryRect(object.target);
        }
        $scope.$apply();
      });
      $scope.renderPlaneCanvas();
      $scope.$apply();
    });
  };

  function updatePlaneBoundaryRect (rect) {
    $scope.planeTopLeft.x = Math.round(rect.left);
    $scope.planeTopLeft.y = Math.round(rect.top);
    $scope.planeBottomRight.x = Math.round(rect.left + rect.currentWidth);
    $scope.planeBottomRight.y = Math.round(rect.top + rect.currentHeight);
  }

  function getPlaneBoundaryRectProps () {
    return {
      scale: 1,
      scaleX: 1,
      scaleY: 1,
      width: $scope.planeBottomRight.x - $scope.planeTopLeft.x,
      height: $scope.planeBottomRight.y - $scope.planeTopLeft.y,
      left: $scope.planeTopLeft.x,
      top: $scope.planeTopLeft.y
    };
  }

  $scope.renderPlaneCanvas = function () {
    planeBoundaryRect.set(getPlaneBoundaryRectProps());
    imageCanvas.renderAll();
  };

  $scope.world = {
    width: 741,
    height: 304,
    depth: 2095
  };
}
<commit_msg>Edit CMU's boundary rect<commit_after>var CANVAS_WIDTH = 828;
var CANVAS_HEIGHT = 495;

var BOUNDARY_RECT_TOP_LEFT_X = 237;
var BOUNDARY_RECT_TOP_LEFT_Y = 138;
var BOUNDARY_RECT_BOTTOM_LEFT_X = 700;
var BOUNDARY_RECT_BOTTOM_LEFT_Y = 347;
var BOUNDARY_RECT_REAL_WIDTH = 2095;
var BOUNDARY_RECT_REAL_HEIGHT = 740;
var BOUNDARY_RECT_FILL_SELECTED = 'rgba(0,188,140,0.2)';
var BOUNDARY_RECT_FILL_DISABLED = 'rgba(178,74,24,0.2)';

var POINT_RADIUS = 5;
var POINT_FILL_COLOR = 'red';
var POINT_LABEL_FONT = 'sans-serif';
var POINT_LABEL_FONT_SIZE = 14;
var POINT_LABEL_FONT_WEIGHT = 'bold';

var CAMERA_DEFAULT_HEIGHT = 40;

angular.module('CameraApp', []).config(function ($interpolateProvider) {
  $interpolateProvider.startSymbol('[[').endSymbol(']]');
});

function CameraController ($scope, $http) {
  var images = {
    cmu: {
      image: 'cmu.jpg',
      plan: 'cmu-plan.jpg'
    },
    stanford: {
      image: 'stanford.jpg',
      plan: 'stanford-plan.jpg'
    }
  }
  var type = window.location.hash.substring(1);
  if (!type) {
    type = 'cmu';
  }
  $scope.selectedImage = images[type];

  // Plan view slicing
  planViewCanvas = new fabric.Canvas('map-container', {
    width: CANVAS_WIDTH,
    height: CANVAS_HEIGHT
  });

  $scope.topLeft = {x: BOUNDARY_RECT_TOP_LEFT_X, y: BOUNDARY_RECT_TOP_LEFT_Y};
  $scope.bottomRight = {x: BOUNDARY_RECT_BOTTOM_LEFT_X, y: BOUNDARY_RECT_BOTTOM_LEFT_Y};
  $scope.boundaryWidth = BOUNDARY_RECT_REAL_WIDTH;
  $scope.boundaryHeight = BOUNDARY_RECT_REAL_HEIGHT;
  $scope.boundaryRectEditable = false;

  var boundaryRect = new fabric.Rect({
    lockRotation: true
  });

  function getBoundaryRectProps () {
    return {
      scale: 1,
      scaleX: 1,
      scaleY: 1,
      width: $scope.bottomRight.x - $scope.topLeft.x,
      height: $scope.bottomRight.y - $scope.topLeft.y,
      left: $scope.topLeft.x,
      top: $scope.topLeft.y
    }
  }

  planViewCanvas.on('object:modified', function (object) {
    if (object.target === boundaryRect) {
      updateBoundaryRect(object.target);
    }
  });

  function updateBoundaryRect (rect) {
    $scope.topLeft.x = Math.round(rect.left);
    $scope.topLeft.y = Math.round(rect.top);
    $scope.bottomRight.x = Math.round(rect.left + rect.currentWidth);
    $scope.bottomRight.y = Math.round(rect.top + rect.currentHeight);
    $scope.$apply();
  }

  function toggleBoundaryRectEditing (state) {
    $scope.boundaryRectEditable = typeof state !== 'undefined' ? state : !$scope.boundaryRectEditable;
    boundaryRect.set({
      selectable: $scope.boundaryRectEditable,
      fill: $scope.boundaryRectEditable ? BOUNDARY_RECT_FILL_SELECTED : BOUNDARY_RECT_FILL_DISABLED,
      hasControls: $scope.boundaryRectEditable,
      hasBorders: $scope.boundaryRectEditable
    });
    planViewCanvas.renderAll();
  };

  $scope.renderBoundaryRect = function () {
    boundaryRect.set(getBoundaryRectProps());
    planViewCanvas.renderAll();
  };

  $scope.pathPoints = [];

  planViewCanvas.on('mouse:down', function(options) {
    if ($scope.boundaryRectEditable) {
      // Prevent point from being added when editing boundary rect
      return;
    }

    var point = options.e;

    var circle = new fabric.Circle({
      radius: POINT_RADIUS,
      fill: POINT_FILL_COLOR,
      left: point.offsetX - POINT_RADIUS,
      top: point.offsetY - POINT_RADIUS,
      selectable: false
    });
    circle.z = CAMERA_DEFAULT_HEIGHT; // Set default z-value for video;

    var label = new fabric.Text(($scope.pathPoints.length + 1).toString(), {
      fontWeight: POINT_LABEL_FONT_WEIGHT,
      fontSize: POINT_LABEL_FONT_SIZE,
      fontFamily: POINT_LABEL_FONT,
      left: point.offsetX - POINT_RADIUS/2,
      top: point.offsetY + POINT_RADIUS,
    });
    $scope.pathPoints.push({
      point: circle,
      label: label
    })
    planViewCanvas.add(circle);
    planViewCanvas.add(label);
    $scope.$apply();
  });

  $scope.deletePoint = function (index) {
    var pt = $scope.pathPoints[index];
    planViewCanvas.remove(pt.point);
    planViewCanvas.remove(pt.label);
    $scope.pathPoints.splice(index, 1);
    for (var i = 0; i < $scope.pathPoints.length; i++) {
      $scope.pathPoints[i].label.setText((i+1).toString());
    }
    planViewCanvas.renderAll();
  }

  $scope.normalizePathPoint = function (point) {
    var x = point.left - $scope.topLeft.x;
    var y = point.top - $scope.topLeft.y;
    var boundaryBoxX = x;
    var boundaryBoxY = y;
    return {
      x: Math.round(((-boundaryBoxY/boundaryRect.currentHeight) + 0.5) * $scope.boundaryHeight, 2),
      y: Math.round(-boundaryBoxX/boundaryRect.currentWidth * $scope.boundaryWidth, 2),
      z: point.z
    };
  }

  function normalizePathPoints (pathPoints) {
    return pathPoints.map(function (point) {
      // Map to boundary box coordinates
      return $scope.normalizePathPoint(point);
    });
  }

  $scope.renderingVideo = false;

  $scope.renderVideoWithPath = function () {
    var pathPoints = $scope.pathPoints.map(function (pt) {
      return pt.point;
    });
    var cameraPathPoints = normalizePathPoints(pathPoints);

    $scope.renderingVideo = true;
    $http.post('/generate_video', {
      camera_path: cameraPathPoints,
      file_name: new Date().getTime(),
      world: $scope.world,
      planeRect: {
        x: parseInt($scope.planeTopLeft.x/scale),
        y: parseInt($scope.planeTopLeft.y/scale),
        width: parseInt(($scope.planeBottomRight.x - $scope.planeTopLeft.x)/scale),
        height: parseInt(($scope.planeBottomRight.y - $scope.planeTopLeft.y)/scale)
      },
      vanishingPoint: {
        x: parseInt($scope.vanishingPoint.left/scale),
        y: parseInt($scope.vanishingPoint.top/scale),
      },
      image: $scope.selectedImage.image
    }).success(function (res, status, headers, config) {
      if (res.status === 'success') {
        $scope.renderingVideo = false;
        var video = res.video;
        var $videoPlayer = $('.video-player');
        $videoPlayer.width(video.width);
        $videoPlayer.height(video.height);
        $videoPlayer.attr('src', video.src);
        $('#video-modal').modal();
      }
    }).error(function (res, status, headers, config) {
      alert('Rendering failed');
      $scope.renderingVideo = false;
    });
  }

  $scope.getRenderVideoButtonState = function () {
    var pathObject = planViewCanvas.getActiveObject();
    return pathObject && pathObject !== boundaryRect && pathObject.path;
  };

  toggleBoundaryRectEditing($scope.boundaryRectEditable);
  boundaryRect.set(getBoundaryRectProps());

  $scope.toggleBoundaryRectEditing = toggleBoundaryRectEditing;

  fabric.Image.fromURL('/static/img/' + $scope.selectedImage.plan, function (img) {
    img.set('selectable', false);
    planViewCanvas.add(img);
    planViewCanvas.add(boundaryRect);
  });

  // Plane slicing section
  imageCanvas = null;

  $scope.planeTopLeft = {x: 198, y: 225};
  $scope.planeBottomRight = {x: 198+378, y: 225+226};

  var planeBoundaryRect = new fabric.Rect({
    lockRotation: true,
    top: 225,
    left: 198,
    width: 378,
    height: 226,
    fill: 'rgba(178,74,24,0.5)'
  });

  var img = new Image();
  var scale;
  img.src = '/static/img/' + $scope.selectedImage.image;
  img.onload = function () {
    var imgWidth = this.width;
    var imgHeight = this.height;
    fabric.Image.fromURL('/static/img/' + $scope.selectedImage.image, function (img) {
      img.set('selectable', false);
      img.set('width', CANVAS_WIDTH);
      scale = CANVAS_WIDTH/imgWidth;
      var canvasHeight = scale * imgHeight;
      img.set('height', canvasHeight);

      imageCanvas = new fabric.Canvas('image-container', {
        width: CANVAS_WIDTH,
        height: canvasHeight
      });
      imageCanvas.add(img);
      imageCanvas.add(planeBoundaryRect);

      $scope.vanishingPoint = new fabric.Circle({
        radius: 5,
        fill: POINT_FILL_COLOR,
        left: 335,
        top: 415.5,
        lockScalingX: true,
        lockScalingY: true
      });

      $scope.vanishingPoint.setControlsVisibility({
        bl: false,
        br: false,
        mb: false,
        ml: false,
        mr: false,
        mt: false,
        tl: false,
        tr: false,
        mtr: false
      })
      imageCanvas.add($scope.vanishingPoint);

      imageCanvas.on('object:modified', function (object) {
        if (object.target === planeBoundaryRect) {
          updatePlaneBoundaryRect(object.target);
        }
        $scope.$apply();
      });
      $scope.renderPlaneCanvas();
      $scope.$apply();
    });
  };

  function updatePlaneBoundaryRect (rect) {
    $scope.planeTopLeft.x = Math.round(rect.left);
    $scope.planeTopLeft.y = Math.round(rect.top);
    $scope.planeBottomRight.x = Math.round(rect.left + rect.currentWidth);
    $scope.planeBottomRight.y = Math.round(rect.top + rect.currentHeight);
  }

  function getPlaneBoundaryRectProps () {
    return {
      scale: 1,
      scaleX: 1,
      scaleY: 1,
      width: $scope.planeBottomRight.x - $scope.planeTopLeft.x,
      height: $scope.planeBottomRight.y - $scope.planeTopLeft.y,
      left: $scope.planeTopLeft.x,
      top: $scope.planeTopLeft.y
    };
  }

  $scope.renderPlaneCanvas = function () {
    planeBoundaryRect.set(getPlaneBoundaryRectProps());
    imageCanvas.renderAll();
  };

  $scope.world = {
    width: 741,
    height: 304,
    depth: 2095
  };
}
<|endoftext|>


<commit_before>function leave_room(){
    socket.emit('left', {}, function() {
        socket.disconnect();
        // go back to the login page
        window.location.href = "/";
    });
}

function send_msg(msg){
    msg = msg.trim();
    if(msg != ''){
        $('#text').val('');
        msg = Aes.Ctr.encrypt(msg, Cookies.get('password'), 256)
        socket.emit('text', {'msg': msg});
    }
}

function filter_msg(msg){
    msg = msg.trim();
    msg = filter_code(msg);
    msg = filter_href(msg);
    return msg;
}

function filter_code(msg){
    if(msg.substring(0,5)=='/code'){
        msg = '
' + msg.substring(5) + '
';
    }
    return msg;
}

function filter_href(msg){
    geturl = new RegExp(
        "(^|[ \t\r\n])((ftp|http|https|gopher|mailto|news|nntp|telnet|wais|file|prospero|aim|webcal):(([A-Za-z0-9$_.+!*(),;/?:@&~=-])|%[A-Fa-f0-9]{2}){2,}(#([a-zA-Z0-9][a-zA-Z0-9$_.+!*(),;/?:@&~=%-]*))?([A-Za-z0-9$_+!*();/?:~-]))",
        "g");
    if(msg.match(geturl) && msg.match(geturl).length){
        msg.match(geturl).forEach(function(_url){
            msg = msg.replace(_url, ''+_url+'')
            ext = _url.slice(-4)
            if(ext=='jpeg' || ext=='.jpg' || ext=='.gif' || ext=='.png'){
                msg = msg + '
';
            }
        });
    }
    return msg;
}

function spawnNotification(theBody,theIcon,theTitle) {
    if( ! window.onfocus ){
        var options = {
          body: theBody,
          icon: theIcon
        }
        var n = new Notification(theTitle,options);
        setTimeout(n.close.bind(n), 5000);
    }
}

function store_message(data){
    data_string = (JSON.stringify(data));
    room_key = 'room_' + data.room_key;
    chat_room_data = JSON.parse(localStorage.getItem(room_key));
    if(chat_room_data==null){
        chat_room_data = [];
    }
    chat_room_data.push(data_string);
    localStorage.setItem(room_key, JSON.stringify(chat_room_data));
}

function build_local_data(room_name){
    room_key = 'room_' + room_name;
    chat_room_data = JSON.parse(localStorage.getItem(room_key));
    if(chat_room_data == null){
        empty_array = [];
        localStorage.setItem(room_key, JSON.stringify(empty_array));
        return;
    }
    for(chat of chat_room_data){
        c = JSON.parse(chat);
        write_msg(c);
    }
}

function write_msg(msg_obj){
    unencrypted_msg = Aes.Ctr.decrypt(msg_obj.msg, Cookies.get('password'), 256);
    filtered_msg = filter_msg( unencrypted_msg );
    $(msg_obj.tpl).insertBefore('#chat li:last');
    new_msg_li = $('#chat li:nth-last-child(2)');
    new_msg_li.find('.msg_content').html(filtered_msg);
    new_msg_user = new_msg_li.attr('data-user');

    // check if the last message was the same person and recent
    previous_message_li = $('#chat li:nth-last-child(3)');
    previous_message_type = previous_message_li.attr('data-type');
    append_to_last = false;
    if(
         previous_message_li.attr('data-user') == new_msg_user
        &&
        previous_message_type == 'msg')
        {
        new_msg_li.find('.user_image_container').find('img').hide();
        previous_message_time = new Date(previous_message_li.attr('data-date'));
        diff = Math.round(Math.abs((new Date() - previous_message_time) / 1000));
        if(diff < 120){
            append_to_last = true;
        }
    }

    $('#chat').scrollTop($('#chat')[0].scrollHeight);
    if( previous_message_type == 'msg'){
    if(append_to_last == true){
            new_msg_li.find('h3').hide();
            new_msg_li.find('.msg_date').hide();
            new_msg_li.addClass('no_break_above');
            previous_message_li.addClass('no_break_below');
        }
    }
    msg_pretty_time = pretty_time_now(msg_obj.sent)
    new_msg_li.find('.msg_date').text(msg_pretty_time);
    if(Cookies.get('user_name')==new_msg_user){
        new_msg_li.addClass('msg_me');
    }
}

function pretty_time_now(msg_time){
    var now = new Date();
    diff = Math.round(Math.abs( now - msg_time) / 1000);

    msg_pretty_time = false;
    if(diff < 20){
        msg_pretty_time = 'seconds ago';
    }else if(diff < 60){
        msg_pretty_time = 'less then a minute ago'
    } else if(diff < 3600){
        minutes = Math.round(diff / 60);
        if(minutes == 1){
            msg_pretty_time = '1 minute ago';
        } else {
            msg_pretty_time = minutes + ' mintues ago';
        }
    } else {
        msg_pretty_time = 'just now';
    }
    return msg_pretty_time;
}

function settings_update(){
    $('.setting-update').click(function(){
        setting_name = $(this).attr('name');
        if(setting_name=='clear_local'){
            localStorage.clear();
        }
    });
}

function lock_console(){
    $('#settings_btn').fadeOut();
    $('#chat_window').fadeOut();
    $('#lock_status').removeClass('fa-unlock-alt').addClass('fa-lock');
    $('#repassword_container').focus();
    $('#repassword_container').fadeIn(1500);
    Cookies.set('password', '');
    Cookies.set('terminal', 'locked');
}

function unlock_console(password){
    console.log('lets open this bitch');
    Cookies.set('password', password);
    build_local_data(Cookies.get('room_name'));
    $('#repassword_container').fadeOut(1500);
    $('#settings_btn').fadeIn();
    $('#chat_window').fadeIn();
    Cookies.set('terminal', 'open');
}

var socket;
var CHATSEC = CHATSEC || (function(){

    return {
        init : function(Args) {
            _args = Args;
            build_local_data(Cookies.get('room_name'));
            $('#room_name').html(':: ' + Cookies.set('room_name'));
            if(Cookies.get('password')==''){
                window.location = '/';
            }
            Notification.requestPermission().then(function(result) {
                console.log(result);
            });

        },
        launch : function(){
            $('.typing').hide();
            $("#textbox").focus();

            // lockout
            var timeoutTime = 300000;
            var timeoutTimer = setTimeout(lock_console, timeoutTime);
            $('body').bind('mousedown mousemove keydown', function(event) {
                timeoutTimer = setTimeout(lock_console, timeoutTime);
            });
            $('.cs_login').keypress(function(e) {
                var code = e.keyCode || e.which;
                if (code == 13) {
                    unlock_console($(this).val());
                    $(this).val('');
                }
            });

            // Sockets
            socket = io.connect(window.location.protocol + '//' + document.domain + ':' + location.port + '/chat');

            socket.on('connect', function() {
                socket.emit('joined', {});
            });

            socket.on('status', function(data) {
                $(data.tpl).insertBefore('#chat li:last');
                $('#chat').scrollTop($('#chat')[0].scrollHeight);
            });

            // Reciving user currently typing
            socket.on('typing', function(data) {
                if(Cookies.get('user_name') != data.user_name ){
                    $('.typing').find('.typing_avatar').attr(
                        'src',
                        '/static/imgs/avatars/black/' + data.avatar
                    );
                    $('.typing').find('h3').text(data.user_name);
                    $('.typing').show().delay(750).fadeOut();
                    $('#chat').scrollTop($('#chat')[0].scrollHeight);
                }
            });

            // Recieving a message
            socket.on('message', function(data) {
                write_msg(data);

                if(Cookies.get('user_name') != data.user_name ){
                    var audio = new Audio('/static/audio/new_msg.mp3');
                    audio.play();
                    spawnNotification(
                        filtered_msg,
                        'http://www.google.com/',
                        'ChatSec - ' + data.user_name );
                }
                store_message(data);
            });

            // Sending a message
            $('#textbox').keypress(function(e) {
                var code = e.keyCode || e.which;
                if (code == 13) {
                    message = $('#textbox').val();
                    send_msg(message);
                    $('#textbox').val('');
                } else {
                    socket.emit('typing', {'msg': 'chatsec-user-typing'});
                }
            });

            $('#send').click(function(e){
                send_msg($('#textbox').val());
            });

            // @todo: make t his actually work or kill it
            $(window).on('beforeunload', function(){
                socket.emit('left', {}, function() {
                    socket.disconnect();
                });
            });

            // Timer Scripts
            window.setInterval(function(){
                // Update msg time
                $("#chat li").each(function( index ) {
                    var sent_time = new Date( $(this).attr('data-date') );
                    msg_pretty_time = pretty_time_now(sent_time)
                    if(msg_pretty_time){
                        $(this).find('.msg_date').text(msg_pretty_time);
                    }
                });
                // Highlight code blocks
                $('pre').each(function(i, block) {
                    // hljs.highlightBlock(block);
                });
            }, 10000);
        }
    };
}());<commit_msg>Syncing current main.js file to squelch some merge difficulties<commit_after>function leave_room(){
    socket.emit('left', {}, function() {
        socket.disconnect();
        // go back to the login page
        window.location.href = "/";
    });
}

function send_msg(msg){
    msg = msg.trim();
    if(msg != ''){
        $('#text').val('');
        msg = Aes.Ctr.encrypt(msg, Cookies.get('password'), 256)
        socket.emit('text', {'msg': msg});
    }
}

function filter_msg(msg){
    msg = msg.trim();
    msg = filter_code(msg);
    msg = filter_href(msg);
    return msg;
}

function filter_code(msg){
    if(msg.substring(0,5)=='/code'){
        msg = '
' + msg.substring(5) + '
';
    }
    return msg;
}

function filter_href(msg){
    geturl = new RegExp(
        "(^|[ \t\r\n])((ftp|http|https|gopher|mailto|news|nntp|telnet|wais|file|prospero|aim|webcal):(([A-Za-z0-9$_.+!*(),;/?:@&~=-])|%[A-Fa-f0-9]{2}){2,}(#([a-zA-Z0-9][a-zA-Z0-9$_.+!*(),;/?:@&~=%-]*))?([A-Za-z0-9$_+!*();/?:~-]))",
        "g");
    if(msg.match(geturl) && msg.match(geturl).length){
        msg.match(geturl).forEach(function(_url){
            msg = msg.replace(_url, ''+_url+'')
            ext = _url.slice(-4)
            if(ext=='jpeg' || ext=='.jpg' || ext=='.gif' || ext=='.png'){
                msg = msg + '
';
            }
        });
    }
    return msg;
}

function spawn_notification(msg_obj) {
    if(window.Notification && Notification.permission !== "denied") {
        Notification.requestPermission(function(status) {  // status is "granted", if accepted by user
            if(Cookies.get('terminal')=='unlocked'){
                title = 'ChatSec - ' + msg_obj.user_name;
                msg = Aes.Ctr.decrypt(msg_obj.msg, Cookies.get('password'), 256);
            } else {
                title ='Chatsec';
                msg = 'New message recieved.';
            }
            var n = new Notification('Title', {
                body: msg,
                icon: 'static/imgs/avatars/black/' + msg_obj.avatar
            });
            setTimeout(n.close.bind(n), 5000);
        });
    }
}

function store_message(data){
    data_string = (JSON.stringify(data));
    storage_key = 'room_' + data.room_key;
    chat_room_data = JSON.parse(localStorage.getItem(storage_key));
    if(chat_room_data==null){
        chat_room_data = [];
    }
    chat_room_data.push(data_string);
    localStorage.setItem(storage_key, JSON.stringify(chat_room_data));
}

function build_local_data(room_key){
    storage_key = 'room_' + room_key;
    chat_room_data = JSON.parse(localStorage.getItem(storage_key));
    if(chat_room_data == null){
        empty_array = [];
        localStorage.setItem(storage_key, JSON.stringify(empty_array));
        return;
    }
    for(chat of chat_room_data){
        c = JSON.parse(chat);
        draw_msg(c);
    }
}

function draw_msg(msg_obj){
    unencrypted_msg = Aes.Ctr.decrypt(msg_obj.msg, Cookies.get('password'), 256);
    filtered_msg = filter_msg( unencrypted_msg );
    $(msg_obj.tpl).insertBefore('#chat li:last');
    new_msg_li = $('#chat li:nth-last-child(2)');
    new_msg_li.find('.msg_content').html(filtered_msg);
    new_msg_user = new_msg_li.attr('data-user');

    msg_pretty_time = pretty_time_now(msg_obj.sent)
    new_msg_li.find('.msg_date').text(msg_pretty_time);
    if(Cookies.get('user_name')==new_msg_user){
        new_msg_li.addClass('msg_me');
    }
    $('#chat').scrollTop($('#chat')[0].scrollHeight);
    if($('#chat li').length <= 1){
        return
    }

    // check if the last message was the same person and recent
    previous_message_li = $('#chat li:nth-last-child(3)');
    previous_message_type = previous_message_li.attr('data-type');
    append_to_last = false;
    if(
         previous_message_li.attr('data-user') == new_msg_user
        &&
        previous_message_type == 'msg')
        {
        new_msg_li.find('.user_image_container').find('img').hide();
        previous_message_time = new Date(previous_message_li.attr('data-date'));
        diff = Math.round(Math.abs((new Date() - previous_message_time) / 1000));
        if(diff < 120){
            append_to_last = true;
        }
    }

    if( previous_message_type == 'msg'){
        if(append_to_last == true){
            new_msg_li.find('h3').hide();
            new_msg_li.find('.msg_date').hide();
            new_msg_li.addClass('no_break_above');
            previous_message_li.addClass('no_break_below');
        }
    }
}

function pretty_time_now(msg_time){
    var now = new Date();
    diff = Math.round(Math.abs( now - msg_time) / 1000);

    msg_pretty_time = false;
    if(diff < 20){
        msg_pretty_time = 'seconds ago';
    }else if(diff < 60){
        msg_pretty_time = 'less then a minute ago'
    }else if(diff <= 5400){
        minutes = Math.round(diff / 60);
        if(minutes == 1){
            msg_pretty_time = '1 minute ago';
        } else {
            msg_pretty_time = minutes + ' mintues ago';
        }
    }else if(diff > 5401){
        hours = Math.round(diff / 3600)
        msg_pretty_time = 'about '+hours+' hours ago';
    } else {
        msg_pretty_time = 'just now';
    }
    return msg_pretty_time;
}

function settings_update(){
    $('.setting-update').click(function(){
        setting_name = $(this).attr('name');
        if(setting_name=='clear_local'){
            localStorage.clear();
        }
    });
}

function lock_console(){
    $('#settings_btn').fadeOut();
    $('#chat_window').fadeOut();
    $('#lock_status').removeClass('fa-unlock-alt').addClass('fa-lock');
    $('#repassword_container').fadeIn(1500);
    $("#repassword").focus();
    $( "#chat li" ).each(function(index) {
        if(! $(this).hasClass('typing')){
            $(this).remove();
        }
    });
    Cookies.set('password', '');
    Cookies.set('terminal', 'locked');
}

function unlock_console(password){
    Cookies.set('password', CryptoJS.MD5(password));
    Cookies.set('terminal', 'open');
    build_local_data(Cookies.get('room_key'));
    $('#lock_status').removeClass('fa-lock').addClass('fa-unlock-alt');
    $('#repassword_container').fadeOut(1500);
    $('#settings_btn').fadeIn();
    $('#chat_window').fadeIn();
    $("#textbox").focus();
    $('#chat').scrollTop($('#chat')[0].scrollHeight);
}

function timerIncrement() {
    idleTime = idleTime + 1;
    if (idleTime >= 2) { // 120 seconds
        lock_console();
    }
}

var socket;
var idleTime = 0;

var CHATSEC = CHATSEC || (function(){

    return {
        init : function(Args) {
            _args = Args;

            $('#room_name').html(':: ' + Cookies.set('room_name'));
            $('title').html('Chatsec::  ' + Cookies.set('room_name'));

            window.Notification.requestPermission().then(function(result) {
                Cookies.set('notifications', true);
                console.log(result);
            });

        },
        launch : function(){
            if(Cookies.get('password')==''){
                window.location = '/';
            }

            $(document).ready(function(){
                build_local_data(Cookies.get('room_key'));
                $('.typing').hide();
                $("#textbox").focus();

                // Manual/Idle Lockout
                $('#lock_btn').click(function(){
                    lock_console();
                });
                var idleInterval = setInterval(timerIncrement, 60000); // 60 seconds
                //Zero the idle timer on mouse movement.
                $(this).mousemove(function (e) {
                    idleTime = 0;
                });
                $(this).keypress(function (e) {
                    idleTime = 0;
                });
                $('.cs_login').keypress(function(e) {
                    var code = e.keyCode || e.which;
                    if (code == 13) {
                        unlock_console($(this).val());
                        $(this).val('');
                        timeoutTime = 0;
                        // set_login_creds($(this));
                    }
                });

                // Sockets
                socket = io.connect(window.location.protocol + '//' + document.domain + ':' + location.port + '/chat');
                socket.on('connect', function() {
                    socket.emit('joined', {});
                });

                socket.on('status', function(data) {
                    $(data.tpl).insertBefore('#chat li:last');
                    $('#chat').scrollTop($('#chat')[0].scrollHeight);
                });

                // Reciving user currently typing
                socket.on('typing', function(data) {
                    if(Cookies.get('user_name') != data.user_name ){
                        $('.typing').find('.typing_avatar').attr(
                            'src',
                            '/static/imgs/avatars/black/' + data.avatar
                        );
                        $('.typing').find('h3').text(data.user_name);
                        $('.typing').show().delay(750).fadeOut();
                        $('#chat').scrollTop($('#chat')[0].scrollHeight);
                    }
                });

                // Recieving a message
                socket.on('message', function(data) {
                    draw_msg(data);

                    if(Cookies.get('user_name') != data.user_name ){
                        var audio = new Audio('/static/audio/new_msg.mp3');
                        audio.play();
                        spawn_notification(data);
                    }
                    store_message(data);
                });

                // Sending a message
                $('#textbox').keypress(function(e) {
                    var code = e.keyCode || e.which;
                    if (code == 13) {
                        message = $('#textbox').val();
                        send_msg(message);
                        $('#textbox').val('');
                    } else {
                        socket.emit('typing', {'msg': 'chatsec-user-typing'});
                    }
                });

                $('#send').click(function(e){
                    send_msg($('#textbox').val());
                });

                // @todo: make t his actually work or kill it
                $(window).on('beforeunload', function(){
                    socket.emit('left', {}, function() {
                        socket.disconnect();
                    });
                });

                // Timer Scripts
                window.setInterval(function(){
                    // Update msg time
                    $("#chat li").each(function( index ) {
                        var sent_time = new Date( $(this).attr('data-date') );
                        msg_pretty_time = pretty_time_now(sent_time)
                        if(msg_pretty_time){
                            $(this).find('.msg_date').text(msg_pretty_time);
                        }
                    });

                    // Highlight code blocks
                    $('pre').each(function(i, block) {
                        // hljs.highlightBlock(block);
                    });
                }, 1000);
            });
        }
    };
}());<|endoftext|>


<commit_before>var southWest = L.latLng(34.9816, -85.4719);
var northEast = L.latLng(35.217, -85.0462);
var center = L.latLng(35.0657, -85.241);
var bounds = L.latLngBounds(southWest, northEast);

var map = L.map('map', {
  maxZoom: 18,
  minZoom: 11,
  maxBounds: bounds,
  center: center,
  zoom: 12
});

L.tileLayer('static/tiles/{z}/{x}/{y}.png', {
    attribution: 'Map data © OpenStreetMap contributors, CC-BY-SA, Zone data © City of Chattanooga, Imagery © Mapbox'}).addTo(map);

r
<commit_msg>Replace local tile URL with Chattanooga Public Library map tiles on GitHub.<commit_after>var southWest = L.latLng(34.9816, -85.4719);
var northEast = L.latLng(35.217, -85.0462);
var center = L.latLng(35.0657, -85.241);
var bounds = L.latLngBounds(southWest, northEast);

var map = L.map('map', {
  maxZoom: 18,
  minZoom: 11,
  maxBounds: bounds,
  center: center,
  zoom: 12
});

L.tileLayer('http://chattanoogapubliclibrary.github.io/cpd-zones-tiles/tiles/{z}/{x}/{y}.png', {
    attribution: 'Map data © OpenStreetMap contributors, CC-BY-SA, Zone data © City of Chattanooga, Imagery © Mapbox'}).addTo(map);

r
<|endoftext|>


<commit_before>// @flow
import { api, type Claims } from 'neon-js'
import { map, reduce } from 'lodash'

import {
  showErrorNotification,
  showSuccessNotification,
  showInfoNotification
} from './notifications'
import {
  getNetwork,
  getWIF,
  getAddress,
  getSigningFunction,
  getPublicKey,
  getIsHardwareLogin,
  getNEO
} from '../core/deprecated'
import { toBigNumber, toNumber } from '../core/math'
import { ASSETS } from '../core/constants'
import { FIVE_MINUTES_MS } from '../core/time'
import poll from '../util/poll'

const POLL_ATTEMPTS = 50
const POLL_FREQUENCY = 5000

const fetchClaims = async ({ net, address }) => {
  const response = await api.getClaimsFrom({ net, address }, api.neoscan)
  const { claims } = response.claims
  return map(claims, 'claim')
}

const calculateClaimableAmount = (claims: Claims) => {
  return reduce(claims, (sum, claim) => claim.plus(sum), 0).toString()
}

const getClaimableAmount = async ({ net, address }) => {
  const claims = await fetchClaims({ net, address })
  return calculateClaimableAmount(claims)
}

const updateClaimableAmount = async ({ net, address, publicKey, privateKey, signingFunction, balance }) => {
  const { response } = await api.sendAsset({
    net,
    address,
    publicKey,
    privateKey,
    signingFunction,
    intents: api.makeIntent({ [ASSETS.NEO]: toNumber(balance) }, address)
  }, api.neoscan)

  if (!response.result || !response.txid) {
    throw new Error('Transaction failed!')
  }

  return response.result.response
}

const pollForUpdatedClaimableAmount = async ({ net, address, claimableAmount }) => {
  return poll(async () => {
    const updatedClaimableAmount = await getClaimableAmount({ net, address })

    if (toBigNumber(updatedClaimableAmount).eq(claimableAmount)) {
      throw new Error('Waiting for updated claims took too long.')
    }

    return updatedClaimableAmount
  }, { attempts: POLL_ATTEMPTS, frequency: POLL_FREQUENCY })
}

const getUpdatedClaimableAmount = async ({ net, address, balance, publicKey, privateKey, signingFunction }) => {
  const claimableAmount = await getClaimableAmount({ net, address })

  if (toBigNumber(balance).eq(0)) {
    return claimableAmount
  } else {
    await updateClaimableAmount({ net, address, balance, publicKey, privateKey, signingFunction })
    return pollForUpdatedClaimableAmount({ net, address, claimableAmount })
  }
}

export const doGasClaim = () => async (dispatch: DispatchType, getState: GetStateType) => {
  const state = getState()
  const address = getAddress(state)
  const net = getNetwork(state)
  const balance = getNEO(state)
  const publicKey = getPublicKey(state)
  const privateKey = getWIF(state)
  const signingFunction = getSigningFunction(state)
  const isHardwareClaim = getIsHardwareLogin(state)

  dispatch(disableClaim(true))

  if (isHardwareClaim) {
    dispatch(showInfoNotification({ message: 'Please sign transaction 1 of 2 on hardware device.' }))
  } else {
    dispatch(showInfoNotification({ message: 'Calculating claimable GAS...' }))
  }

  // step 1: update available claims
  try {
    await getUpdatedClaimableAmount({ net, address, balance, publicKey, privateKey, signingFunction })
  } catch (err) {
    dispatch(disableClaim(false))
    dispatch(showErrorNotification({ message: `Error calculating claimable GAS: ${err.message}` }))
    return
  }

  if (isHardwareClaim) {
    dispatch(showInfoNotification({ message: 'Please sign transaction 2 of 2 on hardware device.' }))
  } else {
    dispatch(showInfoNotification({ message: 'Claiming GAS...' }))
  }

  // step 2: send claim request
  try {
    var { claims } = await api.getClaimsFrom({net, address}, api.neoscan)
    if (isHardwareClaim) claims = claims.slice(0, 25)
    const { response } = await api.claimGas({ net, address, claims, publicKey, privateKey, signingFunction }, api.neoscan)

    if (!response.result) {
      throw new Error('Claiming GAS failed')
    }
  } catch (err) {
    dispatch(disableClaim(false))
    dispatch(showErrorNotification({ message: `Claiming GAS failed: ${err}` }))
    return
  }

  dispatch(showSuccessNotification({
    message: 'Claim was successful! Your balance will update once the blockchain has processed it.'
  }))
  setTimeout(() => dispatch(disableClaim(false)), FIVE_MINUTES_MS)
}

// Constants
export const DISABLE_CLAIM = 'DISABLE_CLAIM'

// Actions
export function disableClaim (disableClaimButton: boolean) {
  return {
    type: DISABLE_CLAIM,
    payload: { disableClaimButton }
  }
}

// State Getters
export const getDisableClaimButton = (state: Object) => state.claim.disableClaimButton

const initialState = {
  disableClaimButton: false
}

export default (state: Object = initialState, action: ReduxAction) => {
  switch (action.type) {
    case DISABLE_CLAIM:
      const { disableClaimButton } = action.payload
      return {
        ...state,
        disableClaimButton
      }
    default:
      return state
  }
}
<commit_msg>Updated GAS claiming to poll half as often for 5 minutes<commit_after>// @flow
import { api, type Claims } from 'neon-js'
import { map, reduce } from 'lodash'

import {
  showErrorNotification,
  showSuccessNotification,
  showInfoNotification
} from './notifications'
import {
  getNetwork,
  getWIF,
  getAddress,
  getSigningFunction,
  getPublicKey,
  getIsHardwareLogin,
  getNEO
} from '../core/deprecated'
import { toBigNumber, toNumber } from '../core/math'
import { ASSETS } from '../core/constants'
import { FIVE_MINUTES_MS } from '../core/time'
import poll from '../util/poll'

const POLL_ATTEMPTS = 30
const POLL_FREQUENCY = 10000

const fetchClaims = async ({ net, address }) => {
  const response = await api.getClaimsFrom({ net, address }, api.neoscan)
  const { claims } = response.claims
  return map(claims, 'claim')
}

const calculateClaimableAmount = (claims: Claims) => {
  return reduce(claims, (sum, claim) => claim.plus(sum), 0).toString()
}

const getClaimableAmount = async ({ net, address }) => {
  const claims = await fetchClaims({ net, address })
  return calculateClaimableAmount(claims)
}

const updateClaimableAmount = async ({ net, address, publicKey, privateKey, signingFunction, balance }) => {
  const { response } = await api.sendAsset({
    net,
    address,
    publicKey,
    privateKey,
    signingFunction,
    intents: api.makeIntent({ [ASSETS.NEO]: toNumber(balance) }, address)
  }, api.neoscan)

  if (!response.result || !response.txid) {
    throw new Error('Transaction failed!')
  }

  return response.result.response
}

const pollForUpdatedClaimableAmount = async ({ net, address, claimableAmount }) => {
  return poll(async () => {
    const updatedClaimableAmount = await getClaimableAmount({ net, address })

    if (toBigNumber(updatedClaimableAmount).eq(claimableAmount)) {
      throw new Error('Waiting for updated claims took too long.')
    }

    return updatedClaimableAmount
  }, { attempts: POLL_ATTEMPTS, frequency: POLL_FREQUENCY })
}

const getUpdatedClaimableAmount = async ({ net, address, balance, publicKey, privateKey, signingFunction }) => {
  const claimableAmount = await getClaimableAmount({ net, address })

  if (toBigNumber(balance).eq(0)) {
    return claimableAmount
  } else {
    await updateClaimableAmount({ net, address, balance, publicKey, privateKey, signingFunction })
    return pollForUpdatedClaimableAmount({ net, address, claimableAmount })
  }
}

export const doGasClaim = () => async (dispatch: DispatchType, getState: GetStateType) => {
  const state = getState()
  const address = getAddress(state)
  const net = getNetwork(state)
  const balance = getNEO(state)
  const publicKey = getPublicKey(state)
  const privateKey = getWIF(state)
  const signingFunction = getSigningFunction(state)
  const isHardwareClaim = getIsHardwareLogin(state)

  dispatch(disableClaim(true))

  if (isHardwareClaim) {
    dispatch(showInfoNotification({ message: 'Please sign transaction 1 of 2 on hardware device.' }))
  } else {
    dispatch(showInfoNotification({ message: 'Calculating claimable GAS...' }))
  }

  // step 1: update available claims
  try {
    await getUpdatedClaimableAmount({ net, address, balance, publicKey, privateKey, signingFunction })
  } catch (err) {
    dispatch(disableClaim(false))
    dispatch(showErrorNotification({ message: `Error calculating claimable GAS: ${err.message}` }))
    return
  }

  if (isHardwareClaim) {
    dispatch(showInfoNotification({ message: 'Please sign transaction 2 of 2 on hardware device.' }))
  } else {
    dispatch(showInfoNotification({ message: 'Claiming GAS...' }))
  }

  // step 2: send claim request
  try {
    var { claims } = await api.getClaimsFrom({net, address}, api.neoscan)
    if (isHardwareClaim) claims = claims.slice(0, 25)
    const { response } = await api.claimGas({ net, address, claims, publicKey, privateKey, signingFunction }, api.neoscan)

    if (!response.result) {
      throw new Error('Claiming GAS failed')
    }
  } catch (err) {
    dispatch(disableClaim(false))
    dispatch(showErrorNotification({ message: `Claiming GAS failed: ${err}` }))
    return
  }

  dispatch(showSuccessNotification({
    message: 'Claim was successful! Your balance will update once the blockchain has processed it.'
  }))
  setTimeout(() => dispatch(disableClaim(false)), FIVE_MINUTES_MS)
}

// Constants
export const DISABLE_CLAIM = 'DISABLE_CLAIM'

// Actions
export function disableClaim (disableClaimButton: boolean) {
  return {
    type: DISABLE_CLAIM,
    payload: { disableClaimButton }
  }
}

// State Getters
export const getDisableClaimButton = (state: Object) => state.claim.disableClaimButton

const initialState = {
  disableClaimButton: false
}

export default (state: Object = initialState, action: ReduxAction) => {
  switch (action.type) {
    case DISABLE_CLAIM:
      const { disableClaimButton } = action.payload
      return {
        ...state,
        disableClaimButton
      }
    default:
      return state
  }
}
<|endoftext|>


<commit_before>Ext.define('doweown.view.AvailView', {
    extend: 'Ext.DataView',
    xtype: 'availview',

    config: {
           title: 'Availability',
           store: 'BranchStore',
           /*onItemDisclosure: function( record, btn, index ) {
                                Ext.Msg.alert( record.get('collection.collectionname'), Ext.emptyFn);
            },*/
            itemTpl: '
 {repository.name} <tpl for="collection">
 {collectionname}
{callnumber}<tpl for="items">
 <tpl switch="isavail"><tpl case="N" case="n">Not Available<tpl default>Available</tpl>:{stat}
 Call#: {call}
 {req.content}
</tpl> <tpl for="holdtag">
 {availkey} {availval.content}
</tpl>  <tpl for="online"> {content}
</tpl> </tpl>

'
     }

});
<commit_msg>added pinheaders<commit_after>Ext.define('doweown.view.AvailView', {
    extend: 'Ext.DataView',
    xtype: 'availview',

    config: {
           title: 'Availability',
           store: 'BranchStore',
	   pinHeaders: true,
           /*onItemDisclosure: function( record, btn, index ) {
                                Ext.Msg.alert( record.get('collection.collectionname'), Ext.emptyFn);
            },*/
            itemTpl: '
 {repository.name} <tpl for="collection">
 {collectionname}
<tpl if="callnumber">{callnumber}</tpl><tpl for="items">
 <tpl switch="isavail"><tpl case="N" case="n">Not Available<tpl default>Available</tpl>:{stat}
 Call#: {call}
 {req.content}
</tpl> <tpl for="holdtag">
 {availkey} {availval.content}
</tpl>  <tpl for="online"> {content}
</tpl> </tpl>

'
     }

});
<|endoftext|>


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

if (!roms.common) {
    roms.common = {};
};

roms.common.validatorPhoneNumber = function(value, element) {
    if (this.optional(element)) {
        return true;
    } else {
        try {
            var phone = cleanPhone(value);
            var phoneUtil = i18n.phonenumbers.PhoneNumberUtil.getInstance();
            var number = phoneUtil.parseAndKeepRawInput(phone, "GB");
            return phoneUtil.isValidNumber(number);
        } catch (exception) {
            return false;
        }
    }
};

roms.common.validatorMobilePhoneNumber = function(value, element) {
    if (this.optional(element)) {
        return true;
    } else {
        try {
            var phone = cleanPhone(value);
            var phoneUtil = i18n.phonenumbers.PhoneNumberUtil.getInstance();
            var number = phoneUtil.parseAndKeepRawInput(phone, "GB");
            return phoneUtil.getNumberType(number) == 1;
        } catch (exception) {
            return false;
        }
    }
};

roms.common.validatorErrorPlacement = function(error, element) {
    var $container = element.closest(".error-container");
    if ($container.length > 0) {
        error.appendTo($container);
    } else {
        element.after(error);
    }
};

/**
 * Match a person to a given forename and surname (exact match).
 * This assumes we have the person-link-search-form and person-link-modal elements on the page
 * @param forename person's first name
 * @param surname person's last name
 * @param $personId jquery element linking to the input use to store the matched person id
 * @param populateFunction callback to populate the page with the selected person
 */
roms.common.matchLinkedPerson = function (forename, surname, $personId, populateFunction) {
    if(!forename || !surname) {
        // clear any linked name
        $personId.data("full-name", "");
        populateFunction(null, forename, surname, $personId);
        return;
    }

    var existingPersonName = $personId.data("full-name");
    if (existingPersonName == forename + " " + surname) {
        // no change in value
        return;
    }
    var existingPersonId = $personId.val();

    $.ajax({
        url: roms.common.relativePath + '/persons/search',
        contentType: "application/json",
        dataType: 'json',
        data:  {
            forename: forename,
            surname: surname,
            checkVolunteer: false
        },
        success: function(data) {
            // no match, and no person linked. We don't show anything
            if ((!data || data.length === 0) && !existingPersonId) {
                return;
            }

            templateData = {};
            templateData.existingPersonId = existingPersonId;
            templateData.existingPersonName = existingPersonName;

            if (data) {
                templateData.matchedPersons = true;
                templateData.results = data;
            }

            var template = $("#person-link-search-form").html();
            var html = Mustache.to_html(template, templateData);

            $("#person-link-modal .modal-body").html(html)
            var modalElement = $("#person-link-modal")

            modalElement.modal('show')

            // if they select the person id, set it to the hidden volunteer person id field
            $("a.matched-person").on("click", function(event){
                populateFunction($(this).data("person-id"), forename, surname, $personId);
                modalElement.modal('hide')
            });
        }
    });

    $personId.data("full-name", forename + " " + surname);
}

/**
 * Extensions to datatables to fit in with bootstrap styling
 * See http://www.datatables.net/media/blog/bootstrap_2/DT_bootstrap.js
 * @param $table table element
 * @param additional dataTable options to set
 */
roms.common.datatables = function($table, options) {
    $.extend( true, $.fn.dataTable.defaults, {
        "sDom": "<'row'<'col-md-2 pull-right'l><'col-md-3 col-md-offset-7'f>>rt<'row'<'col-md-6'i><'col-md-6'p>>",
        "sPaginationType": "bootstrap",
        "oLanguage": {
            "sLengthMenu": "_MENU_ records per page"
        }
    } );

    $.extend( $.fn.dataTableExt.oStdClasses, {
        "sWrapper": "dataTables_wrapper form-inline"
    } );

    /* API method to get paging information */
    $.fn.dataTableExt.oApi.fnPagingInfo = function ( oSettings )
    {
        return {
            "iStart":         oSettings._iDisplayStart,
            "iEnd":           oSettings.fnDisplayEnd(),
            "iLength":        oSettings._iDisplayLength,
            "iTotal":         oSettings.fnRecordsTotal(),
            "iFilteredTotal": oSettings.fnRecordsDisplay(),
            "iPage":          oSettings._iDisplayLength === -1 ?
            0 : Math.ceil( oSettings._iDisplayStart / oSettings._iDisplayLength ),
            "iTotalPages":    oSettings._iDisplayLength === -1 ?
            0 : Math.ceil( oSettings.fnRecordsDisplay() / oSettings._iDisplayLength )
        };
    };

    /* Bootstrap style pagination control */
    $.extend( $.fn.dataTableExt.oPagination, {
        "bootstrap": {
            "fnInit": function( oSettings, nPaging, fnDraw ) {
                var oLang = oSettings.oLanguage.oPaginate;
                var fnClickHandler = function ( e ) {
                    e.preventDefault();
                    if ( oSettings.oApi._fnPageChange(oSettings, e.data.action) ) {
                        fnDraw( oSettings );
                    }
                };

                $(nPaging).append(
                    '
'+
                    '
← '+oLang.sPrevious+'
'+
                    '
'+oLang.sNext+' →
'+
                    '
'
                    );
                var els = $('a', nPaging);
                $(els[0]).bind( 'click.DT', {
                    action: "previous"
                }, fnClickHandler );
                $(els[1]).bind( 'click.DT', {
                    action: "next"
                }, fnClickHandler );
            },

            "fnUpdate": function ( oSettings, fnDraw ) {
                var iListLength = 5;
                var oPaging = oSettings.oInstance.fnPagingInfo();
                var an = oSettings.aanFeatures.p;
                var i, ien, j, sClass, iStart, iEnd, iHalf=Math.floor(iListLength/2);

                if ( oPaging.iTotalPages < iListLength) {
                    iStart = 1;
                    iEnd = oPaging.iTotalPages;
                }
                else if ( oPaging.iPage <= iHalf ) {
                    iStart = 1;
                    iEnd = iListLength;
                } else if ( oPaging.iPage >= (oPaging.iTotalPages-iHalf) ) {
                    iStart = oPaging.iTotalPages - iListLength + 1;
                    iEnd = oPaging.iTotalPages;
                } else {
                    iStart = oPaging.iPage - iHalf + 1;
                    iEnd = iStart + iListLength - 1;
                }

                for ( i=0, ien=an.length ; i<ien ; i++ ) {
                    // Remove the middle elements
                    $('li:gt(0)', an[i]).filter(':not(:last)').remove();

                    // Add the new list items and their event handlers
                    for ( j=iStart ; j<=iEnd ; j++ ) {
                        sClass = (j==oPaging.iPage+1) ? 'class="active"' : '';
                        $('
'+j+'
')
                        .insertBefore( $('li:last', an[i])[0] )
                        .bind('click', function (e) {
                            e.preventDefault();
                            oSettings._iDisplayStart = (parseInt($('a', this).text(),10)-1) * oPaging.iLength;
                            fnDraw( oSettings );
                        } );
                    }

                    // Add / remove disabled classes from the static elements
                    if ( oPaging.iPage === 0 ) {
                        $('li:first', an[i]).addClass('disabled');
                    } else {
                        $('li:first', an[i]).removeClass('disabled');
                    }

                    if ( oPaging.iPage === oPaging.iTotalPages-1 || oPaging.iTotalPages === 0 ) {
                        $('li:last', an[i]).addClass('disabled');
                    } else {
                        $('li:last', an[i]).removeClass('disabled');
                    }
                }
                //If all data fits into one page, hide the pagination and "Showing ? of ? Entries"
                if (oPaging.iTotalPages <= 1) {
                    $('.dataTables_paginate').hide();
                    $('.dataTables_info').hide();
                } else {
                    $('.dataTables_paginate').show();
                    $('.dataTables_info').show();
                }
                //If the number of rows are 5 or less, hide "... results per page" and Search box
                if (oPaging.iTotal <= 5) {
                    $('.dataTables_length').hide();
                    $('.dataTables_filter').hide();
                } else {
                    $('.dataTables_length').show();
                }
                if (oPaging.iFilteredTotal <= 5)    {
                    $('.dataTables_filter').hide();
                } else {
                    $('.dataTables_filter').show();
                }
        }
    } });

    /*
     * TableTools Bootstrap compatibility
     * Required TableTools 2.1+
     */
    if ( $.fn.DataTable.TableTools ) {
        // Set the classes that TableTools uses to something suitable for Bootstrap
        $.extend( true, $.fn.DataTable.TableTools.classes, {
            "container": "DTTT btn-group",
            "buttons": {
                "normal": "btn",
                "disabled": "disabled"
            },
            "collection": {
                "container": "DTTT_dropdown dropdown-menu",
                "buttons": {
                    "normal": "",
                    "disabled": "disabled"
                }
            },
            "print": {
                "info": "DTTT_print_info modal"
            },
            "select": {
                "row": "active"
            }
        } );

        // Have the collection use a bootstrap compatible dropdown
        $.extend( true, $.fn.DataTable.TableTools.DEFAULTS.oTags, {
            "collection": {
                "container": "ul",
                "button": "li",
                "liner": "a"
            }
        } );
    }

    // create the table
    $table.dataTable(options);

}

roms.common.persistentTabs = function() {
    if (location.hash.substr(0,2) == "#!") {
        $("a[href='#" + location.hash.substr(2) + "']").tab("show");
    }

    $("a[data-toggle='tab']").on("shown", function (e) {
        var hash = $(e.target).attr("href");
        if (hash.substr(0,1) == "#") {
            location.replace("#!" + hash.substr(1));
        }
    });
}

roms.common.validation = {};
$(document).ready(function() {
    // store the relative path, used for all the ajax calls
    // we trim the trailing slash to allow uris that include it look absolute
    roms.common.relativePath = $("#relative-path").data("relative-path").replace(/\/$/, '');

    // remote validation method for kingdom hall typeahead lookups
    roms.common.validation.kingdomHall = function($nameInput, $idInput) {
        return {
            // check for an exact match. Populate the kingdom hall id
            url: roms.common.relativePath + "/kingdom-halls/search",
            contentType: "application/json",
            dataType: "json",
            data: {
                name: function() {
                    return $nameInput.val();
                }
            },
            dataFilter: function(rawData) {
                var data = JSON.parse(rawData)
                if (data && data[0].name == $nameInput.val()) {
                    $idInput.val(data[0].id);
                    return true;
                }
             // no match - clear the stored id
                $idInput.val(null);
                return false;
            }
        };
    }

    roms.common.validation.congregation = function($nameInput, $idInput) {
        return {
            // check for an exact match. Populate the congregation id
            url: roms.common.relativePath + "/congregations/search",
            contentType: "application/json",
            dataType: "json",
            data: {
                name: function() {
                    return $nameInput.val();
                }
            },
            dataFilter: function(rawData) {
                var data = JSON.parse(rawData)
                if (data && data[0].name == $nameInput.val()) {
                    $idInput.val(data[0].id);
                    return true;
                }
                // no match - clear the stored id
                $idInput.val(null);
                return false;
            }
        };
    }

    roms.common.validation.user = function($nameInput, $idInput) {
        return {
            // check for an exact match. Populate the user id
            url: roms.common.relativePath + "/users/search",
            contentType: "application/json",
            dataType: "json",
            data: {
                name: function() {
                    return $nameInput.val();
                }
            },
            dataFilter: function(rawData) {
                var data = JSON.parse(rawData)
                if (data && data[0].userName == $nameInput.val()) {
                    $idInput.val(data[0].personId);
                    return true;
                }
                // no match - clear the stored id
                $idInput.val(null);
                return false;
            }
        };
    }

});

// validation configuration

<commit_msg>[#64343772] Minor changes in common.js code<commit_after>/*
 * The MIT License
 *
 * Copyright 2013 RBC1B.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
if (!roms) {
    var roms = {};
};

if (!roms.common) {
    roms.common = {};
};

roms.common.validatorPhoneNumber = function(value, element) {
    if (this.optional(element)) {
        return true;
    } else {
        try {
            var phone = cleanPhone(value);
            var phoneUtil = i18n.phonenumbers.PhoneNumberUtil.getInstance();
            var number = phoneUtil.parseAndKeepRawInput(phone, "GB");
            return phoneUtil.isValidNumber(number);
        } catch (exception) {
            return false;
        }
    }
};

roms.common.validatorMobilePhoneNumber = function(value, element) {
    if (this.optional(element)) {
        return true;
    } else {
        try {
            var phone = cleanPhone(value);
            var phoneUtil = i18n.phonenumbers.PhoneNumberUtil.getInstance();
            var number = phoneUtil.parseAndKeepRawInput(phone, "GB");
            return phoneUtil.getNumberType(number) == 1;
        } catch (exception) {
            return false;
        }
    }
};

roms.common.validatorErrorPlacement = function(error, element) {
    var $container = element.closest(".error-container");
    if ($container.length > 0) {
        error.appendTo($container);
    } else {
        element.after(error);
    }
};

/**
 * Match a person to a given forename and surname (exact match).
 * This assumes we have the person-link-search-form and person-link-modal elements on the page
 * @param forename person's first name
 * @param surname person's last name
 * @param $personId jquery element linking to the input use to store the matched person id
 * @param populateFunction callback to populate the page with the selected person
 */
roms.common.matchLinkedPerson = function (forename, surname, $personId, populateFunction) {
    if(!forename || !surname) {
        // clear any linked name
        $personId.data("full-name", "");
        populateFunction(null, forename, surname, $personId);
        return;
    }

    var existingPersonName = $personId.data("full-name");
    if (existingPersonName == forename + " " + surname) {
        // no change in value
        return;
    }
    var existingPersonId = $personId.val();

    $.ajax({
        url: roms.common.relativePath + '/persons/search',
        contentType: "application/json",
        dataType: 'json',
        data:  {
            forename: forename,
            surname: surname,
            checkVolunteer: false
        },
        success: function(data) {
            // no match, and no person linked. We don't show anything
            if ((!data || data.length === 0) && !existingPersonId) {
                return;
            }

            templateData = {};
            templateData.existingPersonId = existingPersonId;
            templateData.existingPersonName = existingPersonName;

            if (data) {
                templateData.matchedPersons = true;
                templateData.results = data;
            }

            var template = $("#person-link-search-form").html();
            var html = Mustache.to_html(template, templateData);

            $("#person-link-modal .modal-body").html(html)
            var modalElement = $("#person-link-modal")

            modalElement.modal('show')

            // if they select the person id, set it to the hidden volunteer person id field
            $("a.matched-person").on("click", function(event){
                populateFunction($(this).data("person-id"), forename, surname, $personId);
                modalElement.modal('hide')
            });
        }
    });

    $personId.data("full-name", forename + " " + surname);
}

/**
 * Extensions to datatables to fit in with bootstrap styling
 * See http://www.datatables.net/media/blog/bootstrap_2/DT_bootstrap.js
 * @param $table table element
 * @param additional dataTable options to set
 */
roms.common.datatables = function($table, options) {
    $.extend( true, $.fn.dataTable.defaults, {
        "sDom": "<'row'<'col-md-2 pull-right'l><'col-md-3 col-md-offset-7'f>>rt<'row'<'col-md-6'i><'col-md-6'p>>",
        "sPaginationType": "bootstrap",
        "oLanguage": {
            "sLengthMenu": "_MENU_ records per page"
        }
    } );

    $.extend( $.fn.dataTableExt.oStdClasses, {
        "sWrapper": "dataTables_wrapper form-inline"
    } );

    /* API method to get paging information */
    $.fn.dataTableExt.oApi.fnPagingInfo = function ( oSettings )
    {
        return {
            "iStart":         oSettings._iDisplayStart,
            "iEnd":           oSettings.fnDisplayEnd(),
            "iLength":        oSettings._iDisplayLength,
            "iTotal":         oSettings.fnRecordsTotal(),
            "iFilteredTotal": oSettings.fnRecordsDisplay(),
            "iPage":          oSettings._iDisplayLength === -1 ?
            0 : Math.ceil( oSettings._iDisplayStart / oSettings._iDisplayLength ),
            "iTotalPages":    oSettings._iDisplayLength === -1 ?
            0 : Math.ceil( oSettings.fnRecordsDisplay() / oSettings._iDisplayLength )
        };
    };

    /* Bootstrap style pagination control */
    $.extend( $.fn.dataTableExt.oPagination, {
        "bootstrap": {
            "fnInit": function( oSettings, nPaging, fnDraw ) {
                var oLang = oSettings.oLanguage.oPaginate;
                var fnClickHandler = function ( e ) {
                    e.preventDefault();
                    if ( oSettings.oApi._fnPageChange(oSettings, e.data.action) ) {
                        fnDraw( oSettings );
                    }
                };

                $(nPaging).append(
                    '
'+
                    '
← '+oLang.sPrevious+'
'+
                    '
'+oLang.sNext+' →
'+
                    '
'
                    );
                var els = $('a', nPaging);
                $(els[0]).bind( 'click.DT', {
                    action: "previous"
                }, fnClickHandler );
                $(els[1]).bind( 'click.DT', {
                    action: "next"
                }, fnClickHandler );
            },

            "fnUpdate": function ( oSettings, fnDraw ) {
                var iListLength = 5;
                var oPaging = oSettings.oInstance.fnPagingInfo();
                var an = oSettings.aanFeatures.p;
                var i, ien, j, sClass, iStart, iEnd, iHalf=Math.floor(iListLength/2);

                if ( oPaging.iTotalPages < iListLength) {
                    iStart = 1;
                    iEnd = oPaging.iTotalPages;
                }
                else if ( oPaging.iPage <= iHalf ) {
                    iStart = 1;
                    iEnd = iListLength;
                } else if ( oPaging.iPage >= (oPaging.iTotalPages-iHalf) ) {
                    iStart = oPaging.iTotalPages - iListLength + 1;
                    iEnd = oPaging.iTotalPages;
                } else {
                    iStart = oPaging.iPage - iHalf + 1;
                    iEnd = iStart + iListLength - 1;
                }

                for ( i=0, ien=an.length ; i<ien ; i++ ) {
                    // Remove the middle elements
                    $('li:gt(0)', an[i]).filter(':not(:last)').remove();

                    // Add the new list items and their event handlers
                    for ( j=iStart ; j<=iEnd ; j++ ) {
                        sClass = (j==oPaging.iPage+1) ? 'class="active"' : '';
                        $('
'+j+'
')
                        .insertBefore( $('li:last', an[i])[0] )
                        .bind('click', function (e) {
                            e.preventDefault();
                            oSettings._iDisplayStart = (parseInt($('a', this).text(),10)-1) * oPaging.iLength;
                            fnDraw( oSettings );
                        } );
                    }

                    // Add / remove disabled classes from the static elements
                    if ( oPaging.iPage === 0 ) {
                        $('li:first', an[i]).addClass('disabled');
                    } else {
                        $('li:first', an[i]).removeClass('disabled');
                    }

                    if ( oPaging.iPage === oPaging.iTotalPages-1 || oPaging.iTotalPages === 0 ) {
                        $('li:last', an[i]).addClass('disabled');
                    } else {
                        $('li:last', an[i]).removeClass('disabled');
                    }
                }
                //If all data fits into one page, hide the pagination and "Showing ? of ? Entries"
                if (oPaging.iTotalPages <= 1) {
                    $('.dataTables_paginate').hide();
                    $('.dataTables_info').hide();
                } else {
                    $('.dataTables_paginate').show();
                    $('.dataTables_info').show();
                }
                //If the number of rows are 5 or less, hide "... records per page" and Search box
                if (oPaging.iTotal <= 5) {
                    $('.dataTables_length').hide();
                    $('.dataTables_filter').hide();
                }
        }
    } });

    /*
     * TableTools Bootstrap compatibility
     * Required TableTools 2.1+
     */
    if ( $.fn.DataTable.TableTools ) {
        // Set the classes that TableTools uses to something suitable for Bootstrap
        $.extend( true, $.fn.DataTable.TableTools.classes, {
            "container": "DTTT btn-group",
            "buttons": {
                "normal": "btn",
                "disabled": "disabled"
            },
            "collection": {
                "container": "DTTT_dropdown dropdown-menu",
                "buttons": {
                    "normal": "",
                    "disabled": "disabled"
                }
            },
            "print": {
                "info": "DTTT_print_info modal"
            },
            "select": {
                "row": "active"
            }
        } );

        // Have the collection use a bootstrap compatible dropdown
        $.extend( true, $.fn.DataTable.TableTools.DEFAULTS.oTags, {
            "collection": {
                "container": "ul",
                "button": "li",
                "liner": "a"
            }
        } );
    }

    // create the table
    $table.dataTable(options);

}

roms.common.persistentTabs = function() {
    if (location.hash.substr(0,2) == "#!") {
        $("a[href='#" + location.hash.substr(2) + "']").tab("show");
    }

    $("a[data-toggle='tab']").on("shown", function (e) {
        var hash = $(e.target).attr("href");
        if (hash.substr(0,1) == "#") {
            location.replace("#!" + hash.substr(1));
        }
    });
}

roms.common.validation = {};
$(document).ready(function() {
    // store the relative path, used for all the ajax calls
    // we trim the trailing slash to allow uris that include it look absolute
    roms.common.relativePath = $("#relative-path").data("relative-path").replace(/\/$/, '');

    // remote validation method for kingdom hall typeahead lookups
    roms.common.validation.kingdomHall = function($nameInput, $idInput) {
        return {
            // check for an exact match. Populate the kingdom hall id
            url: roms.common.relativePath + "/kingdom-halls/search",
            contentType: "application/json",
            dataType: "json",
            data: {
                name: function() {
                    return $nameInput.val();
                }
            },
            dataFilter: function(rawData) {
                var data = JSON.parse(rawData)
                if (data && data[0].name == $nameInput.val()) {
                    $idInput.val(data[0].id);
                    return true;
                }
             // no match - clear the stored id
                $idInput.val(null);
                return false;
            }
        };
    }

    roms.common.validation.congregation = function($nameInput, $idInput) {
        return {
            // check for an exact match. Populate the congregation id
            url: roms.common.relativePath + "/congregations/search",
            contentType: "application/json",
            dataType: "json",
            data: {
                name: function() {
                    return $nameInput.val();
                }
            },
            dataFilter: function(rawData) {
                var data = JSON.parse(rawData)
                if (data && data[0].name == $nameInput.val()) {
                    $idInput.val(data[0].id);
                    return true;
                }
                // no match - clear the stored id
                $idInput.val(null);
                return false;
            }
        };
    }

    roms.common.validation.user = function($nameInput, $idInput) {
        return {
            // check for an exact match. Populate the user id
            url: roms.common.relativePath + "/users/search",
            contentType: "application/json",
            dataType: "json",
            data: {
                name: function() {
                    return $nameInput.val();
                }
            },
            dataFilter: function(rawData) {
                var data = JSON.parse(rawData)
                if (data && data[0].userName == $nameInput.val()) {
                    $idInput.val(data[0].personId);
                    return true;
                }
                // no match - clear the stored id
                $idInput.val(null);
                return false;
            }
        };
    }

});

// validation configuration

<|endoftext|>