Sport-Tooltip is a super fast and clean Tooltip class I developed with the Haxe community in mind, and is aimed at Haxe/Flash. It is :

  • Extremely simple to use
  • Very compact
  • Using a clean and transparent approach (not messing with your Flash like some other libs!)
  • Stylish & easily customizable
  • Released in Public domain (you can do whatever you want with it)

(Note: it will probably be converted to ActionScript 3 soon).

Kick-off

This demo will illustrate most of the features provided by Sport-Tooltip.

Notice the three different white, red and black areas on the right. Those show the 3 different overflow styles you can get in Sport-Tooltip. Also the yellow area is using a callback for the tooltip text instead of a String. As a result, it returns a random animal from the Chinese zodiac everytime.

Move mouse over the coloured areas to get some tooltips to appear:

This demo’s code is available at the end of this post.

How to use it?

Like so:

1
Tooltip.attach(spriteMario, "My name is Super Mario!");

This will create tooltips containing “My name is Super Mario!” when hovering the sprite.

But what if my tooltip content is not static?

Provide a callback instead

Use Tooltip.attachF() to attach some callback instead of a String:

1
2
3
4
    Tooltip.attachF(mySprite, function() {
        return "Today is " + ["Monday", "Tuesday", "Wednesday",
            "Thursday", "Friday", "Saturday", "Sunday"][Std.random(7)];
    });

You can also refer to functions and static methods with their name:

1
    Tooltip.attachF(mySprite, getTextForTooltip);

What about styling?

Sport-Tooltip uses the following typedef for defining styles:

1
2
3
4
5
6
7
8
9
10
11
/**
 * This is the structure to configure the tooltip.
 */

typedef TooltipStyle = {
    var overflow:       OverflowStyle;
    var fg:             UInt;                   // text color
    var bg:             UInt;                   // background color
    var bgAlpha:        Float;                  // background alpha
    var fontFamily:     String;                 // font-family
    var fontSize:       Int;                    // font-size
}

Overflow defines what happens when a tooltip content overflows out of stage. It can have 3 values, as defined by the enum OverflowStyle:

  • Lock: tooltip will be locked on the border, forbidden to cross it,
  • Serious: tooltip will go in the opposite direction,
  • None: tooltip will be let overflowing off-stage.

For an illustration of overflow, you can have a look at the demo, especially the 3 white, red and black areas.

The other parameters you’re going to be dealing with if restyling the tooltip are easy to figure out:

  • fg is the text color (eg. 0xffffff for white)
  • bg is the background color (eg. 0×000000 for black)
  • bgAlpha is the alpha opacity for the background only (eg. 0.5 for semi-opaque)
  • fontFamily is a string defining the font(s) to use, separated by comas (eg. “Arial, sans-serif”)
  • fontSize is the font size in pixels (eg. 15)

This is nice, but how to actually use it?

Overwriting the default style

The default style is defined in Tooltip.FACTORYSTYLE. But usually you’ll want to change it dynamically at the beginning of your program, like so:

1
2
3
4
5
6
7
8
Tooltip.setDefaultStyle({
    overflow:   Lock,
    bgAlpha:    1.0,
    bg:         0x0,
    fg:         0xffffff,
    fontFamily: "Trebuchet MS",
    fontSize:   15
});

What about those cases where I want a specific style for a tooltip?

Attaching a specific style to a tooltip

Tooltip.attach() admits an optionnal third argument, of the type TooltipStyle. You can write something like this:

1
2
3
4
5
6
7
8
Tooltip.attach(text, "<b>Sport-Tooltip</b> is clean.", {
    overflow:       Serious,
    fg:             0xffffff,
    bg:             0x0000ff,
    bgAlpha:        .9,
    fontFamily:     "Trebuchet MS",
    fontSize:       15
});

Is that it?

That’s about it!! Two other public methods actually exist: unattach() and unattachF().

They are used in those cases where you dynamically create and delete a lot of elements that have tooltips attached to them, so the listeners can get properly unregistered. It’s normally good practice to always call unattach() and unattachF() every time you destroy an element having previously been attached a tooltip.

public API

They are only 5 methods publicly available. Also I haven’t written the returns for the sake of simplicity, all of those 5 methods actually return the class Tooltip, so they can be chained if you want:

  • static function setDefaultStyle(s:TooltipStyle);
  • static function attach(d:DisplayObject, s:String, st:TooltipStyle=null);
  • static function attachF(d:DisplayObject, f:Void->String, st:TooltipStyle=null);
  • static function unattach(d:DisplayObject, s:String, st:TooltipStyle=null);
  • static function unattachD(d:DisplayObject, f:Void->String, st:TooltipStyle=null);

Source code

The source code can be get here:

Enjoy!

Sport-Tooltip, super fast and clean tooltip for Haxe/Flash.

A force-driven simulation used to calculate relatively stable positions of any undirected graph, with or without cycles.

Primary usage for this is to calculate constellations in my game Mandolin, as every constellation is randomly generated and we want beautiful constellations (ie. avoid path crossing, concave cycles and cumbersome layouts), however I made it into a generic class package.

Principle

  • Repulsion: between vertices (particules);
  • Attraction: between edges (springs);
  • Some damping helps prevent the simulation running for an infinite time.


Above: The graph shown in this special example has 7 vertices and the following edges: [0, 1], [1, 2], [2, 0], [3, 4], [4, 5], [5, 6], [6, 3], [3, 0]. The successive pink dots indicate the lowest kinetic positions, to date.

Credits

Written in Haxe and w/ my DungeonEngine. Exponential thanks to Pierre Hebrard, a pure math guru I met tonight here in Hong Kong, International Travel Hotel @ Chungking Mansion, who helped me figure out the last problem with my springs. I hope your job interview will go smooth!

Controls

The remote-control has the following buttons:

  1. Orange: manual iteration, will pause if running
  2. Bright blue: continue
  3. Navy: pause
  4. White: zoom in
  5. Black: zoom out
  6. Truncated purple: reset!
  7. Light gray: increase damping
  8. Dark gray: decrease damping
  9. Truncated yellow: increase repulsion factor
  10. Dark yellow: decrease repulsion factor.

(see also at http://alex.moutonking.com/graph.html).

Generic undirected graph stabilizer

Here is my own RLE compressor (run-length encoding) for HaXe, it has some improvements over the one provided by the Polygonal framework. Also, my version is released in the Public domain.

It is possible to introduce an optimization to the plain RLE compression: assuming sequence of data sometimes offer some ever-changing bytes, we can conventionally imply negative counters introduce verbatim sequences whose length is the two’s-complement of their hexadecimal value.

In short, a counter n can belong to one of those two ranges:

  • 0×01–0x7F (positive): repeat, n times, the following byte (eg: 7x -> xxxxxxx).
  • 0×80-0xFF (negative): transcribe the next -n bytes, verbatim (eg:-3abc -> abc).

Haxe

Haxe is a cross-target language (Javascript, Flash, PHP, Neko, C++, iPhone etc). Another Haxe implementation of RLE-codec is provided with the Polygonal framework. As it didn’t have the verbatim optimization, here is my own implementation:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
import haxe.io.Bytes;
import haxe.io.BytesBuffer;

/**
* Run-length encoding (RLE)
* @example
* import haxe.io.Bytes;
* var rle:Byte = RLE.encode(Bytes.ofString("ABBABBBAAAA"));
* var decoded:Byte = RLE.decode(rle);
*
* // with strings
* var rle:String = RLE.encode(Bytes.ofString("ABBABBBAAAA")).toString();
* var decoded:String = RLE.decode(Bytes.ofString(rle)).toString();
* @end
*
* 2011-07-08 v1.0 Original release.
* Alexandre van 't Westende 2011. Public Domain.
*/

class RLE {
/**
* Compress byte sequence using a custom RLE method.
* "XXABCDEFXXXYYYYYYYYYYYYYYYY" (27 bytes) will be compressed as "2X(-5)ABCDEF3X(16)Y" (13 bytes).
* @param a (haxe.io.Bytes) A sequence of bytes.
* @return The compressed sequence of bytes.
*/

public static function encode(a:haxe.io.Bytes):haxe.io.Bytes {
var
r = new BytesBuffer(),
accSimil:Bool = true,
dissim = new BytesBuffer(),
dl:Int = 0,
p:Int = 0,
l:Int = a.length,
v:Int = 0x100,
pv:Int = 0x100,
co:Int = 1;

pv = v = a.get(p++);
while (p v = (++p &gt; l) ? 0x100 : a.get(p - 1);
if (accSimil &amp;&amp; v != pv || co &gt;= 0x7F) {
r.addByte(co);
r.addByte(pv);
co = 1;
pv = v;
accSimil = false;
}
else if (accSimil &amp;&amp; v == pv) {
co++;
}
else if (!accSimil &amp;&amp; v != pv) {
dissim.addByte(pv);
dl++;
co = 1;
pv = v;
}
else if (!accSimil &amp;&amp; v == pv || dl &gt;= 0x7F) {
if (dl == 0) {
co = 2;
accSimil = true;
pv = v;
}
else
{
var b = dissim.getBytes();
dissim = new BytesBuffer();
dl = 0;
r.addByte(0xFF - b.length);
r.add(b);
co = 2;
pv = v;
accSimil = true;
}
}
else throw "Logic error"; // watchdog.
}

if (accSimil) {
r.addByte(co);
r.addByte(v);
}
else {
var b = dissim.getBytes();
if (b.length &gt; 0) {
r.addByte(0xFF - b.length);
r.add(b);
}
}

return r.getBytes();
}

/**
* Uncompress a byte sequence previously compressed with RLE.encode().
* @param a (haxe.io.Bytes) A compressed sequence of bytes previously made with RLE.encode().
* @return The uncompressed sequence of bytes, same as the original sequence.
*/

public static function decode(a:haxe.io.Bytes):haxe.io.Bytes {
var
r = new BytesBuffer(),
p = 0,
co = 0;

while (p &lt; a.length) {
co = a.get(p++);
if (co &gt;= 0x80) {
for (i in 0...0xFF - co) r.addByte(a.get(p++));
}
else {
var byte = a.get(p++);
for (i in 0...co) r.addByte(byte);
}
}
return r.getBytes();
}
}

Here is a simple test tile:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import RLE;
import haxe.io.Bytes;
import haxe.io.BytesBuffer;

class TestRLE {
static public function main() {
for (example in [
"a",
"aa",
"XXXX",
"ABBA",
"AABB",
"AABA",
"abcdefghijklmnopqrstuvwxyz",
"XXABCDEXXAAAAFGH",
"lfa84q3n0gq34tqk3",
"4#$))))2nf@##0q23kr2Q########$F+!O$$$$$$$*\n\t@$_____~$!_)$T@@@@@@@ir34",
"Afffffffffffffffiiiiiiiiiiiii444444444488888888888vwnnwre000wrg999999999993222nnnnnnnnf",
"fhhhhhhhhhhhh17777777743-fmmmmmmmmaekvvvvvv",
"a222222222vjjjjjjj44444444va",
"AHAHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHH", // a test with more than 0x80 repeated characters
]) {
var encoded:Bytes = RLE.encode(Bytes.ofString(example));
var result:String = RLE.decode(encoded).toString();
var pct:Int = Std.int(encoded.length * 100 / example.length);
trace(example + " [enc+dec] " + result + (example == result ? " ...OK (" + pct + "%)" : " ---ERROR!"));
}
}
}
Run-length encoding in Haxe

French keyboards use AZERTY layout instead of QWERTY. I usually work in english, but I often type Cmd–Q instead of Cmd–A on the Mac, thus quitting Photoshop/Textmate instead of selecting everything, and losing the whole history/open files… The same kind of misadventure regularly happens too with W and Z which are swapped; closing the document when a mere undo was wanted…

So, how to write french accented characters on the Mac, with an english keyboard, without having to use international input methods (which are error prone as recounted before)?

US keyboard has no accented characters

Explanations

Typing accented characters involves producing the accent first (using ALT–<something>), and then typing the letter supposed to be written underneath. For example to type ‘é’ in the word café, you would issue the following sequence:

<ALT–e> <e>    —>  é

Similarly to produce a ‘û‘ – like in the french word flûte (pipe) – you would type:

<ALT–i> <u>    —> û

The list

Here is a list of the sequences I found for the french. If you experiment a bit, you’ll probably find it easier to remember and use than you first expected:

Accent/character Example Sequence
´ Élégante ligne alt–e
` À la bonne heure ! alt–`
ˆ La forêt. alt–i
¨ Joyeux noël ! alt–u
ç Comme ça. alt–c
Ç Ça ira ! alt–C
œ Cœur alt–q
« alt–\
» alt–shift–\
Attention… alt–;
14,90 € alt–@
4 ‰ alt–R

How to remember them

Most sequences are using vowels (e, i, and u, respectively for ´, ˆ, and ¨). Only the ` is using a non-vowel; but the key being the backquote, it’s trivial to remember (producing for example à, è, and ù). The accent ´ is quite often associated with the e (é), which makes it easy too. As for the ˆ and ¨ (ALT–i and ALT–u), they are rarer, and still using vowels. Finally, ç is simply ALT–c.

Other benefits

You also get other characters this way: the german ß (ALT–s), some greek letters, spanish punctuation such as‘¡ hola !’(ALT–1)… Icing on the cake: you can also write capitalized accented letters such as ‘É’, which is not so easy with a true french keyboard.

Simply hold the SHIFT key while typing your character, and it will appear upper-cased.

French accented characters with an english keyboard (Mac)

Developing for all platforms using HTML5, then wrapping the app using a framework such as PhoneGap is a new emerging way of developing. It’s an interesting alternative to the costlier approach of developing a specific version for each targeted platform.

Now you can develop a single HTML5 application and release it on the Apple Store, the Android Market and even other platform such as Blackberry or Palm.

Unificating platforms

At some point, the future of HTML did not seem so bright. But it managed to largely dominate the whole past decade. It transcended the differences between computer’s hardware, network configuration, OS, CPU speed and screen resolutions in a simple but standardized and open fashion.

In some ways the situation ahead is comparable since we have different hardwares and screen resolutions, and two irreconcilable platform: iOS and Android.

Let’s look at a concrete example of how to develop using HTML5 on a given platform. Then we will see how to simply deploy it on several platforms and you can make your own opinion on the subject.

Writing a Tetris application in HTML5 for iPhone

Three weeks ago, Alex Kissinger wrote a good article about how to write a Tetris application for iPhone, using HTML5, not Objective-C. This is a good start for us. You can see it here: http://sixrevisions.com/web-development/html5-iphone-app/.

Tetris app in HTML5 on the iPhone

In the current form presented by the article, the application can not yet be shared on the App Store. We’ll see in the next chapter how we can easily deploy it to a multitude of targets, using PhoneGap.

Deploying your application using PhoneGap

PhoneGap allows you to wrap a HTML5 in a native app that you’ll then be able to deploy to Android phones, iPhones, iPad, Blackberry and many more… Write your web 2.0 app,  wrap it, and deploy it.

PhoneGap explanations (taken from its website)

If you’d like to use another product, other similar solutions are presented in the last chapter.

Manage different screen resolutions

Almost every platform uses a different resolution.

The following article presents strategies using MVC (model, view, controller) to elegantly overcome this universal problem: http://blog.gameclosure.com/?p=59.

A word about HTML5 apps in desktop browsers

HTML5 specifications are not finished yet, and while most mobile/tablet platforms fairly support HTML5 features, this is not the same for visitors using Firefox or Internet Explorer. I  compiled the following table yesterday, and although it concerns the Internet users from France (http://gs.statcounter.com), the results are eloquent.

Browser Global shares Layout engine HTML5 supported from HTML5 from Shares supporting HTML5
Firefox 39.06% Gecko Gecko 2.0 Firefox 4 1.60%
IE 38.44% Trident Trident 5.0 IE 9 0.92%
Chrome 16.42% WebKit WebKit 533 Chrome 5.0 15.77%
Safari 6.65% WebKit WebKit 533 Safari 4.1 5.23%
Opera 1.06% Presto Presto 2.7.62 (I didn’t look)
Total * - - 23.52%

HTML5 support in major browers, march 2011 (France)

The strong warning coming from this: most smartphones and tablets already support HTML5, but almost 75% of Internet users’ browsers do not support HTML5.

Although Firefox 4 and IE9 are supporting it, they hardly represent more than 3% (while Firefox and IE together represent about 77% of the market share). Obviously some inertia is to be expected there.

What this means in the context of this article you shouldn’t use too modern features if your app is intended to run on a website as well. However it’s possible to write portable applications in HTML4+CSS2+JS.

Other mobile tools

As Zeeshan Siddiqui pointed out on his blog (http://helium.com/items/2119797-how-html5-is-aiding-in-cross-platform-development), a number of mobile tools to get us started are already available:

Those are taken from his article:

  • RhoMobile: open source framework, using Ruby, for smartphone development
  • Appcelerator: Zeeshan writes it’s the most favorite amongst developers and allows to create apps for smartphones, tablets and desktops. It can use Javascript, PHP, Python and Ruby.
  • WidgetPad: an online IDE to create webapps, by Satoshi Nakajima
  • PhoneGap: we already talked about it, it has a cross-platform simulator created in Adobe AIR, allows dev for iPhone, iPad Android, Palm, Symbian and Blackberry.

I’d also cite Monkey Coder which translates Monkey code so that it can run on many platforms by translating the code, but its price is $ 120 and it’s not really a HTML5 solution. Other platforms you may want to consider include J2ME Polish (embedded Java solution), Grapple and Open Plug.

Conclusion

Native development will always provide more features and is probably a better experience for the user when done properly, though not all of them might notice. But sometimes it’s not what you want. Since those techniques are fairly new, it remains to see whether it’s possible for an application to become a killer app using an HTML5 approach.

Cross-platform development using HTML5

This license lets others remix, tweak, and build upon your work non-commercially, as long as they credit you and license their new creations under the identical terms.This 11 minutes trip hop/jungle tune was written about 10 years ago, and was a major shift from my previous styles. Original title was Engelpulver. As the song goes on, it gets a gloomier and gloomier atmosphere, a presupposed consequence of the title’s advice being not followed.

Direct download link (mp3)

Don’t deal with angels

A Captcha is an annoying box widely used in this beginning of century to ensure a website’s user qualifies as a human (as opposed to a script or ‘bot’). Some sort of Turing test.

These days it seems harder and harder to use. For human beings, that is.

It’s becoming quite common that people now actually need to enter the text twice, or even three times ; recent forum readings have highlighted this and I don’t expect it will improve over time.

\retrospective/

Back a few years ago, this kind of captcha was already quite advanced. Nevertheless it showed numerous problems:

System used by IPB forums (2004)

  • Simplistic and static grid
  • almost regular noise [sic]
  • black text while nothing else is black
  • using only one and same font
  • no variable text angle
  • no text disformation

Using an adapted Optical Character Recognition (OCR) algorithm, this captcha is probably trivial enough to decipher: 1) filter out non black pixels, 2) launch OCR.

A slightly more difficult is this one, used at Yahoo! for some time and generated with the EZ-Gimpy program. It combined some black-on-white characters with a vortex effect:

Generated by the EZ-Gimpy program, previously used on Yahoo, now is abandoned.

Cracking this one probably involves some topological break-down. What is topology? In short,

Topology (from the Greek τόπος, “place”, and λόγος, “study”) is a major area of mathematics concerned with spatial properties that are preserved under continuous deformations of objects, for example, deformations that involve stretching, but no tearing or gluing. It emerged through the development of concepts from geometry and set theory, such as space, dimension, and transformation. – Wikipedia.

Now there would be three steps, the first one being the most difficult to achieve:

  1. write an algorithm that requires a letter-like shape as input and returns a topological graph describing the spatial relationships between the letter-like shape’s components: paws, loops, bridges, relative lengths and basic orientation; for example ‘b’ has a loop whereas ‘s’ doesn’t have one, ‘n’ has one bridge whereas ‘m’ has two, ‘w’ remotely looks like a ‘m’ so you also need to consider orientation;
  2. generate a topology graph for each possible character (a-z, 0-9…) and build a collection that will be used for later comparison,
  3. isolate captcha’s characters and for each character: process topological graph, compare to the collection built in step 2, retain the closest match.

Now even this CAPTCHA had to be massively abandoned because in January 2008 Network Security Research released a program to recognize this CAPTCHA. According to Wikipedia, ”Windows Live Hotmail and Gmail, the other two major free email providers, were cracked shortly after.”

Ouch! Nowadays (2011) ReCAPTCHA seems the champion. It’s available as a webservice, it’s free, it’s cool and of course and it was acquired by Google in 2009 to help scanning its books.

But sometimes it’s getting difficult:

What? ReCAPTCHA, screenshot by Marat

And the machines’ OCR capabilities are still actively developed: ReCAPTCHA has been reportedly cracked with 30% success rate in august 2010.

Now this brings questions.

Debate future:

  1. As the captchas get harder and harder to read, will the humans soon need some OCR robots to assist them?
  2. When will robots get better than us at deciphering captchas?
  3. What do you think will massively replace captchas say ten years from now: animated problems? abstract logic tests?

By the way, does anybody have Sarah Connors’ phone number?

Update: one I just got 2 minutes ago

Debate future: harder and harder captchas

All integrated development environment (IDE) can search in a whole project but performances are usually slow, this article explains how to use the command-line to perform lightening fast searches.

Suppose we want to list all functions in a project.

We’re going to use the egrep command for this purpose. Egrep is the same command as grep but with -e option, for regular expression search. egrep installed by default on Linux and OSX (Windows users might want to install Cygwin).

The command-line will look like this:

1
egrep -Ri "patternToSearch" *

Explanations:

  • -R: recursive
  • -i: case-insensitive
  • “patternToSearch”: what you want to search, it can have spaces and can be a regular expression
  • *: a wildcard to treat all entries in the current working directory

Here’s a way to display all functions’ definitions in files sitting under the current directory:

Command-line recursive regex search

Another example: look for long hexadecimal strings

Suppose you’re maintaining a Facebook application developed by someone else and at some point you don’t know where the public/secret app keys were stored. This can be troublesome if they are many files.

Well using egrep with a simple a regular expression can give you results in a matter of seconds:

Find hexadecimal string of length >= 10

The regex [a-f0-9]{10,} simply means an uninterrupted string of at least 10-characters belonging to the range 0-f.

Conclusion

It’s probably a matter of personal preference but for me the benefits of the command-line project search outweight the IDE-based search, here are my reasons:

  • results are displayed very quickly
  • you can instantly kill an ongoing command using CTRL+C (for example if you notice the regex is too loose)
  • you have all the grep options: for example -B3 will display the three lines before every match, -A5 will display the match and the five lines after (grep man page for more)
  • finally, since you are already using the shell, it potentially leaves room for further creative solutions, using stream redirection and pipes (e.g.: grep -R social * | mail -s “here you are” jeanjacques@gmail.com).
Command-line recursive regex search

It is a well-known fact that People’s Republic of China is regarding the taiwanese question with firmness, if not rigidness. Quoting Wikipedia:

The People’s Republic of China until the 1990s had made it clear that “there is only one China in the world”, “Taiwan is an inalienable part of China” and “the Government of the People’s Republic of China is the sole legal government of China” – Wikipedia

Today while spending the afternoon in a bookstore I found this book about Countries and Continents:

Interestingly the index had white out on some asian country:

It appeared pp. 125 and 126 were stuck together.

A further examination in the book revealed another white out area, probably concealing the name Taiwan as a country:

Here we are: Taiwan whitened out

Now I can’t say I feel like the hero of 1984. But still. Isn’t this actually counterproductive?

Countries and Continents

Watch this. By subBlue.

Surface detail from subBlue on Vimeo.

Surface detail (by subBlue)