-
Notifications
You must be signed in to change notification settings - Fork 90
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
05be384
commit 4a918b1
Showing
6 changed files
with
297 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,279 @@ | ||
<!DOCTYPE html> | ||
<!-- | ||
Error {{ code }}: {{ message }} | ||
Description: {{ description }} | ||
--> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="utf-8"> | ||
<meta name="viewport" content="width=device-width, initial-scale=1"> | ||
<meta name="robots" content="noindex, nofollow"/> | ||
<meta http-equiv="X-UA-Compatible" content="IE=edge"> | ||
<title>{{ message }} ({{ code }})</title> | ||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> | ||
<link href="https://fonts.googleapis.com/css2?family=Inconsolata:wght@400;700&display=swap" rel="stylesheet"> | ||
<style> | ||
:root{--matrix-glyph-size:15px;--matrix-glyph-font-size:15px;--matrix-glyph-front-color:rgba(255, 255, 255, 0.8);--matrix-glyph-tail-color:#0f0;--matrix-overlay-color:rgba(18, 18, 18, 0.05)} | ||
body,html{margin:0;padding:0;background-color:#000;height:100vh} | ||
#matrix{display:block;position:fixed;width:100vw;height:100vh} | ||
.container{align-items:center;display:flex;justify-content:center;position:absolute;top:0;left:0;width:100vw;height:100vh;z-index:1} | ||
.container .message{background-color:rgba(0,0,0,.85);border:2px solid var(--matrix-glyph-tail-color);padding:15px 20px;margin:0 20px;font-family:Inconsolata,Helvetica,sans-serif;text-align:center;font-size:0;color:var(--matrix-glyph-tail-color);text-shadow:1px 0 2px var(--matrix-glyph-tail-color),-1px 0 2px var(--matrix-glyph-tail-color);box-shadow:1px 0 5px var(--matrix-glyph-tail-color),-1px 0 2px var(--matrix-glyph-tail-color);max-width:640px} | ||
.container .message h1{margin:0;font-size:52px} | ||
.container .message p{margin:.3em 0 0 0;font-size:17px;color:var(--matrix-glyph-front-color)} | ||
/* {{ if show_details }} */ | ||
.container .details{margin-top:20px} | ||
.container .details ul{padding:0} | ||
.container .details code,.container .details span{font-size:11px} | ||
.container .details code{padding-left:7px} | ||
/* {{ end }} */ | ||
.hidden {display:none} | ||
@media screen and (max-width:820px){ | ||
:root{--matrix-glyph-size:10px;--matrix-glyph-font-size:10px} | ||
.container .message h1{font-size:38px} | ||
.container .message p{font-size:13px} | ||
/* {{ if show_details }} */ | ||
.container .details code,.container .details span{font-size:11px} | ||
/* {{ end }} */ | ||
} | ||
</style> | ||
</head> | ||
<body> | ||
|
||
<div class="container"> | ||
<ul id="matrix-words" class="hidden"> | ||
<li>{{ code }}</li> | ||
<li>{{ message }}</li> | ||
<li>{{ description }}</li> | ||
<li>{{ code }} {{ message }}</li> | ||
</ul> | ||
|
||
<div class="message"> | ||
<h1>{{ code }}: <span data-l10n>{{ message }}</span></h1> | ||
<p data-l10n>{{ description }}</p> | ||
|
||
{{ if show_details }} | ||
<div class="details"> | ||
<ul> | ||
{{- if host }}<li><span><span data-l10n>Host</span>:</span> <code>{{ host }}</code></li>{{ end -}} | ||
{{- if original_uri }}<li><span><span data-l10n>Original URI</span>:</span> <code>{{ original_uri }}</code></li>{{ end -}} | ||
{{- if forwarded_for }}<li><span><span data-l10n>Forwarded for</span>:</span> <code>{{ forwarded_for }}</code></li>{{ end -}} | ||
{{- if namespace }}<li><span><span data-l10n>Namespace</span>:</span> <code>{{ namespace }}</code></li>{{ end -}} | ||
{{- if ingress_name }}<li><span><span data-l10n>Ingress name</span>:</span> <code>{{ ingress_name }}</code></li>{{ end -}} | ||
{{- if service_name }}<li><span><span data-l10n>Service name</span>:</span> <code>{{ service_name }}</code></li>{{ end -}} | ||
{{- if service_port }}<li><span><span data-l10n>Service port</span>:</span> <code>{{ service_port }}</code></li>{{ end -}} | ||
{{- if request_id }}<li><span><span data-l10n>Request ID</span>:</span> <code>{{ request_id }}</code></li>{{ end -}} | ||
<li><span><span data-l10n>Timestamp</span>:</span> <code>{{ now.Unix }}</code></li> | ||
</ul> | ||
</div> | ||
{{ end }} | ||
</div> | ||
</div> | ||
|
||
<canvas id="matrix"></canvas> | ||
|
||
<script> | ||
'use strict'; | ||
|
||
/** | ||
* @param {HTMLCanvasElement} $canvas | ||
* @constructor | ||
*/ | ||
const Matrix = function ($canvas) { | ||
const symbols = 'ラドクリフマラソンわたしワタシんょンョたばこタバコとうきょうトウキョウ '.split(''); | ||
|
||
/** | ||
* @return {string} | ||
*/ | ||
const getRandomSymbol = function () { | ||
return symbols[Math.floor(Math.random() * symbols.length)]; | ||
} | ||
|
||
const ctx = $canvas.getContext('2d'); | ||
ctx.globalCompositeOperation = 'lighter'; // https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation | ||
|
||
this.redrawInterval = 70; // fade oud speed | ||
this.glyphSize = 0; | ||
this.rowsCapacity = 0; | ||
this.columnsCapacity = 0; | ||
|
||
/** | ||
* @return {void} | ||
*/ | ||
this.init = () => { | ||
$canvas.width = $canvas.clientWidth; | ||
$canvas.height = $canvas.clientHeight; | ||
|
||
this.glyphSize = parseInt(getComputedStyle($canvas).getPropertyValue('--matrix-glyph-size'), 10); | ||
this.rowsCapacity = Math.ceil($canvas.clientHeight / this.glyphSize); | ||
this.columnsCapacity = Math.ceil($canvas.clientWidth / this.glyphSize); | ||
}; | ||
|
||
/** | ||
* @param {string} symbol | ||
* @param {number} row | ||
* @param {number} column | ||
* @param {string} color | ||
*/ | ||
const drawSymbol = (symbol, row, column, color) => { | ||
if (row > this.rowsCapacity || column > this.columnsCapacity) { | ||
return; | ||
} | ||
|
||
ctx.fillStyle = color; | ||
ctx.font = getComputedStyle($canvas).getPropertyValue('--matrix-glyph-font-size') + ' monospace'; | ||
|
||
if (symbol.length > 1) { | ||
symbol = symbol.charAt(0); // only one char is allowed | ||
} | ||
|
||
let xOffset = 0, charCode = symbol.charCodeAt(0); | ||
|
||
if (charCode >= 33 && charCode <= 126) { // is ascii | ||
xOffset = this.glyphSize / 5; | ||
} | ||
|
||
ctx.fillText(symbol, (column * this.glyphSize) + xOffset, row * this.glyphSize); | ||
}; | ||
|
||
/** | ||
* @param {number} column | ||
* @param {number} speed Lowest = fastest, largest = slowest | ||
* @param {string?} text | ||
* @param {number?} offset | ||
*/ | ||
const drawLine = (column, speed, text, offset) => { | ||
let cursor = 0; | ||
|
||
const tailColor = getComputedStyle($canvas).getPropertyValue('--matrix-glyph-tail-color'), | ||
frontColor = getComputedStyle($canvas).getPropertyValue('--matrix-glyph-front-color'); | ||
|
||
const handler = window.setInterval(() => { | ||
if (column > this.columnsCapacity) { | ||
return window.clearInterval(handler); | ||
} | ||
|
||
if (cursor <= this.rowsCapacity) { | ||
let symbol = getRandomSymbol(); | ||
|
||
if (typeof text === 'string' && typeof offset === 'number') { | ||
if (cursor >= offset && text.length >= cursor - offset) { | ||
symbol = text.charAt(cursor - offset); | ||
} | ||
} | ||
|
||
if (typeof symbol === 'string' && symbol !== ' ') { | ||
const prev = cursor; | ||
|
||
window.setTimeout(() => { // redraw with a green color | ||
drawSymbol(symbol, prev, column, tailColor); | ||
}, speed / 1.3); | ||
|
||
drawSymbol(symbol, cursor, column, frontColor); // white color first | ||
} | ||
|
||
cursor++; | ||
} else { | ||
window.clearInterval(handler); | ||
} | ||
}, speed); | ||
}; | ||
|
||
/** | ||
* @return {void} | ||
*/ | ||
this.redraw = () => { | ||
ctx.fillStyle = getComputedStyle($canvas).getPropertyValue('--matrix-overlay-color'); | ||
ctx.fillRect(0, 0, $canvas.clientWidth, $canvas.clientHeight); | ||
}; | ||
|
||
let redrawIntervalHandler = undefined, dropsIntervalHandler = undefined; | ||
|
||
/** | ||
* @param {HTMLUListElement?} $linesList | ||
*/ | ||
this.run = ($linesList) => { | ||
if (redrawIntervalHandler === undefined) { | ||
redrawIntervalHandler = window.setInterval(this.redraw, this.redrawInterval); | ||
} | ||
|
||
if (dropsIntervalHandler === undefined) { | ||
const fn = () => { | ||
const randomColumn = Math.floor(Math.random() * (this.columnsCapacity + 1)), | ||
minSpeed = 200, maxSpeed = 50, | ||
randomSpeed = Math.floor(Math.random() * (maxSpeed - minSpeed + 1)) + minSpeed; | ||
|
||
const list = []; | ||
let line = undefined, offset = undefined; | ||
|
||
if ($linesList !== undefined) { | ||
Array.prototype.forEach.call($linesList.querySelectorAll('li'), $li => { | ||
const text = $li.innerText.trim(); | ||
|
||
if (text.length > 0) { | ||
list.push(text); | ||
} | ||
}); | ||
|
||
if (list.length > 0 && Math.random() > 0.4) { | ||
line = list[Math.floor(Math.random() * list.length)]; | ||
offset = Math.floor(Math.random() * line.length); | ||
|
||
if (offset <= 5) { | ||
offset *= 3; | ||
} | ||
} | ||
} | ||
|
||
drawLine(randomColumn, randomSpeed, line, offset); | ||
|
||
if (dropsIntervalHandler !== undefined) { | ||
window.clearInterval(dropsIntervalHandler); | ||
dropsIntervalHandler = undefined; | ||
} | ||
|
||
dropsIntervalHandler = window.setInterval(fn, ((minSpeed + maxSpeed) / 2 * this.rowsCapacity) / this.columnsCapacity / 0.5); | ||
}; | ||
|
||
fn(); | ||
} | ||
}; | ||
|
||
/** | ||
* @return {void} | ||
*/ | ||
this.stop = () => { | ||
if (redrawIntervalHandler !== undefined) { | ||
window.clearInterval(redrawIntervalHandler); | ||
redrawIntervalHandler = undefined; | ||
} | ||
|
||
if (dropsIntervalHandler !== undefined) { | ||
window.clearInterval(dropsIntervalHandler); | ||
dropsIntervalHandler = undefined; | ||
} | ||
}; | ||
|
||
if (typeof ResizeObserver === 'function') { | ||
(new ResizeObserver(this.init)).observe($canvas); | ||
} else { | ||
this.init(); | ||
} | ||
}; | ||
|
||
(new Matrix(document.getElementById('matrix'))).run(document.getElementById('matrix-words')); | ||
|
||
if (navigator.language.substring(0, 2).toLowerCase() !== 'en') { | ||
((s, p) => { // localize the page (details here - https://github.com/tarampampam/error-pages/tree/master/l10n) | ||
s.src = 'https://cdn.jsdelivr.net/gh/tarampampam/error-pages@2/l10n/l10n.min.js'; // '../l10n/l10n.js'; | ||
s.async = s.defer = true; | ||
s.addEventListener('load', () => p.removeChild(s)); | ||
p.appendChild(s); | ||
})(document.createElement('script'), document.body); | ||
} | ||
</script> | ||
</body> | ||
<!-- | ||
Error {{ code }}: {{ message }} | ||
Description: {{ description }} | ||
--> | ||
</html> |