No word about onion turned 5 today! More posts to come later, stay tuned.
NASA
Game of Thrones Daily
AnasAbdin
Xuebing Du
2025 on Tumblr: Trends That Defined the Year
KIROKAZE

Andulka
tumblr dot com

No title available
Show & Tell
d e v o n
Keni
Peter Solarz
hello vonnie
sheepfilms
Cosimo Galluzzi
Monterey Bay Aquarium
cherry valley forever
Mike Driver
we're not kids anymore.

seen from Türkiye
seen from India
seen from Australia

seen from Italy
seen from New Zealand
seen from Ireland

seen from Portugal

seen from United Kingdom
seen from Norway

seen from Austria
seen from Austria

seen from Spain
seen from Ireland
seen from Germany
seen from United Kingdom
seen from Türkiye
seen from Sweden

seen from United States

seen from Malaysia

seen from Malaysia
@shamansir
No word about onion turned 5 today! More posts to come later, stay tuned.
Half a year ago I announced the first release of Animatron. The release was private, just for a few friends and colleagues, and it was supposed to remain private for only 3 - 4 months while we ironed out most of the bugs and polished the UI.
Well, as often happens with complex software...
Mastering Functional JavaScript Lecture Slides
In JavaScript, like, say, in Python, functions are also objects. It gives developer the opportunity to write pure (or not so, since there are no native monads support ;) ) functional code. Most people among us do easily forget about this fact, but it is still true and, what's truly great, it was true from the start. These slides are supposed to re-introduce to you the mighty power of functions in JS. No _map_ / _filter_, since they're trivial, but it's more about _deferring_, _queueing_ and _composing_ functions with few-lined chunks of code, plus some general tricks with them, and also what profit you may take out of all of this stuff. No techniques that will only come in new versions or, instead, just were introduced: totally plain old [good] JavaScript. However, a bit of basics at the start are also there, of course. OK, Here we go: [](https://speakerdeck.com/shamansir/mastering-functional-javascript) ### Links Links to the examples: * Deferred functions: * [codepen.io/shamansir/pen/HskmE](http://codepen.io/shamansir/pen/HskmE) _(parser example)_ * [codepen.io/shamansir/pen/kBzJe](http://codepen.io/shamansir/pen/kBzJe) * Partial applications: * [codepen.io/shamansir/pen/xCrgz](http://codepen.io/shamansir/pen/xCrgz) * Queues of functions: * [codepen.io/shamansir/pen/AaHqy](http://codepen.io/shamansir/pen/AaHqy) * Composed functions: * [codepen.io/shamansir/pen/Funwt](http://codepen.io/shamansir/pen/Funwt) Lyfe.js: [bitbucket.org/balpha/lyfe](http://bitbucket.org/balpha/lyfe) Article on lyfe.js: [Introducing Lyfe: yield in JavaScript](http://balpha.de/2011/06/introducing-lyfe-yield-in-javascript)
GWT + mvp4g Lecture Slides
April 29, I've presented a lecture on Web-development with GWT and mvp4g Framework, at Application Developer Days 2011 Conference. Here are the slides.
Slides
Also on Scribd
Schedule
Briefly about GWT. A brief history and examples of GWT usage.
GWT Conceptions
JSNI
Code Splitting
MVP, RMVP, EventBus
Deferred Binding
Dependency Injection
Remote Services
mvp4g
What Helps? Differences and Dignity
Annotation System
RMVP, EventBus Realization
History, #!
Multimodularity
Remarks
GWT UI Components
UiBinder, Standard Components
Developing Custom Components
Our Development of Layouting-system with GWT+mvp4g
Working with Non-Java Server-Side API
i18n in GWT
Conclusion. Examples links.
Links from the slides
Slides in PDF
Briefly оn GWT
Quake 2 in browser
GWT Conception
Article on difference between MVC and MVP
Ray Ryan about GWT-application architecture
Video about EventBus
Presentation on Deferred Binding
Guice wiki-pages
Tutorial on creating Remote Services
Talks on GWT drawbacks (ru)
GWT-code optimization summary (ru)
mvp4g
mvp4g framework web-page
mvp4g framework showcase
Comparison between native GWT-code and a code written with mvp4g
Short tutorial on creating project with mvp4g
UI components
GWT component library
Layouting
Layouting demonstration (in progress) with GWT+mvp4g
Non-Java API
The point
Description, including source code (ru)
i18n
Conclusion
Experika site
Vitaly Gashock twitter
Mikhail Kashkin site
EmDev company site
My Google-profile
LimeJS: Writing a cross-platform game in HTML5 with touch support
Introduction
LimeJS is 2D Open Source HTML5-engine for game development with touch-events support and it works (following to the description on the site) with most of mobile platfroms. I have found it not by myself, but last week I've got a letter with a proposition to tell community about the engine [in russian, this is an english version] and I've decided - sp if this is the case, why waste time on trifles, why not to try this engine in action. Among with that, I have agreed in advance with engine authors that I will tell both advantages and disadvantages, so I hope to clear the advertisment halo from the article with that (though, what means advertisment to open-source)..?
Open Source, cross-platform and HTML5 - are the things I like most - they are freedom and innovations :). And more, the engine is written with Closure and it supports chaining - these facts bring an additional bright colors to the engine features and to a programming process with its usage. For sure, a comfort in games development by itself is also required, so we'll test LimeJS on it together in this article. The engine is presented as working cross-platform. Two example games located on the site home page work good on iPad, a little bit slowly, but quiet playable. And what about my Hero/Android2.1 (HTML5 is not so cool, may be), they are buggy a lot for sure - so literally, it is not very possible to play them. However, almost all of the objects look and act correctly even on smartphone - so we'll hope that it will work great even on a weak smartphones like mine with further optimizations.
By the way, the engine is positioned as a substitute for Flash-technologies in games. It is a painful theme for a lot of us, in connection with the current anti-flash terror on the one hand and a great games existing and recently created on the other. (And I personally think that the comfort of the very animation creating process mechanics in Flash is still not reconstructed even for HTML5/SVG neither for alternatives). So, may be this engine is having a change to fight out a love from Flash developers and make them love with HTML5. They are and you are who decide. A major difference in LimeJS from ProcessingJS (for example) is a targeting - not to state machine and not to each frame manual control but to the timeline - the event-driven mechanics in the game script.
By the way, here is a code example: javascript and html - to let you make a some preliminary conclusion - I treated the engine a little skeptically at start, but now I think that I certainly was wrong.
How The Result Will Look Like
During the article we will develop the very simplified version of ping-pong virtual game with the help of LimeJS. Here is how the result will look like:
There will be videos demonstrating the game we will write running on iPad, iPhone and Android in the end of the article.
Preparation
The engine have a sort of CLI, Command Line Interface. It is written in Python and it gets a required packages using git when installing, so you need to install Python, git and git-svn to work with engine, if you haven't them already installed. (Seems, developers using Windows will need to do some tricks). Then we get the sources from github or by downloading zip and unpack. This how it can be done on Ubuntu:
$ sudo apt-get install python git-core git-svn $ wget https://github.com/digitalfruit/limejs/zipball/master -no-check-certificate $ unzip ./master ./digitalfruit-limejs $ cd ./digitalfruit-limejs
To install all the other packages required for development (including Closure), we run:
$ ./bin/lime.py init
Let's Start
$ ./bin/lime.py create pingpong
Yes, let it be the ping-pong, a little bit similar to that shown by Dominic in making a game with Impact HTML5 Engine tutorial. Later I discovered that in demo-sources there is something like that, but let our variant will be much simpler.
There will pingpong.html and pingpong.js files created in pinpong directory. You may open the .html file in the browser, it is pretty interesting by itself - you'll see a nice circle in the center and you may drag it with mouse or finger. There is also a lot of interesting things in .js-file - you can mention how scene is created and how events handling is managed. The code remains quite understandable and readable. I will not analyze it in details, it is just a stub-example, and you can inspect its "internals" by following the links in the beginning of the article.
The Main Classes and Concept
A brief summary of Programming guide:
Director - is, literally, a director of the game, it holds the scenes, manages transitions between them and keeps the general game settings;
Scene - is a separate screen of the game, you can add child objects and layers to it;
Layer - is any rectangular part of the screen, it is useful to split screen parts in layers and layers can also be a containers for children objects. Though, the layers can overlap each other, like in Photoshop;
ScheduleManager - is a planning tool, it helps to call certain functions either in every frame either after some amount of time will pass;
Node - any entity in the game, has its own position, size, scale factor, rotation angle and local coordinate system, so it can be translated (moved), rotated, scaled and animated;
Sprite - is the ancestor of Node, it has all its properties/possibilities and can represent an image and/or geometric shape (startin from circle to any polygon); sprites can be masked from each other, filled with gradients and their collisions can be tested with hitTest method;
Engine is oriented on timeline, not on the things that required to be shown in current frame;
All the different events related to controllers are handled through Closure mechanisms;
Animations - translation, rotation, scaling, and fading - can be applied to a single object or to several at once and also can be joined in chains (sequential, simultaneous, looped);
DOM- and Canvas-rendering is supported. WebGL-rendering is planned;
If the animation is applied to DOM-element, it is translated to CSS3-property;
The out script can be hardly optimized;
There is an Audio class to play sounds;
Building a scene
Let we leave just a several lines from the pingpong.start function given us by developers:
#!javascript // entrypoint pingpong.start = function(){ var director = new lime.Director(document.body), scene = new lime.Scene(); director.makeMobileWebAppCapable(); // set current scene active director.replaceScene(scene); }
Don not forget to remove the unneсessary goog.require lines. I will not remind you further about it, you can always take a look at a resulting file header in the end of the article. Let's add three layers to the scene - floor_ (means background), walls_ and a board that will have all the action happening on it:
#!javascript var director = new lime.Director(document.body), scene = new lime.Scene(), floor_ = new lime.Layer().setPosition(0,0), walls_ = new lime.Layer().setPosition(0,0), board_ = new lime.Layer().setPosition(0,0); scene.appendChild(floor_); scene.appendChild(walls_); scene.appendChild(board_); . . .
Player blank
In a separate player.js file we describe a player class - it will be the polygon in a shape of skateboard (to check how collisions work):
#!javascript goog.provide('pingpong.Player'); goog.require('lime.Polygon'); pingpong.Player = function() { goog.base(this); // ... polygon construction } goog.inherits(pingpong.Player, lime.Polygon);
In the place of the comment we will describe a polygon vertices and will fill it with half-transparent blue. Here is how the player will look like (in the tutorial, there are fractional numbers from -1 to 1 are used to describe vertices coordinates (relatively to the polygon center), but in the current version I failed to make them work):
#!javascript // -1,-2.5, 0,-3.5, 1,-2.5, 1,2.5, 0,3.5, -1,2.5, 0,1.5, 0,-1.5 this.addPoints(-50,-125, 0,-175, 50,-125, 50,125, 0,175, -50,125, 0,75, 0,-75) .setFill(0,0,210,.7) .setScale(.4);
The red dot on a picture is an anchorPoint, it is calculated automatically for polygon. This point is a reference point of local coordinates system of the sprite - all the relative sizes and distances related to polygon are calculated starting from this point.
For the moment, the code is equivalent to the call:
#!javascript var playerOne = new lime.Polygon().addPoints(...).setFill(...);
But later we will add some behavior to the player and it will be obvious that it was a wise decision to create a special class. Let's check if player is displayed correctly on the scene - let's return back to pingpong.js file... though, why waste a time, let's add both players to the board and mirror a first one to make them stand face-to-face:
#!javascript . . . goog.require('pingpong.Player'); . . . board_ = new lime.Layer().setPosition(0,0), playerOne = new pingpong.Player().setPosition(50,150).setRotation(180), playerTwo = new pingpong.Player().setPosition(400,150); board_.appendChild(playerOne); board_.appendChild(playerTwo); . . .
Before we run it in a browser we need to make one manipulation more - to update dependencies for Closure (it allows you to include just base.js with Closure utilities and pingpong.js in your .html, and all other files are loaded automatically using goog.require). However there is a little bug in the current version of engine - when you create a project, its name is not added to ./bin/projects file. So you need to define pingpong line in your ./bin/projects file before, and after that you can update the dependencies:
$ vim ./bin/projects # add `pingpong` line $ ./bin/lime.py update
So, this is what you can see on the screen:
Ball blank
Now let's make a ball.js file with this content:
#!javascript goog.provide('pingpong.Ball'); goog.require('lime.Circle'); pingpong.Ball = function() { goog.base(this); this.setFill(255,0,0,.7) .setSize(20,20); } goog.inherits(pingpong.Ball, lime.Circle);
Then update dependencies:
$ ./bin/lime.py update
And add the ball to the board in pingpong.js:
#!javascript . . . goog.require('pingpong.Ball'); . . . playerOne = new pingpong.Player().setPosition(50,150).setRotation(180), playerTwo = new pingpong.Player().setPosition(400,150), ball = new pingpong.Ball().setPosition(275,150); board_.appendChild(playerOne); board_.appendChild(playerTwo); board_.appendChild(ball);
Background
Now let's create a field with a players, every player will have a half of the field with its own color. We will say Director what are the game screen size parameters:
#!javascript var director = new lime.Director(document.body,600,480),
This dimensions are not related to any pixels, by no means - the game canvas is automatically resized and maximized to the screen when required, but these dimensions allow us to use relative positions of elements on the canvas. Correct the ball position and players positions relatively to new screen size:
#!javascript playerOne = new pingpong.Player().setPosition(40,240).setRotation(180), playerTwo = new pingpong.Player().setPosition(600,240), ball = new pingpong.Ball().setPosition(320,240);
Now, at last, the background. Yep, it will be just two sprites, splitting the screen in half - no indirect logic.
#!javascript floor_.appendChild(new lime.Sprite().setPosition(160,240) .setSize(320,480) .setFill(100,100,100)); floor_.appendChild(new lime.Sprite().setPosition(480,240) .setSize(320,480) .setFill(200,200,200)); board_.appendChild(...); . . .
Wall blank
Wall will not have a lot of logic, but as a tradition we will also place it in a separate class. Walls will have 20x20 size. Create a file wall.js with this content:
#!javascript goog.provide('pingpong.Wall'); goog.require('lime.Sprite'); pingpong.Wall = function() { goog.base(this); this.setFill(255,255,0) .setSize(20,20); } goog.inherits(pingpong.Wall, lime.Sprite);
Update dependencies:
$ ./bin/lime.py update
And place the walls along the canvas edges in pingpong.js:
#!javascript . . . goog.require('pingpong.Wall'); . . . floor_.appendChild(...); // horizontal walls for (x = 10; x <= 630; x += 20) { walls_.appendChild(new pingpong.Wall().setPosition(x, 10)); walls_.appendChild(new pingpong.Wall().setPosition(x, 470)); } // vertical walls for (y = 30; y <= 450; y += 20) { walls_.appendChild(new pingpong.Wall().setPosition(10, y)); walls_.appendChild(new pingpong.Wall().setPosition(630, y)); } board_.appendChild(...);
That's all, the game board is complete - we can start to program logic!
Players logic
Player sprite must move vertically towards the touched or clicked point, omitting the walls. Moving is done easy:
#!javascript . . . director.makeMobileWebAppCapable(); goog.events.listen(floor_,['mousedown','touchstart'],function(e){ var player_ = (e.position.x <= 320) ? playerOne : playerTwo; player_.runAction( new lime.animation.MoveTo(player_.getPosition().x, e.position.y).setDuration(1)); }); director.replaceScene(scene);
But with this behaviour the players are moving through walls. Keep each wall instance to test on collisions with player is not a best way for us, so we will let a programmer to determine what rectangular bounds are restricted for player. Thus we will need two methods in the end of player.js:
#!javascript pingpong.Player.prototype.setMovementBounds = function(top,right,bottom,left) { this._moveBounds = new goog.math.Box(top,right,bottom,left); return this; } pingpong.Player.prototype.alignBounds = function(x, y) { if (this._moveBounds === undefined) return new goog.math.Coordinate(x, y); var size_ = new goog.math.Size(this.getSize().width * this.getScale().x, this.getSize().height * this.getScale().y); var newX = x, newY = y; if (x < (this._moveBounds.left + (size_.width / 2))) newX = this._moveBounds.left + (size_.width / 2); if (x > (this._moveBounds.right - (size_.width / 2))) newX = this._moveBounds.right - (size_.width / 2); if (y < (this._moveBounds.top + (size_.height / 2))) newY = this._moveBounds.top + (size_.height / 2); if (y > (this._moveBounds.bottom - (size_.height / 2))) newY = this._moveBounds.bottom - (size_.height / 2); return new goog.math.Coordinate(newX, newY); }
The first one allows to set rectangular boundaries for player's movement and the second one - returns the position aligned to the edges of this bounds. Note that scale vector is taken into account in calculation process.
Now let's update the players' definitions in pingpong.js:
#!javascript playerOne = new pingpong.Player().setPosition(40,240) .setRotation(180) .setMovementBounds(20,620,460,20), playerTwo = new pingpong.Player().setPosition(600,240) .setMovementBounds(20,620,460,20),
And let's correct the event where the movement happens:
#!javascript goog.events.listen(floor_,['mousedown','touchstart'],function(e){ var player_ = (e.position.x <= 320) ? playerOne : playerTwo; player_.runAction( new lime.animation.MoveTo( player_.alignBounds(player_.getPosition().x, e.screenPosition.y)) .setDuration(1)); });
Ball logic
We will also need some additional functions for a ball. The first one, as for player, allows to set ball movement bounds, the second one allows to set ball velocity and the third one allows to set "reset position" - a position where the ball will returned when if one of the players misses it (ball.js):
#!javascript pingpong.Ball = function() { goog.base(this); this.setFill(255,0,0,.7) .setSize(20,20); this._xCoef = 1; this._yCoef = 1; this._resetPos = new goog.math.Coordinate(0, 0); this._velocity = 2; } goog.inherits(pingpong.Ball,lime.Circle); pingpong.Ball.prototype.setMovementBounds = function(top,right,bottom,left) { this._moveBounds = new goog.math.Box(top,right,bottom,left); return this; } pingpong.Ball.prototype.setVelocity = function(velocity) { if (velocity) this._velocity = velocity; return this; } pingpong.Ball.prototype.setResetPosition = function(x, y) { this._resetPos = new goog.math.Coordinate(x, y); return this; }
There we also describe the main detection function, it will test if one of the players catched the ball and will reset ball position if not. If the vertical wall was hit, funtion returns the position of hit to let the outer function to determine which player to blame, judging by theirs position.
#!javascript pingpong.Ball.prototype.updateAndCheckHit = function(dt,playerOne,playerTwo) { var newPos_ = this.getPosition(); var size_ = new goog.math.Size(this.getSize().width * this.getScale().x, this.getSize().height * this.getScale().y); newPos_.x += this._xCoef * this._velocity * dt; newPos_.y += this._yCoef * this._velocity * dt; var hitVBounds_ = false; // vertical bounds were hit if (this._moveBounds !== undefined) { if (newPos_.x <= (this._moveBounds.left + (size_.width / 2))) { this._xCoef = 1; hitVBounds_ = true; } if (newPos_.x >= (this._moveBounds.right - (size_.width / 2))) { this._xCoef = -1; hitVBounds_ = true; } if (newPos_.y <= (this._moveBounds.top + (size_.height / 2))) this._yCoef = 1; if (newPos_.y >= (this._moveBounds.bottom - (size_.height / 2))) this._yCoef = -1; } var p1catched_ = playerOne.catched(this.getParent().localToScreen(newPos_)); var p2catched_ = playerTwo.catched(this.getParent().localToScreen(newPos_)); if (hitVBounds_ && !p1catched_ && !p2catched_) { this.setPosition(this._resetPos.x,this._resetPos.y); return newPos_; } else if (p1catched_) { this.xCoef = 1; return null; } else if (p2catched_) { this.xCoef = -1; return null; } this.setPosition(newPos_.x, newPos_.y); return null; }
In such functions you will need to monitor the current coordinate system, you work with, closely and to convert it properly when it is required. In this case parnet - is the layer that holds the ball and the ball position is the position relative to this layer coordinate system. Thereby we convert the ball position defined in layer coordinate system into the screen coordinate system before passing it to the catched method, and inside the catched method described below, we convert the passed ball position defined in screen coordinate system into the player local coordinate system.
Now we need to add the catched method which is used in previous function to player.js file. Using all the polygon vertices coordinates + scale and rotation, it returns if passed position is inside the area of polygon:
#!javascript pingpong.Player.prototype.catched = function(pos) { var p = this.getPoints(), s = this.getScale(), r = this.getRotation(), plen = p.length, coord = this.screenToLocal(pos), inPoly = false; var rsin = Math.sin(r * Math.PI / 180), rcos = Math.cos(r * Math.PI / 180), csx = coord.x * s.x, csy = coord.y * s.y, crx = (csx * rcos) - (csy * rsin), cry = (csx * rsin) + (csy * rcos); crx = coord.x, cry = coord.y; if (plen > 2) { var i, j, c = 0; for (i = 0, j = plen - 1; i < plen; j = i++) { var pix_ = p[i].x, piy_ = p[i].y, pjx_ = p[j].x, pjy_ = p[j].y; if (((piy_ > cry) != (pjy_ > cry)) && (crx < (pjx_ - pix_) * (cry - piy_) / (pjy_ - piy_) + pix_)) { inPoly = !inPoly; } } } return inPoly; }
New setting are required to be set when initializing the ball in pingpong.js:
#!javascript ball = new pingpong.Ball().setPosition(320,240) .setMovementBounds(20,620,460,20) .setVelocity(.2) .setResetPosition(320,240);
And now the main thing, checking the events that happened with the ball. We will use schedule method from scheduleManager, it calls the given function in each frame, telling it how much time passed from the previous frame. Currently we will blame the player who missed the ball in console and in the next subchapter we will make a Label for it:
#!javascript goog.events.listen(. . .); var hitPos_; lime.scheduleManager.schedule(function(dt){ if (hitPos_ = ball.updateAndCheckHit(dt, playerOne, playerTwo)) { console.log('player',(hitPos_.x <= 320) ? 1 : 2,'is a loser'); }; },ball); director.replaceScene(scene);
Blaming Message
Now will add a label which will tell us who failed to catch the ball. Just an information about who failed, we will not waste time on counting the score:
#!javascript ball = . . . .setResetPosition(320,240), label = new lime.Label().setPosition(280,30) .setText('').setFontFamily('Verdana') .setFontColor('#c00').setFontSize(18) .setFontWeight('bold').setSize(150,30);
Don't forget to add the label the to board layer:
#!javascript board_.appendChild(ball); board_.appendChild(label);
And, replace the output target from console to label:
#!javascript goog.events.listen(. . .); var hitPos_ = null, defDelay_ = 500, delay_ = defDelay_; lime.scheduleManager.schedule(function(dt){ delay_ -= dt; if (delay_ <= 0) label.setText(''); if (hitPos_ = ball.updateAndCheckHit(dt, playerOne, playerTwo)) { label.setText('player ' + ((hitPos_.x <= 320) ? 1 : 2) + ' is a loser'); delay_ = defDelay_; }; },ball); director.replaceScene(scene);
That's all. the ball is flying over the board, bounces from players, the one who missed it is blamed with the evil red label - I think it is enough for demonstration game.
Make-up
Great, let's do some make-up to demonstrate how gradients and textures work.
Let out background will have a nice grass-greeny color - we will change a background sprites initialization in pingpong.js:
#!javascript floor_.appendChild(new lime.Sprite().setPosition(160,240) .setSize(321,480) .setFill(new lime.fill.LinearGradient() .setDirection(0,1,1,0) .addColorStop(0,0,92,0,1) .addColorStop(1,134,200,105,1))); floor_.appendChild(new lime.Sprite().setPosition(480,240) .setSize(320,480) .setFill(new lime.fill.LinearGradient() .setDirection(1,1,0,0) .addColorStop(0,0,92,0,1) .addColorStop(1,134,200,105,1)));
For players (player.js) we will give a little bit transparent sea-like blue gradient:
#!javascript this.addPoints(-50,-125, 0,-175, 50,-125, 50,125, 0,175, -50,125, 0,75, 0,-75) .setFill(new lime.fill.LinearGradient() .setDirection(0,1,1,0) .addColorStop(0,0,0,210,.7) .addColorStop(1,0,0,105,.7)) .setScale(.4);
Ball (ball.js) will have a texture:
#!javascript this.setFill('./ball.png') .setSize(20,20);
Wall (wall.js) will be painted with concrete blue color and inherited from RoundedRect:
#!javascript pingpong.Wall = function() { goog.base(this); this.setFill(109,122,181) .setSize(20,20) .setRadius(3); } goog.inherits(pingpong.Wall, lime.RoundedRect);
Now everything looks much prettier:
Compilation
So, the demonstration game is complete. Here are the sources I've got:
pingpong.js | player.js | ball.js | wall.js | ball.png | pingpong.html
Now please re-check all goog.require lines - delete the calls that were not used then update the dependencies and collect all the resulting things in one script:
$ ./bin/lime.py update $ ./bin/lime.py build pingpong -o pingpong/compiled/pp.js
You can copy a pingpong.html file into compiled folder and change the Javascript calls in the header:
#!html <!DOCTYPE HTML> <html> <head> <title>pingpong</title> <script type="text/javascript" src="pp.js"></script> </head> <body onload="pingpong.start()"></body> </html>
Resume
I felt skeptical to the engine at first, (just) two games presented at the site are too casual for me. There are not a lot of example and details in documention, and there is a lot of things required for installation. And an acid square as favicon... :)
But then I've played in the game with numbers, it appeared to be quiet exciting (its principles are similar to Super 7 HD for iPad - but it is a simple one, event though it a demo). But then, when I've trained while writing a game from the article, everything appeared to be convenient, comfortable, considered and even minimalistic. There are minor tweaks and dampness and things not covered in documentation, but if the resulting code is forward-compatible, why not - right now guys are fixing all this stuff. So the final opinion is definitely positive.
The main thing - it is not a state-machine-based engine that is fashionable now - you can build on game script and bind to events, not to time or current frame, you don't need to think how to optimize drawing a lot of objects in next frame - yes, it almost Flash, it is sad that there is no editor :).
Video
LimeJS Engine demonstation on iPhone - PingPong game from Ulric Wilfred on Vimeo.
LimeJS Engine demonstation on Android - PingPong game from Ulric Wilfred on Vimeo.
LimeJS Engine demonstation on iPad - PingPong game from Ulric Wilfred on Vimeo.
(Videos are recorded with the help of engine authors)
To play
Here you can try to play (it can be a little buggy, because it is a very simplified version, please compare the platform-related experience you get with what you see on video)
P.S. Special thanks to lazio_od, he helped me with testing among with engine authors.
People are paying more attention to Android Renderscript now, due to Introducing Renderscript article in Android Developers Blog. So here's an article from the good old 2009 having thoughts on Renderscript and deconstructing a Fountain example on it.
By the way, here is that Fountain package in Honeycomb code.
3 Tiny JavaScript Snippets
Currently I am doing some stuff in JavaScript and I need to have just a tiny amounts of code to work with. As tiny as this article. But there are some things I really need to make the development comfortable for myself. So I require them to be tiny too.
Two-Liner Each (one function)
Works just with objects and arrays. For objects, callback takes key and value. For arrays, callback takes element.
#!javascript /** * Tiny each * @param {Array, Object} iterable the iterable to iterate through * @param {Function} func to call on each iteration, in array-mode gets an element (func(elem)), in object-mode gets a key and value (func(v, k)) */ function each(iterable, func) { if (iterable instanceof Array) for (var i = 0; i < iterable.length; i++) func.call(iterable, iterable[i]); else if (iterable instanceof Object) for (field in iterable) if (iterable.hasOwnProperty(field)) func.call(iterable, iterable[field], field); }
Quick Class Construction (Single Inheritance, one function)
This is just a slightly modified version from this nice article. Also, bind function is useful to make stuff like this: var catMeow = bind(cat, Cat.meow);.
#!javascript function class_(def) { var _proto = def; if (def['_extends'] !== undefined) { var _ex = def['_extends']; if (typeof _ex === 'function') { each(_ex.prototype, function(v, k){ if (_proto[k] === undefined) { _proto[k] = v; } else { _proto['_s_'+k] = v; } }); } else throw new Error('Wrong _extends field'); } var _init = def['_init']; if (_init === undefined) { _init = function() { if (this.prototype['_s__init']) this._init_super(); } } _init.prototype = _proto; def['hasOwnProperty'] = function(k) { return (k !== 'hasOwnProperty') && (Object.prototype.hasOwnProperty.call(this, k) || Object.prototype.hasOwnProperty.call(_proto, k)); } return _init; } function bind(obj, method) { return function() { return method.apply(obj, arguments); } }
Usage
#!javascript var Base = class_({ _init: function(a, b) { this.a = a; this.b = b; } someMethod: function() { console.log('parent'); } }); var Child = class_({ _extends: Base, _init: function(c) { this._s__init(5, 6); this.c = 7; console.log(this.a); console.log(this.b); console.log(this.c); }, someMethod: function() { this._s_someMethod(); console.log('child'); } }); var b = new Base(); var c = new Child(); b.someMethod(); c.someMethod(); console.log(b instanceof Base); console.log(b instanceof Child); console.log(c instanceof Base); console.log(c instanceof Child);
Easy assertions mechanism (one or two functions)
Just for quick TDD, if you like it. If you need only assertions, not a tests suites, take just AssertException and assert function - they are everything you need. Else, runTests allows you to run JUnit-like tests suites, even with proper setUp and tearDown. (Uses console to inform about tests results so in the presented form it may work only in Firefox / WebKit browsers)
#!javascript function AssertException(result, expectation) { this.result = result; this.expectation = expectation; } AssertException.prototype.toString = function () { if (this.expectation) return ('AssertException: Expected: ' + this.expectation + ' Got: ' + this.result); else return ('AssertException: Got: ' + this.result); } /** * Tiny assert * @param {Boolean} test the expression to test * @param {String} [_expectation] what was expected * @throws {AssertException} if assertion was failed */ function assert(test, _expectation) { if (!test) throw new AssertException(test, _expectation); } function _assert(test, val, expectation) { if (!test) throw new AssertException(val, expectation); } function assertNotNull(test) { _assert(test !== null, test + ' == null', 'not null'); } function assertDefined(test) { _assert(test !== undefined, test + ' !== undefined', 'defined'); } function assertTrue(test) { _assert(test, test + ' != true', 'true'); } function assertFalse(test) { _assert(!test, test + ' != false', 'false'); } function assertEquals(first, second) { _assert(first === second, first + ' != ' + second, second + ' == ' + second); } function assertInstance(test, cls) { _assert(test instanceof cls, test + ' not instance of ' + cls, test + ' instance of ' + cls); } function assertType(test, typename) { _assert(typeof test == typename, test + ' is not of type ' + typename, test + ' has type ' + typename); } /** * Tests runner * @param {Object, Function} suite for function-typed parameter, calls a function and informs through Firebug console about assertions for object-typed parameter, works like JUnit, calls every method which name starts with 'test...' also calls 'setUp' and 'tearDown' in the proper moments informs through Firebug console about assertions and passed/failed methods * @param {String} [_name] some name for test case or test suite (used only in logs to help you determine what failed) * @param {String} [_stopWhenFailed] for object-mode, stops testing when first assertion is failed in some method * @returns {AssertException} first failed exception for function-mode, nothing for object-mode * * runTests(new SomeClass()); * runTests(someFunc(), 'someFunc'); */ var __tCount = 0, __fCount = 0; function runTests(suite, _name, _stopWhenFailed) { if (typeof suite === 'function') { __fCount++; var field = (_name ? _name : ('Function ' + __fCount)); try { suite(); console.info('%s: %s', field, 'OK'); } catch (ex) { if (ex instanceof AssertException) { var info_ = '(' + field; if (ex.lineNumber) info_ += ':' + ex.lineNumber; if (ex.expectation) console.error('Assertion failed. Expected:', ex.expectation, '. Got:', ex.result, info_ + ')'); else console.error('Assertion failed. Got:', ex.result, info_ + ')'); console.error(ex); console.warn('%s: %s', field, 'FAILED'); return ex; } else { throw new Error(ex.toString()); } } } else if (typeof suite === 'object') { __tCount++; var title = _name || ("Suite " + __tCount); console.group(title); for (var field in suite) { if ((typeof suite[field] === 'function') && (field.indexOf('test') === 0) && suite.hasOwnProperty(field)) { console.log('Running', title + ' / ' + field); if (suite.setUp) suite.setUp(); var result = runTests(bind(suite, suite[field]), field); var passed = (result === null); if (_stopWhenFailed && (result !== null)) return result; if (suite.tearDown) suite.tearDown(); } } console.groupEnd(); } else { throw new Exception('Passed var has invalid type'); } return null; }
Examples
#!javascript var T1 = class_({ _init: function() { }, setUp: function() { }, test1: function() { assert(null == null); assert(12 == null, '12 == null'); assert('a' == null); assertTrue(true); assertFalse(false); assertTrue(false); assertFalse(true); assertEquals(5, 5.1); assertEquals(5, 5); assertEquals('a', 'ab'); assertEquals('a', 'a'); assertType(12, 'integer'); assertType(12, 'string'); assertType('12', 'string'); assertInstance(this, T1); assertInstance(this, Object); assertInstance(null, Object); assertNotNull(this); assertNotNull(null); }, test2: function() { //throw new Error('Alala'); assertEquals(6, 7.2); }, tearDown: function() { } }); var _f = function() { assertTrue(true); assertEquals('12', true); } runTests(new T1()); runTests(_f, '_f'); new T1().test1(); _f();
Snippets tests
Using TDD-snippet, I wrote a general Test Suite for all of three snippets to demonstrate their interaction.
Test Suite | All snippets
10 Useful Solutions for Android Developer
Contents
Introduction
About list adapters with sections (to group elements in the lists)
About lists containing some actions (list elements do something complex or change themselves when selected)
About list views manual invalidation
About caching images in ListView (for lists with remote images)
About adapters that iterate over cursors (to support pagination in lists)
About OAuth autorization in Android
About using MediaPlayer to play remote video received using HTTP
About queues containing several AsyncTasks (to execute background tasks sequentially)
About changing the list element selection style
About adding QuickActions to your project
Three more mini-solutions
1. Introduction
Last summer I had ignited the desire to write an Android client for vimeo web-service. I like this service and I think it would be cool to monitor updates on video subscriptions from your communicator.
I сonceived this project to be learning one (means I am learning), however as a result I've found that a valuable part was done (you can check out screenshots of the finished things), but it is still in progress. Almost simultaneously with me, being first, makotosan started to write his own version of client aimed at video upload and he is also has not finished it yet, but his version can do things that my version can not (and converse is also true, seems).
Anyway, through programming process I've got some knowledge base which I want to share. Not all the themes are exclusive but some tricks are hidden in the web or even not covered there. I will also give examples from vimeoid source code, so it will allow you to spy how the paragraph subject works in real-time (NB: some achors point to concrete lines in code).
2. Lists with subsections
Among with the regular ListView usage, it is frequently required to make a list with elements grouped in sections like this: section header, item, item, item, ..., section header, item, item, item, ..., section header, item, item, ..., section header, item, item, ... & s.o. See "Statistics" and "Information" sections at the image.
Headers must not react on selection or press and they must have their own layout. This may be accomplished extending the adapter of this list from BaseAdapter, for example, and by overriding its getItemViewType, getViewTypeCount and isEnabled methods, among with getView.
#!java public class SectionedItemsAdapter extends BaseAdapter { . . .
Example from vimeoid: SectionedActionsAdapter
The first step is creating a constants which identify element type, one for header, one for item (so there is a possibility to have more than two types, but it's better to use enum to store idenitifiers in cases like those):
#!java public static final int ITEM_VIEW_TYPE = 0; \\ item public static final int SECTION_VIEW_TYPE = 1; \\ section
Then a constant containing a number of element types (there's two in our case):
#!java public static final int VIEW_TYPES_COUNT = SECTION_VIEW_TYPE + 1;
Adapter must contain the information about all of the elements inside, so the getCount, getItem and getItemId realizations are depend on your situation.
getItemViewType method must return the constant that conforms with the element type in the passed position. There is a special constant named IGNORE_ITEM_VIEW_TYPE exist in Adapter class for the case when type is undefined.
#!java public int getItemViewType(int position) { if (. . .) return ITEM_VIEW_TYPE; if (. . .) return SECTION_VIEW_TYPE; return IGNORE_ITEM_VIEW_TYPE; }
I my case I store the list of sections inside the adapter and they contain their items inside. So I can ask any section to tell me how many items it holds inside and to determine the element type using this data.
This method can be used in overriden getView now:
#!java public View getView(int position, View convertView, ViewGroup parent) { final int viewType = getItemViewType(position); if (viewType == IGNORE_ITEM_VIEW_TYPE) throw new IllegalStateException("Failed to get object at position " + position); if (viewType == SECTION_VIEW_TYPE) { convertView = . . . // here you can get a header layout using LayoutInflater } else if (viewType == ITEM_VIEW_TYPE) { convertView = . . . // here you can get an item layout using LayoutInflater } return convertView; }
isEnabled must return false for elements that can not be pressed or selected and true for others. Here we can use getItemViewType again:
#!java public boolean isEnabled(int position) { return getItemViewType(position) != SECTION_VIEW_TYPE };
getViewTypeCount method returns the very constant determing a number of elements types:
#!java public int getViewTypeCount() { return VIEW_TYPES_COUNT; }
By the way, you can keep a pointer to LayoutInflater in your adapter and get it passed using constructor.
It is all the required things to make a list with sections, if you need to ensure in something - just look into example, but I'll make some notices before.
I use separate structures to store the data about sections and items. The section identifier, its title and child items structures are stored within the section structure. A pointer to parent section structure, item title, icon path and click handler (it will be covered in next paragraph) are stored within the item structure. Both structures' constructors are accessible only from adapters:
Example from vimeoid: LActionItem
I simplified adding sections and items to list using this way. Adapter has methods:
#!java public int addSection(String title); public LActionItem addItem(int section, int icon, String title);
Method addSection returns the section identifier so you can use it to add items in this section:
#!java final int suitsSection = adapter.addSection("Suits"); adapter.addItem(suitsSection, R.drawable.heart, "Hearts"); adapter.addItem(suitsSection, R.drawable.diamond, "Diamonds"); adapter.addItem(suitsSection, R.drawable.spade, "Spades"); adapter.addItem(suitsSection, R.drawable.cross, "Crosses"); final int figuresSection = adapter.addSection("Figures"); adapter.addItem(figuresSection, R.drawable.king, "King"); adapter.addItem(figuresSection, R.drawable.queen, "Queen"); . . .
3. Lists with elements that react on something
Sometimes it is required to change the list element content and/or switch activity when it is clicked. For example, the list of possible actions with some twitter account may contain "follow" element with minus icon, if you still do not follow this man and change its icon to plus when click happened and positive response (to following request) is received from twitter server. You can handle the selected element in current ListActivity and depending on position take a decision, but if your list is inside the general Activity, so may be it will be easier to handle selection inside the adapter.
Example from vimeoid: SectionedActionsAdapter
Uses: LActionItem
Used in: SingleItemActivity_
If you agree with that, your adapter can implement OnItemClickListener interface:
#!java public class ActionsAdapter extends . . . implements OnItemClickListener
And inside the activity that uses this adapter you can do:
#!java final ListView actionsList = (ListView)findViewById(R.id.actionsList); final SectionedActionsAdapter actionsAdapter = new ActionsAdapter(. . .); . . . // fill adapter with values actionsList.setAdapter(actionsAdapter); actionsList.setOnItemClickListener(actionsAdapter);
In my case some actions are responsible for each item in the section - they switch the activity or change the corresponding item content after server request. So I decided to create structures with public-access properties for sections and items, and the item structures contain a pointer to OnClick handler that gets View to change, so you it is possible to change the view just inside the handler. So it is just required to pass a click action to the appropriate handler inside the adapter:
#!java public void onItemClick(AdapterView<?> parent, View view, int position, long id) { final LActionItem item = (LActionItem) getItem(position); if (item.onClick != null) item.onClick(view); }
Using the addItem method described above you can set a handler directly from activity:
#!java final LActionItem heartsItem = adapter.addItem(suitsSection, R.drawable.heart, "Hearts"); heartsItem.onClick = new OnClickListener() { public void onClick(View view) { . . . } };
4. Manual invalidation of list views
As you may know, ListView in Android has a [little trick inside] named ListView Recycler. Its principle is in reusage of old elements views for elements that not fit the screen instead of creating new views while user scrolls the list like this, this principle is used in adapters' getView implementations.
If you need to update (invalidate) concrete known element view (or even its child view) at some moment, when it is visible to user, you may call ListView.invalidate() or Adapter.notifyDataSetChanged(), but sometimes these methods update not only the required view but also its neighbours or even all the visible elements (especially when layout is built incorrectly). There is a way to get the current view of list element using ListView.getChildAt(position) method. But position in this case is not index of the element in a list, as you may considered, but an index relative to visible views on the screen. So a methods like these would help:
#!java public static View getItemViewIfVisible(AdapterView<?> holder, int itemPos) { int firstPosition = holder.getFirstVisiblePosition(); int wantedChild = itemPos - firstPosition; if (wantedChild < 0 || wantedChild >= holder.getChildCount()) return null; return holder.getChildAt(wantedChild); } public static void invalidateByPos(AdapterView<?> parent, int position) { final View itemView = getItemViewIfVisible(parent, position); if (itemView != null) itemView.invalidate(); }
invalidateByPos updates view only if it is shown on the screen (forcing an adapter's getView method call), if this element is not visible - adapter's getView will be called automatically when this view will appear to user after scrolling. To update some child view of an element, you can use getViewIsVisible method, it will return the element view which gives access to its child views and it returns null if this element is not visible so update is not required.
Methods are defined in class: Utils
5. Caching remote images for lists
If you are creating ListView containing images taken from web, this chapter is for you. It would be unwise to get images by URL again each time getView is called in adapter - it is obvious that it would be better to a) cache them b) ask for them only when view with this image is visible. For the moment this task arose so recently for Android programmers, so there are a lot of solutions for it.
My variant is also from that list, it is Fedor Vlasov's solution, that is corrected for my needs. First, I changed a directory for cached images to be static, so it is created once for application cycle and surely cleaned when calling clearCache (it is good to call this method in onDestroy() of Activity using ImageLoader or in finalize() method of adapter using it), also I've changed a bit a way of this directory creation (see Utils.createCacheDir()). Secondly, you may pass the drawables IDs to constructor to determine what drawables to show in this place while loading an image and/or if loading image is failed. Thidly, some minor changes. Though, this class can be a singleton and you can just change its options before using it, but it is left for your decision. In my case the instance is created for each ListActivity started and is passed to adapters of inner ListViews that need it (or created directly in adapters if ListViews are inside a regular Activity). The main method id displayImage(String url, ImageView view), its definition speaks for itself.
Source from vimeoid: ImageLoader
Uses methods from: Utils
6. Adapters iterating over cursors
This chapter is about pagination in ListView. So, user gets first n elements, scrolls list to n-th element and only after that happen the response for n elements to DB or server is performed. Then the user scrolls the element 2n and we ask for next package with n size and so on. In vimeoid I make a resonse only after footerView with 'Load more...' label is clicked, it is not automatic way, but the technique is similar to subject.
Loading by click on footerView: ItemsListActivity_
Guest implementation: ItemsListActivity
Logged-in user implementation: ItemsListActivity
The classes hieararchy is a lit bit more complex, each page is loaded with special AsyncTask that calls Vimeo API in background and notifies the calling activity about are there any elements left or is it the last page, and the activity updates its views according to this data.
Adapter containing a set of cursors: EasyCursorsAdapter
To make a pagination possible, you may just keep a set of page containers (cursors, for example) in adapter and in getView(), if one of last elements is asked for, run the query for next page (AsyncTask is preferred), which will add new container to adapter when it will be received, so the adapter will have a possibility to call notifyDataSetChanged(). Like this:
#!java private final Page[] pages = new Page[MAX_PAGES_COUNT]; public View getView(final int position, View convertView, ViewGroup parent) { if (!waitingNextPage && (pages.length < MAX_PAGES_COUNT) && (position >= ((pages.length * PER_PAGE) - 2))) { final AsyncTask<Integer, . . .> nextPageTask = . . .; nextPageTask.execute(pages.length); // nextPageTask calls addSource, when next page is received waitingNextPage = true; } . . . } public void addSource(Page page) { if (pages.length >= MAX_PAGES_COUNT) return; pages[pages.length] = page; waitingNextPage = false; notifyDataSetChanged(); }
EasyCursorsAdapter is a good example for a case where Cursor is Page analogue. I am sure there are several alternative solution exists and I will be glad if someone will mention them in comments.
7. OAuth in Android
If you are writing a client for a complex web-service - you need to fight with authorization problem and in current moment most web-services use OAuth for its realization and Vimeo is one of those.
There is no need to write your own implementation of OAuth, there is very cool library named signpost exist, and I do not know any better alternatives for now.
Example from vimeoid: VimeoApi
Uses signpost through: JsonOverHttp
Activity that gets user token: ReceiveCredentials
Its definition at manifest: AndroidManifest.xml
To start, you need to get the exclusive key for your application from web-service and set a callback URL to return user there after successful authorization (i.e. vimeoid://oauth.done) (but in case of Android, tou can pass it with call to /request_token). Recently it is done using service web-interface for programmer.
The first authorization algorythm for Android is:
Point signpost to a service's OAuth entry-points
Send a request to /request_token, get a token/secret pair using this key for unauthorized requests of your applization (vimeoid://oauth.done callback URL is passed here): provider.retrieveRequestToken(Uri callbackUri). NB: retrieveRequestToken returns not token but Uri that you need to call in next step at once.
Launch browser activity, call /authorize with passing the application token and, optionally, appending additional parameters about required access rights: startActivity(new Intent(Intent.ACTION_VIEW, authUri + ...))
User will see a page in 'Allow this application to access your account?' style (if he is logged out of service, service will ask him to log in). If user grants access, browser will be redirected to callback URL vimeoid://oauth.done?..., but in case in your AndroidManifest.xml there is a special activity to handle URLs like this, Android will return a user to your application and open this very activity - ReceiveCredentials.
In ReceiveCredentials activity you get user token in parameters Uri uri = getIntent().getData(), now you need to get secret using this token by requesting /access_token: provider.retrieveAccessToken(Uri uri).
Now you can save user's token and secret in private SharedPreferences, for example: consumer.getToken(), consumer.getTokenSecret().
After all these things done you can just sign every request to web-service API with the token/secret you've got: consumer.sign(Object request). If your application was restarted, before doing any request you can check if you have saved tokens in SharedPreferences, if you are - just remember signpost with them: consumer.setTokenWithSecret(String token, String secret), in not - request access token again (or just refresh tokens, if web-service allows it).
Important notice: signpost in Android works only with CommonsHttpOAuthConsumer/CommonsHttpOAuthProvider. DefaultOAuth* classes do not work.
8. Getting video by HTTP and playing it in MediaPlayer
It is very hard to make MediaPlayer do the things you want in case of playing video, as I discovered. To get a video it was required for me to make an unusual HTTP request with special headers, so I had to implement getting stream and its buffering manually. I could not get stream playing using the audio-files-related examples as a pattern, so I download the full video file and start playing just when downloading is finished (if there will be not enough space to get video on SD card, I warn user about it). When player is closed or failed to play, I clear the cache.
Moreover, VideoView/SurfaceView behavior works ambiguously when switching views inside one single layout (black screen from time to time), so I had to just leave a single VideoView in layout and show ProgressDialog on the top of it, while video is loading. Again, if you know something about stream playing videos using MediaPlayer (or getting chunks manually), write to comments.
So, if there is enough to call MediaPlayer.setDataSource(Uri uri) in your case, you can skip some next paragraphs.
And if you also had to get a stream manually, I will notice a few moments and just demonstrate the code, it must speak for itself:
Example from vimeoid: VimeoVideoPlayingTask
Called from activity: Player
Layout: player.xml
It is better to get a stream using AsyncTask. I just aggregate MediaPlayer with ...PlayingTask for convenience, you may use any other way you want, but definitely it is better to get a stream using AsyncTask. In this case in onPreExecute method you may set up yout player, in doInBackground you can get a video stream and return it to onPostExecute and start playing from there. Also, it is handy to show percentage progress of downloading, because you know an amount of data received in doInBackground.
And if there is an exception was raised while getting a stream, it is required to show a message about in using runOnUiThread, because task execution was interrupted.
Calling getWindow().setFormat(PixelFormat.TRANSPARENT); is aimed to prevent views shown above the player to stay above even when they are closed/hidden. Anyway, when it is required to use ViewSwitcher, this stuff do not helps.
Code to get video stream by URL is similar to this one:
#!java public static InputStream getVideoStream(long videoId) throws FailedToGetVideoStreamException, VideoLinkRequestException { try { final HttpClient client = new DefaultHttpClient(); . . . HttpResponse response = client.execute(request); if ((response == null) || (response.getEntity() == null)) throw new FailedToGetVideoStreamException("Failed to get video stream"); lastContentLength = response.getEntity().getContentLength(); return response.getEntity().getContent(); } catch (URISyntaxException use) { throw new VideoLinkRequestException("URI creation failed : " + use.getLocalizedMessage()); } catch (ClientProtocolException cpe) { throw new VideoLinkRequestException("Client call failed : " + cpe.getLocalizedMessage()); } catch (IOException ioe) { throw new VideoLinkRequestException("Connection failed : " + ioe.getLocalizedMessage()); } }
9. AsyncTask Queues
If you need to execute several background tasks sequentially (when one finished - run next), this freestyle pattern (walking by linked list inside) will fir you. For example when your activity started you need to perform several successive calls to some web-server API or database. The main thing is that parameters and result types for all these tasks must be similar.
Here is a task-that-knows-it-has-next-task inteface:
#!java public interface HasNextTask<Params> { public int getId(); void setNextTask(HasNextTask<Params> task); public HasNextTask<Parames> getNextTask(); public AsyncTask<?, ?, ?> execute(Params... params); // must much with AsyncTask<Params, ...> }
Here is an interface that monitors when tasks are performed successfully or not:
#!java public interface PerformHandler<Params, Result> { public void onPerfomed(int taskId, Result result, HasNextTask<Params> nextTask); public void onError(Exception e, String description); }
HasNextTask interface implementation. The hollows given with three dots, you may move them into child class or make this class abstract to implement doInBackground/onPostExecute methods right in createTask method of queue:
#!java public class TaskInQueue<Params, Result> extends AsyncTask<Params, Void, Result> implements HasNextTask<Params> { private final int taskId; private HasNextTask<Params> nextTask = null; private final PerformHandler<Params, Result> listener; public TaskInQueue(PerformHandler<Params, Result> listener, int taskId) { this.taskId = taskId; this.listener = listener; } @Override public Result doInBackground(Params... params) { . . . /* task execution */ } @Override protected void onPostExecute(Result result) { . . . // handling a result, if required listener.onPerformed(taskId, result, nextTask); } @Override public int getId() { return taskId; } @Override public void setNextTask(HasNextTask<Params> nextTask) { if (this.nextTask != null) throw new IllegalStateException("Next task is already set"); this.nextTask = nextTask; } @Override public HasNextTask<Params> getNextTask() { return nextTask; }; }
And the main thing, the queue implementation:
#!java public abstract class TasksQueue<Params, Result> implements PerformHandler<Params, Result>, Runnable { public static final String TAG = "TasksQueue"; private HasNextTask<Params> firstTask = null; private HasNextTask<Params> lastTask = null; private Map<Integer, Params> tasksParams = null; private int currentTask = -1; private boolean running = false; // some task is running now private boolean started = false; // the whole queue is running now private int size = 0; protected HasNextTask<Params> createTask(int taskId) { // can be overriden return new TaskInQueue<Params, Result>(this, taskId); } @Override public HasNextTask<Params> add(int taskId, Params params) { Log.d(TAG, "Adding task " + taskId); final HasNextTask<Params> = createTask(taskId); if (isEmpty()) { firstTask = task; lastTask = task; tasksParams = new HashMap<Integer, Params>(); } else { lastTask.setNextTask(task); lastTask = task; } tasksParams.put(task.getId(), params); size += 1; return task; } @Override public void run() { Log.d(TAG, "Running first task"); if (!isEmpty()) try { started = true; execute(firstTask); } catch (Exception e) { onError(e, e.getLocalizedMessage()); finish(); } else throw new IllegalStateException("Queue is empty"); } @Override public void onPerfomed(int taskId, Result result, HasNextTask<Params> nextTask) { Log.d(TAG, "Task " + taskId + " performed"); if (taskId != currentTask) throw new IllegalStateException("Tasks queue desynchronized"); running = false; try { if (nextTask != null) { execute(nextTask); } else finish(); } catch (Exception e) { onError(e, "Error while executing task " + ((nextTask != null) ? nextTask.getId() : taskId)); finish(); } } protected void execute(HasNextTask<Result> task) throws Exception { Log.d(TAG, "Trying to run task " + task.getId()); if (running) throw new IllegalStateException("Tasks queue desynchronized"); currentTask = task.getId(); running = true; Log.d(TAG, "Running task " + task.getId()); task.execute(tasksParams.get(task.getId())).get(); // wait for result } protected void finish() { firstTask = null; lastTask = null; if (tasksParams != null) tasksParams.clear(); tasksParams = null; currentTask = -1; running = false; started = false; size = 0; } public boolean isEmpty() { return (firstTask == null); } public boolean started() { return started; } public boolean running() { return running; } public int size() { return size; } }
Now in your activities you can easily create a queue of background tasks:
#!java protected final TasksQueue secondaryTasks; private final int TASK_1 = 0; private final int TASK_2 = 1; private final int TASK_3 = 2; public ...Activity() { // constructor secondaryTasks = new TasksQueue<..., ...>() { // here you can override createTask @Override public void onPerfomed(int taskId, ... result) throws JSONException { super.onPerfomed(taskId, result); onSecondaryTaskPerfomed(taskId, result); } @Override public void onError(Exception e, String message) { Log.e(TAG, message + " / " + e.getLocalizedMessage()); Dialogs.makeExceptionToast(ItemsListActivity.this, message, e); } }; secondaryTasks.add(TASK_1, ...); secondaryTasks.add(TASK_2, ...); secondaryTasks.add(TASK_3, ...); } protected void someMethod() { . . . if (!secondaryTasks.isEmpty()) secondaryTasks.run(); . . . } protected void onSecondaryTaskPerfomed(int taskId, ... result) { switch (taskId) { case TASK_1: . . . case TASK_2: . . . case TASK_3: . . . . . . } }
By the way, thanks to Runnable interface you can run queues like this in separate thread:
#!java new Thread(secondaryTasks, "Tasks Queue").start();
Tasks queue in vimeoid: ApiTasksQueue
Created in: SingleItemActivity
Filled with tasks in: UserActivity
Handling completed tasks in: UserActivity
10. ListView selection highlight
You see a blue line on the image, it is a custom selected element highlight and it has four conditions - pressed, focused, disabled and transition animation from pressed to held condition for long tap. First three and held condition - it is so-called 9-patch, sure you heard something about them, animation is an xml-file.
To define the states for selection highlight, set android:listSelector="@drawable/selector_bg" for your ListView in layout. The algorythm is simple, but it to build rules in proper order in not an easy task sometimes. See examples:
Definition: selector_bg.xml
Animation: selector_bg_transition.xml
Declared at: generic_list.xml
There are also a tricks with 9-patch, each time when there is something wrong in layout, the whole list becomes a mess. Main rule is to check ListView declaration first of all, ensure that layout_width and layout_height are set to fill_parent and re-check the parent elements higher in the hierarchy. Then, if it has not helped, you may try to correct 9-patches. The thick black lines on top and to the left determine what image areas will be stretched if the content can't fill the image. The thick black lines (optional) on bottom and to the right determine in what image area the content will fit itself. It is also not so easy to get the correct positions at first time, have to experiment. Don't even think about creating 9-patches without editor, it is a brainfuck - content areas and errors are highlighted in editor, but even when everything seems ok, inflater understands a layout as you expect not every time.
11. Adding QuickActions
QuickActions - is small library for the popping out dialogs with actions like the one shown on the picture (and not just like this, because the design can be changed freely). They became a new trend when official twitter-client appeared. Sure there are another implemantations exists but in vimeoid I use this one and also changed it a bit for my needs.
To show a dialog like this instead of context menu when element in list is long-tapped, it is enough to override onCreateContextMenu method in ListActivity like this:
#!java public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { . . . final AdapterView.AdapterContextMenuInfo info = extractMenuInfo(menuInfo); final QuickAction quickAction = createQuickActions(info.position, getItem(info.position), info.targetView); if (quickAction != null) quickAction.show(); } protected QuickAction createQuickActions(final int position, final ... item, View view) { QuickAction qa = new QuickAction(view); qa.addActionItem(getString(R.string...), getResources().getDrawable(R.drawable...), new QActionClickListener() { @Override public void onClick(View v, QActionItem item) { . . . } }); . . . return qa; }
Directory contating a modified version of a library lib-qactions
Used in: VideosActivity
Adding external library to Eclipse project is described in this article. To be short, it is enough to create the separate Android project with sources for a library, set isLibrary checkbox in Android section in project properties, and in the original project just add the library project using Library -> Add button from the same section. R-file from the library project will be added to the original project after rebuild.
12. Three additional mini-solutions
12a. One entry point to invoke different activities
If your application uses a lot of different activities that called similar way, may be it will be useful for you to move this calls to a separate class, including filling Extras with data:
Example from vimeoid: Invoke
12b. Placeholders in localization strings
My be it is obvious, but in strings from strings.xml you can use placeholders to insert some locale-independent values inside these strings, i.e.: <string name="image_info">Image size: {width}x{height}</string>. format function can help you like this: format(getString(R.string.image_info), "width", String.valueOf(600), "height", String.valueOf(800))
#!java public static String format(String source, String... params) { String result = source; int pos = 0; while (pos < params.length) { result = result.replaceAll("\\{" + params[pos++] + "\\}", params[pos++]); } return result; }
Upd. As I expected, I had missed this method in Android library: there is a standard function getString(int resId, Object... formatArgs). Thanks to zochek.
12c. About wrong layouts
Be sure to read these articles, inflater in Android is very sensitive to complicated structures and if you are writing a complex application, you'll have to fix your layouts sooner or later:
Layout Tricks #1
Layout Tricks #2
Layout Tricks #3
Layout Tricks #4
Speed up your Android UI
My frequently re-rendedered layouts in one moment collapsed and getView has called approximately once per second (and I also meet this case now, but in much rare moments). After replacing a lot of nested complicated LinearLayouts to less-nested and elegant RelativeLayout, inflater clearly felt itself easier and me too, mysefl, because a hierarchy also became less complicated and it became easier to make changes. I do not had time to fix all of these, but now I am more attentive to layouts. Also check that you use width/height=wrap_content only for simple elements if possible, using wrap_content for width/height of LinearLayouts and other compound views is dangerous and may lead to unexpected consequences. It may not lead, but who is forewarned...
Modelling a Solar System in Fluxus
Some time ago I wrote a post about fluxus, livecoding and 3D-prototyping system. Now I want to demonstrate some of its features and describe how you may use them in pseudo(;))scientific needs. For example, you can create a model of a simplified solar system and make it fit in only 125 lines of code (including comments) -- it is the advantage of Racket language with graphic steroids, the core of fluxus and a descendant of PLT Scheme. Here how the result will look like:
There are sources in the post, a short desription of code structure, tutorial movies in Slavic English, examining in detail the whole process of writing this complicated (;)) code.
Sources
HERE
Description
Fluxus uses a term of state machine for scene construction. If you have programmed in OpenGL already, you are familiar with this principle - every next function in the code either modifies the matrix of scene state or changes the content of the scene (i.e. draws an object). You may construct the required scene objects just before any rendering will happen and then change their conditions later or just draw a new primitives in every frame (OpenGL understands that it may cache the objects which state is not changed a lot between frames). I am using the both ways of these, so I prepare the text labels and planets' orbits before rendering process but I draw planets in every new frame.
I have taken all the data about equatorial diameters, orbital radiuses and orbital periods of the planets from the single one table in Wikipedia article. It is very handy that all parameters are presented relatively to Earth properties (that is how astronomical units are calculated), so the Earth diameter and Earth year can be used as system of units in our model.
Do you know that distance from mass center of Earth to mass center of Sun is approximately equal to 11740 Earth diameters? It is the astronomical unit (astro-unit constant) and the distances from Sun to planets are measured relativey to it. And more, 109 Earth diameters fits the diameter of Sun (the Earth diameter is represented with diameter-factor constant in the model).
When we know this data, we can calculate the angles for planets positions (the orbital eccentricities are not taken in account in the model, it's a homework) and place them appropriately in the model.
Examining code
star, planet and planetary system (it is called star-system because the center of it is a star), consisting of star and planets, structures are defined
defined functions of
getting translate vector (qtv - quick translate vector) for planet using its orbital radius and orbital period
getting scale vector (qsv - quick scale vector) of planet using its diameter
fast calculation of planet position angle (curang), relatively to (Sun) (0, 0) point, using planet's orbital period
building orbit primitive (build-orbit) using its orbital radius
building label primitive (qto - _quick text object`) for planet using the passed string
the star of Sun is created, planets and all of them are put into "solar system" instance (solar-system). while filling planets structures, the labels primitives are built for each one.
using the planets data the orbits are built
functions are defined
draw-star, it draws a star
draw-planet, it draws a planet in the required position depending on current time and moving the text label in the same position
render function is defined, it draws sun and planets one by one, calling draw-star and draw-planet
render is assigned to be a function executed for each frame
Videos
Fluxus Livecoding: Building 3D Solar System / Part 1 from Ulric Wilfred on Vimeo.
Fluxus Livecoding: Building 3D Solar System / Part 2 from Ulric Wilfred on Vimeo.
Fluxus Livecoding: Building 3D Solar System / Part 3 from Ulric Wilfred on Vimeo.
Sandwitch Tumblr Theme
Have created Tumblr theme named Sandwitch. I was going to make tumblr-blog look like showdown blog-engine style I've made, and seems the result in the end is even better!
You can turn on tweets translation, allow Disqus comments and... write posts with source code highlighting!
To use source code highlighting it is required to make first line in your code blocks to be something like #!xml, so I recommend to write them using Markdown-edtior (it can be selected in your profile preferences). SHJS (copied to static.tumblr) is used to make it work. You also must specify programming languages used in blog manually (not just by checking "Highlight code" checkbox) in the sort of: ['html','css','xml','javascript','java','python','sh']. The languages you can enable are: html (HTML), xml (XML), css (CSS), javascript (JavaScript), python (Python), java (Java), ruby (Ruby), sql (SQL), sh (Unix Shell), php (PHP), cpp (C++), csharp (C#).
To translate tweets, set your "Twitter username" at theme customization.
To turn on Disqus, set your "Disqus shortname" at the very same settings.
Intro?
Ok, let the fuck it be my blog in English. Tumblr gives way to create two blogs and this is niiice. Since I've developed my [easy-setup-no-server-side-blog-engine](http://code.google.com/p/showdown-blog/), I have a possibility to post my shity staff almost everywhere and in markdown. This will be one of such places. In English. Because I hope my shity stuff is also a little bit important. [Воть тута на рюссъкам](http://shamansir-ru.tumblr.com)
Easy as Sandwich: Blog Engine in JavaScript and XML
Intro
Say you suddenly needed a personal blog. I already have some puny free hosting, and it hosting is puny for real, so it has no PHP and it even has no possibilities to set up any server-side at all. Or even worse, you have only a Dropbox account and in this very moment, suddenly, the personal blog is needed.
And more, may be you prefer to write you posts in Markdown-syntax instead of writing a heavy sad posts using dull HTML. The more, Markdown is now supported at a lot of places (excluding MSDN articles, may be). And there wouldn't be out of place to store separate posts in separate files, so you can take one and copy-paste it in Tumblr or somewhere else. And it gives you a possibility to push files in some repository and to make your articles versioned this way...
And more, you'd like to have two versions of your blog in one entry point. English and russian, for example.
I think you now feel what I mean: I have a proposal for you abou this all. It'd be better to give more than one link already but I am an evil geek so I'll put one in the end of article.
Picture
Components
JQuery, for bread
Showdown, for a sausage
And a dates parser for a mustard
Not to make things to hard, I've taken JQuery (I use only DOM-operations and a helper to load XML files asynchronously from it, so for the cruel need it can be accurately excised). Then I've taken Showdown, it is Markdown syntax parser moved to JavaScript. Then I've taken some strange dates parser (to display them nicely). And I've mixed all these stuff into one solid thing, so I've got a crazy little thing called JS/XML-driven blog engine. Easy as sandwich.
Receipt
To write your first post in a blog, get this package, unpack. Update your preferences (prefs.xml), create some post (posts/<post-id>.xml), add <post-id> in posts.xml. That's all, you're ready, post is published. For the next posts just repeat only last two steps. (In ./create.html you'll find an editor that is ripped out from Showdown, and it will help your phantasy to imagine what Markdown-syntax parsing result will look like).
Now, once more
Set up ising prefs.xml
Put some-post.xml in posts directory
Add some-post to posts.xml
Repeat steps 2 and 3 for next posts
Advantages
Minimalism.
No server side. At all.
Posts are written with Markdown-syntax.
One post - one XML file
Configuration-over-XML
Styles-over-CSS
Tags, tags cloud and tags navigation
Permalink for every post
Supports mobile browsers (some)
Several entry-points are supported
RSS-generating script is included out-of-the-box
Disadvantages
No commenting support
No indexing with search engines
Only for JavaScript-powered browsers
Javascript and JQuery sometimes go slowly in slow networks
If you have no .htaccess, user must name index.html explicitly
Things to optimize
May be later
Paging
Templates support
More Nice RSS / RSS Automation
Calendar
Example
Path to example
Source code
Googlecode project
Upd. Advantages and disadvatages had a bit changed through time, visit the project page to see how exactly they've changed.
Way of the Rainbow: Fingers Motion Detection Algorythm Based on a Colors Differentiation (Driven by LISP)
I am crazy a little bit, so in my spare time I've started to study Lisp and, to make my studying more interesting, I've tried to make a realization of my own algorythm. "Algorythm", for sure, is spoken too loudly, it has no matrix multiplication, no arrays sorting, no bubbles and no hard work in optimization (even no colors calibration, I sorry myself with the fact that this version if for learning). And yes, there are a lot of pictures in the article, and in the end there even will be a video.
Link to the sources, in advance
The goal is simple: Detect the positions of all ten finger in 2D-space (position coordinates and the tilt angle of each in discrete moment), translate these data through stdout or using socket to another application, so the last will have a possibility to make assumptions about "gestures" which user do and react appropriately in user interface. The inspiration for me was in the John Underkoffler talk about future interfaces and the fact that video4linux bindings for Common Lisp by Vitaly Mayatskih were caught by the arm and they could not have come at a better time. Here I present you only the first part - a program that detects coordinates and pinch of fingers. I dont't know if I'll make myself implement the other parts and make an enterprise condition of this part, if no-one will be interested.
The distinctive feature of this way is that it, with the proper courage, can be reproduced in the home conditions. To detect fingers positions in space no sensors or euristic algorythms or pattern-matching like in OpenCV is used. What is used:
Linux
Lisp-interpreter, SBCL is preferred
A bunch of Common-Lisp packages (but may be you already have installed lot of them if you are working with Lisp)
video4linux driver (v4l2convert.so) and GTK support
Any web-camera compatible with video4linux (mine is Genius iSlim 300)
Ten slips of paper which you can put on fingers: two of red, two of orange, two of yellow, two of green and two of blue.
These slips are the base of this crazy-little-algorythm, you can implement it without other parts in any programming language and in eny environment. Algorythm source code is located here, you can follow the code and the description simultaneously. Lisp is considered self-documenting language so I hope everything will be clear :).
Koo. Initial data
In the beginning we need to define which colors a program will discover and understand that possibly there is a finger located in this place. There is no sence to make them exact, we need to determine some delta, a small span of possible values to get both areas, a lighter and a darker one, approximately one color, in our "suspicious" region. I gave the own delta for each color, just because each of them usually behaves diffrently in respect of other ones. All my values are "hardcoded" - I found them through several experiments for concrete illumination and for concrete time of the day (a program works good in my house with the lights turned on from 8PM to the late night with the default camera brightness - it matches the most times and conditions when I have returned back from work). Let we consider it the learning version and that will excuse me. We may add some pre-calibration or general frame illumination analysis and make a colors correction in accordance with this value, but the everyones' slips themselves will be differently shaded anyway, if just we dont start the mass production of them with identical colors inoculated to tomorrow.
So, let us put the slips on our fingers.
The RGB-components on a picture are presented in the range from 0 to 1, the overflow when adding/subtracting is ignored. More of that, this colors are individual for my case, that's whay they look like not ideal.
Koo. First pass. Detecting possible fingers' locations areas.
The main array in the program is *fingers-values* which length is (frame width * frame height). Its every cell corresponds to concrete frame pixel and will contain the number in range from 0 to 200. This array is re-filled with new values (calculated using pixels' RGB-components) in every next frame.
So, while the algorythm cycle goes on, the *fingers-values* array will contain values like these:
0 value - pixel does not match any color plus-minus
Values in range from 1 to 49 - these values are for expected areas of left hand fingers locations, with 9-10 per every finger
Values in range from 50 tо 99 - these values are for expected areas of right hand fingers locations, with 10 per every finger
Values greater than 100 and less than 200 - the exact location of the according finger, to discover which one - subtract 100.
No let's get back to the algorythm, we're running first pass, analysing current video frame pixel by pixel.
If pixel does not filled with any color defined before plus-minus delta, we write 0 to the corresponding *fingers-values* array cell. If here is may be some concrete finger (color of pixel matches to one of predefined colors plus-minus delta), we write the correnponding number to the corresponding cell - 1-9 for thumb, 10-19 for index, 20-29 for middle, 30-39 for ring-finger and 40-49 for little one. Currently I write only 9,19, 29, 39, 49 values in the cells - I expected to make an additional gradation depending on how close was the value to the "middle" color, but this proved unnecessary (but ranges of 10 are making great help in future). It is expected that fingers of left hand are found by default. The number of detected areas of same color are not controlled or regulated any way at this step.
That's all, the frame was scanned, but it is just a first step: there are values less than 50 in our array.
Koo. Second pass. Detecting coordinates and angles.
Before second pass over the frame the temporary array of 10 booleans named hits is created. We control what fingers are already detected with this array. No we are going over every cell of main *fingers-values* array, one by one. If the value of current cell is greater than zero and less than 100 then we check if that finger was already detected, if was- we skip this cell, if not - we're trying to make decision on what hand can it be using the x coodinate for this cell. If the same finger for left hand was found and its x coordinate was greater than current (but not too close to current, I check if no closer than 80px) so we, seems, got the right hand - so we add 50 to current value and work with already updated one.
Now we now which hand it is and the estimated finger location area, it is left to detect its coordinates. So we save x and y of current pixel and then in cycle through angles from 0 to pi with a pi / 20 step (for example) we calculate the pixels' coords for each beam with the corresponding angle which extends from the saved point (in a non-learning version we can make a cache for relative values of these), the beams length is set to the predefined value, in my case it is 31px (including current pixel, 15 to the end and 15 to the start), and their center is located in current point.
The pixels' coordinates of each beam are uniquely correspond with indexes of neigbour cells in *fingers-values* array. While staying in current point with cursor we count pixel-by-pixel for every beam the number of matched values (those whos value between 1 and 50, adding 50 if the current hand is right) and if this number is acceptable for this length (I grant it to have error in 4 pixels, so for minimum 27 pixels of 31 must match) then bingo - we have detected the angle and finger position: finger coordinates (relative) - it is the start and end points of the beam and the finger pinch is the angle of matched beam. We can write to *hits* that finger is found and pass this data to the screen (or to stdout).
Koo. Possible applications.
When we know fingers coordinates and their tilt angles, we can identify almost any gesture. But the analysator need to have the ability of "prediction" of fingers position using the previous states - if the finger was suddenly lost in the center of frame so may be a hand was tightened into a fist or else, if it was lost at the edge of the frame, may be it was a fast outward movement. There is a solvable problem about detecting the hand that owns a single finger - it can be solved using additional markers for palms (if marker is not seen and a fingers are in back order on the frame - it is the backside), there are navy blue and violet colors left (I've added them to pictures for clarity). Or it even may be ignored what hand it is for gestures if there is insuffiecient amount of data (only two fingers are visible from camera). These gestures may be used to manipulate interfaces (as in the mentioned video - to move windows, watching images in albums, making all like in Minority Report, and there's only web-camera and psychological barrier overcome (to put the colored slips or the similar controllers on the fingers) required). Currently it is cheaper than densors and more funny than current applications of Microsoft Kinect :).
Upd. The people gave me this video, the idea seems similar but my version is more attic anyway :). And time had passed and Microsoft Kinect does much more iterensting thing now, so sorry me, Microsoft Kinect :)
Koo. What to improve
Add calibration, detect illumination/brightness level, make "Nijiato, colored slip of paper" a mass production item.
Detect what hand we see in camera with more intelligent way, using additional marker on a hand, for example)
Much of optimization:
relative coordinates of the beams may be cached
calculations may be threaded
we may scan not every frame but every tenth and to presume fast movements using gestures data
...
Koo. README
Currently it is required to install Linux packages named libv4l-dev and libgtkglext and register in ADSF the CLisp packages from this list (the repositories and required commands are indicated). Also you can install rlwrap to make yor work with interpretor easier. If you have 64bit system, you need to remove a hack from CL-V4L2 bindings, it is also described in requirements.
Whene these operations are done, the launch is simple as that:
$ LD_PRELOAD=/usr/lib/libv4l/v4l2convert.so [rlwrap] sbcl * (load "nijiato-demo-load.lisp")
(.so-file may be placed somewhere else depending on a bitness and structure of your OS)
The program in fact is the hardly revised demo-example from CL-V4L2 that shows GTK-window and projects an OpenGL-texture with camera image in it and also allows to get current pixels in every frame. FASL-version can fail to start, I am fighting with this problem. (Upd. No way, I've forgot)
Koo. Video
And finally a video that show program in work. It loads a lot of libraries at start, you can skip first 30 seconds approximately. "Detected" positions of fingers are shown with slim 1-pixel black line (those matched beams) and shown in the console in readable form. In the middle of video two thumbs of both hands are not detected, that is because the distance between them is less than 80 pixels that I have set to be minimal width between hands. The window from camera is intentionally small to ease the calculations for a program :).
P.S. Some (not a lot of) phrases in this article are related to the Russian epic sci-fi movie named Kin-dza-dza, so I promote it with this article :)
Fluxus — Prototyping OpenGL graphics and games on-the-fly (add Scheme to taste)
The internet for a programmer who insterested in 3D-graphics for several years is full of videos where people programming music visualizers, complex color-morphing effects or even more tricky things working at the intersection of technology - literally the author writes code and somewhere on background it is compiled and executed and the author sees the result - this process named livecoding. Most recently the programs like these are written in lisp-family languages, the similar editor exists for ProcessingJS, it renders code immediately in browser, but its not about it.
Fluxus - it is a cross-platform 3D-engine for games drafts based on livecoding principles and simultaneously the prototyping tool for 3D-graphics and interactive things. And there is pretty detailed documentation exist. Programming language is extended with graphic functions []PLT Scheme](http://racket-lang.org).
However, see for yourself:
When application launched, it is started in interpretor mode. To switch to code editor mode, which is used in the most of the videos, press Ctrl+1. To render current defined scene - press F5.
Hereis, for example, two rotating spheres that change their colors through time:
#!lisp (define (animate) (let* ((t (* (time) 2)) (x (sin t)) (y (cos t))) (with-state (translate (vector x y 0)) (colour (vector (+ 1.5 (sin (time))) 0 0)) (draw-sphere)) (with-state (translate (vmul (vector x y 0) 3)) (colour (vector 0 0 (- 1.5 (sin (time))))) (draw-sphere)))) (every-frame (animate))
Ant JUnit Nice Output Formatter
I've seached for nice Apache Ant formatter which do not writes full stack trace in console/file and just writes what methods are passed, what methods are failed, and if failed - where and why they failed (and only trace about methods from test class). I haven't found any. So I've written one.
For example:
[junit] ---------------------------------------------------------- [junit] Testsuite: com.undefined.MyTest [junit] Ran [0.322] testMethodOne ... OK [junit] Ran [0.023] testMethodOne... OK [junit] Ran [0.333] testMethodTwo ... FAILED [junit] Ran [0.343] testMethodThree ... FAILED [junit] [junit] Testcase: testMethodTwo(com.undefined.MyTest): FAILED [junit] (AssertionFailedError): expected:<Bender> but was:<null> [junit] (MyTest) assertEqualsInfo: 887 [junit] (MyTest) testGetUserInfoByUserId: 188
There is ant task for this:
#!xml <target name="easy-test" depends="test-clean, compile"> <mkdir dir="out/junit"/> <junit printsummary="off" fork="on" failureproperty="test.failed" showoutput="off" dir="out" outputtoformatters="false" filtertrace="on" > <classpath> .... </classpath> <formatter classname="com.undefined.testing.OneLinerFormatter" usefile="false" /> <batchtest fork="on" todir="out/junit" filtertrace="on"> <fileset dir="src/java/test"> <include name="**/*Test.java"/> </fileset> </batchtest> </junit> <fail if="test.failed">tests.failed=${test.failed}</fail> </target>
And finally, the implementation:
#!java package com.undefined.testing; import java.io.BufferedReader; import java.io.OutputStream; import java.io.PrintWriter; import java.io.StringReader; import java.io.StringWriter; import java.text.NumberFormat; import java.util.Hashtable; import java.util.regex.Matcher; import java.util.regex.Pattern; import junit.framework.AssertionFailedError; import junit.framework.Test; import org.apache.tools.ant.taskdefs.optional.junit.JUnitResultFormatter; import org.apache.tools.ant.taskdefs.optional.junit.JUnitTest; import org.apache.tools.ant.taskdefs.optional.junit.JUnitVersionHelper; import org.apache.tools.ant.util.FileUtils; import org.apache.tools.ant.util.StringUtils; /** * Prints a single lines of tests to a specified Writer. * Inspired by the BriefJUnitResultFormatter and * XMLJUnitResultFormatter. * * @see FormatterElement * @see BriefJUnitResultFormatter * @see XMLJUnitResultFormatter */ public class OneLinerFormatter implements JUnitResultFormatter { private final String TAB_STR = " "; private final boolean showCausesLines = true; // (\w+\.)+(\w+)\((\w+).(?:\w+):(\d+)\) private final Pattern traceLinePattern = Pattern.compile("(\\w+\\.)+(\\w+)\\((\\w+).(?:\\w+):(\\d+)\\)"); /** * Where to write the log to. */ private OutputStream out; /** * Used for writing the results. */ private PrintWriter output; /** * Used as part of formatting the results. */ private StringWriter results; /** * Used for writing formatted results to. */ private PrintWriter resultWriter; /** * Formatter for timings. */ private NumberFormat numberFormat = NumberFormat.getInstance(); /** * Output suite has written to System.out */ private String systemOutput = null; /** * Output suite has written to System.err */ private String systemError = null; /** * tests that failed. */ private Hashtable failedTests = new Hashtable(); /** * Timing helper. */ private Hashtable testStarts = new Hashtable(); /** * Constructor for OneLinerFormatter. */ public OneLinerFormatter() { results = new StringWriter(); resultWriter = new PrintWriter(results); } /** * Sets the stream the formatter is supposed to write its results to. * @param out the output stream to write to */ public void setOutput(OutputStream out) { this.out = out; output = new PrintWriter(out); } /** * @see JUnitResultFormatter#setSystemOutput(String) */ public void setSystemOutput(String out) { systemOutput = out; } /** * @see JUnitResultFormatter#setSystemError(String) */ public void setSystemError(String err) { systemError = err; } /** * The whole testsuite started. * @param suite the test suite */ public void startTestSuite(JUnitTest suite) { if (output == null) { return; // Quick return - no output do nothing. } StringBuffer sb = new StringBuffer(StringUtils.LINE_SEP); sb.append("----------------------------------------------------------"); sb.append(StringUtils.LINE_SEP); sb.append("Testsuite: "); sb.append(suite.getName()); sb.append(StringUtils.LINE_SEP); output.write(sb.toString()); output.flush(); } /** * The whole testsuite ended. * @param suite the test suite */ public void endTestSuite(JUnitTest suite) { StringBuffer sb = new StringBuffer("Tests run: "); sb.append(suite.runCount()); sb.append(", Failures: "); sb.append(suite.failureCount()); sb.append(", Errors: "); sb.append(suite.errorCount()); sb.append(", Time elapsed: "); sb.append(numberFormat.format(suite.getRunTime() / 1000.0)); sb.append(" sec"); sb.append(StringUtils.LINE_SEP); sb.append(StringUtils.LINE_SEP); // append the err and output streams to the log if (systemOutput != null && systemOutput.length() > 0) { sb.append("------------- Standard Output ---------------") .append(StringUtils.LINE_SEP) .append(systemOutput) .append("------------- ---------------- ---------------") .append(StringUtils.LINE_SEP); } if (systemError != null && systemError.length() > 0) { sb.append("------------- Standard Error -----------------") .append(StringUtils.LINE_SEP) .append(systemError) .append("------------- ---------------- ---------------") .append(StringUtils.LINE_SEP); } if (output != null) { try { output.write(sb.toString()); resultWriter.close(); output.write(results.toString()); output.flush(); } finally { if (out != System.out && out != System.err) { FileUtils.close(out); } } } } /** * A test started. * @param test a test */ public void startTest(Test test) { testStarts.put(test, new Long(System.currentTimeMillis())); } /** * A test ended. * @param test a test */ public void endTest(Test test) { // Fix for bug #5637 - if a junit.extensions.TestSetup is // used and throws an exception during setUp then startTest // would never have been called if (!testStarts.containsKey(test)) { startTest(test); } boolean failed = failedTests.containsKey(test); Long l = (Long) testStarts.get(test); output.write("Ran ["); output.write(((System.currentTimeMillis() - l.longValue()) / 1000.0) + "] "); output.write(getTestName(test) + " ... " + (failed ? "FAILED" : "OK")); output.write(StringUtils.LINE_SEP); output.flush(); } /** * Interface TestListener for JUnit >= 3.4. * * <p>A Test failed. * @param test a test * @param t the exception thrown by the test */ public void addFailure(Test test, Throwable t) { formatError("\tFAILED", test, t); } /** * Interface TestListener for JUnit > 3.4. * * <p>A Test failed. * @param test a test * @param t the assertion failed by the test */ public void addFailure(Test test, AssertionFailedError t) { addFailure(test, (Throwable) t); } /** * A test caused an error. * @param test a test * @param error the error thrown by the test */ public void addError(Test test, Throwable error) { formatError("\tCaused an ERROR", test, error); } /** * Get test name * * @param test a test * @return test name */ protected String getTestName(Test test) { if (test == null) { return "null"; } else { return /* JUnitVersionHelper.getTestCaseClassName(test) + ": " + */ JUnitVersionHelper.getTestCaseName(test); } } /** * Get test case full class name * * @param test a test * @return test full class name */ protected String getTestCaseClassName(Test test) { if (test == null) { return "null"; } else { return JUnitVersionHelper.getTestCaseClassName(test); } } /** * Format the test for printing.. * @param test a test * @return the formatted testname */ protected String formatTest(Test test) { if (test == null) { return "Null Test: "; } else { return "Testcase: " + test.toString() + ":"; } } /** * Format an error and print it. * @param type the type of error * @param test the test that failed * @param error the exception that the test threw */ protected synchronized void formatError(String type, Test test, Throwable error) { if (test != null) { failedTests.put(test, test); endTest(test); } resultWriter.println(formatTest(test) + type); resultWriter.println(TAB_STR + "(" + error.getClass().getSimpleName() + "): " + ((error.getMessage() != null) ? error.getMessage() : error)); if (showCausesLines) { // resultWriter.append(StringUtils.LINE_SEP); resultWriter.println(filterErrorTrace(test, error)); } resultWriter.println(); /* String strace = JUnitTestRunner.getFilteredTrace(error); resultWriter.println(strace); resultWriter.println(); */ } protected String filterErrorTrace(Test test, Throwable error) { String trace = StringUtils.getStackTrace(error); StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); StringReader sr = new StringReader(trace); BufferedReader br = new BufferedReader(sr); String line; try { while ((line = br.readLine()) != null) { if (line.indexOf(getTestCaseClassName(test)) != -1) { Matcher matcher = traceLinePattern.matcher(line); // pw.println(matcher + ": " + matcher.find()); if (matcher.find()) { pw.print(TAB_STR); pw.print("(" + matcher.group(3) + ")"); pw.print(matcher.group(2) + ": "); pw.println(matcher.group(4)); } else { pw.println(line); } } } } catch (Exception e) { return trace; // return the trace unfiltered } return sw.toString(); } }
Google Wave Client as Java Web Application
Zdrawstwooyte.
...So I wrote a small project in Java, which is a client for Google Wave, which in its turn can be extended with the features you need. Its current visual style is not very presentable (though, why not, a-la Windows 3.1 ;) ), 'cause I am not so good in web-design - but for all the project's source code I am responsible with my head :). Then, for example, the required CSS-styles looks the most understandable and the XHTML-structure is the most simplified (not to the detriment of standards) and the real designer can apply his skills in most and make this all look really beautiful.
Source code and war-package with current condition of the project are located at http://code.google.com/p/sametimed
Right now I have no public hosting ready at hand, so I can't show the project in action with ease. However I can, may be, please you with a video (at vimeo), it demonstrates its main possibilities, and perhaps it is pretty enough if you just want to know what the project can do. Anyway, you can run it by yourself, since there are detailed instructions at project site and the detailed source code inspection and concept description are in this very post...
Installation
Just four items required to run this client:
Client WAR-package, you can take it at googlecode project
Wave-protocol server installed with default settings, current version (0.2) (installation tutorial)
Any web-сервер applying Java EE specification (I used Jetty server integrated in Eclipse)
Firefox browser
The more detailed instruction on how to run the client per se or as working Eclipse project are at the project page. Here I will consider the code structure and will describe how it works (sorry, without UML-diagrams).
General concept
Here when I mention «server side» I mean not a wave-protocol server, but a server side of web-application.
Because there is only console (terminal) client for wave-protocol released now as a simple desktop jar-application, the main question is how to transfer information from web-client to server and back well-timed.
That's why it's necessary to introduce the two notions:
Command: is sent from client to server and asks to "open a wave", "add a participant", "undo some action", "say hi" & s.o., it is sent after user makes some action to call it.
Message: is sent from server to client and reports/informs that "someone has invited to a wave", «sonya replied hi», «participant was added to wave», «error happened» & s.o., it is sent with every update related to current client.
With this rules, a command may be sent from client immediately, not much thinking about server load, but the messages about updates are required to be sent only on the fact of the event. However, we have Javascript at server-side and currently it can not handle a things like these. It is the moment when Reverse Ajax was needed, rather its Java realization - DWR (Direct Web Remoting) library. It allows to call some client function from the server in the time when server decides but not client. Their site describes all the features which are not limited with this application.
Upd: Current source code state is rewriting to cometd library, this library is more simple and hm... intuitive. And we're waiting for WebSockets...
Commands and messages are sent in XML, and the content of messages about updates is sent in JSON, that's why JavaSvript is the only one who builds a user interface (I've used JQuery), and a server side is don't even thinks about existence of UI.
(there is a Renderer interface for server-side in project, its realization is called on required updates, but it is just intended for the cases similar to console client)
Current flow description
When you run a client, you see a page with text input for username and a single button. Wave-protocol server is required to be running herwith. When you press a button, the username you've got is passed to servlet (GetClientViewServlet), which connects you to a wave and returns the complete client model in JSON view. On the client side, JQuery build full wavelet insterface using this info. If you'll press this button again, you'll request another wavelet, they both [wavelets] will differ in internal ID (which is generated automatically) that is shown on a blue bar in brackets. Using this ID both server and client determine which client is owner/target for command or a message.
At the same time DWR starts to wait for updates, so you can enter one of allowed commands and press "send". For example, you can create a wave with "\new" command, open it with "\open <id>" command and say something just by entering the text (like in Skype). When you press "send" button, POST request is sent to another servlet (CommandsReceiverServlet), who gets the generated XML-command and permorms it immediately, passing the data to wave-protocol server.
Currently the updates are coming from server-side (and from wave-protocol server) in XML-encoded message (there is a callback on a client-side which called when new messages arrive), that includes the alias of the changed model (i.e. "chat", "inbox", "userslist", "errors" or "editor") and its content in JSON view, which is decoded immediately and updates the corresponding wavelet part.
Upd: I really do not remember why I haven't used JSON in JSON packages (without XML).
As you see, everything is simple.
Project structure
Java:
name.shamansir.sametimed.wave All the classes that lie "outside" and that are directly related to client; here are the abstract AUpdatingWavelet and ADocumentsWavelet classes, they determine the structure of the according wavelet type (the updating wavelet and its extension, a wavelet containg documents). SimpleWavelet class is an example of such realization. WavesClient class handles all the commands and returns the model of wavelet it contains to GetClientViewServlet.
name.shamansir.sametimed.wave.messaging All the things related to commands and messages; Commands/messages identifiers in CommandID/MessageTypeID, the Command and UpdateMessage classes themselves, and the commands receiving servlet CommandsReceiverServlet.
name.shamansir.sametimed.wave.model Classes that define wavelet model; They contain each sub-model definition, like a participants list, chat ot text document. And a ModelID classes that define the possible models with abstract AModel class. Plus ModelFactory, model factory.
name.shamansir.sametimed.wave.model.base The models values, something like "chat lines set", "document text blocks set", "list of waves online" and so on; Here in these classes the encoding to JSON is defined.
name.shamansir.sametimed.wave.model.base.atom What values are consist of, if it is required for their structure — «chat line», «text block», «wave identifier»;
name.shamansir.sametimed.wave.model.base.chat Wavelet with chat extension and its client;
name.shamansir.sametimed.wave.model.base.editor Wavelet with editable document support extenstion, not implemented currently, so disabled;
name.shamansir.sametimed.wave.render Classes related to rendering; There is the very class JSUpdatesListener that calls updates callback function at client using DWR.
The most logical way to make an extension is to implement ADocumentWavelet class and to extend WaveletWithChat class. Since in the most likely case you will operate with a "document" term (and a chat or anything other in this style is a document), this approach will fit you best. Also you'll need to realize what you document model is (by implementing AModel with some type, adding model ID in ModelID enum and adding this model generation in ModelFactory).
If your document will not handle any new commands, then it is enough - you can replace the wavelet that GetClientViewSelvlet returns with your own and voila!.. Oh yes, do no forget to build UI at the client, but I'll mention it below.
Else, if you'll need your own commands, strictly related to your document, you need to add these commands to CommandID type. After that, you need to extend WavesClient class to support your wavelet and to make it handle and pass new commands to wavelet independently from parent class. And, in this case, replace the WavesClient implementation in GetClientViewServlet with your and voila again! (and again, not mentioning the UI)
You'll need, of course, to handle some tricks when writing commands processing, but in outline it is all the required process for client extension.
JavaScript
ui.js is involved in the UI generation, each model block has the corresponding method
command.js sends and generates commands, gets updates messages and contains buttons handlers
ajax.js script to be replaced with the appropriate JQuery method, but my hands haven't reached it :). used in command.js
To add UI generation for your model, you need just to add a line that calls your handling method in createClient and renderUpdate methods of ClientRenderer object in ui.js and to write that method itself. Everything else will (must to) work on its own.
CSS
sametimed-plain.css interface that is even a little bit worse than colored :)
sametimed-colored.css Windows-3.11-like, colored interface
Currently the styles that handle positioning and the appearance (coloring) are not separated in different files (just using comments in that files), but may be I plan to.
Epilogue
I hope there will be a person who will be interested in this project, and if there will be, I plan to improve it more. For this moment, it is just an odd job "for interest", but a little more efforts - ant it can become a sterling project.
I ask those who will test it to send issues and bugs to the appropriate place, within reasonable limits and not about design :).
Participation in development is welcomed, but only for free license :).
An important notice
If you will test this application simultaneously with wave-protocol console (terminal) client, the messages that you send from terminal client will be received one later. It is not a bug and not an issue, it a way how chat "document" is generated. In the case of terminal Google had changed the document elements order so that is will be readable in console (as I suppose) - element start, element end and its body next). In my case the document is built in a "standard" way (start, body, end), this is the reason of discrepancy. If you will correct the way of generation either in my code or in terminal client code to be the same, they will fully comply with each other.
And yes, no input validation is performed currently at client.