diff --git a/tools/game/bong/bong.html b/tools/game/bong/bong.html
new file mode 100644
index 0000000..bb00663
--- /dev/null
+++ b/tools/game/bong/bong.html
@@ -0,0 +1,50 @@
+
+
B-Pong
+
+
+
+
+
+
+
+ 0
+ 0
+
+
+ s_data...
+ debug
+
+
diff --git a/tools/game/bong/bong.js b/tools/game/bong/bong.js
new file mode 100644
index 0000000..d172cc0
--- /dev/null
+++ b/tools/game/bong/bong.js
@@ -0,0 +1,262 @@
+// Initialisation
+var socket = "ws://83.133.179.198:8888/data";
+var field= { w: 320, h: 240 };
+var paddle = { w: 2, h: 30 };
+var ball = { w: 5, h: 5, s: 5 };
+
+// Pong game class
+function pong() {
+ this.ball = {};
+ this.left = {};
+ this.right = {};
+ this.score = {};
+ this.score.left = {};
+ this.score.right = {};
+ this.field = {};
+ this.game = { run: 0 };
+
+ this.ball.size=ball;
+ this.left.size=paddle;
+ this.right.size=paddle;
+ this.field.size=field;
+
+ this.left.x=-field.w+3*this.left.size.w;
+ this.right.x=field.w-3*this.right.size.w;
+
+ this.ball.avatar=$('div#ball');
+ this.left.avatar=$('div#paddle_left');
+ this.right.avatar=$('div#paddle_right');
+ this.score.left.avatar=$('div#score_left');
+ this.score.right.avatar=$('div#score_right');
+ this.field.avatar=$('#playfield');
+
+ function setupavatar(obj){
+ obj.avatar.width(2*obj.size.w)
+ .height(2*obj.size.h);
+ };
+
+ setupavatar(this.ball);
+ setupavatar(this.left);
+ setupavatar(this.right);
+ setupavatar(this.field);
+
+ this.field.avatar.focus();
+
+ this.score.left.pts=0;
+ this.score.right.pts=0;
+ this.setup( (Math.random()>0.5)?1:-1);
+
+ this.field.avatar.keydown(this,function(ev){
+ if(ev.which == 67) ev.data.socketstart(socket);
+ if(ev.which == 81) ev.data.game.run=0;
+ if(ev.which == 82) ev.data.game.run=1;
+ if(ev.which > 48 && ev.which <=57) ev.data.setleft((ev.which-53)/4);
+ });
+
+ $('#debug').css({left:0,top:2*this.field.size.h+10});
+ $('#socket').css({left:0,top:2*this.field.size.h+30});
+}
+
+pong.prototype.setleft = function(where){
+ this.left.y=where*(this.field.size.h-this.left.size.h);
+};
+
+pong.prototype.setright = function(where){
+ this.right.y=where*(this.field.size.h-this.right.size.h);
+};
+
+pong.prototype.setup = function(rtl){
+ this.ball.x=0;
+ this.ball.y=0;
+ this.ball.ang=Math.random()*20/180*Math.PI;
+ if(rtl<0) this.ball.ang=Math.PI-this.ball.ang;
+ this.ball.spd=this.ball.size.s;
+
+ this.left.y=0;
+ this.right.y=0;
+
+ this.game.run=0;
+};
+
+pong.prototype.update= function(t){
+ var upv=0;
+
+ this.ball.vx=Math.cos(this.ball.ang)*this.ball.spd;
+ this.ball.vy=Math.sin(this.ball.ang)*this.ball.spd;
+ this.ball.x+=t*this.ball.vx;
+ this.ball.y+=t*this.ball.vy;
+
+ this.ball.x+=t*this.ball.vx;
+ this.ball.y+=t*this.ball.vy;
+
+ // Clipping
+ if(this.ball.y-this.ball.size.h<-field.h){
+ this.ball.ang=-this.ball.ang;
+ this.ball.y=-field.h+this.ball.size.h;
+ };
+
+ if(this.ball.y+this.ball.size.h>field.h){
+ this.ball.ang=-this.ball.ang;
+ this.ball.y=field.h-this.ball.size.h;
+ };
+
+ function newang(off,bath){
+ var trig=(bath-1)/4;
+ var ad=0;
+ if(Math.abs(off)this.right.x-this.right.size.w &&
+ this.ball.y+this.ball.size.h>this.right.y-this.right.size.h &&
+ this.ball.y-this.ball.size.hthis.left.x-this.left.size.w &&
+ this.ball.y+this.ball.size.h>this.left.y-this.left.size.h &&
+ this.ball.y-this.ball.size.hfield.w){
+ this.score.left.pts++;
+ this.setup(-1);
+ this.ball.ang=Math.PI-this.ball.ang;
+ this.game.run=1;
+ };
+
+ if(this.ball.x-this.ball.size.w<-field.w){
+ this.score.right.pts++;
+ this.setup(1);
+ this.game.run=1;
+ };
+
+ if(this.ball.ang<0)
+ this.ball.ang+=2*Math.PI;
+ if(this.ball.ang>2*Math.PI)
+ this.ball.ang-=2*Math.PI;
+
+ $('#debug').html("ang="+Math.abs(this.ball.ang/Math.PI*180)+" ,x="+Math.ceil(this.ball.x)+" ,y="+Math.ceil(this.ball.y));//+" ,off="+(this.ball.off)+" ,ad="+Math.ceil(this.ball.ad));
+};
+
+pong.prototype.display=function(){
+ function move(obj,av){
+ var x = obj.x - obj.size.w + field.w;
+ var y = obj.y - obj.size.h + field.h;
+ obj.avatar.css({left:x,top:y});
+ };
+
+ move(this.ball);
+ move(this.left);
+ move(this.right);
+ this.score.left.avatar.html(this.score.left.pts);
+ this.score.right.avatar.html(this.score.right.pts);
+};
+
+var time = function() { return +(new Date) / 100 };
+var last = time();
+pong.prototype.run = function(){
+ var now = time();
+
+ if(game.game.run==1)
+ game.update(now - last);
+
+ game.display();
+ last=now;
+};
+
+pong.prototype.socketstart = function(uri){
+ function debug(str){
+ $("#socket").append("
" + str);
+ };
+
+ ws = new WebSocket(uri);
+
+ debug("ws start");
+ ws.onopen = function() {
+ debug("ws open");
+ $('#socket').css({"color": "green"});
+ ws.send("hello");
+ this.game.run=1;
+ };
+
+ ws.onmessage = function (evt) {
+ var data = evt.data;
+ $('#socket').html(data);
+ if(data.slice(0,1)=="{"){
+ var result=JSON.parse(data);
+ if (result.right){
+ this.setright(result.right);
+ } else if (result.left){
+ this.setleft(result.left);
+ }else {
+ // unknown json input
+ };
+ }else{
+ // unknown non-json input
+ };
+ };
+
+ ws.onclose = function() {
+ debug("socket closed");
+ $('#socket').css({"color": "red"});
+ // reconnect
+ };
+};
+
+// Start utility stuff
+(function() {
+ var onEachFrame;
+ if (window.webkitRequestAnimationFrame) {
+ onEachFrame = function(cb) {
+ var _cb = function() { cb(); webkitRequestAnimationFrame(_cb); }
+ _cb();
+ };
+ } else if (window.mozRequestAnimationFrame) {
+ onEachFrame = function(cb) {
+ var _cb = function() { cb(); mozRequestAnimationFrame(_cb); }
+ _cb();
+ };
+ } else {
+ onEachFrame = function(cb) {
+ setInterval(cb, 1000 / 60);
+ }
+ }
+ window.onEachFrame = onEachFrame;
+})();
+
+var game;
+$(document).ready(function(){
+ game=new pong();
+ if (window.MozWebSocket) {
+ window.WebSocket = window.MozWebSocket;
+ }
+ if ("WebSocket" in window) {
+ game.socketstart(socket);
+ } else {
+ alert("You have no web sockets");
+ };
+ window.onEachFrame(game.run);
+});