    function $(e)
    {
        return document.getElementById(e);
    }

    function prepare_box_nodes()
    {
        var boxdivs = $('boxes').getElementsByTagName('div');
        var menulis = $('menuboxes').getElementsByTagName("li");
        var m;

        box_nodes = [];
        for(var i = 0; i < 4; i++) {
            box_nodes[i] = [];
            for(var k = 0; k < 4; k++) {
                box_nodes[i][k] = boxdivs[i * 4 + k];
            }
        }
        for(var i = 0; i < menulis.length; i++) {
            if(m = menulis[i].className.match(/col([0-9]+).*row([0-9]+)/)) {
                menulis[i].underlyingDiv = box_nodes[m[2] - 1][m[1] - 1];
                box_nodes[m[2] - 1][m[1] - 1] = menulis[i];
            }
        }
    }
    function fade(args)
    {
        if(args.element.__fade_timeout) clearTimeout(args.element.__fade_timeout);
        if(args.element.__fade_interval) clearInterval(args.element.__fade_interval);

        var setPos = function(el, top, height) {
            el.style.overflow = "hidden";
            var oldTop = Number(el.getAttribute('oldTop') || 85 * (el.className.replace(/^.*row([0-9]+).*$/, '$1') - 1));
            el.setAttribute('oldTop', oldTop);
            el.style.top = Math.round(oldTop + top) + 'px';
            if(el.tagName == "LI") {
                setPos(el.underlyingDiv, top, height);
            }
            el.style.height = height + "px";
        }

        args.tick = args.tick || 20;
        args.opacity = Number(args.opacity || args.element.getAttribute('__fade_opacity') || 100);
        args.top = Number(args.top || args.element.getAttribute('__fade_top') || 0);
        args.bottom = Number(args.bottom || args.element.getAttribute('__fade_bottom') || 0);
        args.targetOpacity = (typeof(args.targetOpacity) != "undefined" ? args.targetOpacity : (args.opacity || 0));
        args.targetTop = (typeof(args.targetTop) != "undefined" ? args.targetTop : (args.top || 0));
        args.targetBottom = (typeof(args.targetBottom) != "undefined" ? args.targetBottom : (args.bottom || 0));
        args.delay = args.delay || 1;
        args.height = args.height || 73;
        
        args.opacity = Math.max(Math.min(args.opacity, 100), 0);
        args.top = Math.max(Math.min(args.top, args.height), 0);
        args.bottom = Math.max(Math.min(args.bottom, args.height), 0);
        if(args.bottom + args.top >= args.height) args.bottom = args.height - args.top - 1;;

        args.targetOpacity = Math.max(Math.min(args.targetOpacity, 100), 0);
        args.targetTop = Math.max(Math.min(args.targetTop, args.height), 0);
        args.targetBottom = Math.max(Math.min(args.targetBottom, args.height), 0);
        if(args.targetBottom + args.targetTop >= args.height) args.targetBottom = args.height - args.targetTop - 1;;
        
        args.steps = (args.steps || Math.abs(Math.ceil((args.targetOpacity - args.opacity) / args.stepOpacity))
                      || 10);

        args.stepOpacity = Math.ceil((args.targetOpacity - args.opacity) * 1000 / args.steps) / 1000;
        args.stepTop = Math.ceil((args.targetTop - args.top) * 1000 / args.steps) / 1000;
        args.stepBottom = Math.ceil((args.targetBottom - args.bottom) * 1000 / args.steps) / 1000;

        if((args.targetOpacity >= args.opacity) != (args.stepOpacity >= 0)) args.stepOpacity *= -1;
        /*if((args.targetOpacity == args.opacity || args.stepOpacity == 0)
           && (args.targetTop == args.top || args.stepTop == 0)
           && (args.targetBottom == args.bottom || args.stepBottom == 0))
            return;*/

        args.element.__fade_args = args;
        args.element.__fade_timeout = setTimeout(
            function()
            {
                args.element.__fade_timeout = null;
                args.element.__fade_interval = args.interval = setInterval(
                    function() {
                        args.opacity += args.stepOpacity;
                        args.top += args.stepTop;
                        args.bottom += args.stepBottom;

                        var opacityReached = (args.stepOpacity > 0 && args.opacity >= args.targetOpacity)
                            || (args.stepOpacity < 0 && args.opacity <= args.targetOpacity);
                        var topReached = (args.stepTop > 0 && args.top >= args.targetTop)
                            || (args.stepTop < 0 && args.top <= args.targetTop);
                        var bottomReached = (args.stepBottom > 0 && args.bottom >= args.targetBottom)
                            || (args.stepBottom < 0 && args.bottom <= args.targetBottom);
                            
                        if(opacityReached || topReached || bottomReached) {
                            clearInterval(args.interval);
                            args.opacity = args.targetOpacity;
                            args.top = args.targetTop;
                            args.bottom = args.targetBottom;
                            args.element.__fade_interval = null;
                            args.element.__fade_args = null;
                            if(typeof(args.callback) == "function")
                                args.callback();
                        }
        
                        args.element.style.opacity = args.opacity / 100;
                        args.element.style.filter = "Alpha(Opacity="+Math.round(args.opacity) + ")";
                        if(args.stepTop != 0 || args.stepBottom != 0) setPos(args.element, args.top, args.height - args.bottom - args.top);
                        args.element.setAttribute('__fade_opacity', args.opacity);
                        args.element.setAttribute('__fade_top', args.top);
                        args.element.setAttribute('__fade_bottom', args.bottom);
                    },
                    args.tick
                );
            },
            args.delay
        );
    }
    
    function prepare_distance_matrix()
    {
        for(var i = 0; i <= 6; i++) {
            matrix[i] = [];
            for(var x = -3; x <= 3; x++) {
            for(var y = -3; y <= 3; y++) {
                if(Math.abs(x) + Math.abs(y) == i) {
                    matrix[i][matrix[i].length] = {x: x, y: y};
                }
            }
            }
        }
    }
    
    function menu_over(e)
    {
        menu_is_over = true;
        
        var colrow = e.className.match(/col([0-9]+).*row([0-9]+)/);
        var col = colrow[1] - 1, row = colrow[2] - 1;

        var box_node, box_nodes_row;
        var max_dist = 6;
        if(row == 1 || row == 2) max_dist--;
        if(col == 1 || col == 2) max_dist--;
        
        for(var i = 0; i <= max_dist; i++) {
            for(var k = 0; k < matrix[i].length; k++) {
                box_nodes_row = box_nodes[row + matrix[i][k].y];
                if(box_nodes_row && (box_node = box_nodes_row[col + matrix[i][k].x])) {
                    fade({
                        element: box_node,
                        targetOpacity: (box_node == e ? 100 : 20),
                        targetTop: 0,
                        targetBottom: 0,
                        stepOpacity: -5,
                        delay: (box_node == e ? 1 : (max_dist - i) * 100)
                    });
                }
            }
        }
    }
    function menu_out(e)
    {
        var colrow = e.className.match(/col([0-9]+).*row([0-9]+)/);
        var col = colrow[1] - 1, row = colrow[2] - 1;

        var box_node, box_nodes_row;
        var max_dist = 6;
        if(row == 1 || row == 2) max_dist--;
        if(col == 1 || col == 2) max_dist--;
        
        for(var i = 0; i <= max_dist; i++) {
            for(var k = 0; k < matrix[i].length; k++) {
                box_nodes_row = box_nodes[row + matrix[i][k].y];
                if(box_nodes_row && (box_node = box_nodes_row[col + matrix[i][k].x]) && box_node != e) {
                    fade({
                        element: box_node,
                        targetOpacity: 100,
                        targetTop: 0,
                        targetBottom: 0,
                        stepOpacity: 2,
                        delay: (i - 1) * 100,
                        callback: function() { menu_is_over = false;}
                    });
                }
            }
        }
    }
    
    function swap_icons_helper(a, b)
    {
        var ela = box_nodes[a.y][a.x], elb = box_nodes[b.y][b.x];
        
        ela.className = ela.className.replace(/col[0-9]+ row[0-9]+/, "col" + (b.x + 1) + " row" + (b.y + 1));
        if(ela.tagName == "LI") {
            ela.underlyingDiv.className = ela.underlyingDiv.className.replace(/col[0-9]+ row[0-9]+/, "col" + (b.x + 1) + " row" + (b.y + 1));
            ela.underlyingDiv.setAttribute('oldTop', b.y * 85);
            ela.underlyingDiv.style.top = "auto";
        }

        elb.className = elb.className.replace(/col[0-9]+ row[0-9]+/, "col" + (a.x + 1) + " row" + (a.y + 1));
        if(elb.tagName == "LI") {
            elb.underlyingDiv.className = elb.underlyingDiv.className.replace(/col[0-9]+ row[0-9]+/, "col" + (a.x + 1) + " row" + (a.y + 1));
            elb.underlyingDiv.setAttribute('oldTop', a.y * 85);
            elb.underlyingDiv.style.top = "auto";
        }
        
        ela.setAttribute('oldTop', b.y * 85);
        elb.setAttribute('oldTop', a.y * 85);
        ela.style.top = "auto";
        elb.style.top = "auto";

        box_nodes[a.y][a.x] = elb;
        box_nodes[b.y][b.x] = ela;
    }
    
    var uu = 0;
    function swap_icons()
    {
        if(typeof(menu_is_over) != "undefined" && menu_is_over) return;
    
        var a = {x: my_rand(0, 3), y: my_rand(0, 3)}, b;
        do {
            b = {x: my_rand(0, 3), y: my_rand(0, 3)};
        } while(a.x == b.x && a.y == b.y);
        
        var ela = box_nodes[a.y][a.x], elb = box_nodes[b.y][b.x];
        
        var effects = [
            {ax: 36, ay: 36, bx: 36, by: 36}, 
            {ax: 72, ay:  0, bx: 72, by:  0}, 
            {ax:  0, ay: 72, bx:  0, by: 72}, 
            {ax: 72, ay:  0, bx:  0, by: 72}, 
        ];
        var effect = effects[my_rand(0, 3)];
        
        fade({element: ela, targetTop: 1, targetBottom: 1, targetOpacity: 0, steps: 30, tick: 40});
        fade({element: elb, targetTop: 1, targetBottom: 1, targetOpacity: 0, steps: 30, tick: 40, callback:
            function() {
                swap_icons_helper(a, b);
                fade({element: ela, targetTop: 0, targetBottom: 0, targetOpacity: 100, steps: 30, delay: 20, tick: 40});
                fade({element: elb, targetTop: 0, targetBottom: 0, targetOpacity: 100, steps: 30, delay: 20, tick: 40});
            }
        });
    }

    function my_rand(min, max)
    {
        return min + (Math.floor(Math.random() * 100000) % (max - min + 1));
    }
    
    
