<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearchrss/1.0/" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0"><id>tag:blogger.com,1999:blog-923082020090979517</id><updated>2012-05-01T02:07:43.083-07:00</updated><category term="scripting" /><category term="visualization" /><category term="math" /><category term="qml" /><category term="tongue-in-a-cheek" /><category term="javascript" /><category term="ai" /><category term="java" /><category term="game engines" /><category term="books" /><category term="storytelling" /><category term="tutorial" /><category term="boost" /><category term="triz" /><category term="games" /><category term="indie" /><category term="perforce" /><category term="hexagons" /><category term="creativity" /><category term="self-improvement" /><category term="qt" /><category term="productivity" /><category term="programming languages" /><category term="c++" /><category term="learning" /><category term="edutainment" /><title type="text">gd reflections</title><subtitle type="html">Game programming phenomena introspected</subtitle><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://blog.ruslans.com/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://blog.ruslans.com/" /><author><name>ruslans</name><uri>http://www.blogger.com/profile/03375859473751956887</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="24" height="32" src="http://2.bp.blogspot.com/_DVYH9neSnMw/S0V_XM6aN0I/AAAAAAAAAMc/06dTTnY0PNw/S220/avatar3.jpg" /></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>17</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/gd_reflections" /><feedburner:info uri="gd_reflections" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry><id>tag:blogger.com,1999:blog-923082020090979517.post-2832331933412373020</id><published>2011-04-25T12:19:00.000-07:00</published><updated>2011-04-25T14:26:26.648-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="javascript" /><category scheme="http://www.blogger.com/atom/ns#" term="games" /><category scheme="http://www.blogger.com/atom/ns#" term="tutorial" /><category scheme="http://www.blogger.com/atom/ns#" term="programming languages" /><title type="text">Memylon: the language wars are over!</title><content type="html">Meet my cat:
&lt;br /&gt;
&lt;center&gt;&lt;img border="0" src="http://3.bp.blogspot.com/-oXd9AAYMHSk/TbXBpCRDCoI/AAAAAAAAAjM/4qRIbPW8adA/s400/cat.png" /&gt;&lt;/center&gt;
He's programming (and JavaScript in particular) illiterate, but likes to program anyway. And situation like this is perfectly fine, unless that code, which is written to learn things, goes into production. We all know that never happens, though. We do, right?..
&lt;br /&gt;
&lt;br /&gt;
Anyway, one day he wanted to play with &lt;a href="http://en.wikipedia.org/wiki/Canvas_element"&gt;Html5 canvas&lt;/a&gt; and make a small silly game or something.
&lt;br /&gt;
&lt;br /&gt;
And that's what he came up with:
&lt;br /&gt;
&lt;br /&gt;
&lt;center&gt;
&lt;div style="position: inherit;"&gt;
&lt;script type="text/javascript"&gt;
//  the main entry point
window.onload = function () {
    Memylon.init();
}

//  the game module
var Memylon = function() {
    //  constants
    var FRAME_TIME = 50, FLASH_TIME = 1000;
    var CARD_W = 64, CARD_H = 60, CARDS_IN_ROW = 11, CARDS_NUM_VARIATIONS = 54;
    var FLIP_TIME = 500, HIDE_TIME = 500, SHOW_TIME = 300;
    //  variables
    var cards  = [], anims = [];
    var numCardsW = 6, numCardsH = 4;
    var prevIdx = -1;
    var numMisses = 0;
    var canInteract = false;
    var bgImage, cardsImage;
    var context;

    // the initialization function
    function init() {
        var canvas = Utils.$('gameArea');
        if (canvas &amp;&amp; canvas.getContext) {
            context = canvas.getContext('2d');
            Utils.$('restartGame').onclick = function () { 
                this.value = 'Restart';
                resetGame();
            };

            canvas.addEventListener('mousedown', function (e) {
                    var parentX = parentY = 0, obj = canvas;
                    while (obj) {
                        parentX += obj.offsetLeft;
                        parentY += obj.offsetTop;
                        obj = obj.offsetParent;
                    } 
                    if (window.scrollLeft != undefined) {
      parentX += window.scrollLeft; 
      parentY += window.scrollTop;
     } else if (window.scrollX != undefined) {
      parentX -= window.scrollX; 
      parentY -= window.scrollY;
     } else if (document != undefined &amp;&amp; document.documentElement != undefined) {
      parentX -= document.documentElement.scrollLeft; 
      parentY -= document.documentElement.scrollTop;
     }
                    onMouseClick(e.clientX - parentX , e.clientY - parentY);
                }, false);
            setInterval(updateBoard, FRAME_TIME);
        }

        bgImage = Utils.$("bg");
        cardsImage = Utils.$("cards");
    }
    //  draw a card sprite on canvas
    function drawCard(cardID, x, y, scaleX, scaleY) {
        var glyphID = cardID &gt; 0 ? cardID : 0;
        var cx = x + CARD_W*(1 - scaleX)/2;
        var cy = y + CARD_H*(1 - scaleY)/2;
        var glyphX = (glyphID%CARDS_IN_ROW)*CARD_W;
        var glyphY = Math.floor(glyphID/CARDS_IN_ROW)*CARD_H;

        context.drawImage(cardsImage, 
            glyphX, glyphY, CARD_W, CARD_H, 
            cx, cy, CARD_W*scaleX, CARD_H*scaleY);    
    }
    //  play a "flash cards" animation
    function playFlashCards() {
        canInteract = false;
        for (var i in cards) {
            var card = cards[i];
            var startDelay = (i%numCardsW + 1)*80;
            var flashTime = FLASH_TIME*numCardsW;
            card.anim = createAnim(
                ['pose', startDelay, card.id],
                ['flip', FLIP_TIME,  card.id],
                ['pose', flashTime, -card.id],
                ['flip', FLIP_TIME, -card.id]);
        }
        anims = [createAnim(['exec', numCardsW*80 + FLIP_TIME*2 + flashTime, 
            function () { canInteract = true; }])];
    }
    //  game-specific animation update functions
    var AnimFunctions = {
        //  "draw static card" animation
        pose : function(t, cardID, card) {
            drawCard(cardID, card.x, card.y, 1, 1); 
        },
        //  "flip card" animation
        flip : function(t, cardID, card) { 
            var scale = Math.cos(Math.PI*t);
            var id = (scale &gt; 0) ? cardID : -cardID;
            drawCard(id, card.x, card.y, Math.abs(scale), 1); 
        },
        //  "dissolve card" animation
        hide : function(t, cardID, card) {
            if (t &lt; 1) {
                context.globalAlpha = 1 - t;
                drawCard(cardID, card.x, card.y, 1, 1); 
                context.globalAlpha = 1;
            }
        },
        //  flying text animation
        text : function (t, params) { 
            //  append missing parameters with defaults
            Utils.setDefaults(params, {sizeFrom: 10, xFrom: 182, yFrom: 150, alphaFrom: 1, 
                font: 'Arial', bold: true, color: '#2222AA'});
            Utils.setDefaults(params, {sizeTo: params.sizeFrom, alphaTo: params.alphaFrom, 
                xTo: params.xFrom, yTo: params.yFrom});
            //  interpolate current text parameters
            var size = Utils.lerp(params.sizeFrom, params.sizeTo, t);
            var x = Utils.lerp(params.xFrom, params.xTo, t);
            var y = Utils.lerp(params.yFrom, params.yTo, t);
            var alpha = Utils.lerp(params.alphaFrom, params.alphaTo, t);

            context.font         = (params.bold ? 'bold ' : '') + size + 'px ' + params.font;
            context.fillStyle    = params.color;
            context.textBaseline = 'middle';
            context.textAlign    = 'center';
            context.globalAlpha  = alpha;
            context.fillText(params.text, x, y);
            context.globalAlpha  = 1;
        },
        //  executes a function at the end of animation period
        exec : function(t, fn) {
            if (t === 1) {
                fn();
            }
        },
        //  empty "spin doing nothing" animation
        wait : function(t) {
        }
    };
    //  create an animation sequence
    function createAnim() {
        var arg, animType, duration, param;
        var anim = new AnimSequence();
        for (var i = 0, nArg = arguments.length; i &lt; nArg; i++) {
            arg = arguments[i];
            animType = arg[0];
            duration = arg[1];
            param = arg[2];
            anim.add(AnimFunctions[animType], duration, param);    
        }
        return anim;
    }
    //  play the "game is won" scene
    function playFinalScene(cardID) {
        var xCenter = 190;
        anims = [
            createAnim(['wait', 1000], ['text', 500, {
                text: 'This is it.', 
                color: '#5F5B60', alphaTo: 0.8,
                yFrom: 30, xFrom: 400, xTo: xCenter, 
                sizeFrom: 50
            }]),
            createAnim(['wait', 2000], ['text', 700, {
                text: 'the language wars', 
                color: '#735551', 
                yFrom: 75, xFrom: -200, xTo: xCenter, 
                sizeFrom: 30
            }]),
            createAnim(['wait', 2700], ['text', 1000, {
                text: 'ARE OVER.', 
                color: '#81878C', 
                xFrom: xCenter, yTo: 120, 
                sizeFrom: 0, sizeTo: 40
            }]),
            createAnim(['wait', 5000], ['text', 1500, {
                text: 'and the winner is...', 
                color: '#B2A89B', 
                xFrom: 500, xTo: xCenter, yFrom: 160, 
                sizeFrom: 30
            }]),
            createAnim(['wait', 6500], ['text', 5000, {
                text: getCardInfo(cardID).name,
                color: '#D91122', 
                xFrom: -100, xTo: xCenter, yFrom: 210, 
                sizeFrom: 0, sizeTo: 55
            }]),
            createAnim(['exec', 10000, function () {
                var winnerURL = Utils.$('winnerURL');
                winnerURL.style.visibility = 'visible';
                winnerURL.href = getCardInfo(cardID).url;
            }])
        ];
    }
    //  process the "card clicked" event
    function clickCard(cardIdx) {
        var card = cards[cardIdx];
        if (prevIdx === -1) {
            //  no cards are flipped yet
            prevIdx = cardIdx;
            card.anim = createAnim(['flip', FLIP_TIME, card.id]);
            card.id = -card.id;
        } else {
            var prevCard = cards[prevIdx];
            if (Math.abs(card.id) === Math.abs(prevCard.id)) {
                //  animation for the already flipped card: wait and dissolve
                prevCard.anim = 
                    createAnim(['pose', FLIP_TIME, prevCard.id],
                               ['hide', HIDE_TIME, prevCard.id]);
                //  animation for the current card: flip and dissolve
                card.anim = 
                    createAnim(['flip', FLIP_TIME, card.id],
                               ['hide', HIDE_TIME, -card.id]);
                //  animation of the flying card caption
                anims = [createAnim(['text', 2000, {
                    text: getCardInfo(card.id).name, 
                    alphaFrom: 1, alphaTo: 0.01, 
                    sizeFrom: 10, sizeTo: 300}], ['wait'])];
                var cardID = card.id;
                prevCard.id = card.id = 0;
                if (Utils.every(cards, function (card) { return (card.id === 0); })) {
                    //  all matches are found, show the final scene animation
                    playFinalScene(cardID);
                }
            } else {
                //  animation for the already flipped card: wait and flip back 
                prevCard.anim = 
                    createAnim(['pose', FLIP_TIME + SHOW_TIME, prevCard.id],
                               ['flip', FLIP_TIME,  prevCard.id],
                               ['pose', undefined, -prevCard.id]);                    
                //  animation for the current card: flip, wait, flip back 
                card.anim = 
                    createAnim(['flip', FLIP_TIME,  card.id],
                               ['pose', SHOW_TIME, -card.id],
                               ['flip', FLIP_TIME, -card.id],
                               ['pose', undefined,  card.id]);
                prevCard.id = -prevCard.id;
                setNumMisses(numMisses + 1); 
                }
            prevIdx = -1;
        }
    }
    //  reset the game board into the initial state
    function resetGame() {
        var ids, i, idx1, idx2;

        //  generate a random subset of card variations
        ids = [];
        for (i = CARDS_NUM_VARIATIONS - 1; i &gt;= 0; i--) ids[i] = i + 1;
        Utils.shuffleArray(ids);
        cards = [];

        for (i = numCardsW*numCardsH - 1; i &gt;= 0; i--) {
            cards[i] = {
                id   : -ids[Math.floor(i/2)],
                anim : createAnim(['pose'])
            }
        }
        Utils.shuffleArray(cards);

        //  cache the card positions
        for (i in cards) {
            cards[i].x = (i%numCardsW)*CARD_W;
            cards[i].y = Math.floor(i/numCardsW)*CARD_H;
        }

        setNumMisses(0);
        anims = [];
        prevIdx = -1;

        playFlashCards();
        Utils.$('winnerURL').style.visibility = 'hidden';
    }
    //  update/draw the game board
    function updateBoard () {
        var i;
        context.drawImage(bgImage, 0, 0);
        for (i in cards) {
            var card = cards[i];
            card.anim &amp;&amp; card.anim.update(FRAME_TIME, card);
        }    
        for (i in anims) {
            anims[i] &amp;&amp; anims[i].update(FRAME_TIME);
        }      
    }
    //  update the miss counter
    function setNumMisses(num) {
        numMisses = num;
        Utils.$('attemptsCounter').innerHTML = numMisses;
    }
    //  mouse click handler
    function onMouseClick(x, y) { 
        var cardIdx = Math.floor(x/CARD_W) + numCardsW*Math.floor(y/CARD_H);
        var card = cards[cardIdx];
        if (canInteract &amp;&amp; card &amp;&amp; (cardIdx !== prevIdx) &amp;&amp; (card.id !== 0)) {
            clickCard(cardIdx);
        }
    }
    function getCardInfo(cardID) {
        var cardIdx = Math.abs(cardID) - 1;
        var a = Utils.$('links').children[cardIdx];
        return {name:a.innerHTML, url:a.href}; 
    }

    return {
        init : init
    }
}();

//  helper utility functions
var Utils = {
    //  randomly shuffles the array using Fisher-Yates algorithm
    shuffleArray : function (arr) {
        for (var i in arr) {
            var k = Math.floor(Math.random()*i);
            var val = arr[k];
            arr[k] = arr[i];
            arr[i] = val;
        }
    },
    //  returns true if all elements of the array satisfy the given predicate
    every : function (arr, predicate) {
        for (var i in arr) {
            if (!predicate(arr[i])) return false;
        }
        return true;
    },
    //  linear interpolation between a and b with factor t
    lerp : function (a, b, t) {
        return a + t*(b - a);
    },
    //  append parameters in "params" with default values from "defaults"
    setDefaults : function (params, defaults) {
        for (var i in defaults) {
            if (params[i] == undefined) {
                params[i] = defaults[i];
            }
        }
    },
    //  poor man's jQuery
    $ : function (id) {
        return document.getElementById(id);
    }
}

// a simple class representing a list of animations played in sequence
AnimSequence = function () {
    this.anims = [];
    this.curAnim = 0;
    this.curTime = 0;
};
AnimSequence.prototype.add = function (updateFn, duration, startParam) {
    this.anims.push({updateFn: updateFn, duration: duration, startParam: startParam});
};
AnimSequence.prototype.update = function (dt, updateParam) {
    var anim = this.anims[this.curAnim];
    this.curTime += dt;
    if (anim.duration &amp;&amp; this.curTime &gt;= anim.duration) {
        anim.updateFn(1, anim.startParam, updateParam);
        if (this.curAnim &lt; this.anims.length - 1) {
            this.curTime = 0;
            this.curAnim++;
        }
    } else {
        anim.updateFn(anim.duration &amp;&amp; this.curTime/anim.duration, 
            anim.startParam, updateParam);
    }
};
&lt;/script&gt; 

        &lt;br /&gt;
&lt;div id="gameContainer" style="font-weight: bold; font: normal normal 120% Georgia, Serif; height: 270px; position: relative; width: 384px;"&gt;
            &lt;canvas id="gameArea" width="384" height="270"&gt;
                &lt;p&gt;No canvas for you, sorry. Please use a &lt;a href="http://www.google.com/chrome"&gt;proper browser&lt;/a&gt;.&lt;/p&gt;
            &lt;/canvas&gt;
&lt;div id="controls" style="bottom: 0px; font-weight: bold; position: absolute; width: 100%;"&gt;
&lt;span style="bottom: 2px; color: #ffdfdf; left: 5px; position: absolute;"&gt;Misses:&lt;/span&gt; 
                &lt;span id="attemptsCounter" style="bottom: 2px; color: white; left: -20px; position: relative;"&gt;0&lt;/span&gt;
                &lt;a href="http://www.google.com/" id="winnerURL" style="bottom: 2px; color: #ff8f8f; left: -5px; position: relative; visibility: hidden;" target="_blank"&gt;Sure, but what is this?..&lt;/a&gt;
                &lt;input id="restartGame" style="bottom: 2px; position: absolute; right: 2px;" type="button" value="Start Game" /&gt;
            &lt;/div&gt;
&lt;/div&gt;
&lt;img id="cards" src="http://4.bp.blogspot.com/-h6pG0uR0Q28/TbXBe4m54iI/AAAAAAAAAjE/UzpdQl--UNg/s1600/cards.png" style="display: none;" /&gt;
        &lt;img id="bg" src="http://2.bp.blogspot.com/-WIf6-qtjNio/TbXBbfZJUWI/AAAAAAAAAi8/cBP0J-yRFD0/s1600/babel_tower.png" style="display: none;" /&gt;
        &lt;br /&gt;
&lt;div id="links" style="display: none;"&gt;
&lt;a href="http://en.wikipedia.org/wiki/Lua_(programming_language)"&gt;Lua&lt;/a&gt;
            &lt;a href="http://en.wikipedia.org/wiki/Erlang_(programming_language)"&gt;Erlang&lt;/a&gt;
            &lt;a href="http://en.wikipedia.org/wiki/Clojure"&gt;Clojure&lt;/a&gt;
            &lt;a href="http://factorcode.org/"&gt;Factor&lt;/a&gt;
            &lt;a href="http://en.wikipedia.org/wiki/D_(programming_language)/"&gt;D&lt;/a&gt;
            &lt;a href="http://en.wikipedia.org/wiki/Scratch_(programming_language)"&gt;Scratch&lt;/a&gt;
            &lt;a href="http://en.wikipedia.org/wiki/Self_(programming_language)"&gt;Self&lt;/a&gt;
            &lt;a href="http://en.wikipedia.org/wiki/Powershell"&gt;PowerShell&lt;/a&gt;
            &lt;a href="http://en.wikipedia.org/wiki/Go_(programming_language)"&gt;Go&lt;/a&gt;
            &lt;a href="http://en.wikipedia.org/wiki/Python_(programming_language)"&gt;Python&lt;/a&gt;
            &lt;a href="http://en.wikipedia.org/wiki/Haskell_(programming_language)"&gt;Haskell&lt;/a&gt;
            &lt;a href="http://en.wikipedia.org/wiki/Java_(programming_language)"&gt;Java&lt;/a&gt;
            &lt;a href="http://en.wikipedia.org/wiki/Ruby_(programming_language)"&gt;Ruby&lt;/a&gt;
            &lt;a href="http://en.wikipedia.org/wiki/Scala_(programming_language)"&gt;Scala&lt;/a&gt;
            &lt;a href="http://en.wikipedia.org/wiki/Ada_(programming_language)"&gt;Ada&lt;/a&gt;
            &lt;a href="http://en.wikipedia.org/wiki/Smalltalk"&gt;Smalltalk&lt;/a&gt;
            &lt;a href="http://reference.wolfram.com/legacy/v5/Tour/MathematicaAsAProgrammingLanguage.html"&gt;Mathematica&lt;/a&gt;
            &lt;a href="http://ioke.org/"&gt;Ioke&lt;/a&gt;
            &lt;a href="http://en.wikipedia.org/wiki/Squirrel_(programming_language)"&gt;Squirrel&lt;/a&gt;
            &lt;a href="http://www.ps.uni-saarland.de/alice/"&gt;AliceML&lt;/a&gt;
            &lt;a href="http://en.wikipedia.org/wiki/Logo_(programming_language)"&gt;Logo&lt;/a&gt;
            &lt;a href="http://en.wikipedia.org/wiki/Perl_6"&gt;Perl6&lt;/a&gt;
            &lt;a href="http://en.wikipedia.org/wiki/Tcl"&gt;Tcl&lt;/a&gt;
            &lt;a href="http://en.wikipedia.org/wiki/Rebol"&gt;REBOL&lt;/a&gt;
            &lt;a href="http://yosefk.com/c++fqa/"&gt;C++&lt;/a&gt;
            &lt;a href="http://en.wikipedia.org/wiki/Eiffel_(programming_language)"&gt;Eiffel&lt;/a&gt;
            &lt;a href="http://en.wikipedia.org/wiki/Groovy_(programming_language)"&gt;Groovy&lt;/a&gt;
            &lt;a href="http://en.wikipedia.org/wiki/Io_(programming_language)"&gt;Io&lt;/a&gt;
            &lt;a href="http://en.wikipedia.org/wiki/Mercury_(programming_language)"&gt;Mercury&lt;/a&gt;
            &lt;a href="http://en.wikipedia.org/wiki/Visual_Basic_for_Applications"&gt;VBA&lt;/a&gt;
            &lt;a href="http://en.wikipedia.org/wiki/Nemerle"&gt;Nemerle&lt;/a&gt;
            &lt;a href="http://en.wikipedia.org/wiki/Prolog"&gt;Prolog&lt;/a&gt;
            &lt;a href="http://en.wikipedia.org/wiki/Php"&gt;PHP&lt;/a&gt;
            &lt;a href="http://en.wikipedia.org/wiki/Oz_(programming_language)"&gt;Oz&lt;/a&gt;
            &lt;a href="http://en.wikipedia.org/wiki/Lisp_(programming_language)"&gt;Lisp&lt;/a&gt;
            &lt;a href="http://en.wikipedia.org/wiki/J_(programming_language)"&gt;J&lt;/a&gt;
            &lt;a href="http://en.wikipedia.org/wiki/Boo_(programming_language)"&gt;Boo&lt;/a&gt;
            &lt;a href="http://en.wikipedia.org/wiki/Object_Pascal"&gt;Delphi&lt;/a&gt;
            &lt;a href="http://en.wikipedia.org/wiki/Pure_(programming_language)"&gt;Pure&lt;/a&gt;
            &lt;a href="http://en.wikipedia.org/wiki/Qi_(programming_language)"&gt;Qi&lt;/a&gt;
            &lt;a href="http://coq.inria.fr/a-short-introduction-to-coq"&gt;Coq&lt;/a&gt;
            &lt;a href="http://en.wikipedia.org/wiki/Ecmascript"&gt;ECMAScript&lt;/a&gt;
            &lt;a href="http://en.wikipedia.org/wiki/Icon_(programming_language)"&gt;Icon&lt;/a&gt;
            &lt;a href="http://en.wikipedia.org/wiki/Fortran"&gt;Fortran&lt;/a&gt;
            &lt;a href="http://en.wikipedia.org/wiki/Curl_(programming_language)"&gt;Curl&lt;/a&gt;
            &lt;a href="http://en.wikipedia.org/wiki/Clean_(programming_language)"&gt;Clean&lt;/a&gt;
            &lt;a href="http://en.wikipedia.org/wiki/Curry_(programming_language)"&gt;Curry&lt;/a&gt;
            &lt;a href="http://en.wikipedia.org/wiki/LaTeX"&gt;LaTeX&lt;/a&gt;
            &lt;a href="http://en.wikipedia.org/wiki/C_(programming_language)"&gt;C&lt;/a&gt;
            &lt;a href="http://en.wikipedia.org/wiki/Miranda_(programming_language)"&gt;Miranda&lt;/a&gt;
            &lt;a href="http://en.wikipedia.org/wiki/R_(programming_language)"&gt;R&lt;/a&gt;
            &lt;a href="http://en.wikipedia.org/wiki/Squeak"&gt;Squeak&lt;/a&gt;
            &lt;a href="http://en.wikipedia.org/wiki/Ocaml"&gt;OCaml&lt;/a&gt;
            &lt;a href="http://en.wikipedia.org/wiki/Javascript"&gt;JavaScript&lt;/a&gt;
        &lt;/div&gt;
&lt;/div&gt;
&lt;/center&gt;
&lt;br /&gt;
This is a classical &lt;a href="http://en.wikipedia.org/wiki/Concentration_(game)"&gt;Memory game&lt;/a&gt;:
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;At the beginning all the cards are shown for a couple of seconds. Try to remember their positions!&lt;/li&gt;
&lt;li&gt;Then click on two cards at time to flip them over.&lt;/li&gt;
&lt;li&gt;If a matching pair is revealed, then those cards disappear.&lt;/li&gt;
&lt;li&gt;But the cards flip back if they do not match, and this counts as a "miss".&lt;/li&gt;
&lt;li&gt;The goal is to find all the matching pairs with the least amount of misses.&lt;/li&gt;
&lt;/ul&gt;
As you may have noticed, the cards are corresponding to different programming languages, thus the name of the game: &lt;i&gt;Memylon&lt;/i&gt; (what cat does not love cheap puns?..)
&lt;br /&gt;
&lt;br /&gt;
The full source code to the game &lt;a href="https://github.com/silverio/memylon"&gt;can be found on github&lt;/a&gt;.  
&lt;br /&gt;
&lt;br /&gt;
The unsophisticated animal did not use any existing JavaScript libraries. He definitely should have, but sometimes &lt;a href="http://gdreflections.com/2010/01/boost-c-libraries-and-game-engines.html"&gt;reinventing a bicycle&lt;/a&gt; is so much fun (oh yeah, of course he did peek into the jQuery source a couple of times, to check what shape the wheels are there)!
&lt;br /&gt;
&lt;br /&gt;
And of course, please pardon the silly animal if it &lt;a href="http://en.wikipedia.org/wiki/Browser_wars"&gt;does not work in your browser&lt;/a&gt;. It seemed to in the latest Chrome, Opera, Firefox and Konqueror on Linux, as well as in Chrome, Opera, Firefox, Safari and IE9 on Windows (even though with Chrome on Linux the global alpha value on the canvas' context did not seem to affect text transparency... which might be a bug or again a result of illiteracy - go figure).
&lt;br /&gt;
&lt;br /&gt;
First thing he did is running &lt;a href="http://www.gimp.org/"&gt;GIMP&lt;/a&gt; and gathering a collection of programming language pics into an "atlas" image (it should be mentioned that all the language logos/trademarks belong to the corresponding authors/owners, and background image is a courtesy of &lt;a href="http://en.wikipedia.org/wiki/Lucas_van_Valckenborch"&gt;Renaissance&lt;/a&gt;):
&lt;br /&gt;
&lt;br /&gt;
&lt;center&gt;&lt;img border="0" src="http://4.bp.blogspot.com/-h6pG0uR0Q28/TbXBe4m54iI/AAAAAAAAAjE/UzpdQl--UNg/s1600/cards.png" width="400" /&gt;&lt;/center&gt;
&lt;br /&gt;
Of course, every programmer knows that one should start from the hardest things. &lt;i&gt;Not from the ones which are the most fun!!!&lt;/i&gt;
&lt;br /&gt;
&lt;br /&gt;
But come on, he's just a cat.
&lt;br /&gt;
&lt;br /&gt;
After that the illiterate creature opened a text editor and typed in a pile of JavaScript code:
&lt;br /&gt;
&lt;br /&gt;
&lt;div style="height: 520px; overflow: scroll; width: 100%;"&gt;
&lt;table cellpadding="0" cellspacing="0"&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="c1"&gt;//  the main entry point&lt;/span&gt; 
&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="nx"&gt;Memylon&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;init&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; 
&lt;span class="p"&gt;}&lt;/span&gt; 
 
&lt;span class="c1"&gt;//  the game module&lt;/span&gt; 
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;Memylon&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="c1"&gt;//  constants&lt;/span&gt; 
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;FRAME_TIME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;FLASH_TIME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;CARD_W&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;CARD_H&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;CARDS_IN_ROW&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;CARDS_NUM_VARIATIONS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;54&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;FLIP_TIME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;HIDE_TIME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;SHOW_TIME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
    &lt;span class="c1"&gt;//  variables&lt;/span&gt; 
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;cards&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="nx"&gt;anims&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt; 
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;numCardsW&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;numCardsH&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;prevIdx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;numMisses&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;canInteract&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;bgImage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cardsImage&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
 
    &lt;span class="c1"&gt;// the initialization function&lt;/span&gt; 
    &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;canvas&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Utils&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'gameArea'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;canvas&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getContext&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
            &lt;span class="nx"&gt;context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'2d'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
            &lt;span class="nx"&gt;Utils&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'restartGame'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;onclick&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
                &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Restart'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
                &lt;span class="nx"&gt;resetGame&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; 
            &lt;span class="p"&gt;};&lt;/span&gt; 
            &lt;span class="nx"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'mousedown'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
                    &lt;span class="nx"&gt;onMouseClick&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clientX&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;offsetLeft&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clientY&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;offsetTop&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
                &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
            &lt;span class="nx"&gt;setInterval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updateBoard&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;FRAME_TIME&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
        &lt;span class="p"&gt;}&lt;/span&gt; 
 
        &lt;span class="nx"&gt;bgImage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Utils&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"bg"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
        &lt;span class="nx"&gt;cardsImage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Utils&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"cards"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
    &lt;span class="p"&gt;}&lt;/span&gt; 
    &lt;span class="c1"&gt;//  draw a card sprite on canvas&lt;/span&gt; 
    &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;drawCard&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cardID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;scaleX&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;scaleY&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;glyphID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cardID&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;cardID&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;cx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;CARD_W&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;scaleX&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;cy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;CARD_H&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;scaleY&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;glyphX&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;glyphID&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="nx"&gt;CARDS_IN_ROW&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;CARD_W&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;glyphY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;glyphID&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;CARDS_IN_ROW&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;CARD_H&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
 
        &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;drawImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cardsImage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
            &lt;span class="nx"&gt;glyphX&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;glyphY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;CARD_W&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;CARD_H&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
            &lt;span class="nx"&gt;cx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;CARD_W&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;scaleX&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;CARD_H&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;scaleY&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;    
    &lt;span class="p"&gt;}&lt;/span&gt; 
    &lt;span class="c1"&gt;//  play a "flash cards" animation&lt;/span&gt; 
    &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;playFlashCards&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
        &lt;span class="nx"&gt;canInteract&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;cards&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
            &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;card&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cards&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; 
            &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;startDelay&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="nx"&gt;numCardsW&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
            &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;flashTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;FLASH_TIME&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;numCardsW&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
            &lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;anim&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createAnim&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; 
                &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'pose'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;startDelay&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; 
                &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'flip'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;FLIP_TIME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; 
                &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'pose'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;flashTime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; 
                &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'flip'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;FLIP_TIME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt; 
        &lt;span class="p"&gt;}&lt;/span&gt; 
        &lt;span class="nx"&gt;anims&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;createAnim&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;'exec'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;numCardsW&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;80&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;FLIP_TIME&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;flashTime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
            &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;canInteract&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}])];&lt;/span&gt; 
    &lt;span class="p"&gt;}&lt;/span&gt; 
    &lt;span class="c1"&gt;//  game-specific animation update functions&lt;/span&gt; 
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;AnimFunctions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
        &lt;span class="c1"&gt;//  "draw static card" animation&lt;/span&gt; 
        &lt;span class="nx"&gt;pose&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cardID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
            &lt;span class="nx"&gt;drawCard&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cardID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
        &lt;span class="p"&gt;},&lt;/span&gt; 
        &lt;span class="c1"&gt;//  "flip card" animation&lt;/span&gt; 
        &lt;span class="nx"&gt;flip&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cardID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
            &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;scale&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cos&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PI&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
            &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scale&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;cardID&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;cardID&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
            &lt;span class="nx"&gt;drawCard&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scale&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
        &lt;span class="p"&gt;},&lt;/span&gt; 
        &lt;span class="c1"&gt;//  "dissolve card" animation&lt;/span&gt; 
        &lt;span class="nx"&gt;hide&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cardID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
                &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;globalAlpha&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
                &lt;span class="nx"&gt;drawCard&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cardID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
                &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;globalAlpha&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
            &lt;span class="p"&gt;}&lt;/span&gt; 
        &lt;span class="p"&gt;},&lt;/span&gt; 
        &lt;span class="c1"&gt;//  flying text animation&lt;/span&gt; 
        &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
            &lt;span class="c1"&gt;//  append missing parameters with defaults&lt;/span&gt; 
            &lt;span class="nx"&gt;Utils&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setDefaults&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;sizeFrom&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;xFrom&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;182&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;yFrom&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;150&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;alphaFrom&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
                &lt;span class="nx"&gt;font&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'Arial'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;bold&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'#2222AA'&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt; 
            &lt;span class="nx"&gt;Utils&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setDefaults&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;sizeTo&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sizeFrom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;alphaTo&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;alphaFrom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
                &lt;span class="nx"&gt;xTo&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;xFrom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;yTo&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;yFrom&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt; 
            &lt;span class="c1"&gt;//  interpolate current text parameters&lt;/span&gt; 
            &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Utils&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lerp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sizeFrom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sizeTo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
            &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Utils&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lerp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;xFrom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;xTo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
            &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Utils&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lerp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;yFrom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;yTo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
            &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;alpha&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Utils&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lerp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;alphaFrom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;alphaTo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
 
            &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;font&lt;/span&gt;         &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bold&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="s1"&gt;'bold '&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;size&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s1"&gt;'px '&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;font&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
            &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fillStyle&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
            &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textBaseline&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'middle'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
            &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textAlign&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'center'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
            &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;globalAlpha&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;alpha&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
            &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fillText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
            &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;globalAlpha&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
        &lt;span class="p"&gt;},&lt;/span&gt; 
        &lt;span class="c1"&gt;//  executes a function at the end of animation period&lt;/span&gt; 
        &lt;span class="nx"&gt;exec&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
                &lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; 
            &lt;span class="p"&gt;}&lt;/span&gt; 
        &lt;span class="p"&gt;},&lt;/span&gt; 
        &lt;span class="c1"&gt;//  empty "spin doing nothing" animation&lt;/span&gt; 
        &lt;span class="nx"&gt;wait&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
        &lt;span class="p"&gt;}&lt;/span&gt; 
    &lt;span class="p"&gt;};&lt;/span&gt; 
    &lt;span class="c1"&gt;//  create an animation sequence&lt;/span&gt; 
    &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;createAnim&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;animType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;param&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;anim&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;AnimSequence&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; 
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;nArg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;nArg&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
            &lt;span class="nx"&gt;arg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; 
            &lt;span class="nx"&gt;animType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; 
            &lt;span class="nx"&gt;duration&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; 
            &lt;span class="nx"&gt;param&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; 
            &lt;span class="nx"&gt;anim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;AnimFunctions&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;animType&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nx"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;param&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;    
        &lt;span class="p"&gt;}&lt;/span&gt; 
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;anim&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
    &lt;span class="p"&gt;}&lt;/span&gt; 
    &lt;span class="c1"&gt;//  play the "game is won" scene&lt;/span&gt; 
    &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;playFinalScene&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cardID&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;xCenter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;190&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
        &lt;span class="nx"&gt;anims&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; 
            &lt;span class="nx"&gt;createAnim&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;'wait'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'text'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
                &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'This is it.'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
                &lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'#5F5B60'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;alphaTo&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
                &lt;span class="nx"&gt;yFrom&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;xFrom&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;xTo&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;xCenter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
                &lt;span class="nx"&gt;sizeFrom&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt; 
            &lt;span class="p"&gt;}]),&lt;/span&gt; 
            &lt;span class="nx"&gt;createAnim&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;'wait'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'text'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;700&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
                &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'the language wars'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
                &lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'#735551'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
                &lt;span class="nx"&gt;yFrom&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;75&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;xFrom&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;xTo&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;xCenter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
                &lt;span class="nx"&gt;sizeFrom&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt; 
            &lt;span class="p"&gt;}]),&lt;/span&gt; 
            &lt;span class="nx"&gt;createAnim&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;'wait'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2700&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'text'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
                &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'ARE OVER.'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
                &lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'#81878C'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
                &lt;span class="nx"&gt;xFrom&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;xCenter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;yTo&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;120&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
                &lt;span class="nx"&gt;sizeFrom&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;sizeTo&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;40&lt;/span&gt; 
            &lt;span class="p"&gt;}]),&lt;/span&gt; 
            &lt;span class="nx"&gt;createAnim&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;'wait'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'text'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
                &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'and the winner is...'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
                &lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'#B2A89B'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
                &lt;span class="nx"&gt;xFrom&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;xTo&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;xCenter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;yFrom&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;160&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
                &lt;span class="nx"&gt;sizeFrom&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt; 
            &lt;span class="p"&gt;}]),&lt;/span&gt; 
            &lt;span class="nx"&gt;createAnim&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;'wait'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6500&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'text'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
                &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;getCardInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cardID&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
                &lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'#D91122'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
                &lt;span class="nx"&gt;xFrom&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;xTo&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;xCenter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;yFrom&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;210&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
                &lt;span class="nx"&gt;sizeFrom&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;sizeTo&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;55&lt;/span&gt; 
            &lt;span class="p"&gt;}]),&lt;/span&gt; 
            &lt;span class="nx"&gt;createAnim&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;'exec'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
                &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;winnerURL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Utils&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'winnerURL'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
                &lt;span class="nx"&gt;winnerURL&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;visibility&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'visible'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
                &lt;span class="nx"&gt;winnerURL&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;href&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;getCardInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cardID&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
            &lt;span class="p"&gt;}])&lt;/span&gt; 
        &lt;span class="p"&gt;];&lt;/span&gt; 
    &lt;span class="p"&gt;}&lt;/span&gt; 
    &lt;span class="c1"&gt;//  process the "card clicked" event&lt;/span&gt; 
    &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;clickCard&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cardIdx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;card&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cards&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;cardIdx&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; 
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prevIdx&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
            &lt;span class="c1"&gt;//  no cards are flipped yet&lt;/span&gt; 
            &lt;span class="nx"&gt;prevIdx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cardIdx&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
            &lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;anim&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createAnim&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;'flip'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;FLIP_TIME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt; 
            &lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
            &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;prevCard&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cards&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;prevIdx&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; 
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prevCard&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
                &lt;span class="c1"&gt;//  animation for the already flipped card: wait and dissolve&lt;/span&gt; 
                &lt;span class="nx"&gt;prevCard&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;anim&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 
                    &lt;span class="nx"&gt;createAnim&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;'pose'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;FLIP_TIME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;prevCard&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; 
                               &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'hide'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;HIDE_TIME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;prevCard&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt; 
                &lt;span class="c1"&gt;//  animation for the current card: flip and dissolve&lt;/span&gt; 
                &lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;anim&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 
                    &lt;span class="nx"&gt;createAnim&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;'flip'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;FLIP_TIME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; 
                               &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'hide'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;HIDE_TIME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt; 
                &lt;span class="c1"&gt;//  animation of the flying card caption&lt;/span&gt; 
                &lt;span class="nx"&gt;anims&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;createAnim&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;'text'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
                    &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;getCardInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
                    &lt;span class="nx"&gt;alphaFrom&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;alphaTo&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.01&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
                    &lt;span class="nx"&gt;sizeFrom&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;sizeTo&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'wait'&lt;/span&gt;&lt;span class="p"&gt;])];&lt;/span&gt; 
                &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;cardID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
                &lt;span class="nx"&gt;prevCard&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Utils&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;every&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cards&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="p"&gt;}))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
                    &lt;span class="c1"&gt;//  all matches are found, show the final scene animation&lt;/span&gt; 
                    &lt;span class="nx"&gt;playFinalScene&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cardID&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
                &lt;span class="p"&gt;}&lt;/span&gt; 
            &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
                &lt;span class="c1"&gt;//  animation for the already flipped card: wait and flip back &lt;/span&gt; 
                &lt;span class="nx"&gt;prevCard&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;anim&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 
                    &lt;span class="nx"&gt;createAnim&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;'pose'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;FLIP_TIME&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;SHOW_TIME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;prevCard&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; 
                               &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'flip'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;FLIP_TIME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="nx"&gt;prevCard&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; 
                               &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'pose'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;prevCard&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;                    
                &lt;span class="c1"&gt;//  animation for the current card: flip, wait, flip back &lt;/span&gt; 
                &lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;anim&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 
                    &lt;span class="nx"&gt;createAnim&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;'flip'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;FLIP_TIME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; 
                               &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'pose'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;SHOW_TIME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; 
                               &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'flip'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;FLIP_TIME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; 
                               &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'pose'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt; 
                &lt;span class="nx"&gt;prevCard&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;prevCard&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
                &lt;span class="nx"&gt;setNumMisses&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;numMisses&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
                &lt;span class="p"&gt;}&lt;/span&gt; 
            &lt;span class="nx"&gt;prevIdx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
        &lt;span class="p"&gt;}&lt;/span&gt; 
    &lt;span class="p"&gt;}&lt;/span&gt; 
    &lt;span class="c1"&gt;//  reset the game board into the initial state&lt;/span&gt; 
    &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;resetGame&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;ids&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;idx1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;idx2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
 
        &lt;span class="c1"&gt;//  generate a random subset of card variations&lt;/span&gt; 
        &lt;span class="nx"&gt;ids&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt; 
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;CARDS_NUM_VARIATIONS&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;ids&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
        &lt;span class="nx"&gt;Utils&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;shuffleArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ids&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
        &lt;span class="nx"&gt;cards&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt; 
 
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;numCardsW&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;numCardsH&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
            &lt;span class="nx"&gt;cards&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
                &lt;span class="nx"&gt;id&lt;/span&gt;   &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;ids&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)],&lt;/span&gt; 
                &lt;span class="nx"&gt;anim&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;createAnim&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;'pose'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; 
            &lt;span class="p"&gt;}&lt;/span&gt; 
        &lt;span class="p"&gt;}&lt;/span&gt; 
        &lt;span class="nx"&gt;Utils&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;shuffleArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cards&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
 
        &lt;span class="c1"&gt;//  cache the card positions&lt;/span&gt; 
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;cards&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
            &lt;span class="nx"&gt;cards&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="nx"&gt;numCardsW&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;CARD_W&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
            &lt;span class="nx"&gt;cards&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;numCardsW&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;CARD_H&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
        &lt;span class="p"&gt;}&lt;/span&gt; 
 
        &lt;span class="nx"&gt;setNumMisses&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
        &lt;span class="nx"&gt;anims&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt; 
        &lt;span class="nx"&gt;prevIdx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
 
        &lt;span class="nx"&gt;playFlashCards&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; 
        &lt;span class="nx"&gt;Utils&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'winnerURL'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;visibility&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'hidden'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
    &lt;span class="p"&gt;}&lt;/span&gt; 
    &lt;span class="c1"&gt;//  update/draw the game board&lt;/span&gt; 
    &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;updateBoard&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
        &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;drawImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bgImage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;cards&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
            &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;card&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cards&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; 
            &lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;anim&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;anim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;FRAME_TIME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
        &lt;span class="p"&gt;}&lt;/span&gt;    
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;anims&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
            &lt;span class="nx"&gt;anims&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;anims&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;FRAME_TIME&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
        &lt;span class="p"&gt;}&lt;/span&gt;      
    &lt;span class="p"&gt;}&lt;/span&gt; 
    &lt;span class="c1"&gt;//  update the miss counter&lt;/span&gt; 
    &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;setNumMisses&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
        &lt;span class="nx"&gt;numMisses&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
        &lt;span class="nx"&gt;Utils&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'attemptsCounter'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;numMisses&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
    &lt;span class="p"&gt;}&lt;/span&gt; 
    &lt;span class="c1"&gt;//  mouse click handler&lt;/span&gt; 
    &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;onMouseClick&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;cardIdx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;CARD_W&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;numCardsW&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;CARD_H&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;card&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cards&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;cardIdx&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; 
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;canInteract&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;card&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cardIdx&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;prevIdx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
            &lt;span class="nx"&gt;clickCard&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cardIdx&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
        &lt;span class="p"&gt;}&lt;/span&gt; 
    &lt;span class="p"&gt;}&lt;/span&gt; 
    &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;getCardInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cardID&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;cardIdx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cardID&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Utils&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'links'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;cardIdx&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; 
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;href&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt; 
    &lt;span class="p"&gt;}&lt;/span&gt; 
 
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
        &lt;span class="nx"&gt;init&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;init&lt;/span&gt; 
    &lt;span class="p"&gt;}&lt;/span&gt; 
&lt;span class="p"&gt;}();&lt;/span&gt; 
 
&lt;span class="c1"&gt;//  helper utility functions&lt;/span&gt; 
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;Utils&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="c1"&gt;//  randomly shuffles the array using Fisher-Yates algorithm&lt;/span&gt; 
    &lt;span class="nx"&gt;shuffleArray&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
            &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;k&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
            &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;val&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; 
            &lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; 
            &lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
        &lt;span class="p"&gt;}&lt;/span&gt; 
    &lt;span class="p"&gt;},&lt;/span&gt; 
    &lt;span class="c1"&gt;//  returns true if all elements of the array satisfy the given predicate&lt;/span&gt; 
    &lt;span class="nx"&gt;every&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;predicate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;predicate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
        &lt;span class="p"&gt;}&lt;/span&gt; 
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
    &lt;span class="p"&gt;},&lt;/span&gt; 
    &lt;span class="c1"&gt;//  linear interpolation between a and b with factor t&lt;/span&gt; 
    &lt;span class="nx"&gt;lerp&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
    &lt;span class="p"&gt;},&lt;/span&gt; 
    &lt;span class="c1"&gt;//  append parameters in "params" with default values from "defaults"&lt;/span&gt; 
    &lt;span class="nx"&gt;setDefaults&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;defaults&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;defaults&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
                &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;defaults&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; 
            &lt;span class="p"&gt;}&lt;/span&gt; 
        &lt;span class="p"&gt;}&lt;/span&gt; 
    &lt;span class="p"&gt;},&lt;/span&gt; 
    &lt;span class="c1"&gt;//  poor man's jQuery&lt;/span&gt; 
    &lt;span class="nx"&gt;$&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
    &lt;span class="p"&gt;}&lt;/span&gt; 
&lt;span class="p"&gt;}&lt;/span&gt; 
 
&lt;span class="c1"&gt;// a simple class representing a list of animations played in sequence&lt;/span&gt; 
&lt;span class="nx"&gt;AnimSequence&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;anims&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt; 
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;curAnim&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;curTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
&lt;span class="p"&gt;};&lt;/span&gt; 
&lt;span class="nx"&gt;AnimSequence&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prototype&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;add&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updateFn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;startParam&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;anims&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;updateFn&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;updateFn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;duration&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;startParam&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;startParam&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt; 
&lt;span class="p"&gt;};&lt;/span&gt; 
&lt;span class="nx"&gt;AnimSequence&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prototype&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;update&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;updateParam&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;anim&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;anims&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;curAnim&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; 
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;curTime&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;dt&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;anim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;duration&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;curTime&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="nx"&gt;anim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
        &lt;span class="nx"&gt;anim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;updateFn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;anim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;startParam&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;updateParam&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;curAnim&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;anims&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
            &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;curTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
            &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;curAnim&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
        &lt;span class="p"&gt;}&lt;/span&gt; 
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
        &lt;span class="nx"&gt;anim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;updateFn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;anim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;duration&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;curTime&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;anim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
            &lt;span class="nx"&gt;anim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;startParam&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;updateParam&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
    &lt;span class="p"&gt;}&lt;/span&gt; 
&lt;span class="p"&gt;};&lt;/span&gt; 
&lt;/pre&gt;
&lt;/div&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
That's what happens when you give a keyboard to a cat.
&lt;br /&gt;
&lt;br /&gt;
Of course, the cat ran the program through &lt;a href="http://www.jslint.com/"&gt;JSLint&lt;/a&gt;, and it hurt his feelings.

&lt;br /&gt;
&lt;br /&gt;
And that was it.
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;center&gt;&lt;img border="0" src="http://4.bp.blogspot.com/-WIBdS84pBLU/TbXCYPNYywI/AAAAAAAAAjU/MTuC3QgFMYg/s400/coda.png" width="250" /&gt;&lt;/center&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/923082020090979517-2832331933412373020?l=blog.ruslans.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/gd_reflections/~4/7A4iLLtU7k0" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.ruslans.com/feeds/2832331933412373020/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=923082020090979517&amp;postID=2832331933412373020" title="4 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/923082020090979517/posts/default/2832331933412373020" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/923082020090979517/posts/default/2832331933412373020" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/gd_reflections/~3/7A4iLLtU7k0/memylon-language-wars-are-over.html" title="Memylon: the language wars are over!" /><author><name>ruslans</name><uri>http://www.blogger.com/profile/03375859473751956887</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="24" height="32" src="http://2.bp.blogspot.com/_DVYH9neSnMw/S0V_XM6aN0I/AAAAAAAAAMc/06dTTnY0PNw/S220/avatar3.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-oXd9AAYMHSk/TbXBpCRDCoI/AAAAAAAAAjM/4qRIbPW8adA/s72-c/cat.png" height="72" width="72" /><thr:total>4</thr:total><feedburner:origLink>http://blog.ruslans.com/2011/04/memylon-language-wars-are-over.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-923082020090979517.post-759664221349161544</id><published>2011-04-15T10:18:00.000-07:00</published><updated>2011-04-18T03:18:00.460-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="javascript" /><category scheme="http://www.blogger.com/atom/ns#" term="learning" /><category scheme="http://www.blogger.com/atom/ns#" term="edutainment" /><category scheme="http://www.blogger.com/atom/ns#" term="math" /><title type="text">Loot drop and other epic problems of probability theory</title><content type="html">&lt;script type="text/javascript"&gt;
var Probability = {
sum: function (i0, iN, fn) {
    var res = 0;
    for (var i = i0; i &lt;= iN; i++) {
        res += fn(i);
    }
    return res;
},
product: function (i0, iN, fn) {
    var res = 1;
    for (var i = i0; i &lt;= iN; i++) {
        res *= fn(i);
    }
    return res;
},
binomialCoefficient : function (k, n) {
    return Probability.product(1, k, function(i) { 
        return (n - (k - i))/i; 
    });
},
binomialDistribution : function (k, n, p) {
    return Probability.binomialCoefficient(k, n)*
        Math.pow(p, k)*Math.pow(1 - p, n - k);
},
CDF: function (x, pFn) {
    return Probability.sum(0, x, pFn);
},
binomialCDF : function (x, n, p) {
    return Probability.CDF(x, function(i) { 
        return Probability.binomialDistribution(i, n, p); 
    });
}

}
&lt;/script&gt; 
&lt;img border="0" src="http://3.bp.blogspot.com/-akElCaxZdgo/Tah8IxlVR3I/AAAAAAAAAhE/L4mL5uB0gLA/s400/binomial_logo.png" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;" /&gt;

One day my old friend called me and asked if I could give a hand in solving some school math problems (he was trying to tutor his nephew). 
&lt;br /&gt;
&lt;br /&gt;
Among the problems was:
&lt;br /&gt;
&lt;blockquote&gt;
The factory produces some parts. Given that from every 60 parts 12 are defective, find the probability that from 10 parts at least two are defective.
&lt;/blockquote&gt;
Frankly, the solution did not occur immediately at all - it's been a while since the student years.
&lt;br /&gt;
&lt;br /&gt;
What did occur to me immediately, though, is that something is wrong with the way people are usually taught those things at school. There are often troubles remembering them afterwards. Why?..
&lt;br /&gt;
&lt;br /&gt;
Apparently, one of the reasons is that &lt;i&gt;the problems which students are asked to solve are usually plain boring.&lt;/i&gt;
&lt;br /&gt;
&lt;br /&gt;
Why would I care about those "defective parts", indeed?...
&lt;br /&gt;
&lt;br /&gt;
Now, the funny part is that it has nothing to do with the mathematical apparatus at hand (which is &lt;i&gt;the&lt;/i&gt; thing we are supposed to learn): being abstract as it is, it can be applied to many practical problems. And some of them might appear more interesting than others, depending on the context.
&lt;br /&gt;
&lt;br /&gt;
For example, what about:
&lt;br /&gt;
&lt;blockquote&gt;
Two friends are playing World of Warcraft. They agreed to group for farming a boss, who drops a certain epic loot with a chance of 20%. What are the odds that after killing it 10 times both friends would get the desired epic gear?
&lt;/blockquote&gt;
See what I have done here?.. It is exactly the same problem. Except now it's better flavoured, and furthermore, it's actually a &lt;a href="http://wow.joystiq.com/2010/01/13/drop-chance-probability/"&gt;problem of practical interest&lt;/a&gt; to people playing WoW.
&lt;br /&gt;
&lt;br /&gt;
And something makes me feel that there are more young people playing WoW these days than those making defective parts at factories!
&lt;br /&gt;
&lt;br /&gt;
So, here's the (interactive) answer to the problem. Try entering different numbers and pressing the "Recompute" button (keep in mind that the code here does not attempt to be too robust with the boundary cases... also, values might be rounded, so 99.999999% will be shown as 100%, which is not correct):
&lt;br /&gt;
&lt;br /&gt;
&lt;blockquote style="border: 2px solid #cccccc; margin: 5px; padding: 5px;"&gt;
With the loot drop chance of  &lt;input id="lootDropChance" style="width: 20px;" type="text" value="20" /&gt;%, the odds of getting at least &lt;input id="desiredLootDrops" style="width: 20px;" type="text" value="2" /&gt; drop(s) after &lt;input id="attempts" style="width: 30px;" type="text" value="10" /&gt; attempts are &lt;span id="odds" style="font-weight: bold;"&gt;0.012&lt;/span&gt;%.    &lt;input id="recompute" onclick="recomputeLootDropChance();" type="button" value="Recompute" /&gt;
&lt;script type="text/javascript"&gt;
 
function computeDesiredLootDropsChance(attempts, desiredLootDrops, lootDropChance) {
    return 1 - Probability.binomialCDF(desiredLootDrops - 1, attempts, lootDropChance); 
}

function recomputeLootDropChance() { 
    var lootDropChance = document.getElementById("lootDropChance").value/100;
    var desiredLootDrops = document.getElementById("desiredLootDrops").value;
    var attempts = document.getElementById("attempts").value;
    var odds = computeDesiredLootDropsChance(attempts, desiredLootDrops, lootDropChance);
    document.getElementById("odds").innerHTML = (odds*100).toFixed(4); 
} 
recomputeLootDropChance();
&lt;/script&gt;
&lt;/blockquote&gt;
&lt;br /&gt;
It is computed by substituting values into a somewhat intimidating formula:
&lt;br /&gt;
&lt;br /&gt;
&lt;center&gt;&lt;img border="0" src="http://3.bp.blogspot.com/-gObZBvPjn8s/Tah8M9j5M_I/AAAAAAAAAhM/Vmgxh6FmGo8/s400/bin0.png" /&gt;&lt;/center&gt;

Here &lt;b&gt;n&lt;/b&gt; is the total amount of boss kills, &lt;b&gt;p&lt;/b&gt; is the loot drop chance and &lt;b&gt;x&lt;/b&gt; is the minimal desired amount of drops we can get.

&lt;br /&gt;
&lt;br /&gt;
The mentioned &lt;a href="http://wow.joystiq.com/2010/01/13/drop-chance-probability/"&gt;article&lt;/a&gt; uses particular case of this formula, when &lt;b&gt;x&lt;/b&gt; is 1 (i.e. when we want to know the chance that the item drops at least once): 
&lt;br /&gt;
&lt;br /&gt;
&lt;center&gt;&lt;img border="0" src="http://4.bp.blogspot.com/-9QyIhPfWLS0/Tah8PiXTTUI/AAAAAAAAAhU/iAfqaRVm4jM/s400/bin1.png" /&gt;&lt;/center&gt;

Alright, but this is an &lt;i&gt;answer&lt;/i&gt;, not a &lt;i&gt;solution&lt;/i&gt;!
&lt;br /&gt;
&lt;br /&gt;
However, chances are that it is &lt;i&gt;almost&lt;/i&gt; the implied solution to the original problem about the defective parts: the student is supposed to identify the &lt;a href="http://en.wikipedia.org/wiki/Bernoulli_process"&gt;Bernoulli process&lt;/a&gt; (AKA "repeated coin flipping"), remember that the number of successes in a given amount of trials has a &lt;a href="http://en.wikipedia.org/wiki/Binomial_distribution"&gt;binomial distribution&lt;/a&gt;, and use &lt;a href="http://en.wikipedia.org/wiki/Cumulative_distribution_function"&gt;cumulative distribution function&lt;/a&gt; formula for that.
&lt;br /&gt;
&lt;br /&gt;
But this brings another problem with education: &lt;i&gt;we are tought more about "what's" (facts and answers), than of "why's" (motivation and solutions)&lt;/i&gt;.
Resorting to just memoizing the formulas is not too reliable from the point of view of problem solving abilities.
&lt;br /&gt;
&lt;br /&gt;
So, let's try to unlearn all that again and start from the beginning.
&lt;br /&gt;
&lt;h4&gt;

Step 1&lt;/h4&gt;
First, let's treat all our probabilities as being in the range [0, 1], not in percents (converting back and forward is just about multiplication/division by 100%).
&lt;br /&gt;
&lt;br /&gt;
One fundamental formula to consider is:
&lt;br /&gt;
&lt;br /&gt;
&lt;center&gt;&lt;img border="0" src="http://3.bp.blogspot.com/-_tUgnK1mTSA/Tah8RikipUI/AAAAAAAAAhc/dZFhYmRnWv0/s400/bin2.png" /&gt;&lt;/center&gt;
Here P(A) means "probability that event A happens", and P(not A) means "probability that event A does not happen".
&lt;br /&gt;
&lt;blockquote&gt;
The chance of loot drop is 0.2 (which corresponds to 20%). What is the chance that there will be &lt;b&gt;no&lt;/b&gt; loot drop?
&lt;/blockquote&gt;
The answer is 0.8 (1 - 0.2, using the formula).
&lt;br /&gt;
&lt;h4&gt;

Step 2&lt;/h4&gt;
The chance that two independent events A and B would happen &lt;i&gt;both&lt;/i&gt; is: 
&lt;br /&gt;
&lt;center&gt;&lt;img border="0" src="http://3.bp.blogspot.com/-iGHlVasUqh0/Tah85YAbSWI/AAAAAAAAAh0/IKcIiZG7vwA/s400/bin4.png" /&gt;&lt;/center&gt;
&lt;br /&gt;
&lt;blockquote&gt;
The boss can drop the epic sword with 0.1 chance. What is the chance to kill the boss two times, and both times to get the sword?
&lt;/blockquote&gt;
The answer is 0.01 (0.1*0.1). We want &lt;i&gt;both&lt;/i&gt; of the idependent events (sword drops) happen. 
&lt;br /&gt;
&lt;h4&gt;

Step 3&lt;/h4&gt;
One more basic formula from probability theory: if events A and B are mutually exclusive (either of them can happen, but not both together), then: 
&lt;br /&gt;
&lt;br /&gt;
&lt;center&gt;&lt;img border="0" src="http://1.bp.blogspot.com/-vokiQ148Z3Y/Tah83b0ZicI/AAAAAAAAAhs/dPYvD9CwZaU/s400/bin3.png" /&gt;&lt;/center&gt;
&lt;blockquote&gt;
The boss can drop one of two items: an epic sword (0.1 chance) or an epic shield (0.2 chance). What is the chance to get either of them?
&lt;/blockquote&gt;
The answer, according to the formula, is 0.3 (0.1 + 0.2). The two possible loot drop scenarios are mutually exclusive.
&lt;br/&gt;&lt;br/&gt;
This is a special case of the so-called &lt;a href="http://en.wikipedia.org/wiki/Probability_axioms#More_consequences"&gt;addition law of probability&lt;/a&gt;.
&lt;h4&gt;

Step 4&lt;/h4&gt;
Back to the serial boss kills.
&lt;br /&gt;
&lt;blockquote&gt;
The boss can drop an epic sword with 0.2 chance. What is the chance for the two friends to kill the boss 10 times, and get the sword &lt;i&gt;exactly&lt;/i&gt; twice, and do that during &lt;i&gt;the last two kills&lt;/i&gt;?
&lt;/blockquote&gt;
Here's how this scenario does look like:
&lt;br /&gt;
&lt;br /&gt;
&lt;center&gt;&lt;img border="0" src="http://2.bp.blogspot.com/-ah-52FDSRts/Tah9G_IIDXI/AAAAAAAAAic/UNpz6Nch2mw/s400/loot1.png" /&gt;&lt;/center&gt;
Using the knowledge from steps 1 and 2, we find that the answer is (0.8)*(0.8)*(0.8)*(0.8)*(0.8)*(0.8)*(0.8)*(0.8)*(0.2)*(0.2), or in general form:
&lt;center&gt;&lt;img border="0" src="http://3.bp.blogspot.com/-RNvsgNYAXTQ/Tah8-1eJv7I/AAAAAAAAAiE/xdT9MJySDm0/s400/bin6.png" /&gt;&lt;/center&gt;
We've got &lt;b&gt;n&lt;/b&gt; events here, they are all independent, and should &lt;i&gt;all&lt;/i&gt; happen together (thus we have a product of probabilities).
&lt;br /&gt;
&lt;h4&gt;

Step 4&lt;/h4&gt;
&lt;blockquote&gt;
The boss can drop an epic sword with 0.2 chance. What is the chance for the two friends to kill the boss 10 times, and get the sword &lt;i&gt;exactly&lt;/i&gt; twice?
&lt;/blockquote&gt;
Notice that now we actually don't care if that loot necessarily drops exactly during the last two kills. As long as it manages to drop exactly twice during the total 10 kills - we're good.
Which means there are more possible scenarios which satisfy our needs:
&lt;br /&gt;
&lt;br /&gt;
&lt;center&gt;&lt;img border="0" src="http://4.bp.blogspot.com/-OAojjFHFfMs/Tah9JOgtRaI/AAAAAAAAAik/0OyrcREjjmo/s400/loot2.png" /&gt;&lt;/center&gt;
The total amount of such scenarios is C(n, k), which is called &lt;i&gt;binomial coefficient&lt;/i&gt; (the number of distinct k-element subsets of n-sized set):
&lt;center&gt;&lt;img border="0" src="http://2.bp.blogspot.com/-_q_TRAGLRMI/Tah88rT5Q4I/AAAAAAAAAh8/QfctSyBm4oM/s400/bin5.png" /&gt;&lt;/center&gt;
We won't go into details of this particular formula this time, but &lt;a href="http://liesandstats.wordpress.com/2008/06/18/binomial-coefficient-explained-simply/"&gt;here's a really nice and intuitive explanation&lt;/a&gt;.
&lt;br /&gt;
&lt;br /&gt;
Remembering the step 3, and the fact that all of the scenarios are mutually exclusive (if one scenario happens, another one can not happen anymore), and we want &lt;i&gt;any&lt;/i&gt; of them happen (Scenario1 or Scenario2 or ...), the answer is:
&lt;br /&gt;
&lt;br /&gt;
&lt;center&gt;&lt;img border="0" src="http://4.bp.blogspot.com/-gu1-Fkvl1vE/Tah9BNQNEbI/AAAAAAAAAiM/jm-1wXGvBqY/s400/bin7.png" /&gt;&lt;/center&gt;
This is so-called &lt;i&gt;probability mass function&lt;/i&gt; of &lt;a href="http://en.wikipedia.org/wiki/Binomial_distribution"&gt;binomial distribution&lt;/a&gt;.
&lt;br /&gt;
&lt;h4&gt;

Step 5&lt;/h4&gt;
In the original problem, we don't want the loot drop happen &lt;i&gt;exactly&lt;/i&gt; twice. It's rather &lt;i&gt;at least&lt;/i&gt; twice (indeed, I bet nobody would mind if the loot actually drops 2, 3 or even all 10 times, which is also theoretically possible).
&lt;br /&gt;
&lt;br /&gt;
But first let's look at a slightly modified problem:
&lt;br /&gt;
&lt;blockquote&gt;
Two friends are playing World of Warcraft. They agreed to group for farming a boss, who drops a certain epic loot with a chance of 0.2. What are the odds that after killing it 10 times the gear will drop less than 4 times?
&lt;/blockquote&gt;
"Less than 4 times" means: "exactly 3 times &lt;b&gt;or&lt;/b&gt; exactly 2 times &lt;b&gt;or&lt;/b&gt; exactly once &lt;b&gt;or&lt;/b&gt; not at all".
&lt;br /&gt;
&lt;br /&gt;
So it's essentially a sum of formulas from the step 4:
&lt;br /&gt;
&lt;br /&gt;
&lt;center&gt;&lt;img border="0" src="http://2.bp.blogspot.com/-pbAIMvoGR1Y/Tah9DOZziQI/AAAAAAAAAiU/_DkEMbR3mAk/s400/bin8.png" /&gt;&lt;/center&gt;
There is a name for this one, it's called &lt;a href="http://en.wikipedia.org/wiki/Cumulative_distribution_function"&gt;cumulative distribution function&lt;/a&gt;.
&lt;br /&gt;
&lt;br /&gt;
We are interested in the loot dropping "at least 2 times", not "less than 2 times", so simply take that formula and apply the step 1, giving us the final result:
&lt;br /&gt;
&lt;br /&gt;
&lt;center&gt;&lt;img border="0" src="http://3.bp.blogspot.com/-gObZBvPjn8s/Tah8M9j5M_I/AAAAAAAAAhM/Vmgxh6FmGo8/s400/bin0.png" /&gt;&lt;/center&gt;
Now this formula looks much less intimidating, and actually makes sense!
&lt;br /&gt;
&lt;br /&gt;
Isn't it amazing?..
&lt;br /&gt;
&lt;br /&gt;
&lt;h4&gt;

The code&lt;/h4&gt;
JavaScript function which computes the answer:
&lt;br /&gt;
&lt;div style="overflow: auto; width: 100%;"&gt;
&lt;table cellpadding="0" cellspacing="0" style="width: 420px;"&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;pre style="background-color: white; color: #181615; font-size: 8pt; line-height: 13px;"&gt;&lt;i&gt;&lt;span style="color: #898887;"&gt;/**&lt;/span&gt;&lt;/i&gt;
&lt;i&gt;&lt;span style="color: #898887;"&gt;  * Computes the chance that in given amount of attempts the loot would &lt;/span&gt;&lt;/i&gt;
&lt;i&gt;&lt;span style="color: #898887;"&gt;  *  drop at least desiredDrops times&lt;/span&gt;&lt;/i&gt;
&lt;i&gt;&lt;span style="color: #898887;"&gt;  * @param {integer} attempts Total attempts at getting the loot dropped&lt;/span&gt;&lt;/i&gt;
&lt;i&gt;&lt;span style="color: #898887;"&gt;  * @param {integer} desiredDrops The desired least amount of the actual loot drops&lt;/span&gt;&lt;/i&gt;
&lt;i&gt;&lt;span style="color: #898887;"&gt;  * @param {number} dropChance Probability of the loot to drop&lt;/span&gt;&lt;/i&gt;
&lt;i&gt;&lt;span style="color: #898887;"&gt;  */&lt;/span&gt;&lt;/i&gt;
&lt;b&gt;function&lt;/b&gt; computeDesiredDropsChance(attempts, desiredDrops, dropChance) {
    &lt;b&gt;return&lt;/b&gt; &lt;span style="color: #b08000;"&gt;1&lt;/span&gt; - &lt;span style="color: green;"&gt;Probability&lt;/span&gt;.&lt;span style="color: #644a9b;"&gt;binomialCDF&lt;/span&gt;(desiredDrops - &lt;span style="color: #b08000;"&gt;1&lt;/span&gt;, attempts, dropChance); 
}
&lt;/pre&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;br /&gt;
The probability helper functions:
&lt;br /&gt;
&lt;div style="height: 520px; overflow: auto; width: 100%;"&gt;
&lt;table cellpadding="0" cellspacing="0" style="width: 420px;"&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;pre style="background-color: white; color: #181615; font-size: 8pt; line-height: 13px;"&gt;&lt;b&gt;var&lt;/b&gt; Probability = {

&lt;i&gt;&lt;span style="color: #898887;"&gt;/**&lt;/span&gt;&lt;/i&gt;
&lt;i&gt;&lt;span style="color: #898887;"&gt;  * Computes the sum of function values over given integer range&lt;/span&gt;&lt;/i&gt;
&lt;i&gt;&lt;span style="color: #898887;"&gt;  * @param {integer} i0 First index value&lt;/span&gt;&lt;/i&gt;
&lt;i&gt;&lt;span style="color: #898887;"&gt;  * @param {integer} iN Last index value&lt;/span&gt;&lt;/i&gt;
&lt;i&gt;&lt;span style="color: #898887;"&gt;  * @param {function(integer)} fn Function with values to sum up&lt;/span&gt;&lt;/i&gt;
&lt;i&gt;&lt;span style="color: #898887;"&gt;  * @return {number} fn(i0) + fn(i0 + 1) + ... + fn(iN)&lt;/span&gt;&lt;/i&gt;
&lt;i&gt;&lt;span style="color: #898887;"&gt;  */&lt;/span&gt;&lt;/i&gt;
&lt;span style="color: #0057ae;"&gt;sum&lt;/span&gt;: &lt;b&gt;function&lt;/b&gt; (i0, iN, fn) {
    &lt;b&gt;var&lt;/b&gt; res = &lt;span style="color: #b08000;"&gt;0&lt;/span&gt;;
    &lt;b&gt;for&lt;/b&gt; (&lt;b&gt;var&lt;/b&gt; i = i0; i &amp;lt;= iN; i++) {
        res += fn(i);
    }
    &lt;b&gt;return&lt;/b&gt; res;
},

&lt;i&gt;&lt;span style="color: #898887;"&gt;/**&lt;/span&gt;&lt;/i&gt;
&lt;i&gt;&lt;span style="color: #898887;"&gt;  * Computes the product of function values over given integer range&lt;/span&gt;&lt;/i&gt;
&lt;i&gt;&lt;span style="color: #898887;"&gt;  * @param {integer} i0 First index value&lt;/span&gt;&lt;/i&gt;
&lt;i&gt;&lt;span style="color: #898887;"&gt;  * @param {integer} iN Last index value&lt;/span&gt;&lt;/i&gt;
&lt;i&gt;&lt;span style="color: #898887;"&gt;  * @param {function(integer)} fn Function with values to multiply&lt;/span&gt;&lt;/i&gt;
&lt;i&gt;&lt;span style="color: #898887;"&gt;  * @return {number} fn(i0)*fn(i0 + 1)* ... *fn(iN)&lt;/span&gt;&lt;/i&gt;
&lt;i&gt;&lt;span style="color: #898887;"&gt;  */&lt;/span&gt;&lt;/i&gt;
&lt;span style="color: #0057ae;"&gt;product&lt;/span&gt;: &lt;b&gt;function&lt;/b&gt; (i0, iN, fn) {
    &lt;b&gt;var&lt;/b&gt; res = &lt;span style="color: #b08000;"&gt;1&lt;/span&gt;;
    &lt;b&gt;for&lt;/b&gt; (&lt;b&gt;var&lt;/b&gt; i = i0; i &amp;lt;= iN; i++) {
        res *= fn(i);
    }
    &lt;b&gt;return&lt;/b&gt; res;
},

&lt;i&gt;&lt;span style="color: #898887;"&gt;/**&lt;/span&gt;&lt;/i&gt;
&lt;i&gt;&lt;span style="color: #898887;"&gt;  * Computes binomial coefficient (the number of distinct k-element &lt;/span&gt;&lt;/i&gt;
&lt;i&gt;&lt;span style="color: #898887;"&gt;  *  subsets of n-sized set).&lt;/span&gt;&lt;/i&gt;
&lt;i&gt;&lt;span style="color: #898887;"&gt;  *&lt;/span&gt;&lt;/i&gt;
&lt;i&gt;&lt;span style="color: #898887;"&gt;  * Note that we use the multiplicative formula, as opposed to the &lt;/span&gt;&lt;/i&gt;
&lt;i&gt;&lt;span style="color: #898887;"&gt;  *  standard n!/(k!(n-k)!) one,in order to improve robustness/efficiency.&lt;/span&gt;&lt;/i&gt;
&lt;i&gt;&lt;span style="color: #898887;"&gt;  * (http://en.wikipedia.org/wiki/Binomial_coefficient#Multiplicative_formula)&lt;/span&gt;&lt;/i&gt;
&lt;i&gt;&lt;span style="color: #898887;"&gt;  * @param {integer} k Subset size&lt;/span&gt;&lt;/i&gt;
&lt;i&gt;&lt;span style="color: #898887;"&gt;  * @param {integer} n Set size&lt;/span&gt;&lt;/i&gt;
&lt;i&gt;&lt;span style="color: #898887;"&gt;  * @return {number} The binomial coefficient, C(n, k)&lt;/span&gt;&lt;/i&gt;
&lt;i&gt;&lt;span style="color: #898887;"&gt;  */&lt;/span&gt;&lt;/i&gt;
&lt;span style="color: #0057ae;"&gt;binomialCoefficient &lt;/span&gt;: &lt;b&gt;function&lt;/b&gt; (k, n) {
    &lt;b&gt;return&lt;/b&gt; &lt;span style="color: green;"&gt;Probability&lt;/span&gt;.&lt;span style="color: #644a9b;"&gt;product&lt;/span&gt;(&lt;span style="color: #b08000;"&gt;1&lt;/span&gt;, k, &lt;b&gt;function&lt;/b&gt;(i) { 
        &lt;b&gt;return&lt;/b&gt; (n - (k - i))/i; 
    });
},

&lt;i&gt;&lt;span style="color: #898887;"&gt;/**&lt;/span&gt;&lt;/i&gt;
&lt;i&gt;&lt;span style="color: #898887;"&gt;  * Probability mass function for binomial distribution&lt;/span&gt;&lt;/i&gt;
&lt;i&gt;&lt;span style="color: #898887;"&gt;  * http://en.wikipedia.org/wiki/Binomial_distribution&lt;/span&gt;&lt;/i&gt;
&lt;i&gt;&lt;span style="color: #898887;"&gt;  * @param {integer} k Amount of successes&lt;/span&gt;&lt;/i&gt;
&lt;i&gt;&lt;span style="color: #898887;"&gt;  * @param {integer} n Amount of trials&lt;/span&gt;&lt;/i&gt;
&lt;i&gt;&lt;span style="color: #898887;"&gt;  * @param {number} p Probability of success&lt;/span&gt;&lt;/i&gt;
&lt;i&gt;&lt;span style="color: #898887;"&gt;  * @return {number} Probability that amount of successes in Bernoulli &lt;/span&gt;&lt;/i&gt;
&lt;i&gt;&lt;span style="color: #898887;"&gt;  * experiment with n trials is exactly k&lt;/span&gt;&lt;/i&gt;
&lt;i&gt;&lt;span style="color: #898887;"&gt;  */&lt;/span&gt;&lt;/i&gt;
&lt;span style="color: #0057ae;"&gt;binomialDistribution &lt;/span&gt;: &lt;b&gt;function&lt;/b&gt; (k, n, p) {
    &lt;b&gt;return&lt;/b&gt; &lt;span style="color: green;"&gt;Probability&lt;/span&gt;.&lt;span style="color: #644a9b;"&gt;binomialCoefficient&lt;/span&gt;(k, n)*
        &lt;span style="color: green;"&gt;Math&lt;/span&gt;.&lt;span style="color: #644a9b;"&gt;pow&lt;/span&gt;(p, k)*&lt;span style="color: green;"&gt;Math&lt;/span&gt;.&lt;span style="color: #644a9b;"&gt;pow&lt;/span&gt;(&lt;span style="color: #b08000;"&gt;1&lt;/span&gt; - p, n - k);
},

&lt;i&gt;&lt;span style="color: #898887;"&gt;/** &lt;/span&gt;&lt;/i&gt;
&lt;i&gt;&lt;span style="color: #898887;"&gt;  * Cumulative distribution function &lt;/span&gt;&lt;/i&gt;
&lt;i&gt;&lt;span style="color: #898887;"&gt;  *  http://en.wikipedia.org/wiki/Cumulative_distribution_function&lt;/span&gt;&lt;/i&gt;
&lt;i&gt;&lt;span style="color: #898887;"&gt;  * @param {integer} x Upper bound value&lt;/span&gt;&lt;/i&gt;
&lt;i&gt;&lt;span style="color: #898887;"&gt;  * @param {function(integer)} pFn Probability mass function &lt;/span&gt;&lt;/i&gt;
&lt;i&gt;&lt;span style="color: #898887;"&gt;  * @return {number} Probability that random value with &lt;/span&gt;&lt;/i&gt;
&lt;i&gt;&lt;span style="color: #898887;"&gt;  *     probability mass function pFn is smaller or equal to x&lt;/span&gt;&lt;/i&gt;
&lt;i&gt;&lt;span style="color: #898887;"&gt;  */&lt;/span&gt;&lt;/i&gt;
&lt;span style="color: #0057ae;"&gt;CDF&lt;/span&gt;: &lt;b&gt;function&lt;/b&gt; (x, pFn) {
    &lt;b&gt;return&lt;/b&gt; &lt;span style="color: green;"&gt;Probability&lt;/span&gt;.&lt;span style="color: #644a9b;"&gt;sum&lt;/span&gt;(&lt;span style="color: #b08000;"&gt;0&lt;/span&gt;, x, pFn);
},

  &lt;i&gt;&lt;span style="color: #898887;"&gt;/** &lt;/span&gt;&lt;/i&gt;
&lt;i&gt;&lt;span style="color: #898887;"&gt;  * Cumulative distribution function for binomial distribution&lt;/span&gt;&lt;/i&gt;
&lt;i&gt;&lt;span style="color: #898887;"&gt;  * @param {integer} x Upper bound value&lt;/span&gt;&lt;/i&gt;
&lt;i&gt;&lt;span style="color: #898887;"&gt;  * @param {integer} n Amount of trials&lt;/span&gt;&lt;/i&gt;
&lt;i&gt;&lt;span style="color: #898887;"&gt;  * @param {number} p Probability of success&lt;/span&gt;&lt;/i&gt;
&lt;i&gt;&lt;span style="color: #898887;"&gt;  * @return {number} Probability that amount of successes &lt;/span&gt;&lt;/i&gt;
&lt;i&gt;&lt;span style="color: #898887;"&gt;  *     in Bernoulli experiment with n trials is less or equal to x&lt;/span&gt;&lt;/i&gt;
&lt;i&gt;&lt;span style="color: #898887;"&gt;  */&lt;/span&gt;&lt;/i&gt;
&lt;span style="color: #0057ae;"&gt;binomialCDF &lt;/span&gt;: &lt;b&gt;function&lt;/b&gt; (x, n, p) {
    &lt;b&gt;return&lt;/b&gt; &lt;span style="color: green;"&gt;Probability&lt;/span&gt;.&lt;span style="color: #644a9b;"&gt;CDF&lt;/span&gt;(x, &lt;b&gt;function&lt;/b&gt;(i) { 
        &lt;b&gt;return&lt;/b&gt; &lt;span style="color: green;"&gt;Probability&lt;/span&gt;.&lt;span style="color: #644a9b;"&gt;binomialDistribution&lt;/span&gt;(i, n, p); 
    });
}

}
&lt;/pre&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;h4&gt;

Some final notes&lt;/h4&gt;
While it's not too relevant to the main point here, we've still made a bunch of assumptions about how the loot dropping mechanism may work.
&lt;br /&gt;
&lt;br /&gt;
One of them is that we can use the &lt;a href="http://en.wikipedia.org/wiki/Bernoulli_process"&gt;Bernoulli process&lt;/a&gt; to model the loot drops. 
&lt;br /&gt;
&lt;br /&gt;
In simple words, it means that outcome of the previous boss kills are not connected in any way to the outcomes of all the next boss kills.
&lt;br /&gt;
&lt;br /&gt;
It &lt;a href="http://www.wowblues.com/eu/poor-random-loot-drops-in-raids-14574757441.html"&gt;may be the case in WoW&lt;/a&gt; (after all, it's the most simple/efficient model from the implementation point of view), in practice the loot dropping code could be more complex than that, i.e. the history of the loot drops could have been taken into account.
&lt;br /&gt;
&lt;br /&gt;
For example, the code could make sure that those two friends would have 100% guarantee/satisfaction to get their loot after 10 boss kills. 
&lt;br /&gt;
&lt;br /&gt;
But that's a totally different story.

&lt;br /&gt;
&lt;h4&gt;

P.S.&lt;/h4&gt;
Just to be clear: the point is not about World of Warcraft making things interesting.
&lt;br /&gt;
It's rather about how cognition is related to empathy, and how academia could exploit that.
&lt;br /&gt;
&lt;blockquote&gt;
9 of 10 guys are jerks. What is the chance that after dating 5 guys you'd meet the one who's not a jerk?
&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/923082020090979517-759664221349161544?l=blog.ruslans.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/gd_reflections/~4/oBjEUQxd9HY" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.ruslans.com/feeds/759664221349161544/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=923082020090979517&amp;postID=759664221349161544" title="4 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/923082020090979517/posts/default/759664221349161544" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/923082020090979517/posts/default/759664221349161544" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/gd_reflections/~3/oBjEUQxd9HY/loot-drop-and-other-epic-problems-of.html" title="Loot drop and other epic problems of probability theory" /><author><name>ruslans</name><uri>http://www.blogger.com/profile/03375859473751956887</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="24" height="32" src="http://2.bp.blogspot.com/_DVYH9neSnMw/S0V_XM6aN0I/AAAAAAAAAMc/06dTTnY0PNw/S220/avatar3.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-akElCaxZdgo/Tah8IxlVR3I/AAAAAAAAAhE/L4mL5uB0gLA/s72-c/binomial_logo.png" height="72" width="72" /><thr:total>4</thr:total><feedburner:origLink>http://blog.ruslans.com/2011/04/loot-drop-and-other-epic-problems-of.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-923082020090979517.post-5216127610412629335</id><published>2011-02-15T01:47:00.000-08:00</published><updated>2011-03-11T12:29:17.100-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="java" /><category scheme="http://www.blogger.com/atom/ns#" term="hexagons" /><category scheme="http://www.blogger.com/atom/ns#" term="tutorial" /><category scheme="http://www.blogger.com/atom/ns#" term="math" /><title type="text">Hexagonal grid math</title><content type="html">Uniform hexagonal grid is a recurring pattern in computer games and graphics applications.
&lt;br /&gt;
&lt;br /&gt;
There are few operations one might need to perform:
&lt;ul&gt;
&lt;li&gt;finding hexagon's position by its index in the grid;&lt;/li&gt;
&lt;li&gt;picking a hexagon by mouse;&lt;/li&gt;
&lt;li&gt;finding neighbor cells;&lt;/li&gt;
&lt;li&gt;finding hexagon's corner coordinates etc.&lt;/li&gt;
&lt;/ul&gt;
While these things do not appear hard at all (something like primary school-level geometry/arithmetics), it's not as straightforward as with a rectangular grid, hovewer.  
&lt;br /&gt;
&lt;br /&gt;
Having tried to consult with internets I've found 
&lt;a href="http://www.codeproject.com/KB/graphics/hexagonal_part1.aspx"&gt;a neat article on CodeProject&lt;/a&gt;, which was solving exactly the problems mentioned. It's considerably highy rated, which I guess means that this stuff is indeed in demand.
&lt;br /&gt;
&lt;br /&gt;
What have confused me, though, is that presented solution (and code) seemed to be more complex than one could expect:
&lt;ul&gt;
&lt;li&gt;hexagon positions are found iteratively, based on the previously computed positions;&lt;/li&gt;
&lt;li&gt;a bunch of corner cases are treated in the process;&lt;/li&gt;
&lt;li&gt;a whole lot of state is stored for each hexagon;&lt;/li&gt;
&lt;li&gt;there is a separate codepath for the alternative hexagon orientation mode (aka "pointy" orientation), which interwines with the main one;&lt;/li&gt;
&lt;li&gt;to pick a hexagon by mouse, the code iterates on the array of hexagons, and performs &lt;a href="http://astronomy.swin.edu.au/%7Epbourke/geometry/insidepoly/"&gt;generic "point-in-polygon" test&lt;/a&gt; for each, using stored corners' coordinates.&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
Can we do any simpler?..
&lt;br /&gt;
&lt;h4&gt;

Hexagonal grid properties&lt;/h4&gt;
Let's examine the geometric properties of a hexagon and define some constants:
&lt;br /&gt;
&lt;br /&gt;
&lt;center&gt;&lt;img border="0" height="150" src="http://1.bp.blogspot.com/-uhf5CIhqUF4/TVo0NzhZqzI/AAAAAAAAAeQ/0uOx6f0ApcI/s400/hex_single.png" width="313" /&gt;&lt;/center&gt;
&lt;br /&gt;
We define the hexagon by its radius R, and find some other parameters based on it, such as  W ("width"), S ("side") and H ("height").
&lt;br /&gt;
&lt;br /&gt;
Now, let's examine the hexagonal grid itself:
&lt;br /&gt;
&lt;img border="0" src="http://4.bp.blogspot.com/-xxi7xTHUVy8/TVo0cbUyyTI/AAAAAAAAAeY/ajzNIsgBjhI/s400/hex.png" width="420" /&gt;

&lt;br /&gt;
&lt;h4&gt;

Finding hexagon position by its array index&lt;/h4&gt;
From that picture one can figure out the formula for finding position of the top left corner of a hexagon cell by its array index (i, j):
&lt;br /&gt;
&lt;br /&gt;
&lt;center&gt;&lt;img border="0" src="http://3.bp.blogspot.com/-TQlWInXN8M8/TVo0lHGCctI/AAAAAAAAAeg/eekvSPtVpNI/s400/tocell_1.png" /&gt;&lt;/center&gt;
&lt;br /&gt;
Taking into account that for odd columns i%2 (remainder from division of i by 2) equals 1, and for even columns it equals 0, we can rewrite it:
&lt;br /&gt;
&lt;center&gt;&lt;img border="0" src="http://4.bp.blogspot.com/-PqVqrb6f3Y0/TVo0r09MWsI/AAAAAAAAAeo/ZobKTcBz4wI/s400/tocell_2.png" /&gt;&lt;/center&gt;

&lt;h4&gt;

Finding hexagon index by a point&lt;/h4&gt;
Another operation is to find the hexagon array index from a point coordinates on the screen, which is used for mouse picking.

&lt;br /&gt;
&lt;br /&gt;
Let's start from the observation that hexagonal grid can be completely covered by the set of rectangular tiles (of width S and height H). They are drawn as green rectangles with purple triangular insets in the picture above. Each tile overlaps with three hexagons.

&lt;br /&gt;
&lt;br /&gt;
Finding which of those tiles our picking point gets into is not too hard:
&lt;center&gt;&lt;img border="0" src="http://2.bp.blogspot.com/-1o1Q4dm8Q3M/TXqFSAFxojI/AAAAAAAAAgI/u3a-Z8df1Ds/s400/fromcell_1.png" /&gt;&lt;/center&gt;
Here &lt;i&gt;(it, jt)&lt;/i&gt; are the column/row of the rectangular tile picked by the point. Those fancy brackets is a &lt;a href="http://en.wikipedia.org/wiki/Floor_and_ceiling_functions"&gt;floor operation&lt;/a&gt;.
&lt;br /&gt;
&lt;br /&gt;
Coordinates of the point &lt;i&gt;inside&lt;/i&gt; the tile are:
&lt;center&gt;&lt;img border="0" src="http://2.bp.blogspot.com/-492zImChXmg/TVo058Iq9YI/AAAAAAAAAe4/o8M7Rd6psak/s400/fromcell_2.png" /&gt;&lt;/center&gt;
After we have all this, now we can find which one of the three possible hexagons corresponds to our point. For that we zoom into the rectangular cell's coordinate system and build a plot of the separating line (the fat red line in the picture). Its function is &lt;i&gt;xt=R|0.5-yt/H|&lt;/i&gt;, and for all the points above the line (they fall into the green area) we have that &lt;i&gt;xt&amp;gt;R|0.5-yt/H|&lt;/i&gt;.
&lt;br /&gt;
&lt;br /&gt;
For all the other points inside the rectangle, we have to pick either top or bottom hexagon to the left. This is decided based on value of &lt;i&gt;yt&lt;/i&gt;.
&lt;br /&gt;
&lt;br /&gt;
Aditionally, we have to mind the odd/even rows indexing difference (as rows in the hexagon array go in zigzag pattern).
&lt;br /&gt;
&lt;br /&gt;
Putting it all together, the final array indices of the picked hexagon are:
&lt;center&gt;&lt;img border="0" src="http://2.bp.blogspot.com/-DmRt6b6nDqI/TXqEoldnOpI/AAAAAAAAAgA/qFUL4YFhY5I/s400/fromcell_3.png" /&gt;&lt;/center&gt;
&lt;h4&gt;

The "pointy" grid orientation&lt;/h4&gt;
So far we've been only considering the "flat" grid orientation (i.e. hexagons are "lying" on their sides).
&lt;br /&gt;
&lt;br /&gt;
What happens if we want to have the alternative orientation, when hexagons are oriented corners upwards, should we rewrite all the formulas?..
&lt;br /&gt;
&lt;br /&gt;
One simple observation about the "pointy" orientation is that one can get it by mirroring the "flat" one around the diagonal axis.
&lt;br /&gt;
&lt;br /&gt;
The direct consequence of this is that all the calculations for the "pointy" case can be performed by:
&lt;ul&gt;
&lt;li&gt;swapping the input coordinates (i.e. "mirror" them around the diagonal): x&lt;-&gt;y or i&lt;-&gt;j;&lt;/li&gt;
&lt;li&gt;applying the formulas as described above;&lt;/li&gt;
&lt;li&gt;swapping the output coordinates back ("unmirroring" them): i&lt;-&gt;j, x&lt;-&gt;y.
&lt;/ul&gt;
The operation is quite straightforward to do in code (as opposed to having a separate codepath for each case), I am leaving it as an exercise to the reader.
&lt;h4&gt;

The code&lt;/h4&gt;
Here's an example Java code, which has the formulas implemented:

&lt;br /&gt;
&lt;div style="height: 520px; overflow: auto; width: 100%;"&gt;
&lt;table cellpadding="0" cellspacing="0" style="width: 420px;"&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;pre style="background-color: white; color: #181615; font-size: 8pt; line-height: 13px;"&gt;&lt;b&gt;package&lt;/b&gt;&lt;span style="color: olive;"&gt; com.rush;&lt;/span&gt;

&lt;b&gt;&lt;span style="color: green;"&gt;/**&lt;/span&gt;&lt;/b&gt;
&lt;b&gt;&lt;span style="color: green;"&gt; * Uniform hexagonal grid cell's metrics utility class.&lt;/span&gt;&lt;/b&gt;
&lt;i&gt;&lt;span style="color: green;"&gt; &lt;/span&gt;&lt;/i&gt;&lt;b&gt;&lt;span style="color: green;"&gt;*/&lt;/span&gt;&lt;/b&gt;
&lt;b&gt;public&lt;/b&gt; &lt;b&gt;class&lt;/b&gt; HexGridCell {
    &lt;b&gt;private&lt;/b&gt; &lt;span style="color: #0057ae;"&gt;static&lt;/span&gt; &lt;span style="color: #0057ae;"&gt;final&lt;/span&gt; &lt;span style="color: #0057ae;"&gt;int&lt;/span&gt;[] NEIGHBORS_DI = { &lt;span style="color: #b08000;"&gt;0&lt;/span&gt;, &lt;span style="color: #b08000;"&gt;1&lt;/span&gt;, &lt;span style="color: #b08000;"&gt;1&lt;/span&gt;, &lt;span style="color: #b08000;"&gt;0&lt;/span&gt;, -&lt;span style="color: #b08000;"&gt;1&lt;/span&gt;, -&lt;span style="color: #b08000;"&gt;1&lt;/span&gt; };
    &lt;b&gt;private&lt;/b&gt; &lt;span style="color: #0057ae;"&gt;static&lt;/span&gt; &lt;span style="color: #0057ae;"&gt;final&lt;/span&gt; &lt;span style="color: #0057ae;"&gt;int&lt;/span&gt;[][] NEIGHBORS_DJ = { 
            { -&lt;span style="color: #b08000;"&gt;1&lt;/span&gt;, -&lt;span style="color: #b08000;"&gt;1&lt;/span&gt;, &lt;span style="color: #b08000;"&gt;0&lt;/span&gt;, &lt;span style="color: #b08000;"&gt;1&lt;/span&gt;, &lt;span style="color: #b08000;"&gt;0&lt;/span&gt;, -&lt;span style="color: #b08000;"&gt;1&lt;/span&gt; }, { -&lt;span style="color: #b08000;"&gt;1&lt;/span&gt;, &lt;span style="color: #b08000;"&gt;0&lt;/span&gt;, &lt;span style="color: #b08000;"&gt;1&lt;/span&gt;, &lt;span style="color: #b08000;"&gt;1&lt;/span&gt;, &lt;span style="color: #b08000;"&gt;1&lt;/span&gt;, &lt;span style="color: #b08000;"&gt;0&lt;/span&gt; } };

    &lt;b&gt;private&lt;/b&gt; &lt;span style="color: #0057ae;"&gt;final&lt;/span&gt; &lt;span style="color: #0057ae;"&gt;int&lt;/span&gt;[] CORNERS_DX; &lt;i&gt;&lt;span style="color: #898887;"&gt;// array of horizontal offsets of the cell's corners&lt;/span&gt;&lt;/i&gt;
    &lt;b&gt;private&lt;/b&gt; &lt;span style="color: #0057ae;"&gt;final&lt;/span&gt; &lt;span style="color: #0057ae;"&gt;int&lt;/span&gt;[] CORNERS_DY; &lt;i&gt;&lt;span style="color: #898887;"&gt;// array of vertical offsets of the cell's corners&lt;/span&gt;&lt;/i&gt;
    &lt;b&gt;private&lt;/b&gt; &lt;span style="color: #0057ae;"&gt;final&lt;/span&gt; &lt;span style="color: #0057ae;"&gt;int&lt;/span&gt; SIDE;

    &lt;b&gt;private&lt;/b&gt; &lt;span style="color: #0057ae;"&gt;int&lt;/span&gt; mX = &lt;span style="color: #b08000;"&gt;0&lt;/span&gt;; &lt;i&gt;&lt;span style="color: #898887;"&gt;// cell's left coordinate&lt;/span&gt;&lt;/i&gt;
    &lt;b&gt;private&lt;/b&gt; &lt;span style="color: #0057ae;"&gt;int&lt;/span&gt; mY = &lt;span style="color: #b08000;"&gt;0&lt;/span&gt;; &lt;i&gt;&lt;span style="color: #898887;"&gt;// cell's top coordinate&lt;/span&gt;&lt;/i&gt;

    &lt;b&gt;private&lt;/b&gt; &lt;span style="color: #0057ae;"&gt;int&lt;/span&gt; mI = &lt;span style="color: #b08000;"&gt;0&lt;/span&gt;; &lt;i&gt;&lt;span style="color: #898887;"&gt;// cell's horizontal grid coordinate&lt;/span&gt;&lt;/i&gt;
    &lt;b&gt;private&lt;/b&gt; &lt;span style="color: #0057ae;"&gt;int&lt;/span&gt; mJ = &lt;span style="color: #b08000;"&gt;0&lt;/span&gt;; &lt;i&gt;&lt;span style="color: #898887;"&gt;// cell's vertical grid coordinate&lt;/span&gt;&lt;/i&gt;

    &lt;b&gt;&lt;span style="color: green;"&gt;/**&lt;/span&gt;&lt;/b&gt;
&lt;b&gt;&lt;span style="color: green;"&gt;     * Cell radius (distance from center to one of the corners)&lt;/span&gt;&lt;/b&gt;
&lt;b&gt;&lt;span style="color: green;"&gt;     */&lt;/span&gt;&lt;/b&gt;
    &lt;b&gt;public&lt;/b&gt; &lt;span style="color: #0057ae;"&gt;final&lt;/span&gt; &lt;span style="color: #0057ae;"&gt;int&lt;/span&gt; RADIUS;
    &lt;b&gt;&lt;span style="color: green;"&gt;/**&lt;/span&gt;&lt;/b&gt;
&lt;b&gt;&lt;span style="color: green;"&gt;     * Cell height&lt;/span&gt;&lt;/b&gt;
&lt;b&gt;&lt;span style="color: green;"&gt;     */&lt;/span&gt;&lt;/b&gt;
    &lt;b&gt;public&lt;/b&gt; &lt;span style="color: #0057ae;"&gt;final&lt;/span&gt; &lt;span style="color: #0057ae;"&gt;int&lt;/span&gt; HEIGHT;
    &lt;b&gt;&lt;span style="color: green;"&gt;/**&lt;/span&gt;&lt;/b&gt;
&lt;b&gt;&lt;span style="color: green;"&gt;     * Cell width&lt;/span&gt;&lt;/b&gt;
&lt;b&gt;&lt;span style="color: green;"&gt;     */&lt;/span&gt;&lt;/b&gt;
    &lt;b&gt;public&lt;/b&gt; &lt;span style="color: #0057ae;"&gt;final&lt;/span&gt; &lt;span style="color: #0057ae;"&gt;int&lt;/span&gt; WIDTH;

    &lt;b&gt;public&lt;/b&gt; &lt;span style="color: #0057ae;"&gt;static&lt;/span&gt; &lt;span style="color: #0057ae;"&gt;final&lt;/span&gt; &lt;span style="color: #0057ae;"&gt;int&lt;/span&gt; NUM_NEIGHBORS = &lt;span style="color: #b08000;"&gt;6&lt;/span&gt;;

    &lt;b&gt;&lt;span style="color: green;"&gt;/**&lt;/span&gt;&lt;/b&gt;
&lt;b&gt;&lt;span style="color: green;"&gt;     * &lt;/span&gt;&lt;/b&gt;&lt;b&gt;&lt;span style="color: grey;"&gt;@param &lt;/span&gt;&lt;/b&gt;&lt;i&gt;&lt;span style="color: teal;"&gt;radius &lt;/span&gt;&lt;/i&gt;&lt;i&gt;&lt;span style="color: green;"&gt;Cell radius (distance from the center to one of the corners)&lt;/span&gt;&lt;/i&gt;
&lt;i&gt;&lt;span style="color: green;"&gt;     &lt;/span&gt;&lt;/i&gt;&lt;b&gt;&lt;span style="color: green;"&gt;*/&lt;/span&gt;&lt;/b&gt;
    &lt;b&gt;public&lt;/b&gt; &lt;span style="color: #644a9b;"&gt;HexGridCell&lt;/span&gt;(&lt;span style="color: #0057ae;"&gt;int&lt;/span&gt; radius) {
        RADIUS = radius;
        WIDTH = radius * &lt;span style="color: #b08000;"&gt;2&lt;/span&gt;;
        HEIGHT = (&lt;span style="color: #0057ae;"&gt;int&lt;/span&gt;) (((&lt;span style="color: #0057ae;"&gt;float&lt;/span&gt;) radius) * &lt;b&gt;&lt;span style="color: #0095ff;"&gt;Math&lt;/span&gt;&lt;/b&gt;.&lt;span style="color: #644a9b;"&gt;sqrt&lt;/span&gt;(&lt;span style="color: #b08000;"&gt;3&lt;/span&gt;));
        SIDE = radius * &lt;span style="color: #b08000;"&gt;3&lt;/span&gt; / &lt;span style="color: #b08000;"&gt;2&lt;/span&gt;;

        &lt;span style="color: #0057ae;"&gt;int&lt;/span&gt; cdx[] = { RADIUS / &lt;span style="color: #b08000;"&gt;2&lt;/span&gt;, SIDE, WIDTH, SIDE, RADIUS / &lt;span style="color: #b08000;"&gt;2&lt;/span&gt;, &lt;span style="color: #b08000;"&gt;0&lt;/span&gt; };
        CORNERS_DX = cdx;
        &lt;span style="color: #0057ae;"&gt;int&lt;/span&gt; cdy[] = { &lt;span style="color: #b08000;"&gt;0&lt;/span&gt;, &lt;span style="color: #b08000;"&gt;0&lt;/span&gt;, HEIGHT / &lt;span style="color: #b08000;"&gt;2&lt;/span&gt;, HEIGHT, HEIGHT, HEIGHT / &lt;span style="color: #b08000;"&gt;2&lt;/span&gt; };
        CORNERS_DY = cdy;
    }

    &lt;b&gt;&lt;span style="color: green;"&gt;/**&lt;/span&gt;&lt;/b&gt;
&lt;b&gt;&lt;span style="color: green;"&gt;     * &lt;/span&gt;&lt;/b&gt;&lt;b&gt;&lt;span style="color: grey;"&gt;@return &lt;/span&gt;&lt;/b&gt;&lt;i&gt;&lt;span style="color: green;"&gt;X coordinate of the cell's top left corner.&lt;/span&gt;&lt;/i&gt;
&lt;i&gt;&lt;span style="color: green;"&gt;     &lt;/span&gt;&lt;/i&gt;&lt;b&gt;&lt;span style="color: green;"&gt;*/&lt;/span&gt;&lt;/b&gt;
    &lt;b&gt;public&lt;/b&gt; &lt;span style="color: #0057ae;"&gt;int&lt;/span&gt; &lt;span style="color: #644a9b;"&gt;getLeft&lt;/span&gt;() {
        &lt;b&gt;return&lt;/b&gt; mX;
    }

    &lt;b&gt;&lt;span style="color: green;"&gt;/**&lt;/span&gt;&lt;/b&gt;
&lt;b&gt;&lt;span style="color: green;"&gt;     * &lt;/span&gt;&lt;/b&gt;&lt;b&gt;&lt;span style="color: grey;"&gt;@return &lt;/span&gt;&lt;/b&gt;&lt;i&gt;&lt;span style="color: green;"&gt;Y coordinate of the cell's top left corner.&lt;/span&gt;&lt;/i&gt;
&lt;i&gt;&lt;span style="color: green;"&gt;     &lt;/span&gt;&lt;/i&gt;&lt;b&gt;&lt;span style="color: green;"&gt;*/&lt;/span&gt;&lt;/b&gt;
    &lt;b&gt;public&lt;/b&gt; &lt;span style="color: #0057ae;"&gt;int&lt;/span&gt; &lt;span style="color: #644a9b;"&gt;getTop&lt;/span&gt;() {
        &lt;b&gt;return&lt;/b&gt; mY;
    }

    &lt;b&gt;&lt;span style="color: green;"&gt;/**&lt;/span&gt;&lt;/b&gt;
&lt;b&gt;&lt;span style="color: green;"&gt;     * &lt;/span&gt;&lt;/b&gt;&lt;b&gt;&lt;span style="color: grey;"&gt;@return &lt;/span&gt;&lt;/b&gt;&lt;i&gt;&lt;span style="color: green;"&gt;X coordinate of the cell's center&lt;/span&gt;&lt;/i&gt;
&lt;i&gt;&lt;span style="color: green;"&gt;     &lt;/span&gt;&lt;/i&gt;&lt;b&gt;&lt;span style="color: green;"&gt;*/&lt;/span&gt;&lt;/b&gt;
    &lt;b&gt;public&lt;/b&gt; &lt;span style="color: #0057ae;"&gt;int&lt;/span&gt; &lt;span style="color: #644a9b;"&gt;getCenterX&lt;/span&gt;() {
        &lt;b&gt;return&lt;/b&gt; mX + RADIUS;
    }

    &lt;b&gt;&lt;span style="color: green;"&gt;/**&lt;/span&gt;&lt;/b&gt;
&lt;b&gt;&lt;span style="color: green;"&gt;     * &lt;/span&gt;&lt;/b&gt;&lt;b&gt;&lt;span style="color: grey;"&gt;@return &lt;/span&gt;&lt;/b&gt;&lt;i&gt;&lt;span style="color: green;"&gt;Y coordinate of the cell's center&lt;/span&gt;&lt;/i&gt;
&lt;i&gt;&lt;span style="color: green;"&gt;     &lt;/span&gt;&lt;/i&gt;&lt;b&gt;&lt;span style="color: green;"&gt;*/&lt;/span&gt;&lt;/b&gt;
    &lt;b&gt;public&lt;/b&gt; &lt;span style="color: #0057ae;"&gt;int&lt;/span&gt; &lt;span style="color: #644a9b;"&gt;getCenterY&lt;/span&gt;() {
        &lt;b&gt;return&lt;/b&gt; mY + HEIGHT / &lt;span style="color: #b08000;"&gt;2&lt;/span&gt;;
    }

    &lt;b&gt;&lt;span style="color: green;"&gt;/**&lt;/span&gt;&lt;/b&gt;
&lt;b&gt;&lt;span style="color: green;"&gt;     * &lt;/span&gt;&lt;/b&gt;&lt;b&gt;&lt;span style="color: grey;"&gt;@return &lt;/span&gt;&lt;/b&gt;&lt;i&gt;&lt;span style="color: green;"&gt;Horizontal grid coordinate for the cell.&lt;/span&gt;&lt;/i&gt;
&lt;i&gt;&lt;span style="color: green;"&gt;     &lt;/span&gt;&lt;/i&gt;&lt;b&gt;&lt;span style="color: green;"&gt;*/&lt;/span&gt;&lt;/b&gt;
    &lt;b&gt;public&lt;/b&gt; &lt;span style="color: #0057ae;"&gt;int&lt;/span&gt; &lt;span style="color: #644a9b;"&gt;getIndexI&lt;/span&gt;() {
        &lt;b&gt;return&lt;/b&gt; mI;
    }

    &lt;b&gt;&lt;span style="color: green;"&gt;/**&lt;/span&gt;&lt;/b&gt;
&lt;b&gt;&lt;span style="color: green;"&gt;     * &lt;/span&gt;&lt;/b&gt;&lt;b&gt;&lt;span style="color: grey;"&gt;@return &lt;/span&gt;&lt;/b&gt;&lt;i&gt;&lt;span style="color: green;"&gt;Vertical grid coordinate for the cell.&lt;/span&gt;&lt;/i&gt;
&lt;i&gt;&lt;span style="color: green;"&gt;     &lt;/span&gt;&lt;/i&gt;&lt;b&gt;&lt;span style="color: green;"&gt;*/&lt;/span&gt;&lt;/b&gt;
    &lt;b&gt;public&lt;/b&gt; &lt;span style="color: #0057ae;"&gt;int&lt;/span&gt; &lt;span style="color: #644a9b;"&gt;getIndexJ&lt;/span&gt;() {
        &lt;b&gt;return&lt;/b&gt; mJ;
    }

    &lt;b&gt;&lt;span style="color: green;"&gt;/**&lt;/span&gt;&lt;/b&gt;
&lt;b&gt;&lt;span style="color: green;"&gt;     * &lt;/span&gt;&lt;/b&gt;&lt;b&gt;&lt;span style="color: grey;"&gt;@return &lt;/span&gt;&lt;/b&gt;&lt;i&gt;&lt;span style="color: green;"&gt;Horizontal grid coordinate for the given neighbor.&lt;/span&gt;&lt;/i&gt;
&lt;i&gt;&lt;span style="color: green;"&gt;     &lt;/span&gt;&lt;/i&gt;&lt;b&gt;&lt;span style="color: green;"&gt;*/&lt;/span&gt;&lt;/b&gt;
    &lt;b&gt;public&lt;/b&gt; &lt;span style="color: #0057ae;"&gt;int&lt;/span&gt; &lt;span style="color: #644a9b;"&gt;getNeighborI&lt;/span&gt;(&lt;span style="color: #0057ae;"&gt;int&lt;/span&gt; neighborIdx) {
        &lt;b&gt;return&lt;/b&gt; mI + NEIGHBORS_DI[neighborIdx];
    }

    &lt;b&gt;&lt;span style="color: green;"&gt;/**&lt;/span&gt;&lt;/b&gt;
&lt;b&gt;&lt;span style="color: green;"&gt;     * &lt;/span&gt;&lt;/b&gt;&lt;b&gt;&lt;span style="color: grey;"&gt;@return &lt;/span&gt;&lt;/b&gt;&lt;i&gt;&lt;span style="color: green;"&gt;Vertical grid coordinate for the given neighbor.&lt;/span&gt;&lt;/i&gt;
&lt;i&gt;&lt;span style="color: green;"&gt;     &lt;/span&gt;&lt;/i&gt;&lt;b&gt;&lt;span style="color: green;"&gt;*/&lt;/span&gt;&lt;/b&gt;
    &lt;b&gt;public&lt;/b&gt; &lt;span style="color: #0057ae;"&gt;int&lt;/span&gt; &lt;span style="color: #644a9b;"&gt;getNeighborJ&lt;/span&gt;(&lt;span style="color: #0057ae;"&gt;int&lt;/span&gt; neighborIdx) {
        &lt;b&gt;return&lt;/b&gt; mJ + NEIGHBORS_DJ[mI % &lt;span style="color: #b08000;"&gt;2&lt;/span&gt;][neighborIdx];
    }

    &lt;b&gt;&lt;span style="color: green;"&gt;/**&lt;/span&gt;&lt;/b&gt;
&lt;b&gt;&lt;span style="color: green;"&gt;     * Computes X and Y coordinates for all of the cell's 6 corners, clockwise,&lt;/span&gt;&lt;/b&gt;
&lt;b&gt;&lt;span style="color: green;"&gt;     * starting from the top left.&lt;/span&gt;&lt;/b&gt;
&lt;i&gt;&lt;span style="color: green;"&gt;     &lt;/span&gt;&lt;/i&gt;&lt;b&gt;&lt;span style="color: green;"&gt;*&lt;/span&gt;&lt;/b&gt;&lt;i&gt;&lt;span style="color: green;"&gt; &lt;/span&gt;&lt;/i&gt;
&lt;i&gt;&lt;span style="color: green;"&gt;     &lt;/span&gt;&lt;/i&gt;&lt;b&gt;&lt;span style="color: green;"&gt;*&lt;/span&gt;&lt;/b&gt;&lt;i&gt;&lt;span style="color: green;"&gt; &lt;/span&gt;&lt;/i&gt;&lt;b&gt;&lt;span style="color: grey;"&gt;@param &lt;/span&gt;&lt;/b&gt;&lt;i&gt;&lt;span style="color: teal;"&gt;cornersX &lt;/span&gt;&lt;/i&gt;&lt;i&gt;&lt;span style="color: green;"&gt;Array to fill in with X coordinates of the cell's corners&lt;/span&gt;&lt;/i&gt;
&lt;i&gt;&lt;span style="color: green;"&gt;     &lt;/span&gt;&lt;/i&gt;&lt;b&gt;&lt;span style="color: green;"&gt;*&lt;/span&gt;&lt;/b&gt;&lt;i&gt;&lt;span style="color: green;"&gt; &lt;/span&gt;&lt;/i&gt;&lt;b&gt;&lt;span style="color: grey;"&gt;@param &lt;/span&gt;&lt;/b&gt;&lt;i&gt;&lt;span style="color: teal;"&gt;cornersX &lt;/span&gt;&lt;/i&gt;&lt;i&gt;&lt;span style="color: green;"&gt;Array to fill in with Y coordinates of the cell's corners&lt;/span&gt;&lt;/i&gt;
&lt;i&gt;&lt;span style="color: green;"&gt;     &lt;/span&gt;&lt;/i&gt;&lt;b&gt;&lt;span style="color: green;"&gt;*/&lt;/span&gt;&lt;/b&gt;
    &lt;b&gt;public&lt;/b&gt; &lt;span style="color: #0057ae;"&gt;void&lt;/span&gt; &lt;span style="color: #644a9b;"&gt;computeCorners&lt;/span&gt;(&lt;span style="color: #0057ae;"&gt;int&lt;/span&gt;[] cornersX, &lt;span style="color: #0057ae;"&gt;int&lt;/span&gt;[] cornersY) {
        &lt;b&gt;for&lt;/b&gt; (&lt;span style="color: #0057ae;"&gt;int&lt;/span&gt; k = &lt;span style="color: #b08000;"&gt;0&lt;/span&gt;; k &amp;lt; NUM_NEIGHBORS; k++) {
            cornersX[k] = mX + CORNERS_DX[k];
            cornersY[k] = mY + CORNERS_DY[k];
        }
    }

    &lt;b&gt;&lt;span style="color: green;"&gt;/**&lt;/span&gt;&lt;/b&gt;
&lt;b&gt;&lt;span style="color: green;"&gt;     * Sets the cell's horizontal and vertical grid coordinates.&lt;/span&gt;&lt;/b&gt;
&lt;i&gt;&lt;span style="color: green;"&gt;     &lt;/span&gt;&lt;/i&gt;&lt;b&gt;&lt;span style="color: green;"&gt;*/&lt;/span&gt;&lt;/b&gt;
    &lt;b&gt;public&lt;/b&gt; &lt;span style="color: #0057ae;"&gt;void&lt;/span&gt; &lt;span style="color: #644a9b;"&gt;setCellIndex&lt;/span&gt;(&lt;span style="color: #0057ae;"&gt;int&lt;/span&gt; i, &lt;span style="color: #0057ae;"&gt;int&lt;/span&gt; j) {
        mI = i;
        mJ = j;
        mX = i * SIDE;
        mY = HEIGHT * (&lt;span style="color: #b08000;"&gt;2&lt;/span&gt; * j + (i % &lt;span style="color: #b08000;"&gt;2&lt;/span&gt;)) / &lt;span style="color: #b08000;"&gt;2&lt;/span&gt;;
    }
    
    &lt;b&gt;&lt;span style="color: green;"&gt;/**&lt;/span&gt;&lt;/b&gt;
&lt;b&gt;&lt;span style="color: green;"&gt;     * Sets the cell as corresponding to some point inside it (can be used for&lt;/span&gt;&lt;/b&gt;
&lt;b&gt;&lt;span style="color: green;"&gt;     * e.g. mouse picking).&lt;/span&gt;&lt;/b&gt;
&lt;i&gt;&lt;span style="color: green;"&gt;     &lt;/span&gt;&lt;/i&gt;&lt;b&gt;&lt;span style="color: green;"&gt;*/&lt;/span&gt;&lt;/b&gt;
    &lt;b&gt;public&lt;/b&gt; &lt;span style="color: #0057ae;"&gt;void&lt;/span&gt; &lt;span style="color: #644a9b;"&gt;setCellByPoint&lt;/span&gt;(&lt;span style="color: #0057ae;"&gt;int&lt;/span&gt; x, &lt;span style="color: #0057ae;"&gt;int&lt;/span&gt; y) {
        &lt;span style="color: #0057ae;"&gt;int&lt;/span&gt; ci = (&lt;span style="color: #0057ae;"&gt;int&lt;/span&gt;)&lt;b&gt;&lt;span style="color: #0095ff;"&gt;Math&lt;/span&gt;&lt;/b&gt;.&lt;span style="color: #644a9b;"&gt;floor&lt;/span&gt;((&lt;span style="color: #0057ae;"&gt;float&lt;/span&gt;)x/(&lt;span style="color: #0057ae;"&gt;float&lt;/span&gt;)SIDE);
        &lt;span style="color: #0057ae;"&gt;int&lt;/span&gt; cx = x - SIDE*ci;

        &lt;span style="color: #0057ae;"&gt;int&lt;/span&gt; ty = y - (ci % &lt;span style="color: #b08000;"&gt;2&lt;/span&gt;) * HEIGHT / &lt;span style="color: #b08000;"&gt;2&lt;/span&gt;;
        &lt;span style="color: #0057ae;"&gt;int&lt;/span&gt; cj = (&lt;span style="color: #0057ae;"&gt;int&lt;/span&gt;)&lt;b&gt;&lt;span style="color: #0095ff;"&gt;Math&lt;/span&gt;&lt;/b&gt;.&lt;span style="color: #644a9b;"&gt;floor&lt;/span&gt;((&lt;span style="color: #0057ae;"&gt;float&lt;/span&gt;)ty/(&lt;span style="color: #0057ae;"&gt;float&lt;/span&gt;)HEIGHT);
        &lt;span style="color: #0057ae;"&gt;int&lt;/span&gt; cy = ty - HEIGHT*cj;

        &lt;b&gt;if&lt;/b&gt; (cx &amp;gt; &lt;b&gt;&lt;span style="color: #0095ff;"&gt;Math&lt;/span&gt;&lt;/b&gt;.&lt;span style="color: #644a9b;"&gt;abs&lt;/span&gt;(RADIUS / &lt;span style="color: #b08000;"&gt;2&lt;/span&gt; - RADIUS * cy / HEIGHT)) {
            &lt;span style="color: #644a9b;"&gt;setCellIndex&lt;/span&gt;(ci, cj);
        } &lt;b&gt;else&lt;/b&gt; {
            &lt;span style="color: #644a9b;"&gt;setCellIndex&lt;/span&gt;(ci - &lt;span style="color: #b08000;"&gt;1&lt;/span&gt;, cj + (ci % &lt;span style="color: #b08000;"&gt;2&lt;/span&gt;) - ((cy &amp;lt; HEIGHT / &lt;span style="color: #b08000;"&gt;2&lt;/span&gt;) ? &lt;span style="color: #b08000;"&gt;1&lt;/span&gt; : &lt;span style="color: #b08000;"&gt;0&lt;/span&gt;));
        }
    }
}
&lt;/pre&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;br /&gt;
&lt;h4&gt;

Testing the code&lt;/h4&gt;
To test the code I've written a small Java applet.
&lt;br /&gt;
&lt;br /&gt;
It's a hexagonal version of the game called &lt;a href="http://en.wikipedia.org/wiki/Lights_Out_%28game%29"&gt;"Lights Out"&lt;/a&gt; (the idea of which I've borrowed from &lt;a href="https://sites.google.com/site/beyondlightsout/"&gt;here&lt;/a&gt;).
&lt;br /&gt;
&lt;br /&gt;
One starts the game with all the "lights" on (all the hexagons are yellow), and the goal is to switch all of them off (so all the hexagons become gray).
&lt;br /&gt;&lt;br /&gt;
&lt;center&gt;&lt;img border="0" src="http://1.bp.blogspot.com/-DuU5HlI4TbU/TVo1qDG0hNI/AAAAAAAAAfI/Fr3-LGPI8Ts/s400/lights_out.png" /&gt;&lt;/center&gt;

&lt;br /&gt;
Whenever user clicks on a hexagon, it toggles its light, together with all the neighbor hexagons.
&lt;br /&gt;
&lt;br /&gt;
&lt;div style="height: 520px; overflow: auto; width: 100%;"&gt;
&lt;table cellpadding="0" cellspacing="0" style="width: 420px;"&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;pre style="background-color: white; color: #181615; font-size: 8pt; line-height: 13px;"&gt;&lt;b&gt;package&lt;/b&gt;&lt;span style="color: olive;"&gt; com.rush;&lt;/span&gt;

&lt;b&gt;import&lt;/b&gt;&lt;span style="color: olive;"&gt; java.applet.Applet;&lt;/span&gt;
&lt;b&gt;import&lt;/b&gt;&lt;span style="color: olive;"&gt; java.awt.Color;&lt;/span&gt;
&lt;b&gt;import&lt;/b&gt;&lt;span style="color: olive;"&gt; java.awt.Graphics;&lt;/span&gt;
&lt;b&gt;import&lt;/b&gt;&lt;span style="color: olive;"&gt; java.awt.event.MouseEvent;&lt;/span&gt;
&lt;b&gt;import&lt;/b&gt;&lt;span style="color: olive;"&gt; java.awt.event.MouseListener;&lt;/span&gt;

&lt;b&gt;import&lt;/b&gt;&lt;span style="color: olive;"&gt; javax.swing.JFrame;&lt;/span&gt;
&lt;b&gt;import&lt;/b&gt;&lt;span style="color: olive;"&gt; javax.swing.JOptionPane;&lt;/span&gt;

&lt;b&gt;&lt;span style="color: green;"&gt;/**&lt;/span&gt;&lt;/b&gt;
&lt;b&gt;&lt;span style="color: green;"&gt; * Example applet which uses hexagonal grid. &lt;/span&gt;&lt;/b&gt;&lt;span style="color: green;"&gt;It's a hexagonal version of the&lt;/span&gt;
&lt;span style="color: green;"&gt; &lt;/span&gt;&lt;b&gt;&lt;span style="color: green;"&gt;*&lt;/span&gt;&lt;/b&gt;&lt;span style="color: green;"&gt; "lights out" puzzle game: http://en.wikipedia.org/wiki/Lights_Out_(game)&lt;/span&gt;
&lt;span style="color: green;"&gt; &lt;/span&gt;&lt;b&gt;&lt;span style="color: green;"&gt;*/&lt;/span&gt;&lt;/b&gt;
&lt;b&gt;public&lt;/b&gt; &lt;b&gt;class&lt;/b&gt; HexLightsOut &lt;b&gt;extends&lt;/b&gt; &lt;b&gt;&lt;span style="color: #0095ff;"&gt;Applet&lt;/span&gt;&lt;/b&gt; &lt;b&gt;implements&lt;/b&gt; &lt;b&gt;&lt;span style="color: #0095ff;"&gt;MouseListener&lt;/span&gt;&lt;/b&gt; {
    &lt;b&gt;private&lt;/b&gt; &lt;span style="color: #0057ae;"&gt;static&lt;/span&gt; &lt;span style="color: #0057ae;"&gt;final&lt;/span&gt; &lt;span style="color: #0057ae;"&gt;long&lt;/span&gt; serialVersionUID = &lt;span style="color: #b08000;"&gt;1L&lt;/span&gt;;

    &lt;b&gt;private&lt;/b&gt; &lt;span style="color: #0057ae;"&gt;static&lt;/span&gt; &lt;span style="color: #0057ae;"&gt;final&lt;/span&gt; &lt;span style="color: #0057ae;"&gt;int&lt;/span&gt; BOARD_WIDTH = &lt;span style="color: #b08000;"&gt;5&lt;/span&gt;;
    &lt;b&gt;private&lt;/b&gt; &lt;span style="color: #0057ae;"&gt;static&lt;/span&gt; &lt;span style="color: #0057ae;"&gt;final&lt;/span&gt; &lt;span style="color: #0057ae;"&gt;int&lt;/span&gt; BOARD_HEIGHT = &lt;span style="color: #b08000;"&gt;4&lt;/span&gt;;

    &lt;b&gt;private&lt;/b&gt; &lt;span style="color: #0057ae;"&gt;static&lt;/span&gt; &lt;span style="color: #0057ae;"&gt;final&lt;/span&gt; &lt;span style="color: #0057ae;"&gt;int&lt;/span&gt; L_ON = &lt;span style="color: #b08000;"&gt;1&lt;/span&gt;;
    &lt;b&gt;private&lt;/b&gt; &lt;span style="color: #0057ae;"&gt;static&lt;/span&gt; &lt;span style="color: #0057ae;"&gt;final&lt;/span&gt; &lt;span style="color: #0057ae;"&gt;int&lt;/span&gt; L_OFF = &lt;span style="color: #b08000;"&gt;2&lt;/span&gt;;

    &lt;b&gt;private&lt;/b&gt; &lt;span style="color: #0057ae;"&gt;static&lt;/span&gt; &lt;span style="color: #0057ae;"&gt;final&lt;/span&gt; &lt;span style="color: #0057ae;"&gt;int&lt;/span&gt; NUM_HEX_CORNERS = &lt;span style="color: #b08000;"&gt;6&lt;/span&gt;;
    &lt;b&gt;private&lt;/b&gt; &lt;span style="color: #0057ae;"&gt;static&lt;/span&gt; &lt;span style="color: #0057ae;"&gt;final&lt;/span&gt; &lt;span style="color: #0057ae;"&gt;int&lt;/span&gt; CELL_RADIUS = &lt;span style="color: #b08000;"&gt;40&lt;/span&gt;;

    &lt;i&gt;&lt;span style="color: #898887;"&gt;//  game board cells array&lt;/span&gt;&lt;/i&gt;
    &lt;b&gt;private&lt;/b&gt; &lt;span style="color: #0057ae;"&gt;int&lt;/span&gt;[][] mCells = { {    &lt;span style="color: #b08000;"&gt;0&lt;/span&gt;, L_ON, L_ON, L_ON,    &lt;span style="color: #b08000;"&gt;0&lt;/span&gt; }, 
                               { L_ON, L_ON, L_ON, L_ON, L_ON }, 
                               { L_ON, L_ON, L_ON, L_ON, L_ON },
                               {    &lt;span style="color: #b08000;"&gt;0&lt;/span&gt;,    &lt;span style="color: #b08000;"&gt;0&lt;/span&gt;, L_ON,    &lt;span style="color: #b08000;"&gt;0&lt;/span&gt;,    &lt;span style="color: #b08000;"&gt;0&lt;/span&gt; } };

    &lt;b&gt;private&lt;/b&gt; &lt;span style="color: #0057ae;"&gt;int&lt;/span&gt;[] mCornersX = &lt;b&gt;new&lt;/b&gt; &lt;span style="color: #0057ae;"&gt;int&lt;/span&gt;[NUM_HEX_CORNERS];
    &lt;b&gt;private&lt;/b&gt; &lt;span style="color: #0057ae;"&gt;int&lt;/span&gt;[] mCornersY = &lt;b&gt;new&lt;/b&gt; &lt;span style="color: #0057ae;"&gt;int&lt;/span&gt;[NUM_HEX_CORNERS];

    &lt;b&gt;private&lt;/b&gt; &lt;span style="color: #0057ae;"&gt;static&lt;/span&gt; HexGridCell mCellMetrics = &lt;b&gt;new&lt;/b&gt; &lt;span style="color: #644a9b;"&gt;HexGridCell&lt;/span&gt;(CELL_RADIUS);

    @Override
    &lt;b&gt;public&lt;/b&gt; &lt;span style="color: #0057ae;"&gt;void&lt;/span&gt; &lt;span style="color: #644a9b;"&gt;init&lt;/span&gt;() {
        &lt;span style="color: #644a9b;"&gt;addMouseListener&lt;/span&gt;(&lt;b&gt;this&lt;/b&gt;);
    }

    @Override
    &lt;b&gt;public&lt;/b&gt; &lt;span style="color: #0057ae;"&gt;void&lt;/span&gt; &lt;span style="color: #644a9b;"&gt;paint&lt;/span&gt;(&lt;b&gt;&lt;span style="color: #0095ff;"&gt;Graphics&lt;/span&gt;&lt;/b&gt; g) {
        &lt;b&gt;for&lt;/b&gt; (&lt;span style="color: #0057ae;"&gt;int&lt;/span&gt; j = &lt;span style="color: #b08000;"&gt;0&lt;/span&gt;; j &amp;lt; BOARD_HEIGHT; j++) {
            &lt;b&gt;for&lt;/b&gt; (&lt;span style="color: #0057ae;"&gt;int&lt;/span&gt; i = &lt;span style="color: #b08000;"&gt;0&lt;/span&gt;; i &amp;lt; BOARD_WIDTH; i++) {
                mCellMetrics.&lt;span style="color: #644a9b;"&gt;setCellIndex&lt;/span&gt;(i, j);
                &lt;b&gt;if&lt;/b&gt; (mCells[j][i] != &lt;span style="color: #b08000;"&gt;0&lt;/span&gt;) {
                    mCellMetrics.&lt;span style="color: #644a9b;"&gt;computeCorners&lt;/span&gt;(mCornersX, mCornersY);

                    g.&lt;span style="color: #644a9b;"&gt;setColor&lt;/span&gt;((mCells[j][i] == L_ON) ? &lt;b&gt;&lt;span style="color: #0095ff;"&gt;Color&lt;/span&gt;&lt;/b&gt;.&lt;span style="color: #644a9b;"&gt;ORANGE&lt;/span&gt; : &lt;b&gt;&lt;span style="color: #0095ff;"&gt;Color&lt;/span&gt;&lt;/b&gt;.&lt;span style="color: #644a9b;"&gt;GRAY&lt;/span&gt;);
                    g.&lt;span style="color: #644a9b;"&gt;fillPolygon&lt;/span&gt;(mCornersX, mCornersY, NUM_HEX_CORNERS);
                    g.&lt;span style="color: #644a9b;"&gt;setColor&lt;/span&gt;(&lt;b&gt;&lt;span style="color: #0095ff;"&gt;Color&lt;/span&gt;&lt;/b&gt;.&lt;span style="color: #644a9b;"&gt;BLACK&lt;/span&gt;);
                    g.&lt;span style="color: #644a9b;"&gt;drawPolygon&lt;/span&gt;(mCornersX, mCornersY, NUM_HEX_CORNERS);
                }
            }
        }
    }

    @Override
    &lt;b&gt;public&lt;/b&gt; &lt;span style="color: #0057ae;"&gt;void&lt;/span&gt; &lt;span style="color: #644a9b;"&gt;update&lt;/span&gt;(&lt;b&gt;&lt;span style="color: #0095ff;"&gt;Graphics&lt;/span&gt;&lt;/b&gt; g) {
        &lt;span style="color: #644a9b;"&gt;paint&lt;/span&gt;(g);
    }

    &lt;b&gt;&lt;span style="color: green;"&gt;/**&lt;/span&gt;&lt;/b&gt;
&lt;b&gt;&lt;span style="color: green;"&gt;     * Returns true if the cell is inside the game board.&lt;/span&gt;&lt;/b&gt;
&lt;i&gt;&lt;span style="color: green;"&gt;     &lt;/span&gt;&lt;/i&gt;&lt;b&gt;&lt;span style="color: green;"&gt;*&lt;/span&gt;&lt;/b&gt;&lt;i&gt;&lt;span style="color: green;"&gt; &lt;/span&gt;&lt;/i&gt;
&lt;i&gt;&lt;span style="color: green;"&gt;     &lt;/span&gt;&lt;/i&gt;&lt;b&gt;&lt;span style="color: green;"&gt;*&lt;/span&gt;&lt;/b&gt;&lt;i&gt;&lt;span style="color: green;"&gt; &lt;/span&gt;&lt;/i&gt;&lt;b&gt;&lt;span style="color: grey;"&gt;@param &lt;/span&gt;&lt;/b&gt;&lt;i&gt;&lt;span style="color: teal;"&gt;i &lt;/span&gt;&lt;/i&gt;&lt;i&gt;&lt;span style="color: green;"&gt;cell's horizontal index&lt;/span&gt;&lt;/i&gt;
&lt;i&gt;&lt;span style="color: green;"&gt;     &lt;/span&gt;&lt;/i&gt;&lt;b&gt;&lt;span style="color: green;"&gt;*&lt;/span&gt;&lt;/b&gt;&lt;i&gt;&lt;span style="color: green;"&gt; &lt;/span&gt;&lt;/i&gt;&lt;b&gt;&lt;span style="color: grey;"&gt;@param &lt;/span&gt;&lt;/b&gt;&lt;i&gt;&lt;span style="color: teal;"&gt;j &lt;/span&gt;&lt;/i&gt;&lt;i&gt;&lt;span style="color: green;"&gt;cell's vertical index&lt;/span&gt;&lt;/i&gt;
&lt;i&gt;&lt;span style="color: green;"&gt;     &lt;/span&gt;&lt;/i&gt;&lt;b&gt;&lt;span style="color: green;"&gt;*/&lt;/span&gt;&lt;/b&gt;
    &lt;b&gt;private&lt;/b&gt; &lt;span style="color: #0057ae;"&gt;boolean&lt;/span&gt; &lt;span style="color: #644a9b;"&gt;isInsideBoard&lt;/span&gt;(&lt;span style="color: #0057ae;"&gt;int&lt;/span&gt; i, &lt;span style="color: #0057ae;"&gt;int&lt;/span&gt; j) {
        &lt;b&gt;return&lt;/b&gt; i &amp;gt;= &lt;span style="color: #b08000;"&gt;0&lt;/span&gt; &amp;amp;&amp;amp; i &amp;lt; BOARD_WIDTH &amp;amp;&amp;amp; j &amp;gt;= &lt;span style="color: #b08000;"&gt;0&lt;/span&gt; &amp;amp;&amp;amp; j &amp;lt; BOARD_HEIGHT
                &amp;amp;&amp;amp; mCells[j][i] != &lt;span style="color: #b08000;"&gt;0&lt;/span&gt;;
    }

    &lt;b&gt;&lt;span style="color: green;"&gt;/**&lt;/span&gt;&lt;/b&gt;
&lt;b&gt;&lt;span style="color: green;"&gt;     * Toggles the cell's light ON&lt;/span&gt;&lt;/b&gt;&lt;span style="color: #bf0303;"&gt;&amp;lt;&lt;/span&gt;&lt;b&gt;&lt;span style="color: green;"&gt;-&amp;gt;OFF.&lt;/span&gt;&lt;/b&gt;
&lt;i&gt;&lt;span style="color: green;"&gt;     &lt;/span&gt;&lt;/i&gt;&lt;b&gt;&lt;span style="color: green;"&gt;*/&lt;/span&gt;&lt;/b&gt;
    &lt;b&gt;private&lt;/b&gt; &lt;span style="color: #0057ae;"&gt;void&lt;/span&gt; &lt;span style="color: #644a9b;"&gt;toggleCell&lt;/span&gt;(&lt;span style="color: #0057ae;"&gt;int&lt;/span&gt; i, &lt;span style="color: #0057ae;"&gt;int&lt;/span&gt; j) {
        mCells[j][i] = (mCells[j][i] == L_ON) ? L_OFF : L_ON;
    }

    &lt;b&gt;&lt;span style="color: green;"&gt;/**&lt;/span&gt;&lt;/b&gt;
&lt;b&gt;&lt;span style="color: green;"&gt;     * Returns true if all lights have been switched off.&lt;/span&gt;&lt;/b&gt;
&lt;i&gt;&lt;span style="color: green;"&gt;     &lt;/span&gt;&lt;/i&gt;&lt;b&gt;&lt;span style="color: green;"&gt;*/&lt;/span&gt;&lt;/b&gt;
    &lt;b&gt;private&lt;/b&gt; &lt;span style="color: #0057ae;"&gt;boolean&lt;/span&gt; &lt;span style="color: #644a9b;"&gt;isWinCondition&lt;/span&gt;() {
        &lt;b&gt;for&lt;/b&gt; (&lt;span style="color: #0057ae;"&gt;int&lt;/span&gt; j = &lt;span style="color: #b08000;"&gt;0&lt;/span&gt;; j &amp;lt; BOARD_HEIGHT; j++) {
            &lt;b&gt;for&lt;/b&gt; (&lt;span style="color: #0057ae;"&gt;int&lt;/span&gt; i = &lt;span style="color: #b08000;"&gt;0&lt;/span&gt;; i &amp;lt; BOARD_WIDTH; i++) {
                &lt;b&gt;if&lt;/b&gt; (mCells[j][i] == L_ON) {
                    &lt;b&gt;return&lt;/b&gt; &lt;b&gt;false&lt;/b&gt;;
                }
            }
        }
        &lt;b&gt;return&lt;/b&gt; &lt;b&gt;true&lt;/b&gt;;
    }

    &lt;b&gt;&lt;span style="color: green;"&gt;/**&lt;/span&gt;&lt;/b&gt;
&lt;b&gt;&lt;span style="color: green;"&gt;     * Resets the game to the initial position (all lights are on).&lt;/span&gt;&lt;/b&gt;
&lt;i&gt;&lt;span style="color: green;"&gt;     &lt;/span&gt;&lt;/i&gt;&lt;b&gt;&lt;span style="color: green;"&gt;*/&lt;/span&gt;&lt;/b&gt;
    &lt;b&gt;private&lt;/b&gt; &lt;span style="color: #0057ae;"&gt;void&lt;/span&gt; &lt;span style="color: #644a9b;"&gt;resetGame&lt;/span&gt;() {
        &lt;b&gt;for&lt;/b&gt; (&lt;span style="color: #0057ae;"&gt;int&lt;/span&gt; j = &lt;span style="color: #b08000;"&gt;0&lt;/span&gt;; j &amp;lt; BOARD_HEIGHT; j++) {
            &lt;b&gt;for&lt;/b&gt; (&lt;span style="color: #0057ae;"&gt;int&lt;/span&gt; i = &lt;span style="color: #b08000;"&gt;0&lt;/span&gt;; i &amp;lt; BOARD_WIDTH; i++) {
                &lt;b&gt;if&lt;/b&gt; (mCells[j][i] == L_OFF) {
                    mCells[j][i] = L_ON;
                }
            }
        }
    }

    @Override
    &lt;b&gt;public&lt;/b&gt; &lt;span style="color: #0057ae;"&gt;void&lt;/span&gt; &lt;span style="color: #644a9b;"&gt;mouseReleased&lt;/span&gt;(&lt;b&gt;&lt;span style="color: #0095ff;"&gt;MouseEvent&lt;/span&gt;&lt;/b&gt; arg0) {
        mCellMetrics.&lt;span style="color: #644a9b;"&gt;setCellByPoint&lt;/span&gt;(arg0.&lt;span style="color: #644a9b;"&gt;getX&lt;/span&gt;(), arg0.&lt;span style="color: #644a9b;"&gt;getY&lt;/span&gt;());
        &lt;span style="color: #0057ae;"&gt;int&lt;/span&gt; clickI = mCellMetrics.&lt;span style="color: #644a9b;"&gt;getIndexI&lt;/span&gt;();
        &lt;span style="color: #0057ae;"&gt;int&lt;/span&gt; clickJ = mCellMetrics.&lt;span style="color: #644a9b;"&gt;getIndexJ&lt;/span&gt;();

        &lt;b&gt;if&lt;/b&gt; (&lt;span style="color: #644a9b;"&gt;isInsideBoard&lt;/span&gt;(clickI, clickJ)) {
            &lt;i&gt;&lt;span style="color: #898887;"&gt;// toggle the clicked cell together with the neighbors&lt;/span&gt;&lt;/i&gt;
            &lt;span style="color: #644a9b;"&gt;toggleCell&lt;/span&gt;(clickI, clickJ);
            &lt;b&gt;for&lt;/b&gt; (&lt;span style="color: #0057ae;"&gt;int&lt;/span&gt; k = &lt;span style="color: #b08000;"&gt;0&lt;/span&gt;; k &amp;lt; &lt;span style="color: #b08000;"&gt;6&lt;/span&gt;; k++) {
                &lt;span style="color: #0057ae;"&gt;int&lt;/span&gt; nI = mCellMetrics.&lt;span style="color: #644a9b;"&gt;getNeighborI&lt;/span&gt;(k);
                &lt;span style="color: #0057ae;"&gt;int&lt;/span&gt; nJ = mCellMetrics.&lt;span style="color: #644a9b;"&gt;getNeighborJ&lt;/span&gt;(k);
                &lt;b&gt;if&lt;/b&gt; (&lt;span style="color: #644a9b;"&gt;isInsideBoard&lt;/span&gt;(nI, nJ)) {
                    &lt;span style="color: #644a9b;"&gt;toggleCell&lt;/span&gt;(nI, nJ);
                }
            }
        }
        &lt;span style="color: #644a9b;"&gt;repaint&lt;/span&gt;();

        &lt;b&gt;if&lt;/b&gt; (&lt;span style="color: #644a9b;"&gt;isWinCondition&lt;/span&gt;()) {
            &lt;b&gt;&lt;span style="color: #0095ff;"&gt;JOptionPane&lt;/span&gt;&lt;/b&gt;.&lt;span style="color: #644a9b;"&gt;showMessageDialog&lt;/span&gt;(&lt;b&gt;new&lt;/b&gt; &lt;b&gt;&lt;span style="color: #0095ff;"&gt;JFrame&lt;/span&gt;&lt;/b&gt;(), &lt;span style="color: #bf0303;"&gt;"Well done!"&lt;/span&gt;);
            &lt;span style="color: #644a9b;"&gt;resetGame&lt;/span&gt;();
            &lt;span style="color: #644a9b;"&gt;repaint&lt;/span&gt;();
        }
    }

    @Override
    &lt;b&gt;public&lt;/b&gt; &lt;span style="color: #0057ae;"&gt;void&lt;/span&gt; &lt;span style="color: #644a9b;"&gt;mouseClicked&lt;/span&gt;(&lt;b&gt;&lt;span style="color: #0095ff;"&gt;MouseEvent&lt;/span&gt;&lt;/b&gt; arg0) {
    }

    @Override
    &lt;b&gt;public&lt;/b&gt; &lt;span style="color: #0057ae;"&gt;void&lt;/span&gt; &lt;span style="color: #644a9b;"&gt;mouseEntered&lt;/span&gt;(&lt;b&gt;&lt;span style="color: #0095ff;"&gt;MouseEvent&lt;/span&gt;&lt;/b&gt; arg0) {
    }

    @Override
    &lt;b&gt;public&lt;/b&gt; &lt;span style="color: #0057ae;"&gt;void&lt;/span&gt; &lt;span style="color: #644a9b;"&gt;mouseExited&lt;/span&gt;(&lt;b&gt;&lt;span style="color: #0095ff;"&gt;MouseEvent&lt;/span&gt;&lt;/b&gt; arg0) {
    }

    @Override
    &lt;b&gt;public&lt;/b&gt; &lt;span style="color: #0057ae;"&gt;void&lt;/span&gt; &lt;span style="color: #644a9b;"&gt;mousePressed&lt;/span&gt;(&lt;b&gt;&lt;span style="color: #0095ff;"&gt;MouseEvent&lt;/span&gt;&lt;/b&gt; arg0) {
    }
}

&lt;/pre&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
The source is also &lt;a href="https://github.com/silverio/samples/tree/master/HexLightsOut"&gt;available on github&lt;/a&gt;.

&lt;br /&gt;&lt;br /&gt;
The applet in action can be seen &lt;a href="http://digitalcucumbers.com/HexLightsOut/HexLightsOut.html"&gt;here&lt;/a&gt; (all the usual java applet related disclaimers apply).
&lt;br /&gt;&lt;br /&gt;
&lt;b&gt;UPDATE:&lt;/b&gt; Ferris Thomas made &lt;a href="https://github.com/FSThomas/HexLightsOut"&gt;an ActionScript 3 port of the code&lt;/a&gt;, kudos for that!
&lt;br /&gt;&lt;br /&gt;
Additional thanks to Ruurd for spotting typos in the formulas.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/923082020090979517-5216127610412629335?l=blog.ruslans.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/gd_reflections/~4/5ZhMl44N07Q" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.ruslans.com/feeds/5216127610412629335/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=923082020090979517&amp;postID=5216127610412629335" title="18 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/923082020090979517/posts/default/5216127610412629335" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/923082020090979517/posts/default/5216127610412629335" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/gd_reflections/~3/5ZhMl44N07Q/hexagonal-grid-math.html" title="Hexagonal grid math" /><author><name>ruslans</name><uri>http://www.blogger.com/profile/03375859473751956887</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="24" height="32" src="http://2.bp.blogspot.com/_DVYH9neSnMw/S0V_XM6aN0I/AAAAAAAAAMc/06dTTnY0PNw/S220/avatar3.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/-uhf5CIhqUF4/TVo0NzhZqzI/AAAAAAAAAeQ/0uOx6f0ApcI/s72-c/hex_single.png" height="72" width="72" /><thr:total>18</thr:total><feedburner:origLink>http://blog.ruslans.com/2011/02/hexagonal-grid-math.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-923082020090979517.post-697620140032757759</id><published>2010-12-06T10:02:00.000-08:00</published><updated>2010-12-17T02:32:39.674-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="qml" /><category scheme="http://www.blogger.com/atom/ns#" term="tutorial" /><category scheme="http://www.blogger.com/atom/ns#" term="qt" /><category scheme="http://www.blogger.com/atom/ns#" term="scripting" /><title type="text">A cute quick colorpicker</title><content type="html">&lt;a class="c1" href="http://3.bp.blogspot.com/_DVYH9neSnMw/TP0gbayddNI/AAAAAAAAAcI/8j2lETO8ENs/s1600/cp_final.jpg" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" height="151" src="http://3.bp.blogspot.com/_DVYH9neSnMw/TP0gbayddNI/AAAAAAAAAcI/8j2lETO8ENs/s1600/cp_final.jpg" width="203" /&gt;&lt;/a&gt;&lt;br /&gt;
Declarative user interface programming is slowly becoming a mainstream, being backed by technologies like &lt;a href="http://en.wikipedia.org/wiki/Windows_Presentation_Foundation"&gt;WPF&lt;/a&gt;, &lt;a href="http://en.wikipedia.org/wiki/Javafx"&gt;JavaFX&lt;/a&gt;, &lt;a href="http://livedocs.adobe.com/flex/3/html/help.html?content=databinding_1.html"&gt;Flex&lt;/a&gt;&amp;nbsp;and others.&lt;br /&gt;
&lt;br /&gt;
And now Qt is catching up with &lt;a href="http://doc.qt.nokia.com/4.7/qtquick.html"&gt;Qt Quick&lt;/a&gt; and &lt;a href="http://en.wikipedia.org/wiki/QML"&gt;QML&lt;/a&gt;. 
&lt;br /&gt;
&lt;br /&gt;
While the basic ideas behind it are pretty similar to what we've already seen in those other technologies, there are several things which potentially can make it stand out, not the last one being the fact that Qt is open-source and multi-platform and that Qt Quick is naturally built on top of the solid, tried and true Qt Framework. 
&lt;br /&gt;
&lt;br /&gt;
There is hardly a better way of getting the impression of some technology than just trying to make something functional with it, struggling your way through the documentation/examples and counting the number of hoops to jump through in the process.
&lt;br /&gt;
&lt;br /&gt;
So let's try and make a simple QML colorpicker control from scratch, just for the hell of it.
&lt;br /&gt;
&lt;br /&gt;
The first step is, obviously, &lt;a href="http://qt.nokia.com/downloads"&gt;downloading&lt;/a&gt; and installing Qt SDK (at the time of writing it was Qt Creator 2.0.1 with Qt Libraries 4.7.0). 
Run it and create a new QML project, named "colorpicker" (File-&amp;gt; New File or Project... -&amp;gt; Qt Quick Project -&amp;gt; Qt Quick UI -&amp;gt; Choose...).
&lt;br /&gt;
&lt;br /&gt;
After we're done, the final code can be found &lt;a href="https://github.com/silverio/qt/tree/master/colorpicker"&gt;here&lt;/a&gt;.
&lt;br /&gt;
&lt;h1&gt;





Act 1&lt;/h1&gt;
&lt;h3&gt;





Scene 0&lt;/h3&gt;
&lt;i&gt;Enter Rectangle, Gradient.&lt;/i&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://www.blogger.com/post-create.g?blogID=923082020090979517" style="clear: left; float: right;"&gt;&lt;img src="http://3.bp.blogspot.com/_DVYH9neSnMw/TP0gZF2EZYI/AAAAAAAAAbs/Rwy2LK6vViA/s1600/act0_redsq.png" /&gt;&lt;/a&gt;
It all starts with a simple square, filled with a white-red gradient (so it does not appear completely dull).
&lt;br /&gt;
&lt;br /&gt;
QML script essentially descibes a hierarchy of objects, with a single root element.
Every object can have nested children objects, as well as a list of property values.   
&lt;br /&gt;
&lt;br /&gt;
That's pretty common way of specifying what the UI's logical structure &lt;i&gt;is&lt;/i&gt; (e.g. &lt;a href="http://en.wikipedia.org/wiki/Extensible_Application_Markup_Language"&gt;XAML&lt;/a&gt; does the same thing via XML with its tags and attributes).
The "is" part here is essential, because that's where "declarative" comes from (as opposed to imperative code, which describes what something "does"). 
&lt;br /&gt;
&lt;br /&gt;
We make  a  &lt;b&gt;Rectangle&lt;/b&gt; as a root element, tell that its "width" and "height" properties should be 120 pixels, and it's "gradient" property (which is by default a vertical gradient, from top to bottom) is itself a &lt;b&gt;Gradient&lt;/b&gt; object, going from "white" to "red" color (those colors are in turn described inside &lt;b&gt;GradientStop&lt;/b&gt; objects, its children):  
&lt;br /&gt;
&lt;pre style="background-color: white; color: #181615; font-size: 8pt; line-height: 13px;"&gt;&lt;b&gt;import&lt;/b&gt;&lt;span style="color: #bf0303;"&gt; Qt 4.7&lt;/span&gt;
&lt;span style="color: green;"&gt;Rectangle&lt;/span&gt; {
    &lt;span style="color: #0057ae;"&gt;width&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;120&lt;/span&gt;; &lt;span style="color: #0057ae;"&gt;height&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;120&lt;/span&gt;
    &lt;span style="color: #0057ae;"&gt;gradient&lt;/span&gt;: &lt;span style="color: green;"&gt;Gradient&lt;/span&gt; {
        &lt;span style="color: green;"&gt;GradientStop&lt;/span&gt; { &lt;span style="color: #0057ae;"&gt;position&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;0.0&lt;/span&gt;; &lt;span style="color: #0057ae;"&gt;color&lt;/span&gt;: &lt;span style="color: #bf0303;"&gt;"white"&lt;/span&gt; }
        &lt;span style="color: green;"&gt;GradientStop&lt;/span&gt; { &lt;span style="color: #0057ae;"&gt;position&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;1.0&lt;/span&gt;; &lt;span style="color: #0057ae;"&gt;color&lt;/span&gt;: &lt;span style="color: #bf0303;"&gt;"red"&lt;/span&gt; }
    }
}&lt;/pre&gt;
Pressing Ctrl+R will open the QML Viewer window, which would show the result.
&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;





Scene 1&lt;/h3&gt;
&lt;i&gt;Enter Rotation, Anchors, Blending, Color Notation.&lt;/i&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;a class="c1" href="http://www.blogger.com/post-create.g?blogID=923082020090979517" style="clear: left; float: right;"&gt;&lt;img src="http://3.bp.blogspot.com/_DVYH9neSnMw/TP0gZhRiOcI/AAAAAAAAAbw/tQFf4h4CBCo/s1600/act1_grad.png" /&gt;&lt;/a&gt;
Now, let's try to mimic the saturation/brightness picking area appearance. For that we take our red/white square, rotate it by 90 degrees, and blend a black square on top, with a gradient alpha.  
&lt;br /&gt;
&lt;br /&gt;
Here we use an alternate color representation, as a string in a form "#RRGGBB" or "#AARRGGBB" (where, "AA" stands for "transparency", or "alpha").
&lt;br /&gt;
&lt;br /&gt;
&lt;a class="c1" href="http://www.blogger.com/post-create.g?blogID=923082020090979517" style="clear: left; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/_DVYH9neSnMw/TP0gcRg5e1I/AAAAAAAAAcU/OAMEMuqLFOc/s1600/sb_gradient_combine.jpg" /&gt;&lt;/a&gt;
We'll stuff both rectangles as children of a common parent object, an &lt;b&gt;Item&lt;/b&gt;, which is a base visual object type in QML (all other types, including Rectangle, derive from it). It handles basic positioning and size, and also is often used as a lookless grouping container for other objects.
&lt;br /&gt;
&lt;br /&gt;
We'd explicitly specify the size only for this top-level object, and for the children rectangles use the  "anchors.fill" property, which means "use the same size as some other object", the other object in this case being the "parent" object (in fact, here we see the first example of the &lt;i&gt;property binding&lt;/i&gt; in action. Besides, the "." in the property name means that property is an &lt;i&gt;attached property&lt;/i&gt;... but let's ignore these gory details for now):

&lt;br /&gt;
&lt;pre style="background-color: white; color: #181615; font-size: 8pt; line-height: 13px;"&gt;&lt;b&gt;import&lt;/b&gt;&lt;span style="color: #bf0303;"&gt; Qt 4.7&lt;/span&gt;
&lt;span style="color: green;"&gt;Item&lt;/span&gt; {
    &lt;span style="color: #0057ae;"&gt;width&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;120&lt;/span&gt;; &lt;span style="color: #0057ae;"&gt;height&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;120&lt;/span&gt;
    &lt;span style="color: green;"&gt;Rectangle&lt;/span&gt; {
        &lt;span style="color: #0057ae;"&gt;anchors.fill&lt;/span&gt;: parent;
        &lt;span style="color: #0057ae;"&gt;rotation&lt;/span&gt;: -&lt;span style="color: #b08000;"&gt;90&lt;/span&gt;
        &lt;span style="color: #0057ae;"&gt;gradient&lt;/span&gt;: &lt;span style="color: green;"&gt;Gradient&lt;/span&gt; {
            &lt;span style="color: green;"&gt;GradientStop&lt;/span&gt; {
                &lt;span style="color: #0057ae;"&gt;position&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;0.0&lt;/span&gt;; &lt;span style="color: #0057ae;"&gt;color&lt;/span&gt;: &lt;span style="color: #bf0303;"&gt;"#FFFFFFFF"&lt;/span&gt;
            }
            &lt;span style="color: green;"&gt;GradientStop&lt;/span&gt; {
                &lt;span style="color: #0057ae;"&gt;position&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;1.0&lt;/span&gt;; &lt;span style="color: #0057ae;"&gt;color&lt;/span&gt;: &lt;span style="color: #bf0303;"&gt;"#FFFF0000"&lt;/span&gt;
            }
        }
    }
    &lt;span style="color: green;"&gt;Rectangle&lt;/span&gt; {
        &lt;span style="color: #0057ae;"&gt;anchors.fill&lt;/span&gt;: parent
        &lt;span style="color: #0057ae;"&gt;gradient&lt;/span&gt;: &lt;span style="color: green;"&gt;Gradient&lt;/span&gt; {
            &lt;span style="color: green;"&gt;GradientStop&lt;/span&gt; {
                &lt;span style="color: #0057ae;"&gt;position&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;1.0&lt;/span&gt;; &lt;span style="color: #0057ae;"&gt;color&lt;/span&gt;: &lt;span style="color: #bf0303;"&gt;"#FF000000"&lt;/span&gt;
            }
            &lt;span style="color: green;"&gt;GradientStop&lt;/span&gt; {
                &lt;span style="color: #0057ae;"&gt;position&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;0.0&lt;/span&gt;; &lt;span style="color: #0057ae;"&gt;color&lt;/span&gt;: &lt;span style="color: #bf0303;"&gt;"#00000000"&lt;/span&gt;
            }
        }
    }
}
&lt;/pre&gt;
&lt;br /&gt;
&lt;h3&gt;





Interlude&lt;/h3&gt;
&lt;i&gt;A bevel made with rectangles.&lt;/i&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;a class="c1" href="http://www.blogger.com/post-create.g?blogID=923082020090979517" style="clear: left; float: right;"&gt;&lt;img src="http://3.bp.blogspot.com/_DVYH9neSnMw/TP0gZzhVDFI/AAAAAAAAAb0/vbY-6m1Uqws/s1600/act1-5_bevel.png" /&gt;&lt;/a&gt;
Continuing the rectangles topic, let's make a fancy "bevel", which could serve, for example, as a border for an edit box control.
&lt;br /&gt;
&lt;br /&gt;
Here we have a more intense usage of anchor-properties, margins in particular. Also, borders width and color for Rectangles, as well as corner radius.
&lt;br /&gt;
&lt;br /&gt;
The &lt;i&gt;clip: true&lt;/i&gt; property is used to cut away right and bottom parts of the dark ("shadow") rectangle. Note, that the outermost rectangle here is used just as a background for our "bevel":
&lt;br /&gt;
&lt;pre style="background-color: white; color: #181615; font-size: 8pt; line-height: 13px;"&gt;&lt;b&gt;import&lt;/b&gt;&lt;span style="color: #bf0303;"&gt; Qt 4.7&lt;/span&gt;
&lt;span style="color: green;"&gt;Rectangle&lt;/span&gt; {
    &lt;span style="color: #0057ae;"&gt;color&lt;/span&gt;: &lt;span style="color: #bf0303;"&gt;"#3C3C3C"&lt;/span&gt;
    &lt;span style="color: #0057ae;"&gt;width&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;80&lt;/span&gt;; &lt;span style="color: #0057ae;"&gt;height&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;35&lt;/span&gt;
    &lt;span style="color: green;"&gt;Rectangle&lt;/span&gt; {
        &lt;span style="color: #0057ae;"&gt;x&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;20&lt;/span&gt;; &lt;span style="color: #0057ae;"&gt;y&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;10&lt;/span&gt;
        &lt;span style="color: #0057ae;"&gt;width &lt;/span&gt;: &lt;span style="color: #b08000;"&gt;40&lt;/span&gt;; &lt;span style="color: #0057ae;"&gt;height &lt;/span&gt;: &lt;span style="color: #b08000;"&gt;15&lt;/span&gt;; &lt;span style="color: #0057ae;"&gt;radius&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;2&lt;/span&gt;
        &lt;span style="color: #0057ae;"&gt;border.width&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;1&lt;/span&gt;; &lt;span style="color: #0057ae;"&gt;border.color&lt;/span&gt;: &lt;span style="color: #bf0303;"&gt;"#FF101010"&lt;/span&gt;
        &lt;span style="color: #0057ae;"&gt;color&lt;/span&gt;: &lt;span style="color: #bf0303;"&gt;"transparent"&lt;/span&gt;
        &lt;span style="color: #0057ae;"&gt;anchors.leftMargin&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;1&lt;/span&gt;; &lt;span style="color: #0057ae;"&gt;anchors.topMargin&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;3&lt;/span&gt;
        &lt;span style="color: #0057ae;"&gt;clip&lt;/span&gt;: &lt;b&gt;true&lt;/b&gt;
        &lt;span style="color: green;"&gt;Rectangle&lt;/span&gt; {
            &lt;span style="color: #0057ae;"&gt;anchors.fill&lt;/span&gt;: parent; &lt;span style="color: #0057ae;"&gt;radius&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;2&lt;/span&gt;
            &lt;span style="color: #0057ae;"&gt;anchors.leftMargin&lt;/span&gt;: -&lt;span style="color: #b08000;"&gt;1&lt;/span&gt;; &lt;span style="color: #0057ae;"&gt;anchors.topMargin&lt;/span&gt;: -&lt;span style="color: #b08000;"&gt;1&lt;/span&gt;
            &lt;span style="color: #0057ae;"&gt;border.width&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;1&lt;/span&gt;; &lt;span style="color: #0057ae;"&gt;border.color&lt;/span&gt;: &lt;span style="color: #bf0303;"&gt;"#FF525255"&lt;/span&gt;
            &lt;span style="color: #0057ae;"&gt;color&lt;/span&gt;: &lt;span style="color: #bf0303;"&gt;"transparent"&lt;/span&gt;
        }
    }
}
&lt;/pre&gt;
&lt;h3&gt;





Scene 2&lt;/h3&gt;
&lt;i&gt;Enter Custom Properties, Property Binding, Expressions.&lt;/i&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;a class="c1" href="http://www.blogger.com/post-create.g?blogID=923082020090979517" style="clear: left; float: right;"&gt;&lt;img src="http://2.bp.blogspot.com/_DVYH9neSnMw/TP0gaE4JZ0I/AAAAAAAAAb4/VwvGuoz1CAw/s1600/act2_circles.png" /&gt;&lt;/a&gt;
I guess at this point everyone should be fed up with rectangles, so let's try something else. 
&lt;br /&gt;
&lt;br /&gt;
Circles, for example. Let's try and make a visual representation for the cursor in the saturation/brightness area of the colorpicker.
&lt;br /&gt;
&lt;br /&gt;
So, we'll make our circles with... correct, with Rectangles.
&lt;br /&gt;
&lt;br /&gt;
The QML code here is pretty similar to the "bevel" example, with a new twist: &lt;i&gt;custom properties&lt;/i&gt;. 
&lt;br /&gt;
&lt;br /&gt;
We add our own new property to the root Item, and call it "r" (as in "radius"):
&lt;br /&gt;
&lt;pre style="background-color: white; color: #181615; font-size: 8pt; line-height: 13px;"&gt;    property int &lt;span style="color: #0057ae;"&gt;r &lt;/span&gt;: &lt;span style="color: #b08000;"&gt;8&lt;/span&gt;
&lt;/pre&gt;
This will behave as a regular, existing property of the object (e.g. the "width" property) would. In this case, "8" will be a default value for the radius of our cursor.
&lt;br /&gt;
&lt;br /&gt;
Next, let's use this new custom property to turn the child rectangle into a proper circle:
&lt;br /&gt;
&lt;pre style="background-color: white; color: #181615; font-size: 8pt; line-height: 13px;"&gt;       &lt;span style="color: #0057ae;"&gt;radius&lt;/span&gt;: &lt;span style="color: green;"&gt;parent&lt;/span&gt;.&lt;span style="color: #644a9b;"&gt;r&lt;/span&gt;
&lt;/pre&gt;
which means "keep the radius of this rectangle the same as the value of parents &lt;b&gt;r&lt;/b&gt; property is".
&lt;br /&gt;
&lt;br /&gt;
What just happened here is called &lt;i&gt;property binding&lt;/i&gt; (AKA "data binding") and is another cornerstone in declarative UI programming.
&lt;br /&gt;
&lt;br /&gt;
Property binding is a mechanism which keeps the values of certain properties in sync, i.e. when one property changes its value, then the corresponding bound property will update it's value automatically. 
&lt;br /&gt;
&lt;br /&gt;
Furthermore, this value can be transformed ("converted") on the way. In QML this is done in a simple and elegant way, by using expressions, written in JavaScript language:
&lt;br /&gt;
&lt;pre style="background-color: white; color: #181615; font-size: 8pt; line-height: 13px;"&gt;&lt;span style="color: #0057ae;"&gt;width&lt;/span&gt;: &lt;span style="color: green;"&gt;parent&lt;/span&gt;.&lt;span style="color: #644a9b;"&gt;r&lt;/span&gt;*&lt;span style="color: #b08000;"&gt;2&lt;/span&gt;; &lt;span style="color: #0057ae;"&gt;height&lt;/span&gt;: &lt;span style="color: green;"&gt;parent&lt;/span&gt;.&lt;span style="color: #644a9b;"&gt;r&lt;/span&gt;*&lt;span style="color: #b08000;"&gt;2&lt;/span&gt;
&lt;/pre&gt;
Here it means "keep the width and height of the object equal to be a double of the parent's &lt;b&gt;r&lt;/b&gt; property". Expressions can refer more than one property from more than one object, in which case all of them get automatically "bound". 
&lt;br /&gt;
&lt;br /&gt;
I must admit, &lt;a href="http://en.wikipedia.org/wiki/Windows_Presentation_Foundation"&gt; WPF&lt;/a&gt;'s converters and multiple bindings look quite a bit more awkward comparing to this... anyway, here's our cursor's code:
&lt;br /&gt;
&lt;pre style="background-color: white; color: #181615; font-size: 8pt; line-height: 13px;"&gt;&lt;b&gt;import&lt;/b&gt;&lt;span style="color: #bf0303;"&gt; Qt 4.7&lt;/span&gt;
&lt;span style="color: green;"&gt;Item&lt;/span&gt; {
    property int &lt;span style="color: #0057ae;"&gt;r &lt;/span&gt;: &lt;span style="color: #b08000;"&gt;8&lt;/span&gt;
    &lt;span style="color: #0057ae;"&gt;x&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;50&lt;/span&gt;; &lt;span style="color: #0057ae;"&gt;y&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;50&lt;/span&gt;; &lt;span style="color: #0057ae;"&gt;width&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;100&lt;/span&gt;; &lt;span style="color: #0057ae;"&gt;height&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;100&lt;/span&gt;;
    &lt;span style="color: green;"&gt;Rectangle&lt;/span&gt; {
        &lt;span style="color: #0057ae;"&gt;x&lt;/span&gt;: -&lt;span style="color: green;"&gt;parent&lt;/span&gt;.&lt;span style="color: #644a9b;"&gt;r&lt;/span&gt;; &lt;span style="color: #0057ae;"&gt;y&lt;/span&gt;: -&lt;span style="color: green;"&gt;parent&lt;/span&gt;.&lt;span style="color: #644a9b;"&gt;r&lt;/span&gt;
        &lt;span style="color: #0057ae;"&gt;width&lt;/span&gt;: &lt;span style="color: green;"&gt;parent&lt;/span&gt;.&lt;span style="color: #644a9b;"&gt;r&lt;/span&gt;*&lt;span style="color: #b08000;"&gt;2&lt;/span&gt;; &lt;span style="color: #0057ae;"&gt;height&lt;/span&gt;: &lt;span style="color: green;"&gt;parent&lt;/span&gt;.&lt;span style="color: #644a9b;"&gt;r&lt;/span&gt;*&lt;span style="color: #b08000;"&gt;2&lt;/span&gt;
        &lt;span style="color: #0057ae;"&gt;radius&lt;/span&gt;: &lt;span style="color: green;"&gt;parent&lt;/span&gt;.&lt;span style="color: #644a9b;"&gt;r&lt;/span&gt;
        &lt;span style="color: #0057ae;"&gt;border.color&lt;/span&gt;: &lt;span style="color: #bf0303;"&gt;"black"&lt;/span&gt;; &lt;span style="color: #0057ae;"&gt;border.width&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;2&lt;/span&gt;
        &lt;span style="color: #0057ae;"&gt;color&lt;/span&gt;: &lt;span style="color: #bf0303;"&gt;"transparent"&lt;/span&gt;
        &lt;span style="color: green;"&gt;Rectangle&lt;/span&gt; {
            &lt;span style="color: #0057ae;"&gt;anchors.fill&lt;/span&gt;: parent; &lt;span style="color: #0057ae;"&gt;anchors.margins&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;2&lt;/span&gt;;
            &lt;span style="color: #0057ae;"&gt;border.color&lt;/span&gt;: &lt;span style="color: #bf0303;"&gt;"gray"&lt;/span&gt;; &lt;span style="color: #0057ae;"&gt;border.width&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;2&lt;/span&gt;
            &lt;span style="color: #0057ae;"&gt;radius&lt;/span&gt;: width/&lt;span style="color: #b08000;"&gt;2&lt;/span&gt;
            &lt;span style="color: #0057ae;"&gt;color&lt;/span&gt;: &lt;span style="color: #bf0303;"&gt;"transparent"&lt;/span&gt;
        }
    }
}
&lt;/pre&gt;
&lt;br /&gt;
&lt;h3&gt;





Scene 3&lt;/h3&gt;
&lt;i&gt;Enter IDs, Grid, Repeater, Data Models.&lt;/i&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;a class="c1" href="http://www.blogger.com/post-create.g?blogID=923082020090979517" style="clear: left; float: right;"&gt;&lt;img src="http://2.bp.blogspot.com/_DVYH9neSnMw/TP0gaQ93egI/AAAAAAAAAb8/J5q3SFcqZKs/s1600/act3_checker.png" /&gt;&lt;/a&gt;
What about some more rectangles?.. I knew you looked forward. 
&lt;br /&gt;
&lt;br /&gt;
This time, though, let's organize them in a checkerboard pattern.
&lt;br /&gt;
&lt;br /&gt;
But first, let's mention that every object in QML object tree can have it's own "identifier", specified by the &lt;b&gt;id&lt;/b&gt; property. This identifier can be used in property binding, so properties of one object get bound to properties of another object, referenced by its identifier. 
Here, we'll name the root object as "root":
&lt;br /&gt;
&lt;pre style="background-color: white; color: #181615; font-size: 8pt; line-height: 13px;"&gt;    &lt;span style="color: #0057ae;"&gt;id&lt;/span&gt;: root
&lt;/pre&gt;
Next, let's combine a &lt;b&gt;Grid&lt;/b&gt; element, which lays out its children in a grid with the given number of rows/columns, together with a &lt;b&gt;Repeater&lt;/b&gt; element, which creates many similar objects based on two main parameters: visual template (specified as a child of the Repeater object)  and data model.
&lt;br /&gt;
&lt;br /&gt;
Data model, generally, is a list of data items, each of them serving as an input context to the corresponding separate object created by the Repeater. In simpler cases (such as ours) it can be just a number, specifying how many copies of the object to create. The visual template can reference the property called &lt;i&gt;index&lt;/i&gt;, which corresponds to the order of the item in the array.
&lt;br /&gt;
&lt;br /&gt;
We paint all the even elements gray and all the odd elements white, assuming, for the sake of simplicity, that the number of rows in the grid is always odd:
&lt;br /&gt;
&lt;pre style="background-color: white; color: #181615; font-size: 8pt; line-height: 13px;"&gt;&lt;b&gt;import&lt;/b&gt;&lt;span style="color: #bf0303;"&gt; Qt 4.7&lt;/span&gt;
&lt;span style="color: green;"&gt;Grid&lt;/span&gt; {
    &lt;span style="color: #0057ae;"&gt;id&lt;/span&gt;: root
    property int &lt;span style="color: #0057ae;"&gt;cellSide&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;10&lt;/span&gt;
    &lt;span style="color: #0057ae;"&gt;width&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;110&lt;/span&gt;; &lt;span style="color: #0057ae;"&gt;height&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;110&lt;/span&gt;
    &lt;span style="color: #0057ae;"&gt;rows&lt;/span&gt;: height/cellSide; &lt;span style="color: #0057ae;"&gt;columns&lt;/span&gt;: width/cellSide
    &lt;span style="color: green;"&gt;Repeater&lt;/span&gt; {
        &lt;span style="color: #0057ae;"&gt;model&lt;/span&gt;: &lt;span style="color: green;"&gt;root&lt;/span&gt;.&lt;span style="color: #644a9b;"&gt;columns&lt;/span&gt;*&lt;span style="color: green;"&gt;root&lt;/span&gt;.&lt;span style="color: #644a9b;"&gt;rows&lt;/span&gt;
        &lt;span style="color: green;"&gt;Rectangle&lt;/span&gt; {
            &lt;span style="color: #0057ae;"&gt;width&lt;/span&gt;: &lt;span style="color: green;"&gt;root&lt;/span&gt;.&lt;span style="color: #644a9b;"&gt;cellSide&lt;/span&gt;; &lt;span style="color: #0057ae;"&gt;height&lt;/span&gt;: &lt;span style="color: green;"&gt;root&lt;/span&gt;.&lt;span style="color: #644a9b;"&gt;cellSide&lt;/span&gt;
            &lt;span style="color: #0057ae;"&gt;color&lt;/span&gt;: (index%&lt;span style="color: #b08000;"&gt;2&lt;/span&gt; == &lt;span style="color: #b08000;"&gt;0&lt;/span&gt;) ? &lt;span style="color: #bf0303;"&gt;"gray"&lt;/span&gt; : &lt;span style="color: #bf0303;"&gt;"white"&lt;/span&gt;
        }
    }
}
&lt;/pre&gt;
&lt;h1&gt;





Act 2&lt;/h1&gt;
&lt;h3&gt;





Scene 0&lt;/h3&gt;
&lt;i&gt;Enter MouseArea, Signals, Inline JavaScript Code&lt;/i&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;a class="c1" href="http://www.blogger.com/post-create.g?blogID=923082020090979517" style="clear: left; float: right;"&gt;&lt;img src="http://1.bp.blogspot.com/_DVYH9neSnMw/TP0galK2P3I/AAAAAAAAAcA/nu7QjS_4S1s/s1600/act5_dragging.png" /&gt;&lt;/a&gt;
Let's add some interaction now and make a circle, draggable with the mouse. For that we'll use a &lt;b&gt;MouseArea&lt;/b&gt; element, which handles basic mouse tracking. One of the ways it does it is by receiving &lt;i&gt;signals&lt;/i&gt; whenever certain changes in mouse status happen.
&lt;br /&gt;
&lt;br /&gt;
In this case particular signals of interest are &lt;i&gt;onPositionChanged&lt;/i&gt; and &lt;i&gt;onPressed&lt;/i&gt;, as we want to change cursor position in both the case when user clicks with the mouse and when the mouse cursor is dragged. The code, is going to be identical in both cases, so it looks like a good idea to put it into a separate JavaScript function (which we'll call "handleMouse"). The mentioned signals pass a &lt;b&gt;MouseEvent&lt;/b&gt; object (named "mouse") with parameters describing the mouse status change ("x" and."y" corresponding to the current mouse position in particular). 
&lt;br /&gt;
&lt;br /&gt;
Our helper JavaScript function can reside right in the scope of the MouseArea object (which makes this a kind of "custom method" for this object, somewhat similarly tho the custom properties case we've looked into earlier).
&lt;br /&gt;
&lt;br /&gt;
Additionally, the standard JavaSript Math module is used to clamp the cursor position to the area of interest:
&lt;br /&gt;
&lt;pre style="background-color: white; color: #181615; font-size: 8pt; line-height: 13px;"&gt;&lt;b&gt;import&lt;/b&gt;&lt;span style="color: #bf0303;"&gt; Qt 4.7&lt;/span&gt;
&lt;span style="color: green;"&gt;Item&lt;/span&gt; {
    &lt;span style="color: #0057ae;"&gt;width&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;120&lt;/span&gt;; &lt;span style="color: #0057ae;"&gt;height&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;120&lt;/span&gt;
    &lt;span style="color: green;"&gt;Item&lt;/span&gt; {
        &lt;span style="color: #0057ae;"&gt;id&lt;/span&gt;: pickerCursor
        &lt;span style="color: green;"&gt;Rectangle&lt;/span&gt; {
            &lt;span style="color: #0057ae;"&gt;x&lt;/span&gt;: -&lt;span style="color: #b08000;"&gt;10&lt;/span&gt;; &lt;span style="color: #0057ae;"&gt;y&lt;/span&gt;: -&lt;span style="color: #b08000;"&gt;10&lt;/span&gt;
            &lt;span style="color: #0057ae;"&gt;width&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;20&lt;/span&gt;; &lt;span style="color: #0057ae;"&gt;height&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;20&lt;/span&gt;; &lt;span style="color: #0057ae;"&gt;radius&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;10&lt;/span&gt;
            &lt;span style="color: #0057ae;"&gt;border.color&lt;/span&gt;: &lt;span style="color: #bf0303;"&gt;"black"&lt;/span&gt;; &lt;span style="color: #0057ae;"&gt;border.width&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;2&lt;/span&gt;
        }
    }
    &lt;span style="color: green;"&gt;MouseArea&lt;/span&gt; {
        &lt;span style="color: #0057ae;"&gt;anchors.fill&lt;/span&gt;: parent
        &lt;b&gt;function&lt;/b&gt; handleMouse(mouse) {
            &lt;b&gt;if&lt;/b&gt; (&lt;span style="color: green;"&gt;mouse&lt;/span&gt;.&lt;span style="color: #644a9b;"&gt;buttons&lt;/span&gt; &amp;amp; &lt;span style="color: green;"&gt;Qt&lt;/span&gt;.&lt;span style="color: #644a9b;"&gt;LeftButton&lt;/span&gt;) {
                &lt;span style="color: green;"&gt;pickerCursor&lt;/span&gt;.&lt;span style="color: #644a9b;"&gt;x&lt;/span&gt; = &lt;span style="color: green;"&gt;Math&lt;/span&gt;.&lt;span style="color: #644a9b;"&gt;max&lt;/span&gt;(&lt;span style="color: #b08000;"&gt;0&lt;/span&gt;, 
                    &lt;span style="color: green;"&gt;Math&lt;/span&gt;.&lt;span style="color: #644a9b;"&gt;min&lt;/span&gt;(width,  &lt;span style="color: green;"&gt;mouse&lt;/span&gt;.&lt;span style="color: #644a9b;"&gt;x&lt;/span&gt;));
                &lt;span style="color: green;"&gt;pickerCursor&lt;/span&gt;.&lt;span style="color: #644a9b;"&gt;y&lt;/span&gt; = &lt;span style="color: green;"&gt;Math&lt;/span&gt;.&lt;span style="color: #644a9b;"&gt;max&lt;/span&gt;(&lt;span style="color: #b08000;"&gt;0&lt;/span&gt;, 
                    &lt;span style="color: green;"&gt;Math&lt;/span&gt;.&lt;span style="color: #644a9b;"&gt;min&lt;/span&gt;(height, &lt;span style="color: green;"&gt;mouse&lt;/span&gt;.&lt;span style="color: #644a9b;"&gt;y&lt;/span&gt;));
            }
        }
        &lt;span style="color: #0057ae;"&gt;onPositionChanged&lt;/span&gt;: handleMouse(mouse)
        &lt;span style="color: #0057ae;"&gt;onPressed&lt;/span&gt;: handleMouse(mouse)
    }
}
&lt;/pre&gt;
&lt;br /&gt;
&lt;h3&gt;





Scene 1&lt;/h3&gt;
&lt;i&gt;Enter Components, Layout&lt;/i&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;a class="c1" href="http://www.blogger.com/post-create.g?blogID=923082020090979517" style="clear: left; float: right;"&gt;&lt;img src="http://1.bp.blogspot.com/_DVYH9neSnMw/TP0ga6jqWgI/AAAAAAAAAcE/0XbdmliSrWE/s1600/act8.png" /&gt;&lt;/a&gt;
Now, let's start putting things together.
&lt;br /&gt;
&lt;br /&gt;
Besides of the saturation/brightness picking area, we'd also like to have a couple of vertical sliders - one for hue and one for transparency. The only difference betwen them would be a background picture. I the case of hue slider it is a gradient of colors from the rim of the color wheel, and for the alpha slider it's a good old checkerboard with a black-white gradient on top.
The vertical slider can be made in exactly the same way as the draggable cursor from the previous example, except it's limited to the vertical direction. 
&lt;br /&gt;
&lt;br /&gt;
We don't really want to copypaste around the identical code for sliders, and that's where &lt;i&gt;components&lt;/i&gt; come into play.
&lt;br /&gt;
&lt;br /&gt;
Components are reusable chunks of code (most often extracted into a separate file), and they serve as building blocks for Qt Quick application.
&lt;br /&gt;
&lt;br /&gt;
Let's create three separate files: &lt;a href="https://github.com/silverio/qt/blob/master/colorpicker/content/ColorSlider.qml"&gt;ColorSlider.qml&lt;/a&gt; (the vertical slider component, used in hue and alpha sliders), &lt;a href="https://github.com/silverio/qt/blob/master/colorpicker/content/SBPicker.qml"&gt;SBPicker.qml&lt;/a&gt; (saturation/brightness picking box, with code from the earlier examples) and &lt;a href="https://github.com/silverio/qt/blob/master/colorpicker/content/Checkerboard.qml"&gt;Checkerboard.qml&lt;/a&gt; (also familiar checkerboard rectangle) and put them inside the folder named, for example, "content". Our project starts to get some structure:&lt;br /&gt;
&lt;br /&gt;
&lt;a class="c1" href="http://1.bp.blogspot.com/_DVYH9neSnMw/TP0jRD50l-I/AAAAAAAAAcY/g7o9xnZKV-U/s320/components_structure.png" style="clear: left;"&gt;&lt;img src="http://1.bp.blogspot.com/_DVYH9neSnMw/TP0jRD50l-I/AAAAAAAAAcY/g7o9xnZKV-U/s320/components_structure.png" /&gt;&lt;/a&gt;
&lt;br /&gt;
&lt;br /&gt;
Note that component file names should start from a capital letter (CamelCasing is a common idiom here), and those names will be used to reference components from other code.
A QML file can reference all the components, wich have files placed in the same folder. In our case, though, in order for the root file (colorpicker.qml) to use components from the "content" folder, we add the following line:
&lt;br /&gt;
&lt;pre style="background-color: white; color: #181615; font-size: 8pt; line-height: 13px;"&gt;&lt;b&gt;import&lt;/b&gt;&lt;span style="color: #bf0303;"&gt; "content"&lt;/span&gt;
&lt;/pre&gt;
This makes all the components from the "content" folder available inside colorpicker.qml.
&lt;br /&gt;
&lt;br /&gt;
Now that we can reference ColorSlider and SBPicker components, we'd like to arrange them horizontally. For that we use QML's &lt;b&gt;Row&lt;/b&gt; element, which does exactly that:
&lt;br /&gt;
&lt;div style="height: 300px; overflow: auto; width: 100%;"&gt;
&lt;table cellpadding="0" cellspacing="0" style="width: 250px;"&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;pre style="background-color: white; color: #181615; font-size: 8pt; line-height: 13px;"&gt;&lt;i&gt;&lt;span style="color: #898887;"&gt;&lt;b&gt;// colorpicker.qml&lt;/b&gt;&lt;/span&gt;&lt;/i&gt;
&lt;b&gt;import&lt;/b&gt;&lt;span style="color: #bf0303;"&gt; Qt 4.7&lt;/span&gt;
&lt;b&gt;import&lt;/b&gt;&lt;span style="color: #bf0303;"&gt; "content"&lt;/span&gt;

&lt;span style="color: green;"&gt;Rectangle&lt;/span&gt; {
    &lt;span style="color: #0057ae;"&gt;width&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;230&lt;/span&gt;; &lt;span style="color: #0057ae;"&gt;height&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;200&lt;/span&gt;
    &lt;span style="color: #0057ae;"&gt;color&lt;/span&gt;: &lt;span style="color: #bf0303;"&gt;"#3C3C3C"&lt;/span&gt;
    &lt;span style="color: green;"&gt;Row&lt;/span&gt; {
        &lt;span style="color: #0057ae;"&gt;anchors.fill&lt;/span&gt;: parent
        &lt;span style="color: #0057ae;"&gt;spacing&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;3&lt;/span&gt;

        &lt;i&gt;&lt;span style="color: #898887;"&gt;// saturation/brightness picker box&lt;/span&gt;&lt;/i&gt;
        SBPicker {
            &lt;span style="color: #0057ae;"&gt;id&lt;/span&gt;: sbPicker
            &lt;span style="color: #0057ae;"&gt;hueColor &lt;/span&gt;: &lt;span style="color: #bf0303;"&gt;"green"&lt;/span&gt;
            &lt;span style="color: #0057ae;"&gt;width&lt;/span&gt;: &lt;span style="color: green;"&gt;parent&lt;/span&gt;.&lt;span style="color: #644a9b;"&gt;height&lt;/span&gt;; &lt;span style="color: #0057ae;"&gt;height&lt;/span&gt;: &lt;span style="color: green;"&gt;parent&lt;/span&gt;.&lt;span style="color: #644a9b;"&gt;height&lt;/span&gt;
        }

        &lt;i&gt;&lt;span style="color: #898887;"&gt;// hue picking slider&lt;/span&gt;&lt;/i&gt;
        &lt;span style="color: green;"&gt;Item&lt;/span&gt; {
            &lt;span style="color: #0057ae;"&gt;width&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;12&lt;/span&gt;; &lt;span style="color: #0057ae;"&gt;height&lt;/span&gt;: &lt;span style="color: green;"&gt;parent&lt;/span&gt;.&lt;span style="color: #644a9b;"&gt;height&lt;/span&gt;
            &lt;span style="color: green;"&gt;Rectangle&lt;/span&gt; {
                &lt;span style="color: #0057ae;"&gt;anchors.fill&lt;/span&gt;: parent
                &lt;span style="color: #0057ae;"&gt;gradient&lt;/span&gt;: &lt;span style="color: green;"&gt;Gradient&lt;/span&gt; {
                    &lt;span style="color: green;"&gt;GradientStop&lt;/span&gt; { &lt;span style="color: #0057ae;"&gt;position&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;1.0&lt;/span&gt;;  &lt;span style="color: #0057ae;"&gt;color&lt;/span&gt;: &lt;span style="color: #bf0303;"&gt;"#FF0000"&lt;/span&gt; }
                    &lt;span style="color: green;"&gt;GradientStop&lt;/span&gt; { &lt;span style="color: #0057ae;"&gt;position&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;0.85&lt;/span&gt;; &lt;span style="color: #0057ae;"&gt;color&lt;/span&gt;: &lt;span style="color: #bf0303;"&gt;"#FFFF00"&lt;/span&gt; }
                    &lt;span style="color: green;"&gt;GradientStop&lt;/span&gt; { &lt;span style="color: #0057ae;"&gt;position&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;0.76&lt;/span&gt;; &lt;span style="color: #0057ae;"&gt;color&lt;/span&gt;: &lt;span style="color: #bf0303;"&gt;"#00FF00"&lt;/span&gt; }
                    &lt;span style="color: green;"&gt;GradientStop&lt;/span&gt; { &lt;span style="color: #0057ae;"&gt;position&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;0.5&lt;/span&gt;;  &lt;span style="color: #0057ae;"&gt;color&lt;/span&gt;: &lt;span style="color: #bf0303;"&gt;"#00FFFF"&lt;/span&gt; }
                    &lt;span style="color: green;"&gt;GradientStop&lt;/span&gt; { &lt;span style="color: #0057ae;"&gt;position&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;0.33&lt;/span&gt;; &lt;span style="color: #0057ae;"&gt;color&lt;/span&gt;: &lt;span style="color: #bf0303;"&gt;"#0000FF"&lt;/span&gt; }
                    &lt;span style="color: green;"&gt;GradientStop&lt;/span&gt; { &lt;span style="color: #0057ae;"&gt;position&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;0.16&lt;/span&gt;; &lt;span style="color: #0057ae;"&gt;color&lt;/span&gt;: &lt;span style="color: #bf0303;"&gt;"#FF00FF"&lt;/span&gt; }
                    &lt;span style="color: green;"&gt;GradientStop&lt;/span&gt; { &lt;span style="color: #0057ae;"&gt;position&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;0.0&lt;/span&gt;;  &lt;span style="color: #0057ae;"&gt;color&lt;/span&gt;: &lt;span style="color: #bf0303;"&gt;"#FF0000"&lt;/span&gt; }
                }
            }
            ColorSlider { &lt;span style="color: #0057ae;"&gt;id&lt;/span&gt;: hueSlider; &lt;span style="color: #0057ae;"&gt;anchors.fill&lt;/span&gt;: parent }
        }

        &lt;i&gt;&lt;span style="color: #898887;"&gt;// alpha (transparency) picking slider&lt;/span&gt;&lt;/i&gt;
        &lt;span style="color: green;"&gt;Item&lt;/span&gt; {
            &lt;span style="color: #0057ae;"&gt;id&lt;/span&gt;: alphaPicker
            &lt;span style="color: #0057ae;"&gt;width&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;12&lt;/span&gt;; &lt;span style="color: #0057ae;"&gt;height&lt;/span&gt;: &lt;span style="color: green;"&gt;parent&lt;/span&gt;.&lt;span style="color: #644a9b;"&gt;height&lt;/span&gt;
            Checkerboard { &lt;span style="color: #0057ae;"&gt;cellSide&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;4&lt;/span&gt; }
            &lt;i&gt;&lt;span style="color: #898887;"&gt;//  alpha intensity gradient background&lt;/span&gt;&lt;/i&gt;
            &lt;span style="color: green;"&gt;Rectangle&lt;/span&gt; {
                &lt;span style="color: #0057ae;"&gt;anchors.fill&lt;/span&gt;: parent
                &lt;span style="color: #0057ae;"&gt;gradient&lt;/span&gt;: &lt;span style="color: green;"&gt;Gradient&lt;/span&gt; {
                    &lt;span style="color: green;"&gt;GradientStop&lt;/span&gt; { &lt;span style="color: #0057ae;"&gt;position&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;0.0&lt;/span&gt;; &lt;span style="color: #0057ae;"&gt;color&lt;/span&gt;: &lt;span style="color: #bf0303;"&gt;"#FF000000"&lt;/span&gt; }
                    &lt;span style="color: green;"&gt;GradientStop&lt;/span&gt; { &lt;span style="color: #0057ae;"&gt;position&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;1.0&lt;/span&gt;; &lt;span style="color: #0057ae;"&gt;color&lt;/span&gt;: &lt;span style="color: #bf0303;"&gt;"#00000000"&lt;/span&gt; }
                }
            }
            ColorSlider { &lt;span style="color: #0057ae;"&gt;id&lt;/span&gt;: alphaSlider; &lt;span style="color: #0057ae;"&gt;anchors.fill&lt;/span&gt;: parent }
        }

    }
}
&lt;/pre&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;





Scene 2&lt;/h3&gt;
&lt;i&gt;Enter TextInput, Validators, Property Aliases&lt;/i&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;a class="c1" href="http://www.blogger.com/post-create.g?blogID=923082020090979517" style="clear: left; float: right;"&gt;&lt;img src="http://4.bp.blogspot.com/_DVYH9neSnMw/TP0gblU3-MI/AAAAAAAAAcM/KdfM6iTp5so/s1600/details.png" /&gt;&lt;/a&gt;
What we also want to have in our colorpicker is a textbox displaying the whole color in "#AARRGGBB" string format, as well as separate numeric boxes with H, S, V and R, G, B, A values.
&lt;br /&gt;
&lt;br /&gt;
Those numeric boxes, again, are all lookalike, so it's a perfect candidate for a new component.
&lt;br /&gt;
&lt;br /&gt;
The element, which in QML is used for a simple one-line text input, is called &lt;b&gt;TextInput&lt;/b&gt;, and it has a few properties, specific to text editing - such as if text is selectable, what is the selection color, font properties etc.
&lt;br /&gt;
&lt;br /&gt;
One interesting property is &lt;b&gt;validator&lt;/b&gt;, which has a function of allowing only input of a certain type from the user. &lt;b&gt;DoubleValidator&lt;/b&gt;, in particular, only allows floating-point numbers in a specified range and with a specified number of digits after the decimal point.
&lt;br /&gt;
&lt;br /&gt;
So, the NumberBox component would consist of three parts: text input, caption text (drawn to the left of the text input), and a border around the text input.
&lt;br /&gt;
&lt;br /&gt;
External clients are not supposed to see the internal structure of a component, for them it's a black box with an interface. &lt;i&gt;Property aliases&lt;/i&gt; is a convenient way of wiring certain properties of component's internal objects as a part of component's interface. For example, an internal &lt;b&gt;Text&lt;/b&gt; component, which is used to display the NumberBox's caption, can have its "text" property "routed" to the component's interface without exposing the unnecessary details to client: 
&lt;br /&gt;
&lt;pre style="background-color: white; color: #181615; font-size: 8pt; line-height: 13px;"&gt;    property alias  &lt;span style="color: #0057ae;"&gt;caption&lt;/span&gt;: &lt;span style="color: green;"&gt;captionBox&lt;/span&gt;.&lt;span style="color: #644a9b;"&gt;text&lt;/span&gt;
&lt;/pre&gt;
The final number edit box component we place into a separate file: &lt;a href="https://github.com/silverio/qt/blob/master/colorpicker/content/NumberBox.qml"&gt;NumberBox.qml&lt;/a&gt;. 
&lt;br /&gt;
&lt;br /&gt;
&lt;div style="height: 320px; overflow: auto; width: 100%;"&gt;
&lt;table cellpadding="0" cellspacing="0" style="width: 250px;"&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;pre style="background-color: white; color: #181615; font-size: 8pt; line-height: 13px;"&gt;&lt;b&gt;&lt;i&gt;&lt;span style="color: #898887;"&gt;//  NumberBox.qml&lt;/span&gt;&lt;/i&gt;&lt;/b&gt;
&lt;b&gt;import&lt;/b&gt;&lt;span style="color: #bf0303;"&gt; Qt 4.7&lt;/span&gt;

&lt;span style="color: green;"&gt;Row&lt;/span&gt; {
    property alias  &lt;span style="color: #0057ae;"&gt;caption&lt;/span&gt;: &lt;span style="color: green;"&gt;captionBox&lt;/span&gt;.&lt;span style="color: #644a9b;"&gt;text&lt;/span&gt;
    property alias  &lt;span style="color: #0057ae;"&gt;value&lt;/span&gt;: &lt;span style="color: green;"&gt;inputBox&lt;/span&gt;.&lt;span style="color: #644a9b;"&gt;text&lt;/span&gt;
    property alias  &lt;span style="color: #0057ae;"&gt;min&lt;/span&gt;: &lt;span style="color: green;"&gt;numValidator&lt;/span&gt;.&lt;span style="color: #644a9b;"&gt;bottom&lt;/span&gt;
    property alias  &lt;span style="color: #0057ae;"&gt;max&lt;/span&gt;: &lt;span style="color: green;"&gt;numValidator&lt;/span&gt;.&lt;span style="color: #644a9b;"&gt;top&lt;/span&gt;
    property alias  &lt;span style="color: #0057ae;"&gt;decimals&lt;/span&gt;: &lt;span style="color: green;"&gt;numValidator&lt;/span&gt;.&lt;span style="color: #644a9b;"&gt;decimals&lt;/span&gt;

    &lt;span style="color: #0057ae;"&gt;width&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;80&lt;/span&gt;;
    &lt;span style="color: #0057ae;"&gt;height&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;15&lt;/span&gt;
    &lt;span style="color: #0057ae;"&gt;spacing&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;4&lt;/span&gt;
    &lt;span style="color: #0057ae;"&gt;anchors.margins&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;2&lt;/span&gt;
    &lt;span style="color: green;"&gt;Text&lt;/span&gt; {
        &lt;span style="color: #0057ae;"&gt;id&lt;/span&gt;: captionBox
        &lt;span style="color: #0057ae;"&gt;width&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;18&lt;/span&gt;; &lt;span style="color: #0057ae;"&gt;height&lt;/span&gt;: &lt;span style="color: green;"&gt;parent&lt;/span&gt;.&lt;span style="color: #644a9b;"&gt;height&lt;/span&gt;
        &lt;span style="color: #0057ae;"&gt;color&lt;/span&gt;: &lt;span style="color: #bf0303;"&gt;"#AAAAAA"&lt;/span&gt;
        &lt;span style="color: #0057ae;"&gt;font.pixelSize&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;11&lt;/span&gt;; &lt;span style="color: #0057ae;"&gt;font.bold&lt;/span&gt;: &lt;b&gt;true&lt;/b&gt;
        &lt;span style="color: #0057ae;"&gt;horizontalAlignment&lt;/span&gt;: &lt;span style="color: green;"&gt;Text&lt;/span&gt;.&lt;span style="color: #644a9b;"&gt;AlignRight&lt;/span&gt;; &lt;span style="color: #0057ae;"&gt;verticalAlignment&lt;/span&gt;: &lt;span style="color: green;"&gt;Text&lt;/span&gt;.&lt;span style="color: #644a9b;"&gt;AlignBottom&lt;/span&gt;
        &lt;span style="color: #0057ae;"&gt;anchors.bottomMargin&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;3&lt;/span&gt;
    }
    PanelBorder {
        &lt;span style="color: #0057ae;"&gt;height&lt;/span&gt;: &lt;span style="color: green;"&gt;parent&lt;/span&gt;.&lt;span style="color: #644a9b;"&gt;height&lt;/span&gt;
        &lt;span style="color: #0057ae;"&gt;anchors.leftMargin&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;4&lt;/span&gt;;
        &lt;span style="color: #0057ae;"&gt;anchors.left&lt;/span&gt;: &lt;span style="color: green;"&gt;captionBox&lt;/span&gt;.&lt;span style="color: #644a9b;"&gt;right&lt;/span&gt;; &lt;span style="color: #0057ae;"&gt;anchors.right&lt;/span&gt;: &lt;span style="color: green;"&gt;parent&lt;/span&gt;.&lt;span style="color: #644a9b;"&gt;right&lt;/span&gt;
        &lt;span style="color: green;"&gt;TextInput&lt;/span&gt; {
            &lt;span style="color: #0057ae;"&gt;id&lt;/span&gt;: inputBox
            &lt;span style="color: #0057ae;"&gt;anchors.leftMargin&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;4&lt;/span&gt;; &lt;span style="color: #0057ae;"&gt;anchors.topMargin&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;1&lt;/span&gt;; &lt;span style="color: #0057ae;"&gt;anchors.fill&lt;/span&gt;: parent
            &lt;span style="color: #0057ae;"&gt;color&lt;/span&gt;: &lt;span style="color: #bf0303;"&gt;"#AAAAAA"&lt;/span&gt;; &lt;span style="color: #0057ae;"&gt;selectionColor&lt;/span&gt;: &lt;span style="color: #bf0303;"&gt;"#FF7777AA"&lt;/span&gt;
            &lt;span style="color: #0057ae;"&gt;font.pixelSize&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;11&lt;/span&gt;            
            &lt;span style="color: #0057ae;"&gt;maximumLength&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;10&lt;/span&gt;
            &lt;span style="color: #0057ae;"&gt;focus&lt;/span&gt;: &lt;b&gt;true&lt;/b&gt;
            &lt;span style="color: #0057ae;"&gt;selectByMouse&lt;/span&gt;: &lt;b&gt;true&lt;/b&gt;
            &lt;span style="color: #0057ae;"&gt;validator&lt;/span&gt;: DoubleValidator {
                &lt;span style="color: #0057ae;"&gt;id&lt;/span&gt;: numValidator
                &lt;span style="color: #0057ae;"&gt;bottom&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;0&lt;/span&gt;; &lt;span style="color: #0057ae;"&gt;top&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;1&lt;/span&gt;; &lt;span style="color: #0057ae;"&gt;decimals&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;2&lt;/span&gt;
                &lt;span style="color: #0057ae;"&gt;notation&lt;/span&gt;: &lt;span style="color: green;"&gt;DoubleValidator&lt;/span&gt;.&lt;span style="color: #644a9b;"&gt;StandardNotation&lt;/span&gt;
            }
        }
    }
}
&lt;/pre&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
Note that this in turn uses another component, the bevel we already know:  &lt;a href="https://github.com/silverio/qt/blob/master/colorpicker/content/PanelBorder.qml"&gt;PanelBorder.qml&lt;/a&gt;.
&lt;br /&gt;
&lt;br /&gt;
And then the QML file for the details part of the colorpicker looks like this:
&lt;br /&gt;
&lt;div style="height: 320px; overflow: auto; width: 100%;"&gt;
&lt;table cellpadding="0" cellspacing="0" style="width: 250px;"&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;pre style="background-color: white; color: #181615; font-size: 8pt; line-height: 13px;"&gt;&lt;b&gt;import&lt;/b&gt;&lt;span style="color: #bf0303;"&gt; Qt 4.7&lt;/span&gt;
&lt;b&gt;import&lt;/b&gt;&lt;span style="color: #bf0303;"&gt; "content"&lt;/span&gt;
&lt;span style="color: green;"&gt;Rectangle&lt;/span&gt; {
    &lt;span style="color: #0057ae;"&gt;width&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;100&lt;/span&gt;; &lt;span style="color: #0057ae;"&gt;height&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;200&lt;/span&gt;
    &lt;span style="color: #0057ae;"&gt;color&lt;/span&gt;: &lt;span style="color: #bf0303;"&gt;"#3C3C3C"&lt;/span&gt;
    &lt;span style="color: green;"&gt;Column&lt;/span&gt; {
        &lt;span style="color: #0057ae;"&gt;anchors.fill&lt;/span&gt;: parent
        &lt;span style="color: #0057ae;"&gt;anchors.leftMargin&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;4&lt;/span&gt;; &lt;span style="color: #0057ae;"&gt;anchors.rightMargin&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;3&lt;/span&gt;
        &lt;span style="color: #0057ae;"&gt;height&lt;/span&gt;: &lt;span style="color: green;"&gt;parent&lt;/span&gt;.&lt;span style="color: #644a9b;"&gt;height&lt;/span&gt;
        &lt;span style="color: #0057ae;"&gt;spacing&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;4&lt;/span&gt;

        &lt;i&gt;&lt;span style="color: #898887;"&gt;// current color/alpha display rectangle&lt;/span&gt;&lt;/i&gt;
        &lt;span style="color: green;"&gt;Rectangle&lt;/span&gt; {
            &lt;span style="color: #0057ae;"&gt;width&lt;/span&gt;: &lt;span style="color: green;"&gt;parent&lt;/span&gt;.&lt;span style="color: #644a9b;"&gt;width&lt;/span&gt;; &lt;span style="color: #0057ae;"&gt;height&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;30&lt;/span&gt;
            Checkerboard { &lt;span style="color: #0057ae;"&gt;cellSide&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;5&lt;/span&gt; }
            &lt;span style="color: green;"&gt;Rectangle&lt;/span&gt; {
                &lt;span style="color: #0057ae;"&gt;width&lt;/span&gt;: &lt;span style="color: green;"&gt;parent&lt;/span&gt;.&lt;span style="color: #644a9b;"&gt;width&lt;/span&gt;; &lt;span style="color: #0057ae;"&gt;height&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;30&lt;/span&gt;
                &lt;span style="color: #0057ae;"&gt;border.width&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;1&lt;/span&gt;; &lt;span style="color: #0057ae;"&gt;border.color&lt;/span&gt;: &lt;span style="color: #bf0303;"&gt;"black"&lt;/span&gt;
                &lt;span style="color: #0057ae;"&gt;color&lt;/span&gt;: &lt;span style="color: #bf0303;"&gt;"#AAFFFF00"&lt;/span&gt;
            }
        }

        &lt;i&gt;&lt;span style="color: #898887;"&gt;// "#AARRGGBB" color value box&lt;/span&gt;&lt;/i&gt;
        PanelBorder {
            &lt;span style="color: #0057ae;"&gt;id&lt;/span&gt;: colorEditBox
            &lt;span style="color: #0057ae;"&gt;height&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;15&lt;/span&gt;; &lt;span style="color: #0057ae;"&gt;width&lt;/span&gt;: &lt;span style="color: green;"&gt;parent&lt;/span&gt;.&lt;span style="color: #644a9b;"&gt;width&lt;/span&gt;
            &lt;span style="color: green;"&gt;TextInput&lt;/span&gt; {
                &lt;span style="color: #0057ae;"&gt;anchors.fill&lt;/span&gt;: parent
                &lt;span style="color: #0057ae;"&gt;color&lt;/span&gt;: &lt;span style="color: #bf0303;"&gt;"#AAAAAA"&lt;/span&gt;
                &lt;span style="color: #0057ae;"&gt;selectionColor&lt;/span&gt;: &lt;span style="color: #bf0303;"&gt;"#FF7777AA"&lt;/span&gt;
                &lt;span style="color: #0057ae;"&gt;font.pixelSize&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;11&lt;/span&gt;
                &lt;span style="color: #0057ae;"&gt;maximumLength&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;9&lt;/span&gt;
                &lt;span style="color: #0057ae;"&gt;focus&lt;/span&gt;: &lt;b&gt;true&lt;/b&gt;
                &lt;span style="color: #0057ae;"&gt;text&lt;/span&gt;: &lt;span style="color: #bf0303;"&gt;"#AAFFFF00"&lt;/span&gt;
                &lt;span style="color: #0057ae;"&gt;selectByMouse&lt;/span&gt;: &lt;b&gt;true&lt;/b&gt;
            }
        }

        &lt;i&gt;&lt;span style="color: #898887;"&gt;// H, S, B color values boxes&lt;/span&gt;&lt;/i&gt;
        &lt;span style="color: green;"&gt;Column&lt;/span&gt; {
            &lt;span style="color: #0057ae;"&gt;width&lt;/span&gt;: &lt;span style="color: green;"&gt;parent&lt;/span&gt;.&lt;span style="color: #644a9b;"&gt;width&lt;/span&gt;
            NumberBox { &lt;span style="color: #0057ae;"&gt;caption&lt;/span&gt;: &lt;span style="color: #bf0303;"&gt;"H:"&lt;/span&gt;; &lt;span style="color: #0057ae;"&gt;value&lt;/span&gt;: &lt;span style="color: #bf0303;"&gt;"0.1"&lt;/span&gt; }
            NumberBox { &lt;span style="color: #0057ae;"&gt;caption&lt;/span&gt;: &lt;span style="color: #bf0303;"&gt;"S:"&lt;/span&gt;; &lt;span style="color: #0057ae;"&gt;value&lt;/span&gt;: &lt;span style="color: #bf0303;"&gt;"0.2"&lt;/span&gt; }
            NumberBox { &lt;span style="color: #0057ae;"&gt;caption&lt;/span&gt;: &lt;span style="color: #bf0303;"&gt;"B:"&lt;/span&gt;; &lt;span style="color: #0057ae;"&gt;value&lt;/span&gt;: &lt;span style="color: #bf0303;"&gt;"0.3"&lt;/span&gt; }
        }

        &lt;i&gt;&lt;span style="color: #898887;"&gt;// filler rectangle&lt;/span&gt;&lt;/i&gt;
        &lt;span style="color: green;"&gt;Rectangle&lt;/span&gt; {
            &lt;span style="color: #0057ae;"&gt;width&lt;/span&gt;: &lt;span style="color: green;"&gt;parent&lt;/span&gt;.&lt;span style="color: #644a9b;"&gt;width&lt;/span&gt;; &lt;span style="color: #0057ae;"&gt;height&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;5&lt;/span&gt;
            &lt;span style="color: #0057ae;"&gt;color&lt;/span&gt;: &lt;span style="color: #bf0303;"&gt;"transparent"&lt;/span&gt;
        }

        &lt;i&gt;&lt;span style="color: #898887;"&gt;// R, G, B color values boxes&lt;/span&gt;&lt;/i&gt;
        &lt;span style="color: green;"&gt;Column&lt;/span&gt; {
            &lt;span style="color: #0057ae;"&gt;width&lt;/span&gt;: &lt;span style="color: green;"&gt;parent&lt;/span&gt;.&lt;span style="color: #644a9b;"&gt;width&lt;/span&gt;
            NumberBox {
                &lt;span style="color: #0057ae;"&gt;caption&lt;/span&gt;: &lt;span style="color: #bf0303;"&gt;"R:"&lt;/span&gt;; &lt;span style="color: #0057ae;"&gt;value&lt;/span&gt;: &lt;span style="color: #bf0303;"&gt;"255"&lt;/span&gt;
                &lt;span style="color: #0057ae;"&gt;min&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;0&lt;/span&gt;; &lt;span style="color: #0057ae;"&gt;max&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;255&lt;/span&gt;
            }
            NumberBox {
                &lt;span style="color: #0057ae;"&gt;caption&lt;/span&gt;: &lt;span style="color: #bf0303;"&gt;"G:"&lt;/span&gt;; &lt;span style="color: #0057ae;"&gt;value&lt;/span&gt;: &lt;span style="color: #bf0303;"&gt;"255"&lt;/span&gt;
                &lt;span style="color: #0057ae;"&gt;min&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;0&lt;/span&gt;; &lt;span style="color: #0057ae;"&gt;max&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;255&lt;/span&gt;
            }
            NumberBox {
                &lt;span style="color: #0057ae;"&gt;caption&lt;/span&gt;: &lt;span style="color: #bf0303;"&gt;"B:"&lt;/span&gt;; &lt;span style="color: #0057ae;"&gt;value&lt;/span&gt;: &lt;span style="color: #bf0303;"&gt;"0"&lt;/span&gt;
                &lt;span style="color: #0057ae;"&gt;min&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;0&lt;/span&gt;; &lt;span style="color: #0057ae;"&gt;max&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;255&lt;/span&gt;
            }
        }

        &lt;i&gt;&lt;span style="color: #898887;"&gt;// alpha value box&lt;/span&gt;&lt;/i&gt;
        NumberBox {
            &lt;span style="color: #0057ae;"&gt;caption&lt;/span&gt;: &lt;span style="color: #bf0303;"&gt;"A:"&lt;/span&gt;; &lt;span style="color: #0057ae;"&gt;value&lt;/span&gt;: &lt;span style="color: #bf0303;"&gt;"100"&lt;/span&gt;
            &lt;span style="color: #0057ae;"&gt;min&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;0&lt;/span&gt;; &lt;span style="color: #0057ae;"&gt;max&lt;/span&gt;: &lt;span style="color: #b08000;"&gt;255&lt;/span&gt;
        }
    }
}

&lt;/pre&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;br /&gt;
We've used another layout element here, &lt;b&gt;Column&lt;/b&gt;, which is a vertical version of &lt;b&gt;Row&lt;/b&gt;.

&lt;br /&gt;
&lt;h1&gt;





Act 3&lt;/h1&gt;
&lt;h3&gt;





Scene 0&lt;/h3&gt;
&lt;i&gt;Enter Qt Source Code, JavaScript Modules&lt;/i&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;a class="c1" href="http://1.bp.blogspot.com/_DVYH9neSnMw/TP0gb2V7ixI/AAAAAAAAAcQ/tpUdDA1qWD4/s1600/qt_source.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_DVYH9neSnMw/TP0gb2V7ixI/AAAAAAAAAcQ/tpUdDA1qWD4/s1600/qt_source.png" width="200" /&gt;&lt;/a&gt;
We have all the controls in place, and what is left is wiring them together with property binding. For that we need to have some ways of converting between QML's &lt;b&gt;color&lt;/b&gt; values, "#AARRGGBB" text representations, as well as between hue/saturation/brighness/alpha and red/green/blue/alpha.
&lt;br /&gt;
&lt;br /&gt;
The original expectation was that QML would already provide the methods needed. Unfortunately, it turned to be not as straightforward. One of the problems, for example, is that when converting color value to string, the "AA" part in "#AARRGGBB" is for some reason omitted. The documentation regarding the QML color type &lt;a href="http://doc.qt.nokia.com/latest/qml-color.html"&gt;is rather scarce&lt;/a&gt; at the moment. 
&lt;br /&gt;
&lt;br /&gt;
But we have the source code, which is a kind of documentation on its own, given that one has time and desire to understand the internal workings of Qt Framework. Personally I do find this kind of looking inside the black box to be quite a useful experience, especially since Qt has generally nice code and architecture.
&lt;br /&gt;
&lt;br /&gt;
The source code can be conveniently browsed in the Qt Creator itself, by opening the "[QtSDK Folder]/src/src.pro" project.
&lt;br /&gt;
&lt;br /&gt;
Looking into the code confirms that current support for the color manipulation is indeed rather basic (not going beyond what documentation suggests), and problem with the color-to-string conversion appears to be a bug, as code does indeed just ignore the alpha component when composing the color string. Which basically leaves us on our own with the color conversion.
&lt;br /&gt;
&lt;br /&gt;
What we can do, however, is to write the corresponding utility functions ourselves, in a separate JavaScript file. So let's create a file named &lt;a href="https://github.com/silverio/qt/blob/master/colorpicker/content/ColorUtils.js"&gt;ColorUtils.js&lt;/a&gt; and add it to the "components" folder:
&lt;br /&gt;
&lt;div style="height: 320px; overflow: auto; width: 100%;"&gt;
&lt;table cellpadding="0" cellspacing="0" style="width: 250px;"&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;pre style="background-color: white; color: #181615; font-size: 8pt; line-height: 13px;"&gt;&lt;b&gt;&lt;i&gt;&lt;span style="color: #898887;"&gt;//  ColorUtils.js&lt;/span&gt;&lt;/i&gt;&lt;/b&gt;
&lt;i&gt;&lt;span style="color: #898887;"&gt;//  Color manipulation utilities&lt;/span&gt;&lt;/i&gt;

&lt;i&gt;&lt;span style="color: #898887;"&gt;//  creates color value from hue, saturation, brightness, alpha&lt;/span&gt;&lt;/i&gt;
&lt;b&gt;function&lt;/b&gt; hsba(h, s, b, a) {
    &lt;b&gt;var&lt;/b&gt; lightness = (&lt;span style="color: #b08000;"&gt;2&lt;/span&gt; - s)*b;
    &lt;b&gt;var&lt;/b&gt; satHSL = s*b/((lightness &amp;lt;= &lt;span style="color: #b08000;"&gt;1&lt;/span&gt;) ? &lt;span style="color: #0057ae;"&gt;lightness &lt;/span&gt;: &lt;span style="color: #b08000;"&gt;2&lt;/span&gt; - lightness);
    lightness /= &lt;span style="color: #b08000;"&gt;2&lt;/span&gt;;
    &lt;b&gt;return&lt;/b&gt; &lt;span style="color: green;"&gt;Qt&lt;/span&gt;.&lt;span style="color: #644a9b;"&gt;hsla&lt;/span&gt;(h, satHSL, lightness, a);
}

&lt;i&gt;&lt;span style="color: #898887;"&gt;//  creates a full color string from color value and alpha[0..1], e.g. "#FF00FF00"&lt;/span&gt;&lt;/i&gt;
&lt;b&gt;function&lt;/b&gt; fullColorString(clr, a) {
    &lt;b&gt;return&lt;/b&gt; &lt;span style="color: #bf0303;"&gt;"#"&lt;/span&gt; + ((&lt;span style="color: green;"&gt;Math&lt;/span&gt;.&lt;span style="color: #644a9b;"&gt;ceil&lt;/span&gt;(a*&lt;span style="color: #b08000;"&gt;255&lt;/span&gt;) + &lt;span style="color: #b08000;"&gt;256&lt;/span&gt;).&lt;span style="color: #644a9b;"&gt;toString&lt;/span&gt;(&lt;span style="color: #b08000;"&gt;16&lt;/span&gt;).&lt;span style="color: #644a9b;"&gt;substr&lt;/span&gt;(&lt;span style="color: #b08000;"&gt;1&lt;/span&gt;, &lt;span style="color: #b08000;"&gt;2&lt;/span&gt;) +
            &lt;span style="color: green;"&gt;clr&lt;/span&gt;.&lt;span style="color: #644a9b;"&gt;toString&lt;/span&gt;().&lt;span style="color: #644a9b;"&gt;substr&lt;/span&gt;(&lt;span style="color: #b08000;"&gt;1&lt;/span&gt;, &lt;span style="color: #b08000;"&gt;6&lt;/span&gt;)).&lt;span style="color: #644a9b;"&gt;toUpperCase&lt;/span&gt;();
}

&lt;i&gt;&lt;span style="color: #898887;"&gt;//  extracts integer color channel value [0..255] from color value&lt;/span&gt;&lt;/i&gt;
&lt;b&gt;function&lt;/b&gt; getChannelStr(clr, channelIdx) {
    &lt;b&gt;return&lt;/b&gt; &lt;span style="color: #644a9b;"&gt;parseInt&lt;/span&gt;(&lt;span style="color: green;"&gt;clr&lt;/span&gt;.&lt;span style="color: #644a9b;"&gt;toString&lt;/span&gt;().&lt;span style="color: #644a9b;"&gt;substr&lt;/span&gt;(channelIdx*&lt;span style="color: #b08000;"&gt;2&lt;/span&gt; + &lt;span style="color: #b08000;"&gt;1&lt;/span&gt;, &lt;span style="color: #b08000;"&gt;2&lt;/span&gt;), &lt;span style="color: #b08000;"&gt;16&lt;/span&gt;);
}&lt;/pre&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
There are many things which are wrong with this code, but hopefully its main purpose - to demonstrate the idea - is fulfilled.
&lt;br /&gt;
&lt;br /&gt;
One thing to note is that it uses &lt;i&gt;Qt.hsla&lt;/i&gt; method, which is a built-in QML function for creating color value from hue/saturation/alpha/lightness values. As we use HSB space, not HSL, there is &lt;a href="http://en.wikipedia.org/wiki/HSL_and_HSV"&gt;an additional conversion performed&lt;/a&gt;.
&lt;br /&gt;
&lt;br /&gt;
Now, to be able to use these utilities in our colorpicker.qml file, we add the following line:
&lt;br /&gt;
&lt;pre style="background-color: white; color: #181615; font-size: 8pt; line-height: 13px;"&gt;&lt;b&gt;import&lt;/b&gt;&lt;span style="color: #bf0303;"&gt; "content/ColorUtils.js"&lt;/span&gt; as ColorUtils
&lt;/pre&gt;
and refer to the utility functions as, e.g. "ColorUtils.hsba(hue, saturation, brightness, alpha);".
&lt;br /&gt;
&lt;br /&gt;
After that, we finally wire all the text in the numberboxes to the actual color value, the color in the saturation/brightness picking area to correspond to the current hue slider position, and the color/alpha display rectangle to be of the current color, which gives us the final version of &lt;a href="https://github.com/silverio/qt/blob/master/colorpicker/colorpicker.qml"&gt;colorpicker.qml&lt;/a&gt;.

&lt;br /&gt;
&lt;h1&gt;





Grand Finale&lt;/h1&gt;
I've been fascinated with the idea of declarative user interface programming, even playing with that in a &lt;a href="http://gdreflections.com/2009/12/bees-in-space-or-story-of-my-first.html"&gt;game development framework&lt;/a&gt; long time ago (quite ironically, my "JML" markup language from 2003 was pretty similar to QML).
&lt;br /&gt;
&lt;br /&gt;
The paradigm does indeed seem to improve productivity when developing user interfaces, and experience with QML in particular was that it's fun to learn and use. 
&lt;br /&gt;
&lt;br /&gt;
There've been a few gotchas, however.
&lt;br /&gt;
&lt;br /&gt;
For example, I could not figure out how to emulate two-way property binding, that's why our colorpicker does not react on input in the edit boxes. While there might be an obscure way of doing this, it's not supported out of the box.
&lt;br /&gt;
&lt;br /&gt;
Also, the layout engine is rather flaky - e.g. margins do not seem to work as expected when using Row and Column containers, and in few cases I had to use direct property binding to simulate the desired layout behaviour.
&lt;br /&gt;
&lt;br /&gt;
There is no complex brushes and vector graphics, as one would see in WPF, etc.
&lt;br /&gt;
&lt;br /&gt;
However, there is also a plenty of strong points, which competitors lack, and those points are extremely appealing.&lt;br /&gt;
&lt;br /&gt;
Let's wait and see where it moves. I sincerely hope that Qt Quick/QML will take a strong position eventually.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/923082020090979517-697620140032757759?l=blog.ruslans.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/gd_reflections/~4/FW98D42NR9g" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.ruslans.com/feeds/697620140032757759/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=923082020090979517&amp;postID=697620140032757759" title="5 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/923082020090979517/posts/default/697620140032757759" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/923082020090979517/posts/default/697620140032757759" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/gd_reflections/~3/FW98D42NR9g/cute-quick-colorpicker.html" title="A cute quick colorpicker" /><author><name>ruslans</name><uri>http://www.blogger.com/profile/03375859473751956887</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="24" height="32" src="http://2.bp.blogspot.com/_DVYH9neSnMw/S0V_XM6aN0I/AAAAAAAAAMc/06dTTnY0PNw/S220/avatar3.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/_DVYH9neSnMw/TP0gbayddNI/AAAAAAAAAcI/8j2lETO8ENs/s72-c/cp_final.jpg" height="72" width="72" /><thr:total>5</thr:total><feedburner:origLink>http://blog.ruslans.com/2010/12/cute-quick-colorpicker.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-923082020090979517.post-9087446240703701803</id><published>2010-04-13T19:02:00.000-07:00</published><updated>2010-04-16T05:16:38.632-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="creativity" /><category scheme="http://www.blogger.com/atom/ns#" term="self-improvement" /><category scheme="http://www.blogger.com/atom/ns#" term="triz" /><title type="text">Learn yourself some innovation</title><content type="html">&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://1.bp.blogspot.com/_DVYH9neSnMw/S8UhshgvhMI/AAAAAAAAASY/Mzrzp-bInxc/s1600/apple.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_DVYH9neSnMw/S8UhshgvhMI/AAAAAAAAASY/Mzrzp-bInxc/s320/apple.png" /&gt;&lt;/a&gt;&lt;/div&gt;
Looking at today's programmer job positions, a lot of them, along with those usual &lt;a href="http://codeanthem.com/blog/?p=64"&gt;lists of funky acronyms&lt;/a&gt;, include a somewhat confusing line: "strong problem solving skills."&lt;br /&gt;
&lt;br /&gt;
To measure "amount of experience" in any concrete technology is already a tricky business, so how does one go with such an abstract thing as "problem solving ability"? 
&lt;br /&gt;
&lt;br /&gt;
In software development there usually are many problems to solve, and for each of them there are many possible solutions. So it's not just about finding &lt;i&gt;a&lt;/i&gt; solution, but rather about &lt;i&gt;consistently picking the right solutions from many possible&lt;/i&gt; (and picking the right problems, for that matter). At this point we start talking about creativity and innovation. 

&lt;br /&gt;
&lt;br /&gt;
The question is: is it possible at all to &lt;i&gt;develop such a skill&lt;/i&gt;, in a deliberate way? Is this a personality trait, or intuition, experience, knowledge... or all of these?..
&lt;br /&gt;
&lt;br /&gt;
Turns out, people were trying to answer the question for ages. &lt;a href="http://www.niu.edu/~jdye/method.html"&gt;Socrates&lt;/a&gt;, &lt;a href="http://www.jobs.ac.uk/blogs/real-life/2008/09/11/problem-solving-research-advice-from-descartes/"&gt;Descartes&lt;/a&gt;, &lt;a href="http://www.is.wayne.edu/drbowen/crtvyw99/poincare.htm"&gt;Poincare&lt;/a&gt; and many more researched the topic of creativity, innovation and problem solving, looking for answers to the same question: &lt;i&gt;how good ideas are born in human mind&lt;/i&gt;?
&lt;br /&gt;
&lt;br /&gt;
The particular research which I've been poking into for a while, is called "Theory of Inventive Problem Solving" (aka &lt;a href="http://en.wikipedia.org/wiki/TRIZ"&gt;TRIZ&lt;/a&gt;). The author, Russian inventor Genrich Altshuller, having worked in a patent office (it's interesting that Einstein &lt;a href="http://en.wikipedia.org/wiki/Einstein#Patent_office"&gt;had similar experience&lt;/a&gt;) and examined thousands of technical inventions, embarked on a task of finding some common traits in all these seemingly unrelated innovative ideas.
&lt;br /&gt;
&lt;br /&gt;
Essentially, he was &lt;i&gt;reverse-engineering&lt;/i&gt; - first the good technical solutions themselves, and then mental processes, which could lead to such solutions emerging as an idea in one's head. And he came up with some core principles, building them later into his methodology, which managed to become quite recognized.
&lt;br /&gt;
&lt;br /&gt;
As with any good and recognized methodology which goes mainstream and gets the potential to commercialize (it's claimed to have been used at Xerox, Jonson&amp;amp;Jonson, Ford and other industrial giants), it eventually became somewhat complex and confusing, quite often being diluted with a snake oil (&lt;a href="http://steve-yegge.blogspot.com/2006/09/good-agile-bad-agile_27.html"&gt;must...not...mention...agile...&lt;/a&gt;). 
&lt;br /&gt;
&lt;br /&gt;
However, the core principles are simple and sound.
&lt;br /&gt;
&lt;br /&gt;
The first step is to &lt;b&gt;understand the environment&lt;/b&gt; (system) in which problem is being solved. This includes building a mental model of what are the actors in the system, the useful (desired) and harmful properties of the system.
&lt;br /&gt;
&lt;br /&gt;
Furthermore, one should try to extend the boundaries of vision and see not just the system itself, but other interacting systems. Then, going even wider and seeing macro-level ("metasystems") and micro-level ("subsystems"). And not just that - all this should also be extended in time to the past and the future.
&lt;br /&gt;
&lt;br /&gt;
TRIZ claims that there are certain &lt;b&gt;principles of technical systems evolution&lt;/b&gt;, and the need of inventions stems from the fact that some parts of the system are not developed in harmony with some other parts. This tension essentially creates the problems we are trying to solve.
&lt;br /&gt;
&lt;br /&gt;
At this point one is supposed to understand which exactly problem is tried to be solved, and thus this problem then gets reduced to a simple model. Essential part of this is about finding so called &lt;b&gt;contradiction&lt;/b&gt; between two certain properties (parts) of the system. Note that real-world problems usually are not that straightforward - there can be more than single conflicting pair of system properties, but it's claimed that most of the problems can be decomposed to simpler subproblems which would satisfy that duality requirement.
&lt;br /&gt;
&lt;br /&gt;
The next thing to realize is the exact locality of the contradiction in time and space (when and where exactly the conflict does take place) - so called &lt;b&gt;operating zone&lt;/b&gt;.
&lt;br /&gt;
&lt;br /&gt;
Then, solving the problem is essentially about &lt;b&gt;overcoming the contradiction&lt;/b&gt;, but not in just any way - while doing that one should aim for so called &lt;b&gt;ideal solution&lt;/b&gt;.
&lt;br /&gt;
&lt;br /&gt;
Ideal solution is another central principle in TRIZ. What we are trying to achieve should happen "on it's own", i.e. desired new property of the system should be achieved &lt;i&gt;without&amp;nbsp;modifying&amp;nbsp;the system at all&lt;/i&gt; (remember "the fastest code is the one you never run"?..)
&lt;br /&gt;
&lt;br /&gt;
Now, it's obviously not always possible, and in practice one would end with some kind of compromise anyway. But the point here is to build a proper mental setup, which would divert mind from aiming at compromises prematurely.
&lt;br /&gt;
&lt;br /&gt;
To achieve this ideal solution we try to identify &lt;b&gt;existing system resources&lt;/b&gt; and then employ them in some way. If there is no easy way - we may try transforming them first. 
&lt;br /&gt;
&lt;br /&gt;
Particular resources and their transformations are subject of rigorous classification in TRIZ - there are tables, guidelines, &lt;a href="http://www.triz40.com/aff_Principles.htm"&gt;principles&lt;/a&gt; which are built as the result of analysis of classes of existing good solutions. Some of those may be directly applied to the the software development as well (even though I am skeptical about attempts to map &lt;a href="http://www.triz-journal.com/archives/2001/09/e/index.htm"&gt;all&lt;/a&gt; &lt;a href="http://www.triz-journal.com/archives/2001/11/e/index.htm"&gt;of them&lt;/a&gt;). But what is more important here is another (rather obvious) principle: &lt;b&gt;borrow existing good ideas&lt;/b&gt;. 
&lt;br /&gt;
&lt;br /&gt;
For that to happen one has to build the awareness (implicit "knowledge base") about what good software ideas are already out there. No, it's not just about &lt;a href="http://ns.c2.com/cgi/wiki?DesignPatterns"&gt;Design Patterns&lt;/a&gt;, even though they are certainly have some place in this awareness. 
&lt;br /&gt;
&lt;br /&gt;
This proccess has &lt;b&gt;iterative&lt;/b&gt; nature. One should be ready to "restart" the chain of thinking in the case that particular original model does not really lead to the desired solution. In this case it means returning back to analysing the system (subsystems, metasystems) and either building a different model, or even &lt;b&gt;trying to solve different problem&lt;/b&gt;. 

It's also important to constantly &lt;b&gt;reflect&lt;/b&gt; on own thinking process and especially on the solutions which are being found.

&lt;br /&gt;
&lt;br /&gt;
Now, just for an example of how this kind of thinking could map to the activity of problem solving in software development world. There was this wonderful talk, &lt;a href="http://www.youtube.com/watch?v=3ka4KY7TMTU"&gt;"Self and Self"&lt;/a&gt; by David Ungar, which I highly recommend watching. 
&lt;br /&gt;
&lt;br /&gt;
He mentions about how the idea of &lt;a href="http://chaoticjava.com/posts/how-does-garbage-collection-work/"&gt;generational garbage collector&lt;/a&gt; (today used in some form in the most of modern virtual machines) visited him when solving performance problems in virtual machine of &lt;a href="http://en.wikipedia.org/wiki/Self_(programming_language)"&gt;Self&lt;/a&gt;.
&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator c2"&gt;
&lt;a class="c7" href="http://www.youtube.com/watch?v=3ka4KY7TMTU" imageanchor="1"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/_DVYH9neSnMw/S6lVvHmfMYI/AAAAAAAAAQ8/U3K23D28Y00/s320/ungar.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
There are some parallels to observe:
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;li&gt; Memory usage/CPU conflict during garbage collection (two useful system properties conflicting with each other) &lt;/li&gt;
&lt;li&gt; Exploiting skewed probabilities (identify and use existing system resources) &lt;/li&gt;
&lt;li&gt; Optimize by eliminating work (ideal solution) &lt;/li&gt;
&lt;li&gt; Optimize what's important (operating zone) &lt;/li&gt;
&lt;li&gt; Garbage collection should happen to free the memory, and it should not happen because it is time-consuming (contradiction) &lt;/li&gt;
&lt;li&gt; "Generations" - birth, getting old, dying (&lt;a href="http://www.ideationtriz.com/TRIZ_tutorial_6.htm"&gt;"little fellas"&lt;/a&gt; method) &lt;/li&gt;
&lt;br /&gt;
I dare to speculate that there is a chance that aforementioned mental devices could lead to this idea. Even though it's a pure speculation, it's still interesting.
&lt;br /&gt;
&lt;br /&gt;
According to the authors, TRIZ "works" because it helps to chunk the solution space and direct the mind of inventor towards good&amp;nbsp;solutions, shifting the focus away from the "bad" ones.
&lt;br /&gt;
&lt;br /&gt;
Metaphorically, if problem solving is a game (so one is picking the "best" move out of many possible), then TRIZ is probably something like &lt;a href="http://en.wikipedia.org/wiki/Alpha-beta_pruning"&gt;alpha-beta&amp;nbsp;pruning&lt;/a&gt; with&amp;nbsp;heuristics. It reduces the amount of solutions to examine by&amp;nbsp;cutting away the whole "bad solutions branches" when searching the game tree. Essentially, "the algoritm of invention" is nothing&amp;nbsp;else as an attempt to heuristically optimize the huge solution space search,&amp;nbsp;which &lt;a href="http://en.wikipedia.org/wiki/G%C3%B6del,_Escher,_Bach"&gt;happens in human mind&lt;/a&gt;:

&lt;br /&gt;
&lt;blockquote&gt;
The conclusion is that in normal chess play, certain types of situation recur - certain patterns - and it is to those high-level patterns that master is sensitive. He thinks on a &lt;i&gt;different level&lt;/i&gt; from the novice; his set of concepts is different. Nearly everyone is surprised to
find out that in actual play, a master rarely looks ahead any further than a novice does - and moreover, a master usually examines only a handful of possible moves! 
&lt;br /&gt;
&lt;br /&gt;
The trick is that his mode of perceiving the board is like a filter: he literally &lt;i&gt;does not see bad moves&lt;/i&gt; when he looks at a chess situation - no more than chess amateurs see &lt;i&gt;illegal&lt;/i&gt; moves when they look at a chess situation. [...] This might be called &lt;i&gt;implicit
pruning&lt;/i&gt;of the giant branching tree of possibilities. By contrast,&lt;i&gt;explicit pruning&lt;/i&gt;
would involve thinking of a move, and after superficial examination, deciding not
to pursue examining any further.&lt;/blockquote&gt;
&lt;br /&gt;
Does it all mean that one can universally apply TRIZ or similar methodology to creatively solve programming problems?.. I don't really think so. Every person is unique in which mental processes work for them better.
&lt;br /&gt;
&lt;br /&gt;
Still, the described principles, such as: refining the problem, finding the contradiction and bending it to extreme, looking for an ideal solution and trying to employ existing resources of the system (possibly transforming them), borrowing the ideas from existing great software solutions, fighting the psychological inertia - all of them can be useful regardless.
&lt;br /&gt;
&lt;br /&gt;
I guess the process of developing one's own mental toolset is neverending and happens continuously through the career and life. 
&lt;br /&gt;
&lt;br /&gt;
And this is just another tool. Who knows, maybe it will find its place.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/923082020090979517-9087446240703701803?l=blog.ruslans.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/gd_reflections/~4/GStJIYRlzzI" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.ruslans.com/feeds/9087446240703701803/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=923082020090979517&amp;postID=9087446240703701803" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/923082020090979517/posts/default/9087446240703701803" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/923082020090979517/posts/default/9087446240703701803" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/gd_reflections/~3/GStJIYRlzzI/learn-yourself-some-innovation.html" title="Learn yourself some innovation" /><author><name>ruslans</name><uri>http://www.blogger.com/profile/03375859473751956887</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="24" height="32" src="http://2.bp.blogspot.com/_DVYH9neSnMw/S0V_XM6aN0I/AAAAAAAAAMc/06dTTnY0PNw/S220/avatar3.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/_DVYH9neSnMw/S8UhshgvhMI/AAAAAAAAASY/Mzrzp-bInxc/s72-c/apple.png" height="72" width="72" /><thr:total>2</thr:total><feedburner:origLink>http://blog.ruslans.com/2010/04/learn-yourself-some-innovation.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-923082020090979517.post-4474147604687949980</id><published>2010-04-02T06:23:00.000-07:00</published><updated>2010-04-16T00:28:16.590-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="productivity" /><category scheme="http://www.blogger.com/atom/ns#" term="self-improvement" /><title type="text">Getting a good habit, the easy way</title><content type="html">I consider myself an extremely unorganized person, which makes me sometimes wonder what the hell am I doing being a programmer.&lt;br /&gt;
&lt;br /&gt;
In software development, planning is an essential activity for getting the job done - something that I've learned the hard way - and personal traits must be essential in this regard.&lt;br /&gt;
&lt;br /&gt;
However, I've also learned that some of those traits can be actually gained with a bit of effort. Specifically, when we talk about habits, there are several mind exploits, which can be used to &lt;a href="http://blog.ruslans.com/2009/06/pragmatic-thinking-by-andy-hunt.html"&gt;rewire the brain&lt;/a&gt;. &lt;br /&gt;
&lt;br /&gt;
Here's one particularly dead simple, nevertheless useful professional habit, which I managed to get during the last year: &lt;b&gt;using ToDo list for everyday microplanning&lt;/b&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_DVYH9neSnMw/S7KPMd5xGTI/AAAAAAAAAR8/-sWFTJApRM8/s1600/todo1.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="212" src="http://3.bp.blogspot.com/_DVYH9neSnMw/S7KPMd5xGTI/AAAAAAAAAR8/-sWFTJApRM8/s320/todo1.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
As with any good habit, there are several things which can help: &lt;br /&gt;
&lt;ul&gt;&lt;li&gt;should be simple to do, non-burdened with time-wasting activities&lt;/li&gt;
&lt;li&gt;consistent, repeatable in a simple ritual-like steps&amp;nbsp;&lt;/li&gt;
&lt;li&gt;providing positive feedback&lt;/li&gt;
&lt;li&gt;have some triggering mechanisms &amp;nbsp;&lt;/li&gt;
&lt;li&gt;be forgiving to yourself, no giving up early because of false starts&lt;/li&gt;
&lt;li&gt;some kind of public commitment, even artificial one, can also help&lt;/li&gt;
&lt;/ul&gt;&lt;a href="http://2.bp.blogspot.com/_DVYH9neSnMw/S7XPVbUNDLI/AAAAAAAAASE/k_YFglBx8Y8/s1600/todo7.jpg" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/_DVYH9neSnMw/S7XPVbUNDLI/AAAAAAAAASE/k_YFglBx8Y8/s320/todo7.jpg" /&gt;&lt;/a&gt;I use AbstractSpoon &amp;nbsp;&lt;a href="http://www.codeproject.com/script/Articles/ArticleVersion.aspx?aid=5371&amp;amp;av=73114"&gt;ToDoList&lt;/a&gt; (it's really nice and free but Windows-only, unfortunately... however there are many Linux alternatives - the particular application does not really matter).&lt;br /&gt;
&lt;br /&gt;
There are some simple things to make its usage &lt;b&gt;feel streamlined&lt;/b&gt;:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;system-wide shortcut to toggle the application window quickly (Ctrl+Shift+T in my case)&lt;/li&gt;
&lt;li&gt;it&amp;nbsp;starts on system start and resides as an icon in the system tray&lt;/li&gt;
&lt;li&gt;auto-saves on window&amp;nbsp;losing focus&lt;/li&gt;
&lt;li&gt;I use&amp;nbsp;&lt;a href="https://www.dropbox.com/"&gt;dropbox&lt;/a&gt;&amp;nbsp;as a simple way to share the tasklist between different computers.&lt;/li&gt;
&lt;/ul&gt;I start every working day with a &lt;b&gt;simple ritual&lt;/b&gt;:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;open ToDoList with keyboard shortcut and create the new top-level task named by the current date (e.g. "30 mar").&lt;/li&gt;
&lt;li&gt;look at the previous day's ("29 mar") undone tasks, and either move them to the new day, or to the special "Maybe Later" top-level task.&lt;/li&gt;
&lt;li&gt;think about what else is to be done today (usually there is some higher-level issue tracking system, such as &lt;a href="http://trac.edgewall.org/"&gt;Trac&lt;/a&gt;&amp;nbsp;or &lt;a href="http://www.atlassian.com/software/jira/"&gt;JIRA&lt;/a&gt;, which already has a list of issues assigned to me and can serve as a guide), and roughly populate "30 mar" with today's goals.&lt;/li&gt;
&lt;li&gt;look into the "Maybe Later" box and consider if there's something that can be fetched from there for this day. Also, close those of the entries there which are not actual anymore.&lt;/li&gt;
&lt;li&gt;the current day's goals should be pretty fine-grained (I feel more or less comfortable when there are around 10 of them, doable during the working day), but it's not necessary to go into all the details now, they can be refined later, when it actually comes to doing them.&lt;/li&gt;
&lt;li&gt;assign priorities to all the entries (10 being the highest), and they get automatically sorted, topmost being with the highest priority.&lt;/li&gt;
&lt;li&gt;close the task list and start working on the topmost task.&lt;/li&gt;
&lt;/ul&gt;During the day the shape of the list can change - and it's fine.&lt;br /&gt;
&lt;div&gt;Some new things may pop in, in which case they get &lt;b&gt;dispatched correspondingly&lt;/b&gt;:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;if it's an urgent emergency task, then it gets right to the top of the current task list, with the highest priority.&lt;/li&gt;
&lt;li&gt;if it is something which needs to be done, but not necessarily today, then it gets into "Maybe Later" box.&lt;/li&gt;
&lt;li&gt;if this is just a "nice to have" kind of thing, then it gets into the special "IDEAS" box, which is located below the "Maybe Later" one.&lt;/li&gt;
&lt;li&gt;some tasks can happen to become obsolete during the day, then they just get crossed out.&lt;/li&gt;
&lt;/ul&gt;Also, priorities of the tasks can change during the day - I also consider it to be an expected phenomena.&lt;br /&gt;
&lt;br /&gt;
Whenever this "popping in", or any other kind of distraction (quite usual on the working place, unfortunately) happens, there is always this magical "what was I doing" keyboard shortcut, which helps to &lt;b&gt;switch the context back&lt;/b&gt; and focus again at the task at hand.&lt;br /&gt;
&lt;br /&gt;
It did not work all that well from the first attempt, of course, but eventually I managed to get into this &lt;b&gt;simple everyday&amp;nbsp;rhythm&lt;/b&gt; and started to feel comfortable with it.&lt;br /&gt;
&lt;br /&gt;
There is this &lt;b&gt;inherent sense of satisfaction&lt;/b&gt; in seeing several things crossed out at the end of the day, and being able to answer these simple, yet important questions: "&lt;b&gt;what have I done today?&lt;/b&gt; is there anything exceptional about it? why not, exactly?"&lt;/div&gt;&lt;br /&gt;
I believe that this manner of dispatching tasks somewhat resembles the &lt;a target="_blank"  href="http://www.amazon.com/Getting-Things-Done-Stress-Free-Productivity/dp/0142000280?ie=UTF8&amp;tag=gdreflections-20&amp;link_code=btl&amp;camp=213689&amp;creative=392969"&gt;Getting Things Done&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=gdreflections-20&amp;l=btl&amp;camp=213689&amp;creative=392969&amp;o=1&amp;a=0142000280" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important; padding: 0px !important" /&gt; method.&lt;br /&gt;
&lt;br /&gt;
There are few "buckets" of prioritized tasks, which periodically get processed, with the "short term" bucket being a list of today's tasks.&lt;br /&gt;
&lt;br /&gt;
It's not exactly the same, of course. But perhaps I will try to follow the GTD method more closely, eventually.&lt;br /&gt;
&lt;br /&gt;
After all, it's just another useful habit to try developing. There is no harm in trying it, and no penalty if it does not work for me.&lt;br /&gt;
&lt;br /&gt;
Doing the impossible things (such as changing one's personality traits, for example) turns out to be not that hard - with a little bit of persistence and open-mindedness.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/923082020090979517-4474147604687949980?l=blog.ruslans.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/gd_reflections/~4/5RAZW5XFtWI" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.ruslans.com/feeds/4474147604687949980/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=923082020090979517&amp;postID=4474147604687949980" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/923082020090979517/posts/default/4474147604687949980" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/923082020090979517/posts/default/4474147604687949980" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/gd_reflections/~3/5RAZW5XFtWI/getting-good-habit-easy-way-or-how-i.html" title="Getting a good habit, the easy way" /><author><name>ruslans</name><uri>http://www.blogger.com/profile/03375859473751956887</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="24" height="32" src="http://2.bp.blogspot.com/_DVYH9neSnMw/S0V_XM6aN0I/AAAAAAAAAMc/06dTTnY0PNw/S220/avatar3.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/_DVYH9neSnMw/S7KPMd5xGTI/AAAAAAAAAR8/-sWFTJApRM8/s72-c/todo1.jpg" height="72" width="72" /><thr:total>1</thr:total><feedburner:origLink>http://blog.ruslans.com/2010/04/getting-good-habit-easy-way-or-how-i.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-923082020090979517.post-1930106474607243205</id><published>2010-03-17T20:39:00.000-07:00</published><updated>2011-04-25T14:27:15.492-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ai" /><category scheme="http://www.blogger.com/atom/ns#" term="productivity" /><category scheme="http://www.blogger.com/atom/ns#" term="programming languages" /><category scheme="http://www.blogger.com/atom/ns#" term="scripting" /><title type="text">The Dragon Age of mainstream game scripting</title><content type="html">&lt;a href="http://2.bp.blogspot.com/_DVYH9neSnMw/S6GQA7rzAJI/AAAAAAAAAQk/esF8BYU8QSg/s1600-h/Dragon-Age-Origins-Logo.jpg" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" height="160" src="http://2.bp.blogspot.com/_DVYH9neSnMw/S6GQA7rzAJI/AAAAAAAAAQk/esF8BYU8QSg/s200/Dragon-Age-Origins-Logo.jpg" width="200" /&gt;&lt;/a&gt;It's amazing how much depth great role-playing games can have to them. Some of the quests, which start as usual pre-canned in-game experience, can suddenly spill themselves onto higher layers of reality, sometimes in quite unanticipated ways. &lt;br /&gt;
&lt;br /&gt;
I had been enjoying &lt;a href="http://en.wikipedia.org/wiki/Dragon_Age:_Origins"&gt;Dragon Age: Origins&lt;/a&gt;&amp;nbsp;for quite a while&amp;nbsp;already, before I found myself engaged into one of such meta-quests, which I'd like to tell about.&lt;br /&gt;
&lt;br /&gt;
So, I went to Orzammar, the underground dwarven capital, where the "A Paragon of Her Kind" storyline subplot started to unwrap. There was quite intricate political struggle for the crown between two houses going on there, and apparently I was expected to eventually side with one of the parties.&lt;br /&gt;
&lt;br /&gt;
In quite a boilerplate way, the two emissaries were giving tasks to be fullfilled in order to prove the loyalty to either of houses. Apparently, it was also anticipated by the developers that player might want to try playing both sides in a double-agent kind of way, and that's what I've tried doing...&lt;br /&gt;
just to find out that the whole plot got stuck into a logical deadlock, which &lt;a href="http://dragonage.wikia.com/wiki/A_Lord%27s_Trust:_The_First_Task#Bugs"&gt;turned out to be a bug&lt;/a&gt;. Of course, I did not have the recent save games to reload from (of course!), so I became disappointed and unmotivated.&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;a href="http://4.bp.blogspot.com/_DVYH9neSnMw/S6GiXbWHeiI/AAAAAAAAAQ0/sGTprahZ7WQ/s1600-h/dao_toolset.jpg" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" height="135" src="http://4.bp.blogspot.com/_DVYH9neSnMw/S6GiXbWHeiI/AAAAAAAAAQ0/sGTprahZ7WQ/s200/dao_toolset.jpg" width="200" /&gt;&lt;/a&gt;Luckily, Bioware released the &lt;a href="http://social.bioware.com/wiki/datoolset"&gt;Dragon Age Toolkit&lt;/a&gt;, which any owner of the game can download and use to modify the game to his taste. It's a great move from their side to have it released, which me and I believe a lot of other people really appreciate. So, I downloaded it, installed and digged straight into the scripts trying to find the place which could be patched to allow me keep playing.&lt;br /&gt;
&lt;br /&gt;
Long story short, I succeeded at hacking the game plot script and could enjoy the game again.&amp;nbsp;It would be a perfect time for the happy end, perhaps, but the whole "fix the quest scripts to allow continuing playing the game" meta-quest spawned even new set of quests in different layers of reality.&lt;br /&gt;
&lt;br /&gt;
The first quest was about learning how the DA Toolset works, getting insight into the tools and workflow which developers used to produce this great game, examining its strengths and weaknesses. Very useful experience.&lt;br /&gt;
&lt;br /&gt;
But there was another thing, which somewhat stroke me. In the process of digging the scripts I've got the impression that the script code structure is quite a bit more complicated than it could be. The logical deadlock bug in the scripts, mentioned above, turned out to be not as surprising as one would expect, given that author had to anticipate the combinatorial explosion of all the many possible developments in the plot, and the language used for that did not seem helping much in that... and I wonder how much QA efforts and bugfixes&amp;nbsp; it needed before getting into the shippable state.&lt;br /&gt;
&lt;br /&gt;
This another meta-quest was about understanding the current state of higher-level game programming DSLs (aka "game scripting languages"), which in turn made me also sidetracked into such side-quests as trying to learn about the &lt;a href="http://en.wikipedia.org/wiki/Prolog"&gt;Prolog&lt;/a&gt; programming language, &lt;a href="http://en.wikipedia.org/wiki/Semantic_network"&gt;semantic networks&lt;/a&gt; and what else... but I digress.&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_DVYH9neSnMw/S6GUBynr75I/AAAAAAAAAQs/zH-6rU8u5Ss/s1600-h/dulin.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/_DVYH9neSnMw/S6GUBynr75I/AAAAAAAAAQs/zH-6rU8u5Ss/s320/dulin.png" /&gt;&lt;/a&gt;&lt;/div&gt;In case of Dragon Age, the &lt;a href="http://social.bioware.com/wiki/datoolset/index.php/Scripting_overview"&gt;scripting language&lt;/a&gt; has a simple C-like structure, and workflow in scripts is centered around events coming from the engine and other scripts.&lt;br /&gt;
&lt;br /&gt;
When it comes to the story&amp;nbsp;development, scripts collaborate closely with the &lt;a href="http://social.bioware.com/wiki/datoolset/index.php/Conversation_plots_and_scripting"&gt;conversation editor&lt;/a&gt;, which is used to build the dialog trees (which are not actually trees, but rather &lt;a href="http://en.wikipedia.org/wiki/Directed_acyclic_graph"&gt;DAGs&lt;/a&gt;, still represented in a tree view in the editor). Each branch in the dialog tree can be masked out by some global flag, as well as it can change some global flag if player picks this dialog branch in the conversation.&lt;br /&gt;
&lt;br /&gt;
This leads to the following patterns:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;there is a rather extensive set of global flags, related to the given storyline. Sometimes these flags can be quite complicated (e.g. "A_HAPPENED_BUT_B_HAVENT_HAPPENED_YET_AND_PLAYER_DID_C")&lt;/li&gt;
&lt;li&gt;when flag changes (triggered by the player picking certain dialog branch or for some other reason), it fires the event. Events are handled in the scripts, in rather big switch/case blocks.&lt;/li&gt;
&lt;li&gt;every case block can have complex and nested conditions checks, which may change other flags as the result, for example enabling/disabling some other dialog tree branches.&lt;/li&gt;
&lt;/ul&gt;All in all, amount of bookkeeping-style code compared to the actual logic code seems to be incredibly high, and logic code itself is spread over different places, the code being heavy on side-effects. &amp;nbsp;And it's not due to the bad coding, obviously, but rather because of the traits of the scripting language and framework itself.&lt;br /&gt;
&lt;br /&gt;
It seems that one of the main criterias in picking the scripting language for game development still remains familiarity, which most of the time just &lt;a href="http://www.moddb.com/games/overgrowth/news/choosing-a-scripting-language"&gt;means syntax familiarity&lt;/a&gt;.&lt;br /&gt;
Familiarity is considered to be important, so that designers and generally people not having "extensive programming background" can use it without much problems.&lt;br /&gt;
&lt;br /&gt;
And I guess it makes sense. For example, in case of Dragon Age, majority of the scripts appear to be written by intern and fresh from the college folks (one can track the author names from the scripts themselves). Now, by no means I am trying to imply that it somehow correlates with the code quality - years of experience quite often mean nothing, and no doubt those people coming from college are brilliant. But I believe it still kind of shows the general attitude in the industry. Which is: "Game logic scripting is a beginner level, routine task".&lt;br /&gt;
&lt;br /&gt;
Still, the question arises: is this really the most productive level of abstraction to work with? Could be &amp;nbsp;low-level imperative manipulation with global flags and multiply nested blocks of if-then-else logic, giant case switches with side effects replaced with something which maps better into the domain area? Something, which would allow&amp;nbsp;to do more complex, rich, interesting, emergent things without need focusing attention on the spaghetti logic and fighting the peculiarities of the scripting language?..&lt;br /&gt;
&lt;br /&gt;
Despite all the &lt;a href="http://lambda-the-ultimate.org/node/1277"&gt;interest&lt;/a&gt;, &lt;a href="http://queue.acm.org/detail.cfm?id=1483106"&gt;research&lt;/a&gt; &lt;a href="http://grandtextauto.org/"&gt;and&lt;/a&gt; &lt;a href="http://www.interactivestory.net/"&gt;developments&lt;/a&gt; in this area, it seems that on the industrial, mainstream level, the technologies which serve as the game designer's medium for creating the high-level game playing experience, remain grossly underdeveloped. But it would be unfair to call it "the stone age", of course. It &lt;b&gt;is&lt;/b&gt; developing, albeit slowly. And, no matter what tools are used to achieve it, in the end of the day it's&amp;nbsp;&lt;a href="http://www.gamasutra.com/view/news/27162/Dragon_Age_Origins_Sells_In_32_Million_Units.php"&gt;the end result which matters&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Thus I dub the present as "The dragon age of mainstream game scripting".&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/923082020090979517-1930106474607243205?l=blog.ruslans.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/gd_reflections/~4/JHBdXMacQmw" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.ruslans.com/feeds/1930106474607243205/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=923082020090979517&amp;postID=1930106474607243205" title="10 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/923082020090979517/posts/default/1930106474607243205" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/923082020090979517/posts/default/1930106474607243205" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/gd_reflections/~3/JHBdXMacQmw/dragon-age-of-mainstream-game-scripting.html" title="The Dragon Age of mainstream game scripting" /><author><name>ruslans</name><uri>http://www.blogger.com/profile/03375859473751956887</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="24" height="32" src="http://2.bp.blogspot.com/_DVYH9neSnMw/S0V_XM6aN0I/AAAAAAAAAMc/06dTTnY0PNw/S220/avatar3.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/_DVYH9neSnMw/S6GQA7rzAJI/AAAAAAAAAQk/esF8BYU8QSg/s72-c/Dragon-Age-Origins-Logo.jpg" height="72" width="72" /><thr:total>10</thr:total><feedburner:origLink>http://blog.ruslans.com/2010/03/dragon-age-of-mainstream-game-scripting.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-923082020090979517.post-1132344669153232506</id><published>2010-01-27T15:58:00.000-08:00</published><updated>2010-04-16T00:12:25.651-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="storytelling" /><category scheme="http://www.blogger.com/atom/ns#" term="perforce" /><category scheme="http://www.blogger.com/atom/ns#" term="visualization" /><title type="text">Code opera: using Gource to watch a story of Perforce depot</title><content type="html">&lt;a href="http://code.google.com/p/gource/"&gt;Gource&lt;/a&gt;&amp;nbsp;is a neat open-source tool which allows to visualize&amp;nbsp;dynamics of&amp;nbsp;source code repositories, using a planar, &lt;a href="http://en.wikipedia.org/wiki/Spring_based_algorithm"&gt;spring-based&lt;/a&gt; tree layout ("&lt;a href="http://www.cs.usyd.edu.au/~visual/comp4048/Tree_visualization.ppt"&gt;balloon tree"&lt;/a&gt;).&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;b&gt;&lt;span style="font-size: x-large;"&gt;Showing P4 depot&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
Why being interested in &lt;a href="http://perforce.com/"&gt;Perforce&lt;/a&gt; in particular - a proprietary, non-free (and rather expensive) software?.. For a couple of reasons:&lt;br /&gt;
* It's quite commonly used in a big, corporate software shops (including the one I am working at), and still theoretically&amp;nbsp;&lt;a href="http://www.perforce.com/perforce/opensource-faq.html"&gt;can be used&lt;/a&gt; in open software projects, for free (as in a beer)&lt;br /&gt;
* Gource does not seem to have an official support for it yet (it supports Git/Mercurial out of the box, and SVN/CVS via contrib Python scripts)&lt;br /&gt;
&lt;br /&gt;
As an example we can check &lt;a href="http://stlab.adobe.com/wiki/index.php/Using_Perforce_with_the_Adobe_Source_Libraries"&gt;Adobe Source Libraries&lt;/a&gt;:&lt;br /&gt;
&lt;blockquote&gt;export P4PORT=stlab.adobe.com:10666&lt;br /&gt;
export P4USER=guest&lt;br /&gt;
echo "AdobeGuest" | p4 login&lt;br /&gt;
perl gource-p4.pl //adobe_source_libraries/ &amp;gt; gil.log&lt;br /&gt;
gource --log-format custom gil.log&lt;br /&gt;
&lt;/blockquote&gt;(it may take a little while to gather the log file).&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_DVYH9neSnMw/S2DB-Cn5j0I/AAAAAAAAAPE/_BJqTjLS41k/s1600-h/jam-gource.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/_DVYH9neSnMw/S2DB-Cn5j0I/AAAAAAAAAPE/_BJqTjLS41k/s320/jam-gource.png" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;/div&gt;Another example is &lt;a href="http://en.wikipedia.org/wiki/Perforce_Jam"&gt;Jam&lt;/a&gt;&amp;nbsp;(open-source build system)&amp;nbsp;depot. This time in Windows command line:&lt;br /&gt;
&lt;blockquote&gt;p4 set&amp;nbsp;P4PORT=public.perforce.com:1666&lt;br /&gt;
p4 set P4USER=anon&lt;br /&gt;
p4 login&lt;br /&gt;
perl gource-p4.pl //public/jam/src/ &amp;gt; jam.log&lt;br /&gt;
gource --log-format custom&amp;nbsp;jam.log&lt;br /&gt;
&lt;/blockquote&gt;The gource-p4.pl script looks like this:&lt;br /&gt;
&lt;pre style="-webkit-background-clip: initial; -webkit-background-origin: initial; background-attachment: initial; background-color: #f6f8ff; background-image: initial; background-position: initial initial; background-repeat: initial; color: #000020; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;&lt;span style="color: #595979;"&gt;#!/usr/bin/perl&lt;/span&gt;

&lt;span style="color: #007d45;"&gt;$root&lt;/span&gt; &lt;span style="color: #308080;"&gt;=&lt;/span&gt; &lt;span style="color: #007d45;"&gt;$ARGV&lt;/span&gt;&lt;span style="color: #308080;"&gt;[&lt;/span&gt;&lt;span style="color: #008c00;"&gt;0&lt;/span&gt;&lt;span style="color: #308080;"&gt;]&lt;/span&gt;&lt;span style="color: #406080;"&gt;;&lt;/span&gt;
&lt;span style="color: #200080; font-weight: bold;"&gt;map&lt;/span&gt; &lt;span style="color: #406080;"&gt;{&lt;/span&gt; &lt;span style="color: #200080; font-weight: bold;"&gt;my&lt;/span&gt;&lt;span style="color: #308080;"&gt;(&lt;/span&gt;&lt;span style="color: #007d45;"&gt;$change&lt;/span&gt;&lt;span style="color: #308080;"&gt;,&lt;/span&gt; &lt;span style="color: #007d45;"&gt;$user&lt;/span&gt;&lt;span style="color: #308080;"&gt;)&lt;/span&gt; &lt;span style="color: #308080;"&gt;=&lt;/span&gt; &lt;span style="color: #007d45;"&gt;$_&lt;/span&gt; &lt;span style="color: #308080;"&gt;=&lt;/span&gt;&lt;span style="color: #308080;"&gt;~&lt;/span&gt;&lt;span style="color: #1060b6;"&gt; &lt;/span&gt;&lt;span style="color: maroon;"&gt;/&lt;/span&gt;&lt;span style="color: #1060b6;"&gt;Change &lt;/span&gt;&lt;span style="color: #308080;"&gt;(&lt;/span&gt;&lt;span style="color: #308080;"&gt;.&lt;/span&gt;&lt;span style="color: #308080;"&gt;*&lt;/span&gt;&lt;span style="color: #308080;"&gt;)&lt;/span&gt;&lt;span style="color: #1060b6;"&gt; on&lt;/span&gt;&lt;span style="color: #308080;"&gt;.&lt;/span&gt;&lt;span style="color: #308080;"&gt;*&lt;/span&gt;&lt;span style="color: #1060b6;"&gt;by &lt;/span&gt;&lt;span style="color: #308080;"&gt;(&lt;/span&gt;&lt;span style="color: #308080;"&gt;.&lt;/span&gt;&lt;span style="color: #308080;"&gt;*&lt;/span&gt;&lt;span style="color: #308080;"&gt;?&lt;/span&gt;&lt;span style="color: #308080;"&gt;)&lt;/span&gt;&lt;span style="color: #1060b6;"&gt;@&lt;/span&gt;&lt;span style="color: #308080;"&gt;.&lt;/span&gt;&lt;span style="color: #308080;"&gt;*&lt;/span&gt;&lt;span style="color: maroon;"&gt;/&lt;/span&gt;&lt;span style="color: #406080;"&gt;;&lt;/span&gt;
    &lt;span style="color: #200080; font-weight: bold;"&gt;map&lt;/span&gt; &lt;span style="color: #406080;"&gt;{&lt;/span&gt; &lt;span style="color: #200080; font-weight: bold;"&gt;my&lt;/span&gt;&lt;span style="color: #308080;"&gt;(&lt;/span&gt;&lt;span style="color: #007d45;"&gt;$file&lt;/span&gt;&lt;span style="color: #308080;"&gt;,&lt;/span&gt; &lt;span style="color: #007d45;"&gt;$act&lt;/span&gt;&lt;span style="color: #308080;"&gt;,&lt;/span&gt; &lt;span style="color: #007d45;"&gt;$time&lt;/span&gt;&lt;span style="color: #308080;"&gt;)&lt;/span&gt; &lt;span style="color: #308080;"&gt;=&lt;/span&gt; 
            &lt;span style="color: #007d45;"&gt;$_&lt;/span&gt; &lt;span style="color: #308080;"&gt;=&lt;/span&gt;&lt;span style="color: #308080;"&gt;~&lt;/span&gt;&lt;span style="color: #1060b6;"&gt; &lt;/span&gt;&lt;span style="color: maroon;"&gt;/&lt;/span&gt;&lt;span style="color: #007d45;"&gt;$root&lt;/span&gt;&lt;span style="color: #308080;"&gt;(&lt;/span&gt;&lt;span style="color: #308080;"&gt;.&lt;/span&gt;&lt;span style="color: #308080;"&gt;*&lt;/span&gt;&lt;span style="color: #308080;"&gt;)&lt;/span&gt;&lt;span style="color: #0f69ff;"&gt;\n&lt;/span&gt;&lt;span style="color: #308080;"&gt;.&lt;/span&gt;&lt;span style="color: #308080;"&gt;+&lt;/span&gt;&lt;span style="color: #1060b6;"&gt;headAction &lt;/span&gt;&lt;span style="color: #308080;"&gt;(&lt;/span&gt;&lt;span style="color: #308080;"&gt;.&lt;/span&gt;&lt;span style="color: #308080;"&gt;*&lt;/span&gt;&lt;span style="color: #308080;"&gt;)&lt;/span&gt;&lt;span style="color: #0f69ff;"&gt;\n&lt;/span&gt;&lt;span style="color: #308080;"&gt;.&lt;/span&gt;&lt;span style="color: #308080;"&gt;+&lt;/span&gt;&lt;span style="color: #0f69ff;"&gt;\n&lt;/span&gt;&lt;span style="color: #308080;"&gt;.&lt;/span&gt;&lt;span style="color: #308080;"&gt;+&lt;/span&gt;&lt;span style="color: #1060b6;"&gt;headTime &lt;/span&gt;&lt;span style="color: #308080;"&gt;(&lt;/span&gt;&lt;span style="color: #308080;"&gt;.&lt;/span&gt;&lt;span style="color: #308080;"&gt;*&lt;/span&gt;&lt;span style="color: #308080;"&gt;)&lt;/span&gt;&lt;span style="color: #0f69ff;"&gt;\n&lt;/span&gt;&lt;span style="color: #308080;"&gt;.&lt;/span&gt;&lt;span style="color: #308080;"&gt;*&lt;/span&gt;&lt;span style="color: maroon;"&gt;/&lt;/span&gt;&lt;span style="color: #406080;"&gt;;&lt;/span&gt; 
        &lt;span style="color: #007d45;"&gt;$act&lt;/span&gt; &lt;span style="color: #308080;"&gt;=&lt;/span&gt;&lt;span style="color: #308080;"&gt;~&lt;/span&gt; &lt;span style="color: #200080; font-weight: bold;"&gt;s&lt;/span&gt;&lt;span style="color: maroon;"&gt;/&lt;/span&gt;&lt;span style="color: #1060b6;"&gt;edit&lt;/span&gt;&lt;span style="color: #406080;"&gt;|&lt;/span&gt;&lt;span style="color: #1060b6;"&gt;integrate&lt;/span&gt;&lt;span style="color: #406080;"&gt;|&lt;/span&gt;&lt;span style="color: #1060b6;"&gt;branch&lt;/span&gt;&lt;span style="color: maroon;"&gt;/&lt;/span&gt;&lt;span style="color: #1060b6;"&gt;M&lt;/span&gt;&lt;span style="color: maroon;"&gt;/&lt;/span&gt;&lt;span style="color: #406080;"&gt;;&lt;/span&gt; 
        &lt;span style="color: #007d45;"&gt;$act&lt;/span&gt; &lt;span style="color: #308080;"&gt;=&lt;/span&gt;&lt;span style="color: #308080;"&gt;~&lt;/span&gt; &lt;span style="color: #200080; font-weight: bold;"&gt;s&lt;/span&gt;&lt;span style="color: maroon;"&gt;/&lt;/span&gt;&lt;span style="color: #1060b6;"&gt;delete&lt;/span&gt;&lt;span style="color: maroon;"&gt;/&lt;/span&gt;&lt;span style="color: #1060b6;"&gt;D&lt;/span&gt;&lt;span style="color: maroon;"&gt;/&lt;/span&gt;&lt;span style="color: #406080;"&gt;;&lt;/span&gt; &lt;span style="color: #007d45;"&gt;$act&lt;/span&gt; &lt;span style="color: #308080;"&gt;=&lt;/span&gt;&lt;span style="color: #308080;"&gt;~&lt;/span&gt; &lt;span style="color: #200080; font-weight: bold;"&gt;s&lt;/span&gt;&lt;span style="color: maroon;"&gt;/&lt;/span&gt;&lt;span style="color: #1060b6;"&gt;add&lt;/span&gt;&lt;span style="color: maroon;"&gt;/&lt;/span&gt;&lt;span style="color: #1060b6;"&gt;A&lt;/span&gt;&lt;span style="color: maroon;"&gt;/&lt;/span&gt;&lt;span style="color: #406080;"&gt;;&lt;/span&gt; 
        &lt;span style="color: #007d45;"&gt;$line&lt;/span&gt; &lt;span style="color: #308080;"&gt;=&lt;/span&gt; &lt;span style="color: #007d45;"&gt;$time&lt;/span&gt;&lt;span style="color: #308080;"&gt;.&lt;/span&gt;&lt;span style="color: #1060b6;"&gt;"|"&lt;/span&gt;&lt;span style="color: #308080;"&gt;.&lt;/span&gt;&lt;span style="color: #007d45;"&gt;$user&lt;/span&gt;&lt;span style="color: #308080;"&gt;.&lt;/span&gt;&lt;span style="color: #1060b6;"&gt;"|"&lt;/span&gt;&lt;span style="color: #308080;"&gt;.&lt;/span&gt;&lt;span style="color: #007d45;"&gt;$act&lt;/span&gt;&lt;span style="color: #308080;"&gt;.&lt;/span&gt;&lt;span style="color: #1060b6;"&gt;"|"&lt;/span&gt;&lt;span style="color: #308080;"&gt;.&lt;/span&gt;&lt;span style="color: #007d45;"&gt;$file&lt;/span&gt;&lt;span style="color: #308080;"&gt;.&lt;/span&gt;&lt;span style="color: #1060b6;"&gt;"|&lt;/span&gt;&lt;span style="color: #0f69ff;"&gt;\n&lt;/span&gt;&lt;span style="color: #1060b6;"&gt;"&lt;/span&gt;&lt;span style="color: #406080;"&gt;;&lt;/span&gt;
        &lt;span style="color: #200080; font-weight: bold;"&gt;print&lt;/span&gt; &lt;span style="color: #007d45;"&gt;$line&lt;/span&gt; &lt;span style="color: #200080; font-weight: bold;"&gt;if&lt;/span&gt; &lt;span style="color: #007d45;"&gt;$file&lt;/span&gt;&lt;span style="color: #406080;"&gt;;&lt;/span&gt;
    &lt;span style="color: #406080;"&gt;}&lt;/span&gt; &lt;span style="color: #200080; font-weight: bold;"&gt;split&lt;/span&gt;&lt;span style="color: #308080;"&gt;(&lt;/span&gt;&lt;span style="color: maroon;"&gt;/&lt;/span&gt;&lt;span style="color: #0f69ff;"&gt;\.&lt;/span&gt;&lt;span style="color: #308080;"&gt;+&lt;/span&gt;&lt;span style="color: #1060b6;"&gt; depotFile &lt;/span&gt;&lt;span style="color: maroon;"&gt;/&lt;/span&gt;&lt;span style="color: #308080;"&gt;,&lt;/span&gt; &lt;span style="-webkit-background-clip: initial; -webkit-background-origin: initial; background-attachment: initial; background-color: #cceeee; background-image: initial; background-repeat: initial; color: #1060b6;"&gt;`&lt;/span&gt;&lt;span style="-webkit-background-clip: initial; -webkit-background-origin: initial; background-attachment: initial; background-color: #cceeee; background-image: initial; background-repeat: initial; color: black;"&gt;p4 fstat -e &lt;/span&gt;&lt;span style="-webkit-background-clip: initial; -webkit-background-origin: initial; background-attachment: initial; background-color: #cceeee; background-image: initial; background-repeat: initial; color: #007d45;"&gt;$change&lt;/span&gt;&lt;span style="-webkit-background-clip: initial; -webkit-background-origin: initial; background-attachment: initial; background-color: #cceeee; background-image: initial; background-repeat: initial; color: black;"&gt; &lt;/span&gt;&lt;span style="-webkit-background-clip: initial; -webkit-background-origin: initial; background-attachment: initial; background-color: #cceeee; background-image: initial; background-repeat: initial; color: #007d45;"&gt;$root&lt;/span&gt;&lt;span style="-webkit-background-clip: initial; -webkit-background-origin: initial; background-attachment: initial; background-color: #cceeee; background-image: initial; background-repeat: initial; color: black;"&gt;...&lt;/span&gt;&lt;span style="-webkit-background-clip: initial; -webkit-background-origin: initial; background-attachment: initial; background-color: #cceeee; background-image: initial; background-repeat: initial; color: #1060b6;"&gt;`&lt;/span&gt;&lt;span style="color: #308080;"&gt;)&lt;/span&gt;&lt;span style="color: #406080;"&gt;;&lt;/span&gt;
&lt;span style="color: #406080;"&gt;}&lt;/span&gt; &lt;span style="color: #200080; font-weight: bold;"&gt;reverse&lt;/span&gt; &lt;span style="color: #200080; font-weight: bold;"&gt;split&lt;/span&gt;&lt;span style="color: #308080;"&gt;(&lt;/span&gt;&lt;span style="color: maroon;"&gt;/&lt;/span&gt;&lt;span style="color: #0f69ff;"&gt;\n&lt;/span&gt;&lt;span style="color: #308080;"&gt;+&lt;/span&gt;&lt;span style="color: maroon;"&gt;/&lt;/span&gt;&lt;span style="color: #308080;"&gt;,&lt;/span&gt; &lt;span style="-webkit-background-clip: initial; -webkit-background-origin: initial; background-attachment: initial; background-color: #cceeee; background-image: initial; background-repeat: initial; color: #1060b6;"&gt;`&lt;/span&gt;&lt;span style="-webkit-background-clip: initial; -webkit-background-origin: initial; background-attachment: initial; background-color: #cceeee; background-image: initial; background-repeat: initial; color: black;"&gt;p4 changes &lt;/span&gt;&lt;span style="-webkit-background-clip: initial; -webkit-background-origin: initial; background-attachment: initial; background-color: #cceeee; background-image: initial; background-repeat: initial; color: #007d45;"&gt;$root&lt;/span&gt;&lt;span style="-webkit-background-clip: initial; -webkit-background-origin: initial; background-attachment: initial; background-color: #cceeee; background-image: initial; background-repeat: initial; color: black;"&gt;...&lt;/span&gt;&lt;span style="-webkit-background-clip: initial; -webkit-background-origin: initial; background-attachment: initial; background-color: #cceeee; background-image: initial; background-repeat: initial; color: #1060b6;"&gt;`&lt;/span&gt;&lt;span style="color: #308080;"&gt;)&lt;/span&gt;&lt;span style="color: #406080;"&gt;;&lt;/span&gt;&lt;/pre&gt;&lt;div&gt;&lt;span style="color: #406080; font-family: monospace;"&gt;&lt;span style="white-space: pre;"&gt;&lt;span style="color: black; font-family: 'Times New Roman';"&gt;&lt;span style="white-space: normal;"&gt;&lt;span style="color: #406080; font-family: monospace;"&gt;&lt;span style="white-space: pre;"&gt; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="color: #406080; font-family: monospace;"&gt;&lt;span style="white-space: pre;"&gt;&lt;span style="color: black; font-family: 'Times New Roman';"&gt;&lt;span style="white-space: normal;"&gt;&lt;span style="color: #406080; font-family: monospace;"&gt;&lt;span style="white-space: pre;"&gt; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
Granted, both examples of open-source Perforce depots visualizations do not look very exciting, because neither of them seems to be a primary development depot, and most of the commits are done by a few maintenance people.&lt;br /&gt;
&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;However, I've also tried it at the company where I work, watching one-year's worth evolution of the main code branch, and that was quite insightful.&lt;br /&gt;
&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;Gource also allows to supply a folder with images to be used as user portraits, which adds personality to the show, so I used that as well.&lt;br /&gt;
&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;&lt;br /&gt;
&lt;b&gt;&lt;span style="font-size: x-large;"&gt;Stories in code&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
&lt;/div&gt;And I was quite amazed with what I've seen: the code tells stories.&lt;br /&gt;
&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;&lt;br /&gt;
To an outsider it might look like just a boring pictures flying around and zapping with lasers some colored circles tagged by the file names.&lt;br /&gt;
&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;And generally that's the way how it is - plain boring. Boring when observed out of the context, that is.&lt;br /&gt;
&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;&lt;br /&gt;
And even if one of those flying pictures was myself, I was quite&amp;nbsp;under-impressed at first.&lt;br /&gt;
&lt;br /&gt;
&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;But then small stories began to pop in my head:&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;"Oh yes, I remember that refactoring when part of public API was renamed and it triggered the chain reaction..."&lt;/i&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;&lt;i&gt;"Here, ... Bill integrates his branch to ours"&lt;/i&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;&lt;i&gt;"Oh, he found the reason for that bug everyone was puzzled about... see, three&amp;nbsp;seemingly&amp;nbsp;unrelated folders were changed to fix it"&lt;/i&gt;&lt;br /&gt;
&lt;i&gt;"We have quite an activity of people working at the same on that clump of files, maybe we should improve modularity there?.. and then some people have to touch too many different files at once, it seems... could it be bad cohesiveness of code?"&lt;/i&gt;&lt;br /&gt;
&lt;i&gt;"Yeah... there, Peter makes that commit with funny comments we laughed at all together"&lt;/i&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;&lt;i&gt;"Right... Christmas. No commits, obviously... And then, see - what a rush! People fly around like crazy, apparently having a few days off was a good idea"&lt;/i&gt;&lt;br /&gt;
&lt;i&gt;"And here Mark and Frank are working on that new API together... it's nice to see an activity in the unit tests' folders"&lt;/i&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;&lt;i&gt;"Oh, see, John have just committed his new system there, in that new tidy bunch of files... cool stuff, he knows his job... surgical changes"&lt;/i&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;&lt;i&gt;"Ah, that... such a pity we had to revert that... And now - ha-ha, see, Brandon started to fly around like crazy, such a productivity again, huh?.. What was that? A new girlfriend or something?"&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
And so on.&lt;br /&gt;
&lt;br /&gt;
That really reminds me the topic of emergent storytelling in games, when players create their own stories and enjoy them:&lt;br /&gt;
&lt;blockquote&gt;Human beings like stories. Our brains have a natural affinity not only for enjoying narratives and learning from them, but also for creating them. In the same way that your mind sees an abstract pattern and resolves it into a face, your imagination sees a pattern and resolves it into a story.&lt;br /&gt;
&lt;/blockquote&gt;&lt;blockquote&gt;Games have always had a close affinity with story-making. Adding a few lines of description to a video game or a background and artwork to an abstract board game gives dramatic context and an added sense of depth, allowing the player to create an internal narrative as the game progresses.&lt;br /&gt;
&lt;/blockquote&gt;(from "&lt;a href="http://www.blogger.com/goog_1264625587976"&gt;Second Person: Role-Playing and Story in Games and Playable Media&lt;/a&gt;")&lt;br /&gt;
&lt;br /&gt;
Here it's not a game, but rather a meta-game of a kind (it's quite ironic that this is rather a process of &lt;i&gt;making &lt;/i&gt;a game in this particular case, because I work in a game development company). There are still quite a few parallels, it seems.&lt;br /&gt;
&lt;br /&gt;
Quite frankly,&amp;nbsp;Gource provides only the most basic display. It does not tell too much about the code structure and how well different areas of work are factored between different contributors (even though quite often well-though folder structure is a sign of overall good code organization).&lt;br /&gt;
&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;But I can imagine even more narrative devices added, for example:&lt;br /&gt;
&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;* Fetching the information from the continuous integration system and display some crazy particle explosions when build was broken&lt;br /&gt;
&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;* Doing similar, but even more intense display when automatic regression tests were broken&lt;br /&gt;
&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;* Integrate with bug tracker, and give some visual cues about the nature of work being done (bugs, regressions, crashes, new features)&lt;br /&gt;
&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;* Visually tracking the physical code dependencies as well (like #include graphs in C++) and their evolution&lt;br /&gt;
&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;I believe all this is can be useful in a practical sense as well.&lt;br /&gt;
&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;It seems that entertaining things generally have bigger cognitive potential. &lt;a href="http://blog.toolshed.com/"&gt;Andy Hunt&lt;/a&gt;&amp;nbsp;tells in "&lt;a href="http://blog.ruslans.com/2009/06/pragmatic-thinking-by-andy-hunt.html"&gt;Pragmatic Thinking&amp;amp;Learning&lt;/a&gt;":&lt;br /&gt;
&lt;/div&gt;&lt;blockquote&gt;...In fact, additional studies have shown exactly that: positive emotions are essential to learning and creative thinking. Being "happy" broadens your thought processes and brings more of the brain's hardware online.&lt;br /&gt;
Aesthetics make a difference, whether it's an user interface, the layout of your code and comments, the choices of variable names, the arrangement of your desktop or whatever.&lt;br /&gt;
&lt;/blockquote&gt;Nice things matter, especially if they provide a useful view, yet another mental projection upon the code base, which allows to extend one's mental models of this code in a fun, aesthetically pleasing way.&lt;br /&gt;
&lt;br /&gt;
Work should not necessary be boring.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;span style="font-size: x-large;"&gt;So what?..&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
From the practical perspective, one quite satisfying thing to me was that such generally useless one evening exercise gave me quite a bit of awareness about several (seemingly unrelated) things:&lt;br /&gt;
&lt;br /&gt;
* &lt;a href="http://www.hanselman.com/blog/ReadingToBeABetterDeveloperTheCoding4FunDevKit.aspx"&gt;Reading the source code&lt;/a&gt; of Gource (C++), compiling and running it both on Linux and Windows&lt;br /&gt;
* Making up somewhat &lt;a href="http://codekata.pragprog.com/2007/01/code_kata_backg.html"&gt;artificial problem&lt;/a&gt; in this context (how to use it with Perforce) and figuring out what steps can be taken to solve it&lt;br /&gt;
* Getting to know a little bit of Perl (yes,&amp;nbsp;this is my first Perl script ever... it must be quite obvious from the code, anyway), while solving a real-life problem&lt;br /&gt;
* Trying to do it in a (somewhat) functional programming style&lt;br /&gt;
* Improving my regular expressions skills&lt;br /&gt;
* Getting to know a bit of p4 command line interface, again while solving a real-life problem&lt;br /&gt;
* Getting some insight about the Adobe GIL and Perforce Jam open source code bases&lt;br /&gt;
* Using Gource to visualize evolution of the code base at the company where I work.&lt;br /&gt;
* Reflecting on it&lt;br /&gt;
&lt;br /&gt;
I am certainly not sure if regular solving of such small artificial problems (and learning a few random things while doing that) make you a better developer or something.&lt;br /&gt;
Perhaps it does. But if it does not - who cares?..&lt;br /&gt;
It was fun, after all.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/923082020090979517-1132344669153232506?l=blog.ruslans.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/gd_reflections/~4/xCAASs7aG1M" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.ruslans.com/feeds/1132344669153232506/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=923082020090979517&amp;postID=1132344669153232506" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/923082020090979517/posts/default/1132344669153232506" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/923082020090979517/posts/default/1132344669153232506" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/gd_reflections/~3/xCAASs7aG1M/code-opera-using-gource-to-watch-story.html" title="Code opera: using Gource to watch a story of Perforce depot" /><author><name>ruslans</name><uri>http://www.blogger.com/profile/03375859473751956887</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="24" height="32" src="http://2.bp.blogspot.com/_DVYH9neSnMw/S0V_XM6aN0I/AAAAAAAAAMc/06dTTnY0PNw/S220/avatar3.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/_DVYH9neSnMw/S2DB-Cn5j0I/AAAAAAAAAPE/_BJqTjLS41k/s72-c/jam-gource.png" height="72" width="72" /><thr:total>1</thr:total><feedburner:origLink>http://blog.ruslans.com/2010/01/code-opera-using-gource-to-watch-story.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-923082020090979517.post-5181879707268340860</id><published>2010-01-20T17:21:00.000-08:00</published><updated>2010-04-16T00:13:24.454-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="c++" /><category scheme="http://www.blogger.com/atom/ns#" term="visualization" /><category scheme="http://www.blogger.com/atom/ns#" term="game engines" /><category scheme="http://www.blogger.com/atom/ns#" term="boost" /><title type="text">Boost C++ libraries and game engines</title><content type="html">&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;a href="http://www.boost.org/" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/_DVYH9neSnMw/S1Tp4NpVB7I/AAAAAAAAAN0/Af_mIsjMMm4/s200/Boost.png" /&gt;&lt;/a&gt;There is a neat &lt;a href="http://www.boost.org/development/"&gt;development cost calculator&lt;/a&gt;&amp;nbsp;on the boost web site. Pretty easy to use. You enter "code only" into the "include" combo box and get your magic answer:&lt;br /&gt;
&lt;blockquote&gt;&lt;b&gt;$188,229,523&lt;/b&gt;&lt;br /&gt;
&lt;/blockquote&gt;Wow. I mean... Wow! You get almost two hundred millions &lt;b&gt;for free&lt;span style="font-weight: normal;"&gt;, into your personal disposal&lt;/span&gt;&lt;span style="font-weight: normal;"&gt;!&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
Only that makes it worth including Boost into your project, whatever you develop. Right?..&lt;br /&gt;
&lt;br /&gt;
If we talk game engines in particular, there is certainly no need for all the excessive functionality the Boost libraries provide.&lt;br /&gt;
However, there are surprisingly many parts of it, which I've seen being reimplemented in the small and big game engines over and over again (and, frankly, implemented quite a few bits of functionality myself).&lt;br /&gt;
Such as:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.boost.org/doc/libs/1_41_0/libs/smart_ptr/smart_ptr.htm"&gt;smart pointers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.boost.org/doc/libs/1_41_0/libs/pool/doc/index.html"&gt;memory pool allocators&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.boost.org/doc/libs/1_41_0/libs/conversion/lexical_cast.htm"&gt;lexical cast&lt;/a&gt;&amp;nbsp;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.boost.org/doc/libs/1_41_0/doc/html/any.html"&gt;variant types&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.boost.org/doc/libs/1_41_0/doc/html/program_options.html"&gt;program options&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.boost.org/doc/libs/1_41_0/doc/html/property_tree.html"&gt;property trees&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.boost.org/doc/libs/1_41_0/libs/tokenizer/index.html"&gt;tokenizing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.boost.org/doc/libs/1_41_0/doc/html/thread.html"&gt;threading wrappers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.boost.org/doc/libs/1_41_0/doc/html/signals.html"&gt;signals&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.boost.org/doc/libs/1_41_0/libs/serialization/doc/index.html"&gt;serialization&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.boost.org/doc/libs/1_41_0/libs/filesystem/doc/index.htm"&gt;filesystem abstraction&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;div&gt;&amp;nbsp;- these usually find their place in the "core" part of the game engine. Also there are more specialized parts, like:&lt;br /&gt;
&lt;/div&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.boost.org/doc/libs/1_41_0/libs/graph/doc/table_of_contents.html"&gt;graph operations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.boost.org/doc/libs/1_41_0/libs/statechart/doc/index.html"&gt;state machines&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.boost.org/doc/libs/1_41_0/libs/regex/doc/html/index.html"&gt;regular expressions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.boost.org/doc/libs/1_41_0/libs/gil/doc/index.html"&gt;image operations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.boost.org/doc/libs/1_41_0/doc/html/boost_asio.html"&gt;networking&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.boost.org/doc/libs/1_41_0/libs/python/doc/index.html"&gt;python binding&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;div&gt;All of these facilities (and many more) can be&amp;nbsp;considered&amp;nbsp;of direct use for your typical modern game engine.&lt;br /&gt;
&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;Also, it's no doubt that boost code is of very high quality, tried and true, well-tested, portable and besides it&amp;nbsp;&lt;a href="http://www.open-std.org/jtc1/sc22/wg21/docs/library_technical_report.html"&gt;is slowly moving into C++ standard&lt;/a&gt;. It uses template metaprogramming, which presumably in certain cases can improve efficiency due to&amp;nbsp;aggressive inlining and doing some stuff at compile time. The code is also considered to be generic, so one is supposed to be able to flex it to high degrees adapting to one's own needs.&lt;br /&gt;
&lt;br /&gt;
&lt;div style="margin: 0px;"&gt;Jason Gregory in&amp;nbsp;&lt;a href="http://www.amazon.com/Game-Engine-Architecture-Jason-Gregory/dp/1568814135"&gt;Game Engine Architecture&lt;/a&gt;&amp;nbsp;book (in my opinion, rather good one) mentions the topic:&lt;br /&gt;
&lt;/div&gt;&lt;blockquote&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-size: small;"&gt;Boost provides a lot of useful facilities not available in STL.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style="font-size: small;"&gt;In some cases, Boost provides alternatives to work around certain problems with STL's design or implementation.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style="font-size: small;"&gt;Boost does a great job of handling some very complex problems, like smart pointers. (Bear in mind that smart pointers are complex beasts, and they can be performance hogs. Handles are usually preferable; see Section 14.5 for details).&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style="font-size: small;"&gt;Th Boost libraries' documentation is usually excellent. Not only does the documentation explain what each library does and how to use it, but in most cases it also provides an excellent in-depth discussion of the design decisions, constraints, and requirements that went into constructing the library. As such, reading the Boost documentation is a great way to learn about the principles of software design.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;div style="margin: 0px;"&gt;&lt;span style="font-size: small;"&gt;If you are already using STL, then Boost can serve an excellent extension and/or alternative to many STL's features. However, be aware of the following caveats:&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-size: small;"&gt;Most of the Boost classes are templates, so all one needs in order to use them is the appropriate set of header files. However, some of the Boost libraries build into rather large .lib files and may not be feasible for use in very small-scale game projects.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style="font-size: small;"&gt;While the world-wide Boost community is an excellent support network, the Boost libraries come with no guarantees. If you encounter a bug, it will ultimately be your team's responsibility to work around or fix it.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style="font-size: small;"&gt;Backward compatibility may not be supported.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style="font-size: small;"&gt;The Boost libraries are distributed under the Boost Library License. Read the&amp;nbsp;&lt;/span&gt;&lt;a href="http://www.boost.org/users/license.html"&gt;&lt;span style="font-size: small;"&gt;license information&lt;/span&gt;&lt;/a&gt;&lt;span style="font-size: small;"&gt;&amp;nbsp;carefully to be sure it is right for your engine.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/blockquote&gt;&lt;div style="margin: 0px;"&gt;But frankly, while I agree about smart pointers and documentation, there are bigger &amp;nbsp;concerns&amp;nbsp;usually popping up regarding Boost:&lt;br /&gt;
&lt;/div&gt;&lt;ul&gt;&lt;li&gt;Compiling time - due to all inter-dependencies and heavy template use&lt;/li&gt;
&lt;li&gt;Code readability&amp;nbsp;&lt;/li&gt;
&lt;li&gt;Performance (usually as a tradeoff for flexibility and safety, there are quite a few&amp;nbsp;&lt;a href="http://www.gamedev.net/community/forums/topic.asp?topic_id=456646"&gt;horror evidences&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Easiness of misuse and building extra complexity out from nothing&lt;/li&gt;
&lt;li&gt;Versioning problems&lt;/li&gt;
&lt;li&gt;Huge size of the library itself, when used as a third-party dependency&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;It turns out that there is still a lot of controversy regarding the very topic of using boost in games. People are quite often &lt;a href="http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml?showone=Boost#Boost"&gt;cautious&lt;/a&gt; about it, and in many cases avoid using it altogether.&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;Of course, it does not really come as much surprise in regards to the game industry as specific branch of software development. The mental model of your&amp;nbsp;typical game engine architecture, sketched directly from my head into an (almost) UML diagram looks like this:&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_DVYH9neSnMw/S1T9gG8M5QI/AAAAAAAAAOE/NWCzZyCk95M/s1600-h/bicycles.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/_DVYH9neSnMw/S1T9gG8M5QI/AAAAAAAAAOE/NWCzZyCk95M/s200/bicycles.jpg" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;/div&gt;...which hopefully explains a lot.&lt;br /&gt;
&lt;br /&gt;
Recently I've started to try porting some of&amp;nbsp;&lt;a href="http://blog.ruslans.com/2009/12/bees-in-space-or-story-of-my-first.html"&gt;five years old code&lt;/a&gt;&amp;nbsp;to Linux, and on the quest of eradicating windows.h dependencies found out that there is a class called "FilePath", which allows to do some basic filesystem operations and uses WinApi directly.&lt;br /&gt;
&lt;br /&gt;
It came into my mind that its functionality is an ad-hoc implementation of a subset of what &lt;a href="http://www.boost.org/doc/libs/1_41_0/libs/filesystem/doc/index.htm"&gt;boost::filesystem&lt;/a&gt; library provides. Except that the latter is portable, has more functionality, is more stable and well-documented. &lt;br /&gt;
&lt;br /&gt;
There are certain biases I've got, and due to all aforementioned factors (including the &lt;a href="http://en.wikipedia.org/wiki/Not_invented_here"&gt;NIH syndrome&lt;/a&gt;), the decision did not seem to be as simple to make.&lt;br /&gt;
Another mental model of mine has&amp;nbsp;crystallized with time, and here's the sketch of it:&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_DVYH9neSnMw/S1Tb7_fG4sI/AAAAAAAAANk/4LObDkiBj-k/s1600-h/get_boost.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/_DVYH9neSnMw/S1Tb7_fG4sI/AAAAAAAAANk/4LObDkiBj-k/s200/get_boost.jpg" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
I remember Joe Armstrong saying in &lt;a href="http://www.codersatwork.com/"&gt;Coders at Work&lt;/a&gt;:&lt;br /&gt;
&lt;blockquote&gt;&lt;span style="font-size: small;"&gt;&lt;b&gt;Seibel: &lt;/b&gt;But do you think it's really feasible to really open up all those black boxes, look inside, see how they work, and decide how to tweak them to one's own needs?&lt;/span&gt;&lt;br /&gt;
&lt;/blockquote&gt;&lt;blockquote&gt;&lt;span style="font-size: small;"&gt;&lt;b&gt;Armstrong:&lt;/b&gt; Over the years I've kind of made a generic mistake and the generic mistake is not to open the black box. To mentally think, this black box is so impenetrable and so difficult that I won't open it[...] But it's not actually difficult. [...] ...you should certainly consider the possibility of opening them.&lt;/span&gt;&lt;br /&gt;
&lt;/blockquote&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;Shattering the personal biases by means of opening black boxes sounds like a good plan.&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;So, where do all the dependencies come from?&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;Here's the layout of the whole boost include directory (which is roughly 50 Mb, while the whole boost directory is 200 Mb), made with &lt;a href="http://www.tibsoft.com/index.php?page=steptree"&gt;StepTree&lt;/a&gt;:&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_DVYH9neSnMw/S1UOytIT2AI/AAAAAAAAAOM/5YrqkDn-QpE/s1600-h/boost_include.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_DVYH9neSnMw/S1UOytIT2AI/AAAAAAAAAOM/5YrqkDn-QpE/s320/boost_include.jpg" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: left;"&gt;We don't really need all of that. Luckily, there is&amp;nbsp;&lt;a href="http://www.boost.org/doc/libs/1_41_0/tools/bcp/bcp.html"&gt;bcp utility&lt;/a&gt;, which is part of boost distribution and does exactly that - it allows to strip away only the subset of code needed. So, if I am interested in boost::filesystem library:&lt;br /&gt;
&lt;/div&gt;&lt;blockquote&gt;&lt;span style="font-size: small;"&gt;cd boost&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-size: small;"&gt;mkdir ../boost_fs&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-size: small;"&gt;bcp --boost=boost filesystem.hpp boost_fs&lt;/span&gt;&lt;br /&gt;
&lt;/blockquote&gt;&amp;nbsp;It creates boost_fs folder, which has only the code needed to compile this particular library and use it. However, this folder is around 8 Mb, which is a bit more than could be expected (keep in mind that most of this code is header files, which most certainly are going to be included into the project). The layout looks like this (this time rendered in &lt;a href="http://windirstat.info/"&gt;WinDirStat&lt;/a&gt;):&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_DVYH9neSnMw/S1Vm7wvANmI/AAAAAAAAAOU/ovtzt7U1T2k/s1600-h/boost_fs_include.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/_DVYH9neSnMw/S1Vm7wvANmI/AAAAAAAAAOU/ovtzt7U1T2k/s320/boost_fs_include.jpg" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;/div&gt;The boost::filesystem code itself takes just about 3%! The rest is occupied mostly by:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;mpl -&amp;nbsp;which is an "all-around c++ template tricks" kind of library&lt;/li&gt;
&lt;li&gt;preprocessor - which is a library to do the copypasting job for the programmer in very smart way&lt;/li&gt;
&lt;li&gt;type_traits - which allows to get and use some basic information about templated types in case of templated classes&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;Granted, code reuse is generally a good thing, and &amp;nbsp;boost (having the goal of being highly reusable library itself) is known to do it heavily, cross-referencing between the libraries. But this looks a bit extreme.&lt;br /&gt;
Ironically, though, the development guidelines for the Boost libraries do discuss the topic of&amp;nbsp;&lt;a href="http://www.boost.org/development/reuse.html"&gt;excessive library interdependencies&lt;/a&gt;.&lt;br /&gt;
Let's run again bcp in "report mode":&lt;br /&gt;
&lt;blockquote&gt;&lt;span style="font-size: small;"&gt;bcp --report filesystem.hpp fs_report.html&lt;/span&gt;&lt;br /&gt;
&lt;/blockquote&gt;This generates html report file with all the dependencies gathered. At the bottom of this file there are&amp;nbsp;&lt;a href="http://sites.google.com/site/rushbits/Home/boost_fs_report"&gt;all the include chains gathered&lt;/a&gt;&amp;nbsp;(the file is big, mind you).&lt;br /&gt;
This representation is only helpful in showing that there are very many header inclusion paths starting from boost/filesystem.hpp and most of them end in either of other aforementioned boost libraries.&lt;br /&gt;
Let's try to build an inclusion graph using &lt;a href="http://www.stack.nl/%7Edimitri/doxygen/"&gt;Doxygen&lt;/a&gt;:&lt;br /&gt;
&lt;blockquote&gt;sudo apt-get doxygen graphviz&lt;br /&gt;
cd ../boost_fs&lt;br /&gt;
doxygen -g&lt;br /&gt;
emacs Doxyfile&lt;br /&gt;
&lt;/blockquote&gt;Then edit the file to ensure parameters are set:&lt;br /&gt;
&lt;blockquote&gt;HAVE_DOT = YES&lt;br /&gt;
RECURSIVE = YES&lt;br /&gt;
EXTRACT_ALL = YES&lt;br /&gt;
&lt;/blockquote&gt;Save, and then:&lt;br /&gt;
&lt;blockquote&gt;doxygen Doxyfile&lt;br /&gt;
&lt;/blockquote&gt;The part of inclusion graph for the main header, boost/filesystem.hpp look like this:&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_DVYH9neSnMw/S1efxaah7uI/AAAAAAAAAOc/eR-pLgBWwDo/s1600-h/filesystem_8hpp__incl.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="80" src="http://4.bp.blogspot.com/_DVYH9neSnMw/S1efxaah7uI/AAAAAAAAAOc/eR-pLgBWwDo/s400/filesystem_8hpp__incl.png" width="400" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
The gate to the flurry of includes seems to be opened via boost/iterator/iterator_facade.hpp, which has another graph on it's own:&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_DVYH9neSnMw/S1ehhgOqqzI/AAAAAAAAAOk/hyHWTCtcvJc/s1600-h/iterator__facade_8hpp__incl.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="63" src="http://2.bp.blogspot.com/_DVYH9neSnMw/S1ehhgOqqzI/AAAAAAAAAOk/hyHWTCtcvJc/s400/iterator__facade_8hpp__incl.png" width="400" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;/div&gt;Browsing these graphs on its own already starts to give some insight, but to get things even more clear we could try to inspect even different representation of the source code... &lt;a href="http://www.boost.org/doc/libs/1_41_0/boost/filesystem/operations.hpp"&gt;the source code&lt;/a&gt;&amp;nbsp;itself.&lt;br /&gt;
&lt;br /&gt;
Doing that, it becomes more clear where do these dependencies come from. For example, there is a directory iterator, which is templated by the path type, which in fair enough, as the path can have possibly Unicode representation. Iterator classes are generic in a sense that they don't do many assumptions about the particular type uses, and thus require the general metaprogramming facilities provided by mpl and typetraits. Mpl, in turn, uses preprocessor libraries for its needs. And then there are preprocessed headers for several compilers... quite a lot of things are happening in order to provide the functionality which you actually may not need.&lt;br /&gt;
&lt;br /&gt;
In this particular case there is, for example, &lt;a href="http://icculus.org/physfs/"&gt;physfs&lt;/a&gt;&amp;nbsp;library which might suite the needs even better without providing nearly all the generic facilities as boost does.&lt;br /&gt;
&lt;br /&gt;
Does it mean that there is no use for boost? Of course not:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;One still can use it, but physical dependencies tracking is important even more than usual. In case of filesysem it could be wrapped with an additional interface, so as few cpp translation units as possible include boost/filesystem.hpp and the rest which is pulled in together with it.&lt;/li&gt;
&lt;li&gt;One can also possibly take the parts of interest and "strip" them out of unneeded generic parts. Here's a good example: &amp;nbsp;&lt;a href="http://www.ogre3d.org/docs/api/html/OgreAny_8h-source.html"&gt;OgreAny.h&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;One can read the documentation and, most importantly, the code to borrow good practices and ideas (and to examine the "bad" ones as well).&lt;/li&gt;
&lt;/ul&gt;Whatever you do, just make sure you crack the black box open first.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/923082020090979517-5181879707268340860?l=blog.ruslans.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/gd_reflections/~4/C6x8hwztAn0" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.ruslans.com/feeds/5181879707268340860/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=923082020090979517&amp;postID=5181879707268340860" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/923082020090979517/posts/default/5181879707268340860" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/923082020090979517/posts/default/5181879707268340860" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/gd_reflections/~3/C6x8hwztAn0/boost-c-libraries-and-game-engines.html" title="Boost C++ libraries and game engines" /><author><name>ruslans</name><uri>http://www.blogger.com/profile/03375859473751956887</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="24" height="32" src="http://2.bp.blogspot.com/_DVYH9neSnMw/S0V_XM6aN0I/AAAAAAAAAMc/06dTTnY0PNw/S220/avatar3.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/_DVYH9neSnMw/S1Tp4NpVB7I/AAAAAAAAAN0/Af_mIsjMMm4/s72-c/Boost.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://blog.ruslans.com/2010/01/boost-c-libraries-and-game-engines.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-923082020090979517.post-3594430980363825882</id><published>2010-01-11T13:29:00.000-08:00</published><updated>2010-04-16T00:13:53.273-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="self-improvement" /><category scheme="http://www.blogger.com/atom/ns#" term="tongue-in-a-cheek" /><title type="text">Programmer's arrogance graph</title><content type="html">&lt;div class="separator" style="clear: both; text-align: left;"&gt;We know that majority of programmers, even the &lt;a href="http://en.wikipedia.org/wiki/Git_(software)#Name"&gt;most ingenious ones&lt;/a&gt;, are egotistical bastards, driven by arrogance.&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;Programmer's arrogance is both a blind, powerful driving force and also the reason for many failures.&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;For example, anecdotal evidence tells that initial programmer's estimate has to be&lt;a href="http://www.rentacoder.com/RentACoder/DotNet/SoftwareBuyers/Articles/CalculatingRealisticDeliveryDatesFromCoderEstimates.aspx#RealisticEstimate"&gt; multiplied at least twice&lt;/a&gt; to get the "realistic estimate":&lt;br /&gt;
&lt;/div&gt;&lt;blockquote&gt;&lt;span style="font-size: small;"&gt;Why are competent coders so bad at estimating?&amp;nbsp;There are a number of reasons. &amp;nbsp;The main ones are:&lt;/span&gt;&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;span style="font-size: small;"&gt;Unforeseeable problems:&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;span style="font-size: small;"&gt;Many of the problems that come up during software development are unforeseeable. &amp;nbsp;If you have ever started a "simple" home improvement project and later found it was much more complicated than you realized...then you know first hand how programming can be...even for the experts.&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-size: small;"&gt;&lt;/span&gt;&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;span style="font-size: small;"&gt;Misunderstood/unclear requirements:&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;span style="font-size: small;"&gt;When the requirements are unclear, the programmer usually underestimates what it takes to build your software. &amp;nbsp;To use an analogy, they may estimate building your software as if it were a comfortable house. &amp;nbsp;Only mid-project do they realize that you were expecting the Taj Mahal!&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;/blockquote&gt;Or they just fall a victim to their own arrogance. Which is a bit simpler explanation.&lt;br /&gt;
Same stands for "Not Invented Here", "Invented here but not by myself", "My co-workers are all jerks" syndromes. And many more. Oh well.&lt;br /&gt;
&lt;br /&gt;
Now, I've got a theory (which is built on empirical experience, of course), that if we imagine that amount of "arrogance" can be measured with a scalar value (let's call it a "magnitude of arrogance"), and if we try to build a graph of this value changing with the lifetime of the programmer, we might get pretty similar shape in &lt;a href="http://en.wikipedia.org/wiki/Pareto_distribution"&gt;80% of cases&lt;/a&gt;:&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_DVYH9neSnMw/S0t-QoTItdI/AAAAAAAAANU/8DWHk-OBTLo/s1600-h/arrogance.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/_DVYH9neSnMw/S0t-QoTItdI/AAAAAAAAANU/8DWHk-OBTLo/s320/arrogance.png" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;The person (remember that we talk about future programmer) starts on some level of initial arrogance as a child/teenager, goes to school where everything is very new and unknown at first (point marked as "S" on the lifeline, which is horizontal).&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;But then he (not being sexist, just&amp;nbsp;intentionally&amp;nbsp;taking only males here) suddenly realizes that he's the "smartest kid in the class". The next thing he figures out is that his programming teacher "does not know a sh*t".&amp;nbsp;Besides some boring, irrelevant and ages old stuff, that is. And sure he does not have any bleeding edge knowledge about, say, &lt;a href="http://en.wikipedia.org/wiki/How_does_one_patch_KDE2_under_FreeBSD%3F"&gt;patching KDE under freeBSD&lt;/a&gt;.&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;Naturally, this skyrockets the level of arrogance significantly, and it keeps fluctuating somewhere at the top until our geek graduates and gets a job ("J").&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;Here the arrogance might drop down slightly again, because of the things being new and not familiar.&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;However, being used to the "best kid in the class" status, our soon-to-become programmer quite quickly catches up.&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;It might happen because of initial tasks being moderately doable and initial responsibility being not quite high, so this "gee, I can do the stuff" feeling warms up the ego.&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;Also, when coming to a corporate environment, young programmers often get a maintenance job in some legacy codebase. Knowing the &lt;a href="http://www.laputan.org/mud/"&gt;nature of (most of the) legacy code bases&lt;/a&gt;, one would not get surprised if quite soon our kid gets to realize the thing.&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;See, it happens that all these "experienced" folks out there don't know a sh*t about programming either. As&amp;nbsp;Gerald M. Weinberg &lt;a href="http://www.amazon.com/Psychology-Computer-Programming-Silver-Anniversary/dp/0932633420"&gt;puts it&lt;/a&gt;:&lt;br /&gt;
&lt;/div&gt;&lt;blockquote&gt;&lt;span style="font-size: small;"&gt;We often find material in programs that is [...] really present because of the history of the development of the program. For example, once the [...] function is changed to an [...] function, there is no longer any reason for the program [...] to appear. Nevertheless, things being what they are in the programming business, it is unlikely that anyone is going to delve into a working program and modify it just because the definition of [...] function has been changed. And so, some years later, a novice programmer who is given the job of modifying this program will congratulate himself for knowing more about [the subject] than the person who originally wrote this program. Since that person is probably his supervisor, an unhealthy attitude may develop - which, incidentally, is another psychological reality of programming life which we shall have to face eventually.&lt;/span&gt;&lt;br /&gt;
&lt;/blockquote&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;Soon he realizes, though, that things do not quite work as it appeared at first. There are several failures happening, which he fortunately realizes should be blamed on himself, and he suddenly faces the understanding that he knows, in fact, nothing about his job.&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;Then goes a long and painful learning, getting better and better every day, and finally getting to the next level of personal development, where one can look back and say: "see, I am not nearly as lame as I used to be when I started". &lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;So we get another boost of overconfidence, which may or may be not followed by similar, multiple and abrupt drops and&amp;nbsp;consequent slow raises.&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;What usually happens next is the point "P".&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;Which is promotion to the lead position (it does not seem that there is too many ways to get "promoted" in corporate programming business without becoming a manager), or becoming an&amp;nbsp;entrepreneur, or changing the working place to work in considerably more "advanced" company. You name it.&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;The fresh feeling of power gives another arrogance boost.&amp;nbsp;It only lasts that long, though, and soon again come disappointments.&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: left;"&gt;And so on.&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;After many bumps on the road, if being lucky, passionate, persistent and introspective, one might slowly approach the level, which is marked as "H" on the vertical axis.&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;Which is "&lt;a href="http://www.cs.utexas.edu/~EWD/transcriptions/EWD03xx/EWD340.html"&gt;The Humble Programmer&lt;/a&gt;", as E.W.Dijkstra puts it:&lt;br /&gt;
&lt;/div&gt;&lt;blockquote&gt;&lt;span style="font-size: small;"&gt;We shall do a much better programming job, provided that we approach the task with a full appreciation of its tremendous difficulty, provided that we stick to modest and elegant programming languages, provided that we respect the intrinsic limitations of the human mind and approach the task as Very Humble Programmers.&lt;/span&gt;&lt;br /&gt;
&lt;/blockquote&gt;The question is how close projection of this point upon the horizontal axis will happen to be to the point "R" (retirement).&lt;br /&gt;
&lt;br /&gt;
And to the point "D", which comes next.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/923082020090979517-3594430980363825882?l=blog.ruslans.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/gd_reflections/~4/1M-JFRWkx_Y" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.ruslans.com/feeds/3594430980363825882/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=923082020090979517&amp;postID=3594430980363825882" title="4 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/923082020090979517/posts/default/3594430980363825882" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/923082020090979517/posts/default/3594430980363825882" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/gd_reflections/~3/1M-JFRWkx_Y/programmers-arrogance-plotted.html" title="Programmer's arrogance graph" /><author><name>ruslans</name><uri>http://www.blogger.com/profile/03375859473751956887</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="24" height="32" src="http://2.bp.blogspot.com/_DVYH9neSnMw/S0V_XM6aN0I/AAAAAAAAAMc/06dTTnY0PNw/S220/avatar3.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/_DVYH9neSnMw/S0t-QoTItdI/AAAAAAAAANU/8DWHk-OBTLo/s72-c/arrogance.png" height="72" width="72" /><thr:total>4</thr:total><feedburner:origLink>http://blog.ruslans.com/2010/01/programmers-arrogance-plotted.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-923082020090979517.post-4175501063275581871</id><published>2009-12-30T15:51:00.000-08:00</published><updated>2010-04-16T00:13:17.949-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="c++" /><category scheme="http://www.blogger.com/atom/ns#" term="game engines" /><category scheme="http://www.blogger.com/atom/ns#" term="indie" /><title type="text">Bees in Space, or story of my first freeware  game project</title><content type="html">&lt;a href="http://3.bp.blogspot.com/_DVYH9neSnMw/Szufbrub6VI/AAAAAAAAAK4/bxs2pLuqjZc/s1600-h/Untitled-1.jpg" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img alt="" border="0" id="BLOGGER_PHOTO_ID_5421101874413300050" src="http://3.bp.blogspot.com/_DVYH9neSnMw/Szufbrub6VI/AAAAAAAAAK4/bxs2pLuqjZc/s200/Untitled-1.jpg" style="float: left; height: 150px; margin-bottom: 10px; margin-left: 0px; margin-right: 10px; margin-top: 0px; width: 200px;" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;div&gt;It was around five years ago when I decided to try making a small game project on my own and publish it on the internets as freeware.&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;The reason was that I wanted to experience myself a "full" game development cycle in miniature. &lt;br /&gt;
&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;And for fun, of course.&lt;br /&gt;
&lt;br /&gt;
Probably the end result is not such a big deal, but I've certainly enjoyed the process and learned quite a bit from it. Actually doing the things, no matter how small they appear, gives that invaluable insight into their very nature, which can not be gained otherwise. When those small, non-uniform (and often beyond the boundaries of one's present competence) things form a complete whole, a closed loop, then this insight may get even more eyes-opening.&lt;br /&gt;
&lt;br /&gt;
At least that's my feeling about it, in the end.&lt;br /&gt;
&lt;br /&gt;
So now, after five years I've suddenly realized that it was not that bad, after all, and it might be a good idea to reflect on that past thing. Just for fun, again.&lt;br /&gt;
&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;span style="font-size: x-large;"&gt;Picking a theme&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
&lt;a href="http://1.bp.blogspot.com/_DVYH9neSnMw/Szu3R2Z4ZqI/AAAAAAAAALQ/7Ns3oBVof1Q/s1600-h/Untitled-5.jpg" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_DVYH9neSnMw/Szu3R2Z4ZqI/AAAAAAAAALQ/7Ns3oBVof1Q/s200/Untitled-5.jpg" /&gt;&lt;/a&gt;The old-school game called&amp;nbsp;&lt;a href="http://www.boardgamegeek.com/boardgame/19914/hexxagon"&gt;Hexxagon&lt;/a&gt;&amp;nbsp;was a primary inspiration for that.&amp;nbsp;It was very tempting, of course, to start something grand, like Diablo or GTAIII clone, but that would obviously defeat the whole purpose of trying to finish the game and see what happens after that.&lt;br /&gt;
&lt;br /&gt;
Being as simple as it is, it still involves quite a bit of work in different areas of programming, gameplay design, user interface, art, "marketing", maintenance and support etc - even though every problem here is a toy one, as comparing to a "real-life" game project.&lt;br /&gt;
&lt;b&gt;&lt;span style="font-size: x-large;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
&lt;b&gt;&lt;span style="font-size: x-large;"&gt;The Game&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_DVYH9neSnMw/SzvGzJLr8BI/AAAAAAAAALg/QmW0PmAY70U/s1600-h/Untitled-6.jpg" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_DVYH9neSnMw/SzvGzJLr8BI/AAAAAAAAALg/QmW0PmAY70U/s200/Untitled-6.jpg" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;/div&gt;Essentially, it's a &lt;a href="http://en.wikipedia.org/wiki/Zero-sum_(game_theory)"&gt;zero sum&lt;/a&gt;,&amp;nbsp;deterministic two-players&amp;nbsp;game, somewhat similar to &lt;a href="http://en.wikipedia.org/wiki/Reversi"&gt;othello&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
In it's simplest form AI for such a game is using &lt;a href="http://en.wikipedia.org/wiki/Minimax"&gt;minimax algorithm&lt;/a&gt;, quite often with&amp;nbsp;&lt;a href="http://en.wikipedia.org/wiki/Alpha-beta_pruning"&gt;alpha-beta pruning&lt;/a&gt;&amp;nbsp;optimization, to search the game tree, depth first, to a certain level (or until the time limit is reached).&lt;br /&gt;
&lt;br /&gt;
There is quite a bit of research in this area, with a lot of heuristics proposed to improve the "smartness" of the evaluator and game tree search.&amp;nbsp;They would be certainly interesting to try implementing, but as soon as I've got the basic minimax with alpha-beta pruning working, I decided not to bother with this for the time being.&lt;br /&gt;
&lt;br /&gt;
Again, for the sake of being able to work on other things and finish the game.&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
The board evaluation procedure was dead simple - it was the difference between the one's and rival's balls, the bigger the better, weighted together with the possibility to move, based on some simple heuristic, details of which I don't remember.&lt;br /&gt;
&lt;br /&gt;
The "board" was represented as a bitmask, wrapped by rows, with bit being set if there is something in the corresponding cell (with "something" having different meaning depending on the context), and the whole board state was represented as a triple of bitmasks: one for black balls, one for white balls, and one for empty cells.&lt;br /&gt;
&lt;br /&gt;
Then the bulk of operations/queries on the board state can be conveniently/efficiently done with the bitwise operations.&lt;br /&gt;
&lt;br /&gt;
This, I believe, is called &lt;a href="http://en.wikipedia.org/wiki/Bitboard"&gt;"bitboards"&lt;/a&gt;, and is quite common trick when programming similar two-player games.&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;span style="font-size: x-large;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
&lt;b&gt;&lt;span style="font-size: x-large;"&gt;The Engine&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
I admit that quite a bit of things here could be done in much simpler way, especially in context of such a simple task at hand.&lt;br /&gt;
&lt;br /&gt;
However, in retrospective it does not look that bad. It was certainly good learning experience, and some of the engine design decisions taken seem to have saved quite a bit of time, which would be otherwise wasted doing boring and repetitive things manually and then fixing all the mistakes done in the process.&lt;br /&gt;
&lt;br /&gt;
Few of the things, in no particular order:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Game-specific code was minimal and separated from the rest (an "engine" code)&lt;/li&gt;
&lt;li&gt;The engine code itself was quite modular and layered, different layers were communicating through the interfaces (for example, widgets are using the sprite manager to display sprites, which is using the renderer interface to draw the textured quads, and the renderer interface can have separate implementations for different graphics APIs - I used to have two of them dx8 and dx9).&amp;nbsp;&lt;/li&gt;
&lt;li&gt;Sprites were packed into "packages", using custom format, every sprite was cut into power-of-two chunks in a quadtree, and then those chunks were laid out in runtime on the surfaces in the texture memory cache. There was a custom C# tool which did the packing of the sprites, and generating of the font packages as well.&lt;/li&gt;
&lt;li&gt;A poor man c++ reflection system (using macro and template tricks) for the classes, derived from the "base game object" class, which made it possible to automatically serialize object hierarchies in text/binary format.&lt;/li&gt;
&lt;li&gt;Custom text format for representation of the object hierarchies in "scripts". I used XML at first (because I knew that rolling your own is a sin, and XML is the answer), but it turned out to be extremely ugly and hard to edit manually. So I did roll my own (which I called JML), using &lt;a href="http://dinosaur.compilertools.net/"&gt;flex/bison&lt;/a&gt;, and it turned out to be not as bad as they said.&lt;/li&gt;
&lt;li&gt;There is a "data binding" mechanism in scripts, the idea I've borrowed from &lt;a href="http://en.wikipedia.org/wiki/Qt_(toolkit)"&gt;Qt&lt;/a&gt; back then, and then eventually Microsoft has stolen it from me and implemented in &lt;a href="http://en.wikipedia.org/wiki/Windows_Presentation_Foundation"&gt;WPF&lt;/a&gt; :)&lt;/li&gt;
&lt;li&gt;I've got a set of ad-hoc python scripts which would generate project files (.vcproj/.sln, .dsp/.dsw). Every module had a text file called depends.txt, which used a simple syntax to describe which other internal/external libraries it references. The python script would then walk the source tree, find these files and do the generation. This way I could experiment with different physical source code layouts and manage dependencies explicitly without tinkering for ours in Visual Studio property dialogs.&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;So, for example, the main menu dialog script would look like this:&lt;br /&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;dialog &lt;span style="color: #ba2121;"&gt;"MainMenu"&lt;/span&gt;
{
    &lt;span style="color: #666666;"&gt;//&lt;/span&gt; ...
    picture &lt;span style="color: #ba2121;"&gt;"Logo"&lt;/span&gt;
    {
        skinpack        &lt;span style="color: #666666;"&gt;=&lt;/span&gt; &lt;span style="color: #ba2121;"&gt;"logo"&lt;/span&gt;;
        extents         &lt;span style="color: #666666;"&gt;=&lt;/span&gt; { &lt;span style="color: #666666;"&gt;40&lt;/span&gt;, &lt;span style="color: #666666;"&gt;30&lt;/span&gt;, &lt;span style="color: #666666;"&gt;330&lt;/span&gt;, &lt;span style="color: #666666;"&gt;100&lt;/span&gt; };
        stretch         &lt;span style="color: #666666;"&gt;=&lt;/span&gt; &lt;span style="color: green; font-weight: bold;"&gt;true&lt;/span&gt;;
        skinframe       &lt;span style="color: #666666;"&gt;=&lt;/span&gt; &lt;span style="color: #666666;"&gt;0&lt;/span&gt;;
    }

    shortcut &lt;span style="color: #ba2121;"&gt;"EditorShortcut"&lt;/span&gt;
    {
        Key             &lt;span style="color: #666666;"&gt;=&lt;/span&gt; &lt;span style="color: #ba2121;"&gt;"E"&lt;/span&gt;;
        Action          &lt;span style="color: #666666;"&gt;=&lt;/span&gt; &lt;span style="color: #666666;"&gt;&amp;gt;&amp;gt;&lt;/span&gt;MenuSystem.OnEditor;
    }
        
    button &lt;span style="color: #ba2121;"&gt;"ContinueGame"&lt;/span&gt;
    {
        text            &lt;span style="color: #666666;"&gt;=&lt;/span&gt; L&lt;span style="color: #ba2121;"&gt;"Continue Game"&lt;/span&gt;;
        extents         &lt;span style="color: #666666;"&gt;=&lt;/span&gt; { &lt;span style="color: #666666;"&gt;290&lt;/span&gt;, &lt;span style="color: #666666;"&gt;160&lt;/span&gt;, &lt;span style="color: #666666;"&gt;270&lt;/span&gt;, &lt;span style="color: #666666;"&gt;48&lt;/span&gt; };
        font            &lt;span style="color: #666666;"&gt;=&lt;/span&gt; &lt;span style="color: #ba2121;"&gt;"font_menu"&lt;/span&gt;;
        fontheight      &lt;span style="color: #666666;"&gt;=&lt;/span&gt; &lt;span style="color: #666666;"&gt;48&lt;/span&gt;;
        fgcolor         &lt;span style="color: #666666;"&gt;=&lt;/span&gt; &lt;span style="color: #666666;"&gt;0xFF49CD49&lt;/span&gt;;
        shadowcolor     &lt;span style="color: #666666;"&gt;=&lt;/span&gt; &lt;span style="color: #666666;"&gt;0xFF11FF11&lt;/span&gt;;
        hoverfgcolor    &lt;span style="color: #666666;"&gt;=&lt;/span&gt; &lt;span style="color: #666666;"&gt;0xFF88FF88&lt;/span&gt;;
        unpress         &lt;span style="color: #666666;"&gt;=&lt;/span&gt; &lt;span style="color: #666666;"&gt;&amp;gt;&amp;gt;&lt;/span&gt;MenuSystem.OnContinueGame;
        visible         &lt;span style="color: #666666;"&gt;=&lt;/span&gt; &lt;span style="color: #666666;"&gt;&amp;lt;&amp;lt;&lt;/span&gt;Core.Game.HasPlayers;
    }
    &lt;span style="color: #666666;"&gt;//&lt;/span&gt; ...
}&lt;/pre&gt;&lt;/div&gt;&lt;b&gt;&lt;span style="font-size: x-large;"&gt;Design&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_DVYH9neSnMw/SzvG-MUXpWI/AAAAAAAAALw/8B0Og_X4tOs/s1600-h/Untitled-4.jpg" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_DVYH9neSnMw/SzvG-MUXpWI/AAAAAAAAALw/8B0Og_X4tOs/s200/Untitled-4.jpg" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;/div&gt;It was obviously programmer art, from the beginning to end.&lt;br /&gt;
&lt;br /&gt;
I've found a few free sound samples on the internets, painted basic game screen elements myself in gimp (that included the space bee from the main menu screen).&lt;br /&gt;
&lt;br /&gt;
I've used&amp;nbsp;&lt;a href="http://bancomicsans.com/home.html"&gt;Comic Sans MS&lt;/a&gt;&amp;nbsp;in user interface, which is a trademark of amateurish design.The interface itself is not consistent, not intuitive, badly laid out and uses a horrible color palette.&lt;br /&gt;
&lt;br /&gt;
So it's hard to call it a "design", rather an inconsistent pile of placeholders. Which I did realize back then, but again did not overfocus on that, hoping that eventually I might get a help from someone who has a taste and gets interested in this.&lt;br /&gt;
&lt;br /&gt;
&lt;div&gt;&lt;b&gt;&lt;span style="font-size: x-large;"&gt;The Editor&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;I've decided to add a certain "non-linear" twist to the original Hexxagon gameplay.&lt;br /&gt;
&lt;br /&gt;
The player would progress through the sequence of "levels", which get more complex in terms of the original board setup (the "smartness" of the computer opponent would still remain the same, as it is essentially the same limited depth/time minimax solution tree search). When certain level is won, it opens one or more new ones, and it's up to player to pick which one to play next.&lt;br /&gt;
&lt;br /&gt;
So, it is not necessary to win all the levels in order to "beat the game". The levels form a kind of a graph with nodes being the particular board setups. And if there is an edge from a source level to destination one, it means that destination is available to play after the source is won.&lt;br /&gt;
&lt;br /&gt;
While all the levels and transitions between them could perfectly be "designed" in Notepad (and probably it would be a better idea to keep it that simple), I've decided to make an "in-game" editor for those.&lt;br /&gt;
&lt;br /&gt;
Which turned out to be pretty rad in the end:&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_DVYH9neSnMw/Szu1aVW-itI/AAAAAAAAALA/FDqbG4R-xPM/s1600-h/Untitled-2.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_DVYH9neSnMw/Szu1aVW-itI/AAAAAAAAALA/FDqbG4R-xPM/s320/Untitled-2.jpg" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
One could pan, zoom the whole graph, select node groups, move them around, double click on nodes and edit them etc.&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_DVYH9neSnMw/Szu16QMLzbI/AAAAAAAAALI/49f7W8OVYko/s1600-h/Untitled-3.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/_DVYH9neSnMw/Szu16QMLzbI/AAAAAAAAALI/49f7W8OVYko/s320/Untitled-3.jpg" style="cursor: move;" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;/div&gt;The whole game, when zoomed away, would look like a big &lt;a href="http://en.wikipedia.org/wiki/Directed_acyclic_graph"&gt;DAG&lt;/a&gt;, where&amp;nbsp;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;the leftmost node here is the starting level, and the rightmost one is the end level, which has to be won to finish the game.&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;span style="font-size: x-large;"&gt;Release&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
The testing (including the focus testing) was done by myself and my friends. The game was obviously far away from being ready, but at least it was somewhat playable, so I decided not to wait an eternity "til it's done" and publish an early version.&lt;br /&gt;
&lt;a href="http://2.bp.blogspot.com/_DVYH9neSnMw/Szu91AcMPLI/AAAAAAAAALY/wbQOP-4g9Vc/s1600/Untitled-7.jpg" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/_DVYH9neSnMw/Szu91AcMPLI/AAAAAAAAALY/wbQOP-4g9Vc/s200/Untitled-7.jpg" /&gt;&lt;/a&gt;&lt;br /&gt;
I used NSIS for the installer, and was quite happy with that, as the whole distributable size was below 1Mb, which was pretty good for the downloadable game.&lt;br /&gt;
&lt;br /&gt;
Funny enough, I clearly remember myself not counting the things like making an installer or the game's web page as work, which has to be taken into account.&lt;br /&gt;
&lt;br /&gt;
Turned out, that even with the help of such great tools like NSIS or Inno Setup (which make life much, much easier in this regard), it still took considerable amount of time, especially since I did not have much previous experience in these areas.&lt;br /&gt;
&lt;br /&gt;
So that was another good lesson to learn.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;span style="font-size: x-large;"&gt;Evaluation&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
I have submitted "version 0.4" to tucows for evaluation and basically forgot about it, because the evaluation queues are pretty long, and it can take a few months before your software gets there (well, it used to be the case five years ago, but I presume it's not very different today).&lt;br /&gt;
&lt;br /&gt;
So it was quite a surprise for me to finally get my game reviewed and rated... with whooping three cows! Which according to the tucows folks themselves means:&lt;br /&gt;
&lt;blockquote&gt;&lt;span style="font-size: small;"&gt;If your application receives a three-, four-, or five-cow rating, congratulations! As you'll see by reading the Ratings Guide, this is no small feat. You are in the company of some of the best programmers in the world. We receive hundreds of requests each week for inclusion in the Tucows software library. The fact that you scored in the three-cow range or higher has earned you a spot on our site. This is a sign that your product is among the best of its kind.&lt;/span&gt;&lt;br /&gt;
&lt;/blockquote&gt;&lt;/div&gt;&lt;div&gt;See? My little game is among the best of it's kind!&lt;br /&gt;
&lt;br /&gt;
Seriously, though, I've got an extremely good feedback&amp;nbsp;in an e-mail soon after, where they were giving a detailed explanation about how did they evaluate the game, separately on topics of visuals, sound, fun and longevity, user interface, easiness to grasp etc.&lt;br /&gt;
&lt;br /&gt;
Obviously, graphics, sound and user interface were quite far from being the strongest sides, and that was very expected.&lt;br /&gt;
&lt;br /&gt;
Another weak side was perceived complexity of the game, and most of all that it is very hard for a new person to figure out what are the rules of the game and how to play in general (even though the rules are quite simple).&lt;br /&gt;
&lt;br /&gt;
It was also quite expected, as I was observing it myself during my "focus tests", and was going to "fix" it in later versions by making a tutorial (quite frankly, I had to postpone it to &amp;nbsp;"later versions" because it also turned out harder than I was originally expecting). &amp;nbsp; &lt;br /&gt;
&lt;br /&gt;
But still, I've got my three cows and that was quite a revelation.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;span style="font-size: x-large;"&gt;Aftermath&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
Well, there is none. Soon after I've decided to change my job and move to live in another country, so it was left where it was, at version 0.4.&lt;br /&gt;
&lt;br /&gt;
I did not finish the game, there were quite a bit of things to do yet, but still managed to experience one iteration of the possible game project&amp;nbsp;life cycle, from beginning to what can be called "end".&lt;br /&gt;
&lt;br /&gt;
It's not on tucows anymore, but still is downloadable &lt;a href="http://www.softsea.com/review/Honey-Rush.html"&gt;on the internets&lt;/a&gt;.&lt;br /&gt;
I've also&amp;nbsp;&lt;a href="http://forums.indiegamer.com/showthread.php?p=70021"&gt;made&lt;/a&gt; the source code public, and it was available until my hosting period has ended.&lt;br /&gt;
&lt;br /&gt;
But all in all, being a failure it is (i did not really finish the game, and it did not find its players), it still was a success to me personally, in the experience it has brought.&lt;br /&gt;
&lt;br /&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/923082020090979517-4175501063275581871?l=blog.ruslans.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/gd_reflections/~4/qBCQvq1oqIE" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.ruslans.com/feeds/4175501063275581871/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=923082020090979517&amp;postID=4175501063275581871" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/923082020090979517/posts/default/4175501063275581871" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/923082020090979517/posts/default/4175501063275581871" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/gd_reflections/~3/qBCQvq1oqIE/bees-in-space-or-story-of-my-first.html" title="Bees in Space, or story of my first freeware  game project" /><author><name>ruslans</name><uri>http://www.blogger.com/profile/03375859473751956887</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="24" height="32" src="http://2.bp.blogspot.com/_DVYH9neSnMw/S0V_XM6aN0I/AAAAAAAAAMc/06dTTnY0PNw/S220/avatar3.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/_DVYH9neSnMw/Szufbrub6VI/AAAAAAAAAK4/bxs2pLuqjZc/s72-c/Untitled-1.jpg" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://blog.ruslans.com/2009/12/bees-in-space-or-story-of-my-first.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-923082020090979517.post-8466157245515706287</id><published>2009-07-02T11:27:00.001-07:00</published><updated>2010-04-16T00:13:53.274-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="tongue-in-a-cheek" /><title type="text">Kozma Prutkov, one of the brightest minds in the software development</title><content type="html">&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_DVYH9neSnMw/Sk0QU7ASkeI/AAAAAAAAAG4/RVBQRma4KEM/s1600-h/prutkov.jpg"&gt;&lt;blockquote&gt;&lt;/blockquote&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 155px; height: 200px;" src="http://1.bp.blogspot.com/_DVYH9neSnMw/Sk0QU7ASkeI/AAAAAAAAAG4/RVBQRma4KEM/s200/prutkov.jpg" border="0" alt="" id="BLOGGER_PHOTO_ID_5353953483635724770" /&gt;&lt;/a&gt;
Alright, that's quite a stretch. Not only &lt;a href="http://en.wikipedia.org/wiki/Kozma_Prutkov"&gt;Kozma Prutkov&lt;/a&gt; is by no means a software developer (he was a writer, one and a half centuries ago), it's also not a real person (but rather three people behind a single fictional name).&lt;div&gt;
&lt;/div&gt;&lt;div&gt;The reason that he's not that well known is that it appears to be quite hard to translate his aphorisms, which are hugely based on the wordplay. Which reminds of what Douglas Hofstadter said about &lt;a href="http://en.wikipedia.org/wiki/Godel,_Escher,_Bach"&gt;Gödel, Escher, Bach&lt;/a&gt; translation:&lt;/div&gt;&lt;div&gt;&lt;blockquote&gt;There were a million issues to consider in any potential translation, since the book is rife not only with explicit wordplay but also with what Scott Kim dubbed "structural puns" - passages where form and content echo or reinforce each other in some unexpected manner, and very often thanks to happy coincidences involving specific English words.&lt;/blockquote&gt;And I think it's a shame in case of Kozma Prutkov. Those little revelations, hidden in a generally tongue-in-a-cheek perls of wisdom, in some ways defined my own world-view long time ago, and I am even more amused to see how do they manage to take new forms when I return to them today.&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;Fortunately, some people &lt;a href="http://www.geocities.com/uniart/mix/kp.htm"&gt;tried to translate it&lt;/a&gt;, anyway.
&lt;div&gt;
&lt;/div&gt;&lt;div&gt;The good thing about this kind of ambiguous and satirical aphorisms is that one is free to put into them whatever meaning he feels fits better himself. &lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;However, in this particular case I was really impressed to discover so many empirical truisms of the software development, which can be directly mapped upon Kozma Prutkov's aphorisms. &lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;Well, this discovery is quite a pleasant exercise on its own. People tend to get enjoyment in finding familiar patterns observing seemingly unrelated phenomenas ("&lt;a href="http://dukenukem.typepad.com/game_matters/2005/07/learning_to_be_.html"&gt;We experience delight when we recognize patterns, yet we're also surprised by them&lt;/a&gt;").

&lt;/div&gt;&lt;div&gt;So, I will dare to cite some of them.&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;To be honest, my original plan was to append my own thoughts/associations (and possibly explanatory links) triggered by these sentences. But then I understood that most of those thoughts are pretty obvious, and besides that would possibly rob some people from having a kind of enjoyment I had while discovering these associations themselves.

&lt;/div&gt;&lt;div&gt;So for only the couple of the first ones:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-style: italic; "&gt;Do not cut everything that grows.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;&lt;i&gt;&lt;blockquote&gt;&lt;/blockquote&gt;&lt;span class="Apple-style-span" style="font-style: normal;"&gt;&lt;a href="http://c2.com/cgi/wiki/wiki?IfItAintBrokeDontFixIt"&gt;If it ain't broke don't fix it&lt;/a&gt;&lt;/span&gt;&lt;/i&gt;&lt;/div&gt;&lt;ul&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-style: italic; "&gt;Buy a painting first, and then frame it. &lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;i&gt;&lt;span class="Apple-style-span" style="font-style: normal;"&gt;&lt;a href="http://en.wikipedia.org/wiki/You_Ain't_Gonna_Need_It" style="text-decoration: none;"&gt;You are not gonna need it&lt;/a&gt;&lt;/span&gt;&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;&lt;i&gt;The first step of a baby is the first step to his death.&lt;/i&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;Most of the software designs are deemed to die much sooner than one would expect. But chances are that they will give a birth to the next generation, and many others after that. One has to consider it when designing the systems. &lt;/div&gt;&lt;div&gt;&lt;i&gt;
&lt;/i&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;&lt;a href="http://en.wikipedia.org/wiki/You_Ain't_Gonna_Need_It"&gt;&lt;/a&gt;&lt;span class="Apple-style-span" style="font-style: normal;"&gt;Now, I challenge you to find your own associations for the rest:
&lt;/span&gt;&lt;/i&gt;&lt;ul&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-style: italic; "&gt;Many things are incomprehensible to us not because our comprehension is weak, but because those things are not within the frames of our comprehension.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-style: italic; "&gt;If upon a cage of an elephant you will see a sign reading: "buffalo", do not believe your eyes.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-style: italic; "&gt;When casting pebbles into water, look at the ripples being formed thereby. Otherwise this activity will be an empty amusement.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-style: italic; "&gt;Never run to the extreme: who wants to dine too late today takes chances to instead breakfast tomorrow, early in the morning.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-style: italic; "&gt;What other people can say about you if you can't say anything about yourself?&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-style: italic; "&gt;Trace everything back to the beginning and you will understand a lot.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-style: italic; "&gt;New boots always pinch.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-style: italic; "&gt;Nobody will embrace the unembraceable.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-style: italic; "&gt;There is no great thing that would not be surmounted by a still greater thing. There is no thing so small that no smaller thing could fit into it.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-style: italic; "&gt;Look in the root!&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-style: italic; "&gt;Better say little, but well.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-style: italic; "&gt;People's memory is like a piece of white paper: sometimes it writes well, and sometimes bad.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-style: italic; "&gt;What is the best? - Having compared the past, link it to the present.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-style: italic; "&gt;If you have a fountain, plug it up. Let the fountain too have a rest.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-style: italic; "&gt;Only reason on what your notions allow you to discuss. Thus, knowing nothing about the laws of the Iroquois language, can you pass a judgement on it that would not be ill-founded and stupid?&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-style: italic; "&gt;Having lied once, who will believe you?&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-style: italic; "&gt;Looking into the distance, you will see the distance; looking to the sky, you will see the sky; looking in a small mirror, you will only see yourself.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-style: italic; "&gt;Where is the beginning of the end that comes at the end of the beginning?&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-style: italic; "&gt;Do not seek for unity in the whole, but rather in the uniformity of distinction.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-style: italic; "&gt;We don't care for what we have, we deplore what we have lost.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-style: italic; "&gt;Every thing is a manifestation of infinite diversity.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-style: italic; "&gt;Who prevents you from inventing waterproof gun-powder?&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-style: italic; "&gt;When looking at the sun, squint your eyes - and you'll readily discern the spots upon it.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-style: italic; "&gt;If all the past were present, and the present existed along with the future, who would be able to distinguish, where are the causes and where are the consequences?&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-style: italic; "&gt;Virtue is an award for itself. A man excels the virtue, if he serves never receiving an award.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-style: italic; "&gt;The harm or benefit of an act depend on the combination of circumstances.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-style: italic; "&gt;Things can be great or minor not only by fate's will, or contingency, but also by every person's notions.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-style: italic; "&gt;Sometimes, zeal overcomes even the common sense.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-style: italic; "&gt;When it concerns art, every tailor has views of his own.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-style: italic; "&gt;People could not stop living together, even if they walked far away from each other.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-style: italic; "&gt;If you want to be happy, be!&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;I'd be really happy to hear from you, and compare it with the picture in my own head.&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/923082020090979517-8466157245515706287?l=blog.ruslans.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/gd_reflections/~4/8-j0dKB5n5M" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.ruslans.com/feeds/8466157245515706287/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=923082020090979517&amp;postID=8466157245515706287" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/923082020090979517/posts/default/8466157245515706287" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/923082020090979517/posts/default/8466157245515706287" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/gd_reflections/~3/8-j0dKB5n5M/kozma-prutkov-one-of-brightest-minds-in.html" title="Kozma Prutkov, one of the brightest minds in the software development" /><author><name>ruslans</name><uri>http://www.blogger.com/profile/03375859473751956887</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="24" height="32" src="http://2.bp.blogspot.com/_DVYH9neSnMw/S0V_XM6aN0I/AAAAAAAAAMc/06dTTnY0PNw/S220/avatar3.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/_DVYH9neSnMw/Sk0QU7ASkeI/AAAAAAAAAG4/RVBQRma4KEM/s72-c/prutkov.jpg" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://blog.ruslans.com/2009/07/kozma-prutkov-one-of-brightest-minds-in.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-923082020090979517.post-7911508710785640426</id><published>2009-07-01T03:00:00.000-07:00</published><updated>2011-04-25T14:28:07.514-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="self-improvement" /><category scheme="http://www.blogger.com/atom/ns#" term="books" /><category scheme="http://www.blogger.com/atom/ns#" term="programming languages" /><title type="text">There will be no substitute for COBOL</title><content type="html">&lt;a href="http://www.amazon.com/Software-Conflict-2-0-Science-Engineering/dp/0977213307" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;img alt="" border="0" src="http://g-ecx.images-amazon.com/images/G/01/ciu/00/ac/4ed09833e7a06eba7a0c0110.L.jpg" style="cursor: hand; cursor: pointer; float: left; height: 240px; margin: 0 10px 10px 0; width: 240px;" /&gt;&lt;/a&gt;
I've bought that&lt;i&gt; &lt;a href="http://www.amazon.com/Software-Conflict-2-0-Science-Engineering/dp/0977213307"&gt;book&lt;/a&gt; &lt;/i&gt;quite some time ago, and only recently managed to fetch it from my bookshelf (did I already mention that I am a &lt;a href="http://digital-cucumbers.blogspot.com/2009/06/pragmatic-thinking-by-andy-hunt.html"&gt;book junkie&lt;/a&gt;)?..
&lt;div&gt;&lt;/div&gt;&lt;div&gt;Being a second edition of the classic book, some kind of a new thin wrap around ten years old candy, it still manages to sound insightful in some places.&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;Well, that candy is not just old, it's ancient (first edition is 1990, second one is 2005)... well, at least from the perspective of everchanging software development world.&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;Still, I'm done through the bigger half of that, and I am not regretting doing that so far. However, there was one part which has turned out to be mind provoking in a somewhat unexpected way:&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;blockquote&gt;&lt;/blockquote&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;But there's something else happening here, too. With all that heavy use of COBOL in the business world, where money is to be made by cutting costs wherever possible, why haven't at least a few companies switched  to something better? No, I don't mean &lt;a href="http://en.wikipedia.org/wiki/4GL"&gt;4GL&lt;/a&gt;s. I mean &lt;a href="http://en.wikipedia.org/wiki/Third-generation_programming_language"&gt;3GL&lt;/a&gt;s that provide the same capabilities as COBOL. Why haven't the innovative, advanced firms started using a better COBOL?&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;Here's where I want to get to the real point of this essay. I want to take the position that people aren't switching away from COBOL because there really isn't anything better to switch to.&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;Heresy! Ignorance! Stupidity! I can hear the silent cries from my reading audience now. But wait, there is method in my madness, and I would like to explain.&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;...What other tools have been invented to address [the business] problem domain?.. That better way is still COBOL. That's the gist of my heresy.&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;Does that mean that I think COBOL is a good language?&lt;/div&gt;&lt;div&gt;Emphatically, my answer is a resounding "No."&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;...Why? Why is this ancient and clumsy language not replaced by something that does its job more cleanly? Because, I would assert, the research world which might create a better language is so disdainful of business application software in general, and the COBOL language in particular, that it is blind to the thought that a major research challenge lies in defining a better COBOL.&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://en.wikipedia.org/wiki/COBOL"&gt;COBOL&lt;/a&gt;, eh?&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;Now, certainly, COBOL is out from the scene, and that's something Robert Glass acknowledges himself (what a surprise!) in that "special 2nd edition chapter".  But that's not the point.&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;"COBOL" is just a label, and if one blurs it away from the picture (together with probably some other vintage things), the pattern extracted seems to be very familiar.&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;As it usually happens with my poor mind, when it's being provoked by something, I see a reference to several (possibly non-related) things at once:
&lt;ul&gt;&lt;li&gt;That &lt;a href="http://blogs.techrepublic.com.com/programming-and-development/?p=1372"&gt;Deja Vu &lt;/a&gt; feeling one gets often when reading discussions about the present state of the technology. So, does C++ looks like COBOL in this context?..&lt;/li&gt;&lt;li&gt;And what about that &lt;a href="http://www.st.cs.uni-saarland.de/edu/seminare/2005/advanced-fp/docs/sweeny.pdf"&gt;too well known Tim Sweeney talk&lt;/a&gt;?.. &lt;/li&gt;&lt;li&gt;And what is a "programming language", after all? Is it programmers' or users' thing, or maybe both?&lt;/li&gt;&lt;li&gt;Is really software development history developed in a spiral (pretty much like the human history)?&lt;/li&gt;&lt;li&gt;What is the point in developing the new "programming languages"? It seems that users do not care about languages, they prefer &lt;a href="http://digital-cucumbers.blogspot.com/2009/06/ephemerality-of-code-value.html"&gt;working software&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;And what about our's today arrogance? Like in, "C++ is going to stay here for a while, because it's the most efficient language, and computer games do &lt;a href="http://c2.com/cgi-bin/wiki?PrematureOptimization"&gt;demand performance&lt;/a&gt;".&lt;/li&gt;&lt;li&gt;Could it be, that business value of the software is higher if users have more control over the way this software is applied to their domain?&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;I mean, yeah, of course. C++ is not COBOL. And Java is not COBOL. And C# is not COBOL. And F# is not COBOL.&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;Those are bloody modern and mainstream.&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;Or are they?..&lt;/div&gt;&lt;div&gt;Or maybe they are just an another coil of the Spiral?&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;What we are, then? Are we the pivot of that spiral, or just a part of a coil?&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;All our experience, knowledge, mental models - all of it can happen to become nothing in the long term.&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;So, what do we do to prevent that?&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;Learn COBOL, of course.&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/923082020090979517-7911508710785640426?l=blog.ruslans.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/gd_reflections/~4/t-t4lNMir2g" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.ruslans.com/feeds/7911508710785640426/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=923082020090979517&amp;postID=7911508710785640426" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/923082020090979517/posts/default/7911508710785640426" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/923082020090979517/posts/default/7911508710785640426" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/gd_reflections/~3/t-t4lNMir2g/there-will-be-no-substitute-for-cobol.html" title="There will be no substitute for COBOL" /><author><name>ruslans</name><uri>http://www.blogger.com/profile/03375859473751956887</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="24" height="32" src="http://2.bp.blogspot.com/_DVYH9neSnMw/S0V_XM6aN0I/AAAAAAAAAMc/06dTTnY0PNw/S220/avatar3.jpg" /></author><thr:total>1</thr:total><feedburner:origLink>http://blog.ruslans.com/2009/06/there-will-be-no-substitute-for-cobol.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-923082020090979517.post-1748297000668862115</id><published>2009-06-29T15:48:00.000-07:00</published><updated>2011-04-15T13:01:31.213-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="self-improvement" /><title type="text">Programmer's workout</title><content type="html">&lt;a href="http://2.bp.blogspot.com/_DVYH9neSnMw/SklHKEeSVGI/AAAAAAAAAGw/O_TdyTOK458/s1600-h/pumping-weights.jpg" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;img alt="" border="0" id="BLOGGER_PHOTO_ID_5352887870431581282" src="http://2.bp.blogspot.com/_DVYH9neSnMw/SklHKEeSVGI/AAAAAAAAAGw/O_TdyTOK458/s200/pumping-weights.jpg" style="cursor: hand; cursor: pointer; float: left; height: 150px; margin: 0 10px 10px 0; width: 200px;" /&gt;&lt;/a&gt;
There was another metaphor concerning the programmer's skills development, which I personally feel is quite sound.&lt;br /&gt;
&lt;br /&gt;
&lt;div&gt;
&lt;/div&gt;
&lt;div&gt;
We had this discussion with the fellow programmers, about learning new programming languages and technologies, and generally doing the work which is not just something that you are not really get paid for, but also you don't get any visible benefit at all from doing it. You don't produce any measurable value.&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;/div&gt;
&lt;div&gt;
As in, for example, writing a throw-away code in some new programming language just for the sake of learning that language itself.&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;/div&gt;
&lt;div&gt;
The notion of "throw-away code" turns out to be more painful than it could be expected: quite often people get extremely personally attached to their designs, algorithms, code, and time spent on some certain activity in general. So, how come one can even remotely be attached to the throw-away "garbage"?..&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;/div&gt;
&lt;div&gt;
That takes different forms and flavours: one feels sorry that he had spent years in the university studying something which does not seem to help to find a job, others are reluctant to get interested in anything outside their own area of expertise ("we don't have time for that, it's not our job"). In the case of programmers, in particular, it often turns out in discarding any kind of mentioning related to the technologies, programming languages, libraries, development methodologies, practices which appear to be unrelated to their job.&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;/div&gt;
&lt;div&gt;
That's not just &lt;a href="http://en.wikipedia.org/wiki/Cognitive_bias"&gt;cognitive biases&lt;/a&gt; in action (which I wholeheartedly confess in being affected by myself), but also pure and perfectly reasonable human behavior, which does it's best to optimize the actions taken by the human being.&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;/div&gt;
&lt;div&gt;
So, why would one voluntarily do anything, which is deemed to be discarded almost instantly?  &lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;/div&gt;
&lt;div&gt;
Now, here is where comes a &lt;b&gt;programmer's workout  &lt;/b&gt;metaphor into action.&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Consider yourself going to the gym, and spending some hours per week there, doing the exercises. What you do there, that "weight's pumping" is nothing else as taking heavy things at one place and lifting them up many times during some period of time, just to put those weights back to their place in the end.&lt;/div&gt;
&lt;div&gt;
&lt;/div&gt;
&lt;div&gt;
So, without any doubt, whatever happens there is:&lt;/div&gt;
&lt;div&gt;
&lt;ul&gt;
&lt;li&gt;boring&lt;/li&gt;
&lt;li&gt;hard&lt;/li&gt;
&lt;li&gt;time-consuming&lt;/li&gt;
&lt;li&gt;does not give &lt;b&gt;any &lt;/b&gt;visible outcome in the end (those weights end up in the original position).&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
What's the point, then?.. What is the point in doing something, which is barely enjoyable, and gives no visible outcome immediately?&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;/div&gt;
&lt;div&gt;
The stock answer would be that benefit is invisible, long term, and whatnot. &lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;/div&gt;
&lt;div&gt;
But I honestly think that there really is no point, unless you can tune yourself into the state, where you can consistently come up with short-term achievable goals, and furthermore have the feeling of the success every time those goals are achieved.&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;/div&gt;
&lt;div&gt;
So, you've pumped up that thing 12 times two days ago?.. what about adding a couple of kilos on top today and do the same? What about &lt;a href="http://www.positivityblog.com/index.php/2008/01/08/arnold-schwarzeneggers-top-5-tips-for-building-the-life-you-want/"&gt;going an extra mile&lt;/a&gt;?.. Can you spend 10 more minutes in the gym today?.. You can't?.. Well, it's fine, who cares, there's always next time to try again.&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;/div&gt;
&lt;div&gt;
You make this small game out of seemingly boring endeavor, and then eventually, unnoticeably you get to the point where you get used to the process and you start to like it.&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;/div&gt;
&lt;div&gt;
You start to enjoy it.&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;/div&gt;
&lt;div&gt;
And then, what happens next? The forementioned long-term success comes, that's what happens. You don't really feel it "suddenly coming". At that point it's already with you, and it's hard to tell a difference. But it's there. You see it when you start looking at your old photos. Or at your old code, for that matter. &lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;/div&gt;
&lt;div&gt;
And even if it does not do it that soon - who cares, that was just a game, right?&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;/div&gt;
&lt;div&gt;
So, you get a positive outcome out from doing those throw-away exercises, producing the value from nothing.&lt;/div&gt;
&lt;div&gt;
&lt;/div&gt;
&lt;div&gt;
What really happens is building a solid background, be it physical or intellectual.&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;/div&gt;
&lt;div&gt;
The only problem is that this building can be very routine and hard.&lt;/div&gt;
&lt;div&gt;
In this case helping yourself into making it a game can help a lot.&lt;/div&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/923082020090979517-1748297000668862115?l=blog.ruslans.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/gd_reflections/~4/ipj1EXm482Q" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.ruslans.com/feeds/1748297000668862115/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=923082020090979517&amp;postID=1748297000668862115" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/923082020090979517/posts/default/1748297000668862115" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/923082020090979517/posts/default/1748297000668862115" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/gd_reflections/~3/ipj1EXm482Q/programmers-workout.html" title="Programmer's workout" /><author><name>ruslans</name><uri>http://www.blogger.com/profile/03375859473751956887</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="24" height="32" src="http://2.bp.blogspot.com/_DVYH9neSnMw/S0V_XM6aN0I/AAAAAAAAAMc/06dTTnY0PNw/S220/avatar3.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/_DVYH9neSnMw/SklHKEeSVGI/AAAAAAAAAGw/O_TdyTOK458/s72-c/pumping-weights.jpg" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://blog.ruslans.com/2009/06/programmers-workout.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-923082020090979517.post-7961792496090360216</id><published>2009-06-21T06:53:00.000-07:00</published><updated>2011-04-15T13:05:02.340-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="self-improvement" /><category scheme="http://www.blogger.com/atom/ns#" term="books" /><title type="text">Pragmatic Thinking&amp;Learning by Andy Hunt</title><content type="html">&lt;a href="http://ecx.images-amazon.com/images/I/51xArZnegaL._SL500_AA240_.jpg" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;img alt="" border="0" src="http://ecx.images-amazon.com/images/I/51xArZnegaL._SL500_AA240_.jpg" style="cursor: pointer; float: left; height: 240px; margin: 0pt 10px 10px 0pt; width: 240px;" /&gt;&lt;/a&gt;
So,&lt;a href="http://www.pragprog.com/titles/ahptl/pragmatic-thinking-and-learning"&gt; the book&lt;/a&gt; was on my  wish list  for a while, and then I've suddenly bought it.&lt;br /&gt;
&lt;br /&gt;
And read.&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;Fortunately, it's not too big and not too mind-pressing, so it did not fall a victim to my occasional &lt;a href="http://en.wikipedia.org/wiki/Bibliomania"&gt;bibliomania&lt;/a&gt; (yes, I've bought a few other interesting books, some of them still not finished, such a shame).

It was a good read, overall.&lt;br /&gt;
&lt;br /&gt;
Sometimes very insightful, even though sometimes it was giving impression of the text being added just for the sake of keeping the format of the book (which otherwise could be a good article).&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;The style is very accessible (which is &lt;span style="font-style: italic;"&gt;pragmatic &lt;/span&gt;trademark), there are anecdotes and humorous remarks here and there, which makes for easier reading.
&lt;br /&gt;
&lt;blockquote&gt;
...a controversial study done in the United Kingdom noted that if you constantly interrupt your task to check e-mail or respond to an IM text message, your effective IQ drops ten points.

By comparison, smoking a marijuana joint drops your IQ a mere four points.

Whatever you do, please don't do &lt;span style="font-style: italic;"&gt;both&lt;/span&gt;.&lt;/blockquote&gt;
However, some things are abused a bit, in my opinion. For example there is too much fuzz around &lt;a href="http://en.wikipedia.org/wiki/Dreyfus_model_of_skill_acquisition"&gt;Dreyfus model&lt;/a&gt;, or around brain's &lt;a href="http://en.wikipedia.org/wiki/Lateralization_of_brain_function"&gt;L-mode/R-mode&lt;/a&gt;. To the extent, that sometimes it gives an impression of the marketing speech, rather than revelation, which most of the pragmatic bookshelf books traditionally are.

Still, I think the book was a good money investment.

Interesting points I've got from it:
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;There is no golden rules to follow in the software development, everything should be considered in the context, i.e. which systems are there, how they interact (in explicit or hidden ways).&lt;/li&gt;
&lt;li&gt;The role of "subconsciousness" in the problem-solving should not be underestimated (that's w.hat is called "R-mode"), as it tends to see "the big picture", and has generally access to much bigger amounts of knowledge.&lt;/li&gt;
&lt;li&gt;Experts, the ones which are true masters of their profession, rely deeply upon "intuition" to take decisions. Intuition, as ephemeral as it might sound, is nothing else as the ability to access all the knowledge and experience packed into non-linear way deep inside one's mind.&lt;/li&gt;
&lt;li&gt;One does not just "switch to R-mode" to solve complex problems. It's  proper interaction/switching  between L/R modes what is important.&lt;/li&gt;
&lt;li&gt;One can "train" oneself to operate more efficiently on the knowledge access inside the brain (this includes developing of the R-mode).&lt;/li&gt;
&lt;li&gt;It's not only that learning constantly is important, also the way learning happens matters a lot. There are ways to make cognition more effective, such as mind maps, collaborative learning, exploration, playing, engaging metaphors and analogies etc.&lt;/li&gt;
&lt;li&gt;It's important to maintain diversity in the personal skills, trying to learn thing which might seem "irrelevant" to one's profession.&lt;/li&gt;
&lt;li&gt;Stress kills cognition, positive thinking is important for being able to use the brain effectively.&lt;/li&gt;
&lt;li&gt;Failure is important and inseparable part of the learning. One has to embrace failure as the opportunity to gain the experience and to stretch the boundaries of the cognition. On the other hand, it should be safe and non-expensive to fail as often as possible (because stress kills cognition).&lt;/li&gt;
&lt;li&gt;In the 5-tier Dreyfus model (novice, advanced beginner, competent, proficient, expert) applied to the programming skill, most of the people are on the advanced beginner level.&lt;/li&gt;
&lt;li&gt;Software documentation is not as important, as &lt;span style="font-style: italic;"&gt;documenting&lt;/span&gt; process.
&lt;/li&gt;
&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/923082020090979517-7961792496090360216?l=blog.ruslans.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/gd_reflections/~4/wjp-C7zNK8I" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.ruslans.com/feeds/7961792496090360216/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=923082020090979517&amp;postID=7961792496090360216" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/923082020090979517/posts/default/7961792496090360216" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/923082020090979517/posts/default/7961792496090360216" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/gd_reflections/~3/wjp-C7zNK8I/pragmatic-thinking-by-andy-hunt.html" title="Pragmatic Thinking&amp;Learning by Andy Hunt" /><author><name>ruslans</name><uri>http://www.blogger.com/profile/03375859473751956887</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="24" height="32" src="http://2.bp.blogspot.com/_DVYH9neSnMw/S0V_XM6aN0I/AAAAAAAAAMc/06dTTnY0PNw/S220/avatar3.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://blog.ruslans.com/2009/06/pragmatic-thinking-by-andy-hunt.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-923082020090979517.post-5597733171266492025</id><published>2009-06-17T13:41:00.000-07:00</published><updated>2011-04-24T07:12:51.076-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="qt" /><title type="text">About Qt</title><content type="html">I've accidentally found out today, that one nice guy from my language courses actually works for &lt;a href="http://en.wikipedia.org/wiki/Trolltech"&gt;Trolltech&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
So he has told me that, and also that Trolltech is actually a part of Nokia now (again, "revelation" to me, even though these news are 1.5 years old already).&lt;br /&gt;
&lt;br /&gt;
&lt;div&gt;
&lt;/div&gt;
&lt;div&gt;
I have this "not surprised" feeling, for some reason.&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Qt made a good bargain by being multi-platform, GPL, well-designed, productive and appealing GUI toolkit back then. &lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;/div&gt;
&lt;div&gt;
Today, when MFC is in the past (well, almost), as well as C++ usage for the newly created desktop applications, and when Microsoft itself provides "free" and much better alternatives (such as .NET platorm, WPF etc.), it probably makes sense to adjust business strategies in order to still have a chance to occupy a bigger niche.&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;/div&gt;
&lt;div&gt;
Qt still seems to be the most appealing alternative in case of pure C++ applications. The bulk of those these days, though, are the ones with the roots in the past century, so it's highly unlikely that a lot of them would make a business decision to switch to Qt (in some cases, I imagine, it's hardly possible also).&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;/div&gt;
&lt;div&gt;
In any case, it's always entertaining to observe such movements on the market.&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
It's very possible that in 10 years software market (and game development in particular) will work by somewhat different rules than we've got used to.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/923082020090979517-5597733171266492025?l=blog.ruslans.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/gd_reflections/~4/mD4PkQfkNDI" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.ruslans.com/feeds/5597733171266492025/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=923082020090979517&amp;postID=5597733171266492025" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/923082020090979517/posts/default/5597733171266492025" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/923082020090979517/posts/default/5597733171266492025" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/gd_reflections/~3/mD4PkQfkNDI/about-qt.html" title="About Qt" /><author><name>ruslans</name><uri>http://www.blogger.com/profile/03375859473751956887</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="24" height="32" src="http://2.bp.blogspot.com/_DVYH9neSnMw/S0V_XM6aN0I/AAAAAAAAAMc/06dTTnY0PNw/S220/avatar3.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://blog.ruslans.com/2009/06/about-qt.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-923082020090979517.post-4357778600598575035</id><published>2009-06-14T06:30:00.000-07:00</published><updated>2011-04-15T13:02:40.298-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="productivity" /><title type="text">The case of the immediate feedback</title><content type="html">I've spent some time today to make a "hello world" kind of application in &lt;a href="http://www.microsoft.com/visualstudio/en-us/products/2010/default.mspx"&gt;Visual Studio 2010&lt;/a&gt; using &lt;a href="http://axiomengine.sourceforge.net/mediawiki-1.13.2/index.php/Main_Page"&gt;Axiom&lt;/a&gt; engine (which in turn is build upon &lt;a href="http://www.ogre3d.org/"&gt;Ogre3D&lt;/a&gt;).&lt;br /&gt;
&lt;br /&gt;
The goal was to be able to make a small game, which would have all the bookkeeping part done in C#, and all the game logic done in &lt;a href="http://research.microsoft.com/en-us/um/cambridge/projects/fsharp/"&gt;F#&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;Well, I've kind of managed to do that, except that the final setup is not that snappy in regards of iterative experimenting, as it was an initial hope to achieve with F#.&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;It'd take some while to startup Axiom/Ogre every time the change  is made, thus partially defeating the purpose of  trying F# in the first place.&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;Of course, it's very possible that due to my close to zero experience with Axiom I am doing the whole thing in a wrong way, so the mentioned feedback loop could be shortened by introducing some shortcuts.&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;Or, I am approaching the problem in a wrong way.&lt;br /&gt;
&lt;br /&gt;
It might be very well also possible to avoid starting the 3D engine for developing the game logic, by using some kind of placeholder interface (made in WPF, for example).

Something to think about.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/923082020090979517-4357778600598575035?l=blog.ruslans.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/gd_reflections/~4/8OiLab7hzEc" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.ruslans.com/feeds/4357778600598575035/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=923082020090979517&amp;postID=4357778600598575035" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/923082020090979517/posts/default/4357778600598575035" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/923082020090979517/posts/default/4357778600598575035" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/gd_reflections/~3/8OiLab7hzEc/case-of-immediate-feedback.html" title="The case of the immediate feedback" /><author><name>ruslans</name><uri>http://www.blogger.com/profile/03375859473751956887</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="24" height="32" src="http://2.bp.blogspot.com/_DVYH9neSnMw/S0V_XM6aN0I/AAAAAAAAAMc/06dTTnY0PNw/S220/avatar3.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://blog.ruslans.com/2009/06/case-of-immediate-feedback.html</feedburner:origLink></entry></feed>

