<commit_before>/**
 * Player Entity
 */
game.PlayerEntity = me.Entity.extend({

    /**
     * constructor
     */
    init:function (x, y, settings) {
        settings.image = 'pig';
        settings.framewidth = 40;
        settings.frameheight = 40;
        // call the constructor
        this._super(me.Entity, 'init', [x, y , settings]);
        this.name = 'player';

        // shift sprite so that collision box is its bottom
        this.renderable.translate(0, -4);

        // viewport must follow the player
        this.center = this.pos.clone()
                              .add(new me.Vector2d(this.width / 2,
                                                   this.height / 2));
        this.SCROLL_OFFSET_MAX = 30;
        this.SCROLL_OFFSET_SPEED = 1;
        this.SCROLL_OFFSET_INERTIAL_SPEED = 3;
        this.SCROLL_DEADZONE_MAX = 8;
        this.scrollOffset = 0;
        this.scrollDeadzone = 0;
        me.game.viewport.setDeadzone(0, 0);
        me.game.viewport.follow(this.center, me.game.viewport.AXIS.BOTH);

        // we set the velocity of the player's body
        this.WALK_SPEED = 2;
        this.RUN_SPEED = 3;
        this.VERTICAL_SPEED = 9;
        this.body.setVelocity(this.WALK_SPEED, this.VERTICAL_SPEED);

        // we always update the player, ALWAYS
        this.alwaysUpdate = true;

        // setting constants
        this.onAirTime = 100;
        this.JUMP_MAX_AIRBONRNE_TIME = 80;
        this.FLICKERING_TIME = 2000;

        // setting initial direction
        this.direction = new me.Vector2d(1, 0);
        this.knockbacked = false;
        this.powerJumping = false;

        this.carrying = false;

        // animations
        this.renderable.addAnimation('idle', [0, 1, 2], 150);
        this.renderable.addAnimation('walk', [3, 4, 5, 6, 7, 8], 100);
        this.renderable.addAnimation('run', [9, 10, 11, 12, 13, 14], 70);
        this.renderable.addAnimation('jump', [15, 16], 50);
        this.renderable.addAnimation('fall', [18, 19], 50);
        this.renderable.addAnimation('kick', [20, 21, 21, 21], 50);
        this.renderable.addAnimation('stun', [23, 24, 23, 24, 23, 24], 50); // Must blink
        this.renderable.addAnimation('win', [25, 26, 27, 26, 25, 26, 27, 26,
                                             25, 26, 27, 26, 25, 26, 27, 26], 120);
        this.renderable.addAnimation('idle-carry', [28, 29, 30], 150);
        this.renderable.addAnimation('walk-carry', [31, 32, 33, 34, 35, 36], 100);
        this.renderable.addAnimation('run-carry', [37, 38, 39, 40, 41, 42], 50);
        this.renderable.addAnimation('jump-carry', [43, 44], 50);
        this.renderable.addAnimation('fall-carry', [46, 47], 50);
        this.renderable.addAnimation('h-drop', [20, 20], 50);
        this.renderable.addAnimation('v-drop', [48, 48], 50);

        this.setCurrentAnimation('idle');
    },

    setCurrentAnimation: function(name, onComplete) {
        if (!this.renderable.isCurrentAnimation(name)) {
            this.renderable.setCurrentAnimation(name, onComplete);
        }
    },

    flipX: function(flipX) {
        // XXX Should we prevent flipping when kicking or move the kick collision shape?
        if (!this.kicking) {
            this.renderable.flipX(flipX);
        }
    },

     knockback: function (strength, direction) {
         // set state as currently knockbacked
         this.knockbacked = true;

         // set default strength
         strength = strength || 2;
         direction = direction || this.direction;

        // change the velocity
        this.body.vel = new me.Vector2d(-strength * 20 * direction.x, -strength);
    },

    kick: function() {
        if (!this.kicking) {
            this.kicking = true;
            this.body.addShape(new me.Rect(
                this.direction.x < 0 ? -20 : 20,
                15,
                17,
                7
            ));
        }
    },

     hit: function() {
        this.renderable.flicker(this.FLICKERING_TIME);

        // drop the ball
        if (this.carrying) {
            this.dropTheBall();
        }
     },

    /**
     * update the entity
     */
    update : function (dt) {
        // handling movement on the side
        if (me.input.keyStatus('kick') && !this.kicking) {
            this.body.setVelocity(this.RUN_SPEED, this.VERTICAL_SPEED);
        } else {
            this.body.setVelocity(this.WALK_SPEED, this.VERTICAL_SPEED);
        }

        if (!me.input.paused) {
            if (!this.knockbacked) {
                if (me.input.isKeyPressed('left')) {
                    this.flipX(true);
                    this.body.vel.x -= this.body.accel.x * me.timer.tick;
                    this.direction = new me.Vector2d(-1, 0);
                    this.scrollDeadzone -= 1;
                    if(this.scrollDeadzone < -this.SCROLL_DEADZONE_MAX) {
                        this.scrollOffset -= this.SCROLL_OFFSET_SPEED;
                    }
                } else if (me.input.isKeyPressed('right')) {
                    this.flipX(false);
                    this.body.vel.x += this.body.accel.x * me.timer.tick;
                    this.direction = new me.Vector2d(1, 0);
                    this.scrollDeadzone += 1;
                    if(this.scrollDeadzone > this.SCROLL_DEADZONE_MAX) {
                        this.scrollOffset += this.SCROLL_OFFSET_SPEED;
                    }
                } else {
                    this.body.vel.x = 0;
                    this.scrollOffset += (this.SCROLL_OFFSET_INERTIAL_SPEED * Math.sign(this.direction.x));
                }
            }

            if (this.carrying && !me.input.keyStatus('kick')) {
                this.dropTheBall(true);
            }

            // handling jump
            if (me.input.isKeyPressed('jump')) {
                if (!this.body.jumping &&
                    !this.knockbacked &&
                    (!this.body.falling ||
                     this.onAirTime < this.JUMP_MAX_AIRBONRNE_TIME)) {
                    //set velocity
                    this.body.vel.y = -this.body.maxVel.y * me.timer.tick;
                    this.body.jumping = true;

                    //play audio
                    me.audio.playUnique('jump', 'action');
                }
            }

            if (me.input.isKeyPressed('kick')) {
                if (!this.knockbacked) {
                    //play audio
                    if(!this.kicking)
                        me.audio.playUnique('kick', 'action');

                    this.kick();
                }
            }
        }

        this.onAirTime += dt;
        if (!this.body.falling && !this.body.jumping) {
            this.onAirTime = 0;
        }

        // apply physics to the body (this moves the entity)
        this.body.update(dt);

        // handle collisions against other shapes
        me.collision.check(this);

        if (me.state.current().won) {
            this.setCurrentAnimation('win', function() {
                this.setCurrentAnimation('win');
                me.state.current().nextLevel();
            }.bind(this));
            this.body.vel.x = 0;
        } else {
            // update animation
            if (!this.kicking) {
                if (this.knockbacked) {
                    this.setCurrentAnimation('stun');
                } else if (this.body.jumping) {
                    this.setCurrentAnimation(this.getAnimationName('jump'));
                } else if (this.body.falling) {
                    this.setCurrentAnimation(this.getAnimationName('fall'));
                } else if (this.body.vel.x !== 0) {
                    this.setCurrentAnimation(
                        this.getAnimationName(me.input.keyStatus('kick') ? 'run' : 'walk')
                    );
                } else {
                    this.setCurrentAnimation(this.getAnimationName('idle'));
                }
            } else {
                if (!this.renderable.isCurrentAnimation('v-drop') &&
                    !this.renderable.isCurrentAnimation('h-drop')) {
                    this.setCurrentAnimation('kick', (function() {
                        this.kicking = false;
                        this.body.removeShapeAt(1);
                    }).bind(this));
                }
            }
        }

        // Compute the center
        this.scrollDeadzone = this.scrollDeadzone > this.SCROLL_DEADZONE_MAX
                                ? this.SCROLL_DEADZONE_MAX
                                : (this.scrollDeadzone < -this.SCROLL_DEADZONE_MAX
                                        ? -this.SCROLL_DEADZONE_MAX
                                        : this.scrollDeadzone);

        this.scrollOffset = this.scrollOffset > this.SCROLL_OFFSET_MAX
                                ? this.SCROLL_OFFSET_MAX
                                : (this.scrollOffset < -this.SCROLL_OFFSET_MAX
                                        ? -this.SCROLL_OFFSET_MAX
                                        : this.scrollOffset);
        var center = this.pos.clone()
                            .add(new me.Vector2d((this.width / 2) + this.scrollOffset,
                                                 this.height / 2))
        this.center.set(center.x, center.y);

        // return true if we moved or if the renderable was updated
        return (this._super(me.Entity, 'update', [dt]) ||
                this.body.vel.x !== 0 ||
                this.body.vel.y !== 0);
    },

    getAnimationName: function(name) {
        return name + (this.carrying ? '-carry' : '');
    },

    dropTheBall: function(powerUp) {
        var ball = me.game.world.getChildByName('ball')[0];
        ball.carried = false;
        if (powerUp) {
            ball.powerUp();
        } else {
            ball.powerDown();
        }

        var dir = 'h';
        if (me.input.isKeyPressed('up')) {
            dir = 'v';
            ball.pos.set(this.left, this.top - ball.body.height);
            ball.goUp();
        } else {
            var vector = this.direction.clone(),
                response = new me.collision.ResponseObject();

            ball.pos.set(
                this.left + (this.width / 2) - (ball.width / 2) + ((this.width) * vector.x),
                this.top + (this.height / 2) - (ball.height / 2)
            );
            if (me.collision.check(ball, response)) {
                if (response.overlap >= ball.body.width / 2) {
                    vector.x = -vector.x;
                    ball.pos.set(
                        this.left + (this.width / 2) - (ball.width / 2) + ((this.width) * vector.x),
                        this.top + (this.height / 2) - (ball.height / 2)
                    );
                }
            }

            ball.go(vector.x, vector.y);
        }

        this.kicking = true;
        this.setCurrentAnimation(dir + '-drop', function() {
            this.kicking = false;
            this.setCurrentAnimation('idle');
        }.bind(this));

        this.carrying = false;
    },

   /**
     * colision handler
     * (called when colliding with other objects)
     */
    onCollision : function (response, other) {
        var myShapeIndex = response.a.name === this.name ? response.indexShapeA
                                                         : response.indexShapeB;
        var otherShapeIndex = response.a.name === other.name ? response.indexShapeA
                                                             : response.indexShapeB;

        // kick collision shape must not be solid
        if (myShapeIndex > 0) {
            return false;
        }

        // computing independant overlap vector
        var relativeOverlapV = response.overlapV.clone().scale(this.name === response.a.name ? 1 : 0);
        // handling custom collision
        if (other.name === 'ball') {
            if (other.carried) { return false; }
            return !this.powerJumping && !this.renderable.isFlickering();
        } else if (other.name === 'piglet') {
            other.rescue();
            return false;
        } else if (other.name === 'trigger') {
            return false;
        } else if (other.name === 'boar') {
            // if our body (not the foot) touches the boar
            if (otherShapeIndex === 0) {
                return false;
            } else if (otherShapeIndex === 1) {
                // if we come from bottom
                if (!this.knockbacked &&
                    !other.stunned &&
                    relativeOverlapV.y > 0 &&
                    this.bottom - relativeOverlapV.y < other.top &&
                    this.body.vel.y > 0) {
                        // we bounce on the head
                        this.body.vel.set(-8 * 10 * (other.pos.x - this.pos.x) > 0 ? 1 : -1, -8);
                        other.stun();
                }
                return !other.stunned && !this.knockbacked;
            } else {
                // If we're not invincible and not stunned
                if (!this.renderable.isFlickering() && !other.stunned) {
                    // giving priority over stunning. way better
                    this.hit();
                    this.knockback(8, new me.Vector2d((other.pos.x - this.pos.x) > 0 ? 1 : -1, 0));
                }
                return !this.renderable.isFlickering() && !other.stunned;
            }
        }
        else {
            // we're not knockbacked anymore
            this.knockbacked = false;
            this.powerJumping = false;
        }

        // Make all other objects solid
        return true;
    }
});
<commit_msg>are we clipping less? :skull:<commit_after>/**
 * Player Entity
 */
game.PlayerEntity = me.Entity.extend({

    /**
     * constructor
     */
    init:function (x, y, settings) {
        settings.image = 'pig';
        settings.framewidth = 40;
        settings.frameheight = 40;
        // call the constructor
        this._super(me.Entity, 'init', [x, y , settings]);
        this.name = 'player';

        // shift sprite so that collision box is its bottom
        this.renderable.translate(0, -4);

        // viewport must follow the player
        this.center = this.pos.clone()
                              .add(new me.Vector2d(this.width / 2,
                                                   this.height / 2));
        this.SCROLL_OFFSET_MAX = 30;
        this.SCROLL_OFFSET_SPEED = 1;
        this.SCROLL_OFFSET_INERTIAL_SPEED = 3;
        this.SCROLL_DEADZONE_MAX = 8;
        this.scrollOffset = 0;
        this.scrollDeadzone = 0;
        me.game.viewport.setDeadzone(0, 0);
        me.game.viewport.follow(this.center, me.game.viewport.AXIS.BOTH);

        // we set the velocity of the player's body
        this.WALK_SPEED = 2;
        this.RUN_SPEED = 3;
        this.VERTICAL_SPEED = 9;
        this.body.setVelocity(this.WALK_SPEED, this.VERTICAL_SPEED);

        // we always update the player, ALWAYS
        this.alwaysUpdate = true;

        // setting constants
        this.onAirTime = 100;
        this.JUMP_MAX_AIRBONRNE_TIME = 80;
        this.FLICKERING_TIME = 2000;

        // setting initial direction
        this.direction = new me.Vector2d(1, 0);
        this.knockbacked = false;
        this.powerJumping = false;

        this.carrying = false;

        // animations
        this.renderable.addAnimation('idle', [0, 1, 2], 150);
        this.renderable.addAnimation('walk', [3, 4, 5, 6, 7, 8], 100);
        this.renderable.addAnimation('run', [9, 10, 11, 12, 13, 14], 70);
        this.renderable.addAnimation('jump', [15, 16], 50);
        this.renderable.addAnimation('fall', [18, 19], 50);
        this.renderable.addAnimation('kick', [20, 21, 21, 21], 50);
        this.renderable.addAnimation('stun', [23, 24, 23, 24, 23, 24], 50); // Must blink
        this.renderable.addAnimation('win', [25, 26, 27, 26, 25, 26, 27, 26,
                                             25, 26, 27, 26, 25, 26, 27, 26], 120);
        this.renderable.addAnimation('idle-carry', [28, 29, 30], 150);
        this.renderable.addAnimation('walk-carry', [31, 32, 33, 34, 35, 36], 100);
        this.renderable.addAnimation('run-carry', [37, 38, 39, 40, 41, 42], 50);
        this.renderable.addAnimation('jump-carry', [43, 44], 50);
        this.renderable.addAnimation('fall-carry', [46, 47], 50);
        this.renderable.addAnimation('h-drop', [20, 20], 50);
        this.renderable.addAnimation('v-drop', [48, 48], 50);

        this.setCurrentAnimation('idle');
    },

    setCurrentAnimation: function(name, onComplete) {
        if (!this.renderable.isCurrentAnimation(name)) {
            this.renderable.setCurrentAnimation(name, onComplete);
        }
    },

    flipX: function(flipX) {
        // XXX Should we prevent flipping when kicking or move the kick collision shape?
        if (!this.kicking) {
            this.renderable.flipX(flipX);
        }
    },

     knockback: function (strength, direction) {
         // set state as currently knockbacked
         this.knockbacked = true;

         // set default strength
         strength = strength || 2;
         direction = direction || this.direction;

        // change the velocity
        this.body.vel = new me.Vector2d(-strength * 20 * direction.x, -strength);
    },

    kick: function() {
        if (!this.kicking) {
            this.kicking = true;
            this.body.addShape(new me.Rect(
                this.direction.x < 0 ? -20 : 20,
                15,
                17,
                7
            ));
        }
    },

     hit: function() {
        this.renderable.flicker(this.FLICKERING_TIME);

        // drop the ball
        if (this.carrying) {
            this.dropTheBall();
        }
     },

    /**
     * update the entity
     */
    update : function (dt) {
        // handling movement on the side
        if (me.input.keyStatus('kick') && !this.kicking) {
            this.body.setVelocity(this.RUN_SPEED, this.VERTICAL_SPEED);
        } else {
            this.body.setVelocity(this.WALK_SPEED, this.VERTICAL_SPEED);
        }

        if (!me.input.paused) {
            if (!this.knockbacked) {
                if (me.input.isKeyPressed('left')) {
                    this.flipX(true);
                    this.body.vel.x -= this.body.accel.x * me.timer.tick;
                    this.direction = new me.Vector2d(-1, 0);
                    this.scrollDeadzone -= 1;
                    if(this.scrollDeadzone < -this.SCROLL_DEADZONE_MAX) {
                        this.scrollOffset -= this.SCROLL_OFFSET_SPEED;
                    }
                } else if (me.input.isKeyPressed('right')) {
                    this.flipX(false);
                    this.body.vel.x += this.body.accel.x * me.timer.tick;
                    this.direction = new me.Vector2d(1, 0);
                    this.scrollDeadzone += 1;
                    if(this.scrollDeadzone > this.SCROLL_DEADZONE_MAX) {
                        this.scrollOffset += this.SCROLL_OFFSET_SPEED;
                    }
                } else {
                    this.body.vel.x = 0;
                    this.scrollOffset += (this.SCROLL_OFFSET_INERTIAL_SPEED * Math.sign(this.direction.x));
                }
            }

            if (this.carrying && !me.input.keyStatus('kick')) {
                this.dropTheBall(true);
            }

            // handling jump
            if (me.input.isKeyPressed('jump')) {
                if (!this.body.jumping &&
                    !this.knockbacked &&
                    (!this.body.falling ||
                     this.onAirTime < this.JUMP_MAX_AIRBONRNE_TIME)) {
                    //set velocity
                    this.body.vel.y = -this.body.maxVel.y * me.timer.tick;
                    this.body.jumping = true;

                    //play audio
                    me.audio.playUnique('jump', 'action');
                }
            }

            if (me.input.isKeyPressed('kick')) {
                if (!this.knockbacked) {
                    //play audio
                    if(!this.kicking)
                        me.audio.playUnique('kick', 'action');

                    this.kick();
                }
            }
        }

        this.onAirTime += dt;
        if (!this.body.falling && !this.body.jumping) {
            this.onAirTime = 0;
        }

        // apply physics to the body (this moves the entity)
        this.body.update(dt);

        // handle collisions against other shapes
        me.collision.check(this);

        if (me.state.current().won) {
            this.setCurrentAnimation('win', function() {
                this.setCurrentAnimation('win');
                me.state.current().nextLevel();
            }.bind(this));
            this.body.vel.x = 0;
        } else {
            // update animation
            if (!this.kicking) {
                if (this.knockbacked) {
                    this.setCurrentAnimation('stun');
                } else if (this.body.jumping) {
                    this.setCurrentAnimation(this.getAnimationName('jump'));
                } else if (this.body.falling) {
                    this.setCurrentAnimation(this.getAnimationName('fall'));
                } else if (this.body.vel.x !== 0) {
                    this.setCurrentAnimation(
                        this.getAnimationName(me.input.keyStatus('kick') ? 'run' : 'walk')
                    );
                } else {
                    this.setCurrentAnimation(this.getAnimationName('idle'));
                }
            } else {
                if (!this.renderable.isCurrentAnimation('v-drop') &&
                    !this.renderable.isCurrentAnimation('h-drop')) {
                    this.setCurrentAnimation('kick', (function() {
                        this.kicking = false;
                        this.body.removeShapeAt(1);
                    }).bind(this));
                }
            }
        }

        // Compute the center
        this.scrollDeadzone = this.scrollDeadzone > this.SCROLL_DEADZONE_MAX
                                ? this.SCROLL_DEADZONE_MAX
                                : (this.scrollDeadzone < -this.SCROLL_DEADZONE_MAX
                                        ? -this.SCROLL_DEADZONE_MAX
                                        : this.scrollDeadzone);

        this.scrollOffset = this.scrollOffset > this.SCROLL_OFFSET_MAX
                                ? this.SCROLL_OFFSET_MAX
                                : (this.scrollOffset < -this.SCROLL_OFFSET_MAX
                                        ? -this.SCROLL_OFFSET_MAX
                                        : this.scrollOffset);
        var center = this.pos.clone()
                            .add(new me.Vector2d((this.width / 2) + this.scrollOffset,
                                                 this.height / 2))
        this.center.set(center.x, center.y);

        // return true if we moved or if the renderable was updated
        return (this._super(me.Entity, 'update', [dt]) ||
                this.body.vel.x !== 0 ||
                this.body.vel.y !== 0);
    },

    getAnimationName: function(name) {
        return name + (this.carrying ? '-carry' : '');
    },

    dropTheBall: function(powerUp) {
        var ball = me.game.world.getChildByName('ball')[0];
        ball.carried = false;
        if (powerUp) {
            ball.powerUp();
        } else {
            ball.powerDown();
        }

        var dir = 'h';
        if (me.input.isKeyPressed('up')) {
            dir = 'v';
            ball.pos.set(this.left, this.top - ball.body.height);
            ball.goUp();
        } else {
            var vector = this.direction.clone(),
                response = new me.collision.ResponseObject();

            ball.pos.set(
                this.left + (this.width / 2) - (ball.width / 2) + ((this.width) * vector.x),
                this.top + (this.height / 2) - (ball.height / 2)
            );
            if (me.collision.check(ball, response)) {
                if (response.overlap >= ball.body.width / 2) {
                    vector.x = -vector.x;
                    ball.pos.set(
                        this.left + (this.width / 2) - (ball.width / 2) + ((this.width) * vector.x),
                        this.top + (this.height / 2) - (ball.height / 2)
                    );
                }
            }

            ball.go(vector.x, vector.y);
        }

        this.kicking = true;
        this.setCurrentAnimation(dir + '-drop', function() {
            this.kicking = false;
            this.setCurrentAnimation('idle');
        }.bind(this));

        this.carrying = false;
    },

   /**
     * colision handler
     * (called when colliding with other objects)
     */
    onCollision : function (response, other) {
        var myShapeIndex = response.a.name === this.name ? response.indexShapeA
                                                         : response.indexShapeB;
        var otherShapeIndex = response.a.name === other.name ? response.indexShapeA
                                                             : response.indexShapeB;

        // kick collision shape must not be solid
        if (myShapeIndex > 0) {
            return false;
        }

        // computing independant overlap vector
        var relativeOverlapV = response.overlapV.clone().scale(this.name === response.a.name ? 1 : 0);
        // handling custom collision
        if (other.name === 'ball') {
            return false;
        } else if (other.name === 'piglet') {
            other.rescue();
            return false;
        } else if (other.name === 'trigger') {
            return false;
        } else if (other.name === 'boar') {
            // if our body (not the foot) touches the boar
            if (otherShapeIndex === 0) {
                return false;
            } else if (otherShapeIndex === 1) {
                // if we come from bottom
                if (!this.knockbacked &&
                    !other.stunned &&
                    relativeOverlapV.y > 0 &&
                    this.bottom - relativeOverlapV.y < other.top &&
                    this.body.vel.y > 0) {
                        // we bounce on the head
                        this.body.vel.set(-8 * 10 * (other.pos.x - this.pos.x) > 0 ? 1 : -1, -8);
                        other.stun();
                }
                return !other.stunned && !this.knockbacked;
            } else {
                // If we're not invincible and not stunned
                if (!this.renderable.isFlickering() && !other.stunned) {
                    // giving priority over stunning. way better
                    this.hit();
                    this.knockback(8, new me.Vector2d((other.pos.x - this.pos.x) > 0 ? 1 : -1, 0));
                }
                return !this.renderable.isFlickering() && !other.stunned;
            }
        } else {
            // we're not knockbacked anymore
            this.knockbacked = false;
            this.powerJumping = false;
        }

        // Make all other objects solid
        return true;
    }
});
<|endoftext|>


<commit_before>var virusTooltip = d3.tip()
	.direction('se')
	.attr('class', 'd3-tip')
	.offset([0, 12])
	.html(function(d) {

		string = "";

		// safe to assume the following attributes
		if (typeof d.strain != "undefined") {
			string += d.strain;
		}
		string += "

";

		string += "
";

		// check if vaccine strain
		if (vaccineStrains.indexOf(d.strain) != -1) {
			string += "Vaccine strain
";
			var vaccine_date = new Date(vaccineChoice[d.strain]);

			string += "First chosen " + vaccine_date.toLocaleString("en-us", { month: "short" }) + " " + vaccine_date.getFullYear() + "
";
			string += "

";
		}

		if (typeof d.country != "undefined") {
			string += d.country.replace(/([A-Z])/g, ' $1');
		}
		if (typeof d.date != "undefined") {
			string += ", " + d.date;
		}
		if ((typeof d.db != "undefined") && (typeof d.accession != "undefined") && (d.db == "GISAID")) {
			string += "
GISAID ID: EPI" + d.accession;
		}
		if (typeof d.lab != "undefined") {
			if (d.lab != "") {
				string += "
Source: " + d.lab.substring(0,25);
				if (d.lab.length>25) string += '...';
			}
		}
		string += "
";
		// following may or may not be present
		if ((typeof focusNode != "undefined")){
			string += "

";
			string += "HI against serum from "+focusNode.strain;
			string += "

";
			string += "
"
			string += '

Serum	&#916log2	heterol.	autol.

';
			if (typeof focusNode.HI_titers[d.clade] != "undefined"){
				for (var tmp_serum in focusNode.HI_titers[d.clade]){
					var autoHI = focusNode.autologous_titers[tmp_serum];
					var rawHI = focusNode.HI_titers_raw[d.clade][tmp_serum];
					var logHI = focusNode.HI_titers[d.clade][tmp_serum];
					if (correctVirus){logHI-=d.avidity_mut;}
					if (correctPotency){logHI-=focusNode.potency_mut[tmp_serum];}
					var serum_name;
					if (tmp_serum.length<20){
						serum_name = tmp_serum;
					}else{
						serum_name = tmp_serum.substring(0,17)+'...';
					}
					string += '
' + serum_name + '	' +  logHI.toFixed(2) + '	' + rawHI.toFixed(0)+ '	' + autoHI.toFixed(0) +"
";
				}
			}
			string += '
' + 'Tree model' + '	' +  d.HI_dist_tree.toFixed(2) + '	 --- 	---
';
			string += '
' + 'Subs. model ' + '	' +  d.HI_dist_mut.toFixed(2) + '	 --- 	---
';
			string += "

";
		}

		string += "

";
		// following may or may not be present
		string += "
";
		if (typeof d.cHI != "undefined") {
			string += "Antigenic adv: " + d.cHI.toFixed(1) + "
";
		}
		if (typeof d.ep != "undefined") {
			string += "Epitope distance: " + d.ep + "
";
		}
		if (typeof d.rb != "undefined") {
			string += "Receptor binding distance: " + d.rb + "
";
		}
		if (typeof d.LBI != "undefined") {
			string += "Local branching index: " + d.LBI.toFixed(3) + "
";
		}
		string += "
";
		return string;
	});
treeplot.call(virusTooltip);

var linkTooltip = d3.tip()
	.direction('e')
	.attr('class', 'd3-tip')
	.offset([0, 12])
	.html(function(d) {
		string = ""
		if (typeof d.frequency != "undefined") {
			string += "Frequency: " + (100 * d.frequency).toFixed(1) + "%"
		}
		if (typeof d.dHI != "undefined") {
			string += "
Titer drop: " + d.dHI.toFixed(2)
		}
		string += "

";
		string += "
";
		if ((typeof d.aa_muts !="undefined")&&(mutType=='aa')){
			var ncount = 0;
			for (tmp_gene in d.aa_muts) {ncount+=d.aa_muts[tmp_gene].length;}
			if (ncount) {string += "Mutations:
";}
			for (tmp_gene in d.aa_muts){
				if (d.aa_muts[tmp_gene].length){
					string+="
"+tmp_gene+": "+d.aa_muts[tmp_gene].replace(/,/g, ', ') + "
";
				}
			}
		}
		else if ((typeof d.nuc_muts !="undefined")&&(mutType=='nuc')&&(d.nuc_muts.length)){
			var tmp_muts = d.nuc_muts.split(',');
			var nmuts = tmp_muts.length;
			tmp_muts = tmp_muts.slice(0,Math.min(10, nmuts))
			string += "
"+tmp_muts.join(', ');
			if (nmuts>10) {string+=' + '+ (nmuts-10) + ' more';}
			string += "
";
		}
		string += "
";
		string += "click to zoom into clade"
		string += "
";
		return string;
	});
treeplot.call(linkTooltip);
<commit_msg>changed autol to homol in tooltip<commit_after>var virusTooltip = d3.tip()
	.direction('se')
	.attr('class', 'd3-tip')
	.offset([0, 12])
	.html(function(d) {

		string = "";

		// safe to assume the following attributes
		if (typeof d.strain != "undefined") {
			string += d.strain;
		}
		string += "

";

		string += "
";

		// check if vaccine strain
		if (vaccineStrains.indexOf(d.strain) != -1) {
			string += "Vaccine strain
";
			var vaccine_date = new Date(vaccineChoice[d.strain]);

			string += "First chosen " + vaccine_date.toLocaleString("en-us", { month: "short" }) + " " + vaccine_date.getFullYear() + "
";
			string += "

";
		}

		if (typeof d.country != "undefined") {
			string += d.country.replace(/([A-Z])/g, ' $1');
		}
		if (typeof d.date != "undefined") {
			string += ", " + d.date;
		}
		if ((typeof d.db != "undefined") && (typeof d.accession != "undefined") && (d.db == "GISAID")) {
			string += "
GISAID ID: EPI" + d.accession;
		}
		if (typeof d.lab != "undefined") {
			if (d.lab != "") {
				string += "
Source: " + d.lab.substring(0,25);
				if (d.lab.length>25) string += '...';
			}
		}
		string += "
";
		// following may or may not be present
		if ((typeof focusNode != "undefined")){
			string += "

";
			string += "HI against serum from "+focusNode.strain;
			string += "

";
			string += "
"
			string += '

Serum	&#916log2	heterol.	homol.

';
			if (typeof focusNode.HI_titers[d.clade] != "undefined"){
				for (var tmp_serum in focusNode.HI_titers[d.clade]){
					var autoHI = focusNode.autologous_titers[tmp_serum];
					var rawHI = focusNode.HI_titers_raw[d.clade][tmp_serum];
					var logHI = focusNode.HI_titers[d.clade][tmp_serum];
					if (correctVirus){logHI-=d.avidity_mut;}
					if (correctPotency){logHI-=focusNode.potency_mut[tmp_serum];}
					var serum_name;
					if (tmp_serum.length<20){
						serum_name = tmp_serum;
					}else{
						serum_name = tmp_serum.substring(0,17)+'...';
					}
					string += '
' + serum_name + '	' +  logHI.toFixed(2) + '	' + rawHI.toFixed(0)+ '	' + autoHI.toFixed(0) +"
";
				}
			}
			string += '
' + 'Tree model' + '	' +  d.HI_dist_tree.toFixed(2) + '	 --- 	---
';
			string += '
' + 'Subs. model ' + '	' +  d.HI_dist_mut.toFixed(2) + '	 --- 	---
';
			string += "

";
		}

		string += "

";
		// following may or may not be present
		string += "
";
		if (typeof d.cHI != "undefined") {
			string += "Antigenic adv: " + d.cHI.toFixed(1) + "
";
		}
		if (typeof d.ep != "undefined") {
			string += "Epitope distance: " + d.ep + "
";
		}
		if (typeof d.rb != "undefined") {
			string += "Receptor binding distance: " + d.rb + "
";
		}
		if (typeof d.LBI != "undefined") {
			string += "Local branching index: " + d.LBI.toFixed(3) + "
";
		}
		string += "
";
		return string;
	});
treeplot.call(virusTooltip);

var linkTooltip = d3.tip()
	.direction('e')
	.attr('class', 'd3-tip')
	.offset([0, 12])
	.html(function(d) {
		string = ""
		if (typeof d.frequency != "undefined") {
			string += "Frequency: " + (100 * d.frequency).toFixed(1) + "%"
		}
		if (typeof d.dHI != "undefined") {
			string += "
Titer drop: " + d.dHI.toFixed(2)
		}
		string += "

";
		string += "
";
		if ((typeof d.aa_muts !="undefined")&&(mutType=='aa')){
			var ncount = 0;
			for (tmp_gene in d.aa_muts) {ncount+=d.aa_muts[tmp_gene].length;}
			if (ncount) {string += "Mutations:
";}
			for (tmp_gene in d.aa_muts){
				if (d.aa_muts[tmp_gene].length){
					string+="
"+tmp_gene+": "+d.aa_muts[tmp_gene].replace(/,/g, ', ') + "
";
				}
			}
		}
		else if ((typeof d.nuc_muts !="undefined")&&(mutType=='nuc')&&(d.nuc_muts.length)){
			var tmp_muts = d.nuc_muts.split(',');
			var nmuts = tmp_muts.length;
			tmp_muts = tmp_muts.slice(0,Math.min(10, nmuts))
			string += "
"+tmp_muts.join(', ');
			if (nmuts>10) {string+=' + '+ (nmuts-10) + ' more';}
			string += "
";
		}
		string += "
";
		string += "click to zoom into clade"
		string += "
";
		return string;
	});
treeplot.call(linkTooltip);
<|endoftext|>


<commit_before>var chai = require("chai")
var chaiAsPromised = require("chai-as-promised")
var expect = chai.expect
var should = chai.should
chai.use(chaiAsPromised)

var lsys = require('../lindenmayer')

describe('Correct behavior of L-Systems', function() {

  it('should handle UTF8', function() {
    var test = new lsys.LSystem({
      word:'⚣⚤●',
      productions: [['⚣', '♂♂'], ['⚤', '♀♂'], ['●', '○◐◑']]
    })
    expect(test.iterate()).to.equal('♂♂♀♂○◐◑')
  })

  it('should generate the string for the Koch-curve', function() {
    var koch = new lsys.LSystem({
      word: 'F++F++F',
      productions: [
        ['F', 'F-F++F-F']
      ]
    })

    expect(koch.iterate()).to.equal('F-F++F-F++F-F++F-F++F-F++F-F')

    expect(koch.iterate()).to.equal('F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F')

    expect(koch.iterate()).to.equal('F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F-F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F-F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F-F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F-F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F-F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F-F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F')

    var wordFromGenerator = koch.iterate()
    expect(wordFromGenerator).to.equal(koch.word)
  })

  it('should execute final functions to draw eg. visualizations.', function() {
    var vizsys = new lsys.LSystem({
    	word:'A---',
    	productions: [
        ['A', 'AARA-BB-B'],
        ['B', 'ABBA-+--B+-'],
        ['R', 'RA-']
      ],
    	finals: [
        ['A', () => {vizsys.output += '/'}],
        ['B', () => {vizsys.output += '#'}],
        ['R', () => {vizsys.output += '~'}],
        ['-', () => {vizsys.output += '-'}],
        ['+', () => {vizsys.output += '+'}]
      ]
    })

    vizsys.output = ''

    vizsys.iterate(2)
    vizsys.final()
    expect(vizsys.output).to.equal('//~/-##-#//~/-##-#~/-//~/-##-#-/##/-+--#+-/##/-+--#+--/##/-+--#+----')
  })

  it('Final functions must be functions. Should throw an error on any other type.', function() {
    var vizsys = new lsys.LSystem({
      word:'A',
      productions: [['A', 'Z']],
      finals: [
        ['Z', 'A_STRING']
      ]
    })

    expect(function () {
      vizsys.iterate()
      vizsys.final()
    }).to.throw(/not a function/)

    expect(function () {
      vizsys.finals.set('Z', 7)
      vizsys.final()
    }).to.throw(/not a function/)

    expect(function () {
      vizsys.finals.set('Z', new Date())
      vizsys.final()
    }).to.throw(/not a function/)

    var rotation = 5
    expect(function () {
      vizsys.finals.set('Z', () => {rotation *= 2})
      vizsys.final()
    }).to.not.throw(/not a function/)

    expect(rotation).to.equal(10)

  })

  it('Helper functions for context sensitive productions should work properly. Especially with branches.', function() {

    var cs_lsys = new lsys.LSystem({
      word: 'ACBC[-Q]D--[A[FDQ]]E-+FC++G',
      productions: [
        ['C', (index, word) => (cs_lsys.match({direction: 'right', match: 'DEF', index})) ? 'Z' : 'C']
      ],
      branchSymbols: '[]',
      ignoredSymbols: '+-/'
    })

    expect(cs_lsys.iterate()).to.equal('ACBZ[-Q]D--[A[FDQ]]E-+FC++G')

  })

  it('Context sensitive L-System should work inside explicitly wanted branches', function() {
    // this example is taken from ABOP S. 32
    var cs_lsys3 = new lsys.LSystem({
      word: 'ABC[DE][SG[HI[JK]L]MNO]',
      productions: [
        ['S', (index, word) =>
          (
            cs_lsys3.match({direction: 'right', match: 'G[H]M', index, branchSymbols: ['[', ']']}) &&
            cs_lsys3.match({direction: 'left', match: 'BC', index, branchSymbols: ['[', ']']})
          ) ? 'Z' : 'S']
      ]
    })
    expect(cs_lsys3.iterate()).to.equal('ABC[DE][ZG[HI[JK]L]MNO]')

    var cs_lsys4 = new lsys.LSystem({
      word: 'ABC[DE][FG[HI[JK]L]MNO]',
      productions: [
        ['H', (index, word) =>  (
          cs_lsys4.match({direction: 'right', match: 'I[K]L', index, branchSymbols: '[]'}))
          ? 'Z' : 'H']
      ]

    })
    // I[K]L should not apply to I[JK]L
    expect(cs_lsys4.iterate()).to.not.equal('ABC[DE][FG[ZI[JK]L]MNO]')

    var cs_lsys5 = new lsys.LSystem({
      word: 'S][ED]CBA',
      productions: [
        ['S', (index, word) =>  ( cs_lsys5.match({direction: 'right', match: 'CB', index, branchSymbols: '[]'})) ? 'Z' : 'S']
      ]

    })
    // as required by ABOP S. 32 (reversed string)
    expect(cs_lsys5.iterate()).to.equal('Z][ED]CBA')

  })

    it('Context sensitive L-System helper function match() should work in L-Systems that don\'t use branches/brackets.', function() {
      var cs_lsys6 = new lsys.LSystem({
        word: 'A+++C-DE-+F&GH++-',
        productions: [
          ['C', (index, word) =>
            (cs_lsys6.match({direction: 'right', match: 'DEFG', index, ignoredSymbols: '+-&'})) ? 'Z' : 'C'
          ]
        ]
      })
      expect(cs_lsys6.iterate()).to.equal('A+++Z-DE-+F&GH++-')
    })

    it('Classic context sensitive syntax should work.', function() {
      var cs_lsys7 = new lsys.LSystem({
        word: 'A[X]BC',
        productions:
        [
          ['A<B>C', 'Z']
        ]
      })
      cs_lsys7.setProduction('B<C', 'Y')
      console.log(cs_lsys7.productions);

      expect(cs_lsys7.iterate()).to.equal('A[X]ZY')
    })

    it('Very simple parametric L-Systems should work.', function() {
      var para_lsys1 = new lsys.LSystem({
        word: [
          {literal: 'A'},
          {literal: 'B'},
          {literal: 'C'},
          {literal: 'D'},
          {literal: 'E'},
          {literal: 'F'},
          {literal: 'G'}
        ],
        productions: [
          ['C', {literal: 'Z'}]
        ]
      })

      para_lsys1.iterate()
      expect(para_lsys1.getWordAsString({onlyLiterals: true})).to.equal('ABZDEFG')
    })

});
<commit_msg>removed unneeded line in test<commit_after>var chai = require("chai")
var chaiAsPromised = require("chai-as-promised")
var expect = chai.expect
chai.use(chaiAsPromised)

var lsys = require('../lindenmayer')

describe('Correct behavior of L-Systems', function() {

  it('should handle UTF8', function() {
    var test = new lsys.LSystem({
      word:'⚣⚤●',
      productions: [['⚣', '♂♂'], ['⚤', '♀♂'], ['●', '○◐◑']]
    })
    expect(test.iterate()).to.equal('♂♂♀♂○◐◑')
  })

  it('should generate the string for the Koch-curve', function() {
    var koch = new lsys.LSystem({
      word: 'F++F++F',
      productions: [
        ['F', 'F-F++F-F']
      ]
    })

    expect(koch.iterate()).to.equal('F-F++F-F++F-F++F-F++F-F++F-F')

    expect(koch.iterate()).to.equal('F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F')

    expect(koch.iterate()).to.equal('F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F-F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F-F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F-F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F-F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F-F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F-F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F')

    var wordFromGenerator = koch.iterate()
    expect(wordFromGenerator).to.equal(koch.word)
  })

  it('should execute final functions to draw eg. visualizations.', function() {
    var vizsys = new lsys.LSystem({
    	word:'A---',
    	productions: [
        ['A', 'AARA-BB-B'],
        ['B', 'ABBA-+--B+-'],
        ['R', 'RA-']
      ],
    	finals: [
        ['A', () => {vizsys.output += '/'}],
        ['B', () => {vizsys.output += '#'}],
        ['R', () => {vizsys.output += '~'}],
        ['-', () => {vizsys.output += '-'}],
        ['+', () => {vizsys.output += '+'}]
      ]
    })

    vizsys.output = ''

    vizsys.iterate(2)
    vizsys.final()
    expect(vizsys.output).to.equal('//~/-##-#//~/-##-#~/-//~/-##-#-/##/-+--#+-/##/-+--#+--/##/-+--#+----')
  })

  it('Final functions must be functions. Should throw an error on any other type.', function() {
    var vizsys = new lsys.LSystem({
      word:'A',
      productions: [['A', 'Z']],
      finals: [
        ['Z', 'A_STRING']
      ]
    })

    expect(function () {
      vizsys.iterate()
      vizsys.final()
    }).to.throw(/not a function/)

    expect(function () {
      vizsys.finals.set('Z', 7)
      vizsys.final()
    }).to.throw(/not a function/)

    expect(function () {
      vizsys.finals.set('Z', new Date())
      vizsys.final()
    }).to.throw(/not a function/)

    var rotation = 5
    expect(function () {
      vizsys.finals.set('Z', () => {rotation *= 2})
      vizsys.final()
    }).to.not.throw(/not a function/)

    expect(rotation).to.equal(10)

  })

  it('Helper functions for context sensitive productions should work properly. Especially with branches.', function() {

    var cs_lsys = new lsys.LSystem({
      word: 'ACBC[-Q]D--[A[FDQ]]E-+FC++G',
      productions: [
        ['C', (index, word) => (cs_lsys.match({direction: 'right', match: 'DEF', index})) ? 'Z' : 'C']
      ],
      branchSymbols: '[]',
      ignoredSymbols: '+-/'
    })

    expect(cs_lsys.iterate()).to.equal('ACBZ[-Q]D--[A[FDQ]]E-+FC++G')

  })

  it('Context sensitive L-System should work inside explicitly wanted branches', function() {
    // this example is taken from ABOP S. 32
    var cs_lsys3 = new lsys.LSystem({
      word: 'ABC[DE][SG[HI[JK]L]MNO]',
      productions: [
        ['S', (index, word) =>
          (
            cs_lsys3.match({direction: 'right', match: 'G[H]M', index, branchSymbols: ['[', ']']}) &&
            cs_lsys3.match({direction: 'left', match: 'BC', index, branchSymbols: ['[', ']']})
          ) ? 'Z' : 'S']
      ]
    })
    expect(cs_lsys3.iterate()).to.equal('ABC[DE][ZG[HI[JK]L]MNO]')

    var cs_lsys4 = new lsys.LSystem({
      word: 'ABC[DE][FG[HI[JK]L]MNO]',
      productions: [
        ['H', (index, word) =>  (
          cs_lsys4.match({direction: 'right', match: 'I[K]L', index, branchSymbols: '[]'}))
          ? 'Z' : 'H']
      ]

    })
    // I[K]L should not apply to I[JK]L
    expect(cs_lsys4.iterate()).to.not.equal('ABC[DE][FG[ZI[JK]L]MNO]')

    var cs_lsys5 = new lsys.LSystem({
      word: 'S][ED]CBA',
      productions: [
        ['S', (index, word) =>  ( cs_lsys5.match({direction: 'right', match: 'CB', index, branchSymbols: '[]'})) ? 'Z' : 'S']
      ]

    })
    // as required by ABOP S. 32 (reversed string)
    expect(cs_lsys5.iterate()).to.equal('Z][ED]CBA')

  })

    it('Context sensitive L-System helper function match() should work in L-Systems that don\'t use branches/brackets.', function() {
      var cs_lsys6 = new lsys.LSystem({
        word: 'A+++C-DE-+F&GH++-',
        productions: [
          ['C', (index, word) =>
            (cs_lsys6.match({direction: 'right', match: 'DEFG', index, ignoredSymbols: '+-&'})) ? 'Z' : 'C'
          ]
        ]
      })
      expect(cs_lsys6.iterate()).to.equal('A+++Z-DE-+F&GH++-')
    })

    it('Classic context sensitive syntax should work.', function() {
      var cs_lsys7 = new lsys.LSystem({
        word: 'A[X]BC',
        productions:
        [
          ['A<B>C', 'Z']
        ]
      })
      cs_lsys7.setProduction('B<C', 'Y')
      console.log(cs_lsys7.productions);

      expect(cs_lsys7.iterate()).to.equal('A[X]ZY')
    })

    it('Very simple parametric L-Systems should work.', function() {
      var para_lsys1 = new lsys.LSystem({
        word: [
          {literal: 'A'},
          {literal: 'B'},
          {literal: 'C'},
          {literal: 'D'},
          {literal: 'E'},
          {literal: 'F'},
          {literal: 'G'}
        ],
        productions: [
          ['C', {literal: 'Z'}]
        ]
      })

      para_lsys1.iterate()
      expect(para_lsys1.getWordAsString({onlyLiterals: true})).to.equal('ABZDEFG')
    })

});
<|endoftext|>


<commit_before>// TODO: optimize with episode-12 partical removal
import { removeDeadParticles } from '../utils';
import { particle } from '../particle';

const switcher = { on: false };
let frameId;

export const fireWorks = {
  tearDown() {
    switcher.on = false;
    cancelAnimationFrame(frameId);
  },
  setUp() {
    switcher.on = true;
    const canvas = document.getElementById('canvas');
    const context = canvas.getContext('2d');
    const width = canvas.width = window.innerWidth;
    const height = canvas.height = window.innerHeight;
    let particles = [];

    for (let i = 0; i < 100; i++) {
      particles.push(
        particle.create(
          width / 2,
          height / 3,
          Math.random() * 5 + 2,
          Math.random() * Math.PI * 2,
          0.1)
      );
    }

    function update() {
      context.clearRect(0, 0, width, height);

      for (let i = 0; i < particles.length; i++) {
        const p = particles[i];
        p.update();
        context.beginPath();
        context.arc(p.position.getX(), p.position.getY(), 4, 0, Math.PI * 2, false);
        context.fill();
      }

      removeDeadParticles(particles, width, height);
      context.font = '24px serif';
      context.fillText(`particles on page: ${particles.length}`, 200, 50);
      if (switcher.on && particles.length) {
        frameId = requestAnimationFrame(update);
      }
    }

    update();
  },
};
<commit_msg>Just to satisfy the linter<commit_after>// TODO: optimize with episode-12 partical removal
import { removeDeadParticles } from '../utils';
import { particle } from '../particle';

const switcher = { on: false };
let frameId;

export const fireWorks = {
  tearDown() {
    switcher.on = false;
    cancelAnimationFrame(frameId);
  },
  setUp() {
    switcher.on = true;
    const canvas = document.getElementById('canvas');
    const context = canvas.getContext('2d');
    const width = canvas.width = window.innerWidth;
    const height = canvas.height = window.innerHeight;
    let particles = [];

    for (let i = 0; i < 100; i++) {
      particles.push(
        particle.create(
          width / 2,
          height / 3,
          Math.random() * 5 + 2,
          Math.random() * Math.PI * 2,
          0.1)
      );
    }

    function update() {
      context.clearRect(0, 0, width, height);

      for (let i = 0; i < particles.length; i++) {
        const p = particles[i];
        p.update();
        context.beginPath();
        context.arc(p.position.getX(), p.position.getY(), 4, 0, Math.PI * 2, false);
        context.fill();
      }

      particles = removeDeadParticles(particles, width, height);
      context.font = '24px serif';
      context.fillText(`particles on page: ${particles.length}`, 200, 50);
      if (switcher.on && particles.length) {
        frameId = requestAnimationFrame(update);
      }
    }

    update();
  },
};
<|endoftext|>


<commit_before>angular.module('documentationEditorApp', [])
  .controller('EditorController', ['$scope', '$http', '$window', function($scope, $http, $window) {
    $scope.sections = [];
    $scope.nextID = 0;
    $scope.undoRedo = [];
    $scope.id = 0;

    function getNextID() {
      return $scope.nextID++;
    }

    $scope.init = function(id, path) {
      $scope.id = id;
      $scope.path = path;

      $http.get($scope.path + '/source/' + id).then(function(content) {
        $scope.source = content.data;

        var lines = $scope.source.split("\n");
        var currentBlock = null, blockContent = '';

        for (var i = 0; i < lines.length; ++i) {
          var line = lines[i];
          if (line.indexOf('[block:') === 0) {
            currentBlock = line.substring(7, line.length - 1);
          } else if (line.indexOf('[/block]') === 0) {
            $scope.sections.push({
              id: getNextID(),
              type: currentBlock,
              content: JSON.parse(blockContent)
            });
            currentBlock = null;
            blockContent = '';
          } else if (currentBlock != null) {
            blockContent = blockContent + line + '\n';
          } else {
            if ($scope.sections.length > 0 && $scope.sections[$scope.sections.length - 1].type === 'text') {
              $scope.sections[$scope.sections.length - 1].content = $scope.sections[$scope.sections.length - 1].content + "\n" + line;
            } else if (line) {
              $scope.sections.push({
                id: getNextID(),
                type: 'text',
                content: line
              });
            }
          }
        }
      });
    };

    $scope.undo = function($event) {
      $event.preventDefault();
      if ($scope.undoRedo.length === 0) {
        return;
      }
      var o = $scope.undoRedo.pop();
      if (o.type === 'addSection') {
        $scope.sections = $.grep($scope.sections, function(e) { return e.id !== o.data.obj.id });
      } else if (o.type === 'deleteSection') {
        $scope.sections = o.data.sections;
      } else if (o.type === 'deleteLanguage' || o.type === 'addLanguage') {
        var index = getIndex(o.data.id);
        var obj = {
          id: $scope.sections[index].id,
          type: 'code',
          content: {
            codes: o.data.codes
          }
        };
        $scope.sections = [].concat($scope.sections.slice(0, index), [obj], $scope.sections.slice(index + 1));
      } else if (o.type === 'deleteColumn' || o.type === 'addColumn' || o.type === 'addRow' || o.type === 'deleteRow') {
        var index = getIndex(o.data.id);
        $scope.sections[index] = {
          id: $scope.sections[index].id,
          type: 'parameters',
          content: o.data.content
        };
      }
    }

    function getIndex(id) {
      for (var i = 0; i < $scope.sections.length; ++i) {
        if ($scope.sections[i].id === id) {
          return i;
        }
      }
      return -1;
    }

    function add(id, obj) {
      $scope.undoRedo.push({
        type: 'addSection',
        data: {
          id: id,
          obj: obj
        }
      });
      var index = getIndex(id);
      $scope.sections = [].concat($scope.sections.slice(0, index + 1), [obj], $scope.sections.slice(index + 1));
    }

    $scope.addText = function($event, id) {
      $event.preventDefault();
      add(id, { id: getNextID(), type: 'text', content: 'FIXME' });
    };

    $scope.addCallout = function($event, type, id) {
      $event.preventDefault();
      add(id, {
        id: getNextID(),
        type: 'callout',
        content: {
          type: type,
          body: 'FIXME'
        }
      });
    };

    $scope.addCode = function($event, id) {
      $event.preventDefault();
      add(id, {
        id: getNextID(),
        type: 'code',
        content: {
          codes: [
            {
              language: 'fixme',
              code: '// FIXME'
            }
          ]
        }
      });
    };

    $scope.getIntegerIterator = function(v) {
      var a = [];
      for (var i = 0; i < v; ++i) {
        a.push(i);
      }
      return a;
    };

    $scope.deleteSection = function($event, id) {
      $event.preventDefault();
      $scope.undoRedo.push({
        type: 'deleteSection',
        data: {
          sections: $scope.sections
        }
      });
      $scope.sections = $.grep($scope.sections, function(e) { return e.id !== id });
    };

    $scope.deleteLanguage = function($event, id, languageIndex) {
      $event.preventDefault();
      var index = getIndex(id);
      $scope.undoRedo.push({
        type: 'deleteLanguage',
        data: {
          id: id,
          codes: $scope.sections[index].content.codes
        }
      });
      $scope.sections[index].content.codes = $.grep($scope.sections[index].content.codes, function(e, i) { return i !== languageIndex; });
    };

    $scope.addLanguage = function($event, id) {
      $event.preventDefault();
      var index = getIndex(id);
      $scope.undoRedo.push({
        type: 'addLanguage',
        data: {
          id: id,
          codes: $scope.sections[index].content.codes
        }
      });
      $scope.sections[index].content.codes = [].concat($scope.sections[index].content.codes, [{ language: 'fixme', code: '// FIXME' }]);
    };

    $scope.addImage = function($event, id) {
      $event.preventDefault();
      var url = prompt("Image URL (absolute or from after /assets/)", "algolia256x80.png");
      if (url) {
        add(id, {
          type: 'image',
          content: {
            images: [
              {
                image: [url]
              }
            ]
          }
        });
      }
    };

    $scope.addColumn = function($event, id) {
      $event.preventDefault();
      var index = getIndex(id);
      var section = $scope.sections[index];

      $scope.undoRedo.push({
        type: 'addColumn',
        data: {
          id: id,
          content: {
            data: section.content.data,
            cols: section.content.cols,
            rows: section.content.rows
          }
        }
      });

      var col = section.content.cols;
      section.content.data['h-' + col] = section.content.data['h-' + col] || '';
      section.content.cols = section.content.cols + 1;
      for (var i = 0; i < section.content.rows; ++i) {
        section.content.data[i + '-' + col] = section.content.data[i + '-' + col] || '';
      }
    };

    $scope.deleteColumn = function($event, id) {
      $event.preventDefault();
      var index = getIndex(id);
      var section = $scope.sections[index];

      $scope.undoRedo.push({
        type: 'deleteColumn',
        data: {
          id: id,
          content: {
            data: section.content.data,
            cols: section.content.cols,
            rows: section.content.rows
          }
        }
      });

      section.content.cols = section.content.cols - 1;
    };

    $scope.addRow = function($event, id) {
      $event.preventDefault();
      var index = getIndex(id);
      var section = $scope.sections[index];

      $scope.undoRedo.push({
        type: 'addRow',
        data: {
          id: id,
          content: {
            data: section.content.data,
            cols: section.content.cols,
            rows: section.content.rows
          }
        }
      });

      var rows = section.content.rows;
      section.content.rows = section.content.rows + 1;
      for (var i = 0; i < section.content.cols; ++i) {
        section.content.data[rows + '-' + i] = section.content.data[rows + '-' + i] || '';
      }
    };

    $scope.deleteRow = function($event, id) {
      $event.preventDefault();
      var index = getIndex(id);
      var section = $scope.sections[index];

      $scope.undoRedo.push({
        type: 'deleteRow',
        data: {
          id: id,
          content: {
            data: section.content.data,
            cols: section.content.cols,
            rows: section.content.rows
          }
        }
      });

      section.content.rows = section.content.rows - 1;
    };

    function save(preview) {
      var data = [];
      $.each($scope.sections, function(i, section) {
        if (section.type === 'text') {
          data.push(section.content + "\n");
        } else {
          data.push('[block:' + section.type + ']');
          data.push(JSON.stringify(section.content));
          data.push('[/block]');
        }
      });
      return $http.post($scope.path + '/source/' + $scope.id, { data: data.join("\n"), preview: preview });
    }

    $scope.preview = function($event) {
      $event.preventDefault();
      save(true).then(function(content) {
        $window.open($scope.path + '/preview/' + content.data.id);
      });
    };

    $scope.publish = function($event) {
      $event.preventDefault();

      if (confirm('Are you sure you want to publish this page?')) {
        save(false).then(function(content) {
          $window.location.href = $scope.path + '/' + content.data.slug;
        });
      }
    }

  }]).directive('contenteditable', function() {
    return {
      require: 'ngModel',
      link: function(scope, element, attrs, ngModel) {
        function read() {
          ngModel.$setViewValue(element.html().replace(/
/g, '').replace(/<\/div>/g, "\n").replace(/
/g, "\n").replace(/\n{3,}/g, "\n\n"));
        }

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

        element.bind("blur keyup change", function() {
          scope.$apply(read);
        });
      }
    };
  })
;
<commit_msg>Avoid pasted text to be rich text<commit_after>angular.module('documentationEditorApp', [])
  .controller('EditorController', ['$scope', '$http', '$window', function($scope, $http, $window) {
    $scope.sections = [];
    $scope.nextID = 0;
    $scope.undoRedo = [];
    $scope.id = 0;

    function getNextID() {
      return $scope.nextID++;
    }

    $scope.init = function(id, path) {
      $scope.id = id;
      $scope.path = path;

      $http.get($scope.path + '/source/' + id).then(function(content) {
        $scope.source = content.data;

        var lines = $scope.source.split("\n");
        var currentBlock = null, blockContent = '';

        for (var i = 0; i < lines.length; ++i) {
          var line = lines[i];
          if (line.indexOf('[block:') === 0) {
            currentBlock = line.substring(7, line.length - 1);
          } else if (line.indexOf('[/block]') === 0) {
            $scope.sections.push({
              id: getNextID(),
              type: currentBlock,
              content: JSON.parse(blockContent)
            });
            currentBlock = null;
            blockContent = '';
          } else if (currentBlock != null) {
            blockContent = blockContent + line + '\n';
          } else {
            if ($scope.sections.length > 0 && $scope.sections[$scope.sections.length - 1].type === 'text') {
              $scope.sections[$scope.sections.length - 1].content = $scope.sections[$scope.sections.length - 1].content + "\n" + line;
            } else if (line) {
              $scope.sections.push({
                id: getNextID(),
                type: 'text',
                content: line
              });
            }
          }
        }
      });
    };

    $scope.undo = function($event) {
      $event.preventDefault();
      if ($scope.undoRedo.length === 0) {
        return;
      }
      var o = $scope.undoRedo.pop();
      if (o.type === 'addSection') {
        $scope.sections = $.grep($scope.sections, function(e) { return e.id !== o.data.obj.id });
      } else if (o.type === 'deleteSection') {
        $scope.sections = o.data.sections;
      } else if (o.type === 'deleteLanguage' || o.type === 'addLanguage') {
        var index = getIndex(o.data.id);
        var obj = {
          id: $scope.sections[index].id,
          type: 'code',
          content: {
            codes: o.data.codes
          }
        };
        $scope.sections = [].concat($scope.sections.slice(0, index), [obj], $scope.sections.slice(index + 1));
      } else if (o.type === 'deleteColumn' || o.type === 'addColumn' || o.type === 'addRow' || o.type === 'deleteRow') {
        var index = getIndex(o.data.id);
        $scope.sections[index] = {
          id: $scope.sections[index].id,
          type: 'parameters',
          content: o.data.content
        };
      }
    }

    function getIndex(id) {
      for (var i = 0; i < $scope.sections.length; ++i) {
        if ($scope.sections[i].id === id) {
          return i;
        }
      }
      return -1;
    }

    function add(id, obj) {
      $scope.undoRedo.push({
        type: 'addSection',
        data: {
          id: id,
          obj: obj
        }
      });
      var index = getIndex(id);
      $scope.sections = [].concat($scope.sections.slice(0, index + 1), [obj], $scope.sections.slice(index + 1));
    }

    $scope.addText = function($event, id) {
      $event.preventDefault();
      add(id, { id: getNextID(), type: 'text', content: 'FIXME' });
    };

    $scope.addCallout = function($event, type, id) {
      $event.preventDefault();
      add(id, {
        id: getNextID(),
        type: 'callout',
        content: {
          type: type,
          body: 'FIXME'
        }
      });
    };

    $scope.addCode = function($event, id) {
      $event.preventDefault();
      add(id, {
        id: getNextID(),
        type: 'code',
        content: {
          codes: [
            {
              language: 'fixme',
              code: '// FIXME'
            }
          ]
        }
      });
    };

    $scope.getIntegerIterator = function(v) {
      var a = [];
      for (var i = 0; i < v; ++i) {
        a.push(i);
      }
      return a;
    };

    $scope.deleteSection = function($event, id) {
      $event.preventDefault();
      $scope.undoRedo.push({
        type: 'deleteSection',
        data: {
          sections: $scope.sections
        }
      });
      $scope.sections = $.grep($scope.sections, function(e) { return e.id !== id });
    };

    $scope.deleteLanguage = function($event, id, languageIndex) {
      $event.preventDefault();
      var index = getIndex(id);
      $scope.undoRedo.push({
        type: 'deleteLanguage',
        data: {
          id: id,
          codes: $scope.sections[index].content.codes
        }
      });
      $scope.sections[index].content.codes = $.grep($scope.sections[index].content.codes, function(e, i) { return i !== languageIndex; });
    };

    $scope.addLanguage = function($event, id) {
      $event.preventDefault();
      var index = getIndex(id);
      $scope.undoRedo.push({
        type: 'addLanguage',
        data: {
          id: id,
          codes: $scope.sections[index].content.codes
        }
      });
      $scope.sections[index].content.codes = [].concat($scope.sections[index].content.codes, [{ language: 'fixme', code: '// FIXME' }]);
    };

    $scope.addImage = function($event, id) {
      $event.preventDefault();
      var url = prompt("Image URL (absolute or from after /assets/)", "algolia256x80.png");
      if (url) {
        add(id, {
          type: 'image',
          content: {
            images: [
              {
                image: [url]
              }
            ]
          }
        });
      }
    };

    $scope.addColumn = function($event, id) {
      $event.preventDefault();
      var index = getIndex(id);
      var section = $scope.sections[index];

      $scope.undoRedo.push({
        type: 'addColumn',
        data: {
          id: id,
          content: {
            data: section.content.data,
            cols: section.content.cols,
            rows: section.content.rows
          }
        }
      });

      var col = section.content.cols;
      section.content.data['h-' + col] = section.content.data['h-' + col] || '';
      section.content.cols = section.content.cols + 1;
      for (var i = 0; i < section.content.rows; ++i) {
        section.content.data[i + '-' + col] = section.content.data[i + '-' + col] || '';
      }
    };

    $scope.deleteColumn = function($event, id) {
      $event.preventDefault();
      var index = getIndex(id);
      var section = $scope.sections[index];

      $scope.undoRedo.push({
        type: 'deleteColumn',
        data: {
          id: id,
          content: {
            data: section.content.data,
            cols: section.content.cols,
            rows: section.content.rows
          }
        }
      });

      section.content.cols = section.content.cols - 1;
    };

    $scope.addRow = function($event, id) {
      $event.preventDefault();
      var index = getIndex(id);
      var section = $scope.sections[index];

      $scope.undoRedo.push({
        type: 'addRow',
        data: {
          id: id,
          content: {
            data: section.content.data,
            cols: section.content.cols,
            rows: section.content.rows
          }
        }
      });

      var rows = section.content.rows;
      section.content.rows = section.content.rows + 1;
      for (var i = 0; i < section.content.cols; ++i) {
        section.content.data[rows + '-' + i] = section.content.data[rows + '-' + i] || '';
      }
    };

    $scope.deleteRow = function($event, id) {
      $event.preventDefault();
      var index = getIndex(id);
      var section = $scope.sections[index];

      $scope.undoRedo.push({
        type: 'deleteRow',
        data: {
          id: id,
          content: {
            data: section.content.data,
            cols: section.content.cols,
            rows: section.content.rows
          }
        }
      });

      section.content.rows = section.content.rows - 1;
    };

    function save(preview) {
      var data = [];
      $.each($scope.sections, function(i, section) {
        if (section.type === 'text') {
          data.push(section.content + "\n");
        } else {
          data.push('[block:' + section.type + ']');
          data.push(JSON.stringify(section.content));
          data.push('[/block]');
        }
      });
      return $http.post($scope.path + '/source/' + $scope.id, { data: data.join("\n"), preview: preview });
    }

    $scope.preview = function($event) {
      $event.preventDefault();
      save(true).then(function(content) {
        $window.open($scope.path + '/preview/' + content.data.id);
      });
    };

    $scope.publish = function($event) {
      $event.preventDefault();

      if (confirm('Are you sure you want to publish this page?')) {
        save(false).then(function(content) {
          $window.location.href = $scope.path + '/' + content.data.slug;
        });
      }
    }

  }]).directive('contenteditable', ['$document', function($document) {
    return {
      require: 'ngModel',
      link: function(scope, element, attrs, ngModel) {
        function read() {
          var text = element.text().replace(/
/g, '').replace(/<\/div>/g, "\n").replace(/
/g, "\n").replace(/\n{3,}/g, "\n\n");
          ngModel.$setViewValue(text);
        }

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

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

        // force every copy/paste to be plain/text
        element.bind('paste', function(e) {
          e.preventDefault();
          var text = (e.originalEvent || e).clipboardData.getData('text/plain') || '';
          $document[0].execCommand("insertHTML", false, text);
        });
      }
    };
  }])
;
<|endoftext|>


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

CLASS({
  package: 'foam.ui',
  name: 'WebView',
  extendsModel: 'foam.ui.SimpleView',
  imports: [
    'window',
  ],
  help: 'A view that renders the HTML given to it.',
  properties: [
    {
      name: 'data',
    },
    {
      name: 'intervalId',
    },
  ],
  methods: {
    init: function() {
      this.SUPER();
      this.data$.addListener(function() {
        this.$.outerHTML = this.toHTML();
        this.initHTML();
      }.bind(this));
    },
    toHTML: function() {
      var id = this.id;
      return '';
    },
    initHTML: function() {
      this.SUPER();

      this.$.contentDocument.write(this.data);
      // This is a lazy way of handling the change in size when things like
      // images load asynchronously.
      this.intervalId = this.window.setInterval(this.onResize, 500);
      this.onResize();
    },
    destroy: function() {
      this.window.clearInterval(this.intervalId);
    },
  },
  listeners: [
    {
      name: 'onResize',
      isMerged: 500,
      code: function() {
        if ( ! this.$ ) {
          this.window.clearInterval(this.intervalId);
          return;
        }
        if ( this.$.contentDocument.documentElement )
          this.$.style.height = this.$.contentDocument.documentElement.offsetHeight;
      }
    }
  ]
});
<commit_msg>Wrap the content of the webview in a div and use that div to calculate the height of the iFrame instead of the iFrame's body.<commit_after>/**
 * @license
 * Copyright 2015 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

CLASS({
  package: 'foam.ui',
  name: 'WebView',
  extendsModel: 'foam.ui.SimpleView',
  imports: [
    'window',
  ],
  help: 'A view that renders the HTML given to it.',
  properties: [
    {
      name: 'data',
    },
    {
      name: 'intervalId',
    },
  ],
  methods: {
    init: function() {
      this.SUPER();
      this.data$.addListener(function() {
        this.$.outerHTML = this.toHTML();
        this.initHTML();
      }.bind(this));
    },
    toHTML: function() {
      var id = this.id;
      return '';
    },
    initHTML: function() {
      this.SUPER();

      this.$.contentDocument.write('
' + this.data + '
');
      // This is a lazy way of handling the change in size when things like
      // images load asynchronously.
      this.intervalId = this.window.setInterval(this.onResize, 500);
      this.onResize();
    },
    destroy: function() {
      this.window.clearInterval(this.intervalId);
    },
  },
  listeners: [
    {
      name: 'onResize',
      isMerged: 500,
      code: function() {
        if ( ! this.$ ) {
          this.window.clearInterval(this.intervalId);
          return;
        }
        if ( this.$.contentDocument.documentElement )
          this.$.style.height = this.$.contentDocument.body.children[0].clientHeight + 16;
      }
    }
  ]
});
<|endoftext|>


<commit_before>require([ "jquery", "lib/components/lightbox" ], function($, LightBox) {

  "use strict";

  var $el = $("#js-row--content"),
      linkClass = "js-page-hopper-opener",
      $link = $(""),
      lightbox, isOpen;

  $el
    .on("keydown", function(e) {
      if (isOpen) { return; }

      // 75 =k
      if ( e.keyCode == 75 && (e.metaKey || e.ctrlKey) ) {
        $link.trigger("click");
        e.preventDefault();
      }
    })
    .on(":lightbox/open", function(event, data) {
      if (data.opener == $link) {
        isOpen = true;
        $el.trigger(":lightbox/renderContent", "");

        lightbox.$lightboxContent.addClass("card");
      }
    })
    .on(":flyout/close", function() {
      isOpen = false;
    })
    .append($link);

  lightbox = new LightBox({
    $opener: "." + linkClass
  });
});
<commit_msg>Get content rendering<commit_after>require([ "jquery", "lib/components/lightbox" ], function($, LightBox) {

  "use strict";

  var $el = $("body"),
      linkClass = "js-page-hopper-opener",
      $link = $(""),
      lightbox, isOpen;

  $el
    .on("keydown", function(e) {
      if (isOpen) { return; }

      // 75 =k
      if ( e.keyCode == 75 && (e.metaKey || e.ctrlKey) ) {
        $link.trigger("click");
        e.preventDefault();
      }
    })
    .on(":lightbox/open", function(event, data) {
      if (data.opener == $link[0]) {
        isOpen = true;
        $el.trigger(":lightbox/renderContent", "

");
      }
    })
    .on(":flyout/close", function() {
      isOpen = false;
    })
    .append($link);

  lightbox = new LightBox({
    $el: "body",
    $opener: "." + linkClass
  });
});
<|endoftext|>


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

CLASS({
  package: 'foam.util',
  name: 'Timer',

  properties: [
    {
      model_: 'IntProperty',
      name:  'interval',
      help:  'Interval of time between updating time.',
      units: 'ms',
      defaultValue: 10
    },
    {
      model_: 'IntProperty',
      name:  'i',
      defaultValue: 0
    },
    {
      model_: 'FloatProperty',
      name:  'timeWarp',
      defaultValue: 1.0
    },
    {
      model_: 'IntProperty',
      name:  'duration',
      units: 'ms',
      defaultValue: -1
    },
    {
      model_: 'FloatProperty',
      name: 'percent',
      defaultValue: 0
    },
    {
      model_: 'IntProperty',
      name:  'startTime',
      defaultValue: 0
    },
    {
      model_: 'IntProperty',
      name:  'time',
      help:  'The current time in milliseconds since epoch.',
      preSet: function(_, t) { return Math.ceil(t); },
      defaultValue: 0
    },
    {
      model_: 'IntProperty',
      name:  'second',
      help:  'The second of the current minute.',
      defaultValue: 0
    },
    {
      model_: 'IntProperty',
      name:  'minute',
      help:  'The minute of the current hour.',
      defaultValue: 0
    },
    {
      model_: 'IntProperty',
      name:  'hour',
      help:  'The hour of the current day.',
      defaultValue: 0
    },
    {
      name: 'isStarted',
      defaultValue: false,
      hidden: true
    }
  ],

  actions: [
    {
      name:  'start',
      help:  'Start the timer.',

      isAvailable: function() { return true; },
      isEnabled:   function() { return ! this.isStarted; },
      action:      function() { this.isStarted = true; this.tick(); }
    },
    {
      name:  'step',
      help:  'Step the timer.',

      isAvailable: function() { return true; },
      code: function()      {
        this.i++;
        this.time  += this.interval * this.timeWarp;
        this.second = this.time /    1000 % 60 << 0;
        this.minute = this.time /   60000 % 60 << 0;
        this.hour   = this.time / 3600000 % 24 << 0;
      }
    },
    {
      name:  'stop',
      help:  'Stop the timer.',

      isAvailable: function() { return true; },
      isEnabled: function() { return this.isStarted; },
      code: function() {
        this.isStarted = false;
        if ( this.timeout ) {
          clearTimeout(this.timeout);
          this.timeout = undefined;
        }
      }
    }
  ],

  listeners: [
    {
      name: 'tick',
      isFramed: true,
      code: function(e) {
        this.timeout = undefined;
        if ( ! this.isStarted ) return;

        var prevTime = this.startTime_ || 0;
        this.startTime_ = Date.now();
        this.interval = Math.min(100, this.startTime_ - prevTime);
        this.step();
        this.tick();
      }
    }
  ]
});
<commit_msg>Action action to code migration.<commit_after>/**
 * @license
 * Copyright 2015 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

CLASS({
  package: 'foam.util',
  name: 'Timer',

  properties: [
    {
      model_: 'IntProperty',
      name:  'interval',
      help:  'Interval of time between updating time.',
      units: 'ms',
      defaultValue: 10
    },
    {
      model_: 'IntProperty',
      name:  'i',
      defaultValue: 0
    },
    {
      model_: 'FloatProperty',
      name:  'timeWarp',
      defaultValue: 1.0
    },
    {
      model_: 'IntProperty',
      name:  'duration',
      units: 'ms',
      defaultValue: -1
    },
    {
      model_: 'FloatProperty',
      name: 'percent',
      defaultValue: 0
    },
    {
      model_: 'IntProperty',
      name:  'startTime',
      defaultValue: 0
    },
    {
      model_: 'IntProperty',
      name:  'time',
      help:  'The current time in milliseconds since epoch.',
      preSet: function(_, t) { return Math.ceil(t); },
      defaultValue: 0
    },
    {
      model_: 'IntProperty',
      name:  'second',
      help:  'The second of the current minute.',
      defaultValue: 0
    },
    {
      model_: 'IntProperty',
      name:  'minute',
      help:  'The minute of the current hour.',
      defaultValue: 0
    },
    {
      model_: 'IntProperty',
      name:  'hour',
      help:  'The hour of the current day.',
      defaultValue: 0
    },
    {
      name: 'isStarted',
      defaultValue: false,
      hidden: true
    }
  ],

  actions: [
    {
      name:  'start',
      help:  'Start the timer.',

      isAvailable: function() { return true; },
      isEnabled:   function() { return ! this.isStarted; },
      code:        function() { this.isStarted = true; this.tick(); }
    },
    {
      name:  'step',
      help:  'Step the timer.',

      isAvailable: function() { return true; },
      code: function()      {
        this.i++;
        this.time  += this.interval * this.timeWarp;
        this.second = this.time /    1000 % 60 << 0;
        this.minute = this.time /   60000 % 60 << 0;
        this.hour   = this.time / 3600000 % 24 << 0;
      }
    },
    {
      name:  'stop',
      help:  'Stop the timer.',

      isAvailable: function() { return true; },
      isEnabled: function() { return this.isStarted; },
      code: function() {
        this.isStarted = false;
        if ( this.timeout ) {
          clearTimeout(this.timeout);
          this.timeout = undefined;
        }
      }
    }
  ],

  listeners: [
    {
      name: 'tick',
      isFramed: true,
      code: function(e) {
        this.timeout = undefined;
        if ( ! this.isStarted ) return;

        var prevTime = this.startTime_ || 0;
        this.startTime_ = Date.now();
        this.interval = Math.min(100, this.startTime_ - prevTime);
        this.step();
        this.tick();
      }
    }
  ]
});
<|endoftext|>


<commit_before>const logger = require('./logger')(module)
const Promise = require('bluebird')
const enums = require('./enums')
const dbResult = require('./db-result')

module.exports = function queueFindJob (q, name, raw) {
  logger('queueFindJob: ', name, raw)
  return Promise.resolve().then(() => {
    return q.r
    .db(q.db)
    .table(q.name)
    .getAll(name, { index: enums.index.indexName })
    .orderBy('dateCreated')
    .run(q.queryRunOptions)
  }).then((jobsData) => {
    logger('jobsData', jobsData)
    if (raw) { return jobsData }
    return dbResult.toJob(q, jobsData)
  })
}
<commit_msg>Changed function name<commit_after>const logger = require('./logger')(module)
const Promise = require('bluebird')
const enums = require('./enums')
const dbResult = require('./db-result')

module.exports = function queueFindJobByName (q, name, raw) {
  logger('queueFindJobByName: ', name, raw)
  return Promise.resolve().then(() => {
    return q.r
    .db(q.db)
    .table(q.name)
    .getAll(name, { index: enums.index.indexName })
    .orderBy('dateCreated')
    .run(q.queryRunOptions)
  }).then((jobsData) => {
    logger('jobsData', jobsData)
    if (raw) { return jobsData }
    return dbResult.toJob(q, jobsData)
  })
}
<|endoftext|>


<commit_before>examples = {
  "Drinking Water in bbox (overpass QL)":  {
    "overpass": '<osm-script output="json">\n  <query type="node">\n    <has-kv k="amenity" v="drinking_water"/>\n    <bbox-query/>\n  </query>\n  <print mode="body" order="quadtile"/>\n</osm-script>',
  },
  "Drinking Water in bbox (overpass QL)":  {
    "overpass": '[out:json];\n(\n  node\n    ["amenity"="drinking_water"]\n    (bbox)\n);\nout body;',
  },
  "Platforms in Bolzano": {
    "overpass": '<osm-script output="json">\n'+
                '  <area-query ref="3600047207"/>\n'+
                '  <recurse type="node-way" />\n'+
                '  <query type="way">\n'+
                '    <item />\n'+
                '    <has-kv k="highway" v="platform"/>\n'+
                '  </query>\n'+
                '  <union>\n'+
                '    <item />\n'+
                '    <recurse type="down" />\n'+
                '  </union>\n'+
                '  <print mode="body" order="quadtile"/>\n'+
                '</osm-script>',
  },
  "Turn Restrictions in bbox": {
    "overpass": '<osm-script output="json">\n  <union into="r">\n    <query type="relation">\n      <bbox-query/>\n      <has-kv k="type" v="restriction"/>\n    </query>\n  </union>\n  <union>\n    <item set="r" />\n    <recurse type="relation-node" />\n  </union>\n  <query type="node">\n    <item />\n  </query>\n  <union>\n    <item />\n    <item set="r" />\n  </union>\n  <print mode="body" order="quadtile"/>\n</osm-script>',
  },
  "find and show ways with Straße misspelled": {
    "overpass": '<osm-script output="json">\n  <query type="way">\n    <has-kv k="highway"/>\n    <has-kv k="name" regv="[Ss]trasse"/>\n    <bbox-query/>\n  </query>\n  <union>\n    <item />\n    <recurse type="down" />\n  </union>\n  <print mode="body" order="quadtile"/>\n</osm-script>',
  },
}
<commit_msg>small bugfix (typo) in examples file<commit_after>examples = {
  "Drinking Water in bbox":  {
    "overpass": '<osm-script output="json">\n  <query type="node">\n    <has-kv k="amenity" v="drinking_water"/>\n    <bbox-query/>\n  </query>\n  <print mode="body" order="quadtile"/>\n</osm-script>',
  },
  "Drinking Water in bbox (overpass QL)":  {
    "overpass": '[out:json];\n(\n  node\n    ["amenity"="drinking_water"]\n    (bbox)\n);\nout body;',
  },
  "Platforms in Bolzano": {
    "overpass": '<osm-script output="json">\n'+
                '  <area-query ref="3600047207"/>\n'+
                '  <recurse type="node-way" />\n'+
                '  <query type="way">\n'+
                '    <item />\n'+
                '    <has-kv k="highway" v="platform"/>\n'+
                '  </query>\n'+
                '  <union>\n'+
                '    <item />\n'+
                '    <recurse type="down" />\n'+
                '  </union>\n'+
                '  <print mode="body" order="quadtile"/>\n'+
                '</osm-script>',
  },
  "Turn Restrictions in bbox": {
    "overpass": '<osm-script output="json">\n  <union into="r">\n    <query type="relation">\n      <bbox-query/>\n      <has-kv k="type" v="restriction"/>\n    </query>\n  </union>\n  <union>\n    <item set="r" />\n    <recurse type="relation-node" />\n  </union>\n  <query type="node">\n    <item />\n  </query>\n  <union>\n    <item />\n    <item set="r" />\n  </union>\n  <print mode="body" order="quadtile"/>\n</osm-script>',
  },
  "find and show ways with Straße misspelled": {
    "overpass": '<osm-script output="json">\n  <query type="way">\n    <has-kv k="highway"/>\n    <has-kv k="name" regv="[Ss]trasse"/>\n    <bbox-query/>\n  </query>\n  <union>\n    <item />\n    <recurse type="down" />\n  </union>\n  <print mode="body" order="quadtile"/>\n</osm-script>',
  },
}
<|endoftext|>


<commit_before>import ReactModal from 'react-modal';
import React from 'react';

class HelpBubble extends React.Component {

  constructor(props){
    super(props);
    this.state = {
      modalIsOpen: false
    };
  }

  componentWillMount(){
    // This needs to be called for some reason, and we need to do it by the time the DOM exists.
    ReactModal.setAppElement(document.body);
  }

  closeModal(e){
    this.setState({modalIsOpen: false});
    e.preventDefault();
  }

  openModal(e){
    this.setState({modalIsOpen: true});
    e.preventDefault();
  }

  render(){
    return (

          {this.props.teaserText}

        {// The modal is not logically here, but even while not displayed it needs a location in the DOM.
        this.renderModal()}

    );
  }

  renderModal(){
    // There are three ways to close a modal dialog: click on one of the close buttons,
    // click outside the bounds, or press Escape.
    return (
      <ReactModal isOpen={this.state.modalIsOpen} onRequestClose={this.closeModal}>
        {// Every help box has a title and two close buttons. The content is free-form HTML.

              {this.props.title}

              (ESC)

            {this.props.content}

          {// Fills the empty space

            {""}

}

              (close)

}
      </ReactModal>
    );
  }
}

HelpBubble.propTypes = {
  title: React.PropTypes.string.isRequired, // e.g. 'What is a Note?'
  content: React.PropTypes.object.isRequired, // React DOM objects which will be displayed in the modal text box.
  teaserText: React.PropTypes.string.isRequired // text displayed before the user clicks, e.g. 'Find out more.'
};

export default HelpBubble;

<commit_msg>Bind closeModal and openModal<commit_after>import ReactModal from 'react-modal';
import React from 'react';

class HelpBubble extends React.Component {

  constructor(props){
    super(props);

    this.state = {
      modalIsOpen: false
    };

    this.closeModal = this.closeModal.bind(this);
    this.openModal = this.openModal.bind(this);
  }

  componentWillMount(){
    // This needs to be called for some reason, and we need to do it by the time the DOM exists.
    ReactModal.setAppElement(document.body);
  }

  closeModal(e){
    this.setState({modalIsOpen: false});
    e.preventDefault();
  }

  openModal(e){
    this.setState({modalIsOpen: true});
    e.preventDefault();
  }

  render(){
    return (

          {this.props.teaserText}

        {// The modal is not logically here, but even while not displayed it needs a location in the DOM.
        this.renderModal()}

    );
  }

  renderModal(){
    // There are three ways to close a modal dialog: click on one of the close buttons,
    // click outside the bounds, or press Escape.
    return (
      <ReactModal isOpen={this.state.modalIsOpen} onRequestClose={this.closeModal}>
        {// Every help box has a title and two close buttons. The content is free-form HTML.

              {this.props.title}

              (ESC)

            {this.props.content}

          {// Fills the empty space

            {""}

}

              (close)

}
      </ReactModal>
    );
  }
}

HelpBubble.propTypes = {
  title: React.PropTypes.string.isRequired, // e.g. 'What is a Note?'
  content: React.PropTypes.object.isRequired, // React DOM objects which will be displayed in the modal text box.
  teaserText: React.PropTypes.string.isRequired // text displayed before the user clicks, e.g. 'Find out more.'
};

export default HelpBubble;

<|endoftext|>