{"id":4650,"date":"2026-02-05T13:14:25","date_gmt":"2026-02-05T13:14:25","guid":{"rendered":"https:\/\/new.merlinedv.de\/?page_id=4650"},"modified":"2026-03-05T15:14:49","modified_gmt":"2026-03-05T15:14:49","slug":"pacman","status":"publish","type":"page","link":"https:\/\/new.merlinedv.de\/en\/pacman\/","title":{"rendered":"Pacman"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-page\" data-elementor-id=\"4650\" class=\"elementor elementor-4650\" data-elementor-settings=\"{&quot;scroll_snap&quot;:&quot;yes&quot;}\" data-elementor-post-type=\"page\">\n\t\t\t\t<div data-particle_enable=\"false\" data-particle-mobile-disabled=\"false\" class=\"elementor-element elementor-element-3809321 e-flex e-con-boxed e-con e-parent\" data-id=\"3809321\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-ad253cc elementor-widget elementor-widget-html\" data-id=\"ad253cc\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<body>\n<div id=\"shim\">shim for font face<\/div>\n\n<h1> PACMAN<h1>\n\n<p><a href=\"daniel estera\" target=\"_blank\">waiting for the staff in retro-stylee<\/a><\/p>\n\n<div id=\"pacman\"><\/div>\n<\/body>\n\n<script src=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/modernizr\/2.8.3\/modernizr.min.js\"><\/script>\n\n<script src=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/jquery\/2.1.3\/jquery.min.js\"><\/script>\n\n<style>\n    body {\n  background-color: black;\n}\n\n#pacman {\n  height: 470px;\n  width: 382px;\n  border-radius: 5px;\n  margin: 20px auto;\n}\n\n#shim {\n  font-family: 'Permanent Marker', cursive;\n  position: absolute;\n  visibility: hidden\n}\n\nh1 {\n  font-family: 'Permanent Marker', cursive;\n  text-align: center;\n  color: yellow;\n}\n\nbody {\n  width: 100%;\n  height: 100vh;\n  margin: 0px auto;\n  font-family: sans-serif;\n}\n\na {\n  text-decoration: none;\n  color: #0000FF;\n}\n<\/style>\n\n<script>\n    \/*jslint browser: true, undef: true, eqeqeq: true, nomen: true, white: true *\/\n\/*global window: false, document: false *\/\n\n\/*\n * fix looped audio\n * add fruits + levels\n * fix what happens when a ghost is eaten (should go back to base)\n * do proper ghost mechanics (blinky\/wimpy etc)\n *\/\n\nvar NONE        = 4,\n    UP          = 3,\n    LEFT        = 2,\n    DOWN        = 1,\n    RIGHT       = 11,\n    WAITING     = 5,\n    PAUSE       = 6,\n    PLAYING     = 7,\n    COUNTDOWN   = 8,\n    EATEN_PAUSE = 9,\n    DYING       = 10,\n    Pacman      = {};\n\nPacman.FPS = 30;\n\nPacman.Ghost = function (game, map, colour) {\n\n    var position  = null,\n        direction = null,\n        eatable   = null,\n        eaten     = null,\n        due       = null;\n    \n    function getNewCoord(dir, current) { \n        \n        var speed  = isVunerable() ? 1 : isHidden() ? 4 : 2,\n            xSpeed = (dir === LEFT && -speed || dir === RIGHT && speed || 0),\n            ySpeed = (dir === DOWN && speed || dir === UP && -speed || 0);\n    \n        return {\n            \"x\": addBounded(current.x, xSpeed),\n            \"y\": addBounded(current.y, ySpeed)\n        };\n    };\n\n    \/* Collision detection(walls) is done when a ghost lands on an\n     * exact block, make sure they dont skip over it \n     *\/\n    function addBounded(x1, x2) { \n        var rem    = x1 % 10, \n            result = rem + x2;\n        if (rem !== 0 && result > 10) {\n            return x1 + (10 - rem);\n        } else if(rem > 0 && result < 0) { \n            return x1 - rem;\n        }\n        return x1 + x2;\n    };\n    \n    function isVunerable() { \n        return eatable !== null;\n    };\n    \n    function isDangerous() {\n        return eaten === null;\n    };\n\n    function isHidden() { \n        return eatable === null && eaten !== null;\n    };\n    \n    function getRandomDirection() {\n        var moves = (direction === LEFT || direction === RIGHT) \n            ? [UP, DOWN] : [LEFT, RIGHT];\n        return moves[Math.floor(Math.random() * 2)];\n    };\n    \n    function reset() {\n        eaten = null;\n        eatable = null;\n        position = {\"x\": 90, \"y\": 80};\n        direction = getRandomDirection();\n        due = getRandomDirection();\n    };\n    \n    function onWholeSquare(x) {\n        return x % 10 === 0;\n    };\n    \n    function oppositeDirection(dir) { \n        return dir === LEFT && RIGHT ||\n            dir === RIGHT && LEFT ||\n            dir === UP && DOWN || UP;\n    };\n\n    function makeEatable() {\n        direction = oppositeDirection(direction);\n        eatable = game.getTick();\n    };\n\n    function eat() { \n        eatable = null;\n        eaten = game.getTick();\n    };\n\n    function pointToCoord(x) {\n        return Math.round(x \/ 10);\n    };\n\n    function nextSquare(x, dir) {\n        var rem = x % 10;\n        if (rem === 0) { \n            return x; \n        } else if (dir === RIGHT || dir === DOWN) { \n            return x + (10 - rem);\n        } else {\n            return x - rem;\n        }\n    };\n\n    function onGridSquare(pos) {\n        return onWholeSquare(pos.y) && onWholeSquare(pos.x);\n    };\n\n    function secondsAgo(tick) { \n        return (game.getTick() - tick) \/ Pacman.FPS;\n    };\n\n    function getColour() { \n        if (eatable) { \n            if (secondsAgo(eatable) > 5) { \n                return game.getTick() % 20 > 10 ? \"#FFFFFF\" : \"#0000BB\";\n            } else { \n                return \"#0000BB\";\n            }\n        } else if(eaten) { \n            return \"#222\";\n        } \n        return colour;\n    };\n\n    function draw(ctx) {\n  \n        var s    = map.blockSize, \n            top  = (position.y\/10) * s,\n            left = (position.x\/10) * s;\n    \n        if (eatable && secondsAgo(eatable) > 8) {\n            eatable = null;\n        }\n        \n        if (eaten && secondsAgo(eaten) > 3) { \n            eaten = null;\n        }\n        \n        var tl = left + s;\n        var base = top + s - 3;\n        var inc = s \/ 10;\n\n        var high = game.getTick() % 10 > 5 ? 3  : -3;\n        var low  = game.getTick() % 10 > 5 ? -3 : 3;\n\n        ctx.fillStyle = getColour();\n        ctx.beginPath();\n\n        ctx.moveTo(left, base);\n\n        ctx.quadraticCurveTo(left, top, left + (s\/2),  top);\n        ctx.quadraticCurveTo(left + s, top, left+s,  base);\n        \n        \/\/ Wavy things at the bottom\n        ctx.quadraticCurveTo(tl-(inc*1), base+high, tl - (inc * 2),  base);\n        ctx.quadraticCurveTo(tl-(inc*3), base+low, tl - (inc * 4),  base);\n        ctx.quadraticCurveTo(tl-(inc*5), base+high, tl - (inc * 6),  base);\n        ctx.quadraticCurveTo(tl-(inc*7), base+low, tl - (inc * 8),  base); \n        ctx.quadraticCurveTo(tl-(inc*9), base+high, tl - (inc * 10), base); \n\n        ctx.closePath();\n        ctx.fill();\n\n        ctx.beginPath();\n        ctx.fillStyle = \"#FFF\";\n        ctx.arc(left + 6,top + 6, s \/ 6, 0, 300, false);\n        ctx.arc((left + s) - 6,top + 6, s \/ 6, 0, 300, false);\n        ctx.closePath();\n        ctx.fill();\n\n        var f = s \/ 12;\n        var off = {};\n        off[RIGHT] = [f, 0];\n        off[LEFT]  = [-f, 0];\n        off[UP]    = [0, -f];\n        off[DOWN]  = [0, f];\n\n        ctx.beginPath();\n        ctx.fillStyle = \"#000\";\n        ctx.arc(left+6+off[direction][0], top+6+off[direction][1], \n                s \/ 15, 0, 300, false);\n        ctx.arc((left+s)-6+off[direction][0], top+6+off[direction][1], \n                s \/ 15, 0, 300, false);\n        ctx.closePath();\n        ctx.fill();\n\n    };\n\n    function pane(pos) {\n\n        if (pos.y === 100 && pos.x >= 190 && direction === RIGHT) {\n            return {\"y\": 100, \"x\": -10};\n        }\n        \n        if (pos.y === 100 && pos.x <= -10 && direction === LEFT) {\n            return position = {\"y\": 100, \"x\": 190};\n        }\n\n        return false;\n    };\n    \n    function move(ctx) {\n        \n        var oldPos = position,\n            onGrid = onGridSquare(position),\n            npos   = null;\n        \n        if (due !== direction) {\n            \n            npos = getNewCoord(due, position);\n            \n            if (onGrid &&\n                map.isFloorSpace({\n                    \"y\":pointToCoord(nextSquare(npos.y, due)),\n                    \"x\":pointToCoord(nextSquare(npos.x, due))})) {\n                direction = due;\n            } else {\n                npos = null;\n            }\n        }\n        \n        if (npos === null) {\n            npos = getNewCoord(direction, position);\n        }\n        \n        if (onGrid &&\n            map.isWallSpace({\n                \"y\" : pointToCoord(nextSquare(npos.y, direction)),\n                \"x\" : pointToCoord(nextSquare(npos.x, direction))\n            })) {\n            \n            due = getRandomDirection();            \n            return move(ctx);\n        }\n\n        position = npos;        \n        \n        var tmp = pane(position);\n        if (tmp) { \n            position = tmp;\n        }\n        \n        due = getRandomDirection();\n        \n        return {\n            \"new\" : position,\n            \"old\" : oldPos\n        };\n    };\n    \n    return {\n        \"eat\"         : eat,\n        \"isVunerable\" : isVunerable,\n        \"isDangerous\" : isDangerous,\n        \"makeEatable\" : makeEatable,\n        \"reset\"       : reset,\n        \"move\"        : move,\n        \"draw\"        : draw\n    };\n};\n\nPacman.User = function (game, map) {\n    \n    var position  = null,\n        direction = null,\n        eaten     = null,\n        due       = null, \n        lives     = null,\n        score     = 5,\n        keyMap    = {};\n    \n    keyMap[KEY.ARROW_LEFT]  = LEFT;\n    keyMap[KEY.ARROW_UP]    = UP;\n    keyMap[KEY.ARROW_RIGHT] = RIGHT;\n    keyMap[KEY.ARROW_DOWN]  = DOWN;\n\n    function addScore(nScore) { \n        score += nScore;\n        if (score >= 10000 && score - nScore < 10000) { \n            lives += 1;\n        }\n    };\n\n    function theScore() { \n        return score;\n    };\n\n    function loseLife() { \n        lives -= 1;\n    };\n\n    function getLives() {\n        return lives;\n    };\n\n    function initUser() {\n        score = 0;\n        lives = 3;\n        newLevel();\n    }\n    \n    function newLevel() {\n        resetPosition();\n        eaten = 0;\n    };\n    \n    function resetPosition() {\n        position = {\"x\": 90, \"y\": 120};\n        direction = LEFT;\n        due = LEFT;\n    };\n    \n    function reset() {\n        initUser();\n        resetPosition();\n    };        \n    \n    function keyDown(e) {\n        if (typeof keyMap[e.keyCode] !== \"undefined\") { \n            due = keyMap[e.keyCode];\n            e.preventDefault();\n            e.stopPropagation();\n            return false;\n        }\n        return true;\n\t};\n\n    function getNewCoord(dir, current) {   \n        return {\n            \"x\": current.x + (dir === LEFT && -2 || dir === RIGHT && 2 || 0),\n            \"y\": current.y + (dir === DOWN && 2 || dir === UP    && -2 || 0)\n        };\n    };\n\n    function onWholeSquare(x) {\n        return x % 10 === 0;\n    };\n\n    function pointToCoord(x) {\n        return Math.round(x\/10);\n    };\n    \n    function nextSquare(x, dir) {\n        var rem = x % 10;\n        if (rem === 0) { \n            return x; \n        } else if (dir === RIGHT || dir === DOWN) { \n            return x + (10 - rem);\n        } else {\n            return x - rem;\n        }\n    };\n\n    function next(pos, dir) {\n        return {\n            \"y\" : pointToCoord(nextSquare(pos.y, dir)),\n            \"x\" : pointToCoord(nextSquare(pos.x, dir)),\n        };                               \n    };\n\n    function onGridSquare(pos) {\n        return onWholeSquare(pos.y) && onWholeSquare(pos.x);\n    };\n\n    function isOnSamePlane(due, dir) { \n        return ((due === LEFT || due === RIGHT) && \n                (dir === LEFT || dir === RIGHT)) || \n            ((due === UP || due === DOWN) && \n             (dir === UP || dir === DOWN));\n    };\n\n    function move(ctx) {\n        \n        var npos        = null, \n            nextWhole   = null, \n            oldPosition = position,\n            block       = null;\n        \n        if (due !== direction) {\n            npos = getNewCoord(due, position);\n            \n            if (isOnSamePlane(due, direction) || \n                (onGridSquare(position) && \n                 map.isFloorSpace(next(npos, due)))) {\n                direction = due;\n            } else {\n                npos = null;\n            }\n        }\n\n        if (npos === null) {\n            npos = getNewCoord(direction, position);\n        }\n        \n        if (onGridSquare(position) && map.isWallSpace(next(npos, direction))) {\n            direction = NONE;\n        }\n\n        if (direction === NONE) {\n            return {\"new\" : position, \"old\" : position};\n        }\n        \n        if (npos.y === 100 && npos.x >= 190 && direction === RIGHT) {\n            npos = {\"y\": 100, \"x\": -10};\n        }\n        \n        if (npos.y === 100 && npos.x <= -12 && direction === LEFT) {\n            npos = {\"y\": 100, \"x\": 190};\n        }\n        \n        position = npos;        \n        nextWhole = next(position, direction);\n        \n        block = map.block(nextWhole);        \n        \n        if ((isMidSquare(position.y) || isMidSquare(position.x)) &&\n            block === Pacman.BISCUIT || block === Pacman.PILL) {\n            \n            map.setBlock(nextWhole, Pacman.EMPTY);           \n            addScore((block === Pacman.BISCUIT) ? 10 : 50);\n            eaten += 1;\n            \n            if (eaten === 182) {\n                game.completedLevel();\n            }\n            \n            if (block === Pacman.PILL) { \n                game.eatenPill();\n            }\n        }   \n                \n        return {\n            \"new\" : position,\n            \"old\" : oldPosition\n        };\n    };\n\n    function isMidSquare(x) { \n        var rem = x % 10;\n        return rem > 3 || rem < 7;\n    };\n\n    function calcAngle(dir, pos) { \n        if (dir == RIGHT && (pos.x % 10 < 5)) {\n            return {\"start\":0.25, \"end\":1.75, \"direction\": false};\n        } else if (dir === DOWN && (pos.y % 10 < 5)) { \n            return {\"start\":0.75, \"end\":2.25, \"direction\": false};\n        } else if (dir === UP && (pos.y % 10 < 5)) { \n            return {\"start\":1.25, \"end\":1.75, \"direction\": true};\n        } else if (dir === LEFT && (pos.x % 10 < 5)) {             \n            return {\"start\":0.75, \"end\":1.25, \"direction\": true};\n        }\n        return {\"start\":0, \"end\":2, \"direction\": false};\n    };\n\n    function drawDead(ctx, amount) { \n\n        var size = map.blockSize, \n            half = size \/ 2;\n\n        if (amount >= 1) { \n            return;\n        }\n\n        ctx.fillStyle = \"#FFFF00\";\n        ctx.beginPath();        \n        ctx.moveTo(((position.x\/10) * size) + half, \n                   ((position.y\/10) * size) + half);\n        \n        ctx.arc(((position.x\/10) * size) + half, \n                ((position.y\/10) * size) + half,\n                half, 0, Math.PI * 2 * amount, true); \n        \n        ctx.fill();    \n    };\n\n    function draw(ctx) { \n\n        var s     = map.blockSize, \n            angle = calcAngle(direction, position);\n\n        ctx.fillStyle = \"#FFFF00\";\n\n        ctx.beginPath();        \n\n        ctx.moveTo(((position.x\/10) * s) + s \/ 2,\n                   ((position.y\/10) * s) + s \/ 2);\n        \n        ctx.arc(((position.x\/10) * s) + s \/ 2,\n                ((position.y\/10) * s) + s \/ 2,\n                s \/ 2, Math.PI * angle.start, \n                Math.PI * angle.end, angle.direction); \n        \n        ctx.fill();    \n    };\n    \n    initUser();\n\n    return {\n        \"draw\"          : draw,\n        \"drawDead\"      : drawDead,\n        \"loseLife\"      : loseLife,\n        \"getLives\"      : getLives,\n        \"score\"         : score,\n        \"addScore\"      : addScore,\n        \"theScore\"      : theScore,\n        \"keyDown\"       : keyDown,\n        \"move\"          : move,\n        \"newLevel\"      : newLevel,\n        \"reset\"         : reset,\n        \"resetPosition\" : resetPosition\n    };\n};\n\nPacman.Map = function (size) {\n    \n    var height    = null, \n        width     = null, \n        blockSize = size,\n        pillSize  = 0,\n        map       = null;\n    \n    function withinBounds(y, x) {\n        return y >= 0 && y < height && x >= 0 && x < width;\n    }\n    \n    function isWall(pos) {\n        return withinBounds(pos.y, pos.x) && map[pos.y][pos.x] === Pacman.WALL;\n    }\n    \n    function isFloorSpace(pos) {\n        if (!withinBounds(pos.y, pos.x)) {\n            return false;\n        }\n        var peice = map[pos.y][pos.x];\n        return peice === Pacman.EMPTY || \n            peice === Pacman.BISCUIT ||\n            peice === Pacman.PILL;\n    }\n    \n    function drawWall(ctx) {\n\n        var i, j, p, line;\n        \n        ctx.strokeStyle = \"#0000FF\";\n        ctx.lineWidth   = 5;\n        ctx.lineCap     = \"round\";\n        \n        for (i = 0; i < Pacman.WALLS.length; i += 1) {\n            line = Pacman.WALLS[i];\n            ctx.beginPath();\n\n            for (j = 0; j < line.length; j += 1) {\n\n                p = line[j];\n                \n                if (p.move) {\n                    ctx.moveTo(p.move[0] * blockSize, p.move[1] * blockSize);\n                } else if (p.line) {\n                    ctx.lineTo(p.line[0] * blockSize, p.line[1] * blockSize);\n                } else if (p.curve) {\n                    ctx.quadraticCurveTo(p.curve[0] * blockSize, \n                                         p.curve[1] * blockSize,\n                                         p.curve[2] * blockSize, \n                                         p.curve[3] * blockSize);   \n                }\n            }\n            ctx.stroke();\n        }\n    }\n    \n    function reset() {       \n        map    = Pacman.MAP.clone();\n        height = map.length;\n        width  = map[0].length;        \n    };\n\n    function block(pos) {\n        return map[pos.y][pos.x];\n    };\n    \n    function setBlock(pos, type) {\n        map[pos.y][pos.x] = type;\n    };\n\n    function drawPills(ctx) { \n\n        if (++pillSize > 30) {\n            pillSize = 0;\n        }\n        \n        for (i = 0; i < height; i += 1) {\n\t\t    for (j = 0; j < width; j += 1) {\n                if (map[i][j] === Pacman.PILL) {\n                    ctx.beginPath();\n\n                    ctx.fillStyle = \"#000\";\n\t\t            ctx.fillRect((j * blockSize), (i * blockSize), \n                                 blockSize, blockSize);\n\n                    ctx.fillStyle = \"#FFF\";\n                    ctx.arc((j * blockSize) + blockSize \/ 2,\n                            (i * blockSize) + blockSize \/ 2,\n                            Math.abs(5 - (pillSize\/3)), \n                            0, \n                            Math.PI * 2, false); \n                    ctx.fill();\n                    ctx.closePath();\n                }\n\t\t    }\n\t    }\n    };\n    \n    function draw(ctx) {\n        \n        var i, j, size = blockSize;\n\n        ctx.fillStyle = \"#000\";\n\t    ctx.fillRect(0, 0, width * size, height * size);\n\n        drawWall(ctx);\n        \n        for (i = 0; i < height; i += 1) {\n\t\t    for (j = 0; j < width; j += 1) {\n\t\t\t    drawBlock(i, j, ctx);\n\t\t    }\n\t    }\n    };\n    \n    function drawBlock(y, x, ctx) {\n\n        var layout = map[y][x];\n\n        if (layout === Pacman.PILL) {\n            return;\n        }\n\n        ctx.beginPath();\n        \n        if (layout === Pacman.EMPTY || layout === Pacman.BLOCK || \n            layout === Pacman.BISCUIT) {\n            \n            ctx.fillStyle = \"#000\";\n\t\t    ctx.fillRect((x * blockSize), (y * blockSize), \n                         blockSize, blockSize);\n\n            if (layout === Pacman.BISCUIT) {\n                ctx.fillStyle = \"#FFF\";\n\t\t        ctx.fillRect((x * blockSize) + (blockSize \/ 2.5), \n                             (y * blockSize) + (blockSize \/ 2.5), \n                             blockSize \/ 6, blockSize \/ 6);\n\t        }\n        }\n        ctx.closePath();\t \n    };\n\n    reset();\n    \n    return {\n        \"draw\"         : draw,\n        \"drawBlock\"    : drawBlock,\n        \"drawPills\"    : drawPills,\n        \"block\"        : block,\n        \"setBlock\"     : setBlock,\n        \"reset\"        : reset,\n        \"isWallSpace\"  : isWall,\n        \"isFloorSpace\" : isFloorSpace,\n        \"height\"       : height,\n        \"width\"        : width,\n        \"blockSize\"    : blockSize\n    };\n};\n\nPacman.Audio = function(game) {\n    \n    var files          = [], \n        endEvents      = [],\n        progressEvents = [],\n        playing        = [];\n    \n    function load(name, path, cb) { \n\n        var f = files[name] = document.createElement(\"audio\");\n\n        progressEvents[name] = function(event) { progress(event, name, cb); };\n        \n        f.addEventListener(\"canplaythrough\", progressEvents[name], true);\n        f.setAttribute(\"preload\", \"true\");\n        f.setAttribute(\"autobuffer\", \"true\");\n        f.setAttribute(\"src\", path);\n        f.pause();        \n    };\n\n    function progress(event, name, callback) { \n        if (event.loaded === event.total && typeof callback === \"function\") {\n            callback();\n            files[name].removeEventListener(\"canplaythrough\", \n                                            progressEvents[name], true);\n        }\n    };\n\n    function disableSound() {\n        for (var i = 0; i < playing.length; i++) {\n            files[playing[i]].pause();\n            files[playing[i]].currentTime = 0;\n        }\n        playing = [];\n    };\n\n    function ended(name) { \n\n        var i, tmp = [], found = false;\n\n        files[name].removeEventListener(\"ended\", endEvents[name], true);\n\n        for (i = 0; i < playing.length; i++) {\n            if (!found && playing[i]) { \n                found = true;\n            } else { \n                tmp.push(playing[i]);\n            }\n        }\n        playing = tmp;\n    };\n\n    function play(name) { \n        if (!game.soundDisabled()) {\n            endEvents[name] = function() { ended(name); };\n            playing.push(name);\n            files[name].addEventListener(\"ended\", endEvents[name], true);\n            files[name].play();\n        }\n    };\n\n    function pause() { \n        for (var i = 0; i < playing.length; i++) {\n            files[playing[i]].pause();\n        }\n    };\n    \n    function resume() { \n        for (var i = 0; i < playing.length; i++) {\n            files[playing[i]].play();\n        }        \n    };\n    \n    return {\n        \"disableSound\" : disableSound,\n        \"load\"         : load,\n        \"play\"         : play,\n        \"pause\"        : pause,\n        \"resume\"       : resume\n    };\n};\n\nvar PACMAN = (function () {\n\n    var state        = WAITING,\n        audio        = null,\n        ghosts       = [],\n        ghostSpecs   = [\"#00FFDE\", \"#FF0000\", \"#FFB8DE\", \"#FFB847\"],\n        eatenCount   = 0,\n        level        = 0,\n        tick         = 0,\n        ghostPos, userPos, \n        stateChanged = true,\n        timerStart   = null,\n        lastTime     = 0,\n        ctx          = null,\n        timer        = null,\n        map          = null,\n        user         = null,\n        stored       = null;\n\n    function getTick() { \n        return tick;\n    };\n\n    function drawScore(text, position) {\n        ctx.fillStyle = \"#FFFFFF\";\n        ctx.font      = \"12px BDCartoonShoutRegular\";\n        ctx.fillText(text, \n                     (position[\"new\"][\"x\"] \/ 10) * map.blockSize, \n                     ((position[\"new\"][\"y\"] + 5) \/ 10) * map.blockSize);\n    }\n    \n    function dialog(text) {\n        ctx.fillStyle = \"#FFFF00\";\n        ctx.font      = \"18px Calibri\";\n        var width = ctx.measureText(text).width,\n            x     = ((map.width * map.blockSize) - width) \/ 2;        \n        ctx.fillText(text, x, (map.height * 10) + 8);\n    }\n\n    function soundDisabled() {\n        return localStorage[\"soundDisabled\"] === \"true\";\n    };\n    \n    function startLevel() {        \n        user.resetPosition();\n        for (var i = 0; i < ghosts.length; i += 1) { \n            ghosts[i].reset();\n        }\n        audio.play(\"start\");\n        timerStart = tick;\n        setState(COUNTDOWN);\n    }    \n\n    function startNewGame() {\n        setState(WAITING);\n        level = 1;\n        user.reset();\n        map.reset();\n        map.draw(ctx);\n        startLevel();\n    }\n\n    function keyDown(e) {\n        if (e.keyCode === KEY.N) {\n            startNewGame();\n        } else if (e.keyCode === KEY.S) {\n            audio.disableSound();\n            localStorage[\"soundDisabled\"] = !soundDisabled();\n        } else if (e.keyCode === KEY.P && state === PAUSE) {\n            audio.resume();\n            map.draw(ctx);\n            setState(stored);\n        } else if (e.keyCode === KEY.P) {\n            stored = state;\n            setState(PAUSE);\n            audio.pause();\n            map.draw(ctx);\n            dialog(\"Paused\");\n        } else if (state !== PAUSE) {   \n            return user.keyDown(e);\n        }\n        return true;\n    }    \n\n    function loseLife() {        \n        setState(WAITING);\n        user.loseLife();\n        if (user.getLives() > 0) {\n            startLevel();\n        }\n    }\n\n    function setState(nState) { \n        state = nState;\n        stateChanged = true;\n    };\n    \n    function collided(user, ghost) {\n        return (Math.sqrt(Math.pow(ghost.x - user.x, 2) + \n                          Math.pow(ghost.y - user.y, 2))) < 10;\n    };\n\n    function drawFooter() {\n        \n        var topLeft  = (map.height * map.blockSize),\n            textBase = topLeft + 17;\n        \n        ctx.fillStyle = \"#000000\";\n        ctx.fillRect(0, topLeft, (map.width * map.blockSize), 30);\n        \n        ctx.fillStyle = \"#FFFF00\";\n\n        for (var i = 0, len = user.getLives(); i < len; i++) {\n            ctx.fillStyle = \"#FFFF00\";\n            ctx.beginPath();\n            ctx.moveTo(150 + (25 * i) + map.blockSize \/ 2,\n                       (topLeft+1) + map.blockSize \/ 2);\n            \n            ctx.arc(150 + (25 * i) + map.blockSize \/ 2,\n                    (topLeft+1) + map.blockSize \/ 2,\n                    map.blockSize \/ 2, Math.PI * 0.25, Math.PI * 1.75, false);\n            ctx.fill();\n        }\n\n        ctx.fillStyle = !soundDisabled() ? \"#00FF00\" : \"#FF0000\";\n        ctx.font = \"bold 16px sans-serif\";\n        \/\/ctx.fillText(\"\u266a\", 10, textBase);\n        ctx.fillText(\"s\", 10, textBase);\n\n        ctx.fillStyle = \"#FFFF00\";\n        ctx.font      = \"14px Calibri\";\n        ctx.fillText(\"Score: \" + user.theScore(), 30, textBase);\n        ctx.fillText(\"Level: \" + level, 260, textBase);\n    }\n\n    function redrawBlock(pos) {\n        map.drawBlock(Math.floor(pos.y\/10), Math.floor(pos.x\/10), ctx);\n        map.drawBlock(Math.ceil(pos.y\/10), Math.ceil(pos.x\/10), ctx);\n    }\n\n    function mainDraw() { \n\n        var diff, u, i, len, nScore;\n        \n        ghostPos = [];\n\n        for (i = 0, len = ghosts.length; i < len; i += 1) {\n            ghostPos.push(ghosts[i].move(ctx));\n        }\n        u = user.move(ctx);\n        \n        for (i = 0, len = ghosts.length; i < len; i += 1) {\n            redrawBlock(ghostPos[i].old);\n        }\n        redrawBlock(u.old);\n        \n        for (i = 0, len = ghosts.length; i < len; i += 1) {\n            ghosts[i].draw(ctx);\n        }                     \n        user.draw(ctx);\n        \n        userPos = u[\"new\"];\n        \n        for (i = 0, len = ghosts.length; i < len; i += 1) {\n            if (collided(userPos, ghostPos[i][\"new\"])) {\n                if (ghosts[i].isVunerable()) { \n                    audio.play(\"eatghost\");\n                    ghosts[i].eat();\n                    eatenCount += 1;\n                    nScore = eatenCount * 50;\n                    drawScore(nScore, ghostPos[i]);\n                    user.addScore(nScore);                    \n                    setState(EATEN_PAUSE);\n                    timerStart = tick;\n                } else if (ghosts[i].isDangerous()) {\n                    audio.play(\"die\");\n                    setState(DYING);\n                    timerStart = tick;\n                }\n            }\n        }                             \n    };\n\n    function mainLoop() {\n\n        var diff;\n\n        if (state !== PAUSE) { \n            ++tick;\n        }\n\n        map.drawPills(ctx);\n\n        if (state === PLAYING) {\n            mainDraw();\n        } else if (state === WAITING && stateChanged) {            \n            stateChanged = false;\n            map.draw(ctx);\n            dialog(\"Press N to start a New game\");            \n        } else if (state === EATEN_PAUSE && \n                   (tick - timerStart) > (Pacman.FPS \/ 3)) {\n            map.draw(ctx);\n            setState(PLAYING);\n        } else if (state === DYING) {\n            if (tick - timerStart > (Pacman.FPS * 2)) { \n                loseLife();\n            } else { \n                redrawBlock(userPos);\n                for (i = 0, len = ghosts.length; i < len; i += 1) {\n                    redrawBlock(ghostPos[i].old);\n                    ghostPos.push(ghosts[i].draw(ctx));\n                }                                   \n                user.drawDead(ctx, (tick - timerStart) \/ (Pacman.FPS * 2));\n            }\n        } else if (state === COUNTDOWN) {\n            \n            diff = 5 + Math.floor((timerStart - tick) \/ Pacman.FPS);\n            \n            if (diff === 0) {\n                map.draw(ctx);\n                setState(PLAYING);\n            } else {\n                if (diff !== lastTime) { \n                    lastTime = diff;\n                    map.draw(ctx);\n                    dialog(\"Starting in: \" + diff);\n                }\n            }\n        } \n\n        drawFooter();\n    }\n\n    function eatenPill() {\n        audio.play(\"eatpill\");\n        timerStart = tick;\n        eatenCount = 0;\n        for (i = 0; i < ghosts.length; i += 1) {\n            ghosts[i].makeEatable(ctx);\n        }        \n    };\n    \n    function completedLevel() {\n        setState(WAITING);\n        level += 1;\n        map.reset();\n        user.newLevel();\n        startLevel();\n    };\n\n    function keyPress(e) { \n        if (state !== WAITING && state !== PAUSE) { \n            e.preventDefault();\n            e.stopPropagation();\n        }\n    };\n    \n    function init(wrapper, root) {\n        \n        var i, len, ghost,\n            blockSize = wrapper.offsetWidth \/ 19,\n            canvas    = document.createElement(\"canvas\");\n        \n        canvas.setAttribute(\"width\", (blockSize * 19) + \"px\");\n        canvas.setAttribute(\"height\", (blockSize * 22) + 30 + \"px\");\n\n        wrapper.appendChild(canvas);\n\n        ctx  = canvas.getContext('2d');\n\n        audio = new Pacman.Audio({\"soundDisabled\":soundDisabled});\n        map   = new Pacman.Map(blockSize);\n        user  = new Pacman.User({ \n            \"completedLevel\" : completedLevel, \n            \"eatenPill\"      : eatenPill \n        }, map);\n\n        for (i = 0, len = ghostSpecs.length; i < len; i += 1) {\n            ghost = new Pacman.Ghost({\"getTick\":getTick}, map, ghostSpecs[i]);\n            ghosts.push(ghost);\n        }\n        \n        map.draw(ctx);\n        dialog(\"Loading ...\");\n\n        var extension = Modernizr.audio.ogg ? 'ogg' : 'mp3';\n\n        var audio_files = [\n            [\"start\", root + \"audio\/opening_song.\" + extension],\n            [\"die\", root + \"audio\/die.\" + extension],\n            [\"eatghost\", root + \"audio\/eatghost.\" + extension],\n            [\"eatpill\", root + \"audio\/eatpill.\" + extension],\n            [\"eating\", root + \"audio\/eating.short.\" + extension],\n            [\"eating2\", root + \"audio\/eating.short.\" + extension]\n        ];\n\n        load(audio_files, function() { loaded(); });\n    };\n\n    function load(arr, callback) { \n        \n        if (arr.length === 0) { \n            callback();\n        } else { \n            var x = arr.pop();\n            audio.load(x[0], x[1], function() { load(arr, callback); });\n        }\n    };\n        \n    function loaded() {\n\n        dialog(\"Press N to Start\");\n        \n        document.addEventListener(\"keydown\", keyDown, true);\n        document.addEventListener(\"keypress\", keyPress, true); \n        \n        timer = window.setInterval(mainLoop, 1000 \/ Pacman.FPS);\n    };\n    \n    return {\n        \"init\" : init\n    };\n    \n}());\n\n\/* Human readable keyCode index *\/\nvar KEY = {'BACKSPACE': 8, 'TAB': 9, 'NUM_PAD_CLEAR': 12, 'ENTER': 13, 'SHIFT': 16, 'CTRL': 17, 'ALT': 18, 'PAUSE': 19, 'CAPS_LOCK': 20, 'ESCAPE': 27, 'SPACEBAR': 32, 'PAGE_UP': 33, 'PAGE_DOWN': 34, 'END': 35, 'HOME': 36, 'ARROW_LEFT': 37, 'ARROW_UP': 38, 'ARROW_RIGHT': 39, 'ARROW_DOWN': 40, 'PRINT_SCREEN': 44, 'INSERT': 45, 'DELETE': 46, 'SEMICOLON': 59, 'WINDOWS_LEFT': 91, 'WINDOWS_RIGHT': 92, 'SELECT': 93, 'NUM_PAD_ASTERISK': 106, 'NUM_PAD_PLUS_SIGN': 107, 'NUM_PAD_HYPHEN-MINUS': 109, 'NUM_PAD_FULL_STOP': 110, 'NUM_PAD_SOLIDUS': 111, 'NUM_LOCK': 144, 'SCROLL_LOCK': 145, 'SEMICOLON': 186, 'EQUALS_SIGN': 187, 'COMMA': 188, 'HYPHEN-MINUS': 189, 'FULL_STOP': 190, 'SOLIDUS': 191, 'GRAVE_ACCENT': 192, 'LEFT_SQUARE_BRACKET': 219, 'REVERSE_SOLIDUS': 220, 'RIGHT_SQUARE_BRACKET': 221, 'APOSTROPHE': 222};\n\n(function () {\n\t\/* 0 - 9 *\/\n\tfor (var i = 48; i <= 57; i++) {\n        KEY['' + (i - 48)] = i;\n\t}\n\t\/* A - Z *\/\n\tfor (i = 65; i <= 90; i++) {\n        KEY['' + String.fromCharCode(i)] = i;\n\t}\n\t\/* NUM_PAD_0 - NUM_PAD_9 *\/\n\tfor (i = 96; i <= 105; i++) {\n        KEY['NUM_PAD_' + (i - 96)] = i;\n\t}\n\t\/* F1 - F12 *\/\n\tfor (i = 112; i <= 123; i++) {\n        KEY['F' + (i - 112 + 1)] = i;\n\t}\n})();\n\nPacman.WALL    = 0;\nPacman.BISCUIT = 1;\nPacman.EMPTY   = 2;\nPacman.BLOCK   = 3;\nPacman.PILL    = 4;\n\nPacman.MAP = [\n    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],\n\t[0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0],\n\t[0, 4, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 4, 0],\n\t[0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0],\n\t[0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0],\n\t[0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0],\n\t[0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0],\n\t[0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0],\n\t[2, 2, 2, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 2, 2, 2],\n\t[0, 0, 0, 0, 1, 0, 1, 0, 0, 3, 0, 0, 1, 0, 1, 0, 0, 0, 0],\n\t[2, 2, 2, 2, 1, 1, 1, 0, 3, 3, 3, 0, 1, 1, 1, 2, 2, 2, 2],\n\t[0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0],\n\t[2, 2, 2, 0, 1, 0, 1, 1, 1, 2, 1, 1, 1, 0, 1, 0, 2, 2, 2],\n\t[0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0],\n\t[0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0],\n\t[0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0],\n\t[0, 4, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 4, 0],\n\t[0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0],\n\t[0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0],\n\t[0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0],\n\t[0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0],\n\t[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]\n];\n\nPacman.WALLS = [\n    \n    [{\"move\": [0, 9.5]}, {\"line\": [3, 9.5]},\n     {\"curve\": [3.5, 9.5, 3.5, 9]}, {\"line\": [3.5, 8]},\n     {\"curve\": [3.5, 7.5, 3, 7.5]}, {\"line\": [1, 7.5]},\n     {\"curve\": [0.5, 7.5, 0.5, 7]}, {\"line\": [0.5, 1]},\n     {\"curve\": [0.5, 0.5, 1, 0.5]}, {\"line\": [9, 0.5]},\n     {\"curve\": [9.5, 0.5, 9.5, 1]}, {\"line\": [9.5, 3.5]}],\n\n    [{\"move\": [9.5, 1]},\n     {\"curve\": [9.5, 0.5, 10, 0.5]}, {\"line\": [18, 0.5]},\n     {\"curve\": [18.5, 0.5, 18.5, 1]}, {\"line\": [18.5, 7]},\n     {\"curve\": [18.5, 7.5, 18, 7.5]}, {\"line\": [16, 7.5]},\n     {\"curve\": [15.5, 7.5, 15.5, 8]}, {\"line\": [15.5, 9]},\n     {\"curve\": [15.5, 9.5, 16, 9.5]}, {\"line\": [19, 9.5]}],\n\n    [{\"move\": [2.5, 5.5]}, {\"line\": [3.5, 5.5]}],\n\n    [{\"move\": [3, 2.5]},\n     {\"curve\": [3.5, 2.5, 3.5, 3]},\n     {\"curve\": [3.5, 3.5, 3, 3.5]},\n     {\"curve\": [2.5, 3.5, 2.5, 3]},\n     {\"curve\": [2.5, 2.5, 3, 2.5]}],\n\n    [{\"move\": [15.5, 5.5]}, {\"line\": [16.5, 5.5]}],\n\n    [{\"move\": [16, 2.5]}, {\"curve\": [16.5, 2.5, 16.5, 3]},\n     {\"curve\": [16.5, 3.5, 16, 3.5]}, {\"curve\": [15.5, 3.5, 15.5, 3]},\n     {\"curve\": [15.5, 2.5, 16, 2.5]}],\n\n    [{\"move\": [6, 2.5]}, {\"line\": [7, 2.5]}, {\"curve\": [7.5, 2.5, 7.5, 3]},\n     {\"curve\": [7.5, 3.5, 7, 3.5]}, {\"line\": [6, 3.5]},\n     {\"curve\": [5.5, 3.5, 5.5, 3]}, {\"curve\": [5.5, 2.5, 6, 2.5]}],\n\n    [{\"move\": [12, 2.5]}, {\"line\": [13, 2.5]}, {\"curve\": [13.5, 2.5, 13.5, 3]},\n     {\"curve\": [13.5, 3.5, 13, 3.5]}, {\"line\": [12, 3.5]},\n     {\"curve\": [11.5, 3.5, 11.5, 3]}, {\"curve\": [11.5, 2.5, 12, 2.5]}],\n\n    [{\"move\": [7.5, 5.5]}, {\"line\": [9, 5.5]}, {\"curve\": [9.5, 5.5, 9.5, 6]},\n     {\"line\": [9.5, 7.5]}],\n    [{\"move\": [9.5, 6]}, {\"curve\": [9.5, 5.5, 10.5, 5.5]},\n     {\"line\": [11.5, 5.5]}],\n\n\n    [{\"move\": [5.5, 5.5]}, {\"line\": [5.5, 7]}, {\"curve\": [5.5, 7.5, 6, 7.5]},\n     {\"line\": [7.5, 7.5]}],\n    [{\"move\": [6, 7.5]}, {\"curve\": [5.5, 7.5, 5.5, 8]}, {\"line\": [5.5, 9.5]}],\n\n    [{\"move\": [13.5, 5.5]}, {\"line\": [13.5, 7]},\n     {\"curve\": [13.5, 7.5, 13, 7.5]}, {\"line\": [11.5, 7.5]}],\n    [{\"move\": [13, 7.5]}, {\"curve\": [13.5, 7.5, 13.5, 8]},\n     {\"line\": [13.5, 9.5]}],\n\n    [{\"move\": [0, 11.5]}, {\"line\": [3, 11.5]}, {\"curve\": [3.5, 11.5, 3.5, 12]},\n     {\"line\": [3.5, 13]}, {\"curve\": [3.5, 13.5, 3, 13.5]}, {\"line\": [1, 13.5]},\n     {\"curve\": [0.5, 13.5, 0.5, 14]}, {\"line\": [0.5, 17]},\n     {\"curve\": [0.5, 17.5, 1, 17.5]}, {\"line\": [1.5, 17.5]}],\n    [{\"move\": [1, 17.5]}, {\"curve\": [0.5, 17.5, 0.5, 18]}, {\"line\": [0.5, 21]},\n     {\"curve\": [0.5, 21.5, 1, 21.5]}, {\"line\": [18, 21.5]},\n     {\"curve\": [18.5, 21.5, 18.5, 21]}, {\"line\": [18.5, 18]},\n     {\"curve\": [18.5, 17.5, 18, 17.5]}, {\"line\": [17.5, 17.5]}],\n    [{\"move\": [18, 17.5]}, {\"curve\": [18.5, 17.5, 18.5, 17]},\n     {\"line\": [18.5, 14]}, {\"curve\": [18.5, 13.5, 18, 13.5]},\n     {\"line\": [16, 13.5]}, {\"curve\": [15.5, 13.5, 15.5, 13]},\n     {\"line\": [15.5, 12]}, {\"curve\": [15.5, 11.5, 16, 11.5]},\n     {\"line\": [19, 11.5]}],\n\n    [{\"move\": [5.5, 11.5]}, {\"line\": [5.5, 13.5]}],\n    [{\"move\": [13.5, 11.5]}, {\"line\": [13.5, 13.5]}],\n\n    [{\"move\": [2.5, 15.5]}, {\"line\": [3, 15.5]},\n     {\"curve\": [3.5, 15.5, 3.5, 16]}, {\"line\": [3.5, 17.5]}],\n    [{\"move\": [16.5, 15.5]}, {\"line\": [16, 15.5]},\n     {\"curve\": [15.5, 15.5, 15.5, 16]}, {\"line\": [15.5, 17.5]}],\n\n    [{\"move\": [5.5, 15.5]}, {\"line\": [7.5, 15.5]}],\n    [{\"move\": [11.5, 15.5]}, {\"line\": [13.5, 15.5]}],\n    \n    [{\"move\": [2.5, 19.5]}, {\"line\": [5, 19.5]},\n     {\"curve\": [5.5, 19.5, 5.5, 19]}, {\"line\": [5.5, 17.5]}],\n    [{\"move\": [5.5, 19]}, {\"curve\": [5.5, 19.5, 6, 19.5]},\n     {\"line\": [7.5, 19.5]}],\n\n    [{\"move\": [11.5, 19.5]}, {\"line\": [13, 19.5]},\n     {\"curve\": [13.5, 19.5, 13.5, 19]}, {\"line\": [13.5, 17.5]}],\n    [{\"move\": [13.5, 19]}, {\"curve\": [13.5, 19.5, 14, 19.5]},\n     {\"line\": [16.5, 19.5]}],\n\n    [{\"move\": [7.5, 13.5]}, {\"line\": [9, 13.5]},\n     {\"curve\": [9.5, 13.5, 9.5, 14]}, {\"line\": [9.5, 15.5]}],\n    [{\"move\": [9.5, 14]}, {\"curve\": [9.5, 13.5, 10, 13.5]},\n     {\"line\": [11.5, 13.5]}],\n\n    [{\"move\": [7.5, 17.5]}, {\"line\": [9, 17.5]},\n     {\"curve\": [9.5, 17.5, 9.5, 18]}, {\"line\": [9.5, 19.5]}],\n    [{\"move\": [9.5, 18]}, {\"curve\": [9.5, 17.5, 10, 17.5]},\n     {\"line\": [11.5, 17.5]}],\n\n    [{\"move\": [8.5, 9.5]}, {\"line\": [8, 9.5]}, {\"curve\": [7.5, 9.5, 7.5, 10]},\n     {\"line\": [7.5, 11]}, {\"curve\": [7.5, 11.5, 8, 11.5]},\n     {\"line\": [11, 11.5]}, {\"curve\": [11.5, 11.5, 11.5, 11]},\n     {\"line\": [11.5, 10]}, {\"curve\": [11.5, 9.5, 11, 9.5]},\n     {\"line\": [10.5, 9.5]}]\n];\n\nObject.prototype.clone = function () {\n    var i, newObj = (this instanceof Array) ? [] : {};\n    for (i in this) {\n        if (i === 'clone') {\n            continue;\n        }\n        if (this[i] && typeof this[i] === \"object\") {\n            newObj[i] = this[i].clone();\n        } else {\n            newObj[i] = this[i];\n        }\n    }\n    return newObj;\n};\n\n$(function(){\n  var el = document.getElementById(\"pacman\");\n\n  if (Modernizr.canvas && Modernizr.localstorage && \n      Modernizr.audio && (Modernizr.audio.ogg || Modernizr.audio.mp3)) {\n    window.setTimeout(function () { PACMAN.init(el, \"https:\/\/raw.githubusercontent.com\/daleharvey\/pacman\/master\/\"); }, 0);\n  } else { \n    el.innerHTML = \"Sorry, needs a decent browser<br \/><small>\" + \n      \"(firefox 3.6+, Chrome 4+, Opera 10+ and Safari 4+)<\/small>\";\n  }\n});\n\n\n<\/script>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>shim for font face PACMAN waiting for the staff in retro-stylee<\/p>","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":200,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-4650","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/new.merlinedv.de\/en\/wp-json\/wp\/v2\/pages\/4650","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/new.merlinedv.de\/en\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/new.merlinedv.de\/en\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/new.merlinedv.de\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/new.merlinedv.de\/en\/wp-json\/wp\/v2\/comments?post=4650"}],"version-history":[{"count":0,"href":"https:\/\/new.merlinedv.de\/en\/wp-json\/wp\/v2\/pages\/4650\/revisions"}],"wp:attachment":[{"href":"https:\/\/new.merlinedv.de\/en\/wp-json\/wp\/v2\/media?parent=4650"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}