5
\$\begingroup\$

Why I made it

I wanted to experiment with javascript: bookmarklets and see how far a small injected script could go on any site by making a simple injectable game.

How it works

Typing javascript: followed by code in the address bar on most browsers causes it to execute that code on the page you’re on. For example, entering javascript:alert("Hello!") in the URI field of this very website should trigger a popup. Saving the script as a bookmarklet makes it quicker to run.

The game uses this idea: it adds a canvas to the page, tracks cursor or touch movement, and moves a paddle based on which half of the screen you’re interacting with. I also included a readable version of the code for revision and the one-liner ready for bookmarking.

Code

Here is the Javascript code in a readable format:

// Create canvas
var canvas = document.createElement('canvas');
document.body.appendChild(canvas);
canvas.style.position = "absolute";
canvas.style.top = "50px";
canvas.style.left = "0px";
canvas.style.opacity = "0.5";
canvas.style.backgroundColor = "white";
canvas.style.borderColor = "black";
canvas.width = 480;
canvas.height = 320;
var ctx = canvas.getContext('2d');
// Create exit button
var button = document.createElement('button');
document.body.appendChild(button);
button.style.position = "absolute";
button.style.top = "50px";
button.style.left = "480px";
button.style.backgroundColor = "black";
button.style.borderColor = "white";
button.style.width = "50px";
button.style.height = "50px";
button.textContent = "EXIT";
button.style.color = "white";
button.style.opacity = "0.5";
button.addEventListener('click', function () {
 document.location.reload();
});
// Ball variables
var ballRadius = 5;
var x = canvas.width / 2;
var y = canvas.height - 30;
var dx = 2;
var dy = -2;
// Paddle variables
var paddleHeight = 10;
var paddleWidth = 75;
var paddleX = (canvas.width - paddleWidth) / 2;
var paddlespeed = 7;
// Bricks
var brickRowCount = 5;
var brickColumnCount = 5;
var brickWidth = 75;
var brickHeight = 15;
var brickPadding = 10;
var brickOffsetTop = 30;
var brickOffsetLeft = 30;
var bricks = [];
for (var c = 0; c < brickColumnCount; c++) {
 bricks[c] = [];
 for (var r = 0; r < brickRowCount; r++) {
 bricks[c][r] = { x: 0, y: 0, status: 1 };
 }
}
var score = 0;
var lives = 3;
// Draw ball
function drawBall() {
 ctx.beginPath();
 ctx.arc(x, y, ballRadius, 0, Math.PI * 2);
 ctx.fillStyle = 'black';
 ctx.fill();
 ctx.closePath();
}
// Draw paddle
function drawPaddle() {
 ctx.beginPath();
 ctx.rect(paddleX, canvas.height - paddleHeight, paddleWidth, paddleHeight);
 ctx.fillStyle = 'grey';
 ctx.fill();
 ctx.closePath();
}
// Draw bricks
function drawBricks() {
 for (var c = 0; c < brickColumnCount; c++) {
 for (var r = 0; r < brickRowCount; r++) {
 if (bricks[c][r].status == 1) {
 var brickX = c * (brickWidth + brickPadding) + brickOffsetLeft;
 var brickY = r * (brickHeight + brickPadding) + brickOffsetTop;
 bricks[c][r].x = brickX;
 bricks[c][r].y = brickY;
 ctx.beginPath();
 ctx.rect(brickX, brickY, brickWidth, brickHeight);
 ctx.fillStyle = 'black';
 ctx.fill();
 ctx.closePath();
 }
 }
 }
}
// Draw score
function drawScore() {
 ctx.font = '16px Arial';
 ctx.fillStyle = 'black';
 ctx.fillText('Score: ' + score, 8, 20);
}
// Draw lives
function drawLives() {
 ctx.font = '16px Arial';
 ctx.fillStyle = 'black';
 ctx.fillText('Lives: ' + lives, canvas.width - 65, 20);
 ctx.font = '20px Arial';
 ctx.fillText('Made by Emmanuel Ghattas', 100, 25);
}
// Main draw loop
function draw() {
 ctx.clearRect(0, 0, canvas.width, canvas.height);
 drawBricks();
 drawBall();
 drawPaddle();
 drawScore();
 drawLives();
 collisionDetection();
 // Ball collision with walls
 if (x + dx > canvas.width - ballRadius || x + dx < ballRadius) {
 dx = -dx;
 }
 if (y + dy < ballRadius) {
 dy = -dy;
 } else if (y + dy > canvas.height - ballRadius) {
 if (x > paddleX && x < paddleX + paddleWidth) {
 dy = -dy;
 } else {
 lives--;
 if (!lives) {
 alert('GAME OVER!\nGame by: Emmanuel Ghattas.\nBye-Bye!');
 document.location.reload();
 } else {
 x = canvas.width / 2;
 y = canvas.height - 30;
 dy = -dy;
 paddleX = (canvas.width - paddleWidth) / 2;
 }
 }
 }
 x += dx;
 y += dy;
 requestAnimationFrame(draw);
}
// Collision detection
function collisionDetection() {
 for (var c = 0; c < brickColumnCount; c++) {
 for (var r = 0; r < brickRowCount; r++) {
 var b = bricks[c][r];
 if (b.status == 1) {
 if (
 x > b.x &&
 x < b.x + brickWidth &&
 y > b.y &&
 y < b.y + brickHeight
 ) {
 dy = -dy;
 b.status = 0;
 score++;
 if (score === brickRowCount * brickColumnCount) {
 alert('YOU WIN, CONGRATULATIONS!');
 lives = 99;
 dx = 10;
 dy = -10;
 paddlespeed += 2;
 }
 }
 }
 }
 }
}
// Mouse/touch controls
document.addEventListener('click', function (e) {
 var screenWidth = window.innerWidth;
 var clickX = e.clientX;
 if (clickX < screenWidth / 2) {
 paddleX -= paddlespeed;
 if (paddleX < 0) paddleX = 0;
 } else {
 paddleX += paddlespeed;
 if (paddleX + paddleWidth > canvas.width)
 paddleX = canvas.width - paddleWidth;
 }
});
document.addEventListener('touchmove', function (e) {
 var screenWidth = window.innerWidth;
 var touchX = e.touches[0].clientX;
 if (touchX < screenWidth / 2) {
 paddleX -= paddlespeed;
 if (paddleX < 0) paddleX = 0;
 } else {
 paddleX += paddlespeed;
 if (paddleX + paddleWidth > canvas.width)
 paddleX = canvas.width - paddleWidth;
 }
});
// Start the game
draw();

Here it is in the original, ready-to-bookmark one-liner format:

javascript:%20var%20canvas%20=%20document.createElement('canvas');%20document.body.appendChild(canvas);%20canvas.style.position%20=%20%22absolute%22;%20canvas.style.top%20=%20%2250px%22;%20canvas.style.left%20=%20%220px%22;%20canvas.style.opacity%20=%20%220.5%22;%20canvas.style.backgroundColor%20=%20%22white%22;%20canvas.style.borderColor%20=%20%22black%22;%20canvas.width%20=%20480;%20canvas.height%20=%20320;%20%20var%20ctx%20=%20canvas.getContext('2d');%20%20var%20button%20=%20document.createElement('button');%20document.body.appendChild(button);%20button.style.position%20=%20%22absolute%22;%20button.style.top%20=%20%2250px%22;%20button.style.left%20=%20%22480px%22;%20button.style.backgroundColor%20=%20%22black%22;%20button.style.borderColor%20=%20%22white%22;%20button.style.width%20=%20%2250px%22;%20button.style.height%20=%20%2250px%22;%20button.textContent%20=%20%22EXIT%22;%20button.style.color%20=%20%22white%22;%20button.style.opacity%20=%20%220.5%22;%20button.addEventListener('click',%20function(event)%20%7B%20%20%20%20%20document.location.reload();%20%7D);%20%20var%20ballRadius%20=%205;%20var%20x%20=%20canvas.width%20/%202;%20var%20y%20=%20canvas.height%20-%2030;%20var%20dx%20=%202;%20var%20dy%20=%20-2;%20%20var%20paddleHeight%20=%2010;%20var%20paddleWidth%20=%2075;%20var%20paddleX%20=%20(canvas.width%20-%20paddleWidth)%20/%202;%20var%20paddlespeed%20=%207;%20%20var%20brickRowCount%20=%205;%20var%20brickColumnCount%20=%205;%20var%20brickWidth%20=%2075;%20var%20brickHeight%20=%2015;%20var%20brickPadding%20=%2010;%20var%20brickOffsetTop%20=%2030;%20var%20brickOffsetLeft%20=%2030;%20var%20bricks%20=%20%5B%5D;%20%20for%20(var%20c%20=%200;%20c%20%3C%20brickColumnCount;%20c++)%20%7B%20%20%20%20%20bricks%5Bc%5D%20=%20%5B%5D;%20%20%20%20%20for%20(var%20r%20=%200;%20r%20%3C%20brickRowCount;%20r++)%20%7B%20%20%20%20%20%20%20%20%20bricks%5Bc%5D%5Br%5D%20=%20%7B%20x:%200,%20y:%200,%20status:%201%20%7D;%20%20%20%20%20%7D%20%7D%20%20var%20score%20=%200;%20var%20lives%20=%203;%20%20function%20drawBall()%20%7B%20%20%20%20%20ctx.beginPath();%20%20%20%20%20ctx.arc(x,%20y,%20ballRadius,%200,%20Math.PI%20*%202);%20%20%20%20%20ctx.fillStyle%20=%20'black';%20%20%20%20%20ctx.fill();%20%20%20%20%20ctx.closePath();%20%7D%20%20function%20drawPaddle()%20%7B%20%20%20%20%20ctx.beginPath();%20%20%20%20%20ctx.rect(paddleX,%20canvas.height%20-%20paddleHeight,%20paddleWidth,%20paddleHeight);%20%20%20%20%20ctx.fillStyle%20=%20'grey';%20%20%20%20%20ctx.fill();%20%20%20%20%20ctx.closePath();%20%7D%20%20function%20drawBricks()%20%7B%20%20%20%20%20for%20(var%20c%20=%200;%20c%20%3C%20brickColumnCount;%20c++)%20%7B%20%20%20%20%20%20%20%20%20for%20(var%20r%20=%200;%20r%20%3C%20brickRowCount;%20r++)%20%7B%20%20%20%20%20%20%20%20%20%20%20%20%20if%20(bricks%5Bc%5D%5Br%5D.status%20==%201)%20%7B%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20var%20brickX%20=%20c%20*%20(brickWidth%20+%20brickPadding)%20+%20brickOffsetLeft;%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20var%20brickY%20=%20r%20*%20(brickHeight%20+%20brickPadding)%20+%20brickOffsetTop;%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20bricks%5Bc%5D%5Br%5D.x%20=%20brickX;%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20bricks%5Bc%5D%5Br%5D.y%20=%20brickY;%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20ctx.beginPath();%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20ctx.rect(brickX,%20brickY,%20brickWidth,%20brickHeight);%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20ctx.fillStyle%20=%20'black';%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20ctx.fill();%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20ctx.closePath();%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%20%20%20%20%20%20%20%20%20%7D%20%20%20%20%20%7D%20%7D%20%20function%20drawScore()%20%7B%20%20%20%20%20ctx.font%20=%20'16px%20Arial';%20%20%20%20%20ctx.fillStyle%20=%20'black';%20%20%20%20%20ctx.fillText('Score:%20'%20+%20score,%208,%2020);%20%7D%20%20function%20drawLives()%20%7B%20%20%20%20%20ctx.font%20=%20'16px%20Arial';%20%20%20%20%20ctx.fillStyle%20=%20'black';%20%20%20%20%20ctx.fillText('Lives:%20'%20+%20lives,%20canvas.width%20-%2065,%2020);%20%20%20%20%20ctx.font%20=%20'20px%20Arial';%20%20%20%20%20ctx.fillStyle%20=%20'black';%20%20%20%20%20ctx.fillText('Made%20by%20Emmanuel%20Ghattas',%20100,%2025);%20%7D%20%20function%20draw()%20%7B%20%20%20%20%20ctx.clearRect(0,%200,%20canvas.width,%20canvas.height);%20%20%20%20%20drawBricks();%20%20%20%20%20drawBall();%20%20%20%20%20drawPaddle();%20%20%20%20%20drawScore();%20%20%20%20%20drawLives();%20%20%20%20%20collisionDetection();%20%20%20%20%20%20if%20(x%20+%20dx%20%3E%20canvas.width%20-%20ballRadius%20%7C%7C%20x%20+%20dx%20%3C%20ballRadius)%20%7B%20%20%20%20%20%20%20%20%20dx%20=%20-dx;%20%20%20%20%20%7D%20%20%20%20%20if%20(y%20+%20dy%20%3C%20ballRadius)%20%7B%20%20%20%20%20%20%20%20%20dy%20=%20-dy;%20%20%20%20%20%7D%20else%20if%20(y%20+%20dy%20%3E%20canvas.height%20-%20ballRadius)%20%7B%20%20%20%20%20%20%20%20%20if%20(x%20%3E%20paddleX%20&&%20x%20%3C%20paddleX%20+%20paddleWidth)%20%7B%20%20%20%20%20%20%20%20%20%20%20%20%20dy%20=%20-dy;%20%20%20%20%20%20%20%20%20%7D%20else%20%7B%20%20%20%20%20%20%20%20%20%20%20%20%20lives--;%20%20%20%20%20%20%20%20%20%20%20%20%20if%20(!lives)%20%7B%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20alert('GAME%20OVER!%5CnGame%20by:%20Emmanuel%20Ghattas.%5CnBye-Bye!');%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20document.location.reload();%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%20else%20%7B%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20x%20=%20canvas.width%20/%202;%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20y%20=%20canvas.height%20-%2030;%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20dy%20=%200%20-%20dy;%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20paddleX%20=%20(canvas.width%20-%20paddleWidth)%20/%202;%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%20%20%20%20%20%20%20%20%20%7D%20%20%20%20%20%7D%20%20%20%20%20%20x%20+=%20dx;%20%20%20%20%20y%20+=%20dy;%20%20%20%20%20requestAnimationFrame(draw);%20%7D%20%20function%20collisionDetection()%20%7B%20%20%20%20%20for%20(var%20c%20=%200;%20c%20%3C%20brickColumnCount;%20c++)%20%7B%20%20%20%20%20%20%20%20%20for%20(var%20r%20=%200;%20r%20%3C%20brickRowCount;%20r++)%20%7B%20%20%20%20%20%20%20%20%20%20%20%20%20var%20b%20=%20bricks%5Bc%5D%5Br%5D;%20%20%20%20%20%20%20%20%20%20%20%20%20if%20(b.status%20==%201)%20%7B%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20(x%20%3E%20b.x%20&&%20x%20%3C%20b.x%20+%20brickWidth%20&&%20y%20%3E%20b.y%20&&%20y%20%3C%20b.y%20+%20brickHeight)%20%7B%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20dy%20=%20-dy;%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20b.status%20=%200;%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20score++;%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20(score%20==%20brickRowCount%20*%20brickColumnCount)%20%7B%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20alert('YOU%20WIN,%20CONGRATULATIONS!');%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20lives%20=%2099;%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20dx%20=%2010;%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20dy%20=%20-10;%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20paddlespeed%20+=%202;%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%20%20%20%20%20%20%20%20%20%7D%20%20%20%20%20%7D%20%7D%20document.addEventListener('click',%20function(e)%20%7B%20%20%20%20%20var%20screenWidth%20=%20window.innerWidth;%20%20%20%20%20var%20clickX%20=%20e.clientX;%20%20%20%20%20if%20(clickX%20%3C%20screenWidth%20/%202)%20%7B%20%20%20%20%20%20%20%20%20paddleX%20-=%20paddlespeed;%20%20%20%20%20%20%20%20%20if%20(paddleX%20%3C%200)%20%7B%20%20%20%20%20%20%20%20%20%20%20%20%20paddleX%20=%200;%20%20%20%20%20%20%20%20%20%7D%20%20%20%20%20%7D%20else%20%7B%20%20%20%20%20%20%20%20%20paddleX%20+=%20paddlespeed;%20%20%20%20%20%20%20%20%20if%20(paddleX%20+%20paddleWidth%20%3E%20canvas.width)%20%7B%20%20%20%20%20%20%20%20%20%20%20%20%20paddleX%20=%20canvas.width%20-%20paddleWidth;%20%20%20%20%20%20%20%20%20%7D%20%20%20%20%20%7D%20%7D);%20%20document.addEventListener('touchmove',%20function(e)%20%7B%20%20%20%20%20var%20screenWidth%20=%20window.innerWidth;%20%20%20%20%20var%20touchX%20=%20e.touches%5B0%5D.clientX;%20%20%20%20%20if%20(touchX%20%3C%20screenWidth%20/%202)%20%7B%20%20%20%20%20%20%20%20%20paddleX%20-=%204;%20%20%20%20%20%20%20%20%20if%20(paddleX%20%3C%200)%20%7B%20%20%20%20%20%20%20%20%20%20%20%20%20paddleX%20=%200;%20%20%20%20%20%20%20%20%20%7D%20%20%20%20%20%7D%20else%20%7B%20%20%20%20%20%20%20%20%20paddleX%20+=%204;%20%20%20%20%20%20%20%20%20if%20(paddleX%20+%20paddleWidth%20%3E%20canvas.width)%20%7B%20%20%20%20%20%20%20%20%20%20%20%20%20paddleX%20=%20canvas.width%20-%20paddleWidth;%20%20%20%20%20%20%20%20%20%7D%20%20%20%20%20%7D%20%7D);%20%20draw();

Please, tell me if anything comes to mind.

Sᴀᴍ Onᴇᴌᴀ
29.6k16 gold badges46 silver badges203 bronze badges
asked Dec 5 at 17:11
\$\endgroup\$
9
  • 1
    \$\begingroup\$ Just a quick note (I don't have the time for a full review right now) It would be better if the paddle was controlled by mouse moves, rather than (fast) cklicking, especially since the left/right checks work based off the width of the entire page rather than the width of the game. I believe MDN has a decent enough version here that could be interesting. \$\endgroup\$ Commented Dec 5 at 18:10
  • \$\begingroup\$ @JannikS. It is currently based off mouse moves. It first checks if the mouse is moving, then checks on which side of the screen. So if you make the mouse move in circular motions on the left side, it would continuously move towards the left. But I do like the idea of containing it inside the canvas! \$\endgroup\$ Commented Dec 5 at 19:40
  • 2
    \$\begingroup\$ I can't seem to get it working, at least not without clicking repeatedly. Something like onmousemove="/* code here*/" could probbably make the desktop experience better. Also note that all desktops that I'm aware off won't fire touchmove. \$\endgroup\$ Commented Dec 5 at 20:44
  • 1
    \$\begingroup\$ Shouldn't you use const in place of most of those var? Is there a browser you're targeting that doesn't support it? \$\endgroup\$ Commented Dec 6 at 15:13
  • 1
    \$\begingroup\$ That makes it sound like you should just embed your code in an anonymous function. That's more important and helpful in my mind than allowing variables to mutate. \$\endgroup\$ Commented Dec 6 at 15:35

1 Answer 1

-2
\$\begingroup\$

I would consider creating an HTML version, stored as a Data URL for simpler storage and embedding.

I escaped the \n literal in the alert() call with \\n.

The bottom pad that blocks the moving object only moves left on desktop.

You'll have to edit the below code since SE is now prepending attribution, unless you copy the code directly a different way than what the UI offers...

data:text/html;base64,PCFkb2N0eXBlIGh0bWw+PGh0bWw+PGJvZHk+PHNjcmlwdD4vLyBTb3VyY2UgLSBodHRwczovL2NvZGVyZXZpZXcuc3RhY2tleGNoYW5nZS5jb20vcQovLyBQb3N0ZWQgYnkgQ2hpcDAxLCBtb2RpZmllZCBieSBjb21tdW5pdHkuIFNlZSBwb3N0ICdUaW1lbGluZScgZm9yIGNoYW5nZSBoaXN0b3J5Ci8vIFJldHJpZXZlZCAyMDI1LTEyLTA2LCBMaWNlbnNlIC0gQ0MgQlktU0EgNC4wCgovLyBDcmVhdGUgY2FudmFzCnZhciBjYW52YXMgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdjYW52YXMnKTsKZG9jdW1lbnQuYm9keS5hcHBlbmRDaGlsZChjYW52YXMpOwoKY2FudmFzLnN0eWxlLnBvc2l0aW9uID0gImFic29sdXRlIjsKY2FudmFzLnN0eWxlLnRvcCA9ICI1MHB4IjsKY2FudmFzLnN0eWxlLmxlZnQgPSAiMHB4IjsKY2FudmFzLnN0eWxlLm9wYWNpdHkgPSAiMC41IjsKY2FudmFzLnN0eWxlLmJhY2tncm91bmRDb2xvciA9ICJ3aGl0ZSI7CmNhbnZhcy5zdHlsZS5ib3JkZXJDb2xvciA9ICJibGFjayI7CgpjYW52YXMud2lkdGggPSA0ODA7CmNhbnZhcy5oZWlnaHQgPSAzMjA7Cgp2YXIgY3R4ID0gY2FudmFzLmdldENvbnRleHQoJzJkJyk7CgovLyBDcmVhdGUgZXhpdCBidXR0b24KdmFyIGJ1dHRvbiA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2J1dHRvbicpOwpkb2N1bWVudC5ib2R5LmFwcGVuZENoaWxkKGJ1dHRvbik7CgpidXR0b24uc3R5bGUucG9zaXRpb24gPSAiYWJzb2x1dGUiOwpidXR0b24uc3R5bGUudG9wID0gIjUwcHgiOwpidXR0b24uc3R5bGUubGVmdCA9ICI0ODBweCI7CmJ1dHRvbi5zdHlsZS5iYWNrZ3JvdW5kQ29sb3IgPSAiYmxhY2siOwpidXR0b24uc3R5bGUuYm9yZGVyQ29sb3IgPSAid2hpdGUiOwpidXR0b24uc3R5bGUud2lkdGggPSAiNTBweCI7CmJ1dHRvbi5zdHlsZS5oZWlnaHQgPSAiNTBweCI7CmJ1dHRvbi50ZXh0Q29udGVudCA9ICJFWElUIjsKYnV0dG9uLnN0eWxlLmNvbG9yID0gIndoaXRlIjsKYnV0dG9uLnN0eWxlLm9wYWNpdHkgPSAiMC41IjsKCmJ1dHRvbi5hZGRFdmVudExpc3RlbmVyKCdjbGljaycsIGZ1bmN0aW9uICgpIHsKICAgIGRvY3VtZW50LmxvY2F0aW9uLnJlbG9hZCgpOwp9KTsKCi8vIEJhbGwgdmFyaWFibGVzCnZhciBiYWxsUmFkaXVzID0gNTsKdmFyIHggPSBjYW52YXMud2lkdGggLyAyOwp2YXIgeSA9IGNhbnZhcy5oZWlnaHQgLSAzMDsKdmFyIGR4ID0gMjsKdmFyIGR5ID0gLTI7CgovLyBQYWRkbGUgdmFyaWFibGVzCnZhciBwYWRkbGVIZWlnaHQgPSAxMDsKdmFyIHBhZGRsZVdpZHRoID0gNzU7CnZhciBwYWRkbGVYID0gKGNhbnZhcy53aWR0aCAtIHBhZGRsZVdpZHRoKSAvIDI7CnZhciBwYWRkbGVzcGVlZCA9IDc7CgovLyBCcmlja3MKdmFyIGJyaWNrUm93Q291bnQgPSA1Owp2YXIgYnJpY2tDb2x1bW5Db3VudCA9IDU7CnZhciBicmlja1dpZHRoID0gNzU7CnZhciBicmlja0hlaWdodCA9IDE1Owp2YXIgYnJpY2tQYWRkaW5nID0gMTA7CnZhciBicmlja09mZnNldFRvcCA9IDMwOwp2YXIgYnJpY2tPZmZzZXRMZWZ0ID0gMzA7Cgp2YXIgYnJpY2tzID0gW107Cgpmb3IgKHZhciBjID0gMDsgYyA8IGJyaWNrQ29sdW1uQ291bnQ7IGMrKykgewogICAgYnJpY2tzW2NdID0gW107CiAgICBmb3IgKHZhciByID0gMDsgciA8IGJyaWNrUm93Q291bnQ7IHIrKykgewogICAgICAgIGJyaWNrc1tjXVtyXSA9IHsgeDogMCwgeTogMCwgc3RhdHVzOiAxIH07CiAgICB9Cn0KCnZhciBzY29yZSA9IDA7CnZhciBsaXZlcyA9IDM7CgovLyBEcmF3IGJhbGwKZnVuY3Rpb24gZHJhd0JhbGwoKSB7CiAgICBjdHguYmVnaW5QYXRoKCk7CiAgICBjdHguYXJjKHgsIHksIGJhbGxSYWRpdXMsIDAsIE1hdGguUEkgKiAyKTsKICAgIGN0eC5maWxsU3R5bGUgPSAnYmxhY2snOwogICAgY3R4LmZpbGwoKTsKICAgIGN0eC5jbG9zZVBhdGgoKTsKfQoKLy8gRHJhdyBwYWRkbGUKZnVuY3Rpb24gZHJhd1BhZGRsZSgpIHsKICAgIGN0eC5iZWdpblBhdGgoKTsKICAgIGN0eC5yZWN0KHBhZGRsZVgsIGNhbnZhcy5oZWlnaHQgLSBwYWRkbGVIZWlnaHQsIHBhZGRsZVdpZHRoLCBwYWRkbGVIZWlnaHQpOwogICAgY3R4LmZpbGxTdHlsZSA9ICdncmV5JzsKICAgIGN0eC5maWxsKCk7CiAgICBjdHguY2xvc2VQYXRoKCk7Cn0KCi8vIERyYXcgYnJpY2tzCmZ1bmN0aW9uIGRyYXdCcmlja3MoKSB7CiAgICBmb3IgKHZhciBjID0gMDsgYyA8IGJyaWNrQ29sdW1uQ291bnQ7IGMrKykgewogICAgICAgIGZvciAodmFyIHIgPSAwOyByIDwgYnJpY2tSb3dDb3VudDsgcisrKSB7CiAgICAgICAgICAgIGlmIChicmlja3NbY11bcl0uc3RhdHVzID09IDEpIHsKICAgICAgICAgICAgICAgIHZhciBicmlja1ggPSBjICogKGJyaWNrV2lkdGggKyBicmlja1BhZGRpbmcpICsgYnJpY2tPZmZzZXRMZWZ0OwogICAgICAgICAgICAgICAgdmFyIGJyaWNrWSA9IHIgKiAoYnJpY2tIZWlnaHQgKyBicmlja1BhZGRpbmcpICsgYnJpY2tPZmZzZXRUb3A7CgogICAgICAgICAgICAgICAgYnJpY2tzW2NdW3JdLnggPSBicmlja1g7CiAgICAgICAgICAgICAgICBicmlja3NbY11bcl0ueSA9IGJyaWNrWTsKCiAgICAgICAgICAgICAgICBjdHguYmVnaW5QYXRoKCk7CiAgICAgICAgICAgICAgICBjdHgucmVjdChicmlja1gsIGJyaWNrWSwgYnJpY2tXaWR0aCwgYnJpY2tIZWlnaHQpOwogICAgICAgICAgICAgICAgY3R4LmZpbGxTdHlsZSA9ICdibGFjayc7CiAgICAgICAgICAgICAgICBjdHguZmlsbCgpOwogICAgICAgICAgICAgICAgY3R4LmNsb3NlUGF0aCgpOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgfQp9CgovLyBEcmF3IHNjb3JlCmZ1bmN0aW9uIGRyYXdTY29yZSgpIHsKICAgIGN0eC5mb250ID0gJzE2cHggQXJpYWwnOwogICAgY3R4LmZpbGxTdHlsZSA9ICdibGFjayc7CiAgICBjdHguZmlsbFRleHQoJ1Njb3JlOiAnICsgc2NvcmUsIDgsIDIwKTsKfQoKLy8gRHJhdyBsaXZlcwpmdW5jdGlvbiBkcmF3TGl2ZXMoKSB7CiAgICBjdHguZm9udCA9ICcxNnB4IEFyaWFsJzsKICAgIGN0eC5maWxsU3R5bGUgPSAnYmxhY2snOwogICAgY3R4LmZpbGxUZXh0KCdMaXZlczogJyArIGxpdmVzLCBjYW52YXMud2lkdGggLSA2NSwgMjApOwoKICAgIGN0eC5mb250ID0gJzIwcHggQXJpYWwnOwogICAgY3R4LmZpbGxUZXh0KCdNYWRlIGJ5IEVtbWFudWVsIEdoYXR0YXMnLCAxMDAsIDI1KTsKfQoKLy8gTWFpbiBkcmF3IGxvb3AKZnVuY3Rpb24gZHJhdygpIHsKICAgIGN0eC5jbGVhclJlY3QoMCwgMCwgY2FudmFzLndpZHRoLCBjYW52YXMuaGVpZ2h0KTsKCiAgICBkcmF3QnJpY2tzKCk7CiAgICBkcmF3QmFsbCgpOwogICAgZHJhd1BhZGRsZSgpOwogICAgZHJhd1Njb3JlKCk7CiAgICBkcmF3TGl2ZXMoKTsKICAgIGNvbGxpc2lvbkRldGVjdGlvbigpOwoKICAgIC8vIEJhbGwgY29sbGlzaW9uIHdpdGggd2FsbHMKICAgIGlmICh4ICsgZHggPiBjYW52YXMud2lkdGggLSBiYWxsUmFkaXVzIHx8IHggKyBkeCA8IGJhbGxSYWRpdXMpIHsKICAgICAgICBkeCA9IC1keDsKICAgIH0KCiAgICBpZiAoeSArIGR5IDwgYmFsbFJhZGl1cykgewogICAgICAgIGR5ID0gLWR5OwogICAgfSBlbHNlIGlmICh5ICsgZHkgPiBjYW52YXMuaGVpZ2h0IC0gYmFsbFJhZGl1cykgewogICAgICAgIGlmICh4ID4gcGFkZGxlWCAmJiB4IDwgcGFkZGxlWCArIHBhZGRsZVdpZHRoKSB7CiAgICAgICAgICAgIGR5ID0gLWR5OwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIGxpdmVzLS07CiAgICAgICAgICAgIGlmICghbGl2ZXMpIHsKICAgICAgICAgICAgICAgIGFsZXJ0KCdHQU1FIE9WRVIhXG5HYW1lIGJ5OiBFbW1hbnVlbCBHaGF0dGFzLlxuQnllLUJ5ZSEnKTsKICAgICAgICAgICAgICAgIGRvY3VtZW50LmxvY2F0aW9uLnJlbG9hZCgpOwogICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgeCA9IGNhbnZhcy53aWR0aCAvIDI7CiAgICAgICAgICAgICAgICB5ID0gY2FudmFzLmhlaWdodCAtIDMwOwogICAgICAgICAgICAgICAgZHkgPSAtZHk7CiAgICAgICAgICAgICAgICBwYWRkbGVYID0gKGNhbnZhcy53aWR0aCAtIHBhZGRsZVdpZHRoKSAvIDI7CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICB9CgogICAgeCArPSBkeDsKICAgIHkgKz0gZHk7CgogICAgcmVxdWVzdEFuaW1hdGlvbkZyYW1lKGRyYXcpOwp9CgovLyBDb2xsaXNpb24gZGV0ZWN0aW9uCmZ1bmN0aW9uIGNvbGxpc2lvbkRldGVjdGlvbigpIHsKICAgIGZvciAodmFyIGMgPSAwOyBjIDwgYnJpY2tDb2x1bW5Db3VudDsgYysrKSB7CiAgICAgICAgZm9yICh2YXIgciA9IDA7IHIgPCBicmlja1Jvd0NvdW50OyByKyspIHsKICAgICAgICAgICAgdmFyIGIgPSBicmlja3NbY11bcl07CgogICAgICAgICAgICBpZiAoYi5zdGF0dXMgPT0gMSkgewogICAgICAgICAgICAgICAgaWYgKAogICAgICAgICAgICAgICAgICAgIHggPiBiLnggJiYKICAgICAgICAgICAgICAgICAgICB4IDwgYi54ICsgYnJpY2tXaWR0aCAmJgogICAgICAgICAgICAgICAgICAgIHkgPiBiLnkgJiYKICAgICAgICAgICAgICAgICAgICB5IDwgYi55ICsgYnJpY2tIZWlnaHQKICAgICAgICAgICAgICAgICkgewogICAgICAgICAgICAgICAgICAgIGR5ID0gLWR5OwogICAgICAgICAgICAgICAgICAgIGIuc3RhdHVzID0gMDtjb25zb2xlLmxvZwogICAgICAgICAgICAgICAgICAgIHNjb3JlKys7CgogICAgICAgICAgICAgICAgICAgIGlmIChzY29yZSA9PT0gYnJpY2tSb3dDb3VudCAqIGJyaWNrQ29sdW1uQ291bnQpIHsKICAgICAgICAgICAgICAgICAgICAgICAgYWxlcnQoJ1lPVSBXSU4sIENPTkdSQVRVTEFUSU9OUyEnKTsKICAgICAgICAgICAgICAgICAgICAgICAgbGl2ZXMgPSA5OTsKICAgICAgICAgICAgICAgICAgICAgICAgZHggPSAxMDsKICAgICAgICAgICAgICAgICAgICAgICAgZHkgPSAtMTA7CiAgICAgICAgICAgICAgICAgICAgICAgIHBhZGRsZXNwZWVkICs9IDI7CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgfQogICAgfQp9CgovLyBNb3VzZS90b3VjaCBjb250cm9scwpkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCdjbGljaycsIGZ1bmN0aW9uIChlKSB7CiAgICB2YXIgc2NyZWVuV2lkdGggPSB3aW5kb3cuaW5uZXJXaWR0aDsKICAgIHZhciBjbGlja1ggPSBlLmNsaWVudFg7CgogICAgaWYgKGNsaWNrWCA8IHNjcmVlbldpZHRoIC8gMikgewogICAgICAgIHBhZGRsZVggLT0gcGFkZGxlc3BlZWQ7CiAgICAgICAgaWYgKHBhZGRsZVggPCAwKSBwYWRkbGVYID0gMDsKICAgIH0gZWxzZSB7CiAgICAgICAgcGFkZGxlWCArPSBwYWRkbGVzcGVlZDsKICAgICAgICBpZiAocGFkZGxlWCArIHBhZGRsZVdpZHRoID4gY2FudmFzLndpZHRoKQogICAgICAgICAgICBwYWRkbGVYID0gY2FudmFzLndpZHRoIC0gcGFkZGxlV2lkdGg7CiAgICB9Cn0pOwoKZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcigndG91Y2htb3ZlJywgZnVuY3Rpb24gKGUpIHsKICAgIHZhciBzY3JlZW5XaWR0aCA9IHdpbmRvdy5pbm5lcldpZHRoOwogICAgdmFyIHRvdWNoWCA9IGUudG91Y2hlc1swXS5jbGllbnRYOwoKICAgIGlmICh0b3VjaFggPCBzY3JlZW5XaWR0aCAvIDIpIHsKICAgICAgICBwYWRkbGVYIC09IHBhZGRsZXNwZWVkOwogICAgICAgIGlmIChwYWRkbGVYIDwgMCkgcGFkZGxlWCA9IDA7CiAgICB9IGVsc2UgewogICAgICAgIHBhZGRsZVggKz0gcGFkZGxlc3BlZWQ7CiAgICAgICAgaWYgKHBhZGRsZVggKyBwYWRkbGVXaWR0aCA+IGNhbnZhcy53aWR0aCkKICAgICAgICAgICAgcGFkZGxlWCA9IGNhbnZhcy53aWR0aCAtIHBhZGRsZVdpZHRoOwogICAgfQp9KTsKCi8vIFN0YXJ0IHRoZSBnYW1lCmRyYXcoKTsKPC9zY3JpcHQ+CjwvYm9keT4KPC9odG1sPgo=
answered Dec 6 at 4:08
\$\endgroup\$
3
  • 2
    \$\begingroup\$ Among other issues, I really don't think it's safe to copy and paste an opaque script. At the absolute least, I would need to see the original (non-packed) source. What's to stop you from embedding a virus in that data URL? \$\endgroup\$ Commented Dec 6 at 15:22
  • 1
    \$\begingroup\$ @Reinderien What? The source is in OP. No idea what you mean by "embedding a virus in that data URL". Very simple, convert to plain text and read it before loading it in a browser tab, if you're scurred. Further, I don't know what kind of "virus" you think can be embedded in a data URL? \$\endgroup\$ Commented Dec 6 at 16:01
  • \$\begingroup\$ @Reinderien You mean you couldn't do this yourself? var text = await (await fetch(dataURL)).text(); console.log(text);? \$\endgroup\$ Commented Dec 6 at 16:14

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.