<commit_before>var app = angular.module("CoursePlanner", ['ui.sortable']);

app.controller('courseCtrl', ['$scope','$http', function($scope,$http) {
  $scope.years = [];

  //Display help if no years
  $scope.$watch(
    //Watch if the years is empty
    function(scope) {
      return scope.years.length > 0
    },
    //hide div when view is empty
    function(newValue, oldValue) {
      if(newValue) {
        $('#empty-view').hide();
      } else {
        $('#empty-view').show();
      }
    }
  );

  $scope.maxSemesters=4;

  $scope.sortableOptionsCourse = {
    //'placeholder': 'course',
    'connectWith': '.connectedSortable'
  };

  $scope.errormsg = "";
  $scope.setErrorMsg = function(text) {
    $scope.errormsg = text;
  }

  $scope.save = function() {
    var data = JSON.stringify($scope.years);
    var url = 'data:text/json;charset=utf8,' + encodeURIComponent(data);
    window.open(url, '_blank');
    window.focus();
  }

  $scope.load = function() {
    var text = prompt("paste json file here");
    if(text != null) {
      try {
        var data = JSON.parse(text);
        $scope.years = data;
	  } catch(e) {
        $scope.setErrorMsg('invalid json file');
      }
      //$scope.$apply();
	}
  }

  $scope.open = function(dept) {
    path = "files/" + dept + "_default.json";
    $http.get(path).success(function(data){
      $scope.years = data;
    }).error(function(data) {
      $scope.setErrorMsg('Invalid Selection');
    });
  }

  $scope.addYear = function() {
    $scope.years.push(new function() {
      this.title="NEW YEAR";
      this.semesters=[];
    });
	$scope.$apply();
  }

  $scope.removeYear = function(index) {
    if($scope.years[index].semesters.length > 0) {
      if(confirm("Delete year \"" + $scope.years[index].title + "\" ?")){
        $scope.years.splice(index,1);
      }
    } else {
      $scope.years.splice(index,1);
    }
  }

  $scope.removeSemester = function(year,index) {
    if(year.semesters[index].classes > 0) {
      if(confirm("Delete semester \"" + index+1 + "\" ?")){
        year.semesters.splice(index,1);
      }
    } else {
      year.semesters.splice(index,1);
    }
  }

  $scope.addSemester = function(year) {
    if(year.semesters.length < $scope.maxSemesters) {
      year.semesters.push(new function() {
        this.classes=[];
      });
    }
  }

  $scope.addCourse = function(semester) {
    semester.classes.push(new function() {
      this.name="A New Course";
      this.subj="SUBJ";
      this.num="000";
      this.credits=0;
    });
  }

  $scope.deleteCourse = function(course) {
    $scope.years.forEach(function(year) {
      year.semesters.forEach(function(semester) {
        for(i = 0; i < semester.classes.length; ++i) {
          if(semester.classes[i] == course) {
            semester.classes.splice(i,1);
          }
        }
      });
    });
  }
}]);

app.directive('contenteditable',function() {
  return {
    restrict: "A",
    require: "ngModel",
    link: function(scope, element, attrs, ngModel) {

      function read() {
        ngModel.$setViewValue(element.html());
      }

      ngModel.$render = function() {
        element.html(ngModel.$viewValue || "");
      };

      element.bind("blur keyup change", function() {
        scope.$apply(read);
      });
    }
  };
});

app.directive('course', function() {
  return {
    restrict:'AE',
    require:"?ngModel",
    link: function(scope,element,attrs,ngModel) {
      element.on('dblclick',function() {
        var course = ngModel.$modelValue;
        var newPopup;
        newPopup = "

";
        $(newPopup).dialog({
          modal: true,
          width:350,
          resizable:false,
          title: "Edit Course",
          open: function () {
            var markup =
            '<form role="form">\
            \

\
            Name:\
            <input class="form-control input-sm" name="name" id="editedCourseName" value="'+course.name+'" />\

\
            \

\
            Subject:\
            <input class="form-control input-sm" name="subj" id="editedCourseSubject" value="'+course.subj+'"/>\

\
            \

\
            Number:\
            <input class="form-control input-sm" name="num" id="editedCourseNum" value="'+course.num+'"/>\

\
            \

\
            Credits:\
            <input class="form-control input-sm" name="cred" id="editedCourseCred" value="'+course.credits+'"/>\

\
            \
            </form>';
            $(this).html(markup);
          },
          close: function() {
            $(this).dialog('destroy').remove()
          },
          buttons: {
              Cancel: {
                text:"Cancel",
                click: function () {
                  $(this).dialog('destroy').remove()
                }
              },
              Delete: function() {
                scope.$apply(scope.deleteCourse(course));
                $(this).dialog('destroy').remove()
              },
              Save: function() {
                //update model
                course.subj = $(editedCourseSubject).val();
                course.name = $(editedCourseName).val();
                course.num = $(editedCourseNum).val();
                course.credits = $(editedCourseCred).val();
                scope.$apply();
                $(this).dialog('destroy').remove()
              }
          }
        });
      });
    }
  };
});
<commit_msg>fixing lack of prompt on semester delete<commit_after>var app = angular.module("CoursePlanner", ['ui.sortable']);

app.controller('courseCtrl', ['$scope','$http', function($scope,$http) {
  $scope.years = [];

  //Display help if no years
  $scope.$watch(
    //Watch if the years is empty
    function(scope) {
      return scope.years.length > 0
    },
    //hide div when view is empty
    function(newValue, oldValue) {
      if(newValue) {
        $('#empty-view').hide();
      } else {
        $('#empty-view').show();
      }
    }
  );

  $scope.maxSemesters=4;

  $scope.sortableOptionsCourse = {
    //'placeholder': 'course',
    'connectWith': '.connectedSortable'
  };

  $scope.errormsg = "";
  $scope.setErrorMsg = function(text) {
    $scope.errormsg = text;
  }

  $scope.save = function() {
    var data = JSON.stringify($scope.years);
    var url = 'data:text/json;charset=utf8,' + encodeURIComponent(data);
    window.open(url, '_blank');
    window.focus();
  }

  $scope.load = function() {
    var text = prompt("paste json file here");
    if(text != null) {
      try {
        var data = JSON.parse(text);
        $scope.years = data;
	  } catch(e) {
        $scope.setErrorMsg('invalid json file');
      }
      //$scope.$apply();
	}
  }

  $scope.open = function(dept) {
    path = "files/" + dept + "_default.json";
    $http.get(path).success(function(data){
      $scope.years = data;
    }).error(function(data) {
      $scope.setErrorMsg('Invalid Selection');
    });
  }

  $scope.addYear = function() {
    $scope.years.push(new function() {
      this.title="NEW YEAR";
      this.semesters=[];
    });
	$scope.$apply();
  }

  $scope.removeYear = function(index) {
    if($scope.years[index].semesters.length > 0) {
      if(confirm("Delete year \"" + $scope.years[index].title + "\" ?")){
        $scope.years.splice(index,1);
      }
    } else {
      $scope.years.splice(index,1);
    }
  }

  $scope.removeSemester = function(year,index) {
    if(year.semesters[index].classes.length > 0) {
      if(confirm("Delete semester \"" + index+1 + "\" ?")){
        year.semesters.splice(index,1);
      }
    } else {
      year.semesters.splice(index,1);
    }
  }

  $scope.addSemester = function(year) {
    if(year.semesters.length < $scope.maxSemesters) {
      year.semesters.push(new function() {
        this.classes=[];
      });
    }
  }

  $scope.addCourse = function(semester) {
    semester.classes.push(new function() {
      this.name="A New Course";
      this.subj="SUBJ";
      this.num="000";
      this.credits=0;
    });
  }

  $scope.deleteCourse = function(course) {
    $scope.years.forEach(function(year) {
      year.semesters.forEach(function(semester) {
        for(i = 0; i < semester.classes.length; ++i) {
          if(semester.classes[i] == course) {
            semester.classes.splice(i,1);
          }
        }
      });
    });
  }
}]);

app.directive('contenteditable',function() {
  return {
    restrict: "A",
    require: "ngModel",
    link: function(scope, element, attrs, ngModel) {

      function read() {
        ngModel.$setViewValue(element.html());
      }

      ngModel.$render = function() {
        element.html(ngModel.$viewValue || "");
      };

      element.bind("blur keyup change", function() {
        scope.$apply(read);
      });
    }
  };
});

app.directive('course', function() {
  return {
    restrict:'AE',
    require:"?ngModel",
    link: function(scope,element,attrs,ngModel) {
      element.on('dblclick',function() {
        var course = ngModel.$modelValue;
        var newPopup;
        newPopup = "

";
        $(newPopup).dialog({
          modal: true,
          width:350,
          resizable:false,
          title: "Edit Course",
          open: function () {
            var markup =
            '<form role="form">\
            \

\
            Name:\
            <input class="form-control input-sm" name="name" id="editedCourseName" value="'+course.name+'" />\

\
            \

\
            Subject:\
            <input class="form-control input-sm" name="subj" id="editedCourseSubject" value="'+course.subj+'"/>\

\
            \

\
            Number:\
            <input class="form-control input-sm" name="num" id="editedCourseNum" value="'+course.num+'"/>\

\
            \

\
            Credits:\
            <input class="form-control input-sm" name="cred" id="editedCourseCred" value="'+course.credits+'"/>\

\
            \
            </form>';
            $(this).html(markup);
          },
          close: function() {
            $(this).dialog('destroy').remove()
          },
          buttons: {
              Cancel: {
                text:"Cancel",
                click: function () {
                  $(this).dialog('destroy').remove()
                }
              },
              Delete: function() {
                scope.$apply(scope.deleteCourse(course));
                $(this).dialog('destroy').remove()
              },
              Save: function() {
                //update model
                course.subj = $(editedCourseSubject).val();
                course.name = $(editedCourseName).val();
                course.num = $(editedCourseNum).val();
                course.credits = $(editedCourseCred).val();
                scope.$apply();
                $(this).dialog('destroy').remove()
              }
          }
        });
      });
    }
  };
});
<|endoftext|>


<commit_before>/*
 * L.Draggable allows you to add dragging capabilities to any element. Supports mobile devices too.
 */

L.Draggable = L.Class.extend({
	includes: L.Mixin.Events,

	statics: {
		START: L.Browser.touch ? ['touchstart', 'mousedown'] : ['mousedown'],
		END: {
			mousedown: 'mouseup',
			touchstart: 'touchend',
			MSPointerDown: 'touchend'
		},
		MOVE: {
			mousedown: 'mousemove',
			touchstart: 'touchmove',
			MSPointerDown: 'touchmove'
		},
		TAP_TOLERANCE: 15
	},

	initialize: function (element, dragStartTarget, longPress) {
		this._element = element;
		this._dragStartTarget = dragStartTarget || element;
		this._longPress = longPress && !L.Browser.msTouch;
	},

	enable: function () {
		if (this._enabled) { return; }

		for (var i = L.Draggable.START.length - 1; i >= 0; i--) {
			L.DomEvent.on(this._dragStartTarget, L.Draggable.START[i], this._onDown, this);
		}
		this._enabled = true;
	},

	disable: function () {
		if (!this._enabled) { return; }

		for (var i = L.Draggable.START.length - 1; i >= 0; i--) {
			L.DomEvent.off(this._dragStartTarget, L.Draggable.START[i], this._onDown, this);
		}
		this._enabled = false;
		this._moved = false;
	},

	_onDown: function (e) {
		if ((!L.Browser.touch && e.shiftKey) ||
		    ((e.which !== 1) && (e.button !== 1) && !e.touches)) { return; }

		L.DomEvent.preventDefault(e);
		L.DomEvent.stopPropagation(e);

		if (L.Draggable._disabled) { return; }

		this._simulateClick = true;

		if (e.touches && e.touches.length > 1) {
			this._simulateClick = false;
			clearTimeout(this._longPressTimeout);
			return;
		}

		var first = (e.touches && e.touches.length === 1 ? e.touches[0] : e),
		    el = first.target;

		if (L.Browser.touch && el.tagName.toLowerCase() === 'a') {
			L.DomUtil.addClass(el, 'leaflet-active');
		}

		this._moved = false;
		if (this._moving) { return; }

		this._startPoint = new L.Point(first.clientX, first.clientY);
		this._startPos = this._newPos = L.DomUtil.getPosition(this._element);

		//Touch contextmenu event emulation
		if (e.touches && e.touches.length === 1 && L.Browser.touch && this._longPress) {
			this._longPressTimeout = setTimeout(L.bind(function () {
				var dist = (this._newPos && this._newPos.distanceTo(this._startPos)) || 0;

				if (dist < L.Draggable.TAP_TOLERANCE) {
					this._simulateClick = false;
					this._onUp();
					this._simulateEvent('contextmenu', first);
				}
			}, this), 1000);
		}

		L.DomEvent.on(document, L.Draggable.MOVE[e.type], this._onMove, this);
		L.DomEvent.on(document, L.Draggable.END[e.type], this._onUp, this);
	},

	_onMove: function (e) {
		if (e.touches && e.touches.length > 1) { return; }

		var first = (e.touches && e.touches.length === 1 ? e.touches[0] : e),
		    newPoint = new L.Point(first.clientX, first.clientY),
		    diffVec = newPoint.subtract(this._startPoint);

		if (!diffVec.x && !diffVec.y) { return; }

		L.DomEvent.preventDefault(e);

		if (!this._moved) {
			this.fire('dragstart');
			this._moved = true;

			this._startPos = L.DomUtil.getPosition(this._element).subtract(diffVec);

			if (!L.Browser.touch) {
				L.DomUtil.disableTextSelection();
				this._setMovingCursor();
			}
		}

		this._newPos = this._startPos.add(diffVec);
		this._moving = true;

		L.Util.cancelAnimFrame(this._animRequest);
		this._animRequest = L.Util.requestAnimFrame(this._updatePosition, this, true, this._dragStartTarget);
	},

	_updatePosition: function () {
		this.fire('predrag');
		L.DomUtil.setPosition(this._element, this._newPos);
		this.fire('drag');
	},

	_onUp: function (e) {
		var simulateClickTouch;
		clearTimeout(this._longPressTimeout);
		if (this._simulateClick && e.changedTouches) {
			var first = e.changedTouches[0],
			    el = first.target,
			    dist = (this._newPos && this._newPos.distanceTo(this._startPos)) || 0;

			if (el.tagName.toLowerCase() === 'a') {
				L.DomUtil.removeClass(el, 'leaflet-active');
			}

			if (dist < L.Draggable.TAP_TOLERANCE) {
				simulateClickTouch = first;
			}
		}

		if (!L.Browser.touch) {
			L.DomUtil.enableTextSelection();
			this._restoreCursor();
		}

		for (var i in L.Draggable.MOVE) {
			if (L.Draggable.MOVE.hasOwnProperty(i)) {
				L.DomEvent.off(document, L.Draggable.MOVE[i], this._onMove);
				L.DomEvent.off(document, L.Draggable.END[i], this._onUp);
			}
		}

		if (this._moved) {
			// ensure drag is not fired after dragend
			L.Util.cancelAnimFrame(this._animRequest);

			this.fire('dragend');
		}
		this._moving = false;

		if (simulateClickTouch) {
			this._moved = false;
			this._simulateEvent('click', simulateClickTouch);
		}
	},

	_setMovingCursor: function () {
		L.DomUtil.addClass(document.body, 'leaflet-dragging');
	},

	_restoreCursor: function () {
		L.DomUtil.removeClass(document.body, 'leaflet-dragging');
	},

	_simulateEvent: function (type, e) {
		var simulatedEvent = document.createEvent('MouseEvents');

		simulatedEvent.initMouseEvent(
		        type, true, true, window, 1,
		        e.screenX, e.screenY,
		        e.clientX, e.clientY,
		        false, false, false, false, 0, null);

		e.target.dispatchEvent(simulatedEvent);
	}
});
<commit_msg>Fixes box-zooming in Firefox 18+<commit_after>/*
 * L.Draggable allows you to add dragging capabilities to any element. Supports mobile devices too.
 */

L.Draggable = L.Class.extend({
	includes: L.Mixin.Events,

	statics: {
		START: L.Browser.touch ? ['touchstart', 'mousedown'] : ['mousedown'],
		END: {
			mousedown: 'mouseup',
			touchstart: 'touchend',
			MSPointerDown: 'touchend'
		},
		MOVE: {
			mousedown: 'mousemove',
			touchstart: 'touchmove',
			MSPointerDown: 'touchmove'
		},
		TAP_TOLERANCE: 15
	},

	initialize: function (element, dragStartTarget, longPress) {
		this._element = element;
		this._dragStartTarget = dragStartTarget || element;
		this._longPress = longPress && !L.Browser.msTouch;
	},

	enable: function () {
		if (this._enabled) { return; }

		for (var i = L.Draggable.START.length - 1; i >= 0; i--) {
			L.DomEvent.on(this._dragStartTarget, L.Draggable.START[i], this._onDown, this);
		}
		this._enabled = true;
	},

	disable: function () {
		if (!this._enabled) { return; }

		for (var i = L.Draggable.START.length - 1; i >= 0; i--) {
			L.DomEvent.off(this._dragStartTarget, L.Draggable.START[i], this._onDown, this);
		}
		this._enabled = false;
		this._moved = false;
	},

	_onDown: function (e) {
		if (e.shiftKey ||
		    ((e.which !== 1) && (e.button !== 1) && !e.touches)) { return; }

		L.DomEvent.preventDefault(e);
		L.DomEvent.stopPropagation(e);

		if (L.Draggable._disabled) { return; }

		this._simulateClick = true;

		if (e.touches && e.touches.length > 1) {
			this._simulateClick = false;
			clearTimeout(this._longPressTimeout);
			return;
		}

		var first = (e.touches && e.touches.length === 1 ? e.touches[0] : e),
		    el = first.target;

		if (L.Browser.touch && el.tagName.toLowerCase() === 'a') {
			L.DomUtil.addClass(el, 'leaflet-active');
		}

		this._moved = false;
		if (this._moving) { return; }

		this._startPoint = new L.Point(first.clientX, first.clientY);
		this._startPos = this._newPos = L.DomUtil.getPosition(this._element);

		//Touch contextmenu event emulation
		if (e.touches && e.touches.length === 1 && L.Browser.touch && this._longPress) {
			this._longPressTimeout = setTimeout(L.bind(function () {
				var dist = (this._newPos && this._newPos.distanceTo(this._startPos)) || 0;

				if (dist < L.Draggable.TAP_TOLERANCE) {
					this._simulateClick = false;
					this._onUp();
					this._simulateEvent('contextmenu', first);
				}
			}, this), 1000);
		}

		L.DomEvent.on(document, L.Draggable.MOVE[e.type], this._onMove, this);
		L.DomEvent.on(document, L.Draggable.END[e.type], this._onUp, this);
	},

	_onMove: function (e) {
		if (e.touches && e.touches.length > 1) { return; }

		var first = (e.touches && e.touches.length === 1 ? e.touches[0] : e),
		    newPoint = new L.Point(first.clientX, first.clientY),
		    diffVec = newPoint.subtract(this._startPoint);

		if (!diffVec.x && !diffVec.y) { return; }

		L.DomEvent.preventDefault(e);

		if (!this._moved) {
			this.fire('dragstart');
			this._moved = true;

			this._startPos = L.DomUtil.getPosition(this._element).subtract(diffVec);

			if (!L.Browser.touch) {
				L.DomUtil.disableTextSelection();
				this._setMovingCursor();
			}
		}

		this._newPos = this._startPos.add(diffVec);
		this._moving = true;

		L.Util.cancelAnimFrame(this._animRequest);
		this._animRequest = L.Util.requestAnimFrame(this._updatePosition, this, true, this._dragStartTarget);
	},

	_updatePosition: function () {
		this.fire('predrag');
		L.DomUtil.setPosition(this._element, this._newPos);
		this.fire('drag');
	},

	_onUp: function (e) {
		var simulateClickTouch;
		clearTimeout(this._longPressTimeout);
		if (this._simulateClick && e.changedTouches) {
			var first = e.changedTouches[0],
			    el = first.target,
			    dist = (this._newPos && this._newPos.distanceTo(this._startPos)) || 0;

			if (el.tagName.toLowerCase() === 'a') {
				L.DomUtil.removeClass(el, 'leaflet-active');
			}

			if (dist < L.Draggable.TAP_TOLERANCE) {
				simulateClickTouch = first;
			}
		}

		if (!L.Browser.touch) {
			L.DomUtil.enableTextSelection();
			this._restoreCursor();
		}

		for (var i in L.Draggable.MOVE) {
			if (L.Draggable.MOVE.hasOwnProperty(i)) {
				L.DomEvent.off(document, L.Draggable.MOVE[i], this._onMove);
				L.DomEvent.off(document, L.Draggable.END[i], this._onUp);
			}
		}

		if (this._moved) {
			// ensure drag is not fired after dragend
			L.Util.cancelAnimFrame(this._animRequest);

			this.fire('dragend');
		}
		this._moving = false;

		if (simulateClickTouch) {
			this._moved = false;
			this._simulateEvent('click', simulateClickTouch);
		}
	},

	_setMovingCursor: function () {
		L.DomUtil.addClass(document.body, 'leaflet-dragging');
	},

	_restoreCursor: function () {
		L.DomUtil.removeClass(document.body, 'leaflet-dragging');
	},

	_simulateEvent: function (type, e) {
		var simulatedEvent = document.createEvent('MouseEvents');

		simulatedEvent.initMouseEvent(
		        type, true, true, window, 1,
		        e.screenX, e.screenY,
		        e.clientX, e.clientY,
		        false, false, false, false, 0, null);

		e.target.dispatchEvent(simulatedEvent);
	}
});
<|endoftext|>


<commit_before>'use strict';

const debug = require('debug');

const NAMESPACE = 'signaling';

class Logger {
    constructor(prefix) {
        if (prefix) {
            this._debug = debug(NAMESPACE + ':' + prefix);
            this._log = debug(NAMESPACE + ':INFO:' + prefix);
            this._warn = debug(NAMESPACE + ':WARN:' + prefix);
            this._error = debug(NAMESPACE + ':ERROR:' + prefix);
        } else {
            this._debug = debug(NAMESPACE);
            this._log = debug(NAMESPACE + ':INFO');
            this._warn = debug(NAMESPACE + ':WARN');
            this._error = debug(NAMESPACE + ':ERROR');
        }

        this._debug.log = console.info.bind(console);
        this._log.log = console.info.bind(console);
        this._warn.log = console.warn.bind(console);
        this._error.log = console.error.bind(console);
    }

    get debug() {
        return this._debug;
    }

    get log() {
        return this._log;
    }

    get info() {
        return this._log;
    }

    get warn() {
        return this._warn;
    }

    get error() {
        return this._error;
    }
}

module.exports = function (prefix) {
    return new Logger(prefix);
};<commit_msg>change default logger namespace<commit_after>'use strict';

const debug = require('debug');

const NAMESPACE = 'roomrtc';

class Logger {
    constructor(prefix) {
        if (prefix) {
            this._debug = debug(NAMESPACE + ':' + prefix);
            this._log = debug(NAMESPACE + ':INFO:' + prefix);
            this._warn = debug(NAMESPACE + ':WARN:' + prefix);
            this._error = debug(NAMESPACE + ':ERROR:' + prefix);
        } else {
            this._debug = debug(NAMESPACE);
            this._log = debug(NAMESPACE + ':INFO');
            this._warn = debug(NAMESPACE + ':WARN');
            this._error = debug(NAMESPACE + ':ERROR');
        }

        this._debug.log = console.info.bind(console);
        this._log.log = console.info.bind(console);
        this._warn.log = console.warn.bind(console);
        this._error.log = console.error.bind(console);
    }

    get debug() {
        return this._debug;
    }

    get log() {
        return this._log;
    }

    get info() {
        return this._log;
    }

    get warn() {
        return this._warn;
    }

    get error() {
        return this._error;
    }
}

module.exports = function (prefix) {
    return new Logger(prefix);
};<|endoftext|>


<commit_before>var Code = require('code'),
  Lab = require('lab'),
  lab = exports.lab = Lab.script(),
  describe = lab.experiment,
  before = lab.before,
  after = lab.after,
  beforeEach = lab.beforeEach,
  afterEach = lab.afterEach,
  it = lab.test,
  expect = Code.expect,
  fixtures = require('../fixtures'),
  nock = require('nock');

var server;
var username1 = 'bob';

var userMock, licenseMock;

userMock = nock("https://user-api-example.com")
  .get('/user/bob').times(8)
  .reply(200, fixtures.users.bob)
  .get('/user/seldo').times(3)
  .reply(200, fixtures.users.npmEmployee)
  .get('/user/constructor')
  .reply(200, fixtures.users.propName)
  .get('/user/bob/package?format=mini&per_page=100&page=0').times(10)
  .reply(200, fixtures.users.packages)
  .get('/user/bob/stars?format=detailed').times(10)
  .reply(200, fixtures.users.stars)
  .get('/user/bob').times(5)
  .reply(404)
  .get('/user/seldo')
  .reply(404)
  .get('/user/mikeal')
  .reply(404)
  .get('/user/bob/org').times(2)
  .reply(401)
  .get('/package?sort=modified&count=12')
  .reply(200, fixtures.aggregates.recently_updated_packages)
  .get('/package?sort=dependents&count=12')
  .reply(200, fixtures.aggregates.most_depended_upon_packages);

licenseMock = nock('https://license-api-example.com')
  .get('/customer/bob/stripe').times(13)
  .reply(200, {})
  .get('/customer/mikeal/stripe')
  .reply(200, {})
  .get('/customer/seldo/stripe').times(4)
  .reply(200, {});

before(function(done) {
  require('../mocks/server')(function(obj) {
    server = obj;
    done();
  });
});

after(function(done) {
  userMock.done();
  licenseMock.done();
  done();
});

describe("bonbon", function() {

  beforeEach(function(done) {
    process.env.NODE_ENV = 'production';
    done();
  });

  afterEach(function(done) {
    delete process.env.NODE_ENV;
    done();
  });

  describe("feature flags", function() {

    beforeEach(function(done) {
      process.env.FEATURE_STEALTH = 'false';
      process.env.FEATURE_ALPHA = 'group:npm-humans';
      process.env.FEATURE_BETA = 'group:npm-humans,group:friends,bob';
      process.env.FEATURE_COMMON = 'true';
      done();
    });

    afterEach(function(done) {
      delete process.env.FEATURE_STEALTH;
      delete process.env.FEATURE_ALPHA;
      delete process.env.FEATURE_BETA;
      delete process.env.FEATURE_COMMON;
      done();
    });

    it('gives anonymous users access to common features', function(done) {
      var options = {
        url: '/~bob'
      };

      server.inject(options, function(resp) {
        var context = resp.request.response.source.context;
        expect(context.features).to.deep.equal({
          stealth: false,
          alpha: false,
          beta: false,
          common: true
        });
        done();
      });
    });

    it('gives people in the friends group access to beta and common features', function(done) {
      var options = {
        url: '/~bob',
        credentials: fixtures.users.mikeal
      };

      server.inject(options, function(resp) {
        var context = resp.request.response.source.context;
        expect(context.features).to.deep.equal({
          stealth: false,
          alpha: false,
          beta: true,
          common: true
        });
        done();
      });
    });

    it('gives one-off listed friends access to beta and common features', function(done) {
      var options = {
        url: '/~bob',
        credentials: fixtures.users.bob
      };

      server.inject(options, function(resp) {
        var context = resp.request.response.source.context;
        expect(context.features).to.deep.equal({
          stealth: false,
          alpha: false,
          beta: true,
          common: true
        });
        done();
      });
    });

    it('gives npm employees access to alpha, beta, and common features', function(done) {
      var options = {
        url: '/~bob',
        credentials: fixtures.users.npmEmployee
      };

      server.inject(options, function(resp) {
        var context = resp.request.response.source.context;
        expect(context.features).to.deep.equal({
          stealth: false,
          alpha: true,
          beta: true,
          common: true
        });
        done();
      });
    });

  });

  it('allows logged-in npm employees to request the view context with a `json` query param', function(done) {

    var options = {
      url: '/~' + username1 + '?json',
      credentials: fixtures.users.npmEmployee
    };

    expect(process.env.NODE_ENV).to.equal("production");
    server.inject(options, function(resp) {
      expect(resp.statusCode).to.equal(200);
      expect(resp.headers['content-type']).to.match(/json/);
      expect(resp.result).to.be.an.object();
      done();
    });
  });

  it('returns the whole context object if `json` has no value', function(done) {

    var options = {
      url: '/~' + username1 + '?json',
      credentials: fixtures.users.npmEmployee
    };

    expect(process.env.NODE_ENV).to.equal("production");
    server.inject(options, function(resp) {
      expect(resp.statusCode).to.equal(200);
      expect(resp.result.profile).to.exist();
      expect(resp.result.profile.name).to.exist();
      done();
    });
  });

  it('returns a subset of the context if `json` has a value', function(done) {

    var options = {
      url: '/~' + username1 + '?json=profile.resource',
      credentials: fixtures.users.npmEmployee
    };
    expect(process.env.NODE_ENV).to.equal("production");
    server.inject(options, function(resp) {
      expect(resp.statusCode).to.equal(200);
      expect(resp.headers['content-type']).to.match(/json/);
      expect(resp.result.github).to.exist();
      expect(resp.result.twitter).to.exist();
      done();
    });
  });

  it('does not allow logged-in non-employees to request the view context', function(done) {

    var options = {
      url: '/~' + username1 + '?json',
      credentials: fixtures.users.bob
    };
    expect(process.env.NODE_ENV).to.equal("production");
    server.inject(options, function(resp) {
      expect(resp.statusCode).to.equal(200);
      expect(resp.headers['content-type']).to.match(/html/);
      var source = resp.request.response.source;
      expect(source.template).to.equal('user/profile');
      done();
    });
  });

  it('does not allow logged-in non-employees with obj prop names to request the view context', function(done) {

    var options = {
      url: '/~' + username1 + '?json',
      credentials: fixtures.users.propName
    };

    expect(process.env.NODE_ENV).to.equal("production");
    server.inject(options, function(resp) {
      expect(resp.statusCode).to.equal(200);
      expect(resp.headers['content-type']).to.match(/html/);
      expect(resp.result).to.be.a.string();
      done();
    });
  });

  it('does not allow anonymous fixtures.users to request the view context', function(done) {

    var options = {
      url: '/~' + username1 + '?json',
      credentials: fixtures.users.bob
    };
    expect(process.env.NODE_ENV).to.equal("production");
    server.inject(options, function(resp) {
      expect(resp.statusCode).to.equal(200);
      expect(resp.headers['content-type']).to.match(/html/);
      var source = resp.request.response.source;
      expect(source.template).to.equal('user/profile');
      done();
    });
  });

  it('allows anyone to request the view context if NODE_ENV is `dev`', function(done) {
    process.env.NODE_ENV = "dev";
    expect(process.env.NODE_ENV).to.equal("dev");

    var options = {
      url: '/~' + username1 + '?json',
      credentials: null
    };
    server.inject(options, function(resp) {
      expect(resp.statusCode).to.equal(200);
      expect(resp.headers['content-type']).to.match(/json/);
      expect(resp.result).to.be.an.object();
      delete process.env.NODE_ENV;
      done();
    });
  });

  describe('headers', function() {
    it('includes the charset=utf-8 header', function(done) {
      server.inject('/', function(resp) {
        expect(resp.headers['content-type']).to.equal('text/html; charset=utf-8');
        done();
      });
    });
  });

});
<commit_msg>Mock redis in bonbon test<commit_after>var Code = require('code'),
  Lab = require('lab'),
  lab = exports.lab = Lab.script(),
  describe = lab.experiment,
  before = lab.before,
  after = lab.after,
  beforeEach = lab.beforeEach,
  afterEach = lab.afterEach,
  it = lab.test,
  expect = Code.expect,
  fixtures = require('../fixtures'),
  nock = require('nock');
var requireInject = require('require-inject');
var redisMock = require('redis-mock');

var server;
var username1 = 'bob';

var userMock, licenseMock;

userMock = nock("https://user-api-example.com")
  .get('/user/bob').times(8)
  .reply(200, fixtures.users.bob)
  .get('/user/seldo').times(3)
  .reply(200, fixtures.users.npmEmployee)
  .get('/user/constructor')
  .reply(200, fixtures.users.propName)
  .get('/user/bob/package?format=mini&per_page=100&page=0').times(10)
  .reply(200, fixtures.users.packages)
  .get('/user/bob/stars?format=detailed').times(10)
  .reply(200, fixtures.users.stars)
  .get('/user/bob').times(5)
  .reply(404)
  .get('/user/seldo')
  .reply(404)
  .get('/user/mikeal')
  .reply(404)
  .get('/user/bob/org').times(2)
  .reply(401)
  .get('/package?sort=modified&count=12')
  .reply(200, fixtures.aggregates.recently_updated_packages)
  .get('/package?sort=dependents&count=12')
  .reply(200, fixtures.aggregates.most_depended_upon_packages);

licenseMock = nock('https://license-api-example.com')
  .get('/customer/bob/stripe').times(13)
  .reply(200, {})
  .get('/customer/mikeal/stripe')
  .reply(200, {})
  .get('/customer/seldo/stripe').times(4)
  .reply(200, {});

before(function(done) {
  requireInject.installGlobally('../mocks/server', {
    redis: redisMock
  })(function(obj) {
    server = obj;
    done();
  });
});

after(function(done) {
  userMock.done();
  licenseMock.done();
  done();
});

describe("bonbon", function() {

  beforeEach(function(done) {
    process.env.NODE_ENV = 'production';
    done();
  });

  afterEach(function(done) {
    delete process.env.NODE_ENV;
    done();
  });

  describe("feature flags", function() {

    beforeEach(function(done) {
      process.env.FEATURE_STEALTH = 'false';
      process.env.FEATURE_ALPHA = 'group:npm-humans';
      process.env.FEATURE_BETA = 'group:npm-humans,group:friends,bob';
      process.env.FEATURE_COMMON = 'true';
      done();
    });

    afterEach(function(done) {
      delete process.env.FEATURE_STEALTH;
      delete process.env.FEATURE_ALPHA;
      delete process.env.FEATURE_BETA;
      delete process.env.FEATURE_COMMON;
      done();
    });

    it('gives anonymous users access to common features', function(done) {
      var options = {
        url: '/~bob'
      };

      server.inject(options, function(resp) {
        var context = resp.request.response.source.context;
        expect(context.features).to.deep.equal({
          stealth: false,
          alpha: false,
          beta: false,
          common: true
        });
        done();
      });
    });

    it('gives people in the friends group access to beta and common features', function(done) {
      var options = {
        url: '/~bob',
        credentials: fixtures.users.mikeal
      };

      server.inject(options, function(resp) {
        var context = resp.request.response.source.context;
        expect(context.features).to.deep.equal({
          stealth: false,
          alpha: false,
          beta: true,
          common: true
        });
        done();
      });
    });

    it('gives one-off listed friends access to beta and common features', function(done) {
      var options = {
        url: '/~bob',
        credentials: fixtures.users.bob
      };

      server.inject(options, function(resp) {
        var context = resp.request.response.source.context;
        expect(context.features).to.deep.equal({
          stealth: false,
          alpha: false,
          beta: true,
          common: true
        });
        done();
      });
    });

    it('gives npm employees access to alpha, beta, and common features', function(done) {
      var options = {
        url: '/~bob',
        credentials: fixtures.users.npmEmployee
      };

      server.inject(options, function(resp) {
        var context = resp.request.response.source.context;
        expect(context.features).to.deep.equal({
          stealth: false,
          alpha: true,
          beta: true,
          common: true
        });
        done();
      });
    });

  });

  it('allows logged-in npm employees to request the view context with a `json` query param', function(done) {

    var options = {
      url: '/~' + username1 + '?json',
      credentials: fixtures.users.npmEmployee
    };

    expect(process.env.NODE_ENV).to.equal("production");
    server.inject(options, function(resp) {
      expect(resp.statusCode).to.equal(200);
      expect(resp.headers['content-type']).to.match(/json/);
      expect(resp.result).to.be.an.object();
      done();
    });
  });

  it('returns the whole context object if `json` has no value', function(done) {

    var options = {
      url: '/~' + username1 + '?json',
      credentials: fixtures.users.npmEmployee
    };

    expect(process.env.NODE_ENV).to.equal("production");
    server.inject(options, function(resp) {
      expect(resp.statusCode).to.equal(200);
      expect(resp.result.profile).to.exist();
      expect(resp.result.profile.name).to.exist();
      done();
    });
  });

  it('returns a subset of the context if `json` has a value', function(done) {

    var options = {
      url: '/~' + username1 + '?json=profile.resource',
      credentials: fixtures.users.npmEmployee
    };
    expect(process.env.NODE_ENV).to.equal("production");
    server.inject(options, function(resp) {
      expect(resp.statusCode).to.equal(200);
      expect(resp.headers['content-type']).to.match(/json/);
      expect(resp.result.github).to.exist();
      expect(resp.result.twitter).to.exist();
      done();
    });
  });

  it('does not allow logged-in non-employees to request the view context', function(done) {

    var options = {
      url: '/~' + username1 + '?json',
      credentials: fixtures.users.bob
    };
    expect(process.env.NODE_ENV).to.equal("production");
    server.inject(options, function(resp) {
      expect(resp.statusCode).to.equal(200);
      expect(resp.headers['content-type']).to.match(/html/);
      var source = resp.request.response.source;
      expect(source.template).to.equal('user/profile');
      done();
    });
  });

  it('does not allow logged-in non-employees with obj prop names to request the view context', function(done) {

    var options = {
      url: '/~' + username1 + '?json',
      credentials: fixtures.users.propName
    };

    expect(process.env.NODE_ENV).to.equal("production");
    server.inject(options, function(resp) {
      expect(resp.statusCode).to.equal(200);
      expect(resp.headers['content-type']).to.match(/html/);
      expect(resp.result).to.be.a.string();
      done();
    });
  });

  it('does not allow anonymous fixtures.users to request the view context', function(done) {

    var options = {
      url: '/~' + username1 + '?json',
      credentials: fixtures.users.bob
    };
    expect(process.env.NODE_ENV).to.equal("production");
    server.inject(options, function(resp) {
      expect(resp.statusCode).to.equal(200);
      expect(resp.headers['content-type']).to.match(/html/);
      var source = resp.request.response.source;
      expect(source.template).to.equal('user/profile');
      done();
    });
  });

  it('allows anyone to request the view context if NODE_ENV is `dev`', function(done) {
    process.env.NODE_ENV = "dev";
    expect(process.env.NODE_ENV).to.equal("dev");

    var options = {
      url: '/~' + username1 + '?json',
      credentials: null
    };
    server.inject(options, function(resp) {
      expect(resp.statusCode).to.equal(200);
      expect(resp.headers['content-type']).to.match(/json/);
      expect(resp.result).to.be.an.object();
      delete process.env.NODE_ENV;
      done();
    });
  });

  describe('headers', function() {
    it('includes the charset=utf-8 header', function(done) {
      server.inject('/', function(resp) {
        expect(resp.headers['content-type']).to.equal('text/html; charset=utf-8');
        done();
      });
    });
  });

});
<|endoftext|>


<commit_before>import Dropzone from 'dropzone';
import React from 'react';

export default class Uploader extends React.Component {
    constructor(props) {
        super(props);
        // Disable auto discover for all elements
        Dropzone.autoDiscover = false;
    }

    componentDidMount() {
        this.dropzone = new Dropzone(this.view, {
            url      : this.props.uploadUrl,
            paramName: 'award',
            clickable: true,
            maxFiles : 1,

            thumbnailWidth : null,
            thumbnailHeight: null,

            // When set to false you have to call myDropzone.processQueue() yourself
            // in order to upload the dropped files. See below for more information on handling queues.
            autoProcessQueue: false,

            // Consume event to prevent Dropzone's default behavior
            addedfile: () => undefined,

            // An error occured. Receives the errorMessage as second parameter
            // and if the error was due to the XMLHttpRequest the xhr object as third.
            error: (file, error) => this.props.uploadDidFail(file, error),

            // The file has been uploaded successfully. Gets the server response as second argument.
            success: (file, response) => this.props.imageDidUpload(file, response),

            // When the thumbnail has been generated. Receives the dataUrl as second parameter.
            thumbnail: (file, dataUrl) => this.props.imageDidSelect(file, dataUrl),

            // Gets called periodically whenever the file upload progress changes.
            // Gets the progress parameter as second parameter which is a percentage (0-100) and the bytesSent parameter as third which is the number of the bytes that have been sent to the server.
            // When an upload finishes dropzone ensures that uploadprogress will be called with a percentage of 100 at least once.
            // Warning: This function can potentially be called with the same progress multiple times.
            uploadprogress: (file, progress, bytesSent) => {
                let transfer = this.props.dataDidTransfer;
                if (transfer !== undefined) {
                    transfer(file, progress, bytesSent);
                }
            }
        });

        this.props.uploadDidInit(this.createWrapper(this.dropzone));
    }

    componentWillUnmount() {
        if (this.dropzone !== null) {
            this.dropzone.destroy();
            this.dropzone = null;
        }
    }

    createWrapper(dropzone) {
        return {
            reset: () => {
                dropzone.removeAllFiles();
            },

            start: () => {
                dropzone.processQueue();
            }
        };
    }

    render() {
        return (

                 (this.view = view)}>

        );
    }

}

Uploader.propTypes = {
    dataDidTransfer: React.PropTypes.func,
    imageDidSelect : React.PropTypes.func.isRequired,
    imageDidUpload : React.PropTypes.func.isRequired,
    uploadDidFail  : React.PropTypes.func.isRequired,
    uploadDidInit  : React.PropTypes.func.isRequired,
    uploadUrl      : React.PropTypes.string.isRequired
};
<commit_msg>remove uploader display object<commit_after><|endoftext|>


<commit_before>var async = require("async");
var namedQueue = require("named-queue");
var qs = require("querystring");
var _ = require("lodash");
var needle = require("needle");
var Stremio = require("stremio-addons");

// Use cinemeta to pull names of movies and series against IMDB IDs
var stremio = new Stremio.Client();
stremio.add("http://cinemeta.strem.io/stremioget/stremio/v1");
//stremio.add("http://localhost:3005/stremioget/stremio/v1");

// Constants
var CACHE_TTL = 4*60*60*1000; // if we don't find an item, how long does it stay in the cache as "not found" before we retry it
var MAX_CACHE_SIZE = 20000;

var GOOGLE_AJAX_API = "http://ajax.googleapis.com/ajax/services/search/web?v=1.0&rsz=large&q=";
var GOOGLE_SEARCH = "https://www.google.com/search?safe=off&site=&source=hp&q=";

function assert(condition, log)
{
    if (!condition) console.log("name-retriever: "+log);
}

// Utility to reduce the name to it's most basic form
function simplifyName(n) {
    if (!n) return n;
    return n.toLowerCase()
        .trim()
        .replace(/\([^\(]+\)$/, "") // remove brackets at end
        .replace(/&/g, "and") // unify & vs "and"
        .replace(/[^0-9a-z ]+/g, " ") // remove any special characters
        .split(" ").filter(function(r){ return r }).join(" ") // remove any aditional whitespaces
};

// Index entry in our in-mem index
function indexEntry(entry) {
    if (entry.year) entry.year = parseInt(entry.year.toString().split("-")[0]); // first year for series
    var n = simplifyName(entry.name);
    if (!meta[n]) meta[n] = [];
    meta[n].push(entry);
    byImdb[entry.imdb_id] = entry;
}

// Find in our metadata set
var pulled = { movie: false, series: false };
var meta = { }, byImdb = { };
function metadataFind(query, cb) {
    // It's OK if we don't pass type and we don't fetch names, because
    if (query.type && !pulled[query.type]) stremio.call("names."+query.type, { }, function(err, res) {
        if (err) console.error(err);
        if (res) {
            res.forEach(indexEntry);
            pulled[query.type] = 1;
        }
        match();
    });
    else process.nextTick(match);

    function match() {
        var matches = meta[query.name] || [ ];
        var m = _.findWhere(matches, _.pick(query, "year", "type"));
        return cb(null, m && m.imdb_id);
    };
}

// Find in the web / Google
function webFind(task, cb) {
    var opts = {
        follow_max: 3,
        open_timeout: 15*1000,
        headers: { "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.86 Safari/537.36" }
    };

    if (task.hintUrl) return needle.get(task.hintUrl, opts, function(err, resp, body) {
        if (err) return cb(err);
        var match = body && body.match(new RegExp("\/title\/(tt[0-9]+)\/")); // Match IMDB Id from the whole body
        var id = match && match[1];
        cb(null, id, { match: task.hintUrl });
    });

    // WARNING: www. vs not?  is there difference?
    // no quotes - they can actually make the results dumber
    var query = "site:imdb.com "
        +task.name.toLowerCase()+(task.year ? " "+task.year : "")
        +((task.type=="series") ? " \"tv series\"" : ""); // Compute that now so that we can use the mapping

    // Google search api is deprecated, use this
    webFind({ hintUrl: GOOGLE_SEARCH+encodeURIComponent(query) }, cb);
}

// In-memory cache for matched items, to avoid flooding Google (or whatever search api we use)
var cache = { };

// Outside API
function nameToImdb(args, cb) {
    args = typeof(args)=="string" ? { name: args } : args;

    var q = _.pick(args, "name", "year", "type");
    q.name = simplifyName(q.name);

    if (! q.name) return cb(new Error("empty name"));

    if (q.year && typeof(q.year)=="string") q.year = parseInt(q.year.split("-")[0]);
    if (q.year && isNaN(q.year)) return cb(new Error("invalid year"));

    if (q.type && !(q.type=="movie" || q.type=="series")) return cb(null, null); // no match for other types

    var hash = new Buffer(args.hintUrl || _.values(q).join(":")).toString("ascii"); // convert to ASCII since EventEmitter bugs with UTF8
    if (cache.hasOwnProperty(hash)) return cb(null, cache[hash]);

    queue.push({ id: hash, q: q, args: args }, function(err, imdb_id, match) {
        if (err) return cb(err);
        if (imdb_id) {
            cache[hash] = imdb_id;
            setTimeout(function() { delete cache[hash] }, CACHE_TTL);
        }
        cb(null, imdb_id, match);
    });
};

var queue = new namedQueue(function(task, cb) {
    // Find it in our metadata, if not, fallback to Google
    metadataFind(task.q, function(err, id) {
        if (err) return cb(err);
        if (id || task.args.strict || task.args.noGoogle) return cb(null, id, { match: "metadata" }); // strict means don't search google
        webFind(task.args, cb);
    });
}, 3);

module.exports = nameToImdb;
module.exports.byImdb = byImdb;
<commit_msg>hintUrl: should not require slash at the end of the imdb link<commit_after>var async = require("async");
var namedQueue = require("named-queue");
var qs = require("querystring");
var _ = require("lodash");
var needle = require("needle");
var Stremio = require("stremio-addons");

// Use cinemeta to pull names of movies and series against IMDB IDs
var stremio = new Stremio.Client();
stremio.add("http://cinemeta.strem.io/stremioget/stremio/v1");
//stremio.add("http://localhost:3005/stremioget/stremio/v1");

// Constants
var CACHE_TTL = 4*60*60*1000; // if we don't find an item, how long does it stay in the cache as "not found" before we retry it
var MAX_CACHE_SIZE = 20000;

var GOOGLE_AJAX_API = "http://ajax.googleapis.com/ajax/services/search/web?v=1.0&rsz=large&q=";
var GOOGLE_SEARCH = "https://www.google.com/search?safe=off&site=&source=hp&q=";

function assert(condition, log)
{
    if (!condition) console.log("name-retriever: "+log);
}

// Utility to reduce the name to it's most basic form
function simplifyName(n) {
    if (!n) return n;
    return n.toLowerCase()
        .trim()
        .replace(/\([^\(]+\)$/, "") // remove brackets at end
        .replace(/&/g, "and") // unify & vs "and"
        .replace(/[^0-9a-z ]+/g, " ") // remove any special characters
        .split(" ").filter(function(r){ return r }).join(" ") // remove any aditional whitespaces
};

// Index entry in our in-mem index
function indexEntry(entry) {
    if (entry.year) entry.year = parseInt(entry.year.toString().split("-")[0]); // first year for series
    var n = simplifyName(entry.name);
    if (!meta[n]) meta[n] = [];
    meta[n].push(entry);
    byImdb[entry.imdb_id] = entry;
}

// Find in our metadata set
var pulled = { movie: false, series: false };
var meta = { }, byImdb = { };
function metadataFind(query, cb) {
    // It's OK if we don't pass type and we don't fetch names, because
    if (query.type && !pulled[query.type]) stremio.call("names."+query.type, { }, function(err, res) {
        if (err) console.error(err);
        if (res) {
            res.forEach(indexEntry);
            pulled[query.type] = 1;
        }
        match();
    });
    else process.nextTick(match);

    function match() {
        var matches = meta[query.name] || [ ];
        var m = _.findWhere(matches, _.pick(query, "year", "type"));
        return cb(null, m && m.imdb_id);
    };
}

// Find in the web / Google
function webFind(task, cb) {
    var opts = {
        follow_max: 3,
        open_timeout: 15*1000,
        headers: { "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.86 Safari/537.36" }
    };

    if (task.hintUrl) return needle.get(task.hintUrl, opts, function(err, resp, body) {
        if (err) return cb(err);
        var match = body && body.match(new RegExp("\/title\/(tt[0-9]+)")); // Match IMDB Id from the whole body
        var id = match && match[1];
        cb(null, id, { match: task.hintUrl });
    });

    // WARNING: www. vs not?  is there difference?
    // no quotes - they can actually make the results dumber
    var query = "site:imdb.com "
        +task.name.toLowerCase()+(task.year ? " "+task.year : "")
        +((task.type=="series") ? " \"tv series\"" : ""); // Compute that now so that we can use the mapping

    // Google search api is deprecated, use this
    webFind({ hintUrl: GOOGLE_SEARCH+encodeURIComponent(query) }, cb);
}

// In-memory cache for matched items, to avoid flooding Google (or whatever search api we use)
var cache = { };

// Outside API
function nameToImdb(args, cb) {
    args = typeof(args)=="string" ? { name: args } : args;

    var q = _.pick(args, "name", "year", "type");
    q.name = simplifyName(q.name);

    if (! q.name) return cb(new Error("empty name"));

    if (q.year && typeof(q.year)=="string") q.year = parseInt(q.year.split("-")[0]);
    if (q.year && isNaN(q.year)) return cb(new Error("invalid year"));

    if (q.type && !(q.type=="movie" || q.type=="series")) return cb(null, null); // no match for other types

    var hash = new Buffer(args.hintUrl || _.values(q).join(":")).toString("ascii"); // convert to ASCII since EventEmitter bugs with UTF8
    if (cache.hasOwnProperty(hash)) return cb(null, cache[hash]);

    queue.push({ id: hash, q: q, args: args }, function(err, imdb_id, match) {
        if (err) return cb(err);
        if (imdb_id) {
            cache[hash] = imdb_id;
            setTimeout(function() { delete cache[hash] }, CACHE_TTL);
        }
        cb(null, imdb_id, match);
    });
};

var queue = new namedQueue(function(task, cb) {
    // Find it in our metadata, if not, fallback to Google
    metadataFind(task.q, function(err, id) {
        if (err) return cb(err);
        if (id || task.args.strict || task.args.noGoogle) return cb(null, id, { match: "metadata" }); // strict means don't search google
        webFind(task.args, cb);
    });
}, 3);

module.exports = nameToImdb;
module.exports.byImdb = byImdb;
<|endoftext|>


<commit_before>/*
 * L.Draggable allows you to add dragging capabilities to any element. Supports mobile devices too.
 */

L.Draggable = L.Class.extend({
	includes: L.Mixin.Events,

	statics: {
		START: L.Browser.touch ? ['touchstart', 'mousedown'] : ['mousedown'],
		END: {
			mousedown: 'mouseup',
			touchstart: 'touchend',
			MSPointerDown: 'touchend'
		},
		MOVE: {
			mousedown: 'mousemove',
			touchstart: 'touchmove',
			MSPointerDown: 'touchmove'
		}
	},

	initialize: function (element, dragStartTarget) {
		this._element = element;
		this._dragStartTarget = dragStartTarget || element;
	},

	enable: function () {
		if (this._enabled) { return; }

		for (var i = L.Draggable.START.length - 1; i >= 0; i--) {
			L.DomEvent.on(this._dragStartTarget, L.Draggable.START[i], this._onDown, this);
		}

		this._enabled = true;
	},

	disable: function () {
		if (!this._enabled) { return; }

		for (var i = L.Draggable.START.length - 1; i >= 0; i--) {
			L.DomEvent.off(this._dragStartTarget, L.Draggable.START[i], this._onDown, this);
		}

		this._enabled = false;
		this._moved = false;
	},

	_onDown: function (e) {
		if (e.shiftKey || ((e.which !== 1) && (e.button !== 1) && !e.touches)) { return; }

		L.DomEvent
		    .stopPropagation(e);

		if (e.type === 'touchstart') {
			L.DomEvent.preventDefault(e);
		}

		if (L.Draggable._disabled) { return; }

		var first = e.touches ? e.touches[0] : e,
		    el = first.target;

		// if touching a link, highlight it
		if (L.Browser.touch && el.tagName.toLowerCase() === 'a') {
			L.DomUtil.addClass(el, 'leaflet-active');
		}

		this._moved = false;

		if (this._moving) { return; }

		this._startPoint = new L.Point(first.clientX, first.clientY);
		this._startPos = this._newPos = L.DomUtil.getPosition(this._element);

		L.DomEvent
		    .on(document, L.Draggable.MOVE[e.type], this._onMove, this)
		    .on(document, L.Draggable.END[e.type], this._onUp, this);
	},

	_onMove: function (e) {
		if (e.touches && e.touches.length > 1) { return; }

		var first = (e.touches && e.touches.length === 1 ? e.touches[0] : e),
		    newPoint = new L.Point(first.clientX, first.clientY),
		    offset = newPoint.subtract(this._startPoint);

		if (!offset.x && !offset.y) { return; }

		L.DomEvent.preventDefault(e);

		if (!this._moved) {
			this.fire('dragstart');

			this._moved = true;
			this._startPos = L.DomUtil.getPosition(this._element).subtract(offset);

			if (!L.Browser.touch) {
				L.DomUtil.disableTextSelection();
				L.DomUtil.addClass(document.body, 'leaflet-dragging');
			}
		}

		this._newPos = this._startPos.add(offset);
		this._moving = true;

		L.Util.cancelAnimFrame(this._animRequest);
		this._animRequest = L.Util.requestAnimFrame(this._updatePosition, this, true, this._dragStartTarget);
	},

	_updatePosition: function () {
		this.fire('predrag');
		L.DomUtil.setPosition(this._element, this._newPos);
		this.fire('drag');
	},

	_onUp: function () {
		if (!L.Browser.touch) {
			L.DomUtil.enableTextSelection();
			L.DomUtil.removeClass(document.body, 'leaflet-dragging');
		}

		for (var i in L.Draggable.MOVE) {
			L.DomEvent
			    .off(document, L.Draggable.MOVE[i], this._onMove)
			    .off(document, L.Draggable.END[i], this._onUp);
		}

		if (this._moved) {
			// ensure drag is not fired after dragend
			L.Util.cancelAnimFrame(this._animRequest);

			this.fire('dragend');
		}

		this._moving = false;
	}
});
<commit_msg>remove unnecessary preventDefault<commit_after>/*
 * L.Draggable allows you to add dragging capabilities to any element. Supports mobile devices too.
 */

L.Draggable = L.Class.extend({
	includes: L.Mixin.Events,

	statics: {
		START: L.Browser.touch ? ['touchstart', 'mousedown'] : ['mousedown'],
		END: {
			mousedown: 'mouseup',
			touchstart: 'touchend',
			MSPointerDown: 'touchend'
		},
		MOVE: {
			mousedown: 'mousemove',
			touchstart: 'touchmove',
			MSPointerDown: 'touchmove'
		}
	},

	initialize: function (element, dragStartTarget) {
		this._element = element;
		this._dragStartTarget = dragStartTarget || element;
	},

	enable: function () {
		if (this._enabled) { return; }

		for (var i = L.Draggable.START.length - 1; i >= 0; i--) {
			L.DomEvent.on(this._dragStartTarget, L.Draggable.START[i], this._onDown, this);
		}

		this._enabled = true;
	},

	disable: function () {
		if (!this._enabled) { return; }

		for (var i = L.Draggable.START.length - 1; i >= 0; i--) {
			L.DomEvent.off(this._dragStartTarget, L.Draggable.START[i], this._onDown, this);
		}

		this._enabled = false;
		this._moved = false;
	},

	_onDown: function (e) {
		if (e.shiftKey || ((e.which !== 1) && (e.button !== 1) && !e.touches)) { return; }

		L.DomEvent.stopPropagation(e);

		if (L.Draggable._disabled) { return; }

		var first = e.touches ? e.touches[0] : e,
		    el = first.target;

		// if touching a link, highlight it
		if (L.Browser.touch && el.tagName.toLowerCase() === 'a') {
			L.DomUtil.addClass(el, 'leaflet-active');
		}

		this._moved = false;

		if (this._moving) { return; }

		this._startPoint = new L.Point(first.clientX, first.clientY);
		this._startPos = this._newPos = L.DomUtil.getPosition(this._element);

		L.DomEvent
		    .on(document, L.Draggable.MOVE[e.type], this._onMove, this)
		    .on(document, L.Draggable.END[e.type], this._onUp, this);
	},

	_onMove: function (e) {
		if (e.touches && e.touches.length > 1) { return; }

		var first = (e.touches && e.touches.length === 1 ? e.touches[0] : e),
		    newPoint = new L.Point(first.clientX, first.clientY),
		    offset = newPoint.subtract(this._startPoint);

		if (!offset.x && !offset.y) { return; }

		L.DomEvent.preventDefault(e);

		if (!this._moved) {
			this.fire('dragstart');

			this._moved = true;
			this._startPos = L.DomUtil.getPosition(this._element).subtract(offset);

			if (!L.Browser.touch) {
				L.DomUtil.disableTextSelection();
				L.DomUtil.addClass(document.body, 'leaflet-dragging');
			}
		}

		this._newPos = this._startPos.add(offset);
		this._moving = true;

		L.Util.cancelAnimFrame(this._animRequest);
		this._animRequest = L.Util.requestAnimFrame(this._updatePosition, this, true, this._dragStartTarget);
	},

	_updatePosition: function () {
		this.fire('predrag');
		L.DomUtil.setPosition(this._element, this._newPos);
		this.fire('drag');
	},

	_onUp: function () {
		if (!L.Browser.touch) {
			L.DomUtil.enableTextSelection();
			L.DomUtil.removeClass(document.body, 'leaflet-dragging');
		}

		for (var i in L.Draggable.MOVE) {
			L.DomEvent
			    .off(document, L.Draggable.MOVE[i], this._onMove)
			    .off(document, L.Draggable.END[i], this._onUp);
		}

		if (this._moved) {
			// ensure drag is not fired after dragend
			L.Util.cancelAnimFrame(this._animRequest);

			this.fire('dragend');
		}

		this._moving = false;
	}
});
<|endoftext|>


<commit_before>import classNames from 'classnames';
import Immutable from 'immutable';
import React from 'react';
import Reorderable from '../lib/Reorderable';
import styles from './ListContainer.scss';

class ListContainer extends React.Component {
  static defaultProps = {
    horizontalItemIds: Immutable.Range(0, 5).map(i => `Horiz ${i}`).toList(),
    itemHeight: 40,
    itemWidth: 120,
    verticalItemIds: Immutable.Range(0, 5).map(i => `Vert ${i}`).toList(),
  };

  constructor(props) {
    super(props);

    const { horizontalItemIds, verticalItemIds } = props;
    this.state = {
      horizontalItemIds,
      verticalItemIds,
    };

    this.getItem = this.getItem.bind(this);
    this.handleHorizontalChange = this.handleHorizontalChange.bind(this);
    this.handleVerticalChange = this.handleVerticalChange.bind(this);
  }

  getItem(id, options) {
    return (
      <div className={classNames(styles.item, styles[`item--${options.axis}`])}>

        {id}

    );
  }

  handleHorizontalChange(itemIds) {
    this.setState({
      horizontalItemIds: itemIds,
    });
  }

  handleVerticalChange(itemIds) {
    this.setState({
      verticalItemIds: itemIds,
    });
  }

  log(...args) {
    console.log(...args);
  }

  render() {
    const { itemHeight, itemWidth } = this.props;
    const { horizontalItemIds, verticalItemIds } = this.state;
    return (

        <Reorderable
          className={styles.verticalReorderable}
          itemGetter={(id, options) => this.getItem(id, {
            axis: 'y',
            ...options,
          })}
          itemIds={verticalItemIds}
          itemSize={itemHeight}
          logger={this.log}
          onChange={this.handleVerticalChange}
        />
        <Reorderable
          axis="x"
          className={styles.horizontalReorderable}
          itemGetter={(id, options) => this.getItem(id, {
            axis: 'x',
            ...options,
          })}
          itemIds={horizontalItemIds}
          itemSize={itemWidth}
          logger={this.log}
          onChange={this.handleHorizontalChange}
        />

    );
  }
}

export default ListContainer;
<commit_msg>add gh ribbon<commit_after>import classNames from 'classnames';
import Immutable from 'immutable';
import React from 'react';
import Reorderable from '../lib/Reorderable';
import styles from './ListContainer.scss';

class ListContainer extends React.Component {
  static defaultProps = {
    horizontalItemIds: Immutable.Range(0, 5).map(i => `Horiz ${i}`).toList(),
    itemHeight: 40,
    itemWidth: 120,
    verticalItemIds: Immutable.Range(0, 5).map(i => `Vert ${i}`).toList(),
  };

  constructor(props) {
    super(props);

    const { horizontalItemIds, verticalItemIds } = props;
    this.state = {
      horizontalItemIds,
      verticalItemIds,
    };

    this.getItem = this.getItem.bind(this);
    this.handleHorizontalChange = this.handleHorizontalChange.bind(this);
    this.handleVerticalChange = this.handleVerticalChange.bind(this);
  }

  getItem(id, options) {
    return (
      <div className={classNames(styles.item, styles[`item--${options.axis}`])}>

        {id}

    );
  }

  handleHorizontalChange(itemIds) {
    this.setState({
      horizontalItemIds: itemIds,
    });
  }

  handleVerticalChange(itemIds) {
    this.setState({
      verticalItemIds: itemIds,
    });
  }

  log(...args) {
    console.log(...args);
  }

  render() {
    const { itemHeight, itemWidth } = this.props;
    const { horizontalItemIds, verticalItemIds } = this.state;
    return (

        <Reorderable
          className={styles.verticalReorderable}
          itemGetter={(id, options) => this.getItem(id, {
            axis: 'y',
            ...options,
          })}
          itemIds={verticalItemIds}
          itemSize={itemHeight}
          logger={this.log}
          onChange={this.handleVerticalChange}
        />
        <Reorderable
          axis="x"
          className={styles.horizontalReorderable}
          itemGetter={(id, options) => this.getItem(id, {
            axis: 'x',
            ...options,
          })}
          itemIds={horizontalItemIds}
          itemSize={itemWidth}
          logger={this.log}
          onChange={this.handleHorizontalChange}
        />
        {process.env.NODE_ENV === 'production' &&
          <img
            alt="Fork me on GitHub"
            data-canonical-src="https://s3.amazonaws.com/github/ribbons/forkme_right_red_aa0000.png"
            src="https://camo.githubusercontent.com/365986a132ccd6a44c23a9169022c0b5c890c387/68747470733a2f2f73332e616d617a6f6e6177732e636f6d2f6769746875622f726962626f6e732f666f726b6d655f72696768745f7265645f6161303030302e706e67"
            style={{
              border: 0,
              position: 'fixed',
              top: 0,
              right: 0,
            }}
          />
        }

    );
  }
}

export default ListContainer;
<|endoftext|>


<commit_before>var fs = require('fs');
var Shumway = require('../../../build/bundles/shumway.player.js').Shumway;
var FileLoader = Shumway.FileLoader;
var CompressionMethod = Shumway.SWF.CompressionMethod;

exports.run = function (info, cb) {
  var result = Object.create(null);
  var buffer = fs.readFileSync(info.path);
  var loader = new Shumway.FileLoader({
    onLoadOpen: function (file) {
      if (file instanceof Shumway.SWF.SWFFile) {
        var dictionary = file.dictionary;
        for (var i = 0; i < dictionary.length; i++) {
          if (dictionary[i]) {
            var symbol = file.getSymbol(dictionary[i].id);
          }
        }
        result.type = 'SWF';
        result.file_size = file.bytesTotal;
        result.compression = CompressionMethod[file.compression];
        result.swf_version = file.swfVersion;
        result.uses_avm1 = file.useAVM1;
        result.frame_rate = file.frameRate;
        result.frame_count = file.frameCount;
        var bounds = file.bounds;
        result.width = bounds.width / 20 | 0;
        result.height = bounds.height / 20 | 0;
      } else if (file instanceof Shumway.ImageFile) {
        result.type = 'Image';
        result.file_size = file.bytesTotal;
        result.mime_type = file.mimeType;
      } else {
        throw new Error('Unknown file format');
      }
    },
    onLoadProgress: function () { },
    onNewEagerlyParsedSymbols: function (list, delta) {
      return Promise.resolve();
    },
    onImageBytesLoaded: function () { }
  });
  try {
    loader.loadBytes(new Uint8Array(buffer));
    if (cb) {
      cb(null, result);
    }
  } catch (e) {
    console.error(e.toString());
    if (cb) {
      cb(e, null);
    }
  }
};
<commit_msg>Report max event loop ticks needed to render all frames of a SWF<commit_after>var fs = require('fs');
var Shumway = require('../../../build/bundles/shumway.player.js').Shumway;
var FileLoader = Shumway.FileLoader;
var CompressionMethod = Shumway.SWF.CompressionMethod;

exports.run = function (info, cb) {
  var result = Object.create(null);
  var buffer = fs.readFileSync(info.path);
  var loader = new Shumway.FileLoader({
    onLoadOpen: function (file) {
      if (file instanceof Shumway.SWF.SWFFile) {
        var dictionary = file.dictionary;
        var maxTicks = file.frameCount;
        for (var i = 0; i < dictionary.length; i++) {
          if (dictionary[i]) {
            var symbol = file.getSymbol(dictionary[i].id);
            if (symbol.type === 'sprite' && symbol.frameCount > maxTicks) {
              maxTicks = symbol.frameCount;
            }
          }
        }
        result.type = 'SWF';
        result.file_size = file.bytesTotal;
        result.compression = CompressionMethod[file.compression];
        result.swf_version = file.swfVersion;
        result.uses_avm1 = file.useAVM1;
        result.frame_rate = file.frameRate;
        result.frame_count = file.frameCount;
        var bounds = file.bounds;
        result.width = bounds.width / 20 | 0;
        result.height = bounds.height / 20 | 0;
        result.max_ticks = maxTicks;
      } else if (file instanceof Shumway.ImageFile) {
        result.type = 'Image';
        result.file_size = file.bytesTotal;
        result.mime_type = file.mimeType;
      } else {
        throw new Error('Unknown file format');
      }
    },
    onLoadProgress: function () { },
    onNewEagerlyParsedSymbols: function (list, delta) {
      return Promise.resolve();
    },
    onImageBytesLoaded: function () { }
  });
  try {
    loader.loadBytes(new Uint8Array(buffer));
    if (cb) {
      cb(null, result);
    }
  } catch (e) {
    console.error(e.toString());
    if (cb) {
      cb(e, null);
    }
  }
};
<|endoftext|>


<commit_before>'use strict';
const {PassThrough} = require('stream');
const zlib = require('zlib');
const mimicResponse = require('mimic-response');

module.exports = response => {
	const contentEncoding = response.headers['content-encoding'];

	if (!['gzip', 'deflate', 'br'].includes(contentEncoding)) {
		return response;
	}

	const isBrotli = contentEncoding === 'br';
	if (isBrotli && typeof zlib.createBrotliDecompress !== 'function') {
		return response;
	}

	const decompress = isBrotli ? zlib.createBrotliDecompress() : zlib.createUnzip();
	const stream = new PassThrough();

	mimicResponse(response, stream);

	decompress.on('error', error => {
		// Ignore empty response
		if (error.code === 'Z_BUF_ERROR') {
			stream.end();
			return;
		}

		stream.emit('error', error);
	});

	response.pipe(decompress).pipe(stream);

	return stream;
};
<commit_msg>Tiny readability tweaks<commit_after>'use strict';
const {PassThrough: PassThroughStream} = require('stream');
const zlib = require('zlib');
const mimicResponse = require('mimic-response');

module.exports = response => {
	const contentEncoding = response.headers['content-encoding'];

	if (!['gzip', 'deflate', 'br'].includes(contentEncoding)) {
		return response;
	}

	const isBrotli = contentEncoding === 'br';
	if (isBrotli && typeof zlib.createBrotliDecompress !== 'function') {
		return response;
	}

	const decompress = isBrotli ? zlib.createBrotliDecompress() : zlib.createUnzip();
	const stream = new PassThroughStream();

	mimicResponse(response, stream);

	decompress.on('error', error => {
		// Ignore empty response
		if (error.code === 'Z_BUF_ERROR') {
			stream.end();
			return;
		}

		stream.emit('error', error);
	});

	response.pipe(decompress).pipe(stream);

	return stream;
};
<|endoftext|>


<commit_before>angular.module('run.controller', [])

.controller('RunController', function($scope, $timeout, $location, Geo){
  $scope.raceStarted = 0;
  $scope.startTime;
  $scope.userLocation;
  $scope.destination;

  var tick = function() {
    $scope.time = Math.floor((Date.now() - $scope.startTime)/1000);
    $timeout(tick, 100)
  }

  $scope.startRun = function() {
    $scope.startTime = Date.now();
    $scope.raceStarted = true;
    tick();
  }

  $scope.currentCoords = {
    lat: null,
    lng: null
  };
  // $scope.getCurrentCoords = function() {
  //   console.log('ran');
  //   Geo.getCurrentCoords(function(coordsObj) {
  //     $scope.currentCoords = coordsObj;
  //     console.log('$scope.currentCoords.lat: ', $scope.currentCoords.lat);
  //     console.log('$scope.currentCoords.lng: ', $scope.currentCoords.lng);
  //   });
  // };

  $scope.makeInitialMap = function($scope) {
    console.log('in controller');
    Geo.makeInitialMap($scope);
  };

  $scope.makeInitialMap($scope);

  $scope.updateCurrentPosition = function($scope, $location) {
    Geo.updateCurrentPosition($scope);
    $scope.checkIfFinished($location);
  };

  $scope.checkIfFinished = function($location) {
    console.log('check if finished');
    if ($scope.destination && $scope.userLocation) {
      var conv = 110.574;
      var currLat = $scope.destination.lat;
      var currLng = $scope.destination.lng;
      var destLat = $scope.userLocation.lat;
      var destLng = $scope.userLocation.lng;
      var distRemaining = Math.sqrt(Math.pow((currLat - destLat), 2) + Math.pow((currLng - destLng) , 2));

      if (distRemaining < 0.0008) {
        $location.path('/finish');
        clearInterval($scope.geoUpdater);
      }
    }
  }

  // Determine user location and update map each second
<<<<<<< HEAD
<<<<<<< HEAD
  $scope.geoUpdater = setInterval(function() {$scope.updateCurrentPosition($scope, $location)}, 1000);
=======
  $scope.geoUpdater = setInterval(function() {$scope.updateCurrentPosition($scope)}, 1000);
>>>>>>> Modify race end conditions
=======
  $scope.geoUpdater = setInterval(function() {$scope.updateCurrentPosition($scope, $location)}, 1000);
>>>>>>> Determine whether user has reached destination

  // Stop geotracker upon canceling run
  $scope.stopGeoUpdater = function() {
    clearInterval($scope.geoUpdater);
  };
})
<commit_msg>Resolve more merge conflicts<commit_after>angular.module('run.controller', [])

.controller('RunController', function($scope, $timeout, $location, Geo){
  $scope.raceStarted = 0;
  $scope.startTime;
  $scope.userLocation;
  $scope.destination;

  var tick = function() {
    $scope.time = Math.floor((Date.now() - $scope.startTime)/1000);
    $timeout(tick, 100)
  }

  $scope.startRun = function() {
    $scope.startTime = Date.now();
    $scope.raceStarted = true;
    tick();
  }

  $scope.currentCoords = {
    lat: null,
    lng: null
  };
  // $scope.getCurrentCoords = function() {
  //   console.log('ran');
  //   Geo.getCurrentCoords(function(coordsObj) {
  //     $scope.currentCoords = coordsObj;
  //     console.log('$scope.currentCoords.lat: ', $scope.currentCoords.lat);
  //     console.log('$scope.currentCoords.lng: ', $scope.currentCoords.lng);
  //   });
  // };

  $scope.makeInitialMap = function($scope) {
    console.log('in controller');
    Geo.makeInitialMap($scope);
  };

  $scope.makeInitialMap($scope);

  $scope.updateCurrentPosition = function($scope, $location) {
    Geo.updateCurrentPosition($scope);
    $scope.checkIfFinished($location);
  };

  $scope.checkIfFinished = function($location) {
    if ($scope.destination && $scope.userLocation) {
      var currLat = $scope.destination.lat;
      var currLng = $scope.destination.lng;
      var destLat = $scope.userLocation.lat;
      var destLng = $scope.userLocation.lng;
      var distRemaining = Math.sqrt(Math.pow((currLat - destLat), 2) + Math.pow((currLng - destLng) , 2));

      if (distRemaining < 0.0008) {
        $location.path('/finish');
        clearInterval($scope.geoUpdater);
      }
    }
  }

  // Determine user location and update map each second
<<<<<<< HEAD
<<<<<<< HEAD
  $scope.geoUpdater = setInterval(function() {$scope.updateCurrentPosition($scope, $location)}, 1000);
=======
  $scope.geoUpdater = setInterval(function() {$scope.updateCurrentPosition($scope)}, 1000);
>>>>>>> Modify race end conditions
=======
  $scope.geoUpdater = setInterval(function() {$scope.updateCurrentPosition($scope, $location)}, 1000);
>>>>>>> Determine whether user has reached destination

  // Stop geotracker upon canceling run
  $scope.stopGeoUpdater = function() {
    clearInterval($scope.geoUpdater);
  };
})
<|endoftext|>


<commit_before>/**
 * dom/view/base.js
 */

var baseView = {
    make: function (opts) {
        var instance = {};
        _.extend(instance, this);
        instance['initialize'](opts);
        return instance;
    },
    'extend': function (subclass) {
        return _.extend({}, this, subclass, { parentView: this });
    },

    '$': function(selector) {
        return this['$el'].find(selector);
    },

    isView: true,

    'initialize': function (opts) {
        var self = this;
        uniqueId(self);
        _.extend(self, opts);
        self['$el'] = $(self['el']);
        self['el']['view'] = self;
        self.priority = self.domParentView ? self.domParentView.priority - 1 : BASE_PRIORITY_VIEW;
        self.scope = autorun(self.render, self, self.priority, 'view_' + self.Name,
                             self.onScopeExecute, self, true);
    },

    onScopeExecute: function (scope) {
        log(INFO, this, 'lookups', scope.lookups);
    },

    /**
     * View.destroy
     *
     * Destroys this view, removing all bindings and sub-views (recursively).
     */
    destroy: function (destroyRoot) {
        var self = this;
        log(VERBOSE, self, 'destroy', 'due to re-render of ' + destroyRoot.Name);
        self.destroyed = true;
        self.scope.destroy();
        _.each(self.subViews || [], function (view) {
            view.destroy(self);
        });
        self['destroyDOM'](self.$el);
    },

    /**
     * View.render
     *
     * This function is called at View init, and again whenever any model properties that this View
     * depended on are changed.
     */
    render: function () {
        var self = this;
        // This view may get a reset call at the same instant that another
        // view gets created to replace it.
        if (!self.destroyed) {
            /**
             * Move all this view's children to another temporary DOM element.  This will be used as the
             * pseudo-parent element for the destroyDOM call.
             */
            if (self.templateId) {
                /**
                 * If the DOM fragment to be removed has an active (focused) element, we attempt
                 * to restore that focus after refreshing this DOM fragment.  We also attempt
                 * to restore the selection start/end, which only works in Webkit/Gecko right
                 * now; see the URL below for possible IE compatibility.
                 */
                var activeElement = document.activeElement;
                var activeElementSelector, activeElementIndex, selectionStart, selectionEnd;
                if (_.contains($(activeElement).parents(), self.el)) {
                    // XXX this could be improved to pick up on IDs/classes/attributes or something?
                    activeElementSelector = 'input';
                    activeElementIndex = _.indexOf(self.$(activeElementSelector), activeElement);
                    // XXX for IE compatibility, this might work:
                    // http://the-stickman.com/web-development/javascript/ ...
                    // finding-selection-cursor-position-in-a-textarea-in-internet-explorer/
                    selectionStart = activeElement.selectionStart;
                    selectionEnd = activeElement.selectionEnd;
                }

                var $old = $('<div>').append(this.$el.children());
                var newHtml = renderTemplate(self.templateId, self);
                log(INFO, self, 'newhtml', newHtml);
                self.$el.html(newHtml);

                /**
                 * Execute the "fragment ready" callback.
                 */
                self['ready']();
                self['postReady']();

                /**
                 * (Re-)create sub-views for each descendent element with a tbone attribute.
                 * On re-renders, the pre-existing list of sub-views is passed to render, which
                 * attempts to pair already-rendered views with matching elements in this view's
                 * newly re-rendered template.  Matching views are transferred to the new DOM
                 * hierarchy without disruption.
                 */
                var oldSubViews = self.subViews || [];
                self.subViews = render(self.$('[tbone]'), self, oldSubViews);
                var obsoleteSubViews = _.difference(oldSubViews, self.subViews);
                /**
                 * Destroy all of the sub-views that were not reused.
                 */
                _.each(obsoleteSubViews, function (view) {
                    view.destroy(self);
                });
                /**
                 * Call destroyDOM with the the pseudo-parent created above.  This DOM fragment contains all
                 * of the previously-rendered (if any) DOM structure of this view and subviews, minus any
                 * subviews that are being reused (which have already been moved to the new parent).
                 */
                self['destroyDOM']($old);

                /**
                 * If we saved it above, restore the active element focus and selection.
                 */
                if (activeElementSelector) {
                    var newActiveElement = self.$(activeElementSelector)[activeElementIndex];
                    if (newActiveElement) {
                        $(newActiveElement).focus();
                        if (selectionStart != null && selectionEnd != null) {
                            newActiveElement.selectionStart = selectionStart;
                            newActiveElement.selectionEnd = selectionEnd;
                        }
                    }
                }
            } else {
                self['ready']();
                self['postReady']();
            }
            self['postRender']();
            viewRenders++;
        }
    },

    /**
     * View.ready
     *
     * The "template-ready" callback.  This is the restricted tbone equivalent of document-ready.
     * It is the recommended means of adding interactivity/data/whatever to Views.
     *
     * At the moment this callback is executed, subviews are neither rendered nor are they
     * attached to the DOM fragment.  If you need to interact with subviews, use postRender.
     */
    'ready': noop,

    /**
     * View.postReady
     *
     * This is the same as ready, except that it executes after ready.  The typical use case is
     * to override this in your base template to provide automatic application-wide helpers,
     * such as activating a tooltip library, and to use View.ready for specific view logic.
     */
    'postReady': noop,

    /**
     * View.postRender
     *
     * The "fragment-updated" callback.  This is executed whenever this view is re-rendered,
     * and after all sub-views (recursively) have rendered.
     *
     * Note that because we optimistically re-use sub-views, this may be called multiple times
     * with the same sub-view DOM fragments.  Ensure that anything you do to DOM elements in
     * sub-views is idempotent.
     */
    'postRender': noop,

    /**
     * View.destroyDOM
     *
     * The "document-destroy" callback.  Use this to do cleanup on removal of old HTML, e.g.
     * destroying associated tooltips.
     *
     * Note: Destroy contents of the $el parameter, not this.$el!  (XXX make this less error-prone)
     *
     * @param  {!jQuery} $el jQuery selection of DOM fragment to destroy
     */
    'destroyDOM': function ($el) { },

    /**
     * If a root attribute was specified, use that as the root object for this view's
     * render, both in templating automatically as well as available via this.root in
     * `ready` and `postRender` callbacks.
     */
    root: function () {
        return this['query'](DONT_GET_DATA, '');
    },

    /**
     * Perform a query relative to the view's rootObj and rootStr, delegating to
     * rootObj for the actual query but prepending rootStr to the prop string.
     **/
    'query': function (flag, prop, value) {
        var isSet = false;
        if (typeof flag !== 'number') {
            /**
             * If no flag provided, shift the prop and value over.  We do it this way instead
             * of having flag last so that we can type-check flag and discern optional flags
             * from optional values.  And flag should only be used internally, anyway.
             */
            value = prop;
            prop = flag;
            flag = 0;
            /**
             * Use arguments.length to switch to set mode in order to properly support
             * setting undefined.
             */
            isSet = arguments.length === 2;
        }
        prop = (this.rootStr ? this.rootStr + '.' : '') + (prop || '');
        return isSet ? this.rootObj(flag, prop, value) : this.rootObj(flag, prop);
    },

    // deprecated
    'lookup': function (query) {
        return this['query'](query);
    },

    'parentRoot': function () {
        return this.domParentView && this.domParentView.root();
    },

    /**
     * Get the DOM parent view, i.e. the view associated with the closest
     * ancestor DOM node that is a view root element.
     */
    'parent': function () {
        return this.domParentView;
    },

    // These are used at template render.  They're really not properties of views so much
    // as it is useful to reference these functions on the view, which is what we pass to
    // _.template already.
    'getHashId': getHashId,
    'isQueryable': isQueryable,
    'denullText': denullText

};

var defaultView = baseView;
/**
 * Set the default View to use when rendering templates with no matching View.
 * @param {ViewPrototype} view
 */
function setDefaultView(view) {
    defaultView = view;
}
<commit_msg>Remove lookup from base view<commit_after>/**
 * dom/view/base.js
 */

var baseView = {
    make: function (opts) {
        var instance = {};
        _.extend(instance, this);
        instance['initialize'](opts);
        return instance;
    },
    'extend': function (subclass) {
        return _.extend({}, this, subclass, { parentView: this });
    },

    '$': function(selector) {
        return this['$el'].find(selector);
    },

    isView: true,

    'initialize': function (opts) {
        var self = this;
        uniqueId(self);
        _.extend(self, opts);
        self['$el'] = $(self['el']);
        self['el']['view'] = self;
        self.priority = self.domParentView ? self.domParentView.priority - 1 : BASE_PRIORITY_VIEW;
        self.scope = autorun(self.render, self, self.priority, 'view_' + self.Name,
                             self.onScopeExecute, self, true);
    },

    onScopeExecute: function (scope) {
        log(INFO, this, 'lookups', scope.lookups);
    },

    /**
     * View.destroy
     *
     * Destroys this view, removing all bindings and sub-views (recursively).
     */
    destroy: function (destroyRoot) {
        var self = this;
        log(VERBOSE, self, 'destroy', 'due to re-render of ' + destroyRoot.Name);
        self.destroyed = true;
        self.scope.destroy();
        _.each(self.subViews || [], function (view) {
            view.destroy(self);
        });
        self['destroyDOM'](self.$el);
    },

    /**
     * View.render
     *
     * This function is called at View init, and again whenever any model properties that this View
     * depended on are changed.
     */
    render: function () {
        var self = this;
        // This view may get a reset call at the same instant that another
        // view gets created to replace it.
        if (!self.destroyed) {
            /**
             * Move all this view's children to another temporary DOM element.  This will be used as the
             * pseudo-parent element for the destroyDOM call.
             */
            if (self.templateId) {
                /**
                 * If the DOM fragment to be removed has an active (focused) element, we attempt
                 * to restore that focus after refreshing this DOM fragment.  We also attempt
                 * to restore the selection start/end, which only works in Webkit/Gecko right
                 * now; see the URL below for possible IE compatibility.
                 */
                var activeElement = document.activeElement;
                var activeElementSelector, activeElementIndex, selectionStart, selectionEnd;
                if (_.contains($(activeElement).parents(), self.el)) {
                    // XXX this could be improved to pick up on IDs/classes/attributes or something?
                    activeElementSelector = 'input';
                    activeElementIndex = _.indexOf(self.$(activeElementSelector), activeElement);
                    // XXX for IE compatibility, this might work:
                    // http://the-stickman.com/web-development/javascript/ ...
                    // finding-selection-cursor-position-in-a-textarea-in-internet-explorer/
                    selectionStart = activeElement.selectionStart;
                    selectionEnd = activeElement.selectionEnd;
                }

                var $old = $('<div>').append(this.$el.children());
                var newHtml = renderTemplate(self.templateId, self);
                log(INFO, self, 'newhtml', newHtml);
                self.$el.html(newHtml);

                /**
                 * Execute the "fragment ready" callback.
                 */
                self['ready']();
                self['postReady']();

                /**
                 * (Re-)create sub-views for each descendent element with a tbone attribute.
                 * On re-renders, the pre-existing list of sub-views is passed to render, which
                 * attempts to pair already-rendered views with matching elements in this view's
                 * newly re-rendered template.  Matching views are transferred to the new DOM
                 * hierarchy without disruption.
                 */
                var oldSubViews = self.subViews || [];
                self.subViews = render(self.$('[tbone]'), self, oldSubViews);
                var obsoleteSubViews = _.difference(oldSubViews, self.subViews);
                /**
                 * Destroy all of the sub-views that were not reused.
                 */
                _.each(obsoleteSubViews, function (view) {
                    view.destroy(self);
                });
                /**
                 * Call destroyDOM with the the pseudo-parent created above.  This DOM fragment contains all
                 * of the previously-rendered (if any) DOM structure of this view and subviews, minus any
                 * subviews that are being reused (which have already been moved to the new parent).
                 */
                self['destroyDOM']($old);

                /**
                 * If we saved it above, restore the active element focus and selection.
                 */
                if (activeElementSelector) {
                    var newActiveElement = self.$(activeElementSelector)[activeElementIndex];
                    if (newActiveElement) {
                        $(newActiveElement).focus();
                        if (selectionStart != null && selectionEnd != null) {
                            newActiveElement.selectionStart = selectionStart;
                            newActiveElement.selectionEnd = selectionEnd;
                        }
                    }
                }
            } else {
                self['ready']();
                self['postReady']();
            }
            self['postRender']();
            viewRenders++;
        }
    },

    /**
     * View.ready
     *
     * The "template-ready" callback.  This is the restricted tbone equivalent of document-ready.
     * It is the recommended means of adding interactivity/data/whatever to Views.
     *
     * At the moment this callback is executed, subviews are neither rendered nor are they
     * attached to the DOM fragment.  If you need to interact with subviews, use postRender.
     */
    'ready': noop,

    /**
     * View.postReady
     *
     * This is the same as ready, except that it executes after ready.  The typical use case is
     * to override this in your base template to provide automatic application-wide helpers,
     * such as activating a tooltip library, and to use View.ready for specific view logic.
     */
    'postReady': noop,

    /**
     * View.postRender
     *
     * The "fragment-updated" callback.  This is executed whenever this view is re-rendered,
     * and after all sub-views (recursively) have rendered.
     *
     * Note that because we optimistically re-use sub-views, this may be called multiple times
     * with the same sub-view DOM fragments.  Ensure that anything you do to DOM elements in
     * sub-views is idempotent.
     */
    'postRender': noop,

    /**
     * View.destroyDOM
     *
     * The "document-destroy" callback.  Use this to do cleanup on removal of old HTML, e.g.
     * destroying associated tooltips.
     *
     * Note: Destroy contents of the $el parameter, not this.$el!  (XXX make this less error-prone)
     *
     * @param  {!jQuery} $el jQuery selection of DOM fragment to destroy
     */
    'destroyDOM': function ($el) { },

    /**
     * If a root attribute was specified, use that as the root object for this view's
     * render, both in templating automatically as well as available via this.root in
     * `ready` and `postRender` callbacks.
     */
    root: function () {
        return this['query'](DONT_GET_DATA, '');
    },

    /**
     * Perform a query relative to the view's rootObj and rootStr, delegating to
     * rootObj for the actual query but prepending rootStr to the prop string.
     **/
    'query': function (flag, prop, value) {
        var isSet = false;
        if (typeof flag !== 'number') {
            /**
             * If no flag provided, shift the prop and value over.  We do it this way instead
             * of having flag last so that we can type-check flag and discern optional flags
             * from optional values.  And flag should only be used internally, anyway.
             */
            value = prop;
            prop = flag;
            flag = 0;
            /**
             * Use arguments.length to switch to set mode in order to properly support
             * setting undefined.
             */
            isSet = arguments.length === 2;
        }
        prop = (this.rootStr ? this.rootStr + '.' : '') + (prop || '');
        return isSet ? this.rootObj(flag, prop, value) : this.rootObj(flag, prop);
    },

    'parentRoot': function () {
        return this.domParentView && this.domParentView.root();
    },

    /**
     * Get the DOM parent view, i.e. the view associated with the closest
     * ancestor DOM node that is a view root element.
     */
    'parent': function () {
        return this.domParentView;
    },

    // These are used at template render.  They're really not properties of views so much
    // as it is useful to reference these functions on the view, which is what we pass to
    // _.template already.
    'getHashId': getHashId,
    'isQueryable': isQueryable,
    'denullText': denullText

};

var defaultView = baseView;
/**
 * Set the default View to use when rendering templates with no matching View.
 * @param {ViewPrototype} view
 */
function setDefaultView(view) {
    defaultView = view;
}
<|endoftext|>


<commit_before><commit_msg>added facespace pages for all of the cast<commit_after><|endoftext|>


<commit_before>const Broker = require('./index')
const {
  secureRandom,
  createConnection,
  newLogger,
  retryProtocol,
  createCluster,
} = require('testHelpers')
const createConsumer = require('../consumer')

describe('Broker > DescribeGroups', () => {
  let groupId, seedBroker, broker, cluster, consumer

  beforeEach(async () => {
    groupId = `consumer-group-id-${secureRandom()}`
    seedBroker = new Broker({
      connection: createConnection(),
      logger: newLogger(),
    })
    await seedBroker.connect()

    const { coordinator: { host, port } } = await retryProtocol(
      'GROUP_COORDINATOR_NOT_AVAILABLE',
      async () => await seedBroker.findGroupCoordinator({ groupId })
    )

    broker = new Broker({
      connection: createConnection({ host, port }),
      logger: newLogger(),
    })
    await broker.connect()

    cluster = createCluster()
    consumer = createConsumer({
      cluster,
      groupId,
      maxWaitTimeInMs: 1,
      logger: newLogger(),
    })
  })

  afterEach(async () => {
    await consumer.disconnect()
    await seedBroker.disconnect()
    await broker.disconnect()
  })

  test('request', async () => {
    await consumer.run({ eachMessage: jest.fn() })
    const response = await broker.describeGroups({ groupIds: [groupId] })

    expect(response).toEqual({
      groups: [
        {
          errorCode: 0,
          groupId,
          members: [
            {
              clientHost: expect.any(String),
              clientId: expect.any(String),
              memberAssignment: expect.anything(),
              memberId: expect.any(String),
              memberMetadata: expect.anything(),
            },
          ],
          protocol: 'RoundRobinAssigner',
          protocolType: 'consumer',
          state: 'Stable',
        },
      ],
    })
  })
})
<commit_msg>Fix describe groups broker test<commit_after>const Broker = require('./index')
const {
  secureRandom,
  createConnection,
  newLogger,
  retryProtocol,
  createCluster,
} = require('testHelpers')
const createConsumer = require('../consumer')

describe('Broker > DescribeGroups', () => {
  let groupId, topicName, seedBroker, broker, cluster, consumer

  beforeEach(async () => {
    groupId = `consumer-group-id-${secureRandom()}`
    topicName = `test-topic-${secureRandom()}`
    seedBroker = new Broker({
      connection: createConnection(),
      logger: newLogger(),
    })
    await seedBroker.connect()

    const { coordinator: { host, port } } = await retryProtocol(
      'GROUP_COORDINATOR_NOT_AVAILABLE',
      async () => await seedBroker.findGroupCoordinator({ groupId })
    )

    broker = new Broker({
      connection: createConnection({ host, port }),
      logger: newLogger(),
    })
    await broker.connect()

    cluster = createCluster()
    consumer = createConsumer({
      cluster,
      groupId,
      maxWaitTimeInMs: 1,
      logger: newLogger(),
    })
  })

  afterEach(async () => {
    await consumer.disconnect()
    await seedBroker.disconnect()
    await broker.disconnect()
  })

  test('request', async () => {
    await consumer.connect()
    await consumer.subscribe({ topic: topicName, fromBeginning: true })
    await consumer.run({ eachMessage: jest.fn() })
    const response = await broker.describeGroups({ groupIds: [groupId] })

    expect(response).toEqual({
      groups: [
        {
          errorCode: 0,
          groupId,
          members: [
            {
              clientHost: expect.any(String),
              clientId: expect.any(String),
              memberAssignment: expect.anything(),
              memberId: expect.any(String),
              memberMetadata: expect.anything(),
            },
          ],
          protocol: 'RoundRobinAssigner',
          protocolType: 'consumer',
          state: 'Stable',
        },
      ],
    })
  })
})
<|endoftext|>