<commit_before>var drawingCanvas;
var draw;
var tilew = 32;
var tileh = 32
var maxx = 10;
var maxy = 8;
var treeHp = 3;
var then;
var imgReady = false;
var attackDuration = 1000;

var heroTiles = { "fighter": new Image(), "mage": new Image(),  "thief": new Image()};
heroTiles["fighter"].src = "images/fighter_anim.png";
heroTiles["mage"].src = "images/mage_anim.png";
heroTiles["thief"].src = "images/thief_anim.png";

var gameTiles = { "tree": new Image() };
gameTiles.tree.src = "images/tree.png";
var imgBg = new Image();
imgBg.onload = function () {
	imgReady = true;
};
imgBg.src = "images/background.png";

function Hero(x,y,role,keyset) {
	this.speed = 2.5;
	this.dir = 0;
	this.x=x;
	this.y=y;
	this.role=role;
	this.moving = 0;
	this.lastAttack= 0;
	this.keyset = keyset;

	this.attack = function() { this.lastAttack = Date.now(); };

	this.secSinceLastAttack = function() { return Date.now() - this.lastAttack; };

	this.isAttacking = function() {
	  return this.secSinceLastAttack()<attackDuration;
	};
	this.render = function() {
		movstate = Math.floor(this.moving) % 4;
		if (isEven(movstate)) anim=0
		else anim=((movstate-1)/2)+1;
		if (this.secSinceLastAttack()<500)
		{
		  draw.drawImage(heroTiles[this.role],3*this.dir*tilew,tileh,3*tilew,3*tileh,tilew*(1+this.x)-tilew, tileh*(1+this.y)-tileh,tilew*3,tileh*3);
		} else {
		  draw.drawImage(heroTiles[this.role],3*this.dir*32+32*anim,0,32,32,tilew*(1+this.x), tileh*(1+this.y),32,32);
		};

	};

   this.update = function (modifier) {
	if (!this.isAttacking())
	{
		map.unset(this.x,this.y);
		stillmoving = 0;
		if (this.keyset[0] in keysDown) { // Player holding up
			if (!isBlocked(this.x,Math.floor(this.y)))
			{
			 this.y -= this.speed * modifier;
			 this.dir = 0;
			 stillmoving = 1;
			 if (this.y<=0) { this.y=0; }
			}
		}
		if (this.keyset[1] in keysDown) { // Player holding right
			if (!isBlocked(Math.ceil(this.x),this.y))
			{
			 this.x += this.speed * modifier;
			 this.dir = 1;
			 stillmoving = 1;
			 if (this.x>=maxx) { this.x=maxx; }
			}
		}
		if (this.keyset[2] in keysDown) { // Player holding down
			if (!isBlocked(this.x,Math.ceil(this.y)))
			{
	  		 this.y += this.speed * modifier;
			 this.dir = 2;
			 stillmoving = 1;
			 if (this.y>=maxy) { this.y=maxy; }
			}
		}
		if (this.keyset[3] in keysDown) { // Player holding left
			if (!isBlocked(Math.floor(this.x),this.y))
			{
	 		 this.x -= this.speed * modifier;
			 this.dir = 3;
			 stillmoving = 1;
			 if (this.x<=0) { this.x=0; }
			}
		}
		if (this.keyset[4] in keysDown) { // Player attacking
		  this.attack();
		  this.moving=0;
		}
		if (stillmoving || this.moving>0) {
		 this.moving+=modifier*5;
		}
		if (!stillmoving && Math.floor(this.moving % 4)==0)
		{
			this.moving=0;
		}
		map.set(this.x,this.y,this);
	}
  }
}

function Tree(x,y) {
	this.x = x;
	this.y = y;
	this.hp = treeHp;
	map.set(this.x,this.y,this);

	this.render = function()
	{
	  draw.drawImage(gameTiles["tree"],0,0,32,32,tilew*(1+this.x), tileh*(1+this.y),32,32);
	};

	this.hit = function()
	{
	  this.hp--;
	  if (this.hp==0) {
	    map.unset(this.x,this.y);
	    for (var i=0; i<trees.length; i++)
	    {
	       if (trees[i]==this) trees[i] = "dead";
	    }
	  }
	};
}

function Map() {
	this.world = {};
	for (var y=-1; y<maxy+1; y++)
	{
	  this.world[y] = {};
	  for (var x=-1; x<maxx+1; x++)
	  {
	    if (isEven(x) || isEven(y))
	      this.world[y][x]="free";
	    else
              this.world[y][x]="stone";
	  }
	};

	this.set = function(x,y,to) {
		this.world[Math.round(y)][Math.round(x)] = to;
	};

	this.unset = function(x,y) {
		this.world[Math.round(y)][Math.round(x)] = "free";
	};

	this.get = function(x,y) {
		if (x<0 || y<0 || x>maxx || y>maxy) return "stone";
		return this.world[Math.round(y)][Math.round(x)];
	};

}

var map = new Map();
var players = [new Hero(0,maxy-1,"fighter",[38,39,40,37,32]),new Hero(maxx-1,0,"mage",[104,102,101,100,13])];
var trees = [new Tree(4,4)];

var keysDown = {};

var reset = function () {
}

var fullscreen = function() {
	if (drawingCanvas.requestFullscreen) {
		drawingCanvas.requestFullscreen();
	} else if (drawingCanvas.webkitRequestFullscreen) {
		drawingCanvas.webkitRequestFullscreen();
	} else if (drawingCanvas.mozRequestFullScreen) {
		drawingCanvas.mozRequestFullScreen();
	} else if (drawingCanvas.msRequestFullscreen) {
		drawingCanvas.msRequestFullscreen();
	}
}

var render = function () {
	bg();
	for (var i=0;i<players.length;i++) {
		players[i].render();
	};
	for (var i=0;i<trees.length;i++) {
	  if (trees[i]!="dead")
	    trees[i].render();
	};
};

function isBlocked(x,y) {
	if (isOdd(Math.round(x*10)/10) && isOdd(Math.round(y*10)/10))
		return true;
	if (map.get(x,y)=="free") return false;
	return true;
}

function bg()
{
	draw.drawImage(imgBg,0,0);
}

var main = function () {
	var now = Date.now();
	var delta = now - then;

	for (var i=0;i<players.length;i++)
		players[i].update(delta / 1000);
	render();

	then = now;

	// Request to do this again ASAP
	requestAnimationFrame(main);
};

function init() {
	drawingCanvas = document.getElementById('canvascontainer');

	if(drawingCanvas.getContext) {
		draw = drawingCanvas.getContext('2d');
	}
	bg();

	then = Date.now();
	reset();
	main();

//	test();

}

addEventListener("keydown", function (e) {
	keysDown[e.keyCode] = true;
}, false);

addEventListener("keyup", function (e) {
	delete keysDown[e.keyCode];
}, false);

	var w = window;
	requestAnimationFrame = w.requestAnimationFrame || w.webkitRequestAnimationFrame || w.msRequestAnimationFrame || w.mozRequestAnimationFrame;

<commit_msg>removed old lines<commit_after>var drawingCanvas;
var draw;
var tilew = 32;
var tileh = 32
var maxx = 10;
var maxy = 8;
var treeHp = 3;
var then;
var imgReady = false;
var attackDuration = 1000;

var heroTiles = { "fighter": new Image(), "mage": new Image(),  "thief": new Image()};
heroTiles["fighter"].src = "images/fighter_anim.png";
heroTiles["mage"].src = "images/mage_anim.png";
heroTiles["thief"].src = "images/thief_anim.png";

var gameTiles = { "tree": new Image() };
gameTiles.tree.src = "images/tree.png";
var imgBg = new Image();
imgBg.onload = function () {
	imgReady = true;
};
imgBg.src = "images/background.png";

function Hero(x,y,role,keyset) {
	this.speed = 2.5;
	this.dir = 0;
	this.x=x;
	this.y=y;
	this.role=role;
	this.moving = 0;
	this.lastAttack= 0;
	this.keyset = keyset;

	this.attack = function() { this.lastAttack = Date.now(); };

	this.secSinceLastAttack = function() { return Date.now() - this.lastAttack; };

	this.isAttacking = function() {
	  return this.secSinceLastAttack()<attackDuration;
	};
	this.render = function() {
		movstate = Math.floor(this.moving) % 4;
		if (isEven(movstate)) anim=0
		else anim=((movstate-1)/2)+1;
		if (this.secSinceLastAttack()<500)
		{
		  draw.drawImage(heroTiles[this.role],3*this.dir*tilew,tileh,3*tilew,3*tileh,tilew*(1+this.x)-tilew, tileh*(1+this.y)-tileh,tilew*3,tileh*3);
		} else {
		  draw.drawImage(heroTiles[this.role],3*this.dir*32+32*anim,0,32,32,tilew*(1+this.x), tileh*(1+this.y),32,32);
		};

	};

   this.update = function (modifier) {
	if (!this.isAttacking())
	{
		map.unset(this.x,this.y);
		stillmoving = 0;
		if (this.keyset[0] in keysDown) { // Player holding up
			if (!isBlocked(this.x,Math.floor(this.y)))
			{
			 this.y -= this.speed * modifier;
			 this.dir = 0;
			 stillmoving = 1;
			 if (this.y<=0) { this.y=0; }
			}
		}
		if (this.keyset[1] in keysDown) { // Player holding right
			if (!isBlocked(Math.ceil(this.x),this.y))
			{
			 this.x += this.speed * modifier;
			 this.dir = 1;
			 stillmoving = 1;
			 if (this.x>=maxx) { this.x=maxx; }
			}
		}
		if (this.keyset[2] in keysDown) { // Player holding down
			if (!isBlocked(this.x,Math.ceil(this.y)))
			{
	  		 this.y += this.speed * modifier;
			 this.dir = 2;
			 stillmoving = 1;
			 if (this.y>=maxy) { this.y=maxy; }
			}
		}
		if (this.keyset[3] in keysDown) { // Player holding left
			if (!isBlocked(Math.floor(this.x),this.y))
			{
	 		 this.x -= this.speed * modifier;
			 this.dir = 3;
			 stillmoving = 1;
			 if (this.x<=0) { this.x=0; }
			}
		}
		if (this.keyset[4] in keysDown) { // Player attacking
		  this.attack();
		  this.moving=0;
		}
		if (stillmoving || this.moving>0) {
		 this.moving+=modifier*5;
		}
		if (!stillmoving && Math.floor(this.moving % 4)==0)
		{
			this.moving=0;
		}
		map.set(this.x,this.y,this);
	}
  }
}

function Tree(x,y) {
	this.x = x;
	this.y = y;
	this.hp = treeHp;
	map.set(this.x,this.y,this);

	this.render = function()
	{
	  draw.drawImage(gameTiles["tree"],0,0,32,32,tilew*(1+this.x), tileh*(1+this.y),32,32);
	};

	this.hit = function()
	{
	  this.hp--;
	  if (this.hp==0) {
	    map.unset(this.x,this.y);
	    for (var i=0; i<trees.length; i++)
	    {
	       if (trees[i]==this) trees[i] = "dead";
	    }
	  }
	};
}

function Map() {
	this.world = {};
	for (var y=-1; y<maxy+1; y++)
	{
	  this.world[y] = {};
	  for (var x=-1; x<maxx+1; x++)
	  {
	    if (isEven(x) || isEven(y))
	      this.world[y][x]="free";
	    else
              this.world[y][x]="stone";
	  }
	};

	this.set = function(x,y,to) {
		this.world[Math.round(y)][Math.round(x)] = to;
	};

	this.unset = function(x,y) {
		this.world[Math.round(y)][Math.round(x)] = "free";
	};

	this.get = function(x,y) {
		if (x<0 || y<0 || x>maxx || y>maxy) return "stone";
		return this.world[Math.round(y)][Math.round(x)];
	};

}

var map = new Map();
var players = [new Hero(0,maxy-1,"fighter",[38,39,40,37,32]),new Hero(maxx-1,0,"mage",[104,102,101,100,13])];
var trees = [new Tree(4,4)];

var keysDown = {};

var reset = function () {
}

var fullscreen = function() {
	if (drawingCanvas.requestFullscreen) {
		drawingCanvas.requestFullscreen();
	} else if (drawingCanvas.webkitRequestFullscreen) {
		drawingCanvas.webkitRequestFullscreen();
	} else if (drawingCanvas.mozRequestFullScreen) {
		drawingCanvas.mozRequestFullScreen();
	} else if (drawingCanvas.msRequestFullscreen) {
		drawingCanvas.msRequestFullscreen();
	}
}

var render = function () {
	bg();
	for (var i=0;i<players.length;i++) {
		players[i].render();
	};
	for (var i=0;i<trees.length;i++) {
	  if (trees[i]!="dead")
	    trees[i].render();
	};
};

function isBlocked(x,y) {
	if (isOdd(Math.round(x*10)/10) && isOdd(Math.round(y*10)/10))
		return true;
	if (map.get(x,y)=="free") return false;
	return true;
}

function bg()
{
	draw.drawImage(imgBg,0,0);
}

var main = function () {
	var now = Date.now();
	var delta = now - then;

	for (var i=0;i<players.length;i++)
		players[i].update(delta / 1000);
	render();

	then = now;

	// Request to do this again ASAP
	requestAnimationFrame(main);
};

function init() {
	drawingCanvas = document.getElementById('canvascontainer');

	if(drawingCanvas.getContext) {
		draw = drawingCanvas.getContext('2d');
	}
	bg();

	then = Date.now();
	reset();
	main();

}

addEventListener("keydown", function (e) {
	keysDown[e.keyCode] = true;
}, false);

addEventListener("keyup", function (e) {
	delete keysDown[e.keyCode];
}, false);

	var w = window;
	requestAnimationFrame = w.requestAnimationFrame || w.webkitRequestAnimationFrame || w.msRequestAnimationFrame || w.mozRequestAnimationFrame;

<|endoftext|>


<commit_before>'use strict';

/**
 * @ngdoc overview
 * @name clientApp
 * @description
 * # clientApp
 *
 * Main module of the application.
 */
angular
  .module('myapp', [
    'ngRoute'
  ])
  .config(function ($routeProvider) {
    $routeProvider
      .when('/', {
        templateUrl: 'views/main.html',
        controller: 'MainCtrl',
        controllerAs: 'main'
      })
      .when('/hey', {
        templateUrl: 'views/main.html',
        controller: 'MainCtrl',
        controllerAs: 'main'
      })
      .otherwise({
        redirectTo: '/'
      });
  });
<commit_msg>Update app.js<commit_after>'use strict';

/**
 * @ngdoc overview
 * @name clientApp
 * @description
 * # clientApp
 *
 * Main module of the application.
 */
angular
  .module('myapp', [
    'ngRoute'
  ])
  .config(function ($routeProvider) {
    $routeProvider
      .when('/', {
        templateUrl: '#/views/main.html',
        controller: 'MainCtrl',
        controllerAs: 'main'
      })
      .when('/hey', {
        templateUrl: '#/views/main.html',
        controller: 'MainCtrl',
        controllerAs: 'main'
      })
      .otherwise({
        redirectTo: '/#'
      });
  });
<|endoftext|>


<commit_before>// Copyright (c) 2014 Turbulenz Limited
/* global Protolib: false*/
/* global Config: false*/
/* global Floor: false*/
/* global PhysicsManager: false */

function Application() {}
Application.prototype =
    {
    // Use the properties from Config by default, otherwise use these defaults
    protolibConfig: Protolib.extend(true, {
        fps: 60,
        useShadows: true
    },
                                    Config),

    init: function initFn()
    {
        var errorCallback = function errorCallback(msg) {
            window.alert(msg);
        };
        TurbulenzEngine.onerror = errorCallback;

        var warningCallback = function warningCallback(msg) {
            window.alert(msg);
        };
        TurbulenzEngine.onwarning = warningCallback;

        var protolib = this.protolib;
        var version = protolib.version;
        var requiredVersion = [0, 2, 1];
        if (version === undefined ||
            version[0] !== requiredVersion[0] ||
            version[1] !== requiredVersion[1] ||
            version[2] !== requiredVersion[2])
        {
            protolib.utils.error("Protolib is not requiredVersion");
            return false;
        }

        var mathDevice = protolib.getMathDevice();
        var graphicsDevice = protolib.getGraphicsDevice();
        var inputDevice = protolib.getInputDevice();
        var draw2D = protolib.globals.draw2D;
        var camera = protolib.globals.camera;
        var scene = protolib.globals.scene;

        protolib.setClearColor(mathDevice.v3Build(0.0, 0.0, 0.0));

        // Initialization code goes here

        this.spawnTime = 30;
        this.spawnCount = 0;
        var enemiesList = this.enemiesList = [];

        var floor = this.floor = Floor.create(graphicsDevice, mathDevice);
        var cameraController = this.cameraController = CameraController.create(graphicsDevice, inputDevice, camera);

        // positio camera
        protolib.moveCamera(mathDevice.v3Build(0, 12, -5));
        protolib.setCameraDirection(mathDevice.v3Build(0, -1, -1));

        // Physics
        var physicsDeviceParameters = {};
        var physicsDevice = this.physicsDevice = TurbulenzEngine.createPhysicsDevice(physicsDeviceParameters);

        var dynamicsWorldParameters = { gravity: [0, 0, 0.5] };
        var dynamicsWorld = this.dynamicsWorld = physicsDevice.createDynamicsWorld(dynamicsWorldParameters);
        var physicsManager = this.physicsManager = PhysicsManager.create(mathDevice, physicsDevice, dynamicsWorld);

        // Create floor
        var floorShape = physicsDevice.createPlaneShape({
            normal: mathDevice.v3Build(0, 1, 0),
            distance: 0,
            margin: 0.005
        });

        var floorSceneNode = SceneNode.create({
            name: "Floor1",
            local: mathDevice.m43BuildTranslation(0, 0, 0),
            dynamic: true,
            disabled: false
        });

        var floorRigidBody = physicsDevice.createCollisionObject({
            shape: floorShape,
            transform: mathDevice.m43BuildTranslation(0, 0, 0),
            friction: 0.5,
            restitution: 0.3,
            group: physicsDevice.FILTER_STATIC,
            mask: physicsDevice.FILTER_ALL
        });

        this.physicsManager.addNode(floorSceneNode, floorRigidBody);

        // Collision Detection
        function collisionMade(objectA, objectB, pairContacts) {

            window.console.log('collisionMade');

            // remove node & body from scene
            $.each(enemiesList, function(i){
                if(enemiesList[i].node.name === objectB.userData.name) {
                    enemiesList.splice(i,1); // remove object from list
                    return false;
                }
            })
            physicsManager.deleteNode(objectB.userData);
            if (objectB.userData.scene === scene) scene.removeRootNode(objectB.userData);
        }

        // Add ship
        var shipShape = physicsDevice.createBoxShape({
            halfExtents: mathDevice.v3Build(0.038, 0.038, 0.038),
            margin: 0.001
        });

        // createRigidBody
        var shipRigidBody = physicsDevice.createCollisionObject({
            shape: shipShape,
            mass: 10.0,
            inertia: mathDevice.v3ScalarMul(shipShape.inertia, 10.0),
            transform: mathDevice.m43BuildTranslation(0, 0, 0),
            kinematic: true,
            trigger: true,
            group: physicsDevice.FILTER_CHARACTER,
            mask: physicsDevice.FILTER_DEBRIS,
            //onAddedContacts: collisionMade,
            //onProcessedContacts: collisionMade,
            onRemovedContacts: collisionMade
        });

        var shipMesh = protolib.loadMesh({
            mesh: "models/ship.dae",
            v3Position: mathDevice.v3Build(0, 0, 0),
            v3Size: mathDevice.v3Build(50.0, 50.0, 50.0)
        });

        var ship = this.ship = {
            node: shipMesh.node,
            body: shipRigidBody,
            mesh: shipMesh,
            velocityX: 1
        };

        this.physicsManager.addNode(ship.node, shipRigidBody);

        window.console.log(this.ship);

        // Add light
        protolib.setAmbientLightColor(mathDevice.v3Build(1, 1, 1));

        // Controls
        var settings = {
            debug: true
        }
        protolib.addWatchVariable({
            title: "Enable Debugging",
            object: settings,
            property: "debug",
            group: "Settings",
            type: protolib.watchTypes.SLIDER,
            options: {
                min: 0,
                max: 1,
                step: 1
            }
        });

        protolib.setPreDraw(function drawFn() {

            dynamicsWorld.update();
            physicsManager.update();

        });

        protolib.setPreRendererDraw(function renderDrawFn() {

            floor.render(graphicsDevice, camera);
            if (settings.debug) {
                scene.drawPhysicsNodes(graphicsDevice, protolib.globals.shaderManager, camera, physicsManager);
                scene.drawPhysicsGeometry(graphicsDevice, protolib.globals.shaderManager, camera, physicsManager);
            }

        });

        return true;
    },

    reset: function resetFn()
    {

    },

    spawnEnemy: function spawnEnemyFn()
    {
        var protolib = this.protolib;
        var mathDevice = protolib.getMathDevice();
        var physicsDevice = this.physicsDevice;

        // Create enemy
        var max = 10;
        var spawnY = -100;
        var randomX = Math.random()*(max-(-max)+1)+(-max);

        var enemyShape = physicsDevice.createBoxShape({
            halfExtents: mathDevice.v3Build(0.5, 0.5, 0.5),
            margin: 0.001
        });

        var enemyBody = this.enemyBody = physicsDevice.createRigidBody({
            shape: enemyShape,
            mass: 1.0,
            inertia: mathDevice.v3ScalarMul(enemyShape.inertia, 1.0),
            transform: mathDevice.m43BuildTranslation(randomX, 0, spawnY),
            friction: 0.8,
            restitution: 0.2,
            angularDamping: 0.4,
            linearVelocity: mathDevice.v3Build(0, 0, 10),
            group: physicsDevice.FILTER_DEBRIS,
            mask: physicsDevice.FILTER_CHARACTER
        });

        var enemyMesh = protolib.loadMesh({
            mesh: "models/cube.dae",
            v3Position: mathDevice.v3Build(randomX, 0, spawnY),
            v3Size: mathDevice.v3Build(1.0, 1.0, 1.0)
        });

        var enemy = {
            node: enemyMesh.node,
            body: enemyBody,
            mesh: enemyMesh,
        };

        this.physicsManager.addNode(enemy.node, enemyBody);

        this.enemiesList.push(enemy);

    },

    update: function updateFn()
    {
        var protolib = this.protolib;
        var mathDevice = protolib.getMathDevice();
        var graphicsDevice = protolib.getGraphicsDevice();
        var delta = protolib.time.app.delta;
        var camera = protolib.globals.camera;

        if (protolib.beginFrame())
        {
            // Update code goes here

            this.spawnCount += 1;
            if (this.spawnCount >= this.spawnTime) {
                this.spawnEnemy();
                this.spawnCount = 0;
            }

            // Move player
            var keyDown = false;

            var shipVelocity = this.ship.velocityX;
            var shipPosition = this.ship.mesh.v3Position;
            if (protolib.isKeyDown(protolib.keyCodes.LEFT))
            {
                shipPosition[0] -= shipVelocity;
                keyDown = true;
            }
            if (protolib.isKeyDown(protolib.keyCodes.RIGHT))
            {
                shipPosition[0] += shipVelocity;
                keyDown = true;
            }
            if (keyDown)
            {
                this.ship.mesh.setPosition(mathDevice.v3Build( shipPosition[0], 0, 0));
            }

            this.cameraController.update();
            protolib.endFrame();
        }
    },

    destroy: function destroyFn()
    {
        var protolib = this.protolib;
        if (protolib)
        {
            // Destruction code goes here
            protolib.destroy();
            this.protolib = null;
        }
    }
};

// Application constructor function
Application.create = function applicationCreateFn(params)
{
    var app = new Application();
    app.protolib = params.protolib;
    if (!app.protolib)
    {
        var console = window.console;
        if (console)
        {
            console.error("Protolib could not be found");
        }
        return null;
    }
    if (!app.init())
    {
        app.protolib.utils.error("Protolib could not be initialized");
        return null;
    }
    return app;
};
<commit_msg>movement boundaries<commit_after>// Copyright (c) 2014 Turbulenz Limited
/* global Protolib: false*/
/* global Config: false*/
/* global Floor: false*/
/* global PhysicsManager: false */

function Application() {}
Application.prototype =
    {
    // Use the properties from Config by default, otherwise use these defaults
    protolibConfig: Protolib.extend(true, {
        fps: 60,
        useShadows: true
    },
                                    Config),

    init: function initFn()
    {
        var errorCallback = function errorCallback(msg) {
            window.alert(msg);
        };
        TurbulenzEngine.onerror = errorCallback;

        var warningCallback = function warningCallback(msg) {
            window.alert(msg);
        };
        TurbulenzEngine.onwarning = warningCallback;

        var protolib = this.protolib;
        var version = protolib.version;
        var requiredVersion = [0, 2, 1];
        if (version === undefined ||
            version[0] !== requiredVersion[0] ||
            version[1] !== requiredVersion[1] ||
            version[2] !== requiredVersion[2])
        {
            protolib.utils.error("Protolib is not requiredVersion");
            return false;
        }

        var mathDevice = protolib.getMathDevice();
        var graphicsDevice = protolib.getGraphicsDevice();
        var inputDevice = protolib.getInputDevice();
        var draw2D = protolib.globals.draw2D;
        var camera = protolib.globals.camera;
        var scene = protolib.globals.scene;

        protolib.setClearColor(mathDevice.v3Build(0.0, 0.0, 0.0));

        // Initialization code goes here

        this.spawnTime = 30;
        this.spawnCount = 0;
        this.boundaryMax = 20;
        var enemiesList = this.enemiesList = [];

        var floor = this.floor = Floor.create(graphicsDevice, mathDevice);
        //var cameraController = this.cameraController = CameraController.create(graphicsDevice, inputDevice, camera);

        // positio camera
        protolib.moveCamera(mathDevice.v3Build(0, 12, -5));
        protolib.setCameraDirection(mathDevice.v3Build(0, -1, -1));

        // Physics
        var physicsDeviceParameters = {};
        var physicsDevice = this.physicsDevice = TurbulenzEngine.createPhysicsDevice(physicsDeviceParameters);

        var dynamicsWorldParameters = { gravity: [0, 0, 0.5] };
        var dynamicsWorld = this.dynamicsWorld = physicsDevice.createDynamicsWorld(dynamicsWorldParameters);
        var physicsManager = this.physicsManager = PhysicsManager.create(mathDevice, physicsDevice, dynamicsWorld);

        // Create floor
        var floorShape = physicsDevice.createPlaneShape({
            normal: mathDevice.v3Build(0, 1, 0),
            distance: 0,
            margin: 0.005
        });

        var floorSceneNode = SceneNode.create({
            name: "Floor1",
            local: mathDevice.m43BuildTranslation(0, 0, 0),
            dynamic: true,
            disabled: false
        });

        var floorRigidBody = physicsDevice.createCollisionObject({
            shape: floorShape,
            transform: mathDevice.m43BuildTranslation(0, 0, 0),
            friction: 0.5,
            restitution: 0.3,
            group: physicsDevice.FILTER_STATIC,
            mask: physicsDevice.FILTER_ALL
        });

        this.physicsManager.addNode(floorSceneNode, floorRigidBody);

        // Collision Detection
        function collisionMade(objectA, objectB, pairContacts) {

            window.console.log('collisionMade');

            // remove node & body from scene
            $.each(enemiesList, function(i){
                if(enemiesList[i].node.name === objectB.userData.name) {
                    enemiesList.splice(i,1); // remove object from list
                    return false;
                }
            })
            physicsManager.deleteNode(objectB.userData);
            if (objectB.userData.scene === scene) scene.removeRootNode(objectB.userData);
        }

        // Add ship
        var shipShape = physicsDevice.createBoxShape({
            halfExtents: mathDevice.v3Build(0.038, 0.038, 0.038),
            margin: 0.001
        });

        // createRigidBody
        var shipRigidBody = physicsDevice.createCollisionObject({
            shape: shipShape,
            mass: 10.0,
            inertia: mathDevice.v3ScalarMul(shipShape.inertia, 10.0),
            transform: mathDevice.m43BuildTranslation(0, 0, 0),
            kinematic: true,
            trigger: true,
            group: physicsDevice.FILTER_CHARACTER,
            mask: physicsDevice.FILTER_DEBRIS,
            //onAddedContacts: collisionMade,
            //onProcessedContacts: collisionMade,
            onRemovedContacts: collisionMade
        });

        var shipMesh = protolib.loadMesh({
            mesh: "models/ship.dae",
            v3Position: mathDevice.v3Build(0, 0, 0),
            v3Size: mathDevice.v3Build(50.0, 50.0, 50.0)
        });

        var ship = this.ship = {
            node: shipMesh.node,
            body: shipRigidBody,
            mesh: shipMesh,
            velocityX: 0.5
        };

        this.physicsManager.addNode(ship.node, shipRigidBody);

        window.console.log(this.ship);

        // Add light
        protolib.setAmbientLightColor(mathDevice.v3Build(1, 1, 1));

        // Controls
        var settings = {
            debug: false
        }
        protolib.addWatchVariable({
            title: "Enable Debugging",
            object: settings,
            property: "debug",
            group: "Settings",
            type: protolib.watchTypes.SLIDER,
            options: {
                min: 0,
                max: 1,
                step: 1
            }
        });

        protolib.setPreDraw(function drawFn() {

            dynamicsWorld.update();
            physicsManager.update();

        });

        protolib.setPreRendererDraw(function renderDrawFn() {

            floor.render(graphicsDevice, camera);
            if (settings.debug) {
                scene.drawPhysicsNodes(graphicsDevice, protolib.globals.shaderManager, camera, physicsManager);
                scene.drawPhysicsGeometry(graphicsDevice, protolib.globals.shaderManager, camera, physicsManager);
            }

        });

        return true;
    },

    reset: function resetFn()
    {

    },

    spawnEnemy: function spawnEnemyFn()
    {
        var protolib = this.protolib;
        var mathDevice = protolib.getMathDevice();
        var physicsDevice = this.physicsDevice;

        // Create enemy
        var spawnY = -100;
        var randomX = Math.random()*(this.boundaryMax-(-this.boundaryMax)+1)+(-this.boundaryMax);

        var enemyShape = physicsDevice.createBoxShape({
            halfExtents: mathDevice.v3Build(0.5, 0.5, 0.5),
            margin: 0.001
        });

        var enemyBody = this.enemyBody = physicsDevice.createRigidBody({
            shape: enemyShape,
            mass: 1.0,
            inertia: mathDevice.v3ScalarMul(enemyShape.inertia, 1.0),
            transform: mathDevice.m43BuildTranslation(randomX, 0, spawnY),
            friction: 0.8,
            restitution: 0.2,
            angularDamping: 0.4,
            linearVelocity: mathDevice.v3Build(0, 0, 10),
            group: physicsDevice.FILTER_DEBRIS,
            mask: physicsDevice.FILTER_CHARACTER
        });

        var enemyMesh = protolib.loadMesh({
            mesh: "models/cube.dae",
            v3Position: mathDevice.v3Build(randomX, 0, spawnY),
            v3Size: mathDevice.v3Build(1.0, 1.0, 1.0)
        });

        var enemy = {
            node: enemyMesh.node,
            body: enemyBody,
            mesh: enemyMesh,
        };

        this.physicsManager.addNode(enemy.node, enemyBody);

        this.enemiesList.push(enemy);

    },

    update: function updateFn()
    {
        var protolib = this.protolib;
        var mathDevice = protolib.getMathDevice();
        var graphicsDevice = protolib.getGraphicsDevice();
        var delta = protolib.time.app.delta;
        var camera = protolib.globals.camera;

        if (protolib.beginFrame())
        {
            // Update code goes here

            this.spawnCount += 1;
            if (this.spawnCount >= this.spawnTime) {
                this.spawnEnemy();
                this.spawnCount = 0;
            }

            // Move player
            var keyDown = false;

            var shipVelocity = this.ship.velocityX;
            var shipPosition = this.ship.mesh.v3Position;
            var posDelta = shipPosition[0];
            if (protolib.isKeyDown(protolib.keyCodes.LEFT))
            {
                shipPosition[0] -= shipVelocity;
                keyDown = true;
            }
            if (protolib.isKeyDown(protolib.keyCodes.RIGHT))
            {
                shipPosition[0] += shipVelocity;
                keyDown = true;
            }

            shipPosition[0] = protolib.utils.clamp(shipPosition[0], -this.boundaryMax-5, this.boundaryMax+5);
            this.ship.mesh.setPosition(shipPosition);
            posDelta = this.ship.mesh.v3Position[0] - posDelta;

            if (posDelta != 0) protolib.moveCamera(mathDevice.v3Build(posDelta, 0, 0));
            //this.cameraController.update();

            protolib.endFrame();
        }
    },

    destroy: function destroyFn()
    {
        var protolib = this.protolib;
        if (protolib)
        {
            // Destruction code goes here
            protolib.destroy();
            this.protolib = null;
        }
    }
};

// Application constructor function
Application.create = function applicationCreateFn(params)
{
    var app = new Application();
    app.protolib = params.protolib;
    if (!app.protolib)
    {
        var console = window.console;
        if (console)
        {
            console.error("Protolib could not be found");
        }
        return null;
    }
    if (!app.init())
    {
        app.protolib.utils.error("Protolib could not be initialized");
        return null;
    }
    return app;
};
<|endoftext|>


<commit_before>"use strict";
Relive.useSingleton = false;

window.addEventListener("load", function ()
{
    var load, latest = [], title = document.title, start, actions,
            streamMenuItems = Array.prototype.slice.call(document.querySelectorAll("#menu .group-stream"), 0);

    Object.toArray = function (obj)
    {
        return Object.keys(obj)
            .reduce(function (list, key)
            {
                list.push(obj[key]);
                return list;
            }, []);
    };

    function pause ()
    {
        Replayer.pause();
        document.body.style.overflow = "";
    }

    function menu (full)
    {
        streamMenuItems.forEach(function (item)
        {
            if (full)
            {
                item.removeAttribute("data-disabled");
            }
            else
            {
                item.setAttribute("data-disabled", "disabled");
            }
        });
        document.getElementById("menu").style.display = (Notifications.supported || full ? "" : "none");
    }

    actions = {
        stream: function ()
        {
            var bits, station, stream;

            // Detect a URL with #stream-0-0 or #track-0-0-0
            if (/^#(?:station-[\da-zA-z]+|stream-[\da-zA-z]+-[\da-zA-z]+|track-[\da-zA-z]+-[\da-zA-z]+-[\da-zA-z]+)$/.test(location.hash))
            {
                bits = location.hash.split("-");
                start = Relive.fromBase62(bits[3] || "");

                try
                {
                    station = Relive.fromBase62(bits[1]);

                    if (bits[0] === "#station")
                    {
                        station = document.querySelector("ul [data-id='" + station + "'] > div");
                        station.scrollIntoView();
                        station.click();
                        actions.stations();
                    }
                    else
                    {
                        stream = Relive.fromBase62(bits[2]);
                        document.querySelector("[data-id='" + station + "'] [data-id='" + stream + "']").click();
                    }
                }
                catch (e)
                {
                    console.log("There is no station ", station, stream ? " stream " + stream : "", " only Zuul.");
                }
            }
        },
        latest: function ()
        {
            var element = document.getElementById("latest");
            element.className = "active";
            element.nextElementSibling.className = "";

            document.title = title;
            document.querySelector("#lists").style.marginLeft = "";
            document.querySelector("#lists > ol").style.marginLeft = "";

            menu(false);
            pause();
        },
        stations: function ()
        {
            var element = document.getElementById("stations");
            element.className = "active";
            element.previousElementSibling.className = "";

            document.title = title;
            document.querySelector("#lists").style.marginLeft = "";
            document.querySelector("#lists > ol").style.marginLeft = "-100%";

            menu(false);
            pause();
        }
    };
    actions[null] = actions.latest;

    function entry (station, stream)
    {
        return App.entry(station, stream, menu, function ()
        {
            Replayer.loadStream(station, stream, start);
        });
    }

    function latestStreams ()
    {
        var date, list, lists;

        if (latest)
        {
            lists = document.getElementById("lists");

            date = new Date();
            date = date.setMonth(date.getMonth() - 3);

            list = lists.children[2];
            list.setAttribute("reversed", "reversed");

            latest.sort(function (a, b)
            {
                return b.timestamp - a.timestamp;
            })
            .every(function (stream, i)
            {
                list.appendChild(entry(stream._station, stream));
                return stream.timestamp >= date || list.children.length < 25;
            });

            list.className = "loaded";
            latest = null;

            // Firefox tries to restore the scroll state, which is now invalid.
            // Unfortunately this creates a funky state where the content is at
            // the top but the scrollbar is wherever Firefox put it. If you use
            // the scroll wheel, the page moves down from the top. Use the
            // scrollbar and Firefox snaps the page to its location first.
            window.scrollTo(0, 0);

            if (history.state && history.state.name === "stations")
            {
                actions.stations();
            }
            actions.stream();
        }
    };

    function stationInfo (station, parent)
    {
        Relive.loadStationInfo(station.id, function (info)
        {
            var url, list, streams;

            if (station.websiteURL)
            {
                url = document.createElement("a");
                url.href = station.websiteURL;
                url.textContent = station.websiteURL;
                url.addEventListener("click", function (event)
                {
                    event.stopPropagation();
                });
                parent.firstChild.appendChild(url);
            }

            list = document.createElement("ol");
            list.setAttribute("reversed", "reversed");

            // Again? :(
            streams = Object.toArray(info.streams)
                .sort(function (a, b)
                {
                    return b.timestamp - a.timestamp;
                });

            streams.forEach(function (stream)
            {
                list.appendChild(entry(station, stream));

                if (latest)
                {
                    stream._station = station;
                    latest.push(stream);
                }
            });

            if (latest)
            {
                clearTimeout(load);
                load = setTimeout(latestStreams, 2000);
            }

            parent.appendChild(list);
        }, error);
    };

    Relive.loadStations(function (stations)
    {
        var list = document.createElement("ul");

        // Why is this an object? When will there ever be meaningful holes in the list?
        stations = Object.toArray(stations)
            .sort(function (a, b)
            {
                return a.name.localeCompare(b.name);
            });

        stations.forEach(function (station, i)
        {
            var name, entry;

            name = document.createElement("div");
            name.addEventListener("click", function (event)
            {
                entry.className = (entry.className ? "" : "open");
                entry.style.height = (entry.className ? entry.scrollHeight + "px" : "");
            });
            name.textContent = station.name;

            entry = document.createElement("li");
            entry.setAttribute("data-id", station.id);
            entry.appendChild(name);
            list.appendChild(entry);

            stationInfo(station, entry);
        });

        document.getElementById("lists")
            .appendChild(document.createElement("ol"))
            .parentNode.appendChild(list);
    }, error);

    document.getElementById("latest").addEventListener("click", function (event)
    {
        if (event.target.className !== "active")
        {
            actions.latest();

            if (history.pushState)
            {
                history.pushState({
                    name: "latest"
                }, "");
            }
        }
    });

    document.getElementById("stations").addEventListener("click", function (event)
    {
        if (event.target.className !== "active")
        {
            actions.stations();

            if (history.pushState)
            {
                history.pushState({
                    name: "stations"
                }, "");
            }
        }
    });

    document.querySelector("#menu > span").addEventListener("click", function (event)
    {
        event.target.parentNode.className = (event.target.parentNode.className ? "" : "open");
    });

    if (Notifications.supported)
    {
        (function ()
        {
            var setting = document.getElementById("notify-segment-changes");

            if (localStorage)
            {
                setting.checked = (localStorage.notifySegmentChanges === "true");
            }

            setting.addEventListener("change", function (event)
            {
                if (localStorage)
                {
                    localStorage.notifySegmentChanges = setting.checked;
                }
            });
        }());
    }
    else
    {
        // If no notification support, hide the menu by default and remove the only dependent option.
        // The menu will be unhidden on the replayer screen to allow access to the remaining features.
        document.getElementById("menu").style.display = "none";
        document.getElementById("notify-segment-changes").parentNode.setAttribute("data-disabled", "disabled");
        document.querySelector("#lists header").style.paddingRight = "1em";
    }

    // This will break the shortcut to turn on "caret browsing" in Firefox.
    // It is here for compatibility with the desktop client.
    Events.keydown(window, 118, 120, function (event)
    {
        if (event.keyCode === 118 && (document.querySelector("#lists").style.marginLeft || document.querySelector("#stations.active") === null))
        {
            document.querySelector("#lists > ol").style.marginLeft = "-100%";
            document.getElementById("latest").className = "";
            document.getElementById("stations").className = "active";
            document.getElementById("back").click();
        }
        else if (event.keyCode === 120)
        {
            document.querySelector("#menu > span").click();
        }
    });

    document.getElementById("back").addEventListener("click", function (event)
    {
        pause();
        start = null;

        menu(false);

        // Pausing is asynchronous and may do a history replacement which would happen after
        // the push state below if the action wasn't placed at the end of the event queue.
        setTimeout(function ()
        {
            if (history.pushState)
            {
                history.pushState({
                    name: document.querySelector("#latest.active,#stations.active").id
                }, "");
            }
            else
            {
                location.hash = "";
            }

            document.querySelector("#lists").style.marginLeft = "";
            document.title = title;
        }, 1);
    });

    if (history.pushState)
    {
        window.addEventListener("popstate", function (event)
        {
            actions[history.state && history.state.name]();
        });
    }

    streamMenuItems.forEach(function (item)
    {
        if (Copy.forceFallback)
        {
            item.innerHTML = item.innerHTML.replace(/\s+$/, "") + "...";
        }
        item.addEventListener("click", function (event)
        {
            document.dispatchEvent(Events.create(event.target.getAttribute("data-event")));
            document.getElementById("menu").className = "";
        });
    });
});
<commit_msg>It's App.error not just error.<commit_after>"use strict";
Relive.useSingleton = false;

window.addEventListener("load", function ()
{
    var load, latest = [], title = document.title, start, actions,
            streamMenuItems = Array.prototype.slice.call(document.querySelectorAll("#menu .group-stream"), 0);

    Object.toArray = function (obj)
    {
        return Object.keys(obj)
            .reduce(function (list, key)
            {
                list.push(obj[key]);
                return list;
            }, []);
    };

    function pause ()
    {
        Replayer.pause();
        document.body.style.overflow = "";
    }

    function menu (full)
    {
        streamMenuItems.forEach(function (item)
        {
            if (full)
            {
                item.removeAttribute("data-disabled");
            }
            else
            {
                item.setAttribute("data-disabled", "disabled");
            }
        });
        document.getElementById("menu").style.display = (Notifications.supported || full ? "" : "none");
    }

    actions = {
        stream: function ()
        {
            var bits, station, stream;

            // Detect a URL with #stream-0-0 or #track-0-0-0
            if (/^#(?:station-[\da-zA-z]+|stream-[\da-zA-z]+-[\da-zA-z]+|track-[\da-zA-z]+-[\da-zA-z]+-[\da-zA-z]+)$/.test(location.hash))
            {
                bits = location.hash.split("-");
                start = Relive.fromBase62(bits[3] || "");

                try
                {
                    station = Relive.fromBase62(bits[1]);

                    if (bits[0] === "#station")
                    {
                        station = document.querySelector("ul [data-id='" + station + "'] > div");
                        station.scrollIntoView();
                        station.click();
                        actions.stations();
                    }
                    else
                    {
                        stream = Relive.fromBase62(bits[2]);
                        document.querySelector("[data-id='" + station + "'] [data-id='" + stream + "']").click();
                    }
                }
                catch (e)
                {
                    console.log("There is no station ", station, stream ? " stream " + stream : "", " only Zuul.");
                }
            }
        },
        latest: function ()
        {
            var element = document.getElementById("latest");
            element.className = "active";
            element.nextElementSibling.className = "";

            document.title = title;
            document.querySelector("#lists").style.marginLeft = "";
            document.querySelector("#lists > ol").style.marginLeft = "";

            menu(false);
            pause();
        },
        stations: function ()
        {
            var element = document.getElementById("stations");
            element.className = "active";
            element.previousElementSibling.className = "";

            document.title = title;
            document.querySelector("#lists").style.marginLeft = "";
            document.querySelector("#lists > ol").style.marginLeft = "-100%";

            menu(false);
            pause();
        }
    };
    actions[null] = actions.latest;

    function entry (station, stream)
    {
        return App.entry(station, stream, menu, function ()
        {
            Replayer.loadStream(station, stream, start);
        });
    }

    function latestStreams ()
    {
        var date, list, lists;

        if (latest)
        {
            lists = document.getElementById("lists");

            date = new Date();
            date = date.setMonth(date.getMonth() - 3);

            list = lists.children[2];
            list.setAttribute("reversed", "reversed");

            latest.sort(function (a, b)
            {
                return b.timestamp - a.timestamp;
            })
            .every(function (stream, i)
            {
                list.appendChild(entry(stream._station, stream));
                return stream.timestamp >= date || list.children.length < 25;
            });

            list.className = "loaded";
            latest = null;

            // Firefox tries to restore the scroll state, which is now invalid.
            // Unfortunately this creates a funky state where the content is at
            // the top but the scrollbar is wherever Firefox put it. If you use
            // the scroll wheel, the page moves down from the top. Use the
            // scrollbar and Firefox snaps the page to its location first.
            window.scrollTo(0, 0);

            if (history.state && history.state.name === "stations")
            {
                actions.stations();
            }
            actions.stream();
        }
    };

    function stationInfo (station, parent)
    {
        Relive.loadStationInfo(station.id, function (info)
        {
            var url, list, streams;

            if (station.websiteURL)
            {
                url = document.createElement("a");
                url.href = station.websiteURL;
                url.textContent = station.websiteURL;
                url.addEventListener("click", function (event)
                {
                    event.stopPropagation();
                });
                parent.firstChild.appendChild(url);
            }

            list = document.createElement("ol");
            list.setAttribute("reversed", "reversed");

            // Again? :(
            streams = Object.toArray(info.streams)
                .sort(function (a, b)
                {
                    return b.timestamp - a.timestamp;
                });

            streams.forEach(function (stream)
            {
                list.appendChild(entry(station, stream));

                if (latest)
                {
                    stream._station = station;
                    latest.push(stream);
                }
            });

            if (latest)
            {
                clearTimeout(load);
                load = setTimeout(latestStreams, 2000);
            }

            parent.appendChild(list);
        }, App.error);
    };

    Relive.loadStations(function (stations)
    {
        var list = document.createElement("ul");

        // Why is this an object? When will there ever be meaningful holes in the list?
        stations = Object.toArray(stations)
            .sort(function (a, b)
            {
                return a.name.localeCompare(b.name);
            });

        stations.forEach(function (station, i)
        {
            var name, entry;

            name = document.createElement("div");
            name.addEventListener("click", function (event)
            {
                entry.className = (entry.className ? "" : "open");
                entry.style.height = (entry.className ? entry.scrollHeight + "px" : "");
            });
            name.textContent = station.name;

            entry = document.createElement("li");
            entry.setAttribute("data-id", station.id);
            entry.appendChild(name);
            list.appendChild(entry);

            stationInfo(station, entry);
        });

        document.getElementById("lists")
            .appendChild(document.createElement("ol"))
            .parentNode.appendChild(list);
    }, App.error);

    document.getElementById("latest").addEventListener("click", function (event)
    {
        if (event.target.className !== "active")
        {
            actions.latest();

            if (history.pushState)
            {
                history.pushState({
                    name: "latest"
                }, "");
            }
        }
    });

    document.getElementById("stations").addEventListener("click", function (event)
    {
        if (event.target.className !== "active")
        {
            actions.stations();

            if (history.pushState)
            {
                history.pushState({
                    name: "stations"
                }, "");
            }
        }
    });

    document.querySelector("#menu > span").addEventListener("click", function (event)
    {
        event.target.parentNode.className = (event.target.parentNode.className ? "" : "open");
    });

    if (Notifications.supported)
    {
        (function ()
        {
            var setting = document.getElementById("notify-segment-changes");

            if (localStorage)
            {
                setting.checked = (localStorage.notifySegmentChanges === "true");
            }

            setting.addEventListener("change", function (event)
            {
                if (localStorage)
                {
                    localStorage.notifySegmentChanges = setting.checked;
                }
            });
        }());
    }
    else
    {
        // If no notification support, hide the menu by default and remove the only dependent option.
        // The menu will be unhidden on the replayer screen to allow access to the remaining features.
        document.getElementById("menu").style.display = "none";
        document.getElementById("notify-segment-changes").parentNode.setAttribute("data-disabled", "disabled");
        document.querySelector("#lists header").style.paddingRight = "1em";
    }

    // This will break the shortcut to turn on "caret browsing" in Firefox.
    // It is here for compatibility with the desktop client.
    Events.keydown(window, 118, 120, function (event)
    {
        if (event.keyCode === 118 && (document.querySelector("#lists").style.marginLeft || document.querySelector("#stations.active") === null))
        {
            document.querySelector("#lists > ol").style.marginLeft = "-100%";
            document.getElementById("latest").className = "";
            document.getElementById("stations").className = "active";
            document.getElementById("back").click();
        }
        else if (event.keyCode === 120)
        {
            document.querySelector("#menu > span").click();
        }
    });

    document.getElementById("back").addEventListener("click", function (event)
    {
        pause();
        start = null;

        menu(false);

        // Pausing is asynchronous and may do a history replacement which would happen after
        // the push state below if the action wasn't placed at the end of the event queue.
        setTimeout(function ()
        {
            if (history.pushState)
            {
                history.pushState({
                    name: document.querySelector("#latest.active,#stations.active").id
                }, "");
            }
            else
            {
                location.hash = "";
            }

            document.querySelector("#lists").style.marginLeft = "";
            document.title = title;
        }, 1);
    });

    if (history.pushState)
    {
        window.addEventListener("popstate", function (event)
        {
            actions[history.state && history.state.name]();
        });
    }

    streamMenuItems.forEach(function (item)
    {
        if (Copy.forceFallback)
        {
            item.innerHTML = item.innerHTML.replace(/\s+$/, "") + "...";
        }
        item.addEventListener("click", function (event)
        {
            document.dispatchEvent(Events.create(event.target.getAttribute("data-event")));
            document.getElementById("menu").className = "";
        });
    });
});
<|endoftext|>


<commit_before>'use strict';

angular.module('yololiumApp', [
  'ngCookies',
  'ngResource',
  'ngSanitize',
  'duScroll',
  'ui.router',
  'ui.bootstrap',
  'steve'
])
  .config(function ($stateProvider, $urlRouterProvider, $httpProvider/*, stConfig*/) {
    var nav
      , footer
      ;

    // This identifies your website in the createToken call
    //window.Stripe.setPublishableKey(StApi.stripe.publicKey);

    // IMPORTANT: (Issue #4)
    // These funny arrays (in resolve) are neccessary because ui.router
    // doesn't get properly mangled by ng-min
    // See https://github.com/yeoman/generator-angular#minification-safe
    nav = {
      templateUrl: '/views/nav.html'
    , controller: 'NavCtrl as N'
    , resolve: {
        mySession: ['StSession', function (StSession) {
          return StSession.get();
        }]
      }
    };

    footer = {
      templateUrl: '/views/footer.html'
    , controller: 'FooterCtrl as F'
    };

    //$locationProvider.html5Mode(true);

    // Deal with missing trailing slash
    $urlRouterProvider.rule(function($injector, $location) {
      var path = $location.path(), search = $location.search()
        ;

      if (path[path.length - 1] === '/') {
        return;
      }

      if (Object.keys(search).length === 0) {
        return path + '/';
      }

      var params = []
        ;

      angular.forEach(search, function(v, k){
        params.push(k + '=' + v);
      });

      return path + '/?' + params.join('&');
    });
    $urlRouterProvider.otherwise('/');

    $stateProvider
      .state('root', {
        url: '/'
      , views: {
          body: {
            template: '

'
          , controller: function ($state, mySession, stConfig) {
              if (!stConfig.useSplash) {
                $state.go('home');
                return;
              }

              if (!mySession || !mySession.account || 'guest' === mySession.account.role) {
                $state.go('splash');
              } else {
                $state.go('home');
              }
            }
          , resolve: {
              mySession: ['StSession', function (StSession) {
                console.log('hello world');
                return StSession.get();
              }]
            }
          }
        }
      })

      .state('home', {
        views: {
          nav: nav
        , body: {
            templateUrl: 'views/main.html'
          , controller: 'MainCtrl as M'
          , resolve: {
              mySession: ['StSession', function (StSession) {
                console.log('hello world');
                return StSession.get();
              }]
            }
          }
        , footer: footer
        }
      })

      // This is the root state for not-logged-in users
      .state('splash', {
        url: '/splash/'
      , views: {
          nav: nav
        , body: {
            templateUrl: 'views/splash.html'
          , controller: 'SplashCtrl as S'
          , resolve: {
              mySession: ['StSession', function (StSession) {
                return StSession.get();
              }]
            }
          }
        , footer: footer
        }
      })

      .state('user', {
        url: '/user/'
      , views: {
          nav: nav
        , body: {
            templateUrl: 'views/user.html'
          , controller: 'UserCtrl as U'
          , resolve: {
              mySession: ['StSession', function (StSession) {
                return StSession.get();
              }]
            }
          }
        , footer: footer
        }
      })

      .state('oauth', {
        url: '/authorize/:token/'
      , views: {
          nav: nav
        , body: {
            templateUrl: 'views/oauth.html'
          , controller: 'OauthCtrl as O'
          , resolve: {
            }
          }
        , footer: footer
        }
      })

      .state('admin', {
        url: '/admin/'
      , views: {
          nav: nav
        , body: {
            templateUrl: 'views/admin.html'
          , controller: 'AdminCtrl as A'
          , resolve: {
              mySession: ['StSession', function (StSession) {
                return StSession.ensureSession();
              }]
            }
          }
        , footer: footer
        }
      })

      .state('call', {
        url: '/call/'
      , views: {
          nav: nav
        , body: {
            templateUrl: 'views/call.html'
          , controller: 'CallCtrl as Call'
          , resolve: {
              mySession: ['StSession', function (StSession) {
                return StSession.ensureSession('admin');
              }]
            }
          }
        , footer: footer
        }
      })

      .state('account', {
        url: '/account/'
      , views: {
          nav: nav
        , body: {
            templateUrl: 'views/account.html'
          , controller: "AccountCtrl as A"
          , resolve: {
              mySession: ['StSession', function (StSession) {
                return StSession.get();
              }]
            }
          }
        , footer: footer
        }
      })

      .state('push', {
        url: '/push/'
      , views: {
          nav: nav
        , body: {
            templateUrl: 'views/push.html'
          , controller: "PushCtrl as P"
          , resolve: {
              mySession: ['StSession', function (StSession) {
                return StSession.get();
              }]
            }
          }
        , footer: footer
        }
      })

      .state('store', {
        url: '/store/'
      , views: {
          nav: nav
        , body: {
            templateUrl: 'views/store.html'
          , controller: "StoreCtrl as S"
          , resolve: {
              mySession: ['StSession', function (StSession) {
                return StSession.get();
              }]
            }
          }
        , footer: footer
        }
      })

      // states that don't change the url
      /*
      .state('about', {
        parent: 'main'
      })
      .state('privacy', {
        parent: 'main'
      })
      */
      .state('about', {
        url: '/about/'
      , views: {
          nav: nav
        , body: {
            templateUrl: 'views/about.html'
          }
        , footer: footer
        }
      })
      ;

    // alternatively, register the interceptor via an anonymous factory
    $httpProvider.interceptors.push(function(/*$q*/) {
      var recase = window.Recase.create({ exceptions: {} })
        ;

      return {
        'request': function (config) {
          /*
          if (!/.html/.test(config.url)) {
            console.log('[$http] request');
            console.log(config);
            //console.log(config.method, config.url);
          }
          */
          if (config.data
              && !/^https?:\/\//.test(config.url)
              && /json/.test(config.headers['Content-Type'])
          ) {
            config.data = recase.snakeCopy(config.data);
          }
          return config;
        }
      , 'requestError': function (rejection) {
          //console.log('[$http] requestError');
          //console.log(rejection);
          return rejection;
        }
      , 'response': function (response) {
          var config = response.config
            ;

          // our own API is snake_case (to match webApi / ruby convention)
          // but we convert to camelCase for javascript convention
          if (!/^https?:\/\//.test(config.url) && /json/.test(response.headers('Content-Type'))) {
            response.data = recase.camelCopy(response.data);
          }
          return response;
        }
      , 'responseError': function (rejection) {
          //console.log('[$http] responseError');
          //console.log(rejection);
          return rejection;
        }

      };
    });
  })
  .run(function ($rootScope, $state, StSession) {
    var currentSession
      ;

    // TODO subscribe to session changes
    StSession.get().then(function (session) {
      currentSession = session;
    });

    $rootScope.stStateHack = {};
    $rootScope.$on('$stateChangeStart', function (e, to, params, from) {
      // TODO https://github.com/angular-ui/ui-router/issues/92 @christopherthielen (at the very bottom)
      $rootScope.stStateHack.to = to && to.name;
      $rootScope.stStateHack.from = from && "" !== from.name && from.name;
      $rootScope.stStateHack.params = params;

      console.log('change start', to, from);
      if (!angular.isFunction(to.data && to.data.rule)) { return; }

      var result = to.data.rule(currentSession)
        ;

      // if (!result || result.ok) { /*business as usual*/ } else { /* other thing */ }
      if (result && result.to) {
        e.preventDefault();
        // TODO go to authentication state
        // TODO include previous state in params (so it knows where to go next)
        $state.go(result.to, result.params, { notify: false });
      }
    });

    $rootScope.$on('$stateChangeError', function (e, to) {
      console.error(e);
      console.error(to);
      // TODO if login is rejected, don't finish the state change
    });
  })
  ;
<commit_msg>fixed a few places I was passing the incorrect tokens around<commit_after>'use strict';

angular.module('yololiumApp', [
  'ngCookies',
  'ngResource',
  'ngSanitize',
  'duScroll',
  'ui.router',
  'ui.bootstrap',
  'steve'
])
  .config(function ($stateProvider, $urlRouterProvider, $httpProvider/*, stConfig*/) {
    var nav
      , footer
      ;

    // This identifies your website in the createToken call
    //window.Stripe.setPublishableKey(StApi.stripe.publicKey);

    // IMPORTANT: (Issue #4)
    // These funny arrays (in resolve) are neccessary because ui.router
    // doesn't get properly mangled by ng-min
    // See https://github.com/yeoman/generator-angular#minification-safe
    nav = {
      templateUrl: '/views/nav.html'
    , controller: 'NavCtrl as N'
    , resolve: {
        mySession: ['StSession', function (StSession) {
          return StSession.get();
        }]
      }
    };

    footer = {
      templateUrl: '/views/footer.html'
    , controller: 'FooterCtrl as F'
    };

    //$locationProvider.html5Mode(true);

    // Deal with missing trailing slash
    $urlRouterProvider.rule(function($injector, $location) {
      var path = $location.path(), search = $location.search()
        ;

      if (path[path.length - 1] === '/') {
        return;
      }

      if (Object.keys(search).length === 0) {
        return path + '/';
      }

      var params = []
        ;

      angular.forEach(search, function(v, k){
        params.push(k + '=' + v);
      });

      return path + '/?' + params.join('&');
    });
    $urlRouterProvider.otherwise('/');

    $stateProvider
      .state('root', {
        url: '/'
      , views: {
          body: {
            template: '

'
          , controller: function ($state, mySession, stConfig) {
              if (!stConfig.useSplash) {
                $state.go('home');
                return;
              }

              if (!mySession || !mySession.account || 'guest' === mySession.account.role) {
                $state.go('splash');
              } else {
                $state.go('home');
              }
            }
          , resolve: {
              mySession: ['StSession', function (StSession) {
                console.log('hello world');
                return StSession.get();
              }]
            }
          }
        }
      })

      .state('home', {
        views: {
          nav: nav
        , body: {
            templateUrl: 'views/main.html'
          , controller: 'MainCtrl as M'
          , resolve: {
              mySession: ['StSession', function (StSession) {
                console.log('hello world');
                return StSession.get();
              }]
            }
          }
        , footer: footer
        }
      })

      // This is the root state for not-logged-in users
      .state('splash', {
        url: '/splash/'
      , views: {
          nav: nav
        , body: {
            templateUrl: 'views/splash.html'
          , controller: 'SplashCtrl as S'
          , resolve: {
              mySession: ['StSession', function (StSession) {
                return StSession.get();
              }]
            }
          }
        , footer: footer
        }
      })

      .state('user', {
        url: '/user/'
      , views: {
          nav: nav
        , body: {
            templateUrl: 'views/user.html'
          , controller: 'UserCtrl as U'
          , resolve: {
              mySession: ['StSession', function (StSession) {
                return StSession.get();
              }]
            }
          }
        , footer: footer
        }
      })

      .state('oauth', {
        url: '/authorize/:token/'
      , views: {
          nav: nav
        , body: {
            templateUrl: 'views/oauth.html'
          , controller: 'OauthCtrl as O'
          , resolve: {
              mySession: ['StSession', function (StSession) {
                return StSession.get().then(function (session) {
                  console.log('oauth session');
                  console.log(session);
                  return session;
                });
              }]
            }
          }
        , footer: footer
        }
      })

      .state('admin', {
        url: '/admin/'
      , views: {
          nav: nav
        , body: {
            templateUrl: 'views/admin.html'
          , controller: 'AdminCtrl as A'
          , resolve: {
              mySession: ['StSession', function (StSession) {
                return StSession.ensureSession();
              }]
            }
          }
        , footer: footer
        }
      })

      .state('call', {
        url: '/call/'
      , views: {
          nav: nav
        , body: {
            templateUrl: 'views/call.html'
          , controller: 'CallCtrl as Call'
          , resolve: {
              mySession: ['StSession', function (StSession) {
                return StSession.ensureSession('admin');
              }]
            }
          }
        , footer: footer
        }
      })

      .state('account', {
        url: '/account/'
      , views: {
          nav: nav
        , body: {
            templateUrl: 'views/account.html'
          , controller: "AccountCtrl as A"
          , resolve: {
              mySession: ['StSession', function (StSession) {
                return StSession.get();
              }]
            }
          }
        , footer: footer
        }
      })

      .state('push', {
        url: '/push/'
      , views: {
          nav: nav
        , body: {
            templateUrl: 'views/push.html'
          , controller: "PushCtrl as P"
          , resolve: {
              mySession: ['StSession', function (StSession) {
                return StSession.get();
              }]
            }
          }
        , footer: footer
        }
      })

      .state('store', {
        url: '/store/'
      , views: {
          nav: nav
        , body: {
            templateUrl: 'views/store.html'
          , controller: "StoreCtrl as S"
          , resolve: {
              mySession: ['StSession', function (StSession) {
                return StSession.get();
              }]
            }
          }
        , footer: footer
        }
      })

      // states that don't change the url
      /*
      .state('about', {
        parent: 'main'
      })
      .state('privacy', {
        parent: 'main'
      })
      */
      .state('about', {
        url: '/about/'
      , views: {
          nav: nav
        , body: {
            templateUrl: 'views/about.html'
          }
        , footer: footer
        }
      })
      ;

    // alternatively, register the interceptor via an anonymous factory
    $httpProvider.interceptors.push(function(/*$q*/) {
      var recase = window.Recase.create({ exceptions: {} })
        ;

      return {
        'request': function (config) {
          /*
          if (!/.html/.test(config.url)) {
            console.log('[$http] request');
            console.log(config);
            //console.log(config.method, config.url);
          }
          */
          if (config.data
              && !/^https?:\/\//.test(config.url)
              && /json/.test(config.headers['Content-Type'])
          ) {
            config.data = recase.snakeCopy(config.data);
          }
          return config;
        }
      , 'requestError': function (rejection) {
          //console.log('[$http] requestError');
          //console.log(rejection);
          return rejection;
        }
      , 'response': function (response) {
          var config = response.config
            ;

          // our own API is snake_case (to match webApi / ruby convention)
          // but we convert to camelCase for javascript convention
          if (!/^https?:\/\//.test(config.url) && /json/.test(response.headers('Content-Type'))) {
            response.data = recase.camelCopy(response.data);
          }
          return response;
        }
      , 'responseError': function (rejection) {
          //console.log('[$http] responseError');
          //console.log(rejection);
          return rejection;
        }

      };
    });
  })
  .run(function ($rootScope, $state, StSession) {
    var currentSession
      ;

    // TODO subscribe to session changes
    StSession.get().then(function (session) {
      currentSession = session;
    });

    $rootScope.stStateHack = {};
    $rootScope.$on('$stateChangeStart', function (e, to, params, from) {
      // TODO https://github.com/angular-ui/ui-router/issues/92 @christopherthielen (at the very bottom)
      $rootScope.stStateHack.to = to && to.name;
      $rootScope.stStateHack.from = from && "" !== from.name && from.name;
      $rootScope.stStateHack.params = params;

      console.log('change start', to, from);
      if (!angular.isFunction(to.data && to.data.rule)) { return; }

      var result = to.data.rule(currentSession)
        ;

      // if (!result || result.ok) { /*business as usual*/ } else { /* other thing */ }
      if (result && result.to) {
        e.preventDefault();
        // TODO go to authentication state
        // TODO include previous state in params (so it knows where to go next)
        $state.go(result.to, result.params, { notify: false });
      }
    });

    $rootScope.$on('$stateChangeError', function (e, to) {
      console.error(e);
      console.error(to);
      // TODO if login is rejected, don't finish the state change
    });
  })
  ;
<|endoftext|>


<commit_before>"use strict";
var Dot = function (radius, color, position, velocity, force) {
	this.radius = radius;
	this.color = color;
	this.force = force;
	this.position = position;
	this.velocity = velocity;

	this.draw = function (context) {
		context.beginPath();
		context.arc(this.position.x, this.position.y, this.radius, 0, 2 * Math.PI, false);
		context.fillStyle = this.color;
		context.fill();
	};

	this.setVelocity = function (newv) {
		this.velocity = Vector.mult(newv, this.force);
	};

	this.update = function () {
		this.position.add(this.velocity);

	};

};<commit_msg>removed<commit_after><|endoftext|>


<commit_before>
var exec = require('child-process-promise').exec;

function tagNotExists(tag) {
    return exec(`git rev-parse -q -v ${tag}^{tree}`)
        .then(res => { throw new Error('Tag already exists')})
        .catch(err => {
           if(err.code === 128) {
               return;
           }
           throw err;
        });
}

function filesClean(files) {
    return exec(`git st --porcelain ${files.join(' ')}`)
        .then(result => {
            if(result.stdout.length > 0) {
                throw new Error('Files not clean');
            }
        });
}

function onBranch(branch) {
    return exec('git rev-parse --abbrev-ref HEAD')
        .then(result => {
            if(result.stdout.trim() !== branch) {
                throw new Error(`Must be on ${branch} branch`)
            }
        })
}

function upToDate(origin, branch) {
    return exec(`git fetch ${origin} ${branch}`)
        .then(() => exec(`git log ..${origin}/${branch}`))
        .then(result => {
            if(result.stdout.trim().length > 0) {
                throw new Error(`Not up to date with ${origin}/${branch}`);
            }
        })
}

function commitAndTag(files, tag, message) {
    return exec(`git add ${files.join(' ')}`)
        .then(() => exec(`git commit -m "${message}"`))
        .then(() => exec(`git tag ${tag}`));
}

class GitRelease {
    constructor(tag, origin, branch, message) {
        this.tag = tag;
        this.origin = origin;
        this.branch = branch;
        this.message = message;
    }
    files() {
        return [];
    }
    preflight(files) {
        return Promise.all([
            tagNotExists(this.tag),
            onBranch(this.branch),
            upToDate(this.origin, this.branch),
            filesClean(files)
        ])
        return Promise.resolve();
    }
    modify() {
        return Promise.resolve();
    }
    commit(files) {
        // Add, commit and tag.
        return commitAndTag(files, this.tag, this.message);
    }
}

module.exports = GitRelease;<commit_msg>Issue #161: Remove git st command (#162)<commit_after>
var exec = require('child-process-promise').exec;

function tagNotExists(tag) {
    return exec(`git rev-parse -q -v ${tag}^{tree}`)
        .then(res => { throw new Error('Tag already exists')})
        .catch(err => {
           if(err.code === 128) {
               return;
           }
           throw err;
        });
}

function filesClean(files) {
    return exec(`git status --porcelain ${files.join(' ')}`)
        .then(result => {
            if(result.stdout.length > 0) {
                throw new Error('Files not clean');
            }
        });
}

function onBranch(branch) {
    return exec('git rev-parse --abbrev-ref HEAD')
        .then(result => {
            if(result.stdout.trim() !== branch) {
                throw new Error(`Must be on ${branch} branch`)
            }
        })
}

function upToDate(origin, branch) {
    return exec(`git fetch ${origin} ${branch}`)
        .then(() => exec(`git log ..${origin}/${branch}`))
        .then(result => {
            if(result.stdout.trim().length > 0) {
                throw new Error(`Not up to date with ${origin}/${branch}`);
            }
        })
}

function commitAndTag(files, tag, message) {
    return exec(`git add ${files.join(' ')}`)
        .then(() => exec(`git commit -m "${message}"`))
        .then(() => exec(`git tag ${tag}`));
}

class GitRelease {
    constructor(tag, origin, branch, message) {
        this.tag = tag;
        this.origin = origin;
        this.branch = branch;
        this.message = message;
    }
    files() {
        return [];
    }
    preflight(files) {
        return Promise.all([
            tagNotExists(this.tag),
            onBranch(this.branch),
            upToDate(this.origin, this.branch),
            filesClean(files)
        ])
        return Promise.resolve();
    }
    modify() {
        return Promise.resolve();
    }
    commit(files) {
        // Add, commit and tag.
        return commitAndTag(files, this.tag, this.message);
    }
}

module.exports = GitRelease;
<|endoftext|>


<commit_before>#!/usr/bin/env node

/* eslint-disable global-require */

const { spawn } = require('child_process');
const { promisify } = require('util');
const { readdir: readdirRaw, readFile: readFileRaw, statSync, cop } = require('fs');
const { join } = require('path');

const readdir = promisify(readdirRaw);
const readFile = promisify(readFileRaw);

const p = l => join(__dirname, '..', ...l);
const logger = console;

const exec = async (command, args = [], options = {}) =>
  new Promise((resolve, reject) => {
    const child = spawn(command, args, { ...options, stdio: 'inherit' });

    child.on('close', code => {
      if (code) {
        reject();
      } else {
        resolve();
      }
    });
  });

const hasBuildScript = async l => {
  const text = await readFile(l, 'utf8');
  const json = JSON.parse(text);

  return !!json.scripts['build-storybook'];
};

const handleExamples = async files => {
  const deployables = files.filter(f => {
    const packageJsonLocation = p(['examples', f, 'package.json']);
    const stats = statSync(packageJsonLocation);

    return stats.isFile() && hasBuildScript(packageJsonLocation);
  });

  await deployables.reduce(async (acc, d) => {
    await acc;

    logger.log('');
    logger.log(
      `-----------------${Array(d.length)
        .fill('-')
        .join('')}`
    );
    logger.log(`▶  building: ${d}`);
    logger.log(
      `-----------------${Array(d.length)
        .fill('-')
        .join('')}`
    );
    const out = p(['built-storybooks', d]);
    const cwd = p(['examples', d]);

    await exec(`yarn`, [`build-storybook`, `--output-dir=${out}`, '--quiet'], { cwd });

    logger.log('-------');
    logger.log('✅ done');
    logger.log('-------');
  }, Promise.resolve());

  const copy = require('recursive-copy');
  const target = 'official-storybook';
  const copyables = deployables.filter(f => f !== target);

  await copyables.reduce(async (acc, d) => {
    await acc;

    logger.log(`💿 copy ${d} to built-storybooks`);
    const to = p(['built-storybooks', target, 'built-storybooks', d]);
    const from = p(['built-storybooks', d]);

    await copy(from, to, {
      overwrite: true,
    });
  }, Promise.resolve());
};

const run = async () => {
  await exec('yarn', ['bootstrap', '--core']);

  const examples = await readdir(p(['examples']));

  await handleExamples(examples);
};

run();
<commit_msg>ADD a manual index page<commit_after>#!/usr/bin/env node

/* eslint-disable global-require */

const { spawn } = require('child_process');
const { promisify } = require('util');
const {
  readdir: readdirRaw,
  readFile: readFileRaw,
  writeFile: writeFileRaw,
  statSync,
  cop,
} = require('fs');
const { join } = require('path');

const readdir = promisify(readdirRaw);
const readFile = promisify(readFileRaw);
const writeFile = promisify(writeFileRaw);

const p = l => join(__dirname, '..', ...l);
const logger = console;

const exec = async (command, args = [], options = {}) =>
  new Promise((resolve, reject) => {
    const child = spawn(command, args, { ...options, stdio: 'inherit' });

    child.on('close', code => {
      if (code) {
        reject();
      } else {
        resolve();
      }
    });
  });

const hasBuildScript = async l => {
  const text = await readFile(l, 'utf8');
  const json = JSON.parse(text);

  return !!json.scripts['build-storybook'];
};

const handleExamples = async files => {
  const deployables = files.filter(f => {
    const packageJsonLocation = p(['examples', f, 'package.json']);
    const stats = statSync(packageJsonLocation);

    return stats.isFile() && hasBuildScript(packageJsonLocation);
  });

  await deployables.reduce(async (acc, d) => {
    await acc;

    logger.log('');
    logger.log(
      `-----------------${Array(d.length)
        .fill('-')
        .join('')}`
    );
    logger.log(`▶  building: ${d}`);
    logger.log(
      `-----------------${Array(d.length)
        .fill('-')
        .join('')}`
    );
    const out = p(['built-storybooks', d]);
    const cwd = p(['examples', d]);

    await exec(`yarn`, [`build-storybook`, `--output-dir=${out}`, '--quiet'], { cwd });

    logger.log('-------');
    logger.log('✅ done');
    logger.log('-------');
  }, Promise.resolve());

  const copy = require('recursive-copy');
  const target = 'official-storybook';
  const copyables = deployables.filter(f => f !== target);

  await copyables.reduce(async (acc, d) => {
    await acc;

    logger.log(`💿 copy ${d} to built-storybooks`);
    const to = p(['built-storybooks', target, 'built-storybooks', d]);
    const from = p(['built-storybooks', d]);

    await copy(from, to, {
      overwrite: true,
    });
  }, Promise.resolve());

  logger.log('-------');
  logger.log('✅ done');
  logger.log('-------');
  logger.log('');

  logger.log(`📑 creating index`);

  const indexLocation = p(['built-storybooks', 'index.html']);
  const indexContent = `
    <style>
      body {
        background: black;
        color: white;
      }
      #frame {
        position: absolute;
        left: 0;
        right: 0;
        width: 100vw;
        height: calc(100vh - 30px);
        bottom: 0;
        top: 30px;
        border: 0 none;
        margin: 0;
        padding: 0;
      }
      #select {
        position: absolute;
        top: 0;
        right: 10px;
        left: 10px;
        height: 30px;
        width: calc(100vw - 20px);
        background: black;
        color: white;
        border: 0 none;
        border-radius: 0;
        padding: 10px;
        box-sizing: border-box;
      }
    </style>

    <script>
      function handle() {
        var value = document.getElementById("select").value;
        var frame = document.getElementById("frame");

        sessionStorage.clear();
        localStorage.clear();

        frame.setAttribute('src', value);
      }
    </script>

    <select id="select" onchange="handle()">
      ${deployables.map(i => `<option value="/${i}/">${i}</option>`).join('\n')}
    </select>

    <iframe id="frame" src="/${deployables[0]}/" />
  `;

  await writeFile(indexLocation, indexContent);

  logger.log('-------');
  logger.log('✅ done');
  logger.log('-------');
};

const run = async () => {
  await exec('yarn', ['bootstrap', '--core']);

  const examples = await readdir(p(['examples']));

  await handleExamples(examples);
};

run();
<|endoftext|>