<commit_before>game.PlayerEntity = me.Entity.extend ({
	init: function(x, y, settings){
		this.setSuper();
		this.setPlayerTimers();
		this.setAttributes();
		this.setFlags();

		me.game.viewport.follow(this.pos, me.game.viewport.AXIS.BOTH); //makes it so the window always follows the character on BOTH axis

		this.addAnimation();

		this.type = "PlayerEntity";

		this.attack = game.data.playerAttack;
		this.renderable.addAnimation("idle", [78]); //animation for when the character is not moving
		this.renderable.addAnimation("attack", [65, 66, 67, 68, 69, 70, 71, 72]);
		this.renderable.addAnimation("walk", [117, 118, 119, 120, 121, 122, 123, 124, 125], 80); //walking animation for character using the OrcSpear sprite sheet

		this.renderable.setCurrentAnimation("idle"); //sets the default animation to "idle"

	},

	setSuper:function(){
		this._super(me.Entity, 'init', [x, y, {
			image: "player",
			width: 64, //size put aside for the character
			height: 64,
			spritewidth: "64", //size of the image
			spriteheight: "64",
			getShape: function(){
				return(new me.Rect(0, 0, 64, 50)).toPolygon();	//pretty much the hitbox of the character
			}
		}]);
	},

	setPlayerTimers: function(){
		this.lastAttack = new Date().getTime();
		this.now = new Date().getTime();
		this.lastHit = this.now;
	},

	setAttributes: function(){
		this.health = game.data.playerHealth;
		this.body.setVelocity(game.data.playerMoveSpeed, 14); //moves five units right
	},

	setFlags: function(){ this.dead = false; this.facing ="right";
	//keeps track of the direction of the character },=

	update: function(delta){
		this.now = new Date().getTime(); //keeps track of the timer

		this.dead.checkIfDead();

		this.checkKeyPressesAndMove();

		if(me.input.isKeyPressed("attack") && !this.body.jumping && !this.body.falling){
			if(!this.renderable.isCurrentAnimation("attack")){
				this.renderable.setCurrentAnimation("attack", "idle"); //sets current animation to attack then reverts back to idle
				this.renderable.setAnimationFrame(); //the next time this sequence starts, it begins form the first animtion and not from where it left off
			}
		}
		else if(this.body.vel.x !== 0 && !this.renderable.isCurrentAnimation("attack")) {
			if(!this.renderable.isCurrentAnimation("walk")){
				this.renderable.setCurrentAnimation("walk");
			}
		}
		else if(!this.renderable.isCurrentAnimation("attack")){
			this.renderable.setCurrentAnimation("idle"); //if the character isn't moving the character becomes idle
		}

		me.collision.check(this, true, this.collideHandler.bind(this), true);

		this.body.update(delta); //delta is the change in time

		this._super(me.Entity, "update", [delta]);
		return true;
	},

	checkIfDead: function(){
		if(this.health <=0){ //if the character's health is less than zero
			return true; //the character is dead
		}
	},

	checkKeyPressesAndMove: function(){
		if(me.input.isKeyPressed("right")){ //checks if the right key is pressed
			this.moveRight();
		}
		else if(me.input.isKeyPressed("left")){
			this.moveLeft();
		}
		else{
			this.body.vel.x = 0;
		}
		if(me.input.isKeyPressed("jump") && !this.body.jumping && !this.body.falling){ //says that you can only jump if you're not already jumping or falling
			this.jump();
		}
	},

	moveRight: function(){
		//adds to the position of the x by adding the velocity defined above in setVelocity() and multiplying
		//it by me.timer.tick
		//me.time.tick makes movement smooth
		this.facing = "right";
		this.body.vel.x += this.body.accel.x * me.timer.tick;
		this.flipX(true);
	},

	moveLeft: function(){
		this.facing = "left";
		this.body.vel.x -= this.body.accel.x * me.timer.tick;
		this.flipX(false); //flips the animation so that when the character goes left, the animation goes the same way
	},

	jump: function(){
		this.body.jumping = true;
		this.body.vel.y -= this.body.accel.y * me.timer.tick;
	},

	collideHandler: function(response){
		if(response.b.type === 'EnemyBaseEntity'){ //if something runs into the Enemy base, it checks some things
			var ydif = this.pos.y - response.b.pos.y; //the difference between the base's y and the player's y
			var xdif = this.pos.x - response.b.pos.x; //the difference between the base's x and the player's x

			if(ydif<-40 && ydif>-50 && xdif<70 && xdif>-35){
				this.body.falling = false;
				this.body.vel.y = -1;
			}
			else if(xdif>-15  && this.facing === 'right' && (xdif < 0)){
				this.body.vel.x = 0;
				this.pos.x = this.pos.x - 1;
			}else if(xdif<50 && this.facing === 'left' && (xdif > 0)){
				this.body.vel.x = 0;
				this.pos.x = this.pos.x + 1;
			}

			if(this.renderable.isCurrentAnimation("attack") && this.now-this.lastHit >= game.data.playerTimer){ //checks to see if there's been 400 miliseconds since the base was last hit
				this.lastHit = this.now;
				response.b.loseHealth(game.data.playerHealth);
			}
		}else if(response.b.type==='EnemyCreep'){
			var ydif = this.pos.y - response.b.pos.y; //the difference between the base's y and the player's y
			var xdif = this.pos.x - response.b.pos.x; //the difference between the base's x and the player's x

			if(xdif > 0){ //makes it so you can't walk through the creep without doing damage
				this.pos.x = this.pos.x +1;
				if(this.facing==='left'){
					this.body.vel.x = 0;
				}
			}else{
				this.pos.x = this.pos.x -1;
				if(this.facing==='right'){
					this.body.vel.x = 0;
				}
			}

			if(this.renderable.isCurrentAnimation("attack") && this.now-this.lastHit >= game.data.playerTimer
				&&	(Math.abs(ydif<=40)
				&& ((xdif>0) && this.facing==="left") || ((xdif<0) && this.facing==="right")
				)){ //if I'm attacking, and I attacked one second ago, and my ydif is less than 40, and I'm facing right or left, it will attack
				this.lastHit = this.now;
				//if the creeps health is less than the attack, execute code
				if(response.b.health <= game.data.playerAttack){
					//adds one gold for killing a creep
					console.log("gold " + game.data.gold);
					game.data.gold += 1;
				}

				response.b.loseHealth(game.data.playerAttack);
			}
		}
	},
	loseHealth: function(damage){
		this.health = this.health - damage;
	}
xa<commit_msg>video 32, refactoring animations, CODED (no need for comments) *expected error, fixed error with Update function<commit_after>game.PlayerEntity = me.Entity.extend ({
	init: function(x, y, settings){
		this.setSuper();
		this.setPlayerTimers();
		this.setAttributes();
		this.setFlags();

		me.game.viewport.follow(this.pos, me.game.viewport.AXIS.BOTH); //makes it so the window always follows the character on BOTH axis

		this.addAnimation();

		this.type = "PlayerEntity";

		this.attack = game.data.playerAttack;
		this.renderable.addAnimation("idle", [78]); //animation for when the character is not moving
		this.renderable.addAnimation("attack", [65, 66, 67, 68, 69, 70, 71, 72]);
		this.renderable.addAnimation("walk", [117, 118, 119, 120, 121, 122, 123, 124, 125], 80); //walking animation for character using the OrcSpear sprite sheet

		this.renderable.setCurrentAnimation("idle"); //sets the default animation to "idle"

	},

	setSuper:function(){
		this._super(me.Entity, 'init', [x, y, {
			image: "player",
			width: 64, //size put aside for the character
			height: 64,
			spritewidth: "64", //size of the image
			spriteheight: "64",
			getShape: function(){
				return(new me.Rect(0, 0, 64, 50)).toPolygon();	//pretty much the hitbox of the character
			}
		}]);
	},

	setPlayerTimers: function(){
		this.lastAttack = new Date().getTime();
		this.now = new Date().getTime();
		this.lastHit = this.now;
	},

	setAttributes: function(){
		this.health = game.data.playerHealth;
		this.body.setVelocity(game.data.playerMoveSpeed, 14); //moves five units right
	},

	setFlags: function(){
		this.dead = false;
		this.facing ="right";
		//keeps track of the direction of the character
	 },

	update: function(delta){
		this.now = new Date().getTime(); //keeps track of the timer

		this.dead.checkIfDead();

		this.checkKeyPressesAndMove();

		this.setAnimation();

		me.collision.check(this, true, this.collideHandler.bind(this), true);

		this.body.update(delta); //delta is the change in time

		this._super(me.Entity, "update", [delta]);
		return true;
	},

	checkIfDead: function(){
		if(this.health <=0){ //if the character's health is less than zero
			return true; //the character is dead
		}
	},

	checkKeyPressesAndMove: function(){
		if(me.input.isKeyPressed("right")){ //checks if the right key is pressed
			this.moveRight();
		}
		else if(me.input.isKeyPressed("left")){
			this.moveLeft();
		}
		else{
			this.body.vel.x = 0;
		}
		if(me.input.isKeyPressed("jump") && !this.body.jumping && !this.body.falling){ //says that you can only jump if you're not already jumping or falling
			this.jump();
		}

		this.attacking = me.input.isKeyPressed("attack") && !this.body.jumping && !this.body.falling && !isCurrentAnimation("walk");
	},

	moveRight: function(){
		//adds to the position of the x by adding the velocity defined above in setVelocity() and multiplying
		//it by me.timer.tick
		//me.time.tick makes movement smooth
		this.facing = "right";
		this.body.vel.x += this.body.accel.x * me.timer.tick;
		this.flipX(true);
	},

	moveLeft: function(){
		this.facing = "left";
		this.body.vel.x -= this.body.accel.x * me.timer.tick;
		this.flipX(false); //flips the animation so that when the character goes left, the animation goes the same way
	},

	jump: function(){
		this.body.jumping = true;
		this.body.vel.y -= this.body.accel.y * me.timer.tick;
	},

	setAnimation: function(){
		if(this.attacking){
			if(!this.renderable.isCurrentAnimation("attack")){
				this.renderable.setCurrentAnimation("attack", "idle"); //sets current animation to attack then reverts back to idle
				this.renderable.setAnimationFrame(); //the next time this sequence starts, it begins form the first animtion and not from where it left off
			}
		}
		else if(this.body.vel.x !== 0 && !this.renderable.isCurrentAnimation("attack")) {
			if(!this.renderable.isCurrentAnimation("walk")){
				this.renderable.setCurrentAnimation("walk");
			}
		}
		else if(!this.renderable.isCurrentAnimation("attack")){
			this.renderable.setCurrentAnimation("idle"); //if the character isn't moving the character becomes idle
		}
	},

	collideHandler: function(response){
		if(response.b.type === 'EnemyBaseEntity'){ //if something runs into the Enemy base, it checks some things
			var ydif = this.pos.y - response.b.pos.y; //the difference between the base's y and the player's y
			var xdif = this.pos.x - response.b.pos.x; //the difference between the base's x and the player's x

			if(ydif<-40 && ydif>-50 && xdif<70 && xdif>-35){
				this.body.falling = false;
				this.body.vel.y = -1;
			}
			else if(xdif>-15  && this.facing === 'right' && (xdif < 0)){
				this.body.vel.x = 0;
				this.pos.x = this.pos.x - 1;
			}else if(xdif<50 && this.facing === 'left' && (xdif > 0)){
				this.body.vel.x = 0;
				this.pos.x = this.pos.x + 1;
			}

			if(this.renderable.isCurrentAnimation("attack") && this.now-this.lastHit >= game.data.playerTimer){ //checks to see if there's been 400 miliseconds since the base was last hit
				this.lastHit = this.now;
				response.b.loseHealth(game.data.playerHealth);
			}
		}else if(response.b.type==='EnemyCreep'){
			var ydif = this.pos.y - response.b.pos.y; //the difference between the base's y and the player's y
			var xdif = this.pos.x - response.b.pos.x; //the difference between the base's x and the player's x

			if(xdif > 0){ //makes it so you can't walk through the creep without doing damage
				this.pos.x = this.pos.x +1;
				if(this.facing==='left'){
					this.body.vel.x = 0;
				}
			}else{
				this.pos.x = this.pos.x -1;
				if(this.facing==='right'){
					this.body.vel.x = 0;
				}
			}

			if(this.renderable.isCurrentAnimation("attack") && this.now-this.lastHit >= game.data.playerTimer
				&&	(Math.abs(ydif<=40)
				&& ((xdif>0) && this.facing==="left") || ((xdif<0) && this.facing==="right")
				)){ //if I'm attacking, and I attacked one second ago, and my ydif is less than 40, and I'm facing right or left, it will attack
				this.lastHit = this.now;
				//if the creeps health is less than the attack, execute code
				if(response.b.health <= game.data.playerAttack){
					//adds one gold for killing a creep
					console.log("gold " + game.data.gold);
					game.data.gold += 1;
				}

				response.b.loseHealth(game.data.playerAttack);
			}
		}
	},
	loseHealth: function(damage){
		this.health = this.health - damage;
	}
xa<|endoftext|>


<commit_before>// app/controllers/MainCtrl.js

app.controller('MainController', ['$scope', '$state', '$log', '$sce', 'DataService',
    function($scope, $state, $log, $sce, DataService) {

      $scope.error;
      $scope.annotateMode = false;
      $scope.chapterText = "";
      $scope.annotatedChapterText = "";
      $scope.annotationArray;
      $scope.selectChapter;

      $scope.loadChapter = function () {
        $scope.error = false;
        $scope.annotatedChapterText = "";
        loadChapterAndAnnotations($scope.selectChapter);
      };

      $scope.addAnnotation = function () {
        $scope.textSelection = getTextSelection();
      };

      $scope.delete = function (event) {
        var index = parseInt(event.target.attributes[0].value);
        if (event.target.tagName === "SPAN") {
          $scope.annotatedChapterText = $scope.chapterText;
          $scope.annotationArray.splice(index, 1);
          $scope.annotatedChapterText =
          createAnnotatedChapterText($scope.annotatedChapterText, $scope.annotationArray);
        }
      };

      $scope.saveJSON = function () {
        var annotationsJSON = angular.toJson($scope.annotationArray.reverse(), true);
        if (annotationsJSON) {
          $log.info(annotationsJSON);
        } else {
          $log.warn('There are no annotations for the current selected chapter.')
        }
      };

      function loadChapterAndAnnotations (chapterNumber) {
        DataService.getChapterText(chapterNumber)
          .then(function(chapter) {

            $scope.chapterText = chapter.data;

            DataService.getChapterAnnotations(chapterNumber)
              .then(function (response) {
                $scope.annotatedChapterText = chapter.data;  //.replace(/\n/g,"
");
                $scope.annotationArray = response.data.document.span.reverse();
                $scope.annotatedChapterText =
                createAnnotatedChapterText($scope.annotatedChapterText, $scope.annotationArray);
              })
              .catch(function (error) {
                $scope.error = error;
                $log.error(error.status, error.statusText);
              });
          })
          .catch(function (error) {
             $scope.error = error;
             $log.error(error.status, error.statusText);
          });
      }; // end loadChapterAndAnnotations function

      function createAnnotatedChapterText (text, annotations) {
        angular.forEach(annotations, function (value, index) {
          var start = parseInt(value.extent.charseq._START) ;
          var end = parseInt(value.extent.charseq._END) + 1;
          var subText = text.substring(start, end);
          var category = value._category;
          var arrayIndex = index.toString();
          var preText = text.substring(0, start);
          var hiliteText =
          '' + subText + '';
          var postText = text.substring(end);
          text = preText + hiliteText + postText;
        });
        return text;
      };

      $scope.selectText = function (event) {
        var selection = document.getSelection();
        var start = selection.anchorOffset < selection.focusOffset ? selection.anchorOffset : selection.focusOffset;
        var end = selection.anchorOffset < selection.focusOffset ? selection.focusOffset - 1: selection.anchorOffset - 1;
        console.log('Selection', selection, start, end); // also think about getRangeAt(0) or createRange()
      };

}]);
<commit_msg>modified getTextSelection function to return object of text, end, start properties<commit_after>// app/controllers/MainCtrl.js

app.controller('MainController', ['$scope', '$state', '$log', '$sce', 'DataService',
    function($scope, $state, $log, $sce, DataService) {

      $scope.error;
      $scope.annotateMode = false;
      $scope.chapterText = "";
      $scope.annotatedChapterText = "";
      $scope.annotationArray;
      $scope.selectChapter;

      $scope.loadChapter = function () {
        $scope.error = false;
        $scope.annotatedChapterText = "";
        loadChapterAndAnnotations($scope.selectChapter);
      };

      $scope.addAnnotation = function () {
        $scope.textSelection = getTextSelection();
      };

      $scope.delete = function (event) {
        var index = parseInt(event.target.attributes[0].value);
        if (event.target.tagName === "SPAN") {
          $scope.annotatedChapterText = $scope.chapterText;
          $scope.annotationArray.splice(index, 1);
          $scope.annotatedChapterText =
          createAnnotatedChapterText($scope.annotatedChapterText, $scope.annotationArray);
        }
      };

      $scope.saveJSON = function () {
        var annotationsJSON = angular.toJson($scope.annotationArray.reverse(), true);
        if (annotationsJSON) {
          $log.info(annotationsJSON);
        } else {
          $log.warn('There are no annotations for the current selected chapter.')
        }
      };

      function loadChapterAndAnnotations (chapterNumber) {
        DataService.getChapterText(chapterNumber)
          .then(function(chapter) {

            $scope.chapterText = chapter.data;

            DataService.getChapterAnnotations(chapterNumber)
              .then(function (response) {
                $scope.annotatedChapterText = chapter.data;  //.replace(/\n/g,"
");
                $scope.annotationArray = response.data.document.span.reverse();
                $scope.annotatedChapterText =
                createAnnotatedChapterText($scope.annotatedChapterText, $scope.annotationArray);
              })
              .catch(function (error) {
                $scope.error = error;
                $log.error(error.status, error.statusText);
              });
          })
          .catch(function (error) {
             $scope.error = error;
             $log.error(error.status, error.statusText);
          });
      }; // end loadChapterAndAnnotations function

      function createAnnotatedChapterText (text, annotations) {
        angular.forEach(annotations, function (value, index) {
          var start = parseInt(value.extent.charseq._START) ;
          var end = parseInt(value.extent.charseq._END) + 1;
          var subText = text.substring(start, end);
          var category = value._category;
          var arrayIndex = index.toString();
          var preText = text.substring(0, start);
          var hiliteText =
          '' + subText + '';
          var postText = text.substring(end);
          text = preText + hiliteText + postText;
        });
        return text;
      };

      function getTextSelection (event) {
        var selection = document.getSelection();
        var rangeContents = selection.getRangeAt(0).cloneContents();
        var start = selection.anchorOffset < selection.focusOffset ? selection.anchorOffset : selection.focusOffset;
        var end = selection.anchorOffset < selection.focusOffset ? selection.focusOffset - 1: selection.anchorOffset - 1;
        var span = document.createElement('span');
        span.appendChild(rangeContents);
        var rangeText = span.innerHTML;
        return {
          text: rangeText,
          end: end,
          start: start
        }
      };

}]);
<|endoftext|>


<commit_before>game.PlayerEntity = me.Entity.extend({
    init: function(x, y, settings){
        this._super(me.Entity, 'init', [x, y, {
            image: "player",
            width: 64,
            height: 64,
            spritewidth: "64",
            spriteheight: "64",
            getShape: function(){
                return(new me.Rect(0, 0, 64, 64)).toPolygon();
            }
        }]);
       this.body.setVelocity(5, 20);
       //keeps track of which direction your character is going
       this.facing = "right";
       this.now = new Date().getTime();
       this.lastHit = this.now;
       this.lastAttack = new Date().getTime();  //Haven't used this
       me.game.viewport.follow(this.pos, me.game.viewport.AXIS.BOTH);

       this.renderable.addAnimation("idle", [78]);
       this.renderable.addAnimation("walk", [117, 118, 119, 120, 121, 122, 123, 124, 125], 80);
       this.renderable.addAnimation("attack", [65, 66, 67, 68, 69, 70, 71, 72], 80);

       this.renderable.setCurrentAnimation("idle");
    },

    update: function(delta){
        this.now = new Date().getTime();
        if(me.input.isKeyPressed("right")){
            //adds the position of my x by the velocity defined above in
            //setVelocity and multiplying it by me.timer.tick
            //me.timer.tick makes movement look smooth
            this.body.vel.x += this.body.accel.x * me.timer.tick;
            this.facing = "right";
            this.flipX(true);
        }else if(me.input.isKeyPressed("left")){
            this.facing = "left";
            this.body.vel.x -=this.body.accel.x * me.timer.tick;
            this.flipX(false);
        }else{
            this.body.vel.x = 0;
        }
        //i made the character go left when the left key is pressed
        if(me.input.isKeyPressed("jump") && !this.body.jumping && !this.body.falling){
            this.jumping = true;
            this.body.vel.y -= this.body.accel.y * me.timer.tick;
        }
        //i am making the character jump when i press the space button
        if(me.input.isKeyPressed("attack")){
            if(!this.renderable.isCurrentAnimation("attack")){
                console.log(this.renderable.isCurrentAnimation("attack"));
                //sets the current animation to attack and once that is over
                //goes back to the idle animation
                this.renderable.setCurrentAnimation("attack", "idle");
                //makes it so the next time we start this sequence we begin
                //from the first animation, not from wherever we left off when we
                //switched to another animation
                this.renderable.setAnimationFrame();
            }
        }

        else if(this.body.vel.x !== 0 && !this.renderable.isCurrentAnimation("attack")) {
             if(!this.renderable.isCurrentAnimation("walk")){
                 this.renderable.setCurrentAnimation("walk");
        }
        }else if(!this.renderable.isCurrentAnimation("attack")){
           this.renderable.setCurrentAnimation("idle");
        }

        me.collision.check(this, true, this.collideHandler.bind(this), true);
        this.body.update(delta);

        this._super(me.Entity, "update", [delta]);
        return true;
    },

    collideHandler: function(response){
        if(response.b.type==='EnemyBaseEntity'){
            var ydif = this.pos.y - response.b.pos.y;
            var xdif = this.pos.x - response.b.pos.x;

            if(ydif<-40 && xdif< 70 && xdif>-35){
                this.body.falling = false;
                this.body.vel.y = -1;
            }
            else if(xdif>-35 && this.facing==='right' && (xdif<0)){
                this.body.vel.x = 0;
                this.pos.x = this.pos.x -1;
            }else if(xdif<70 && this.facing==='left' && (xdif>0)){
                this.body.vel.x = 0;
                this.pos.x = this.pos.x +1;
            }

            if(this.renderable.isCurrentAnimation("attack") && this.now-this.lastHit >= 1000){
                console.log("tower Hit");
                this.lastHit = this.now;
                response.b.loseHealth();
            }
        }
    }
});

game.PlayerBaseEntity = me.Entity.extend({
    init : function(x, y, settings){
        this._super(me.Entity, 'init', [x, y, {
            image: "tower",
            width: 100,
            height: 100,
            spritewidth: "100",
            spriteheight: "100",
            getShape: function(){
                return (new me.Rect(0, 0, 100, 70)).toPolygon();
            }
        }]);
        this.broken = false;
        this.health = 10;
        this.alwaysUpdate = true;
        this.body.onCollision = this.onCollision.bind(this);
        console.log("init");
        this.type = "PlayerBaseEntity";

        this.renderable.addAnimation("idle", [0]);
        this.renderable.addAnimation("broken", [1]);
        this.renderable.setCurrentAnimation("idle");
    },

    update:function(delta){
        if(this.health<=0){
            this.broken = true;
            this.renderable.setCurrentAnimation("broken");
        }
        this.body.update(delta);

        this._super(me.Entity, "update", [delta]);
        return true;
    },

    onCollision: function(){

    }

});

game.EnemyBaseEntity = me.Entity.extend({
    init : function(x, y, settings){
        this._super(me.Entity, 'init', [x, y, {
            image: "tower",
            width: 100,
            height: 100,
            spritewidth: "100",
            spriteheight: "100",
            getShape: function(){
                return (new me.Rect(0, 0, 100, 70)).toPolygon();
            }
        }]);
        this.broken = false;
        this.health = 10;
        this.alwaysUpdate = true;
        this.body.onCollision = this.onCollision.bind(this);
        this.type = "EnemyBaseEntity";

        this.renderable.addAnimation("idle", [0]);
        this.renderable.addAnimation("broken", [1]);
        this.renderable.setCurrentAnimation("idle");
    },

    update:function(delta){
        if(this.health<=0){
            this.broken = true;
            this.renderable.setCurrentAnimation("broken");
        }
        this.body.update(delta);

        this._super(me.Entity, "update", [delta]);
        return true;
    },

    onCollision: function(){

    },

    loseHealth: function(){
        this.health--;
    }

});

game.EnemyCreep = me.Entity.extend({
    init: function(x, y, settings){
        this._super(me.Entity, 'init', [x, y, {
            image: "creep1",
            width: 32,
            height: 64,
            spritewidth: "32",
            spriteheight: "64",
            getShape: function(){
                return (new me.Rect(0, 0, 32, 64)).toPolygon();
            }
        }]);
        this.health = 10;
        this.alwaysUpdate = true;

        this.body.setVelocity(3, 20);

        this.type = "EnemyCreep";

        this.renderable.addAnimation("walk", [3, 4, 5], 80);
        this.renderable.setCurrentAnimation("walk");

    },

    update: function(){
        return true;
    }
});

game.GameManager = Object.extend({
    init: function(x, y, settings){
        this.now = new Date().getTime();
        this.lastCreep = new Date().getTime();

        this.alwaysUpdate = true;
    },

    update: function(){
        this.now = new Date().getTime();

        if(Math.round(this.now/1000)%10 ===0 && (this.now - this.lastCreep >= 1000)){
            this.lastCreep = this.now;
            var creepe = me.pool.pull("EnemyCreep", 1000, 0, {});
            me.game.world.addChild(creepe, 5);
        }

        return true;
    }
});

<commit_msg>coded video 20 and everything works<commit_after>game.PlayerEntity = me.Entity.extend({
    init: function(x, y, settings){
        this._super(me.Entity, 'init', [x, y, {
            image: "player",
            width: 64,
            height: 64,
            spritewidth: "64",
            spriteheight: "64",
            getShape: function(){
                return(new me.Rect(0, 0, 64, 64)).toPolygon();
            }
        }]);
       this.body.setVelocity(5, 20);
       //keeps track of which direction your character is going
       this.facing = "right";
       this.now = new Date().getTime();
       this.lastHit = this.now;
       this.lastAttack = new Date().getTime();  //Haven't used this
       me.game.viewport.follow(this.pos, me.game.viewport.AXIS.BOTH);

       this.renderable.addAnimation("idle", [78]);
       this.renderable.addAnimation("walk", [117, 118, 119, 120, 121, 122, 123, 124, 125], 80);
       this.renderable.addAnimation("attack", [65, 66, 67, 68, 69, 70, 71, 72], 80);

       this.renderable.setCurrentAnimation("idle");
    },

    update: function(delta){
        this.now = new Date().getTime();
        if(me.input.isKeyPressed("right")){
            //adds the position of my x by the velocity defined above in
            //setVelocity and multiplying it by me.timer.tick
            //me.timer.tick makes movement look smooth
            this.body.vel.x += this.body.accel.x * me.timer.tick;
            this.facing = "right";
            this.flipX(true);
        }else if(me.input.isKeyPressed("left")){
            this.facing = "left";
            this.body.vel.x -=this.body.accel.x * me.timer.tick;
            this.flipX(false);
        }else{
            this.body.vel.x = 0;
        }
        //i made the character go left when the left key is pressed
        if(me.input.isKeyPressed("jump") && !this.body.jumping && !this.body.falling){
            this.jumping = true;
            this.body.vel.y -= this.body.accel.y * me.timer.tick;
        }
        //i am making the character jump when i press the space button
        if(me.input.isKeyPressed("attack")){
            if(!this.renderable.isCurrentAnimation("attack")){
                console.log(this.renderable.isCurrentAnimation("attack"));
                //sets the current animation to attack and once that is over
                //goes back to the idle animation
                this.renderable.setCurrentAnimation("attack", "idle");
                //makes it so the next time we start this sequence we begin
                //from the first animation, not from wherever we left off when we
                //switched to another animation
                this.renderable.setAnimationFrame();
            }
        }

        else if(this.body.vel.x !== 0 && !this.renderable.isCurrentAnimation("attack")) {
             if(!this.renderable.isCurrentAnimation("walk")){
                 this.renderable.setCurrentAnimation("walk");
        }
        }else if(!this.renderable.isCurrentAnimation("attack")){
           this.renderable.setCurrentAnimation("idle");
        }

        me.collision.check(this, true, this.collideHandler.bind(this), true);
        this.body.update(delta);

        this._super(me.Entity, "update", [delta]);
        return true;
    },

    collideHandler: function(response){
        if(response.b.type==='EnemyBaseEntity'){
            var ydif = this.pos.y - response.b.pos.y;
            var xdif = this.pos.x - response.b.pos.x;

            if(ydif<-40 && xdif< 70 && xdif>-35){
                this.body.falling = false;
                this.body.vel.y = -1;
            }
            else if(xdif>-35 && this.facing==='right' && (xdif<0)){
                this.body.vel.x = 0;
                this.pos.x = this.pos.x -1;
            }else if(xdif<70 && this.facing==='left' && (xdif>0)){
                this.body.vel.x = 0;
                this.pos.x = this.pos.x +1;
            }

            if(this.renderable.isCurrentAnimation("attack") && this.now-this.lastHit >= 1000){
                console.log("tower Hit");
                this.lastHit = this.now;
                response.b.loseHealth();
            }
        }
    }
});

game.PlayerBaseEntity = me.Entity.extend({
    init : function(x, y, settings){
        this._super(me.Entity, 'init', [x, y, {
            image: "tower",
            width: 100,
            height: 100,
            spritewidth: "100",
            spriteheight: "100",
            getShape: function(){
                return (new me.Rect(0, 0, 100, 70)).toPolygon();
            }
        }]);
        this.broken = false;
        this.health = 10;
        this.alwaysUpdate = true;
        this.body.onCollision = this.onCollision.bind(this);
        console.log("init");
        this.type = "PlayerBaseEntity";

        this.renderable.addAnimation("idle", [0]);
        this.renderable.addAnimation("broken", [1]);
        this.renderable.setCurrentAnimation("idle");
    },

    update:function(delta){
        if(this.health<=0){
            this.broken = true;
            this.renderable.setCurrentAnimation("broken");
        }
        this.body.update(delta);

        this._super(me.Entity, "update", [delta]);
        return true;
    },

    onCollision: function(){

    }

});

game.EnemyBaseEntity = me.Entity.extend({
    init : function(x, y, settings){
        this._super(me.Entity, 'init', [x, y, {
            image: "tower",
            width: 100,
            height: 100,
            spritewidth: "100",
            spriteheight: "100",
            getShape: function(){
                return (new me.Rect(0, 0, 100, 70)).toPolygon();
            }
        }]);
        this.broken = false;
        this.health = 10;
        this.alwaysUpdate = true;
        this.body.onCollision = this.onCollision.bind(this);
        this.type = "EnemyBaseEntity";

        this.renderable.addAnimation("idle", [0]);
        this.renderable.addAnimation("broken", [1]);
        this.renderable.setCurrentAnimation("idle");
    },

    update:function(delta){
        if(this.health<=0){
            this.broken = true;
            this.renderable.setCurrentAnimation("broken");
        }
        this.body.update(delta);

        this._super(me.Entity, "update", [delta]);
        return true;
    },

    onCollision: function(){

    },

    loseHealth: function(){
        this.health--;
    }

});

game.EnemyCreep = me.Entity.extend({
    init: function(x, y, settings){
        this._super(me.Entity, 'init', [x, y, {
            image: "creep1",
            width: 32,
            height: 64,
            spritewidth: "32",
            spriteheight: "64",
            getShape: function(){
                return (new me.Rect(0, 0, 32, 64)).toPolygon();
            }
        }]);
        this.health = 10;
        this.alwaysUpdate = true;

        this.body.setVelocity(3, 20);

        this.type = "EnemyCreep";

        this.renderable.addAnimation("walk", [3, 4, 5], 80);
        this.renderable.setCurrentAnimation("walk");

    },

    update: function(delta){

    	this.body.vel.x -= this.body.accel.x * me.timer.tick;

    	this.body.update(delta);

        this._super(me.Entity, "update", [delta]);

        return true;
    }
});

game.GameManager = Object.extend({
    init: function(x, y, settings){
        this.now = new Date().getTime();
        this.lastCreep = new Date().getTime();

        this.alwaysUpdate = true;
    },

    update: function(){
        this.now = new Date().getTime();

        if(Math.round(this.now/1000)%10 ===0 && (this.now - this.lastCreep >= 1000)){
            this.lastCreep = this.now;
            var creepe = me.pool.pull("EnemyCreep", 1000, 0, {});
            me.game.world.addChild(creepe, 5);
        }

        return true;
    }
});

<|endoftext|>


<commit_before>/*
 * Chrome-Last.fm-Scrobbler Slacker.com Connector
 *
 * Uses Jordan Perr's pandora connector as a template --- http://jperr.com --- jordan[at]jperr[dot]com
 *
 * Joe Crawford joe@artlung.com
 */

/********* Configuration: ***********/

// changes to the DOM in this container will trigger an update.
LFM_WATCHED_CONTAINER = "div#track-metadata";

function LFM_IS_A_SONG() {
	return !$("#mini-track-name").hasClass("noClick");
}

// function that returns title of current song
function LFM_TRACK_TITLE() {
	return $("#mini-track-name").text();
}

// function that returns artist of current song
function LFM_TRACK_ARTIST() {
	return $("#mini-artist-name").text();
}

// function that returns artist of current song
function LFM_TRACK_ALBUM() {
	return false; // currently no way to get name of currently playing track
}

// function that returns duration of current song in seconds
// called at begining of song
function LFM_TRACK_DURATION() {
	durationArr = $('#progress-total').text().split(":");
	return parseInt(durationArr[0], 10)*60 + parseInt(durationArr[1], 10);
}

/********* Connector: ***********/

var LFM_lastTrack = "";
var LFM_isWaiting = 0;

function LFM_updateNowPlaying(){
	// Acquire data from page
	title = LFM_TRACK_TITLE();
	artist = LFM_TRACK_ARTIST();
	duration = LFM_TRACK_DURATION();
	album = LFM_TRACK_ALBUM();
	newTrack = title + " " + artist;
	isASong = LFM_IS_A_SONG();
	// Update scrobbler if necessary
	if (isASong && newTrack != " " && newTrack != LFM_lastTrack){
		if (duration === 0) {
			// Nasty workaround for delayed duration visiblity with skipped tracks.
			setTimeout(LFM_updateNowPlaying, 5000);
			return 0;
		}
		console.log("submitting a now playing request. artist: "+artist+", title: "+title+", duration: "+duration);
		LFM_lastTrack = newTrack;
		chrome.runtime.sendMessage({type: 'validate', artist: artist, track: title}, function(response) {
			if (response !== false) {
				if (album) { // only if we really have an album again sometime
					chrome.runtime.sendMessage({type: 'nowPlaying', artist: artist, track: title, duration: duration, album: album});
				} else {
					chrome.runtime.sendMessage({type: 'nowPlaying', artist: artist, track: title, duration: duration});
				}
			} else { // on failure send nowPlaying 'unknown song'
				chrome.runtime.sendMessage({type: 'nowPlaying', duration: duration});
			}
		});
	}
	LFM_isWaiting = 0;
}

// Run at startup
$(function(){
	console.log("Slacker module starting up");

	$(LFM_WATCHED_CONTAINER).live('DOMSubtreeModified', function(e) {
		//console.log("Live watcher called");
		if ($(LFM_WATCHED_CONTAINER).length > 0) {
			if(LFM_isWaiting === 0){
				LFM_isWaiting = 1;
				setTimeout(LFM_updateNowPlaying, 10000);
			}
			return;
		}
	});

	$(window).unload(function() {
		chrome.runtime.sendMessage({type: 'reset'});
		return true;
	});
});
<commit_msg>Slacker not scrobbling (New interface) #511<commit_after>/*jslint sloppy: true */
/*global LFM_WATCHED_CONTAINER:true, $ */
/*member length, text, split, log, chrome, runtime, sendMessage, live, unload,
artist, track, duration, album, type, hasClass */
/*
 * Chrome-Last.fm-Scrobbler Slacker.com Connector
 *
 * Uses Jordan Perr's pandora connector as a template --- http://jperr.com --- jordan[at]jperr[dot]com
 *
 * Joe Crawford joe@artlung.com
 */

/********* Configuration: ***********/

// changes to the DOM in this container will trigger an update.
var SITE_VERSION;
var SITE_VERSION_4 = 4;
var SITE_VERSION_6 = 6;

function LFM_WATCHED_CONTAINER() {
 return (SITE_VERSION === SITE_VERSION_6) ? 'section.mini' : 'div#track-metadata';
}

function LFM_IS_A_SONG() {
	if (SITE_VERSION === SITE_VERSION_6) {
		return ($('ul[id=tuning]:visible li a.disabled:visible').length === 0);
	} else if (SITE_VERSION === SITE_VERSION_4) {
		return !$('#mini-track-name').hasClass('noClick');
	}
}

// function that returns title of current song
function LFM_TRACK_TITLE() {
	if (SITE_VERSION === SITE_VERSION_6) {
		return $('.metadata:visible span.link:eq(1)').text();
	} else if (SITE_VERSION === SITE_VERSION_4) {
		return $('#mini-track-name').text();
	}
}

// function that returns artist of current song
function LFM_TRACK_ARTIST() {
	if (SITE_VERSION === SITE_VERSION_6) {
		return $('.metadata:visible span.link:eq(0)').text();
	} else if (SITE_VERSION === SITE_VERSION_4) {
		return $('#mini-artist-name').text();
	}}

// function that returns artist of current song
function LFM_TRACK_ALBUM() {
	return false; // currently no way to get name of currently playing track
}

// function that returns duration of current song in seconds
// called at begining of song
function LFM_TRACK_DURATION() {
	var durationArr;
	if (SITE_VERSION === SITE_VERSION_6) {
		durationArr = $('#progressContainer span:first').text().split(':');
	} else if (SITE_VERSION === SITE_VERSION_4) {
		durationArr = $('#progress-total').text().split(':');
	}
	return parseInt(durationArr[0], 10)*60 + parseInt(durationArr[1], 10);
}

/********* Connector: ***********/

var LFM_lastTrack = '';
var LFM_isWaiting = 0;

var title, artist, duration, album, newTrack, isASong;

function LFM_updateNowPlaying(){
	// Acquire data from page
	title = LFM_TRACK_TITLE();
	artist = LFM_TRACK_ARTIST();
	duration = LFM_TRACK_DURATION();
	album = LFM_TRACK_ALBUM();
	newTrack = title + '' + artist;
	isASong = LFM_IS_A_SONG();
	console.log('=====================================================================');
	console.log(title, artist, duration, album, newTrack, isASong);
	console.log('=====================================================================');

	// Update scrobbler if necessary
	if (isASong && newTrack != ' ' && newTrack != LFM_lastTrack){
		if (duration === 0) {
			// Nasty workaround for delayed duration visiblity with skipped tracks.
			setTimeout(LFM_updateNowPlaying, 5000);
			return 0;
		}
		console.log('=====================================================================');
		console.log('submitting a now playing request. artist: '+ artist + ', title: '+ title +', duration: ' + duration);
		console.log('=====================================================================');
		LFM_lastTrack = newTrack;
		chrome.runtime.sendMessage({type: 'validate', artist: artist, track: title}, function(response) {
			if (response !== false) {
				if (album) { // only if we really have an album again sometime
					chrome.runtime.sendMessage({type: 'nowPlaying', artist: artist, track: title, duration: duration, album: album});
				} else {
					chrome.runtime.sendMessage({type: 'nowPlaying', artist: artist, track: title, duration: duration});
				}
			} else { // on failure send nowPlaying 'unknown song'
				chrome.runtime.sendMessage({type: 'nowPlaying', duration: duration});
			}
		});
	}
	LFM_isWaiting = 0;
}

// Run at startup
$(function(){
	console.log('=====================================================================');
	console.log('Slacker LAST.FM Scrobbler module starting up');
	if ($('section').length > 0) {
		SITE_VERSION = SITE_VERSION_6;
	} else {
		SITE_VERSION = SITE_VERSION_4;
	}
	console.log('Slacker LAST.FM Scrobbler for Site Version ' + SITE_VERSION);
	console.log('=====================================================================');
	$(LFM_WATCHED_CONTAINER()).live('DOMSubtreeModified', function() {

		if ($(LFM_WATCHED_CONTAINER).length > 0) {
			if(LFM_isWaiting === 0){
				LFM_isWaiting = 1;
				setTimeout(LFM_updateNowPlaying, 10000);
			}
			return;
		}
	});

	$(window).unload(function() {
		chrome.runtime.sendMessage({type: 'reset'});
		return true;
	});
});
<|endoftext|>


<commit_before>import Ember from 'ember';
import Analytics from 'ember-osf/mixins/analytics';

/**
 * @module ember-preprints
 * @submodule controllers
 */

/**
 * @class Discover Controller
 *
 * Most of the discover page is built using the discover-page component in ember-osf. The component is largely based on
 * SHARE's discover interface (https://github.com/CenterForOpenScience/ember-share/blob/develop/app/controllers/discover.js) and
 * the existing preprints interface
 */

export default Ember.Controller.extend(Analytics, {
    i18n: Ember.inject.service(),
    theme: Ember.inject.service(),
    activeFilters: { providers: [], subjects: [] },
    additionalProviders: Ember.computed('themeProvider', function() { // Do additionalProviders exist?
        // for now, using this property to alter many pieces of the landing/discover page
        return (this.get('themeProvider.additionalProviders') || []).length > 1;
    }),
    consumingService: 'preprints', // Consuming service - preprints here
    detailRoute: 'content', // Name of detail route for this application
    discoverHeader: Ember.computed('i18n', 'additionalProviders', function() { // Header for preprints discover page
        // If additionalProviders, use more generic Repository Search page title
        return this.get('additionalProviders') ? this.get('i18n').t('discover.search.heading_repository_search') : this.get('i18n').t('discover.search.heading');
    }),
    end: '', // End query param. Must be passed to component, so can be reflected in the URL
    externalProviders: Ember.computed('model', function() {
        return this.get('model').filter(item => item.id !== 'osf');
    }),
    facets: Ember.computed('i18n.locale', 'additionalProviders', function() { // List of facets available for preprints
        if (this.get('additionalProviders')) { // if additionalProviders exist, use subset of SHARE facets
            return [
                { key: 'sources', title: this.get('i18n').t('discover.main.source'), component: 'search-facet-source'},
                { key: 'date', title: this.get('i18n').t('discover.main.date'), component: 'search-facet-daterange'},
                { key: 'type', title: this.get('i18n').t('discover.main.type'), component: 'search-facet-worktype'},
                { key: 'tags', title: this.get('i18n').t('discover.main.tag'), component: 'search-facet-typeahead'},
            ];
        } else { // Regular preprints and branded preprints get provider and taxonomy facets
            return [
                { key: 'sources', title: `${this.get('i18n').t('discover.main.providers')}`, component: 'search-facet-provider' },
                { key: 'subjects', title: `${this.get('i18n').t('discover.main.subject')}`, component: 'search-facet-taxonomy' }
            ]
        }
    }),
    filterMap: { // Map active filters to facet names expected by SHARE
        providers: 'sources',
        subjects: 'subjects'
    },
    filterReplace: { // Map filter names for front-end display
        'Open Science Framework': 'OSF',
        'Cognitive Sciences ePrint Archive': 'Cogprints',
        OSF: 'OSF Preprints',
        'Research Papers in Economics': 'RePEc'
    },
    lockedParams: Ember.computed('additionalProviders', function() { // Query parameters that cannot be changed.
        // if additionalProviders, open up search results to all types of results instead of just preprints.
        return this.get('additionalProviders') ? {} : {types: 'preprint'};
    }),
    page: 1, // Page query param. Must be passed to component, so can be reflected in URL
    provider: '', // Provider query param. Must be passed to component, so can be reflected in URL
    q: '', // q query param.  Must be passed to component, so can be reflected in URL
    queryParams: ['page', 'q', 'sources', 'tags', 'type', 'start', 'end', 'subject', 'provider'], // Pass in the list of queryParams for this component
    searchPlaceholder: Ember.computed('additionalProviders', function() { // Search bar placeholder
        return this.get('additionalProviders') ? 'discover.search.repository_placeholder': 'discover.search.placeholder';
    }),
    showActiveFilters: Ember.computed('additionalProviders', function() {  // Whether Active Filters should be displayed.
        // additionalProviders are using SHARE facets which do not work with Active Filters at this time
        return !this.get('additionalProviders');
    }),
    sortOptions: Ember.computed('i18n.locale', function() { // Sort options for preprints
        const i18n = this.get('i18n');
        return [{
            display: i18n.t('discover.relevance'),
            sortBy: ''
        }, {
            display: i18n.t('discover.sort_oldest_newest'),
            sortBy: 'date_updated'
        }, {
            display: i18n.t('discover.sort_newest_oldest'),
            sortBy: '-date_updated'
        }];
    }),
    sources: '', // Sources query param. Must be passed to component, so can be reflected in the URL
    start: '', // Start query param. Must be passed to component, so can be reflected in the URL
    subject: '', // Subject query param.  Must be passed to component, so can be reflected in URL
    tags: '', // Tags query param.  Must be passed to component, so can be reflected in URL
    themeProvider: Ember.computed('model', function() { // Pulls the preprint provider from the already loaded model
        let themeProvider = null;
        this.get('model').forEach(provider => {
            if (provider.id === this.get('theme.id')) {
                themeProvider = provider;
            }
        });
        return themeProvider;
    }),
    type: '', //Type query param. Must be passed to component, so can be reflected in URL
    _clearFilters() {
        this.set('activeFilters', {
            providers: [],
            subjects: []
        });
        this.set('provider', '');
        this.set('subject', '');
    },
    _clearQueryString() {
        this.set('q', '');
    }
});
<commit_msg>Pass in key instead of t<commit_after>import Ember from 'ember';
import Analytics from 'ember-osf/mixins/analytics';

/**
 * @module ember-preprints
 * @submodule controllers
 */

/**
 * @class Discover Controller
 *
 * Most of the discover page is built using the discover-page component in ember-osf. The component is largely based on
 * SHARE's discover interface (https://github.com/CenterForOpenScience/ember-share/blob/develop/app/controllers/discover.js) and
 * the existing preprints interface
 */

export default Ember.Controller.extend(Analytics, {
    i18n: Ember.inject.service(),
    theme: Ember.inject.service(),
    activeFilters: { providers: [], subjects: [] },
    additionalProviders: Ember.computed('themeProvider', function() { // Do additionalProviders exist?
        // for now, using this property to alter many pieces of the landing/discover page
        return (this.get('themeProvider.additionalProviders') || []).length > 1;
    }),
    consumingService: 'preprints', // Consuming service - preprints here
    detailRoute: 'content', // Name of detail route for this application
    discoverHeader: Ember.computed('additionalProviders', function() { // Header for preprints discover page
        // If additionalProviders, use more generic Repository Search page title
        return this.get('additionalProviders') ? 'discover.search.heading_repository_search' : 'discover.search.heading';
    }),
    end: '', // End query param. Must be passed to component, so can be reflected in the URL
    externalProviders: Ember.computed('model', function() {
        return this.get('model').filter(item => item.id !== 'osf');
    }),
    facets: Ember.computed('i18n.locale', 'additionalProviders', function() { // List of facets available for preprints
        if (this.get('additionalProviders')) { // if additionalProviders exist, use subset of SHARE facets
            return [
                { key: 'sources', title: this.get('i18n').t('discover.main.source'), component: 'search-facet-source'},
                { key: 'date', title: this.get('i18n').t('discover.main.date'), component: 'search-facet-daterange'},
                { key: 'type', title: this.get('i18n').t('discover.main.type'), component: 'search-facet-worktype'},
                { key: 'tags', title: this.get('i18n').t('discover.main.tag'), component: 'search-facet-typeahead'},
            ];
        } else { // Regular preprints and branded preprints get provider and taxonomy facets
            return [
                { key: 'sources', title: `${this.get('i18n').t('discover.main.providers')}`, component: 'search-facet-provider' },
                { key: 'subjects', title: `${this.get('i18n').t('discover.main.subject')}`, component: 'search-facet-taxonomy' }
            ]
        }
    }),
    filterMap: { // Map active filters to facet names expected by SHARE
        providers: 'sources',
        subjects: 'subjects'
    },
    filterReplace: { // Map filter names for front-end display
        'Open Science Framework': 'OSF',
        'Cognitive Sciences ePrint Archive': 'Cogprints',
        OSF: 'OSF Preprints',
        'Research Papers in Economics': 'RePEc'
    },
    lockedParams: Ember.computed('additionalProviders', function() { // Query parameters that cannot be changed.
        // if additionalProviders, open up search results to all types of results instead of just preprints.
        return this.get('additionalProviders') ? {} : {types: 'preprint'};
    }),
    page: 1, // Page query param. Must be passed to component, so can be reflected in URL
    provider: '', // Provider query param. Must be passed to component, so can be reflected in URL
    q: '', // q query param.  Must be passed to component, so can be reflected in URL
    queryParams: ['page', 'q', 'sources', 'tags', 'type', 'start', 'end', 'subject', 'provider'], // Pass in the list of queryParams for this component
    searchPlaceholder: Ember.computed('additionalProviders', function() { // Search bar placeholder
        return this.get('additionalProviders') ? 'discover.search.repository_placeholder': 'discover.search.placeholder';
    }),
    showActiveFilters: Ember.computed('additionalProviders', function() {  // Whether Active Filters should be displayed.
        // additionalProviders are using SHARE facets which do not work with Active Filters at this time
        return !this.get('additionalProviders');
    }),
    sortOptions: Ember.computed('i18n.locale', function() { // Sort options for preprints
        const i18n = this.get('i18n');
        return [{
            display: i18n.t('discover.relevance'),
            sortBy: ''
        }, {
            display: i18n.t('discover.sort_oldest_newest'),
            sortBy: 'date_updated'
        }, {
            display: i18n.t('discover.sort_newest_oldest'),
            sortBy: '-date_updated'
        }];
    }),
    sources: '', // Sources query param. Must be passed to component, so can be reflected in the URL
    start: '', // Start query param. Must be passed to component, so can be reflected in the URL
    subject: '', // Subject query param.  Must be passed to component, so can be reflected in URL
    tags: '', // Tags query param.  Must be passed to component, so can be reflected in URL
    themeProvider: Ember.computed('model', function() { // Pulls the preprint provider from the already loaded model
        let themeProvider = null;
        this.get('model').forEach(provider => {
            if (provider.id === this.get('theme.id')) {
                themeProvider = provider;
            }
        });
        return themeProvider;
    }),
    type: '', //Type query param. Must be passed to component, so can be reflected in URL
    _clearFilters() {
        this.set('activeFilters', {
            providers: [],
            subjects: []
        });
        this.set('provider', '');
        this.set('subject', '');
    },
    _clearQueryString() {
        this.set('q', '');
    }
});
<|endoftext|>


<commit_before>var dfu = {};

(function() {
    'use strict';

    dfu.DETACH = 0x00;
    dfu.DNLOAD = 0x01;
    dfu.UPLOAD = 0x02;
    dfu.GETSTATUS = 0x03;
    dfu.CLRSTATUS = 0x04;
    dfu.GETSTATE = 0x05;
    dfu.ABORT = 6;

    dfu.appIDLE = 0;
    dfu.appDETACH = 1;
    dfu.dfuIDLE = 2;
    dfu.dfuDNLOAD_SYNC = 3;
    dfu.dfuDNBUSY = 4;
    dfu.dfuDNLOAD_IDLE = 5;
    dfu.dfuMANIFEST_SYNC = 6;
    dfu.dfuMANIFEST = 7;
    dfu.dfuMANIFEST_WAIT_RESET = 8;
    dfu.dfuUPLOAD_IDLE = 9;
    dfu.dfuERROR = 10;

    dfu.Device = function(device, settings) {
        this.device_ = device;
        this.settings = settings;
        this.intfNumber = settings["interface"].interfaceNumber;
    };

    dfu.findDeviceDfuInterfaces = function(device) {
        let interfaces = [];
        for (let conf of device.configurations) {
            for (let intf of conf.interfaces) {
                for (let alt of intf.alternates) {
                    if (alt.interfaceClass == 0xFE &&
                        alt.interfaceSubclass == 0x01 &&
                        (alt.interfaceProtocol == 0x01 || alt.interfaceProtocol == 0x02)) {
                        let settings = {
                            "configuration": conf,
                            "interface": intf,
                            "alternate": alt
                        };
                        interfaces.push(settings);
                    }
                }
            }
        }

        return interfaces;
    }

    dfu.findAllDfuInterfaces = function() {
        return navigator.usb.getDevices().then(
            devices => {
                let matches = [];
                for (let device of devices) {
                    let interfaces = dfu.findDeviceDfuInterfaces(device);
                    for (let interface_ of interfaces) {
                        matches.push(new dfu.Device(device, interface_))
                    }
                }
                return matches;
            }
        )
    };

    dfu.Device.prototype.logDebug = function(msg) {

    };

    dfu.Device.prototype.logInfo = function(msg) {
        console.log(msg);
    };

    dfu.Device.prototype.logWarning = function(msg) {
        console.log(msg);
    };

    dfu.Device.prototype.logError = function(msg) {
        console.log(msg);
    };

    dfu.Device.prototype.logProgress = function(done, total) {
        if (typeof total === 'undefined') {
            console.log(done)
        } else {
            console.log(done + '/' + total);
        }
    };

    dfu.Device.prototype.open = function() {
        return this.device_.open()
            .then(() => {
                const confValue = this.settings.configuration.configurationValue;
                if (this.device_.configuration === null ||
                    this.device_.configuration.configurationValue != confValue) {
                    return this.device_.selectConfiguration(confValue);
                }
            })
            .then(() => {
                const intfNumber = this.settings["interface"].interfaceNumber;
                if (!this.device_.configuration.interfaces[intfNumber].claimed) {
                    return this.device_.claimInterface(intfNumber);
                }
                return Promise.resolve();
            })
            .then(() => {
                const intfNumber = this.settings["interface"].interfaceNumber;
                const altSetting = this.settings.alternate.alternateSetting;
                let intf = this.device_.configuration.interfaces[intfNumber];
                if (intf.alternate === null ||
                    intf.alternate.alternateSetting != altSetting) {
                    return this.device_.selectAlternateInterface(intfNumber, altSetting);
                } else {
                    return Promise.resolve();
                }
            });
    }

    dfu.Device.prototype.close = function() {
        return this.device_.close();
    };

    dfu.Device.prototype.readDeviceDescriptor = function() {
        const GET_DESCRIPTOR = 0x06;
        const DT_DEVICE = 0x01;
        const wValue = (DT_DEVICE << 8);

        return this.device_.controlTransferIn({
            "requestType": "standard",
            "recipient": "device",
            "request": GET_DESCRIPTOR,
            "value": wValue,
            "index": 0
        }, 18).then(
            result => {
                if (result.status == "ok") {
                     return Promise.resolve(result.data);
                } else {
                    return Promise.reject(result.status);
                }
            }
        );
    };

    dfu.parseDeviceDescriptor = function(data) {
        return {
            bLength:            data.getUint8(0),
            bDescriptorType:    data.getUint8(1),
            bcdUSB:             data.getUint16(2, true),
            bDeviceClass:       data.getUint8(4),
            bDeviceSubClass:    data.getUint8(5),
            bDeviceProtocol:    data.getUint8(6),
            bMaxPacketSize:     data.getUint8(7),
            idVendor:           data.getUint16(8, true),
            idProduct:          data.getUint16(10, true),
            bcdDevice:          data.getUint16(12, true),
            iManufacturer:      data.getUint8(14),
            iProduct:           data.getUint8(15),
            iSerialNumber:      data.getUint8(16),
            bNumConfigurations: data.getUint8(17),
        };
    };

    dfu.parseConfigurationDescriptor = function(data) {
        let descriptorData = new DataView(data.buffer.slice(9));
        let descriptors = dfu.parseSubDescriptors(descriptorData);
        return {
            bLength:            data.getUint8(0),
            bDescriptorType:    data.getUint8(1),
            wTotalLength:       data.getUint16(2, true),
            bNumInterfaces:     data.getUint8(4),
            bConfigurationValue:data.getUint8(5),
            iConfiguration:     data.getUint8(6),
            bmAttributes:       data.getUint8(7),
            bMaxPower:          data.getUint8(8),
            descriptors:        descriptors
        };
    };

    dfu.parseInterfaceDescriptor = function(data) {
        return {
            bLength:            data.getUint8(0),
            bDescriptorType:    data.getUint8(1),
            bInterfaceNumber:   data.getUint8(2),
            bAlternateSetting:  data.getUint8(3),
            bNumEndpoints:      data.getUint8(4),
            bInterfaceClass:    data.getUint8(5),
            bInterfaceSubClass: data.getUint8(6),
            bInterfaceProtocol: data.getUint8(7),
            iInterface:         data.getUint8(8),
            descriptors:        []
        };
    };

    dfu.parseFunctionalDescriptor = function(data) {
        return {
            bLength:           data.getUint8(0),
            bDescriptorType:   data.getUint8(1),
            bmAttributes:      data.getUint8(2),
            wDetachTimeOut:    data.getUint16(3, true),
            wTransferSize:     data.getUint16(5, true),
            bcdDFUVersion:     data.getUint16(7, true)
        };
    };

    dfu.parseSubDescriptors = function(descriptorData) {
        const DT_INTERFACE = 4;
        const DT_ENDPOINT = 5;
        const DT_DFU_FUNCTIONAL = 0x21;
        let remainingData = descriptorData;
        let descriptors = [];
        while (remainingData.byteLength > 2) {
            let bLength = remainingData.getUint8(0);
            let bDescriptorType = remainingData.getUint8(1);
            let descData = new DataView(remainingData.buffer.slice(0, bLength));
            if (bDescriptorType == DT_INTERFACE) {
                descriptors.push(dfu.parseInterfaceDescriptor(descData));
            } else if (bDescriptorType == DT_DFU_FUNCTIONAL) {
                descriptors.push(dfu.parseFunctionalDescriptor(descData));
            } else {
                let desc = {
                    bLength: bLength,
                    bDescriptorType: bDescriptorType,
                    data: descData
                };
                descriptors.push(desc);
            }
            remainingData = new DataView(remainingData.buffer.slice(bLength));
        }

        return descriptors;
    };

    dfu.Device.prototype.readConfigurationDescriptor = function(index) {
        const GET_DESCRIPTOR = 0x06;
        const DT_CONFIGURATION = 0x02;
        const wValue = ((DT_CONFIGURATION << 8) | index);

        return this.device_.controlTransferIn({
            "requestType": "standard",
            "recipient": "device",
            "request": GET_DESCRIPTOR,
            "value": wValue,
            "index": 0
        }, 4).then(
            result => {
                if (result.status == "ok") {
                    // Read out length of the configuration descriptor
                    let wLength = result.data.getUint16(2, true);
                    return this.device_.controlTransferIn({
                        "requestType": "standard",
                        "recipient": "device",
                        "request": GET_DESCRIPTOR,
                        "value": wValue,
                        "index": 0
                    }, wLength);
                } else {
                    return Promise.reject(result.status);
                }
            }
        ).then(
            result => {
                if (result.status == "ok") {
                    return Promise.resolve(result.data);
                } else {
                    return Promise.reject(result.status);
                }
            }
        );
    };

    dfu.Device.prototype.requestOut = function(bRequest, data, wValue=0) {
        return this.device_.controlTransferOut({
            "requestType": "class",
            "recipient": "interface",
            "request": bRequest,
            "value": wValue,
            "index": this.intfNumber
        }, data).then(
            result => {
                if (result.status == "ok") {
                    return Promise.resolve(result.bytesWritten);
                } else {
                    return Promise.reject(result.status);
                }
            }
        );
    };

    dfu.Device.prototype.requestIn = function(bRequest, wLength, wValue=0) {
        return this.device_.controlTransferIn({
            "requestType": "class",
            "recipient": "interface",
            "request": bRequest,
            "value": wValue,
            "index": this.intfNumber
        }, wLength).then(
            result => {
                if (result.status == "ok") {
                    return Promise.resolve(result.data);
                } else {
                    return Promise.reject(result.status);
                }
            }
        );
    };

    dfu.Device.prototype.detach = function() {
        return this.requestOut(dfu.DETACH, undefined, 1000);
    };

    dfu.Device.prototype.download = function(data, blockNum) {
        return this.requestOut(dfu.DNLOAD, data, blockNum);
    };

    dfu.Device.prototype.dnload = dfu.Device.prototype.download;

    dfu.Device.prototype.upload = function(length, blockNum) {
        return this.requestIn(dfu.UPLOAD, length, blockNum)
    };

    dfu.Device.prototype.clearStatus = function() {
        return this.requestOut(dfu.CLRSTATUS);
    };

    dfu.Device.prototype.clrStatus = dfu.Device.prototype.clearStatus;

    dfu.Device.prototype.getStatus = function() {
        return this.requestIn(dfu.GETSTATUS, 6).then(
            data => {
                return {
                    "status": data.getUint8(0),
                    "pollTimeout": data.getUint32(1, true) & 0xFFFFFF,
                    "state": data.getUint8(4)
                };
            },
            error => { throw "DFU GETSTATUS failed"; }
        );
    };

    dfu.Device.prototype.getState = function() {
        return this.requestIn(dfu.GETSTATE, 1).then(
            data => data.getUint8(0),
            error => { throw "DFU GETSTATE failed"; }
        );
    };

    dfu.Device.prototype.abort = function() {
        return this.requestOut(dfu.ABORT);
    };

    dfu.Device.prototype.do_upload = function(xfer_size) {
        let transaction = 0;
        let blocks = [];
        let bytes_read = 0;

        this.logInfo("Copying data from DFU device to browser");

        let device = this;
        function upload_success(result) {
            if (result.byteLength > 0) {
                blocks.push(result);
                bytes_read += result.byteLength;
            }

            if (result.byteLength == xfer_size) {
                // Update progress
                device.logProgress(bytes_read);
                return device.upload(xfer_size, transaction++).then(upload_success);
            } else {
                // Update progress
                device.logProgress(bytes_read, bytes_read);
                return Promise.resolve(new Blob(blocks, { type: "application/octet-stream" }));
            }
        }

        // Initialize progress to 0
        device.logProgress(0);

        return device.upload(xfer_size, transaction).then(upload_success);
    };

    dfu.Device.prototype.poll_until_idle = function(result, idleState) {
        if (result.state == idleState || result.state == dfu.dfuERROR) {
            return Promise.resolve(result);
        } else {
            let self = this;
            let deferred = new Promise(function (resolve, reject) {
                function poll_after_sleeping() {
                    resolve(device.getStatus().then(
                        result => self.poll_until_idle(result, idleState),
                        error => { throw "Error during getStatus: " + error; })
                    );
                }
                device.logDebug("Sleeping for " + result.pollTimeout + "ms");
                setTimeout(poll_after_sleeping, result.pollTimeout);
            });
            return deferred;
        }
    };

    dfu.Device.prototype.do_download = function(xfer_size, data) {
        let bytes_sent = 0;
        let expected_size = data.byteLength;
        let transaction = 0;

        this.logInfo("Copying data from browser to DFU device");

        let device = this;
        function poll_until_download_idle(result) {
            return device.poll_until_idle(result, dfu.dfuDNLOAD_IDLE);
        }

        function poll_until_dfu_idle(result) {
            return device.poll_until_idle(result, dfu.dfuIDLE);
        }

        let downloadOperation = new Promise(function (resolve, reject) {
            function download_success(bytes_written) {
                bytes_sent += bytes_written;

                // Update progress
                device.logProgress(bytes_sent, expected_size);

                device.logDebug("Wrote " + bytes_written + " bytes");
                let bytes_left = expected_size - bytes_sent;
                let chunk_size = Math.min(bytes_left, xfer_size);

                device.getStatus().then(poll_until_download_idle).then(
                    result => {
                        if (result.status != 0x0) {
                            throw "DFU DOWNLOAD failed state=${result.state}, status=${result.status}";
                        }
                        return Promise.resolve();
                    }
                ).then(
                    () => {
                        if (bytes_left > 0) {
                            return device.download(data.slice(bytes_sent, bytes_sent+chunk_size), transaction++).then(download_success);
                        } else {
                            device.logDebug("Sending empty block");
                            return device.download(new ArrayBuffer([]), transaction++).then(
                                () => resolve(bytes_sent),
                                error => reject(error)
                            );
                        }
                    }
                )
            }

            // Initialize progress to 0
            device.logProgress(bytes_sent, expected_size);

            device.download(data.slice(0, xfer_size), transaction++).then(download_success);
        });

        return downloadOperation.then(
            bytes_written => {
                device.logInfo("Wrote " + bytes_written + " bytes");
                // Transition to MANIFEST_SYNC state
                device.logInfo("Manifesting new firmware");
                device.getStatus().then(poll_until_dfu_idle).then(
                    result => {
                        if (result.status != 0x0) {
                            throw "DFU MANIFEST failed state=${result.state}, status=${result.status}";
                        }
                        return Promise.resolve();
                    }
                );
            }
        );
    };

})();
<commit_msg>Fix DFU functional descriptor parser bug<commit_after>var dfu = {};

(function() {
    'use strict';

    dfu.DETACH = 0x00;
    dfu.DNLOAD = 0x01;
    dfu.UPLOAD = 0x02;
    dfu.GETSTATUS = 0x03;
    dfu.CLRSTATUS = 0x04;
    dfu.GETSTATE = 0x05;
    dfu.ABORT = 6;

    dfu.appIDLE = 0;
    dfu.appDETACH = 1;
    dfu.dfuIDLE = 2;
    dfu.dfuDNLOAD_SYNC = 3;
    dfu.dfuDNBUSY = 4;
    dfu.dfuDNLOAD_IDLE = 5;
    dfu.dfuMANIFEST_SYNC = 6;
    dfu.dfuMANIFEST = 7;
    dfu.dfuMANIFEST_WAIT_RESET = 8;
    dfu.dfuUPLOAD_IDLE = 9;
    dfu.dfuERROR = 10;

    dfu.Device = function(device, settings) {
        this.device_ = device;
        this.settings = settings;
        this.intfNumber = settings["interface"].interfaceNumber;
    };

    dfu.findDeviceDfuInterfaces = function(device) {
        let interfaces = [];
        for (let conf of device.configurations) {
            for (let intf of conf.interfaces) {
                for (let alt of intf.alternates) {
                    if (alt.interfaceClass == 0xFE &&
                        alt.interfaceSubclass == 0x01 &&
                        (alt.interfaceProtocol == 0x01 || alt.interfaceProtocol == 0x02)) {
                        let settings = {
                            "configuration": conf,
                            "interface": intf,
                            "alternate": alt
                        };
                        interfaces.push(settings);
                    }
                }
            }
        }

        return interfaces;
    }

    dfu.findAllDfuInterfaces = function() {
        return navigator.usb.getDevices().then(
            devices => {
                let matches = [];
                for (let device of devices) {
                    let interfaces = dfu.findDeviceDfuInterfaces(device);
                    for (let interface_ of interfaces) {
                        matches.push(new dfu.Device(device, interface_))
                    }
                }
                return matches;
            }
        )
    };

    dfu.Device.prototype.logDebug = function(msg) {

    };

    dfu.Device.prototype.logInfo = function(msg) {
        console.log(msg);
    };

    dfu.Device.prototype.logWarning = function(msg) {
        console.log(msg);
    };

    dfu.Device.prototype.logError = function(msg) {
        console.log(msg);
    };

    dfu.Device.prototype.logProgress = function(done, total) {
        if (typeof total === 'undefined') {
            console.log(done)
        } else {
            console.log(done + '/' + total);
        }
    };

    dfu.Device.prototype.open = function() {
        return this.device_.open()
            .then(() => {
                const confValue = this.settings.configuration.configurationValue;
                if (this.device_.configuration === null ||
                    this.device_.configuration.configurationValue != confValue) {
                    return this.device_.selectConfiguration(confValue);
                }
            })
            .then(() => {
                const intfNumber = this.settings["interface"].interfaceNumber;
                if (!this.device_.configuration.interfaces[intfNumber].claimed) {
                    return this.device_.claimInterface(intfNumber);
                }
                return Promise.resolve();
            })
            .then(() => {
                const intfNumber = this.settings["interface"].interfaceNumber;
                const altSetting = this.settings.alternate.alternateSetting;
                let intf = this.device_.configuration.interfaces[intfNumber];
                if (intf.alternate === null ||
                    intf.alternate.alternateSetting != altSetting) {
                    return this.device_.selectAlternateInterface(intfNumber, altSetting);
                } else {
                    return Promise.resolve();
                }
            });
    }

    dfu.Device.prototype.close = function() {
        return this.device_.close();
    };

    dfu.Device.prototype.readDeviceDescriptor = function() {
        const GET_DESCRIPTOR = 0x06;
        const DT_DEVICE = 0x01;
        const wValue = (DT_DEVICE << 8);

        return this.device_.controlTransferIn({
            "requestType": "standard",
            "recipient": "device",
            "request": GET_DESCRIPTOR,
            "value": wValue,
            "index": 0
        }, 18).then(
            result => {
                if (result.status == "ok") {
                     return Promise.resolve(result.data);
                } else {
                    return Promise.reject(result.status);
                }
            }
        );
    };

    dfu.parseDeviceDescriptor = function(data) {
        return {
            bLength:            data.getUint8(0),
            bDescriptorType:    data.getUint8(1),
            bcdUSB:             data.getUint16(2, true),
            bDeviceClass:       data.getUint8(4),
            bDeviceSubClass:    data.getUint8(5),
            bDeviceProtocol:    data.getUint8(6),
            bMaxPacketSize:     data.getUint8(7),
            idVendor:           data.getUint16(8, true),
            idProduct:          data.getUint16(10, true),
            bcdDevice:          data.getUint16(12, true),
            iManufacturer:      data.getUint8(14),
            iProduct:           data.getUint8(15),
            iSerialNumber:      data.getUint8(16),
            bNumConfigurations: data.getUint8(17),
        };
    };

    dfu.parseConfigurationDescriptor = function(data) {
        let descriptorData = new DataView(data.buffer.slice(9));
        let descriptors = dfu.parseSubDescriptors(descriptorData);
        return {
            bLength:            data.getUint8(0),
            bDescriptorType:    data.getUint8(1),
            wTotalLength:       data.getUint16(2, true),
            bNumInterfaces:     data.getUint8(4),
            bConfigurationValue:data.getUint8(5),
            iConfiguration:     data.getUint8(6),
            bmAttributes:       data.getUint8(7),
            bMaxPower:          data.getUint8(8),
            descriptors:        descriptors
        };
    };

    dfu.parseInterfaceDescriptor = function(data) {
        return {
            bLength:            data.getUint8(0),
            bDescriptorType:    data.getUint8(1),
            bInterfaceNumber:   data.getUint8(2),
            bAlternateSetting:  data.getUint8(3),
            bNumEndpoints:      data.getUint8(4),
            bInterfaceClass:    data.getUint8(5),
            bInterfaceSubClass: data.getUint8(6),
            bInterfaceProtocol: data.getUint8(7),
            iInterface:         data.getUint8(8),
            descriptors:        []
        };
    };

    dfu.parseFunctionalDescriptor = function(data) {
        return {
            bLength:           data.getUint8(0),
            bDescriptorType:   data.getUint8(1),
            bmAttributes:      data.getUint8(2),
            wDetachTimeOut:    data.getUint16(3, true),
            wTransferSize:     data.getUint16(5, true),
            bcdDFUVersion:     data.getUint16(7, true)
        };
    };

    dfu.parseSubDescriptors = function(descriptorData) {
        const DT_INTERFACE = 4;
        const DT_ENDPOINT = 5;
        const DT_DFU_FUNCTIONAL = 0x21;
        const USB_CLASS_APP_SPECIFIC = 0xFE;
        const USB_SUBCLASS_DFU = 0x01;
        let remainingData = descriptorData;
        let descriptors = [];
        let currIntf;
        let inDfuIntf = false;
        while (remainingData.byteLength > 2) {
            let bLength = remainingData.getUint8(0);
            let bDescriptorType = remainingData.getUint8(1);
            let descData = new DataView(remainingData.buffer.slice(0, bLength));
            if (bDescriptorType == DT_INTERFACE) {
                currIntf = dfu.parseInterfaceDescriptor(descData);
                if (currIntf.bInterfaceClass == USB_CLASS_APP_SPECIFC &&
                    currIntf.bInterfaceSubclass == USB_SUBCLASS_DFU) {
                    inDfuIntf = true;
                } else {
                    inDfuIntf = false;
                }
                descriptors.push(currIntf);
            } else if (inDfuIntf && bDescriptorType == DT_DFU_FUNCTIONAL) {
                descriptors.push(dfu.parseFunctionalDescriptor(descData));
            } else {
                let desc = {
                    bLength: bLength,
                    bDescriptorType: bDescriptorType,
                    data: descData
                };
                descriptors.push(desc);
            }
            remainingData = new DataView(remainingData.buffer.slice(bLength));
        }

        return descriptors;
    };

    dfu.Device.prototype.readConfigurationDescriptor = function(index) {
        const GET_DESCRIPTOR = 0x06;
        const DT_CONFIGURATION = 0x02;
        const wValue = ((DT_CONFIGURATION << 8) | index);

        return this.device_.controlTransferIn({
            "requestType": "standard",
            "recipient": "device",
            "request": GET_DESCRIPTOR,
            "value": wValue,
            "index": 0
        }, 4).then(
            result => {
                if (result.status == "ok") {
                    // Read out length of the configuration descriptor
                    let wLength = result.data.getUint16(2, true);
                    return this.device_.controlTransferIn({
                        "requestType": "standard",
                        "recipient": "device",
                        "request": GET_DESCRIPTOR,
                        "value": wValue,
                        "index": 0
                    }, wLength);
                } else {
                    return Promise.reject(result.status);
                }
            }
        ).then(
            result => {
                if (result.status == "ok") {
                    return Promise.resolve(result.data);
                } else {
                    return Promise.reject(result.status);
                }
            }
        );
    };

    dfu.Device.prototype.requestOut = function(bRequest, data, wValue=0) {
        return this.device_.controlTransferOut({
            "requestType": "class",
            "recipient": "interface",
            "request": bRequest,
            "value": wValue,
            "index": this.intfNumber
        }, data).then(
            result => {
                if (result.status == "ok") {
                    return Promise.resolve(result.bytesWritten);
                } else {
                    return Promise.reject(result.status);
                }
            }
        );
    };

    dfu.Device.prototype.requestIn = function(bRequest, wLength, wValue=0) {
        return this.device_.controlTransferIn({
            "requestType": "class",
            "recipient": "interface",
            "request": bRequest,
            "value": wValue,
            "index": this.intfNumber
        }, wLength).then(
            result => {
                if (result.status == "ok") {
                    return Promise.resolve(result.data);
                } else {
                    return Promise.reject(result.status);
                }
            }
        );
    };

    dfu.Device.prototype.detach = function() {
        return this.requestOut(dfu.DETACH, undefined, 1000);
    };

    dfu.Device.prototype.download = function(data, blockNum) {
        return this.requestOut(dfu.DNLOAD, data, blockNum);
    };

    dfu.Device.prototype.dnload = dfu.Device.prototype.download;

    dfu.Device.prototype.upload = function(length, blockNum) {
        return this.requestIn(dfu.UPLOAD, length, blockNum)
    };

    dfu.Device.prototype.clearStatus = function() {
        return this.requestOut(dfu.CLRSTATUS);
    };

    dfu.Device.prototype.clrStatus = dfu.Device.prototype.clearStatus;

    dfu.Device.prototype.getStatus = function() {
        return this.requestIn(dfu.GETSTATUS, 6).then(
            data => {
                return {
                    "status": data.getUint8(0),
                    "pollTimeout": data.getUint32(1, true) & 0xFFFFFF,
                    "state": data.getUint8(4)
                };
            },
            error => { throw "DFU GETSTATUS failed"; }
        );
    };

    dfu.Device.prototype.getState = function() {
        return this.requestIn(dfu.GETSTATE, 1).then(
            data => data.getUint8(0),
            error => { throw "DFU GETSTATE failed"; }
        );
    };

    dfu.Device.prototype.abort = function() {
        return this.requestOut(dfu.ABORT);
    };

    dfu.Device.prototype.do_upload = function(xfer_size) {
        let transaction = 0;
        let blocks = [];
        let bytes_read = 0;

        this.logInfo("Copying data from DFU device to browser");

        let device = this;
        function upload_success(result) {
            if (result.byteLength > 0) {
                blocks.push(result);
                bytes_read += result.byteLength;
            }

            if (result.byteLength == xfer_size) {
                // Update progress
                device.logProgress(bytes_read);
                return device.upload(xfer_size, transaction++).then(upload_success);
            } else {
                // Update progress
                device.logProgress(bytes_read, bytes_read);
                return Promise.resolve(new Blob(blocks, { type: "application/octet-stream" }));
            }
        }

        // Initialize progress to 0
        device.logProgress(0);

        return device.upload(xfer_size, transaction).then(upload_success);
    };

    dfu.Device.prototype.poll_until_idle = function(result, idleState) {
        if (result.state == idleState || result.state == dfu.dfuERROR) {
            return Promise.resolve(result);
        } else {
            let self = this;
            let deferred = new Promise(function (resolve, reject) {
                function poll_after_sleeping() {
                    resolve(device.getStatus().then(
                        result => self.poll_until_idle(result, idleState),
                        error => { throw "Error during getStatus: " + error; })
                    );
                }
                device.logDebug("Sleeping for " + result.pollTimeout + "ms");
                setTimeout(poll_after_sleeping, result.pollTimeout);
            });
            return deferred;
        }
    };

    dfu.Device.prototype.do_download = function(xfer_size, data) {
        let bytes_sent = 0;
        let expected_size = data.byteLength;
        let transaction = 0;

        this.logInfo("Copying data from browser to DFU device");

        let device = this;
        function poll_until_download_idle(result) {
            return device.poll_until_idle(result, dfu.dfuDNLOAD_IDLE);
        }

        function poll_until_dfu_idle(result) {
            return device.poll_until_idle(result, dfu.dfuIDLE);
        }

        let downloadOperation = new Promise(function (resolve, reject) {
            function download_success(bytes_written) {
                bytes_sent += bytes_written;

                // Update progress
                device.logProgress(bytes_sent, expected_size);

                device.logDebug("Wrote " + bytes_written + " bytes");
                let bytes_left = expected_size - bytes_sent;
                let chunk_size = Math.min(bytes_left, xfer_size);

                device.getStatus().then(poll_until_download_idle).then(
                    result => {
                        if (result.status != 0x0) {
                            throw "DFU DOWNLOAD failed state=${result.state}, status=${result.status}";
                        }
                        return Promise.resolve();
                    }
                ).then(
                    () => {
                        if (bytes_left > 0) {
                            return device.download(data.slice(bytes_sent, bytes_sent+chunk_size), transaction++).then(download_success);
                        } else {
                            device.logDebug("Sending empty block");
                            return device.download(new ArrayBuffer([]), transaction++).then(
                                () => resolve(bytes_sent),
                                error => reject(error)
                            );
                        }
                    }
                )
            }

            // Initialize progress to 0
            device.logProgress(bytes_sent, expected_size);

            device.download(data.slice(0, xfer_size), transaction++).then(download_success);
        });

        return downloadOperation.then(
            bytes_written => {
                device.logInfo("Wrote " + bytes_written + " bytes");
                // Transition to MANIFEST_SYNC state
                device.logInfo("Manifesting new firmware");
                device.getStatus().then(poll_until_dfu_idle).then(
                    result => {
                        if (result.status != 0x0) {
                            throw "DFU MANIFEST failed state=${result.state}, status=${result.status}";
                        }
                        return Promise.resolve();
                    }
                );
            }
        );
    };

})();
<|endoftext|>